diff --git a/lua/markview.lua b/lua/markview.lua index 5942ab2..d236668 100644 --- a/lua/markview.lua +++ b/lua/markview.lua @@ -1165,14 +1165,22 @@ markview.configuration = { } }, html = { - default = { - conceal = false + tags = { + enable = true, + + default = { + conceal = false + }, + + config = { + p = { conceal = true, hl = "Title" }, + u = { conceal = true, hl = "Underlined" }, + i = { conceal = true, hl = "Italic" } + } }, - types = { - p = { conceal = true, hl = "Title" }, - u = { conceal = true, hl = "Underlined" }, - i = { conceal = true, hl = "Italic" } + entites = { + enable = true } }, diff --git a/lua/markview/entites.lua b/lua/markview/entites.lua new file mode 100644 index 0000000..c0beec5 --- /dev/null +++ b/lua/markview/entites.lua @@ -0,0 +1,256 @@ +local entites = {}; + +entites.lookup = { + Aacute = "Á", + aacute = "á", + Acirc = "Â", + acirc = "â", + acute = "´", + AElig = "Æ", + aelig = "æ", + Agrave = "À", + agrave = "à", + alefsym = "ℵ", + Alpha = "Α", + alpha = "α", + amp = "&", + ["and"] = "∧", + ang = "∠", + Aring = "Å", + aring = "å", + asymp = "≈", + Atilde = "Ã", + atilde = "ã", + Auml = "Ä", + auml = "ä", + bdquo = "„", + Beta = "Β", + beta = "β", + brvbar = "¦", + bull = "•", + cap = "∩", + Ccedil = "Ç", + ccedil = "ç", + cedil = "¸", + cent = "¢", + Chi = "Χ", + chi = "χ", + circ = "ˆ", + clubs = "♣", + congc = "≅", + copy = "©", + crarr = "↵", + cup = "∪", + curren = "¤", + Dagger = "‡", + dagger = "†", + dArr = "⇓", + darr = "↓", + deg = "°", + Delta = "Δ", + delta = "δ", + diams = "♦", + divide = "÷", + Eacute = "É", + eacute = "é", + Ecirc = "Ê", + ecirc = "ê", + Egrave = "È", + egrave = "è", + empty = "∅", + Epsilon = "Ε", + epsilon = "ε", + equiv = "≡", + Eta = "Η", + eta = "η", + ETH = "Ð", + eth = "ð", + Euml = "Ë", + euml = "ë", + euro = "€", + exists = "∃", + fnof = "ƒ", + forall = "∀", + frac12 = "½", + frac14 = "¼", + frac34 = "¾", + frasl = "⁄", + Gamma = "Γ", + gamma = "γ", + ge = "≥", + gt = ">", + harr = "↔", + hArr = "⇔", + hearts = "♥", + hellip = "…", + Iacute = "Í", + iacute = "í", + Icirc = "Î", + icirc = "î", + iexcl = "¡", + Igrave = "Ì", + igrave = "ì", + image = "ℑ", + infin = "∞", + int = "∫", + Iota = "Ι", + iota = "ι", + iquest = "¿", + isin = "∈", + Iuml = "Ï", + iuml = "ï", + Kappa = "Κ", + kappa = "κ", + Lambda = "Λ", + lambda = "λ", + lang = "⟨", + laquo = "«", + lArr = "⇐", + larr = "←", + lceil = "⌈", + ldquo = "“", + le = "≤", + lfloor = "⌊", + lowast = "∗", + loz = "◊", + -- lrm = "‎", + lsaquo = "‹", + lsquo = "‘", + lt = "<", + macr = "¯", + mdash = "—", + micro = "µ", + middot = "·", + minus = "−", + Mu = "Μ", + mu = "μ", + nabla = "∇", + nbsp = " ", + ndash = "–", + ne = "≠", + ni = "∋", + ["not"] = "¬", + notin = "∉", + nsub = "⊄", + Ntilde = "Ñ", + ntilde = "ñ", + Nu = "Ν", + nu = "ν", + Oacute = "Ó", + oacute = "ó", + Ocirc = "Ô", + ocirc = "ô", + OElig = "Œ", + oelig = "œ", + Ograve = "Ò", + ograve = "ò", + Omeg = "Ω", + omega = "ω", + Omicron = "Ο", + omicron = "ο", + oline = "‾", + ["or"] = "∨", + Oslash = "Ø", + oslash = "ø", + Otilde = "Õ", + otilde = "õ", + Ouml = "Ö", + ouml = "ö", + para = "¶", + part = "∂", + permil = "‰", + perp = "⊥", + Phi = "Φ", + phi = "φ", + Pi = "Π", + pi = "π", + piv = "ϖ", + plusmn = "±", + pound = "£", + Prime = "″", + prime = "′", + prod = "∏", + prop = "∝", + Psi = "Ψ", + psi = "ψ", + quot = "\"", + radic = "√", + rang = "⟩", + raquo = "»", + rArr = "⇒", + rarr = "→", + rceil = "⌉", + rdquo = "”", + real = "ℜ", + reg = "®", + rflo = "⌋", + Rho = "Ρ", + rho = "ρ", + -- rlm = "‏", + rsaquo = "›", + rsquo = "’", + sbquo = "‚", + Scaron = "Š", + scaron = "š", + sdot = "⋅", + sect = "§", + shy = "­", + Sigma = "Σ", + sigma = "σ", + sigmaf = "ς", + sim = "∼", + spades = "♠", + sub = "⊂", + sube = "⊆", + sum = "∑", + sup = "⊃", + sup1 = "¹", + sup2 = "²", + sup3 = "³", + supe = "⊇", + szlig = "ß", + Tau = "Τ", + tau = "τ", + there4 = "∴", + Theta = "Θ", + theta = "θ", + thetasym = "ϑ", + thinsp = " ", + THORN = "Þ", + thorn = "þ", + tilde = "˜", + times = "×", + trade = "™", + Uacute = "Ú", + uacute = "ú", + uArr = "⇑", + uarr = "↑", + Ucirc = "Û", + ucirc = "û", + Ugrave = "Ù", + ugrave = "ù", + uml = "¨", + upsih = "ϒ", + Upsilon = "Υ", + upsilon = "υ", + Uuml = "Ü", + uuml = "ü", + weierp = "℘", + Xi = "Ξ", + xi = "ξ", + Yacute = "Ý", + yacute = "ý", + yen = "¥", + yuml = "ÿ", + Yuml = "Ÿ", + Zeta = "Ζ", + zeta = "ζ", + -- zwj = "‍", + -- zwnj = "‌" +} + +entites.get = function (string) + return entites.lookup[string], vim.fn.strdisplaywidth(entites.lookup[string]); +end + +return entites; diff --git a/lua/markview/parser.lua b/lua/markview/parser.lua index 4af70a2..5fc0269 100644 --- a/lua/markview/parser.lua +++ b/lua/markview/parser.lua @@ -430,6 +430,8 @@ parser.md_inline = function (buffer, TStree, from, to) ] @link) ((code_span) @code) + + ((entity_reference) @entity) ]]); -- The last 2 _ represent the metadata & query @@ -511,6 +513,19 @@ parser.md_inline = function (buffer, TStree, from, to) row_start = row_start, row_end = row_end, + col_start = col_start, + col_end = col_end + }) + elseif capture_name == "entity" then + table.insert(parser.parsed_content, { + node = capture_node, + type = "html_entity", + + text = capture_text, + + row_start = row_start, + row_end = row_end, + col_start = col_start, col_end = col_end }) @@ -521,8 +536,6 @@ end parser.html = function (buffer, TStree, from, to) local scanned_queies = vim.treesitter.query.parse("html", [[ ((element) @elem) - - ;((entity_reference) @entity) ]]); for capture_id, capture_node, _, _ in scanned_queies:iter_captures(TStree:root(), buffer, from, to) do diff --git a/lua/markview/renderer.lua b/lua/markview/renderer.lua index 0370235..9ca7461 100644 --- a/lua/markview/renderer.lua +++ b/lua/markview/renderer.lua @@ -1,6 +1,7 @@ local renderer = {}; local devicons = require("nvim-web-devicons"); +local entites = require("markview.entites"); local utils = require("markview.utils"); @@ -203,7 +204,11 @@ local display_width = function (text, config) while tmp_string:match("<([^>]+)>") do -- This shouldn't run so many times - if iterations > 10 then + if not html_conf or html_conf.enable == false then + break; + elseif not html_conf.tags or html_conf.tags.enable == false then + break; + elseif iterations > 10 then break; else iterations = iterations + 1; @@ -227,10 +232,11 @@ local display_width = function (text, config) goto invalid; end - local conf = html_conf.default or {}; + local tag_conf = html_conf.tags; + local conf = tag_conf.default or {}; - if html_conf.types and html_conf.types[filtered_tag] then - conf = html_conf.types[filtered_tag] + if tag_conf.config and tag_conf.config[filtered_tag] then + conf = tag_conf.config[filtered_tag] end local internal_text = tmp_string:match("<" .. start_tag .. ">(.-)") or ""; @@ -246,6 +252,34 @@ local display_width = function (text, config) ::invalid:: end + for entity_name, semicolon in final_string:gmatch("&(%a+)(;?)") do + if not html_conf or html_conf.enable == false then + break; + elseif not html_conf.entites or html_conf.entites.enable == false then + break; + end + + local entity = entites.get(entity_name); + + if not entity then + goto invalid; + end + + if semicolon then + final_string = final_string:gsub("&" .. entity_name .. ";", entity); + + d_width = d_width - vim.fn.strchars("&" .. entity_name .. ";"); + d_width = d_width + vim.fn.strdisplaywidth(entity); + else + final_string = final_string:gsub("&" .. entity_name, entity); + + d_width = d_width - vim.fn.strchars("&" .. entity_name); + d_width = d_width + vim.fn.strdisplaywidth(entity); + end + + ::invalid:: + end + return d_width, vim.fn.strchars(text), final_string; end @@ -1383,10 +1417,14 @@ renderer.render_html_inline = function (buffer, content, user_config) return; end - local html_conf = user_config.default or {}; + if not user_config.tags or user_config.tags.enable == false then + return; + end + + local html_conf = user_config.tags.default or {}; - if user_config.types[content.tag] then - html_conf = user_config.types[content.tag]; + if user_config.tags.config[content.tag] then + html_conf = user_config.tags.config[content.tag]; end if html_conf.conceal ~= false then @@ -1405,6 +1443,33 @@ renderer.render_html_inline = function (buffer, content, user_config) end end +renderer.render_html_entities = function (buffer, content, user_config) + if not user_config or user_config.enable == false then + return; + end + + if not user_config.entites or user_config.entites.enable == false then + return; + end + + local filtered_entity = content.text:gsub("[&;]", ""); + local entity = entites.get(filtered_entity); + + if not entity then + return; + end + + vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, { + virt_text_pos = "inline", + virt_text = { + { entity, set_hl(user_config.entites.hl) } + }, + + end_col = content.col_end, + conceal = "" + }); +end + renderer.render_in_range = function (buffer, partial_contents, config_table) for _, content in ipairs(partial_contents) do local type = content.type; @@ -1434,10 +1499,12 @@ renderer.render_in_range = function (buffer, partial_contents, config_table) pcall(renderer.render_lists, buffer, content, config_table.list_items) elseif type == "checkbox" then pcall(renderer.render_checkboxes, buffer, content, config_table.checkboxes) - elseif type == "table" then - pcall(renderer.render_tables, buffer, content, config_table) elseif type == "html_inline" then pcall(renderer.render_html_inline, buffer, content, config_table.html); + elseif type == "html_entity" then + pcall(renderer.render_html_entities, buffer, content, config_table.html); + elseif type == "table" then + pcall(renderer.render_tables, buffer, content, config_table) end ::extmark_skipped:: @@ -1494,6 +1561,8 @@ renderer.render = function (buffer, parsed_content, config_table, conceal_start, pcall(renderer.render_checkboxes, buffer, content, config_table.checkboxes) elseif type == "html_inline" then pcall(renderer.render_html_inline, buffer, content, config_table.html); + elseif type == "html_entity" then + pcall(renderer.render_html_entities, buffer, content, config_table.html); elseif type == "table" then pcall(renderer.render_tables, buffer, content, config_table); end