's range.
+M.html_container_elements_opts = {
+ opening_tag_offset = function (range)
+ range[2] = range[2] + 1;
+ range[3] = range[3] - 1;
+
+ return range;
+ end,
+ on_opening_tag = function ()
+ return { hl_mode = "combine", hl_group = "Special" }
+ end
+};
+
+-- [ HTML | Container elements > Parameters ] ---------------------------------------------
+
+--- Parsed version of an HTML container element.
+---@class __html.container_elements
+---
+---@field class "html_container_element"
+---
+---@field opening_tag __container.data Table containing information regarding the opening tag.
+---@field closing_tag __container.data Table containing information regarding the closing tag.
+---
+---@field name string Tag name(in lowercase).
+---
+---@field text string[] Text of this node.
+---@field range node.range Range of this node.
+M.__html_container_elements = {
+ class = "html_container_element",
+ name = "p",
+ text = {
+ "",
+ "text
"
+ },
+
+ opening_tag = {
+ text = "",
+ range = { 0, 0, 0, 3 }
+ },
+ closing_tag = {
+ text = "
",
+ range = { 1, 5, 1, 8 }
+ },
+
+ range = {
+ row_start = 0,
+ row_end = 1,
+ col_start = 0,
+ col_end = 8
+ }
+};
+
+--- Container element segment data.
+---@class __container.data
+---
+---@field text string Text inside this segment.
+---@field range integer[] Range of this segment(Result of `{ TSNode:range() }`).
+M.__conteiner_segment_opts = {
+ text = "",
+ range = { 0, 0, 0, 3 }
+};
+
+
+-- [ HTML | Headings ] --------------------------------------------------------------------
+
+--- HTML heading config.
+---@class html.headings
+---
+---@field enable boolean
+---@field [string] config.extmark | fun(buffer: integer, item: __html.headings): config.extmark
+M.html_headings = {
+ ---+${lua}
+
+ enable = true,
+
+ heading_1 = {
+ hl_group = "MarkviewPalette1Bg"
+ },
+ heading_2 = {
+ hl_group = "MarkviewPalette2Bg"
+ },
+ heading_3 = {
+ hl_group = "MarkviewPalette3Bg"
+ },
+ heading_4 = {
+ hl_group = "MarkviewPalette4Bg"
+ },
+ heading_5 = {
+ hl_group = "MarkviewPalette5Bg"
+ },
+ heading_6 = {
+ hl_group = "MarkviewPalette6Bg"
+ },
+
+ ---_
+};
+
+-- [ HTML | Headings โข Static ] -----------------------------------------------------------
+
+--- HTML heading config.
+---@class html.headings_static
+---
+---@field enable boolean Enables heading rendering.
+---@field [string] config.extmark Configuration for .
+M.html_headings = {
+ enable = true,
+ heading_1 = { fg = "#1e1e2e" }
+};
+
+-- [ HTML | Headings > Parameters ] --------------------------------------------------------
+
+---@class __html.headings
+---
+---@field class "html_heading"
+---@field level integer Heading level.
+---@field range node.range
+---@field text string[]
+M.__html_headings = {
+ class = "html_heading",
+ level = 1,
+ text = {
+ "
",
+ "heading text",
+ " "
+ },
+ range = {
+ row_start = 0,
+ col_start = 0,
+ row_end = 2,
+ col_end = 5
+ }
+};
+
+-- [ HTML | Void elements ] ---------------------------------------------------------------
+
+--- HTML element config.
+---@class html.void_elements
+---
+---@field enable boolean
+---@field [string] void_elements.opts | fun(buffer: integer, item: __html.void_elements): void_elements.opts
+M.html_void_elements = {
+ enable = true,
+ bold = {
+ node_offset = function (range)
+ return range;
+ end,
+ on_node = function ()
+ return { fg = "#1e1e2e", bg = "#cdd6f4" }
+ end
+ }
+};
+
+-- [ HTML | Void elements โข Static ] ------------------------------------------------------
+
+--- Static configuration for void elements..
+---@class html.void_elements
+---
+---@field enable boolean Enables void element rendering.
+---@field [string] void_elements.opts Configuration for .
+M.html_void_elements = {
+ enable = true,
+ bold = {
+ node_offset = function (range)
+ return range;
+ end,
+ on_node = function ()
+ return { fg = "#1e1e2e", bg = "#cdd6f4" }
+ end
+ }
+};
+
+-- [ HTML | Void elements > Type definition ] --------------------------------------------
+
+--- Configuration table for a specific void element.
+---@class void_elements.opts
+---
+---@field node_offset? fun(range: integer[]): table
+---@field on_node config.extmark | fun(tag: __html.void_elements): config.extmark
+M.html_void_elements_opts = {
+ node_offset = function (range)
+ return range;
+ end,
+ on_node = function ()
+ return { fg = "#1e1e2e", bg = "#cdd6f4" }
+ end
+};
+
+-- [ HTML | Void elements > Parameters ] --------------------------------------------------
+
+--- Parsed version of a void element.
+---@class __html.void_elements
+---
+---@field class "html_void_element"
+---
+---@field name string Element name(always in lowercase).
+---
+---@field text string[]
+---@field range node.range
+M.__html_void_elements = {
+ class = "html_void_element",
+ name = "img",
+ text = {
+ " "
+ },
+ range = {
+ row_start = 0,
+ row_end = 0,
+ col_start = 0,
+ col_end = 27
+ }
+};
+
+return M;
diff --git a/lua/definitions/latex.lua b/lua/definitions/latex.lua
new file mode 100644
index 0000000..f7de35c
--- /dev/null
+++ b/lua/definitions/latex.lua
@@ -0,0 +1,609 @@
+---@meta
+
+--- LaTeX related stuff
+local M = {};
+
+-- [ Markview | LaTeX ] -------------------------------------------------------------------
+
+--- Configuration for LaTeX.
+---@class config.latex
+---
+---@field enable boolean
+---
+---@field blocks? latex.blocks | fun(): latex.blocks
+---@field commands? latex.commands | fun(): latex.commands
+---@field escapes? latex.escapes | fun(): latex.escapes
+---@field fonts? latex.fonts | fun(): latex.fonts
+---@field inlines? latex.inlines | fun(): latex.inlines
+---@field parenthesis? latex.parenthesis | fun(): latex.parenthesis
+---@field subscripts? latex.subscripts | fun(): latex.subscripts
+---@field superscripts? latex.superscripts | fun(): latex.superscripts
+---@field symbols? latex.symbols | fun(): latex.symbols
+---@field texts? latex.texts | fun(): latex.texts
+M.latex = {
+ enable = true,
+
+ commands = {},
+ texts = {},
+ symbols = {},
+ subscripts = {},
+ superscripts = {},
+ parenthesis = {},
+ escapes = {},
+ inlines = {},
+ blocks = {},
+ fonts = {}
+};
+
+-- [ Markview | LaTeX โข Static ] ----------------------------------------------------------
+
+--- Static configuration for LaTeX.
+---@class config.latex_static
+---
+---@field enable boolean
+---
+--- LaTeX blocks configuration(typically made with `$$...$$`).
+---@field blocks? latex.blocks
+--- LaTeX commands configuration(e.g. `\frac{x}{y}`).
+---@field commands? latex.commands
+--- LaTeX escaped characters configuration.
+---@field escapes? latex.escapes
+--- LaTeX fonts configuration(e.g. `\mathtt{}`).
+---@field fonts? latex.fonts
+--- Inline LaTeX configuration(typically made with `$...$`).
+---@field inlines? latex.inlines
+--- Configuration for hiding `{}`.
+---@field parenthesis? latex.parenthesis
+--- LaTeX subscript configuration(`_{}`, `_x`).
+---@field subscripts? latex.subscripts
+--- LaTeX superscript configuration(`^{}`, `^x`).
+---@field superscripts? latex.superscripts
+--- TeX math symbols configuration(e.g. `\alpha`).
+---@field symbols? latex.symbols
+--- Text block configuration(`\text{}`).
+---@field texts? latex.texts
+M.latex = {
+ enable = true,
+
+ commands = {},
+ texts = {},
+ symbols = {},
+ subscripts = {},
+ superscripts = {},
+ parenthesis = {},
+ escapes = {},
+ inlines = {},
+ blocks = {},
+ fonts = {}
+};
+
+-- [ LaTeX | LaTeX blocks ] ---------------------------------------------------------------
+
+--- Configuration table for latex math blocks.
+---@class latex.blocks
+---
+---@field enable boolean
+---
+---@field hl? string | fun(buffer: integer, item: __latex.blocks): string?
+---@field pad_amount integer | fun(buffer: integer, item: __latex.blocks): integer
+---@field pad_char string | fun(buffer: integer, item: __latex.blocks): string
+---
+---@field text string | fun(buffer: integer, item: __latex.blocks): string
+---@field text_hl? string | fun(buffer: integer, item: __latex.blocks): string?
+M.latex_blocks = {
+ enable = true,
+
+ hl = "MarkviewCode",
+ pad_char = " ",
+ pad_amount = 3,
+
+ text = "Math"
+};
+
+-- [ LaTeX | LaTeX blocks โข Static ] ------------------------------------------------------
+
+--- Configuration table for latex math blocks.
+---@class latex.blocks_static
+---
+---@field enable boolean Enables rendering of LaTeX blocks.
+---
+---@field hl? string Primary highlight group for the LaTeX block.
+---@field pad_amount integer Number of `pad_char` to add before & after the text.
+---@field pad_char string Character to use for padding.
+---
+---@field text string Text to show on the top left.
+---@field text_hl? string Highlight group for the `text`.
+
+-- [ LaTeX | LaTeX blocks > Parameters ] --------------------------------------------------
+
+---@class __latex.blocks
+---
+---@field class "latex_block"
+---@field marker string
+---
+---@field text string[]
+---@field range node.range
+M.__latex_blocks = {
+ class = "latex_block",
+ marker = "$$",
+
+ closed = true,
+
+ text = { "$$1 + 2 = 3$$" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+ col_start = 0,
+ col_end = 13
+ }
+};
+
+-- [ LaTeX | LaTeX commands ] -------------------------------------------------------------
+
+--- Configuration for LaTeX commands.
+---@class latex.commands
+---
+---@field enable boolean
+---@field [string] commands.opts | fun(buffer: integer, item: __latex.commands): commands.opts
+M.latex_commands = {
+ enable = true,
+ sin = {
+ condition = function (item)
+ return #item.args == 2;
+ end,
+ on_command = function ()
+ return { conceal = "" };
+ end
+ }
+};
+
+-- [ LaTeX | LaTeX commands โข Static ] ----------------------------------------------------
+
+--- Static configuration for LaTeX commands.
+---@class latex.commands_static
+---
+---@field enable boolean Enables latex command preview.
+---@field [string] commands.opts Configuration table for {string}.
+
+-- [ LaTeX | LaTeX commands > Type definition ] --------------------------------------------
+
+---@class commands.opts
+---
+---@field condition? fun(item: __latex.commands): boolean Condition used to determine if a command is valid.
+---
+---@field command_offset? fun(range: integer[]): integer[] Modifies the command's range(`{ row_start, col_start, row_end, col_end }`).
+---@field on_command? config.extmark | fun(tag: table): config.extmark Extmark configuration to use on the command.
+---@field on_args? commands.arg_opts[]? Configuration table for each argument.
+M.latex_commands_opts = {
+ on_command = function ()
+ return { conceal = "" };
+ end,
+ command_offset = nil,
+ on_args = {}
+};
+
+---@class commands.arg_opts
+---
+---@field after_offset? fun(range: integer[]): integer[] Modifies the range of the argument(only for `on_after`).
+---@field before_offset? fun(range: integer[]): integer[] Modifies the range of the argument(only for `on_before`).
+---@field condition? fun(item: table): boolean Can be used to change when the command preview is shown.
+---@field content_offset? fun(range: integer[]): table Modifies the argument's range(only for `on_content`).
+---@field on_after? config.extmark | fun(tag: table): config.extmark Extmark configuration to use at the end of the argument.
+---@field on_before? config.extmark | fun(tag: table): config.extmark Extmark configuration to use at the start of the argument.
+---@field on_content? config.extmark | fun(tag: table): config.extmark Extmark configuration to use on the argument.
+M.latex_commands_arg_opts = {
+ on_after = { virt_text = { { ")", "Comment" } }, virt_text_pos = "overlay" },
+ on_before = { virt_text = { { ")", "Comment" } }, virt_text_pos = "overlay" }
+};
+
+-- [ LaTeX | LaTeX commands > Parameters ] ------------------------------------------------
+
+--- LaTeX commands(must have at least 1 argument).
+---@class __latex.commands
+---
+---@field class "latex_command"
+---
+---@field command { name: string, range: integer[] } Command name(without `\`) and it's range.
+---@field args { text: string, range: integer[] }[] List of arguments(inside `{...}`) with their text & range.
+---
+---@field text string[]
+---@field range node.range
+M.__latex_commands = {
+ class = "latex_command",
+
+ command = {
+ name = "frac",
+ range = { 0, 0, 0, 5 }
+ },
+ args = {
+ {
+ text = "{1}",
+ range = { 0, 5, 0, 8 }
+ },
+ {
+ text = "{2}",
+ range = { 0, 8, 0, 11 }
+ }
+ },
+ text = { "\\frac{1}{2}" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 11
+ }
+};
+
+-- [ LaTeX | LaTeX escapes ] --------------------------------------------------------------
+
+--- Configuration table for latex escaped characters.
+---@class latex.escapes
+---
+---@field enable boolean Enables escaped character preview.
+---@field hl? string | fun(item: __latex.escapes): string? Highlight group for the escaped character.
+M.latex_escapes = {
+ enable = true,
+ hl = "Operator"
+};
+
+-- [ LaTeX | LaTeX escapes โข Static ] -----------------------------------------------------
+
+--- Static configuration table for latex escaped characters.
+---@class latex.escapes_static
+---
+---@field enable boolean Enables escaped character preview.
+---@field hl? string | fun(item: __latex.escapes): string? Highlight group for the escaped character.
+
+-- [ LaTeX | LaTeX escapes > Parameters ] -------------------------------------------------
+
+--- Escaped characters.
+---@class __latex.escapes
+---
+---@field class "latex_escaped"
+---
+---@field text string[]
+---@field range node.range
+M.__latex_escapes = {
+ class = "latex_escaped",
+
+ text = { "\\|" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 2
+ }
+};
+
+-- [ LaTeX | LaTeX fonts ] ----------------------------------------------------------------
+
+--- Configuration table for latex math fonts.
+---@class latex.fonts
+---
+---@field enable boolean
+---
+---@field default fonts.opts | fun(buffer: integer, item: __latex.fonts): fonts.opts
+---@field [string] fonts.opts | fun(buffer: integer, item: __latex.fonts): fonts.opts
+M.latex_fonts = {
+ enable = true,
+ default = { hl = "Special" }
+};
+
+-- [ LaTeX | LaTeX fonts โข Static ] -------------------------------------------------------
+
+--- Static configuration table for latex math fonts.
+---@class latex.fonts_static
+---
+---@field enable boolean
+---
+---@field default fonts.opts Default configuration for fonts
+---@field [string] fonts.opts Configuration for `\string{}` font.
+
+--- Configuration for a specific fonts.
+---@class fonts.opts
+---
+---@field enable? boolean Whether to enable this font.
+---@field hl? string | fun(buffer: integer, item: __latex.fonts): string? Highlight group for this font.
+M.fonts_opts = {
+ enable = true,
+ hl = "Special"
+};
+
+-- [ LaTeX | LaTeX fonts > Parameters ] ----------------------------------------------------
+
+--- Math fonts
+---@class __latex.fonts
+---
+---@field class "latex_font"
+---
+---@field name string Font name.
+---
+---@field text string[]
+---@field range node.range
+M.__latex_fonts = {
+ class = "latex_font",
+
+ name = "mathtt",
+
+ text = { "\\mathtt{abcd}" },
+ range = {
+ font = { 0, 0, 0, 7 },
+ row_start = 0,
+ row_end = 0,
+ col_start = 0,
+ col_end = 13
+ }
+};
+
+-- [ LaTeX | Inline LaTeX ] ---------------------------------------------------------------
+
+--- Configuration table for inline latex math.
+---@class latex.inlines
+---
+---@field enable boolean Enables preview of inline latex maths.
+---
+---@field corner_left? string | fun(buffer: integer, item: __latex.inlines): string? Left corner.
+---@field corner_left_hl? string | fun(buffer: integer, item: __latex.inlines): string? Highlight group for left corner.
+---@field corner_right? string | fun(buffer: integer, item: __latex.inlines): string? Right corner.
+---@field corner_right_hl? string | fun(buffer: integer, item: __latex.inlines): string? Highlight group for right corner.
+---@field hl? string | fun(buffer: integer, item: __latex.inlines): string? Base Highlight group.
+---@field padding_left? string | fun(buffer: integer, item: __latex.inlines): string? Left padding.
+---@field padding_left_hl? string | fun(buffer: integer, item: __latex.inlines): string? Highlight group for left padding.
+---@field padding_right? string | fun(buffer: integer, item: __latex.inlines): string? Right padding.
+---@field padding_right_hl? string | fun(buffer: integer, item: __latex.inlines): string? Highlight group for right padding.
+M.latex_inlines = {
+ enable = true,
+
+ corner_left = " ",
+ corner_right = " ",
+
+ hl = "MarkviewInlineCode"
+};
+
+-- [ LaTeX | Inline LaTeX โข Static ] ------------------------------------------------------
+
+--- Configuration table for inline latex math.
+---@class latex.inlines_static
+---
+---@field enable boolean Enables preview of inline latex maths.
+---
+---@field corner_left? string Left corner.
+---@field corner_left_hl? string Highlight group for left corner.
+---@field corner_right? string Right corner.
+---@field corner_right_hl? string Highlight group for right corner.
+---@field hl? string Base Highlight group.
+---@field padding_left? string Left padding.
+---@field padding_left_hl? string Highlight group for left padding.
+---@field padding_right? string Right padding.
+---@field padding_right_hl? string Highlight group for right padding.
+
+-- [ LaTeX | Inline LaTeX > Parameters ] --------------------------------------------------
+
+--- Inline LaTeX(typically made using `$...$`).
+---@class __latex.inlines
+---
+---@field class "latex_inlines"
+---@field marker string
+---
+---@field closed boolean Is there a closing `$`?
+---@field text string[]
+---@field range node.range
+M.__latex_inlines = {
+ class = "latex_inlines",
+ marker = "$",
+ closed = true,
+
+ text = { "$1 + 1 = 2$" },
+ range = {
+ row_start = 0,
+ col_start = 0,
+
+ row_end = 0,
+ col_end = 11
+ }
+};
+
+-- [ LaTeX | Parenthesis ] ----------------------------------------------------------------
+
+--- Configuration table for {}.
+---@alias latex.parenthesis { enable: boolean }
+
+-- [ LaTeX | Parenthesis > Parameters ] ----------------------------------------------------------------
+
+--- {} in LaTeX.
+---@class __latex.parenthesis
+---
+---@field class "latex_parenthesis"
+---@field text string[]
+---@field range node.range
+M.__latex_parenthesis = {
+ class = "latex_parenthesis",
+ text = { "{1+2}" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 5
+ }
+};
+
+-- [ LaTeX | Subscripts ] ----------------------------------------------------------------
+
+--- Configuration for subscripts.
+---@class latex.subscripts
+---
+---@field enable boolean Enables preview of subscript text.
+---@field hl? string | string[] Highlight group for the subscript text. Can be a list to use different hl for nested subscripts.
+M.latex_subscripts = {
+ enable = true,
+ hl = "MarkviewSubscript"
+};
+
+-- [ LaTeX | Subscripts > Parameters ] -----------------------------------------------------
+
+--- Subscript text(e.g. _h, _{hi}, _{+} etc.).
+---@class __latex.subscripts
+---
+---@field class "latex_subscript"
+---
+---@field parenthesis boolean Is the text within `{...}`?
+---@field level integer Level of the subscript text. Used for handling nested subscript text.
+---@field preview boolean Can the text be previewed?
+---
+---@field text string[]
+---@field range node.range
+M.__latex_subscripts = {
+ class = "latex_subscript",
+ parenthesis = true,
+ preview = true,
+ level = 1,
+
+ text = { "_{hi}" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 5
+ }
+};
+
+-- [ LaTeX | Superscripts ] ---------------------------------------------------------------
+
+--- Configuration for superscripts.
+---@class latex.superscripts
+---
+---@field enable boolean Enables preview of superscript text.
+---@field hl? string | string[] Highlight group for the superscript text. Can be a list to use different hl for nested superscripts.
+M.latex_subscripts = {
+ enable = true,
+ hl = "MarkviewSuperscript"
+};
+
+-- [ LaTeX | Superscripts > Parameters ] --------------------------------------------------
+
+--- Superscript text(e.g. ^h, ^{hi}, ^{+} etc.).
+---@class __latex.superscripts
+---
+---@field class "latex_superscript"
+---
+---@field parenthesis boolean Is the text within `{...}`?
+---@field level integer Level of the superscript text. Used for handling nested superscript text.
+---@field preview boolean Can the text be previewed?
+---
+---@field text string[]
+---@field range node.range
+M.__latex_superscripts = {
+ class = "latex_superscript",
+ parenthesis = true,
+ preview = true,
+ level = 1,
+
+ text = { "^{hi}" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 5
+ }
+};
+
+-- [ LaTeX | Symbols ] --------------------------------------------------------------------
+
+--- Configuration table for TeX math symbols.
+---@class latex.symbols
+---
+---@field enable boolean
+---@field hl? string | fun(buffer: integer, item: __latex.symbols): string?
+M.latex_symbols = {
+ enable = true,
+ hl = "MarkviewSuperscript"
+};
+
+-- [ LaTeX | Symbols โข Static ] -----------------------------------------------------------
+
+--- Configuration table for TeX math symbols.
+---@class latex.symbols_static
+---
+---@field enable boolean Enables preview of latex math symbols.
+---@field hl? string Highlight group for the symbols.
+
+-- [ LaTeX | Symbols > Parameters ] -------------------------------------------------------
+
+--- Math symbols in LaTeX(e.g. \Alpha).
+---@class __latex.symbols
+---
+---@field class "latex_symbols"
+---@field name string Symbol name(without the `\`).
+---@field style "superscripts" | "subscripts" | nil Text styles to apply(if possible).
+---
+---@field text string[]
+---@field range node.range
+M.__latex_symbols = {
+ class = "latex_symbols",
+ name = "pi",
+ style = nil,
+
+ text = { "\\pi" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 3
+ }
+};
+
+-- [ LaTeX | Texts ] ----------------------------------------------------------------------
+
+--- Configuration table for text.
+---@alias latex.texts { enable: boolean }
+
+-- [ LaTeX | Texts > Parameters ] ---------------------------------------------------------
+
+--- `\text{}` nodes.
+---@class __latex.text
+---
+---@field class "latex_text"
+---@field text string[]
+---@field range node.range
+M.__latex_word = {
+ class = "latex_text",
+ text = { "word" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 5,
+ col_end = 9
+ }
+};
+
+
+-- [ LaTeX | Misc ] -----------------------------------------------------------------------
+
+--- Groups of characters(without any spaces between them).
+--- Used for applying fonts & text styles.
+---@class __latex.word
+---
+---@field class "latex_word"
+---
+---@field text string[]
+---@field range node.range
+M.__latex_word = {
+ class = "latex_word",
+ text = { "word" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 5,
+ col_end = 9
+ }
+};
+
+return M;
diff --git a/lua/definitions/markdown.lua b/lua/definitions/markdown.lua
new file mode 100644
index 0000000..c9a9ff3
--- /dev/null
+++ b/lua/definitions/markdown.lua
@@ -0,0 +1,1032 @@
+---@meta
+
+--- Markdown related stuff.
+local M = {};
+
+-- [ Markview | Markdown ] ----------------------------------------------------------------
+
+--- Configuration for markdown.
+---@class config.markdown
+---
+---@field enable boolean
+---
+---@field block_quotes markdown.block_quotes | fun(): markdown.block_quotes
+---@field code_blocks markdown.code_blocks | fun(): __markdown.code_blocks
+---@field headings markdown.headings | fun(): markdown.headings
+---@field horizontal_rules markdown.horizontal_rules | fun(): markdown.horizontal_rules
+---@field list_items markdown.list_items | fun(): markdown.list_items
+---@field metadata_minus markdown.metadata_minus | fun(): markdown.metadata_minus
+---@field metadata_plus markdown.metadata_plus | fun(): markdown.metadata_plus
+---@field reference_definitions markdown.reference_definitions | fun(): markdown.reference_definitions
+---@field tables markdown.tables | fun(): markdown.tables
+M.markdown = {
+ enable = true,
+
+ metadata_minus = {},
+ horizontal_rules = {},
+ headings = {},
+ code_blocks = {},
+ block_quotes = {},
+ list_items = {},
+ metadata_plus = {},
+ reference_definitions = {},
+ tables = {}
+};
+
+-- [ Markview | Markdown โข Static ] -------------------------------------------------------
+
+--- Static configuration for markdown.
+---@class config.markdown_static
+---
+---@field enable boolean
+---
+---@field block_quotes markdown.block_quotes Block quote configuration.
+---@field code_blocks markdown.code_blocks Fenced code block configuration.
+---@field headings markdown.headings Heading configuration.
+---@field horizontal_rules markdown.horizontal_rules Horizontal rules configuration.
+---@field list_items markdown.list_items List items configuration.
+---@field metadata_minus markdown.metadata_minus YAML metadata configuration.
+---@field metadata_plus markdown.metadata_plus TOML metadata configuration.
+---@field reference_definitions markdown.reference_definitions Reference link definition configuration.
+---@field tables markdown.tables Table configuration.
+
+-- [ Markdown | Block quotes ] ------------------------------------------------------------
+
+--- Configuration for block quotes.
+---@class markdown.block_quotes
+---
+---@field enable boolean
+---
+---@field wrap? boolean | fun(buffer: integer, item: __markdown.block_quotes): boolean?
+---
+---@field default block_quotes.opts | fun(buffer: integer, item: __markdown.block_quotes): boolean?
+---@field [string] block_quotes.opts | fun(buffer: integer, item: __markdown.block_quotes): boolean?
+M.markdown_block_quotes = {
+ enable = true,
+ default = { border = "", hl = "MarkviewBlockQuoteDefault" },
+
+ ["EXAMPLE"] = { border = { "|", "^", "โข" } }
+};
+
+-- [ Markdown | Block quotes โข Static ] ---------------------------------------------------
+
+--- Static configuration for block quotes.
+---@class markdown.block_quotes_static
+---
+---@field enable boolean
+---
+---@field wrap? boolean Enables basic wrap support.
+---
+---@field default block_quotes.opts Default block quote configuration.
+---@field [string] block_quotes.opts Configuration for >[!{string}] callout.
+
+-- [ Markdown | Block quotes > Type definition ] ------------------------------------------
+
+--- Configuration options for various types of block quotes.
+---@class block_quotes.opts
+---
+---@field border string | string[] | fun(buffer: integer, item: __markdown.block_quotes): (string | string[])
+---@field border_hl? (string | string[]) | fun(buffer: integer, item: __markdown.block_quotes): (string | string[])?
+---@field hl? string | fun(buffer: integer, item: __markdown.block_quotes): string?
+---@field icon? string | fun(buffer: integer, item: __markdown.block_quotes): string?
+---@field icon_hl? string | fun(buffer: integer, item: __markdown.block_quotes): string?
+---@field preview? string | fun(buffer: integer, item: __markdown.block_quotes): string?
+---@field preview_hl? string | fun(buffer: integer, item: __markdown.block_quotes): string?
+---@field title? boolean | fun(buffer: integer, item: __markdown.block_quotes): string?
+M.block_quotes_opts = {
+ border = "|",
+ hl = "MarkviewBlockQuoteDefault",
+ icon = "ฯ",
+ preview = "ฯ Some text"
+};
+
+-- [ Markdown | Block quotes > Type definition โข Static ] ---------------------------------
+
+--- Static configuration options for various types of block quotes.
+---@class block_quotes.opts
+---
+---@field border string | string[] Text for the border.
+---@field border_hl? string | string[] Highlight group for the border.
+---@field hl? string Base highlight group for the block quote.
+---@field icon? string Icon to show before the block quote title.
+---@field icon_hl? string Highlight group for the icon.
+---@field preview? string Callout/Alert preview string(shown where >[!{string}] was).
+---@field preview_hl? string Highlight group for the preview.
+---@field title? boolean Whether the block quote can have a title or not.
+M.block_quotes_opts = {
+ border = "|",
+ hl = "MarkviewBlockQuoteDefault",
+ icon = "ฯ",
+ preview = "ฯ Some text"
+};
+
+-- [ Markdown | Block quotes > Parameters ] -----------------------------------------------
+
+---@class __markdown.block_quotes
+---
+---@field class "markdown_block_quote"
+---
+---@field callout string? Callout text(text inside `[!...]`).
+---@field title string? Title of the callout.
+---
+---@field text string[]
+---@field range __block_quotes.range
+---
+---@field __nested boolean Is the node nested?
+M.__markdown_block_quotes = {
+ class = "markdown_block_quote",
+ callout = "TIP",
+ title = "Title",
+
+ text = {
+ ">[!TIP] Title",
+ "> Something."
+ },
+ range = {
+ row_start = 0,
+ row_end = 2,
+
+ col_start = 0,
+ col_end = 0,
+
+ callout_start = 3,
+ callout_end = 6,
+
+ title_start = 8,
+ title_end = 13
+ }
+};
+
+---@class __block_quotes.range
+---
+---@field row_start integer
+---@field row_end integer
+---@field col_start integer
+---@field col_end integer
+---
+---@field callout_start? integer Start column of callout text(after `[!`).
+---@field callout_end? integer End column of callout text(before `]`).
+---@field title_start? integer Start column of the title.
+---@field title_end? integer End column of the title.
+M.__block_quotes_range = {
+ row_start = 0,
+ row_end = 2,
+
+ col_start = 0,
+ col_end = 0,
+
+ callout_start = 3,
+ callout_end = 6,
+
+ title_start = 8,
+ title_end = 13
+};
+
+-- [ Markdown | Code blocks ] -------------------------------------------------------------
+
+--- Configuration for code blocks.
+---@class markdown.code_blocks
+---
+---@field enable boolean
+---
+---@field border_hl? string | fun(buffer: integer, item: __markdown.code_blocks): string?
+---@field info_hl? string | fun(buffer: integer, item: __markdown.code_blocks): string?
+---@field label_direction? "left" | "right" | fun(buffer: integer, item: __markdown.code_blocks): ("left" | "right")
+---@field label_hl? string | fun(buffer: integer, item: __markdown.code_blocks): string?
+---@field min_width? integer | fun(buffer: integer, item: __markdown.code_blocks): integer
+---@field pad_amount? integer | fun(buffer: integer, item: __markdown.code_blocks): integer
+---@field pad_char? string | fun(buffer: integer, item: __markdown.code_blocks): string?
+---@field sign? boolean | fun(buffer: integer, item: __markdown.code_blocks): boolean
+---@field sign_hl? string | fun(buffer: integer, item: __markdown.code_blocks): string?
+---@field style "simple" | "block" | fun(buffer: integer, item: __markdown.code_blocks): ("simple" | "block")
+---
+---@field default code_blocks.opts | fun(buffer: integer, item: __markdown.code_blocks): code_blocks.opts
+---@field [string] code_blocks.opts | fun(buffer: integer, item: __markdown.code_blocks): code_blocks.opts
+M.markdown_code_blocks = {
+ style = "simple",
+ hl = "MarkviewCode"
+} or {
+ style = "block",
+ label_direction = "right",
+ min_width = 60,
+ pad_amount = 3,
+ pad_char = " "
+};
+
+-- [ Markdown | Code blocks โข Static ] ----------------------------------------------------
+
+--- Static configuration for code blocks.
+---@class markdown.code_blocks_static
+---
+---@field enable boolean
+---
+---@field border_hl? string Highlight group for the top & bottom border.
+---@field info_hl? string Highlight group for the info string.
+---@field label_direction? "left" | "right" Changes where the label is shown.
+---@field label_hl? string Highlight group for the label.
+---@field min_width? integer Minimum width of the code block.
+---@field pad_amount? integer Left & right padding size.
+---@field pad_char? string Character to use for the padding.
+---@field sign? boolean Whether to show signs for the code blocks.
+---@field sign_hl? string Highlight group for the signs.
+---@field style "simple" | "block" Preview style for code blocks.
+---
+---@field default code_blocks.opts_static Default line configuration for the code block.
+---@field [string] code_blocks.opts_static Line configuration for the code block whose `language` matches `string`
+
+-- [ Markdown | Code blocks > Type definitions ] ------------------------------------------
+
+--- Configuration for highlighting a line inside a code block.
+---@class code_blocks.opts
+---
+---@field block_hl string | fun(buffer: integer, line: string): string?
+---@field pad_hl string | fun(buffer: integer, line: string): string?
+
+--- Static configuration for highlighting a line inside a code block.
+---@class code_blocks.opts_static
+---
+---@field block_hl string? Highlight group for the background of the line.
+---@field pad_hl string? Highlight group for the padding of the line.
+
+-- [ Markdown | Code blocks > Parameters ] ------------------------------------------------
+
+---@class __markdown.code_blocks
+---
+---@field class "markdown_code_block"
+---
+---@field delimiters [ string, string ] Code block delimiters.
+---@field language string? Language string(typically after ```).
+---@field info_string string? Extra information regarding the code block.
+---
+---@field text string[]
+---@field range __code_blocks.range
+M.__markdown_code_blocks = {
+ class = "markdown_code_block",
+
+ language = "lua",
+ info_string = "lua Info string",
+
+ text = {
+ "``` lua Info string",
+ 'vim.print("Hello, Neovim!");',
+ "```"
+ },
+
+ range = {
+ row_start = 0,
+ row_end = 3,
+
+ col_start = 0,
+ col_end = 0,
+
+ language = { 0, 4, 0, 7 },
+ info_string = { 0, 4, 0, 15 }
+ }
+};
+
+---@class __code_blocks.range
+---
+---@field row_start integer
+---@field row_end integer
+---@field col_start integer
+---@field col_end integer
+---
+---@field language? integer[] Range of the language string.
+---@field info_string? integer[] Range of info string.
+M.__code_blocks_range = {
+ row_start = 0,
+ row_end = 3,
+
+ col_start = 0,
+ col_end = 0,
+
+ language = { 0, 4, 0, 7 },
+ info_string = { 0, 4, 0, 15 }
+};
+
+-- [ Markdown | Headings ] ----------------------------------------------------------------
+
+---@class markdown.headings
+---
+---@field enable boolean Enables preview of headings.
+---
+---@field heading_1 headings.atx | fun(buffer: integer, item: __markdown.atx): headings.atx
+---@field heading_2 headings.atx | fun(buffer: integer, item: __markdown.atx): headings.atx
+---@field heading_3 headings.atx | fun(buffer: integer, item: __markdown.atx): headings.atx
+---@field heading_4 headings.atx | fun(buffer: integer, item: __markdown.atx): headings.atx
+---@field heading_5 headings.atx | fun(buffer: integer, item: __markdown.atx): headings.atx
+---@field heading_6 headings.atx | fun(buffer: integer, item: __markdown.atx): headings.atx
+---
+---@field setext_1 headings.setext | fun(buffer: integer, item: __markdown.setext): headings.setext
+---@field setext_2 headings.setext | fun(buffer: integer, item: __markdown.setext): headings.setext
+---
+---@field shift_width integer Amount of spaces to add before the heading(per level).
+---
+---@field org_indent? boolean Whether to enable org-mode like section indentation.
+---@field org_shift_width? integer Shift width for org indents.
+---@field org_shift_char? string Shift char for org indent.
+---@field org_indent_wrap? boolean Whether to enable wrap support. May have severe performance issues!
+M.markdown_headings = {
+ enable = true,
+ shift_width = 1,
+
+ heading_1 = {},
+ heading_2 = {},
+ heading_3 = {},
+ heading_4 = {},
+ heading_5 = {},
+ heading_6 = {}
+};
+
+-- [ Markdown | Headings > Type definitions ] ---------------------------------------------
+
+---@class headings.atx
+---
+---@field align? "left" | "center" | "right" Label alignment.
+---@field corner_left? string Left corner.
+---@field corner_left_hl? string Highlight group for left corner.
+---@field corner_right? string Right corner.
+---@field corner_right_hl? string Highlight group for right corner.
+---@field hl? string Base Highlight group.
+---@field icon? string Icon.
+---@field icon_hl? string Highlight group for icon.
+---@field padding_left? string Left padding.
+---@field padding_left_hl? string Highlight group for left padding.
+---@field padding_right? string Right padding.
+---@field padding_right_hl? string Highlight group for right padding.
+---@field sign? string Text to show on the sign column.
+---@field sign_hl? string Highlight group for the sign.
+---@field style "simple" | "label" | "icon" Preview style.
+M.headings_atx = {
+ style = "simple",
+ hl = "MarkviewHeading1"
+} or {
+ style = "label",
+ align = "center",
+
+ padding_left = " ",
+ padding_right = " ",
+
+ hl = "MarkviewHeading1"
+} or {
+ style = "icon",
+
+ icon = "~",
+ hl = "MarkviewHeading1"
+};
+
+---@class headings.setext
+---
+---@field border string Text to use for the preview border.
+---@field border_hl? string Highlight group for the border.
+---@field hl? string Base highlight group.
+---@field icon? string Text to use for the icon.
+---@field icon_hl? string Highlight group for the icon.
+---@field sign? string Text to show in the sign column.
+---@field sign_hl? string Highlight group for the sign.
+---@field style "simple" | "decorated" Preview style.
+M.headings_setext = {
+ style = "simple",
+ hl = "MarkviewHeading1"
+} or {
+ style = "decorated",
+ border = "โ",
+ hl = "MarkviewHeading1"
+};
+
+-- [ Markdown | Headings > Parameters ] ---------------------------------------------------
+
+---@class __markdown.atx
+---
+---@field class "markdown_atx_heading"
+---
+---@field marker "#" | "##" | "###" | "####" | "#####" | "######" Heading marker.
+---
+---@field text string[]
+---@field range node.range
+M.__markdown_atx = {
+ class = "markdown_atx_heading",
+ marker = "#",
+
+ text = { "# Heading 1" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 11
+ }
+};
+
+---@class __markdown.setext
+---
+---@field class "markdown_setext_heading"
+---
+---@field marker "---" | "===" Heading marker.
+---
+---@field text string[]
+---@field range node.range
+M.__markdown_setext = {
+ class = "markdown_setext_heading",
+ marker = "---",
+ text = {
+ "Heading",
+ "---"
+ },
+ range = {
+ row_start = 0,
+ row_end = 2,
+
+ col_start = 0,
+ col_end = 3
+ }
+};
+
+-- [ Markdown | Horizontal rules ] --------------------------------------------------------
+
+--- Configuration for horizontal rules.
+---@class markdown.horizontal_rules
+---
+---@field enable boolean Enables preview of horizontal rules.
+---
+---@field parts ( horizontal_rules.text | horizontal_rules.repeating )[] Parts for the horizontal rules.
+M.markdown_horizontal_rules = {
+ enable = true,
+ parts = {};
+};
+
+-- [ Markdown | Horizontal rules > Type definitions ] -------------------------------------
+
+---@class horizontal_rules.text
+---
+---@field type "text" Part name.
+---
+---@field hl? string Highlight group for this part.
+---@field text string Text to show.
+M.hr_text = {
+ type = "text",
+
+ hl = "MarkviewPalette9",
+ text = " ฯ "
+};
+
+---@class horizontal_rules.repeating
+---
+---@field type "repeating" Part name.
+---
+---@field direction "left" | "right" Direction from which the highlight groups are applied from.
+---
+---@field repeat_amount integer | fun(buffer: integer, item: __markdown.horizontal_rules): integer How many times to repeat the text.
+---@field repeat_hl? boolean | fun(buffer: integer, item: __markdown.horizontal_rules): boolean Whether to repeat the highlight groups.
+---@field repeat_text? boolean | fun(buffer: integer, item: __markdown.horizontal_rules): boolean Whether to repeat the text.
+---
+---@field text string | string[] Text to repeat.
+---@field hl? string | string[] Highlight group for the text.
+M.hr_repeating = {
+ type = "repeating",
+
+ repeat_amount = math.floor(vim.o.columns / 2),
+ repeat_hl = false,
+ repeat_text = true,
+
+ text = "-",
+ hl = { "MarkviewPalette0", "MarkviewPalette1", "MarkviewPalette2", "MarkviewPalette3" }
+};
+
+-- [ Markdown | Horizontal rules > Parameters ] -------------------------------------------
+
+---@class __markdown.horizontal_rules
+---
+---@field class "markdown_hr"
+---@field text string[]
+---@field range node.range
+M.__markdown_hr = {
+ class = "markdown_hr",
+ text = { "---" },
+ range = {
+ row_start = 0,
+ row_end = 1,
+
+ col_start = 0,
+ col_end = 0
+ }
+};
+
+-- [ Markdown | List items ] --------------------------------------------------------------
+
+--- Configuration for list items.
+---@class markdown.list_items
+---
+---@field enable boolean
+---
+---@field indent_size integer Indentation size for list items.
+---@field shift_width integer Virtual indentation size for previewed list items.
+---
+---@field marker_dot list_items.ordered Configuration for `n.` list items.
+---@field marker_minus list_items.unordered Configuration for `-` list items.
+---@field marker_parenthesis list_items.ordered Configuration for `n)` list items.
+---@field marker_plus list_items.unordered Configuration for `+` list items.
+---@field marker_star list_items.unordered Configuration for `*` list items.
+---
+---@field wrap? boolean Enables wrap support.
+M.markdown_list_items = {
+ enable = true,
+ marker_plus = {},
+ marker_star = {},
+ marker_minus = {},
+ marker_dot = {},
+ marker_parenthesis = {}
+};
+
+-- [ Markdown | List items > Type definitions ] -------------------------------------------
+
+---@class list_items.unordered
+---
+---@field add_padding boolean
+---@field conceal_on_checkboxes? boolean
+---@field enable? boolean
+---@field hl? string
+---@field text string
+M.list_items_unordered = {
+ enable = true,
+ hl = "MarkviewListItemPlus",
+ text = "โข",
+ add_padding = true,
+ conceal_on_checkboxes = true
+};
+
+---@class list_items.ordered
+---
+---@field add_padding boolean
+---@field conceal_on_checkboxes? boolean
+---@field enable? boolean
+M.list_items_ordered = {
+ enable = true,
+ add_padding = true,
+ conceal_on_checkboxes = true
+};
+
+-- [ Markdown | List items > Parameters ] -------------------------------------------------
+
+---@class __markdown.list_items
+---
+---@field class "markdown_list_item"
+---@field candidates integer[] List of line numbers(0-indexed) from `range.row_start` that should be indented.
+---@field marker "-" | "+" | "*" | string List marker text.
+---@field checkbox? string Checkbox state(if there is a checkbox).
+---@field indent integer Spaces before the list marker.
+---@field text string[]
+---@field range node.range
+---
+---@field __block boolean Indicates whether the list item is the children of a block quote.
+M.__markdown_list_items = {
+ class = "markdown_list_item",
+ marker = "-",
+ checkbox = nil,
+ candidates = { 0 },
+
+ text = { "- List item" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 11
+ }
+};
+
+-- [ Markdown | Metadata minus ] ----------------------------------------------------------
+
+--- Configuration for YAML metadata.
+---@class markdown.metadata_minus
+---
+---@field enable boolean
+---
+---@field border_bottom? string | fun(buffer: integer, item: __markdown.metadata_minus): string?
+---@field border_bottom_hl? string | fun(buffer: integer, item: __markdown.metadata_minus): string?
+---@field border_hl? string | fun(buffer: integer, item: __markdown.metadata_minus): string?
+---@field border_top? string | fun(buffer: integer, item: __markdown.metadata_minus): string?
+---@field border_top_hl? string | fun(buffer: integer, item: __markdown.metadata_minus): string?
+---
+---@field hl? string | fun(buffer: integer, item: __markdown.metadata_minus): string?
+M.markdown_metadata_minus = {
+ enable = true,
+ hl = "MarkviewCode"
+};
+
+-- [ Markdown | Metadata minus โข Static ] -------------------------------------------------
+
+--- Static configuration for YAML metadata.
+---@class markdown.metadata_minus_static
+---
+---@field enable boolean
+---
+---@field border_bottom? string Bottom border.
+---@field border_bottom_hl? string Highlight group for the bottom border.
+---@field border_hl? string Primary highlight group for the borders.
+---@field border_top? string Top border.
+---@field border_top_hl? string Highlight group for the top border.
+---
+---@field hl? string Background highlight group.
+
+-- [ Markdown | Metadata minus > Parameters ] ---------------------------------------------
+
+---@class __markdown.metadata_minus
+---
+---@field class "markdown_metadata_minus"
+---@field text string[]
+---@field range node.range
+M.__markdown_metadata_minus = {
+ class = "markdown_metadata_minus",
+
+ text = {
+ "---",
+ "author: OXY2DEV",
+ "---"
+ },
+ range = {
+ row_start = 0,
+ row_end = 2,
+
+ col_start = 0,
+ col_end = 3
+ }
+};
+
+-- [ Markdown | Metadata plus ] -----------------------------------------------------------
+
+--- Configuration for TOML metadata.
+---@class markdown.metadata_plus
+---
+---@field enable boolean
+---
+---@field border_bottom? string | fun(buffer: integer, item: __markdown.metadata_plus): string?
+---@field border_bottom_hl? string | fun(buffer: integer, item: __markdown.metadata_plus): string?
+---@field border_hl? string | fun(buffer: integer, item: __markdown.metadata_plus): string?
+---@field border_top? string | fun(buffer: integer, item: __markdown.metadata_plus): string?
+---@field border_top_hl? string | fun(buffer: integer, item: __markdown.metadata_plus): string?
+---
+---@field hl? string | fun(buffer: integer, item: __markdown.metadata_plus): string?
+M.markdown_metadata_plus = {
+ enable = true,
+ hl = "MarkviewCode"
+};
+
+-- [ Markdown | Metadata plus โข Static ] --------------------------------------------------
+
+--- Static configuration for TOML metadata.
+---@class markdown.metadata_plus_static
+---
+---@field enable boolean
+---
+---@field border_bottom? string Bottom border.
+---@field border_bottom_hl? string Highlight group for the bottom border.
+---@field border_hl? string Primary highlight group for the borders.
+---@field border_top? string Top border.
+---@field border_top_hl? string Highlight group for the top border.
+---
+---@field hl? string Background highlight group.
+
+-- [ Markdown | Metadata plus > Parameters ] ----------------------------------------------
+
+---@class __markdown.metadata_plus
+---
+---@field class "markdown_metadata_plus"
+---@field text string[]
+---@field range node.range
+M.__markdown_metadata_plus = {
+ class = "markdown_metadata_plus",
+
+ text = {
+ "---",
+ "author: OXY2DEV",
+ "---"
+ },
+ range = {
+ row_start = 0,
+ row_end = 2,
+
+ col_start = 0,
+ col_end = 3
+ }
+};
+
+-- [ Markdown | Reference definitions ] ---------------------------------------------------
+
+--- Configuration for reference definitions.
+---@class markdown.reference_definitions
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for reference definitions.
+---@field [string] config.inline_generic Configuration for reference definitions whose description matches `string`.
+M.markdown_ref_def = {
+ enable = true,
+ default = { hl = "Title" },
+ ["^mkv"] = {
+ hl = "Special"
+ }
+};
+
+-- [ Markdown | Reference definitions > Parameters ] --------------------------------------
+
+---@class __markdown.reference_definitions
+---
+---@field class "markdown_link_ref_definition"
+---
+---@field label? string Visible part of the reference link definition.
+---@field description? string Description of the reference link.
+---
+---@field text string[]
+---@field range __reference_definitions.range
+M.__markdown_reference_definitions = {
+ class = "markdown_link_ref_definition",
+ label = "nvim",
+ description = "https://www.neovim.org",
+
+ text = {
+ "[nvim]:",
+ "https://www.neovim.org"
+ },
+ range = {
+ row_start = 0,
+ row_end = 1,
+
+ col_start = 0,
+ col_end = 21,
+
+ label = { 0, 0, 0, 7 },
+ description = { 1, 0, 1, 21 }
+ }
+};
+
+---@class __reference_definitions.range
+---
+---@field row_start integer
+---@field row_end integer
+---@field col_start integer
+---@field col_end integer
+---
+---@field label integer[] Range of the label node(result of `TSNode:range()`).
+---@field description? integer[] Range of the description node. Same as `label`.
+M.__reference_definitions_range = {
+ row_start = 0,
+ row_end = 1,
+
+ col_start = 0,
+ col_end = 21,
+
+ label = { 0, 0, 0, 7 },
+ description = { 1, 0, 1, 21 }
+};
+
+-- [ Markdown | Tables ] ------------------------------------------------------------------
+
+--- Configuration for tables.
+---@class markdown.tables
+---
+---@field enable boolean
+---
+---@field block_decorator boolean
+---@field use_virt_lines boolean
+---
+---@field hl tables.parts | fun(buffer: integer, item: __markdown.tables): tables.parts
+---@field parts tables.parts | fun(buffer: integer, item: __markdown.tables): tables.parts
+M.markdown_tables = {
+ parts = {},
+ enable = true,
+ hl = {},
+ block_decorator = true,
+ use_virt_lines = true
+};
+
+-- [ Markdown | Tables โข Static ] ---------------------------------------------------------
+
+--- Static configuration for tables.
+---@class markdown.tables_static
+---
+---@field enable boolean
+---
+---@field block_decorator boolean Whether to draw top & bottom border.
+---@field use_virt_lines boolean Whether to use virtual lines for the borders.
+---
+---@field hl tables.parts Highlight groups for the parts.
+---@field parts tables.parts Parts for the table.
+
+-- [ Markdown | Tables > Type definitions ] -----------------------------------------------
+
+--- Parts that make the previewed table.
+---@class tables.parts
+---
+---@field align_center [ string, string ]
+---@field align_left string
+---@field align_right string
+---@field top string[]
+---@field header string[]
+---@field separator string[]
+---@field row string[]
+---@field bottom string[]
+---@field overlap string[]
+M.tables_parts = {
+ align_center = { "" },
+ row = { "", "", "" },
+ top = { "", "", "", "" },
+ bottom = { "", "", "", "" },
+ header = { "", "", "" },
+ overlap = { "", "", "", "" },
+ separator = { "", "", "" },
+ align_left = "",
+ align_right = ""
+};
+
+-- [ Markdown | Tables > Parameters ] -----------------------------------------------------
+
+---@class __markdown.tables
+---
+---@field class "markdown_table"
+---
+---@field top_border boolean Can we draw the top border?
+---@field bottom_border boolean Can we draw the bottom border?
+---@field border_overlap boolean Is the table's borders overlapping another table?
+---
+---@field alignments ( "left" | "center" | "right" | "default" )[] Text alignments.
+---@field header __tables.cell[]
+---@field separator __tables.cell[]
+---@field rows __tables.cell[][]
+---
+---@field text string[]
+---@field range node.range
+M.__markdown_tables = {
+ class = "markdown_table",
+
+ top_border = true,
+ bottom_border = true,
+ border_overlap = false,
+
+ alignments = { "default", "default", "default" },
+ header = {
+ {
+ class = "separator",
+ text = "|",
+ col_start = 0,
+ col_end = 1
+ },
+ {
+ class = "column",
+ text = " Col 1 ",
+ col_start = 2,
+ col_end = 9
+ },
+ {
+ class = "separator",
+ text = "|",
+ col_start = 10,
+ col_end = 11
+ },
+ {
+ class = "column",
+ text = " Col 2 ",
+ col_start = 12,
+ col_end = 19
+ },
+ {
+ class = "separator",
+ text = "|",
+ col_start = 20,
+ col_end = 21
+ }
+ },
+ separator = {
+ {
+ class = "separator",
+ text = "|",
+ col_start = 0,
+ col_end = 1
+ },
+ {
+ class = "column",
+ text = " ----- ",
+ col_start = 2,
+ col_end = 9
+ },
+ {
+ class = "separator",
+ text = "|",
+ col_start = 10,
+ col_end = 11
+ },
+ {
+ class = "column",
+ text = " ----- ",
+ col_start = 12,
+ col_end = 19
+ },
+ {
+ class = "separator",
+ text = "|",
+ col_start = 20,
+ col_end = 21
+ }
+ },
+ rows = {
+ {
+ {
+ class = "separator",
+ text = "|",
+ col_start = 0,
+ col_end = 1
+ },
+ {
+ class = "column",
+ text = " Cell 1 ",
+ col_start = 2,
+ col_end = 10
+ },
+ {
+ class = "separator",
+ text = "|",
+ col_start = 11,
+ col_end = 12
+ },
+ {
+ class = "column",
+ text = " Cell 2 ",
+ col_start = 13,
+ col_end = 21
+ },
+ {
+ class = "separator",
+ text = "|",
+ col_start = 22,
+ col_end = 23
+ }
+ }
+ },
+
+ text = {
+ "| Col 1 | Col 2 |",
+ "| ----- | ----- |",
+ "| Cell 1 | Cell 2 |"
+ }
+};
+
+---@class __tables.cell
+---
+---@field class "separator" | "column" | "missing_separator"
+---
+---@field text string
+---
+---@field col_start integer
+---@field col_end integer
+M.__tables_cell = {
+ class = "separator",
+ text = "|",
+ col_start = 0,
+ col_end = 1
+};
+
+-- [ Markdown | Misc ] --------------------------------------------------------------------
+
+---@class __markdown.checkboxes
+---
+---@field class "markdown_checkbox"
+---@field state string State of the checkbox(text inside `[]`).
+---@field text string[],
+---@field range node.range
+M.__markdown_checkboxes = {
+ class = "markdown_checkbox",
+ state = " ",
+ text = { "[ ]" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 2,
+ col_end = 5
+ }
+};
+
+---@class __markdown.sections
+---
+---@field class "markdown_section"
+---@field level integer
+---@field text string[]
+---@field range node.range
+M.__markdown_sections = {
+ class = "markdown_section",
+
+ text = {
+ "# header",
+ "",
+ "Some text"
+ },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 9
+ }
+};
+
+return M;
diff --git a/lua/definitions/markdown_inline.lua b/lua/definitions/markdown_inline.lua
new file mode 100644
index 0000000..5b0471f
--- /dev/null
+++ b/lua/definitions/markdown_inline.lua
@@ -0,0 +1,754 @@
+---@meta
+
+local M = {};
+
+-- [ Markview | Inline ] ------------------------------------------------------------------
+
+--- Configuration for inline markdown.
+---@class config.markdown_inline
+---
+---@field enable boolean
+---
+---@field block_references inline.block_references | fun(): inline.block_references
+---@field checkboxes inline.checkboxes | fun(): inline.checkboxes
+---@field emails inline.emails | fun(): inline.emails
+---@field embed_files inline.embed_files | fun(): inline.embed_files
+---@field emoji_shorthands inline.emojis | fun(): inline.emojis
+---@field entities inline.entities | fun(): inline.entities
+---@field escapes inline.escapes | fun(): inline.escapes
+---@field footnotes inline.footnotes | fun(): inline.footnotes
+---@field highlights inline.highlights | fun(): inline.highlights
+---@field hyperlinks inline.hyperlinks | fun(): inline.hyperlinks
+---@field images inline.images | fun(): inline.images
+---@field inline_codes inline.inline_codes | fun(): inline.inline_codes
+---@field internal_links inline.internal_links | fun(): inline.internal_links
+---@field uri_autolinks inline.uri_autolinks | fun(): inline.uri_autolinks
+M.markdown_inline = {
+ enable = true,
+
+ block_references = {},
+ checkboxes = {},
+ emails = {},
+ embed_files = {},
+ emoji_shorthands = {},
+ entities = {},
+ escapes = {},
+ footnotes = {},
+ highlights = {},
+ hyperlinks = {},
+ images = {},
+ inline_codes = {},
+ internal_links = {},
+ uri_autolinks = {},
+};
+
+-- [ Markview | Inline โข Static ] ---------------------------------------------------------
+
+--- Static configuration for inline markdown.
+---@class config.markdown_inline_static
+---
+---@field enable boolean
+---
+---@field block_references inline.block_references Block reference link configuration.
+---@field checkboxes inline.checkboxes Checkbox configuration.
+---@field inline_codes inline.inline_codes Inline code/code span configuration.
+---@field emails inline.emails Email link configuration.
+---@field embed_files inline.embed_files Embed file link configuration.
+---@field emoji_shorthands inline.emojis Github styled emoji shorthands.
+---@field entities inline.entities HTML entities configuration.
+---@field escapes inline.escapes Escaped characters configuration.
+---@field footnotes inline.footnotes Footnotes configuration.
+---@field highlights inline.highlights Highlighted text configuration.
+---@field hyperlinks inline.hyperlinks Hyperlink configuration.
+---@field images inline.images Image link configuration.
+---@field internal_links inline.internal_links Internal link configuration.
+---@field uri_autolinks inline.uri_autolinks URI autolink configuration.
+
+-- [ Inline | Block references ] ----------------------------------------------------------
+
+--- Configuration for block reference links.
+---@class inline.block_references
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __inline.block_references): config.inline_generic
+---@field [string] config.inline_generic | fun(buffer: integer, item: __inline.block_references): config.inline_generic
+M.inline_block_ref = {
+ enable = true,
+ default = {},
+ ["^obs"] = {
+ hl = "Special"
+ }
+};
+
+-- [ Inline | Block references โข Static ] -------------------------------------------------
+
+--- Static configuration for block reference links.
+---@class inline.block_references
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for block reference links.
+---@field [string] config.inline_generic Configuration for block references whose label matches with the key's pattern.
+
+-- [ Inline | Block references > Parameters ] ---------------------------------------------
+
+---@class __inline.block_references
+---
+---@field class "inline_link_block_ref"
+---
+---@field file? string File name.
+---@field block string Block ID.
+---
+---@field label string
+---
+---@field text string[]
+---@field range inline_link.range
+M.__inline_block_references = {
+ class = "inline_link_block_ref",
+
+ file = "Some_file.md",
+ block = "Block",
+ label = "Some_file.md#^Block",
+
+ text = { "![[Some_file.md#^Block]]" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 25,
+
+ label = { 0, 3, 0, 23 },
+ file = { 0, 3, 0, 12 },
+ block = { 0, 14, 0, 23 }
+ }
+};
+
+
+-- [ Inline | Checkboxes ] ----------------------------------------------------------------
+
+--- Configuration for checkboxes.
+---@class inline.checkboxes
+---
+---@field enable boolean
+---
+---@field checked checkboxes.opts Configuration for [x] & [X].
+---@field unchecked checkboxes.opts Configuration for [ ].
+---
+---@field [string] checkboxes.opts
+M.inline_checkboxes = {
+ enable = true,
+ checked = {},
+ unchecked = {},
+ ["-"] = {}
+}
+
+---@class checkboxes.opts
+---
+---@field text string
+---@field hl? string
+---@field scope_hl? string Highlight group for the list item.
+M.checkboxes_opts = {
+ text = "โ",
+ hl = "MarkviewCheckboxChecked"
+};
+
+-- [ Inline | Checkboxes > Parameters ] ---------------------------------------------------
+
+---@class __inline.checkboxes
+---
+---@field class "inline_checkbox"
+---@field state string Checkbox state(text inside `[]`).
+---
+---@field text string[]
+---@field range? node.range Range of the checkbox. `nil` when rendering list items.
+M.__inline_checkboxes = {
+ class = "inline_checkbox",
+ state = "-",
+
+ text = { "[-]" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 2,
+ col_end = 5
+ }
+};
+
+-- [ Inline | Emails ] --------------------------------------------------------------------
+
+--- Configuration for emails.
+---@class inline.emails
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __inline.emails): config.inline_generic
+---@field [string] config.inline_generic | fun(buffer: integer, item: __inline.emails): config.inline_generic
+M.inline_emails = {
+ enable = true,
+ default = {},
+ ["teams"] = {
+ hl = "Special"
+ }
+};
+
+-- [ Inline | Emails โข Static ] -----------------------------------------------------------
+
+--- Static configuration for emails.
+---@class inline.emails
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for emails
+---@field [string] config.inline_generic Configuration for emails whose label(address) matches `string`.
+
+-- [ Inline | Emails > Parameters ] -------------------------------------------------------
+
+---@class __inline.emails
+---
+---@field class "inline_link_email"
+---@field label string
+---@field text string[]
+---@field range inline_link.range
+M.__inline_link_emails = {
+ class = "inline_link_email",
+ label = "example@mail.com",
+
+ text = { "" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 17,
+
+ label = { 0, 1, 0, 16 }
+ }
+};
+
+-- [ Inline | Embed files ] ---------------------------------------------------------------
+
+--- Configuration for obsidian's embed files.
+---@class inline.embed_files
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __inline.embed_files): inline.embed_files
+---@field [string] config.inline_generic | fun(buffer: integer, item: __inline.embed_files): inline.embed_files
+M.inline_embed_files = {
+ enable = true,
+ default = {},
+ ["img$"] = {
+ hl = "Special"
+ }
+};
+
+-- [ Inline | Embed files โข Static ] ------------------------------------------------------
+
+--- Static configuration for obsidian's embed files.
+---@class inline.embed_files
+---
+---@field enable boolean
+---
+---@field default config.inline_generic_static Default configuration for embed file links.
+---@field [string] config.inline_generic_static Configuration for embed file links whose label matches `string`.
+
+-- [ Inline | Embed files > Parameters ] --------------------------------------------------
+
+---@class __inline.embed_files
+---
+---@field class "inline_link_embed_file"
+---
+---@field label string Text inside `[[...]]`.
+---
+---@field text string[]
+---@field range node.range
+M.__inline_link_embed_files = {
+ class = "inline_link_embed_file",
+ label = "v25",
+
+ text = { "![[v25]]" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 8
+ }
+};
+
+-- [ Inline | Emojis ] ------------------------------------------------------------------
+
+--- Configuration for emoji shorthands.
+---@class inline.emojis
+---
+---@field enable boolean
+---
+---@field hl? string | fun(buffer: integer, item: __inline.entities): inline.emojis
+M.inline_emojis = {
+ enable = true,
+ hl = "Comment"
+};
+
+-- [ Inline | Emojis โข Static ] ---------------------------------------------------------
+
+--- Static configuration for emoji shorthands.
+---@class inline.emojis_static
+---
+---@field enable boolean
+---
+---@field hl? string Highlight group for the emoji.
+
+-- [ Inline | Emojis > Parameters ] --------------------------------------------------------
+
+---@class __inline.emojis
+---
+---@field class "inline_emoji"
+---
+---@field name string Emoji name(without `:`).
+---
+---@field text string[]
+---@field range node.range
+M.__inline_emojis = {
+ class = "inline_emoji",
+ name = "label",
+ text = { ":label:" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 7
+ }
+};
+
+-- [ Inline | Entities ] ------------------------------------------------------------------
+
+--- Configuration for HTML entities.
+---@class inline.entities
+---
+---@field enable boolean
+---
+---@field hl? string | fun(buffer: integer, item: __inline.entities): inline.entities
+M.inline_entities = {
+ enable = true,
+ hl = "Comment"
+};
+
+-- [ Inline | Entities โข Static ] ---------------------------------------------------------
+
+--- Static configuration for HTML entities.
+---@class inline.entities_static
+---
+---@field enable boolean
+---
+---@field hl? string Highlight group for the symbol.
+
+-- [ Inline | Entities > Parameters ] ------------------------------------------------------
+
+---@class __inline.entities
+---
+---@field class "inline_entity"
+---
+---@field name string Entity name(text after "\")
+---
+---@field text string[]
+---@field range node.range
+M.__inline_entities = {
+ class = "inline_entity",
+ name = "Int",
+ text = { "∬" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 5
+ }
+};
+
+-- [ Inline | Escapes ] -------------------------------------------------------------------
+
+--- Configuration for escaped characters.
+---@alias inline.escapes { enable: boolean }
+
+-- [ Inline | Escapes > Parameters ] ------------------------------------------------------
+
+---@class __inline.escapes
+---
+---@field class "inline_escaped"
+---
+---@field text string[]
+---@field range node.range
+M.__inline_escaped = {
+ class = "inline_escaped",
+
+ text = { "\\'" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 2
+ }
+};
+
+-- [ Inline | Footnotes ] -----------------------------------------------------------------
+
+--- Configuration for footnotes.
+---@class inline.footnotes
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __inline.footnotes): inline.footnotes
+---@field [string] config.inline_generic | fun(buffer: integer, item: __inline.footnotes): inline.footnotes
+M.inline_footnotes = {
+ enable = true,
+
+ default = {},
+
+ ["^from"] = {
+ match_string = "^from",
+ hl = "Special"
+ }
+};
+
+-- [ Inline | Footnotes โข Static ] --------------------------------------------------------
+
+--- Static configuration for footnotes.
+---@class inline.footnotes_static
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for footnotes.
+---@field [string] config.inline_generic Configuration for footnotes whose label matches `string`.
+
+-- [ Inline | Footnotes > Parameters ] ----------------------------------------------------
+
+---@class __inline.footnotes
+---
+---@field class "inline_footnotes"
+---@field label string
+---@field text string[]
+---@field range inline_link.range
+M.__inline_footnotes = {
+ class = "inline_footnotes",
+ label = "1",
+
+ text = { "[^1]" },
+ range = {
+ label = { 0, 2, 0, 3 },
+
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 4
+ }
+};
+
+-- [ Inline | Highlights ] ----------------------------------------------------------------
+
+--- Configuration for highlighted texts.
+---@class inline.highlights
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __inline.highlights): inline.highlights
+---@field [string] config.inline_generic | fun(buffer: integer, item: __inline.highlights): inline.highlights
+M.inline_highlights = {
+ enable = true,
+
+ default = {},
+
+ ["^!"] = {
+ hl = "Special"
+ }
+};
+
+-- [ Inline | Highlights โข Static ] -------------------------------------------------------
+
+--- Static configuration for highlighted texts.
+---@class inline.highlights
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for highlighted text.
+---@field [string] config.inline_generic Configuration for highlighted text that matches `string`.
+
+-- [ Inline | Highlights > Parameters ] ---------------------------------------------------
+
+---@class __inline.highlights
+---
+---@field class "inline_highlight"
+---@field text string[]
+---@field range node.range
+M.__inline_highlights = {
+ class = "inline_highlight",
+
+ text = { "==Highlight==" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 13
+ }
+};
+
+-- [ Inline | Hyperlinks ] ----------------------------------------------------------------
+
+--- Configuration for hyperlinks.
+---@class inline.hyperlinks
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __inline.hyperlinks): inline.hyperlinks
+---@field [string] config.inline_generic | fun(buffer: integer, item: __inline.hyperlinks): inline.hyperlinks
+M.inline_hyperlinks = {
+ enable = true,
+ default = {},
+ ["^neovim%.org"] = {
+ hl = "Special"
+ }
+};
+
+-- [ Inline | Hyperlinks โข Static ] -------------------------------------------------------
+
+--- Static configuration for hyperlinks.
+---@class inline.hyperlinks_static
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for hyperlinks.
+---@field [string] config.inline_generic Configuration for links whose description matches `string`.
+
+-- [ Inline | Hyperlinks > Parameters ] ---------------------------------------------------
+
+---@class __inline.hyperlinks
+---
+---@field class "inline_link_hyperlink"
+---
+---@field label? string
+---@field description? string
+---
+---@field text string[]
+---@field range inline_link.range
+M.__inline_hyperlinks = {
+ class = "inline_link_hyperlink",
+
+ label = "link",
+ description = "test.svg",
+
+ text = { "[link](example.md)" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 18,
+
+ label = { 0, 1, 0, 5 },
+ description = { 0, 7, 0, 16 }
+ }
+};
+
+-- [ Inline | Images ] --------------------------------------------------------------------
+
+--- Configuration for image links.
+---@class inline.images
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(vuffer: integer, item: __inline.images): inline.images
+---@field [string] config.inline_generic | fun(vuffer: integer, item: __inline.images): inline.images
+M.inline_images = {
+ enable = true,
+ default = {},
+ ["svg$"] = {
+ hl = "Special"
+ }
+};
+
+-- [ Inline | Images โข Static ] -----------------------------------------------------------
+
+--- Static configuration for image links.
+---@class inline.images_static
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for image links
+---@field [string] config.inline_generic Configuration image links whose description matches `string`.
+
+-- [ Inline | Images > Parameters ] -------------------------------------------------------
+
+---@class __inline.images
+---
+---@field class "inline_link_image"
+---@field label? string
+---@field description? string
+---@field text string[]
+---@field range inline_link.range
+M.__inline_images = {
+ class = "inline_link_image",
+ label = "image",
+ description = "test.svg",
+
+ text = { "" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 18,
+
+ label = { 0, 2, 0, 7 },
+ description = { 0, 9, 0, 17 }
+ }
+};
+
+
+-- [ Inline | Inline codes ] --------------------------------------------------------------
+
+--- Configuration for inline codes.
+---@alias inline.inline_codes config.inline_generic
+
+-- [ Inline | Inline codes โข Static ] -----------------------------------------------------
+
+--- Static configuration for inline codes.
+---@alias inline.inline_codes_static config.inline_generic_static
+
+-- [ Inline | Inline codes > Parameters ] -------------------------------------------------
+
+---@class __inline.inline_codes
+---
+---@field class "inline_code_span"
+---@field text string[]
+---@field range node.range
+M.__inline_inline_codes = {
+ class = "inline_code_span",
+ text = { "`inline code`" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 13
+ }
+};
+
+-- [ Inline | Internal links ] ------------------------------------------------------------
+
+--- Configuration for obsidian's internal links.
+---@class inline.internal_links
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __inline.internal_links): config.inline_generic
+---@field [string] config.inline_generic | fun(buffer: integer, item: __inline.internal_links): config.inline_generic
+M.inline_internal_links = {
+ enable = true,
+ default = {},
+ ["^vault"] = {
+ match_string = "^vault",
+ hl = "Special"
+ }
+};
+
+-- [ Inline | Internal links โข Static ] ---------------------------------------------------
+
+--- Configuration for obsidian's internal links.
+---@class inline.internal_links_static
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for internal links.
+---@field [string] config.inline_generic Configuration for internal links whose label match `string`.
+
+-- [ Inline | Internal links > Parameters ] ------------------------------------------------------------
+
+---@class __inline.internal_links
+---
+---@field class "inline_link_internal"
+---
+---@field alias? string
+---@field label string Text inside `[[...]]`.
+---
+---@field text string[]
+---@field range inline_link.range
+M.__inline_internal_links = {
+ class = "inline_link_internal",
+
+ alias = "Alias",
+ label = "v25|Alias",
+
+ text = { "[[v25|alias]]" },
+ range = {
+ alias = { 0, 6, 0, 11 },
+ label = { 0, 2, 0, 11 },
+
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 13
+ }
+};
+
+-- [ Inline | URI autolinks ] ------------------------------------------------------------
+
+--- Configuration for uri autolinks.
+---@class inline.uri_autolinks
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __inline.uri_autolinks): config.inline_generic
+---@field [string] config.inline_generic | fun(buffer: integer, item: __inline.uri_autolinks): config.inline_generic
+M.inline_uri_autolinks = {
+ enable = true,
+ default = {},
+ ["^https"] = {
+ match_string = "^https",
+ hl = "Special"
+ }
+};
+
+-- [ Inline | URI autolinks โข Static ] ---------------------------------------------------
+
+--- Static configuration for uri autolinks.
+---@class inline.uri_autolinks_static
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for URI autolinks.
+---@field [string] config.inline_generic Configuration for URI autolinks whose label match `string`.
+
+-- [ Inline | URI autolinks > Parameters ] ------------------------------------------------
+
+---@class __inline.uri_autolinks
+---
+---@field class "inline_link_uri_autolinks"
+---
+---@field label string
+---
+---@field text string[]
+---@field range inline_link.range
+M.__inline_uri_autolinks = {
+ class = "inline_link_uri_autolinks",
+ label = "https://example.com",
+
+ text = { "" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 21,
+
+ label = { 0, 1, 0, 20 }
+ }
+};
+
+return M;
diff --git a/lua/definitions/preview.lua b/lua/definitions/preview.lua
new file mode 100644
index 0000000..c78142a
--- /dev/null
+++ b/lua/definitions/preview.lua
@@ -0,0 +1,522 @@
+---@meta
+
+local M = {};
+
+-- [ Markview | Preview options ] ---------------------------------------------------------
+
+--- Preview configuration for `markview.nvim`.
+---@class config.preview
+---
+--- Enables *preview* when attaching to new buffers.
+---@field enable? boolean
+--- Enables `hybrid mode` when attaching to new buffers.
+---@field enable_hybrid_mode? boolean
+---
+--- Icon provider.
+---@field icon_provider?
+---| "internal" Internal icon provider.
+---| "devicons" `nvim-web-devicons` as icon provider.
+---| "mini" `mini.icons` as icon provider.
+---
+--- Callback functions.
+---@field callbacks? preview.callbacks
+--- VIM-modes where `hybrid mode` is enabled.
+---@field hybrid_modes? string[]
+--- Options that should/shouldn't be previewed in `hybrid_modes`.
+---@field ignore_previews? preview.ignore
+--- Clear lines around the cursor in `hybrid mode`, instead of nodes?
+---@field linewise_hybrid_mode? boolean
+--- VIM-modes where previews will be shown.
+---@field modes? string[]
+---
+--- Debounce delay for updating previews.
+---@field debounce? integer
+--- Buffer filetypes where the plugin should attach.
+---@field filetypes? string[]
+--- Buftypes that should be ignored(e.g. nofile).
+---@field ignore_buftypes? string[]
+--- Maximum number of lines a buffer can have before switching to partial rendering.
+---@field max_buf_lines? integer
+---
+--- Lines before & after the cursor that is considered being edited.
+--- Edited content isn't rendered.
+---@field edit_range? [ integer, integer ]
+--- Lines before & after the cursor that is considered being previewed.
+---@field draw_range? [ integer, integer ]
+---
+--- Window options for the `splitview` window.
+--- See `:h nvim.open_win()`.
+---@field splitview_winopts? table
+M.preview = {
+ ---+${conf}
+
+ enable = true,
+
+ callbacks = {
+ ---+${func}
+
+ on_attach = function (_, wins)
+ ---+${lua}
+
+ --- Initial state for attached buffers.
+ ---@type string
+ local attach_state = spec.get({ "preview", "enable" }, { fallback = true, ignore_enable = true });
+
+ if attach_state == false then
+ --- Attached buffers will not have their previews
+ --- enabled.
+ --- So, don't set options.
+ return;
+ end
+
+ for _, win in ipairs(wins) do
+ --- Preferred conceal level should
+ --- be 3.
+ vim.wo[win].conceallevel = 3;
+ end
+
+ ---_
+ end,
+
+ on_detach = function (_, wins)
+ ---+${lua}
+ for _, win in ipairs(wins) do
+ --- Only set `conceallevel`.
+ --- `concealcursor` will be
+ --- set via `on_hybrid_disable`.
+ vim.wo[win].conceallevel = 0;
+ end
+ ---_
+ end,
+
+ on_enable = function (_, wins)
+ ---+${lua}
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].conceallevel = 3;
+ end
+
+ ---_
+ end,
+
+ on_disable = function (_, wins)
+ ---+${lua}
+ for _, win in ipairs(wins) do
+ vim.wo[win].conceallevel = 0;
+ end
+ ---_
+ end,
+
+ on_hybrid_enable = function (_, wins)
+ ---+${lua}
+
+ ---@type string[]
+ local prev_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ ---@type string[]
+ local hybd_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
+
+ local concealcursor = "";
+
+ for _, mode in ipairs(prev_modes) do
+ if vim.list_contains(hybd_modes, mode) == false and vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].concealcursor = concealcursor;
+ end
+
+ ---_
+ end,
+
+ on_hybrid_disable = function (_, wins)
+ ---+${lua}
+
+ ---@type string[]
+ local prev_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ local concealcursor = "";
+
+ for _, mode in ipairs(prev_modes) do
+ if vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].concealcursor = concealcursor;
+ end
+
+ ---_
+ end,
+
+ on_mode_change = function (_, wins, current_mode)
+ ---+${lua}
+
+ ---@type string[]
+ local preview_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ ---@type string[]
+ local hybrid_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
+
+ local concealcursor = "";
+
+ for _, mode in ipairs(preview_modes) do
+ if vim.list_contains(hybrid_modes, mode) == false and vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ if vim.list_contains(preview_modes, current_mode) then
+ vim.wo[win].conceallevel = 3;
+ vim.wo[win].concealcursor = concealcursor;
+ else
+ vim.wo[win].conceallevel = 0;
+ vim.wo[win].concealcursor = "";
+ end
+ end
+ ---_
+ end,
+
+ on_splitview_open = function (_, _, win)
+ ---+${lua}
+ vim.wo[win].conceallevel = 3;
+ vim.wo[win].concealcursor = "n";
+ ---_
+ end
+ ---_
+ },
+ debounce = 150,
+ icon_provider = "internal",
+
+ draw_range = { 2 * vim.o.lines, 2 * vim.o.lines },
+ edit_range = { 0, 0 },
+
+ modes = { "n", "no", "c" },
+ hybrid_modes = {},
+ linewise_hybrid_mode = false,
+ max_buf_lines = 1000,
+
+ filetypes = { "markdown", "quarto", "rmd", "typst" },
+ ignore_buftypes = { "nofile" },
+ ignore_previews = {},
+
+ splitview_winopts = {
+ split = "right"
+ }
+
+ ---_
+};
+
+-- [ Markview | Preview options > Callbacks ] ---------------------------------------------
+
+--- Callback functions for specific events.
+---@class preview.callbacks
+---
+--- Called when attaching to a buffer.
+---@field on_attach? fun(buf: integer, wins: integer[]): nil
+--- Called when detaching from a buffer.
+---@field on_detach? fun(buf: integer, wins: integer[]): nil
+---
+--- Called when disabling preview of a buffer.
+--- Also called when opening `splitview`.
+---@field on_disable? fun(buf: integer, wins: integer[]): nil
+--- Called when enabling preview of a buffer.
+--- Also called when disabling `splitview`.
+---@field on_enable? fun(buf: integer, wins: integer[]): nil
+---
+--- Called when disabling hybrid mode in a buffer.
+--- > Called after `on_attach` when attaching to a buffer.
+--- > Called after `on_disable`.
+---@field on_hybrid_disable? fun(buf: integer, wins: integer[]): nil
+--- Called when enabling hybrid mode in a buffer.
+--- > Called after `on_attach`(if `hybrid_mod` is disabled).
+--- > Called after `on_enable`.
+---@field on_hybrid_enable? fun(buf: integer, wins: integer[]): nil
+---
+--- Called when changing VIM-modes(only on active buffers).
+---@field on_mode_change? fun(buf: integer, wins: integer[], mode: string): nil
+---
+--- Called before closing splitview.
+---@field on_splitview_close? fun(source: integer, preview_buf: integer, preview_win: integer): nil
+--- Called when opening splitview.
+---@field on_splitview_open? fun(source: integer, preview_buf: integer, preview_win: integer): nil
+M.preview_callbacks = {
+ ---+${func}
+
+ on_attach = function (_, wins)
+ ---+${lua}
+
+ --- Initial state for attached buffers.
+ ---@type string
+ local attach_state = spec.get({ "preview", "enable" }, { fallback = true, ignore_enable = true });
+
+ if attach_state == false then
+ --- Attached buffers will not have their previews
+ --- enabled.
+ --- So, don't set options.
+ return;
+ end
+
+ for _, win in ipairs(wins) do
+ --- Preferred conceal level should
+ --- be 3.
+ vim.wo[win].conceallevel = 3;
+ end
+
+ ---_
+ end,
+
+ on_detach = function (_, wins)
+ ---+${lua}
+ for _, win in ipairs(wins) do
+ --- Only set `conceallevel`.
+ --- `concealcursor` will be
+ --- set via `on_hybrid_disable`.
+ vim.wo[win].conceallevel = 0;
+ end
+ ---_
+ end,
+
+ on_enable = function (_, wins)
+ ---+${lua}
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].conceallevel = 3;
+ end
+
+ ---_
+ end,
+
+ on_disable = function (_, wins)
+ ---+${lua}
+ for _, win in ipairs(wins) do
+ vim.wo[win].conceallevel = 0;
+ end
+ ---_
+ end,
+
+ on_hybrid_enable = function (_, wins)
+ ---+${lua}
+
+ ---@type string[]
+ local prev_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ ---@type string[]
+ local hybd_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
+
+ local concealcursor = "";
+
+ for _, mode in ipairs(prev_modes) do
+ if vim.list_contains(hybd_modes, mode) == false and vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].concealcursor = concealcursor;
+ end
+
+ ---_
+ end,
+
+ on_hybrid_disable = function (_, wins)
+ ---+${lua}
+
+ ---@type string[]
+ local prev_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ local concealcursor = "";
+
+ for _, mode in ipairs(prev_modes) do
+ if vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].concealcursor = concealcursor;
+ end
+
+ ---_
+ end,
+
+ on_mode_change = function (_, wins, current_mode)
+ ---+${lua}
+
+ ---@type string[]
+ local preview_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ ---@type string[]
+ local hybrid_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
+
+ local concealcursor = "";
+
+ for _, mode in ipairs(preview_modes) do
+ if vim.list_contains(hybrid_modes, mode) == false and vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ if vim.list_contains(preview_modes, current_mode) then
+ vim.wo[win].conceallevel = 3;
+ vim.wo[win].concealcursor = concealcursor;
+ else
+ vim.wo[win].conceallevel = 0;
+ vim.wo[win].concealcursor = "";
+ end
+ end
+ ---_
+ end,
+
+ on_splitview_open = function (_, _, win)
+ ---+${lua}
+ vim.wo[win].conceallevel = 3;
+ vim.wo[win].concealcursor = "n";
+ ---_
+ end
+ ---_
+};
+
+-- [ Markview | Preview options > Ignore preview ] ----------------------------------------
+
+--- Items to ignore when rendering.
+---@class preview.ignore
+---
+---@field html? ignore_html[]
+---@field latex? ignore_latex[]
+---@field markdown? ignore_md[]
+---@field markdown_inline? ignore_inline[]
+---@field typst? ignore_typst[]
+---@field yaml? ignore_yaml[]
+M.preview_ignore = {
+ markdown = { "!block_quotes", "!code_blocks" }
+};
+
+---+${lua}
+
+---@alias ignore_html
+---| "!container_elements"
+---| "!headings"
+---| "!void_elements"
+---
+---| "container_elements"
+---| "headings"
+---| "void_elements"
+
+---@alias ignore_latex
+---| "!blocks"
+---| "!commands"
+---| "!escapes"
+---| "!fonts"
+---| "!inlines"
+---| "!parenthesis"
+---| "!subscripts"
+---| "!superscripts"
+---| "!symbols"
+---| "!texts"
+---
+---| "blocks"
+---| "commands"
+---| "escapes"
+---| "fonts"
+---| "inlines"
+---| "parenthesis"
+---| "subscripts"
+---| "superscripts"
+---| "symbols"
+---| "texts"
+
+---@alias ignore_md
+---| "!block_quotes"
+---| "!code_blocks"
+---| "!headings"
+---| "!horizontal_rules"
+---| "!list_items"
+---| "!metadata_minus"
+---| "!metadata_plus"
+---| "!reference_definitions"
+---| "!tables"
+---
+---| "block_quotes"
+---| "code_blocks"
+---| "headings"
+---| "horizontal_rules"
+---| "list_items"
+---| "metadata_minus"
+---| "metadata_plus"
+---| "reference_definitions"
+---| "tables"
+---
+---| "checkboxes"
+
+---@alias ignore_inline
+---| "!block_references"
+---| "!checkboxes"
+---| "!emails"
+---| "!embed_files"
+---| "!entities"
+---| "!escapes"
+---| "!footnotes"
+---| "!highlights"
+---| "!hyperlinks"
+---| "!images"
+---| "!inline_codes"
+---| "!internal_links"
+---| "!uri_autolinks"
+---
+---| "block_references"
+---| "checkboxes"
+---| "emails"
+---| "embed_files"
+---| "entities"
+---| "escapes"
+---| "footnotes"
+---| "highlights"
+---| "hyperlinks"
+---| "images"
+---| "inline_codes"
+---| "internal_links"
+---| "uri_autolinks"
+
+---@alias ignore_typst
+---| "!code_blocks"
+---| "!code_spans"
+---| "!escapes"
+---| "!headings"
+---| "!labels"
+---| "!list_items"
+---| "!math_blocks"
+---| "!math_spans"
+---| "!raw_blocks"
+---| "!raw_spans"
+---| "!reference_links"
+---| "!subscripts"
+---| "!superscripts"
+---| "!symbols"
+---| "!terms"
+---| "!url_links"
+---
+---| "code_blocks"
+---| "code_spans"
+---| "escapes"
+---| "headings"
+---| "labels"
+---| "list_items"
+---| "math_blocks"
+---| "math_spans"
+---| "raw_blocks"
+---| "raw_spans"
+---| "reference_links"
+---| "subscripts"
+---| "superscripts"
+---| "symbols"
+---| "terms"
+---| "url_links"
+
+---@alias ignore_yaml
+---| "!properties"
+---
+---| "properties"
+
+---_
+
+return M;
diff --git a/lua/definitions/typst.lua b/lua/definitions/typst.lua
new file mode 100644
index 0000000..a9085ad
--- /dev/null
+++ b/lua/definitions/typst.lua
@@ -0,0 +1,909 @@
+---@meta
+
+local M = {};
+
+-- [ Markview | Typst ] -------------------------------------------------------------------
+
+--- Configuration for Typst.
+---@class config.typst
+---
+---@field enable boolean
+---
+---@field code_blocks typst.code_blocks | fun(): typst.code_blocks
+---@field code_spans typst.code_spans | fun(): typst.code_spans
+---@field escapes typst.escapes | fun(): typst.escapes
+---@field headings typst.headings | fun(): typst.headings
+---@field labels typst.labels | fun(): typst.labels
+---@field list_items typst.list_items | fun(): typst.list_items
+---@field math_blocks typst.math_blocks | fun(): typst.math_blocks
+---@field math_spans typst.math_spans | fun(): typst.math_spans
+---@field raw_blocks typst.raw_blocks | fun(): typst.raw_blocks
+---@field raw_spans typst.raw_spans | fun(): typst.raw_spans
+---@field reference_links typst.reference_links | fun(): typst.reference_links
+---@field subscripts typst.subscripts | fun(): typst.subscripts
+---@field superscripts typst.subscripts | fun(): typst.superscripts
+---@field symbols typst.symbols | fun(): typst.symbols
+---@field terms typst.terms | fun(): typst.terms
+---@field url_links typst.url_links | fun(): typst.url_links
+M.typst = {
+ enable = true,
+
+ code_blocks = {},
+ code_spans = {},
+ escapes = {},
+ headings = {},
+ labels = {},
+ list_items = {},
+ math_spans = {},
+ math_blocks = {},
+ raw_spans = {},
+ raw_blocks = {},
+ reference_links = {},
+ subscripts = {},
+ superscript = {},
+ symbols = {},
+ terms = {},
+ url_links = {},
+};
+
+-- [ Markview | Typst โข Static ] ----------------------------------------------------------
+
+--- Static configuration for Typst.
+---@class config.typst_static
+---
+---@field enable boolean
+---
+---@field code_blocks typst.code_blocks Configuration for block of typst code.
+---@field code_spans typst.code_spans Configuration for inline typst code.
+---@field escapes typst.escapes Configuration for escaped characters.
+---@field headings typst.headings Configuration for headings.
+---@field labels typst.labels Configuration for labels.
+---@field list_items typst.list_items Configuration for list items
+---@field math_blocks typst.math_blocks Configuration for blocks of math code.
+---@field math_spans typst.math_spans Configuration for inline math code.
+---@field raw_blocks typst.raw_blocks Configuration for raw blocks.
+---@field raw_spans typst.raw_spans Configuration for raw spans.
+---@field reference_links typst.reference_links Configuration for reference links.
+---@field subscripts typst.subscripts Configuration for subscript texts.
+---@field superscripts typst.subscripts Configuration for superscript texts.
+---@field symbols typst.symbols Configuration for typst symbols.
+---@field terms typst.terms Configuration for terms.
+---@field url_links typst.url_links Configuration for URL links.
+
+-- [ Typst | Code blocks ] ----------------------------------------------------------------
+
+--- Configuration for code blocks.
+---@class typst.code_blocks
+---
+---@field enable boolean
+---
+---@field hl? string | fun(buffer: integer, item: __typst.code_block): string?
+---@field min_width integer | fun(buffer: integer, item: __typst.code_block): integer
+---@field pad_amount integer | fun(buffer: integer, item: __typst.code_block): integer
+---@field pad_char? string | fun(buffer: integer, item: __typst.code_block): string?
+---@field sign? string | fun(buffer: integer, item: __typst.code_block): string
+---@field sign_hl? string | fun(buffer: integer, item: __typst.code_block): string?
+---@field style ( "simple" | "block" ) | fun(buffer: integer, item: __typst.code_block): ( "simple" | "block" )
+---@field text string | fun(buffer: integer, item: __typst.code_block): string
+---@field text_direction ( "left" | "right" ) | fun(buffer: integer, item: __typst.code_block): ( "left" | "right" )
+---@field text_hl? string | fun(buffer: integer, item: __typst.code_block): string?
+M.typst_codes_block = {
+ style = "block",
+ text_direction = "right",
+ pad_amount = 3,
+ pad_char = " ",
+ min_width = 60,
+ hl = "MarkviewCode"
+} or {
+ style = "simple",
+ hl = "MarkviewCode"
+};
+
+-- [ Typst | Code blocks โข Static ] -------------------------------------------------------
+
+--- Static configuration for code blocks.
+---@class typst.code_blocks_static
+---
+---@field enable boolean
+---
+---@field hl? string
+---@field min_width integer Minimum width of code blocks.
+---@field pad_amount integer Number of paddings added around the text.
+---@field pad_char? string Character to use for padding.
+---@field sign? string Sign for the code block.
+---@field sign_hl? string Highlight group for the sign.
+---@field style
+---| "simple" Only highlights the lines inside this block.
+---| "block" Creates a box around the code block.
+---@field text string Text to use as the label.
+---@field text_direction
+---| "left" Shows label on the top-left side of the block
+---| "right" Shows label on the top-right side of the block
+---@field text_hl? string Highlight group for the label
+
+-- [ Typst | Code blocks > Parameters ] ---------------------------------------------------
+
+---@class __typst.code_block
+---@field class "typst_code_block"
+---@field text string[]
+---@field range node.range
+M.__typst_codes = {
+ class = "typst_code_block",
+
+ text = {
+ "#{",
+ " let a = [from]",
+ "}"
+ },
+ range = {
+ row_start = 0,
+ row_end = 2,
+
+ col_start = 0,
+ col_end = 1
+ }
+};
+
+-- [ Typst | Code spans ] ----------------------------------------------------------------
+
+--- Configuration for code spans.
+---@class typst.code_spans
+---
+---@field enable boolean
+---
+---@field corner_left? string | fun(buffer: integer, item: __typst.code_spans): string?
+---@field corner_left_hl? string | fun(buffer: integer, item: __typst.code_spans): string?
+---@field corner_right? string | fun(buffer: integer, item: __typst.code_spans): string?
+---@field corner_right_hl? string | fun(buffer: integer, item: __typst.code_spans): string?
+---@field hl? string | fun(buffer: integer, item: __typst.code_spans): string?
+---@field padding_left? string | fun(buffer: integer, item: __typst.code_spans): string?
+---@field padding_left_hl? string | fun(buffer: integer, item: __typst.code_spans): string?
+---@field padding_right? string | fun(buffer: integer, item: __typst.code_spans): string?
+---@field padding_right_hl? string | fun(buffer: integer, item: __typst.code_spans): string?
+M.typst_codes_inline = {
+ enable = true,
+
+ padding_left = " ",
+ corner_left = " ",
+ hl = "MarkviewCode"
+};
+
+-- [ Typst | Code spans โข Static ] -------------------------------------------------------
+
+--- Static configuration for code spans.
+---@class typst.code_spans_static
+---
+---@field enable boolean
+---
+---@field corner_left? string Left corner.
+---@field corner_left_hl? string Highlight group for left corner.
+---@field corner_right? string Right corner.
+---@field corner_right_hl? string Highlight group for right corner.
+---@field hl? string Base Highlight group.
+---@field padding_left? string Left padding.
+---@field padding_left_hl? string Highlight group for left padding.
+---@field padding_right? string Right padding.
+---@field padding_right_hl? string Highlight group for right padding.
+
+-- [ Typst | Code spans > Parameters ] ----------------------------------------------------
+
+---@class __typst.code_spans
+---@field class "typst_code_span"
+---@field text string[]
+---@field range node.range
+M.__typst_codes = {
+ class = "typst_code_span",
+
+ text = { "#{ let a = 1 }" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 13
+ }
+};
+
+-- [ Typst | Escapes ] ---------------------------------------------------------------------
+
+---@alias typst.escapes { enable: boolean }
+
+-- [ Typst | Escapes > Parameters ] -------------------------------------------------------
+
+---@class __typst.escapes
+---
+---@field class "typst_escaped"
+---@field text string[]
+---@field range node.range
+M.__typst_escapes = {
+ class = "typst_escaped",
+
+ text = { "\\|" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 2
+ }
+};
+
+-- [ Typst | Headings ] -------------------------------------------------------------------
+
+--- Configuration for Typst headings.
+---@class typst.headings
+---
+---@field enable boolean
+---
+---@field shift_width integer Amount of spaces to shift per heading level.
+---
+---@field [string] headings.typst Heading level configuration(name format: "heading_%d", %d = heading level).
+M.typst_headings = {
+ enable = true,
+ shift_width = 1,
+
+ heading_1 = { style = "simple", hl = "MarkviewPalette1" }
+};
+
+-- [ Typst | Headings > Type definitions ] ------------------------------------------------
+
+--- Heading level configuration.
+---@class headings.typst
+---
+---@field style "simple" | "icon"
+---@field hl? string
+---@field icon? string
+---@field icon_hl? string
+---@field sign? string
+---@field sign_hl? string
+M.headings_typst = {
+ style = "simple",
+ hl = "MarkviewHeading1"
+} or {
+ style = "icon",
+
+ icon = "~",
+ hl = "MarkviewHeading1"
+};
+
+-- [ Typst | Headings > Parameters ] ------------------------------------------------------
+
+---@class __typst.headings
+---
+---@field class "typst_heading"
+---
+---@field level integer Heading level.
+---
+---@field text string[]
+---@field range node.range
+M.__typst_headings = {
+ class = "typst_heading",
+ level = 1,
+
+ text = { "= Heading 1" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 10
+ }
+};
+
+-- [ Typst | Labels ] ---------------------------------------------------------------------
+
+--- Configuration for typst labels.
+---@class typst.labels
+---
+---@field enable boolean
+---
+---@field default config.inline_generic | fun(buffer: integer, item: __typst.labels): config.inline_generic
+---@field [string] config.inline_generic | fun(buffer: integer, item: __typst.labels): config.inline_generic
+M.typst_labels = {
+ enable = true,
+ default = { hl = "MarkviewInlineCode" },
+ ["^nv"] = {
+ hl = "MarkviewPalette1"
+ }
+};
+
+-- [ Typst | Labels โข Static ] ------------------------------------------------------------
+
+--- Static configuration for typst labels.
+---@class typst.labels
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for labels.
+---@field [string] config.inline_generic Configuration for labels whose text matches `string`.
+
+-- [ Typst | Labels > Parameters ] --------------------------------------------------------
+
+---@class __typst.labels
+---
+---@field class "typst_labels"
+---
+---@field text string[]
+---@field range node.range
+M.__typst_labels = {
+ class = "typst_labels",
+
+ text = { "" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 7
+ }
+};
+
+
+-- [ Typst | List items ] -----------------------------------------------------------------
+
+--- Configuration for list items.
+---@class typst.list_items
+---
+---@field enable boolean
+---
+---@field indent_size integer Indentation size for list items.
+---@field shift_width integer Preview indentation size for list items.
+---
+---@field marker_dot list_items.ordered Configuration for `n.` list items.
+---@field marker_minus list_items.typst Configuration for `-` list items.
+---@field marker_plus list_items.typst Configuration for `+` list items.
+M.typst_list_items = {
+ enable = true,
+ marker_plus = {},
+ marker_minus = {},
+ marker_dot = {},
+};
+
+-- [ Typst | List items > Type definitions ] ----------------------------------------------
+
+---@class list_items.typst
+---
+---@field enable? boolean
+---
+---@field add_padding boolean
+---@field hl? string
+---@field text string
+M.list_items_unordered = {
+ enable = true,
+ hl = "MarkviewListItemPlus",
+ text = "โข",
+ add_padding = true,
+ conceal_on_checkboxes = true
+};
+
+-- [ Typst | List items > Parameters ] ----------------------------------------------------
+
+---@class __typst.list_items
+---
+---@field class "typst_list_item"
+---@field indent integer
+---@field marker "+" | "-" | string
+---@field number? integer Number to show on the list item when previewing.
+---@field text string[]
+---@field range node.range
+M.__typst_list_items = {
+ class = "typst_list_item",
+ indent = 0,
+ marker = "-",
+
+ text = { "- List item" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 11
+ }
+};
+
+-- [ Typst | Math blocks ] -----------------------------------------------------------------
+
+--- Configuration for math blocks.
+---@class typst.math_blocks
+---
+---@field enable boolean
+---
+---@field hl? string
+---@field pad_amount integer Number of `pad_char` to add before the lines.
+---@field pad_char string Text used as padding.
+---@field text string
+---@field text_hl? string
+M.typst_math_blocks = {
+ enable = true,
+ hl = "MarkviewInlineCode"
+};
+
+-- [ Typst | Math blocks > Parameters ] ---------------------------------------------------
+
+---@class __typst.maths
+---
+---@field class "typst_math"
+---
+---@field inline boolean Should we render it inline?
+---@field closed boolean Is the node closed(ends with `$$`)?
+---
+---@field text string[]
+---@field range node.range
+M.__typst_maths = {
+ class = "typst_math",
+ inline = true,
+ closed = true,
+
+ text = { "$ 1 + 2 $" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 9
+ }
+};
+
+-- [ Typst | Math spans ] -----------------------------------------------------------------
+
+---@alias typst.math_spans config.inline_generic
+M.typst_math_spans = {
+ enable = true,
+ hl = "MarkviewInlineCode"
+};
+
+-- [ Typst | Math spans > Parameters ] ----------------------------------------------------
+
+---@class __typst.maths
+---
+---@field class "typst_math"
+---
+---@field inline boolean Should we render it inline?
+---@field closed boolean Is the node closed(ends with `$$`)?
+---
+---@field text string[]
+---@field range node.range
+M.__typst_maths = {
+ class = "typst_math",
+ inline = true,
+ closed = true,
+
+ text = { "$ 1 + 2 $" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 9
+ }
+};
+
+-- [ Typst | Raw blocks ] -----------------------------------------------------------------
+
+---@class typst.raw_blocks
+---
+---@field enable boolean
+---
+---@field border_hl? string | fun(buffer: integer, item: __typst.raw_blocks): string?
+---@field label_direction? ( "left" | "right" ) | fun(buffer: integer, item: __typst.raw_blocks): ( "left" | "right" )
+---@field label_hl? string | fun(buffer: integer, item: __typst.raw_blocks): string?
+---@field min_width integer | fun(buffer: integer, item: __typst.raw_blocks): integer
+---@field pad_amount? integer | fun(buffer: integer, item: __typst.raw_blocks): integer
+---@field pad_char? string | fun(buffer: integer, item: __typst.raw_blocks): string?
+---@field sign? boolean | fun(buffer: integer, item: __typst.raw_blocks): boolean?
+---@field sign_hl? string | fun(buffer: integer, item: __typst.raw_blocks): string?
+---@field style ( "simple" | "block" ) | fun(buffer: integer, item: __typst.raw_blocks): ( "simple" | "block" )
+---
+---@field default raw_blocks.opts | fun(buffer: integer, item: __typst.raw_blocks): raw_blocks.opts
+---@field [string] raw_blocks.opts | fun(buffer: integer, item: __typst.raw_blocks): raw_blocks.opts
+M.typst_raw_blocks = {
+ enable = true,
+ hl = "MarkviewInlineCode"
+};
+
+-- [ Typst | Raw blocks โข Static ] --------------------------------------------------------
+
+---@class typst.raw_blocks_static
+---
+---@field enable boolean
+---
+---@field border_hl? string Highlight group for top & bottom border of raw blocks.
+---@field label_direction? "left" | "right" Changes where the label is shown.
+---@field label_hl? string Highlight group for the label
+---@field min_width? integer Minimum width of the code block.
+---@field pad_amount? integer Left & right padding size.
+---@field pad_char? string Character to use for the padding.
+---@field sign? boolean Whether to show signs for the code blocks.
+---@field sign_hl? string Highlight group for the signs.
+---@field style "simple" | "block" Preview style for code blocks.
+---
+---@field default raw_blocks.opts_static Default line configuration for the raw block.
+---@field [string] raw_blocks.opts_static Line configuration for the raw block whose `language` matches `string`
+
+-- [ Typst | Raw blocks > Type definitions ] -----------------------------------------------
+
+--- Configuration for highlighting a line inside a raw block.
+---@class raw_blocks.opts
+---
+---@field block_hl string | fun(buffer: integer, line: string): string?
+---@field pad_hl string | fun(buffer: integer, line: string): string?
+
+--- Static configuration for highlighting a line inside a raw block.
+---@class raw_blocks.opts_static
+---
+---@field block_hl string? Highlight group for the background of the line.
+---@field pad_hl string? Highlight group for the padding of the line.
+
+-- [ Typst | Raw blocks > Parameters ] ----------------------------------------------------
+
+---@class __typst.raw_blocks
+---
+---@field class "typst_raw_block"
+---@field language? string
+---@field text string[]
+---@field range node.range
+M.__typst_raw_blocks = {
+ class = "typst_raw_block",
+ language = "lua",
+
+ text = {
+ "```lua",
+ 'vim.print("Hello, Neovim")',
+ "```"
+ },
+ range = {
+ row_start = 0,
+ row_end = 2,
+
+ col_start = 0,
+ col_end = 3
+ }
+};
+
+-- [ Typst | Raw spans ] ------------------------------------------------------------------
+
+---@alias typst.raw_spans config.inline_generic
+M.typst_raw_spans = {
+ enable = true,
+ hl = "MarkviewInlineCode"
+};
+
+-- [ Typst | Raw spans โข Static ] ---------------------------------------------------------
+
+---@alias typst.raw_spans_static config.inline_generic_static
+
+-- [ Typst | Raw spans > Parameters ] -----------------------------------------------------
+
+---@class __typst.raw_spans
+---
+---@field class "typst_raw_span"
+---
+---@field text string[]
+---@field range node.range
+M.__typst_raw_spans = {
+ class = "typst_raw_span",
+
+ text = { "`hi`" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 4
+ }
+};
+
+-- [ Typst | Reference links ] -----------------------------------------------------------
+
+---@class typst.reference_links
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for reference links.
+---@field [string] config.inline_generic Configuration for reference links whose label matches `string`.
+M.typst_link_ref = {
+ enable = true,
+ default = { hl = "MarkviewHyperlink" },
+ ["neovim.org"] = {
+ match_string = "",
+ hl = "MarkviewPalette1"
+ }
+};
+
+-- [ Typst | Reference links > Parameters ] -----------------------------------------------
+
+---@class __typst.reference_links
+---
+---@field class "typst_link_ref"
+---
+---@field label string
+---
+---@field text string[]
+---@field range inline_link.range
+M.__typst_link_ref = {
+ class = "typst_link_ref",
+ label = "label",
+
+ text = { "@label" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 6,
+
+ label = { 0, 1, 0, 6 }
+ }
+};
+
+-- [ Typst | Subscripts ] ------------------------------------------------------------------
+
+--- Configuration for subscript text.
+---@class typst.subscripts
+---
+---@field enable boolean
+---
+---@field hl? string | string[]
+---@field marker_left? string
+---@field marker_right? string
+M.typst_subscripts = {
+ enable = true,
+ hl = "MarkviewSubscript"
+};
+
+-- [ Typst | Subscripts > Parameters ] ----------------------------------------------------
+
+---@class __typst.subscripts
+---
+---@field class "typst_subscript"
+---@field parenthesis boolean Whether the text is surrounded by parenthesis.
+---@field level integer Subscript level.
+---@field text string[]
+---@field range node.range
+M.__typst_subscripts = {
+ class = "typst_subscript",
+ parenthesis = true,
+ preview = true,
+ level = 1,
+
+ text = { "_{12}" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 5
+ }
+};
+
+-- [ Typst | Superscripts ] ---------------------------------------------------------------
+
+--- Configuration for superscript text.
+---@class typst.superscripts
+---
+---@field enable boolean
+---
+---@field hl? string | string[]
+---@field marker_left? string
+---@field marker_right? string
+M.typst_superscripts = {
+ enable = true,
+ hl = "MarkviewSuperscript"
+};
+
+-- [ Typst | Superscripts > Parameters ] --------------------------------------------------
+
+---@class __typst.superscripts
+---
+---@field class "typst_superscript"
+---@field parenthesis boolean Whether the text is surrounded by parenthesis.
+---@field level integer Superscript level.
+---@field text string[]
+---@field range node.range
+M.__typst_superscripts = {
+ class = "typst_superscript",
+ parenthesis = true,
+ preview = true,
+ level = 1,
+
+ text = { "^{12}" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 5
+ }
+};
+
+-- [ Typst | Symbols ] --------------------------------------------------------------------
+
+--- Configuration for symbols in typst.
+---@class typst.symbols
+---
+---@field enable boolean
+---@field hl? string
+M.typst_symbols = {
+ enable = true,
+ hl = "Special"
+};
+
+-- [ Typst | Symbols > Parameters ] -------------------------------------------------------
+
+---@class __typst.symbols
+---
+---@field class "typst_symbol"
+---@field name string
+---@field text string[]
+---@field range node.range
+M.__typst_symbols = {
+ class = "typst_symbol",
+ name = "alpha",
+
+ text = { "alpha" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 5
+ }
+};
+
+
+---@class typst.fonts
+---
+---@field enable boolean
+---@field hl? string
+M.typst_fonts = {
+ enable = true,
+ hl = "Special"
+};
+
+-- [ Typst | Terms ] --------------------------------------------------------------------
+
+---@class typst.terms
+---
+---@field enable boolean
+---
+---@field default term.opts Default configuration for terms.
+---@field [string] term.opts Configuration for terms whose label matches `string`.
+M.typst_term = {
+ enable = true,
+ default = {},
+};
+
+-- [ Typst | Terms > Type definitions ] ---------------------------------------------------
+
+---@class term.opts
+---
+---@field text string
+---@field hl? string
+M.term_opts = {
+ text = "ฯ",
+ hl = "Comment"
+};
+
+-- [ Typst | Terms > Parameters ] ---------------------------------------------------------
+
+---@class __typst.terms
+---
+---@field class "typst_term"
+---
+---@field label string
+---
+---@field text string[]
+---@field range inline_link.range
+M.__typst_terms = {
+ class = "typst_term",
+ label = "Term",
+
+ text = { "/ Term" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 6,
+
+ label = { 0, 2, 0, 6 }
+ }
+};
+
+-- [ Typst | URL links ] ------------------------------------------------------------------
+
+--- Configuration for URL links.
+---@class typst.url_links
+---
+---@field enable boolean
+---
+---@field default config.inline_generic Default configuration for URL links.
+---@field [string] config.inline_generic Configuration for URL links whose label matches `string`.
+M.typst_link_ref = {
+ enable = true,
+ default = { hl = "MarkviewHyperlink" },
+ ["neovim.org"] = {
+ hl = "MarkviewPalette1"
+ }
+};
+
+-- [ Typst | URL links > Parameters ] -----------------------------------------------------
+
+---@class __typst.url_links
+---
+---@field class "typst_link_url"
+---@field label string
+---@field text string[]
+---@field range inline_link.range
+M.__typst_url_links = {
+ class = "typst_link_url",
+ label = "https://example.com",
+
+ text = { "https://example.com" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 19,
+
+ label = { 0, 0, 0, 19 }
+ }
+};
+
+-- [ Typst | Misc ] -----------------------------------------------------------------------
+
+---@class __typst.emphasis
+---
+---@field class "typst_emphasis"
+---@field text string[]
+---@field range node.range
+M.__typst_emphasis = {
+ class = "typst_emphasis",
+ text = { "_emphasis_" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 9
+ }
+};
+
+---@class __typst.strong
+---
+---@field class "typst_strong"
+---@field text string[]
+---@field range node.range
+M.__typst_strong = {
+ class = "typst_strong",
+
+ text = { "*strong*" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 7
+ }
+};
+
+---@class __typst.text
+---
+---@field class "typst_text"
+---@field text string[]
+---@field range node.range
+M.__typst_text = {
+ class = "typst_text",
+
+ text = { "1" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 1
+ }
+};
+
+return M;
diff --git a/lua/definitions/yaml.lua b/lua/definitions/yaml.lua
new file mode 100644
index 0000000..3159ecb
--- /dev/null
+++ b/lua/definitions/yaml.lua
@@ -0,0 +1,84 @@
+---@meta
+
+local M = {};
+
+ ------------------------------------------------------------------------------------------
+
+--- Configuration for YAML.
+---@class config.yaml
+---
+---@field enable boolean
+---@field properties yaml.properties
+M.yaml = {
+ enable = true,
+ properties = {}
+};
+
+-- [ YAML | Properties ] ------------------------------------------------------------------
+
+--- Configuration for YAML properties.
+---@class yaml.properties
+---
+---@field enable boolean
+---
+---@field data_types { [string]: properties.opts } Configuration for various data types.
+---
+---@field default properties.opts Default configuration for properties.
+---@field [string] properties.opts Configuration for properties whose name matches `string`.
+M.yaml_properties = {
+ enable = true,
+ default = {},
+ data_types = {},
+};
+
+-- [ YAML | Properties > Types ] ----------------------------------------------------------
+
+---@class properties.opts
+---
+---@field border_bottom? string Scope guide border bottom.
+---@field border_bottom_hl? string
+---@field border_hl? string
+---@field border_middle? string Scope guide border middle.
+---@field border_middle_hl? string
+---@field border_top? string Scope guide border top.
+---@field border_top_hl? string
+---
+---@field hl? string
+---@field text? string
+---
+---@field use_types? boolean When `true`, the configuration table merges with the value's data type configuration.
+M.properties_opts = {
+ use_types = true,
+
+ text = "ฯ",
+ hl = "Title"
+};
+
+-- [ YAML | Properties > Parameters ] -----------------------------------------------------
+
+---@class __yaml.properties
+---
+---@field class "yaml_property"
+---@field type "date" | "date_&_time" | "number" | "text" | "list" | "checkbox" | "nil" | "unknown"
+---@field key string
+---@field value string
+---@field text string[]
+---@field range node.range
+M.__yaml_properties = {
+ class = "yaml_property",
+ type = "checkbox",
+
+ key = "key",
+ value = "value",
+
+ text = { "key: value" },
+ range = {
+ row_start = 0,
+ row_end = 0,
+
+ col_start = 0,
+ col_end = 10
+ }
+};
+
+return M;
diff --git a/lua/markview.lua b/lua/markview.lua
index 0006dee..26d1420 100644
--- a/lua/markview.lua
+++ b/lua/markview.lua
@@ -1,1405 +1,1297 @@
+--- Base module for `markview.nvim`.
+--- Contains,
+--- โข State variables.
+--- โข Default autocmd group.
+--- โข Plugin commands implementations.
+--- โข Setup function.
+--- โข And various helper functions.
+--- And other minor things!
local markview = {};
-local utils = require("markview.utils");
-local hls = require("markview.highlights");
-local ts = require("markview.treesitter");
-local latex = require("markview.latex_renderer");
+local spec = require("markview.spec");
+local health = require("markview.health");
-markview.parser = require("markview.parser");
-markview.renderer = require("markview.renderer");
-markview.keymaps = require("markview.keymaps");
+--- Plugin state variables.
+---@type mkv.state
+markview.state = {
+ enable = true,
+
+ attached_buffers = {},
+ buffer_states = {},
----@type integer[] List of attached buffers
-markview.attached_buffers = {};
+ splitview_buffer = nil,
+ splitview_source = nil,
+ splitview_window = nil
+};
----@type integer[] List of attached windows
-markview.attached_windows = {};
+---@type integer Autocmd group ID.
+markview.augroup = vim.api.nvim_create_augroup("markview", { clear = true });
----@type { was_detached: boolean, id: integer }[]
-markview.autocmds = {};
+-------------------------------------------------------------------------------------------
----@class markview.state Stores the various states of the plugin
+--- Simple 1-time renderer for `markview`.
---
----@field enable boolean Plugin state
----@field hybrid_mode boolean Hybrid mode state
----@field buf_states { [integer]: boolean } Buffer local plugin state
-markview.state = {
- enable = true,
- hybrid_mode = true,
- buf_states = {}
-};
+--- A buffer must be cleared before being
+--- able to render again.
+markview.strict_render = {
+ ---+${lua}
+
+ --- Buffers where immediate render was used.
+ ---@type integer[]
+ on = {},
+
+ --- Clears an immediately rendered buffer.
+ --- Makes rendering on that buffer possible
+ --- again.
+ ---@param self table
+ ---@param buffer integer?
+ clear = function (self, buffer)
+ ---+${lua}
+
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
+
+ if vim.list_contains(self.on, buffer) == false then
+ return;
+ end
----@type markview.configuration
-markview.configuration = {
- __inside_code_block = false,
-
- buf_ignore = { "nofile" },
-
- callbacks = {
- ---+ ${class, Callbacks}
- on_enable = function (_, window)
- local _m = {};
-
- if markview.state.hybrid_mode == true and vim.islist(markview.configuration.hybrid_modes) then
- for _, mod in ipairs(markview.configuration.modes) do
- if vim.list_contains({ "n", "i", "v", "c" }, mod) and
- not vim.list_contains(markview.configuration.hybrid_modes, mod)
- then
- table.insert(_m, mod);
- end
- end
- else
- for _, mod in ipairs(markview.configuration.modes) do
- if vim.list_contains({ "n", "i", "v", "c" }, mod) then
- table.insert(_m, mod);
- end
- end
- end
+ markview.clear(buffer);
- vim.wo[window].conceallevel = 2;
- vim.wo[window].concealcursor = table.concat(_m);
- end,
- on_disable = function (_, window)
- vim.wo[window].conceallevel = 0;
- vim.wo[window].concealcursor = "";
- end,
-
- on_mode_change = function (_, window, mode)
- if vim.list_contains(markview.configuration.modes, mode) then
- local _m = {};
-
- if markview.state.hybrid_mode == true and vim.islist(markview.configuration.hybrid_modes) then
- for _, mod in ipairs(markview.configuration.modes) do
- if vim.list_contains({ "n", "i", "v", "c" }, mod) and
- not vim.list_contains(markview.configuration.hybrid_modes, mod)
- then
- table.insert(_m, mod);
- end
- end
- else
- for _, mod in ipairs(markview.configuration.modes) do
- if vim.list_contains({ "n", "i", "v", "c" }, mod) then
- table.insert(_m, mod);
- end
- end
- end
-
- vim.wo[window].concealcursor = table.concat(_m);
- vim.wo[window].conceallevel = 2;
- else
- vim.wo[window].conceallevel = 0;
- vim.wo[window].concealcursor = "";
- end
- end,
+ markview.actions.__exec_callback("on_disable", buffer, vim.fn.win_findbuf(buffer))
- split_enter = nil
- ---_
- },
+ --- Execute the disable one callback.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewDisable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
- debounce = 50,
- escaped = { enable = true },
+ --- Execute the attaching callback.
+ markview.actions.__exec_callback("on_detach", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewDetach",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
- filetypes = { "markdown", "quarto", "rmd" },
+ for b, buf in ipairs(self.on) do
+ if buf == buffer then
+ table.remove(self.on, b);
+ return;
+ end
+ end
+ ---_
+ end,
- highlight_groups = "dynamic",
+ --- Immediately renders in buffer.
+ --- Prevents redrawing on that buffer again(until cleared).
+ ---@param self table
+ ---@param buffer integer?
+ render = function (self, buffer, max_lines)
+ ---+${lua}
- hybrid_modes = nil,
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
+ max_lines = max_lines or spec.get({ "prevent", "max_buf_lines" }, { ignore_enable = true, fallback = 1000 });
- ignore_nodes = nil,
- initial_state = true,
+ if vim.list_contains(self.on, buffer) then
+ return;
+ elseif vim.api.nvim_buf_line_count(buffer) >= max_lines then
+ return;
+ end
- max_file_length = 1000,
- modes = { "n", "no", "c" },
- render_distance = 100,
+ local parser = require("markview.parser");
+ local renderer = require("markview.renderer");
- split_conf = {
- split = "right"
- },
+ markview.render(buffer);
+ local content;
+ markview.clear(buffer);
+ content, _ = parser.parse(buffer, 0, -1, true);
- block_quotes = {
- ---+ ${class, Block quote}
- enable = true,
+ --- Execute the attaching callback.
+ markview.actions.__exec_callback("on_attach", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewAttach",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
+
+ markview.actions.__exec_callback("on_enable", buffer, vim.fn.win_findbuf(buffer))
- default = {
- border = "โ", hl = "MarkviewBlockQuoteDefault"
- },
-
- callouts = {
- ---+ ${conf, From `Obsidian`}
- {
- match_string = "ABSTRACT",
- preview = "๓ฑซ Abstract",
- hl = "MarkviewBlockQuoteNote",
-
- title = true,
- icon = "๓ฑซ",
-
- border = "โ"
- },
- {
- match_string = "SUMMARY",
- hl = "MarkviewBlockQuoteNote",
- preview = "๓ฑซ Summary",
-
- title = true,
- icon = "๓ฑซ",
-
- border = "โ"
- },
- {
- match_string = "TLDR",
- hl = "MarkviewBlockQuoteNote",
- preview = "๓ฑซ Tldr",
-
- title = true,
- icon = "๓ฑซ",
-
- border = "โ"
- },
- {
- match_string = "TODO",
- hl = "MarkviewBlockQuoteNote",
- preview = "๎ Todo",
-
- title = true,
- icon = "๎",
-
- border = "โ"
- },
- {
- match_string = "INFO",
- hl = "MarkviewBlockQuoteNote",
- preview = "๎ช Info",
-
- custom_title = true,
- icon = "๎",
-
- border = "โ"
- },
- {
- match_string = "SUCCESS",
- hl = "MarkviewBlockQuoteOk",
- preview = "๓ฐ Success",
-
- title = true,
- icon = "๓ฐ ",
-
- border = "โ"
- },
- {
- match_string = "CHECK",
- hl = "MarkviewBlockQuoteOk",
- preview = "๓ฐ Check",
-
- title = true,
- icon = "๓ฐ ",
-
- border = "โ"
- },
- {
- match_string = "DONE",
- hl = "MarkviewBlockQuoteOk",
- preview = "๓ฐ Done",
-
- title = true,
- icon = "๓ฐ ",
-
- border = "โ"
- },
- {
- match_string = "QUESTION",
- hl = "MarkviewBlockQuoteWarn",
- preview = "๓ฐ Question",
-
- title = true,
- icon = "๓ฐ",
-
- border = "โ"
- },
- {
- match_string = "HELP",
- hl = "MarkviewBlockQuoteWarn",
- preview = "๓ฐ Help",
-
- title = true,
- icon = "๓ฐ",
-
- border = "โ"
- },
- {
- match_string = "FAQ",
- hl = "MarkviewBlockQuoteWarn",
- preview = "๓ฐ Faq",
-
- title = true,
- icon = "๓ฐ",
-
- border = "โ"
- },
- {
- match_string = "FAILURE",
- hl = "MarkviewBlockQuoteError",
- preview = "๓ฐ
Failure",
-
- title = true,
- icon = "๓ฐ
",
-
- border = "โ"
- },
- {
- match_string = "FAIL",
- hl = "MarkviewBlockQuoteError",
- preview = "๓ฐ
Fail",
-
- title = true,
- icon = "๓ฐ
",
-
- border = "โ"
- },
- {
- match_string = "MISSING",
- hl = "MarkviewBlockQuoteError",
- preview = "๓ฐ
Missing",
-
- title = true,
- icon = "๓ฐ
",
-
- border = "โ"
- },
- {
- match_string = "DANGER",
- hl = "MarkviewBlockQuoteError",
- preview = "๏ญ Danger",
-
- title = true,
- icon = "๏ญ",
-
- border = "โ"
- },
- {
- match_string = "ERROR",
- hl = "MarkviewBlockQuoteError",
- preview = "๏ญ Error",
-
- title = true,
- icon = "๏ญ",
-
- border = "โ"
- },
- {
- match_string = "BUG",
- hl = "MarkviewBlockQuoteError",
- preview = "๏ฏ Bug",
-
- title = true,
- icon = "๏ฏ",
-
- border = "โ"
- },
- {
- match_string = "EXAMPLE",
- hl = "MarkviewBlockQuoteSpecial",
- preview = "๓ฑซ Example",
-
- title = true,
- icon = "๓ฑซ",
-
- border = "โ"
- },
- {
- match_string = "QUOTE",
- hl = "MarkviewBlockQuoteDefault",
- preview = "๏ Quote",
-
- title = true,
- icon = "๏",
-
- border = "โ"
- },
- {
- match_string = "CITE",
- hl = "MarkviewBlockQuoteDefault",
- preview = "๏ Cite",
-
- title = true,
- icon = "๏",
-
- border = "โ"
- },
- {
- match_string = "HINT",
- hl = "MarkviewBlockQuoteOk",
- preview = "๏ Hint",
-
- title = true,
- icon = "๏",
-
- border = "โ"
- },
- {
- match_string = "ATTENTION",
- hl = "MarkviewBlockQuoteWarn",
- preview = "๎ฉฌ Attention",
-
- title = true,
- icon = "๏",
-
- border = "โ"
- },
- ---_
- ---+ ${conf, From Github}
- {
- match_string = "NOTE",
- hl = "MarkviewBlockQuoteNote",
- preview = "๓ฐฝ Note",
-
- border = "โ"
- },
- {
- match_string = "TIP",
- hl = "MarkviewBlockQuoteOk",
- preview = "๏ Tip",
-
- border = "โ"
- },
- {
- match_string = "IMPORTANT",
- hl = "MarkviewBlockQuoteSpecial",
- preview = "๎ญ Important",
-
- border = "โ"
- },
- {
- match_string = "WARNING",
- hl = "MarkviewBlockQuoteWarn",
- preview = "๎ฉฌ Warning",
-
- border = "โ"
- },
- {
- match_string = "CAUTION",
- hl = "MarkviewBlockQuoteError",
- preview = "๓ฐณฆ Caution",
-
- border = "โ"
- },
- ---_
-
- ---+ ${conf, Custom}
- {
- match_string = "CUSTOM",
- hl = "MarkviewBlockQuoteWarn",
- preview = "๓ฐ ณ Custom",
-
- custom_title = true,
- custom_icon = "๓ฐ ณ",
-
- border = "โ"
+ --- Execute the enable/disable one too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewEnable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
}
- ---_
- }
+ });
+
+ renderer.render(buffer, content);
+ table.insert(self.on, buffer);
---_
- },
+ end
+ ---_
+};
- checkboxes = {
- ---+ ${conf, Minimal style checkboxes}
- enable = true,
+-------------------------------------------------------------------------------------------
+
+--- Cleans up invalid buffers.
+markview.clean = function ()
+ ---+${lua}
+
+ --- Should a buffer be cleaned?
+ ---@param bufnr integer
+ ---@return boolean
+ local function should_clean(bufnr)
+ if not bufnr then
+ return true;
+ elseif vim.api.nvim_buf_is_loaded(bufnr) == false then
+ return true;
+ elseif vim.api.nvim_buf_is_valid(bufnr) == false then
+ return true;
+ end
- checked = {
- text = "๓ฐ ", hl = "MarkviewCheckboxChecked"
- },
- unchecked = {
- text = "๓ฐฐ", hl = "MarkviewCheckboxUnchecked"
- },
- custom = {
- {
- match_string = "/",
- text = "๓ฑ",
- hl = "MarkviewCheckboxPending"
- },
- {
- match_string = ">",
- text = "๏",
- hl = "MarkviewCheckboxCancelled"
- },
- {
- match_string = "<",
- text = "๓ฐ",
- hl = "MarkviewCheckboxCancelled"
- },
- {
- match_string = "-",
- text = "๓ฐถ",
- hl = "MarkviewCheckboxCancelled",
- scope_hl = "MarkviewCheckboxStriked"
- },
-
- {
- match_string = "?",
- text = "๓ฐ",
- hl = "MarkviewCheckboxPending"
- },
- {
- match_string = "!",
- text = "๓ฐฆ",
- hl = "MarkviewCheckboxUnchecked"
- },
- {
- match_string = "*",
- text = "๓ฐ",
- hl = "MarkviewCheckboxPending"
- },
- {
- match_string = '"',
- text = "๓ฐธฅ",
- hl = "MarkviewCheckboxCancelled"
- },
- {
- match_string = "l",
- text = "๓ฐ",
- hl = "MarkviewCheckboxProgress"
- },
- {
- match_string = "b",
- text = "๓ฐ",
- hl = "MarkviewCheckboxProgress"
- },
- {
- match_string = "i",
- text = "๓ฐฐ",
- hl = "MarkviewCheckboxChecked"
- },
- {
- match_string = "S",
- text = "๎พ",
- hl = "MarkviewCheckboxChecked"
- },
- {
- match_string = "I",
- text = "๓ฐจ",
- hl = "MarkviewCheckboxPending"
- },
- {
- match_string = "p",
- text = "๏
ค",
- hl = "MarkviewCheckboxChecked"
- },
- {
- match_string = "c",
- text = "๏
ฅ",
- hl = "MarkviewCheckboxUnchecked"
- },
- {
- match_string = "f",
- text = "๓ฑ ",
- hl = "MarkviewCheckboxUnchecked"
- },
- {
- match_string = "k",
- text = "๏",
- hl = "MarkviewCheckboxPending"
- },
- {
- match_string = "w",
- text = "๏ฝ",
- hl = "MarkviewCheckboxProgress"
- },
- {
- match_string = "u",
- text = "๓ฐต",
- hl = "MarkviewCheckboxChecked"
- },
- {
- match_string = "d",
- text = "๓ฐณ",
- hl = "MarkviewCheckboxUnchecked"
- },
- }
- ---_
- },
+ return false;
+ end
- code_blocks = {
- ---+ ${class, Code blocks}
- enable = true,
- icons = "internal",
+ ---+${func}
+ for index, buffer in ipairs(markview.state.attached_buffers) do
+ if should_clean(buffer) == true then
+ table.remove(markview.state.attached_buffers, index);
+ markview.state.buffer_states[buffer] = nil;
- style = "block",
- hl = "MarkviewCode",
- info_hl = "MarkviewCodeInfo",
+ if markview.state.splitview_source == buffer then
+ markview.actions.splitClose();
+ end
+ end
+ end
+ ---_
+ ---_
+end
- min_width = 60,
- pad_amount = 3,
+--- Checks if the buffer is safe.
+---@param buffer integer?
+---@return boolean
+markview.buf_is_safe = function (buffer)
+ ---+${func}
+ markview.clean();
+
+ if not buffer then
+ return false;
+ elseif vim.api.nvim_buf_is_valid(buffer) == false then
+ return false;
+ elseif vim.v.exiting ~= vim.NIL then
+ return false;
+ end
- language_names = nil,
- language_direction = "right",
+ return true;
+ ---_
+end
- sign = true, sign_hl = nil
- ---_
- },
+--- Checks if the window is safe.
+---@param window integer?
+---@return boolean
+markview.win_is_safe = function (window)
+ ---+${func}
+ if not window then
+ return false;
+ elseif vim.api.nvim_win_is_valid(window) == false then
+ return false;
+ elseif vim.api.nvim_win_get_tabpage(window) ~= vim.api.nvim_get_current_tabpage() then
+ return false;
+ end
- footnotes = {
- enable = true,
- use_unicode = true,
- hl = "Special"
- },
+ return true;
+ ---_
+end
- headings = {
- ---+ ${class, Headings}
- enable = true,
- shift_width = 1,
-
- heading_1 = {
- ---+ ${conf, Heading 1}
- style = "icon",
- sign = "๓ฐ ", sign_hl = "MarkviewHeading1Sign",
-
- icon = "๓ฐผ ", hl = "MarkviewHeading1",
- ---_
- },
- heading_2 = {
- ---+ ${conf, Heading 2}
- style = "icon",
- sign = "๓ฐ ", sign_hl = "MarkviewHeading2Sign",
-
- icon = "๓ฐจ ", hl = "MarkviewHeading2",
- ---_
- },
- heading_3 = {
- ---+ ${conf, Heading 3}
- style = "icon",
-
- icon = "๓ฐผ ", hl = "MarkviewHeading3",
- ---_
- },
- heading_4 = {
- ---+ ${conf, Heading 4}
- style = "icon",
-
- icon = "๓ฐฒ ", hl = "MarkviewHeading4",
- ---_
- },
- heading_5 = {
- ---+ ${conf, Heading 5}
- style = "icon",
-
- icon = "๓ฐผ ", hl = "MarkviewHeading5",
- ---_
- },
- heading_6 = {
- ---+ ${conf, Heading 6}
- style = "icon",
-
- icon = "๓ฐด ", hl = "MarkviewHeading6",
- ---_
- },
-
- setext_1 = {
- ---+ ${conf, Setext heading 1}
- style = "decorated",
-
- sign = "๓ฐ ", sign_hl = "MarkviewHeading1Sign",
- icon = " ๎ชซ ", hl = "MarkviewHeading1",
- line = "โ"
- ---_
- },
- setext_2 = {
- ---+ ${conf, Setext heading 2}
- style = "decorated",
-
- sign = "๓ฐ ", sign_hl = "MarkviewHeading2Sign",
- icon = " ๎ชช ", hl = "MarkviewHeading2",
- line = "โ"
- ---_
- }
- ---_
- },
+--- Checks if the buffer can be attached to.
+---@param buffer integer
+---@return boolean
+markview.can_attach = function (buffer)
+ ---+${fund}
+ markview.clean();
+
+ if not markview.buf_is_safe(buffer) then
+ return false;
+ elseif vim.list_contains(markview.state.attached_buffers, buffer) then
+ return false;
+ end
- horizontal_rules = {
- ---+ ${class, Horizontal rules}
- enable = true,
+ return true;
+ ---_
+end
- parts = {
- {
- ---+ ${conf, Left portion}
- type = "repeating",
- repeat_amount = function () --[[@as function]]
- local textoff = vim.fn.getwininfo(vim.api.nvim_get_current_win())[1].textoff;
+--- Checks if decorations can be drawn on a buffer.
+---@param buffer integer
+---@return boolean
+markview.can_draw = function (buffer)
+ ---+${func}
+ markview.clean();
+
+ if not markview.buf_is_safe(buffer) then
+ return false;
+ elseif markview.state.buffer_states[buffer] == false then
+ return false;
+ end
- return math.floor((vim.o.columns - textoff - 3) / 2);
- end,
+ return true;
+ ---_
+end
- text = "โ",
- hl = {
- "MarkviewGradient1", "MarkviewGradient2", "MarkviewGradient3", "MarkviewGradient4", "MarkviewGradient5", "MarkviewGradient6", "MarkviewGradient7", "MarkviewGradient8", "MarkviewGradient9", "MarkviewGradient10"
- }
- ---_
- },
- {
- type = "text",
- text = " ๎ชช ",
- },
- {
- ---+ ${conf, Right portion}
- type = "repeating",
- repeat_amount = function () --[[@as function]]
- local textoff = vim.fn.getwininfo(vim.api.nvim_get_current_win())[1].textoff;
-
- return math.ceil((vim.o.columns - textoff - 3) / 2);
- end,
-
- direction = "right",
- text = "โ",
- hl = {
- "MarkviewGradient1", "MarkviewGradient2", "MarkviewGradient3", "MarkviewGradient4", "MarkviewGradient5", "MarkviewGradient6", "MarkviewGradient7", "MarkviewGradient8", "MarkviewGradient9", "MarkviewGradient10"
- }
- ---_
- }
- }
- ---_
- },
+--- Wrapper to clear decorations from a buffer
+---@param buffer integer
+markview.clear = function (buffer)
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
- html = {
- ---+ ${class, Html}
- enable = true,
+ require("markview.renderer").clear(buffer, 0, -1);
+end
- tags = {
- enable = true,
+--- Renders preview.
+---@param buffer integer?
+---@param state { enable: boolean, hybrid_mode: boolean? }?
+markview.render = function (buffer, state)
+ ---+${lua}
- default = {
- conceal = false
- },
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
- configs = {
- b = { conceal = true, hl = "Bold" },
- strong = { conceal = true, hl = "Bold" },
+ local parser = require("markview.parser");
+ local renderer = require("markview.renderer");
- u = { conceal = true, hl = "Underlined" },
+ ---@type integer Number of lines a buffer can have to be fully rendered.
+ local line_limit = spec.get({ "preview", "max_buf_lines" }, { fallback = 1000, ignore_enable = true });
+ ---@type [ integer, integer ] Number of lines to draw on large buffers.
+ local draw_range = spec.get({ "preview", "draw_range" }, { fallback = { vim.o.lines, vim.o.lines }, ignore_enable = true });
+ ---@type [ integer, integer ] Number of lines to be considered being edited.
+ local edit_range = spec.get({ "preview", "edit_range" }, { fallback = { 1, 0 }, ignore_enable = true });
- i = { conceal = true, hl = "Italic" },
- emphasize = { conceal = true, hl = "Italic" },
+ ---@type integer Buffer's line count.
+ local line_count = vim.api.nvim_buf_line_count(buffer);
- marked = { conceal = true, hl = "Special" },
- }
- },
+ ---@type string[] List of modes where to use hybrid_mode.
+ local hybrid_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {}, ignore_enable = true });
+ ---@type boolean Is line-wise hybrid mode enabled?
+ local linewise_hybrid_mode = spec.get({ "preview", "linewise_hybrid_mode" }, { fallback = false, ignore_enable = true })
- entities = {
- enable = true
- }
- ---_
- },
+ ---@type string Current mode shorthand.
+ local mode = vim.api.nvim_get_mode().mode;
- injections = {
- ---+ ${class, Query injections}
- enable = true,
- -- languages = {
- -- markdown = {
- -- enable = true,
- -- query = [[
- -- (section
- -- (atx_heading)
- -- ) @fold
- -- (#set! @fold)
- -- ]]
- -- }
- -- }
- ---_
- },
+ state = state or markview.state.buffer_states[buffer];
- inline_codes = {
- ---+ ${class, Inline codes}
- enable = true,
- corner_left = " ",
- corner_right = " ",
+ local function hybrid_mode()
+ if type(state) == "table" and state.hybrid_mode == false then
+ return false;
+ else
+ return vim.list_contains(hybrid_modes, mode);
+ end
+ end
- hl = "MarkviewInlineCode"
- ---_
- },
+ local content;
- latex = {
- ---+ ${class, Latex}
- enable = true,
+ markview.clear(buffer);
- brackets = {
- enable = true,
- hl = "@punctuation.brackets"
- },
-
- block = {
- enable = true,
-
- hl = "Code",
- text = { "๎ LaTeX ", "Special" }
- },
-
- inline = {
- enable = true
- },
-
- operators = {
- enable = true,
- configs = latex.operator_conf
- },
-
- symbols = {
- enable = true,
- hl = "@operator.latex",
- overwrite = {},
- groups = {
- {
- match = { "lim", "today" },
- hl = "Special"
- }
- }
- },
-
- subscript = {
- enable = true,
- hl = "MarkviewLatexSubscript",
- },
- superscript = {
- enable = true,
- hl = "MarkviewLatexSuperscript",
- },
- ---_
- },
+ if line_count <= line_limit then
+ content, _ = parser.parse(buffer, 0, -1, true);
- links = {
- ---+ ${class, Links}
- enable = true,
+ if hybrid_mode() == true and linewise_hybrid_mode == false then
+ for _, win in ipairs(vim.fn.win_findbuf(buffer)) do
+ ---@type [ integer, integer ] Cursor position.
+ local cursor = vim.api.nvim_win_get_cursor(win);
+ --- 1-index โ 0-index
+ cursor[1] = cursor[1] - 1;
+
+ content = renderer.filter(content, nil, {
+ math.max(0, cursor[1] - edit_range[1]),
+ math.min(cursor[1] + edit_range[2], line_count)
+ });
+ end
+
+ renderer.render(buffer, content);
+ elseif hybrid_mode() == true then
+ renderer.render(buffer, content);
- hyperlinks = {
- enable = true,
- __emoji_link_compatability = true,
+ for _, win in ipairs(vim.fn.win_findbuf(buffer)) do
+ ---@type [ integer, integer ] Cursor position.
+ local cursor = vim.api.nvim_win_get_cursor(win);
+ --- 1-index โ 0-index
+ cursor[1] = cursor[1] - 1;
- icon = "๓ฐท ",
- hl = "MarkviewHyperlink",
+ renderer.clear(buffer,
+ math.max(0, cursor[1] - edit_range[1]),
+ math.min(cursor[1] + 1 + edit_range[2], line_count)
+ );
+ end
+ else
+ renderer.render(buffer, content);
+ end
+ else
+ for _, win in ipairs(vim.fn.win_findbuf(buffer)) do
+ ---@type [ integer, integer ] Cursor position.
+ local cursor = vim.api.nvim_win_get_cursor(win);
+ --- 1-index โ 0-index
+ cursor[1] = cursor[1] - 1;
+
+ content, _ = parser.parse(buffer, math.max(0, cursor[1] - draw_range[1]), math.min(line_count, cursor[1] + draw_range[2]), true);
+
+ if hybrid_mode() == true and linewise_hybrid_mode == false then
+ content = renderer.filter(content, nil, {
+ math.max(0, cursor[1] - edit_range[1]),
+ math.min(cursor[1] + edit_range[2], line_count)
+ });
+ renderer.render(buffer, content);
+ elseif hybrid_mode() == true then
+ renderer.render(buffer, content);
+
+ renderer.clear(buffer,
+ math.max(0, cursor[1] - edit_range[1]),
+ math.min(cursor[1] + 1 + edit_range[2], line_count)
+ );
+ else
+ renderer.render(buffer, content);
+ end
+ end
+ end
+ ---_
+end
- custom = {
- ---+ ${conf, Stack*}
- { match_string = "stackoverflow%.com", icon = "๏
ฌ " },
- { match_string = "stackexchange%.com", icon = "๏ " },
- ---_
+--- Updates cursor position in splitview.
+markview.update_splitview_cursor = function ()
+ ---+${lua}
- { match_string = "neovim%.org", icon = "๏ฏ " },
+ local utils = require("markview.utils");
+ local buffer = markview.state.splitview_source;
- { match_string = "dev%.to", icon = "๎ปด " },
- { match_string = "github%.com", icon = "๏ " },
- { match_string = "reddit%.com", icon = "๏ก " },
- { match_string = "freecodecamp%.org", icon = "๎ " },
+ if markview.buf_is_safe(buffer) == false then
+ --- Buffer isn't safe.
+ -- markview.state.splitview_source = nil;
+ pcall(markview.actions.splitClose);
+ return;
+ elseif markview.win_is_safe(utils.buf_getwin(buffer)) == false then
+ --- Buffer doesn't have any windows attached.
+ pcall(markview.actions.splitClose);
+ return;
+ end
- { match_string = "https://(.+)$", icon = "๓ฐ " },
- { match_string = "http://(.+)$", icon = "๓ฐ " },
- { match_string = "[%.]md$", icon = "๎ฌ " }
- }
- },
- images = {
- enable = true,
- __emoji_link_compatability = true,
+ --- In case the preview buffer/window got
+ --- deleted, we should regenerate them.
+ markview.actions.__splitview_setup();
- icon = "๓ฐฅถ ",
- hl = "MarkviewImageLink",
+ local pre_win = markview.state.splitview_window;
- custom = {
- { match_string = "%.svg$", icon = "๓ฐก " },
- }
- },
- emails = {
- enable = true,
- __emoji_link_compatability = true,
-
- icon = "๏ ",
- hl = "MarkviewEmail"
- },
-
- internal_links = {
- enable = true,
- __emoji_link_compatability = true,
-
- icon = "๎ญ ",
- hl = "MarkviewHyperlink"
- }
- ---_
- },
+ local cursor = vim.api.nvim_win_get_cursor(utils.buf_getwin(buffer));
+ pcall(vim.api.nvim_win_set_cursor, pre_win, cursor);
- list_items = {
- ---+ ${class, List items}
- enable = true,
+ ---_
+end
- indent_size = 2,
- shift_width = 4,
+markview.splitview_render = function ()
+ ---+${lua}
- marker_minus = {
- add_padding = true,
+ local utils = require("markview.utils");
+ local buffer = markview.state.splitview_source;
- text = "๎ฉฑ",
- hl = "MarkviewListItemMinus"
- },
+ if markview.buf_is_safe(buffer) == false then
+ --- Buffer isn't safe.
+ -- markview.state.splitview_source = nil;
+ pcall(markview.actions.splitClose);
+ return;
+ elseif markview.win_is_safe(utils.buf_getwin(buffer)) == false then
+ --- Buffer doesn't have any windows attached.
+ pcall(markview.actions.splitClose);
+ return;
+ end
- marker_plus = {
- add_padding = true,
+ --- In case the preview buffer/window got
+ --- deleted, we should regenerate them.
+ markview.actions.__splitview_setup();
- text = "๎ชซ",
- hl = "MarkviewListItemPlus"
- },
+ local max_lines = spec.get({ "preview", "max_buf_lines" }, { fallback = 1000, ignore_enable = true });
+ local line_count = vim.api.nvim_buf_line_count(buffer);
- marker_star = {
- add_padding = true,
+ local main_win = utils.buf_getwin(buffer);
+ local cursor = vim.api.nvim_win_get_cursor(main_win);
- text = "๎ชฉ",
- hl = "MarkviewListItemStar"
- },
+ local pre_buf = markview.state.splitview_buffer;
+ local pre_win = markview.state.splitview_window;
- marker_dot = {
- add_padding = true
- },
+ local lines = vim.api.nvim_buf_get_lines(
+ buffer,
+ math.max(0, cursor[1] - (max_lines + 1)),
+ math.min(line_count, cursor[1] + (max_lines + 1)),
+ false
+ );
+ vim.api.nvim_buf_set_lines(
+ pre_buf,
+ math.max(0, cursor[1] - (max_lines + 1)),
+ math.min(line_count, cursor[1] + (max_lines + 1)),
+ false,
+ lines
+ );
- marker_parenthesis = {
- add_padding = true
- },
- ---_
- },
+ pcall(vim.api.nvim_win_set_cursor, pre_win, cursor);
- tables = {
- ---+ ${class, Tables}
+ markview.render(pre_buf, {
enable = true,
+ hybrid_mode = false
+ });
+ ---_
+end
- parts = {
- top = { "โญ", "โ", "โฎ", "โฌ" },
- header = { "โ", "โ", "โ" },
- separator = { "โ", "โ", "โค", "โผ" },
- row = { "โ", "โ", "โ" },
- bottom = { "โฐ", "โ", "โฏ", "โด" },
-
- overlap = { "โ", "โ", "โฅ", "โฟ" },
-
- align_left = "โผ",
- align_right = "โพ",
- align_center = { "โด", "โถ" }
- },
-
- hl = {
- top = { "TableHeader", "TableHeader", "TableHeader", "TableHeader" },
- header = { "TableHeader", "TableHeader", "TableHeader" },
- separator = { "TableHeader", "TableHeader", "TableHeader", "TableHeader" },
- row = { "TableBorder", "TableBorder", "TableBorder" },
- bottom = { "TableBorder", "TableBorder", "TableBorder", "TableBorder" },
-
- overlap = { "TableBorder", "TableBorder", "TableBorder", "TableBorder" },
-
- align_left = "TableAlignLeft",
- align_right = "TableAlignRight",
- align_center = { "TableAlignCenter", "TableAlignCenter" }
- },
-
- col_min_width = 10,
- block_decorator = true,
- use_virt_lines = true
- ---_
- }
-};
+-------------------------------------------------------------------------------------------
---- Split view related functions
----@class markview.splitView
----
----@field attached_buffer integer? Buffer ID of the currently attached buffer, `nil` if no buffer is attached
----@field augroup integer Autocmd group for scroll sync and closing the window
----
----@field close function Window closing function
----@field open function Window opening function
----@field init function Initializes the current buffer to be shown in a split
-markview.splitView = {
- attached_buffer = nil,
- augroup = vim.api.nvim_create_augroup("markview_splitview", { clear = true }),
-
- buffer = vim.api.nvim_create_buf(false, true),
- window = nil,
-
- close = function (self)
- pcall(vim.api.nvim_win_close, self.window, true);
- self.augroup = vim.api.nvim_create_augroup("markview_splitview", { clear = true });
-
- self.attached_buffer = nil;
- self.window = nil;
- end,
+--- Various actions(provides core functionalities of `markview.nvim`).
+markview.actions = {
+ ---+${lua}
- init = function (self, buffer)
- -- If buffer is already opened, exit
- if self.attached_buffer and (buffer == self.attached_buffer or buffer == self.buffer) then
+ ["__exec_callback"] = function (autocmd, ...)
+ if vim.list_contains({ "string", "integer" }, type(autocmd)) == false then
+ --- Invalid data type.
return;
end
- self.augroup = vim.api.nvim_create_augroup("markview_splitview", { clear = true });
-
- -- Register the buffer
- self.attached_buffer = buffer;
+ local callbacks = spec.get({ "preview", "callbacks" }, { fallback = nil, ignore_enable = true });
+ pcall(callbacks[autocmd], ...);
- local windows = utils.find_attached_wins(buffer);
+ health.notify("trace", {
+ level = 1,
+ message = {
+ { "Callback: ", "Special" },
+ { " " .. autocmd .. " ", "DiagnosticVirtualTextInfo" }
+ }
+ });
+ end,
+ ["__is_attached"] = function (buffer)
+ buffer = buffer or vim.api.nvim_get_current_buf();
+ return vim.list_contains(markview.state.attached_buffers, buffer);
+ end,
+ ["__is_enabled"] = function (buffer)
+ buffer = buffer or vim.api.nvim_get_current_buf();
- -- Buffer isn't attached to a window
- if #windows == 0 then
- windows = { vim.api.nvim_get_current_win() };
- -- return;
+ if vim.list_contains(markview.state.attached_buffers, buffer) == false then
+ return false;
+ elseif type(markview.state.buffer_states[buffer]) ~= "table" then
+ return false;
+ else
+ return markview.state.buffer_states[buffer].enable;
end
+ end,
- -- If window doesn't exist, open it
- if not self.window or vim.api.nvim_win_is_valid(self.window) == false then
- self.window = vim.api.nvim_open_win(self.buffer, false, vim.tbl_deep_extend("force", {
- win = windows[1],
- split = "right"
- }, markview.configuration.split_conf or {}));
+ ["__splitview_setup"] = function ()
+ --+${lua}
- pcall(markview.configuration.callbacks.split_enter, self.buffer, self.window);
- else
- vim.api.nvim_win_set_config(self.window, vim.tbl_deep_extend("force", {
- win = windows[1],
- split = "right"
- }, markview.configuration.split_conf or {}));
+ if markview.buf_is_safe(markview.state.splitview_source) == false then
+ return;
end
- local content = vim.api.nvim_buf_get_lines(buffer, 0, -1, false);
-
- -- Write text to the split buffer
- vim.bo[self.buffer].modifiable = true;
- vim.api.nvim_buf_set_lines(self.buffer, 0, -1, false, content);
- vim.bo[self.buffer].modifiable = false;
+ local utils = require("markview.utils");
+ local win = utils.buf_getwin(markview.state.splitview_source);
- vim.bo[self.buffer].filetype = vim.bo[buffer].filetype;
+ if markview.win_is_safe(win) == false then
+ markview.actions.splitClose();
+ return;
+ end
- vim.wo[self.window].number = false;
- vim.wo[self.window].relativenumber = false;
- vim.wo[self.window].statuscolumn = "";
+ if markview.buf_is_safe(markview.state.splitview_buffer) == false then
+ pcall(vim.api.nvim_buf_delete, markview.state.splitview_buffer, { force = true });
+ markview.state.splitview_buffer = vim.api.nvim_create_buf(false, true);
+ end
- vim.wo[self.window].cursorline = true;
+ vim.bo[markview.state.splitview_buffer].ft = vim.bo[markview.state.splitview_source].ft;
+
+ if markview.win_is_safe(markview.state.splitview_window) == false then
+ pcall(vim.api.nvim_win_close, markview.state.splitview_window, true);
+ markview.state.splitview_window = vim.api.nvim_open_win(
+ markview.state.splitview_buffer,
+ false,
+ spec.get({ "preview", "splitview_winopts", }, {
+ fallback = { split = "right" }
+ })
+ );
+ end
- -- Run callback
- pcall(markview.configuration.callbacks.on_enable, self.buf, self.window);
+ vim.wo[markview.state.splitview_window].wrap = vim.wo[win].wrap;
+ vim.wo[markview.state.splitview_window].linebreak = vim.wo[win].linebreak;
- local cursor = vim.api.nvim_win_get_cursor(windows[1]);
- pcall(vim.api.nvim_win_set_cursor, self.window, cursor);
+ ---_
+ end,
- vim.api.nvim_buf_clear_namespace(self.buffer, markview.renderer.namespace, 0, -1);
- local parsed_content;
+ ["traceExport"] = function ()
+ ---+${lua}
- if #content < markview.configuration.max_file_length then
- -- Buffer isn't too big. Render everything
- parsed_content = markview.parser.init(self.buffer, markview.configuration);
+ local scrolloff = vim.fn.getwininfo(vim.api.nvim_get_current_win())[1].textoff;
+ local buf_width = vim.o.columns - scrolloff;
- markview.renderer.render(self.buffer, parsed_content, markview.configuration)
- else
- -- Buffer is too big, render only parts of it
- local start = math.max(0, cursor[1] - markview.configuration.render_distance);
- local stop = math.min(lines, cursor[1] + markview.configuration.render_distance);
+ local version = vim.version();
+ local colorscheme = vim.g.colors_name or "";
- parsed_content = markview.parser.init(self.buffer, markview.configuration, start, stop);
+ local time_col = math.max(20, math.floor((buf_width - 7) * 0.2));
+ local desc_col = buf_width - (time_col + 3);
- markview.renderer.render(self.buffer, parsed_content, markview.configuration)
+ local function center (text, width)
+ if vim.fn.strdisplaywidth(text) > width then
+ return vim.fn.strcharpart(text, width);
+ else
+ local pad_amount = width - vim.fn.strdisplaywidth(text);
+ return string.rep(" ", math.ceil(pad_amount / 2)) .. text .. string.rep(" ", math.floor(pad_amount / 2));
+ end
end
+ local lines = {
+ "Plugin: markview.nvim",
+ "Time: " .. os.date(),
+ string.format("Nvim version: %d.%d.%d", version.major, version.minor, version.patch),
+ "Colorscheme: " .. colorscheme,
+ "",
+ "Level description,",
+ " 1 = START",
+ " 2 = PAUSE",
+ " 3 = STOP",
+ " 4 = ERROR",
+ " 5 = LOG",
+ " 6 = ENABLE",
+ " 7 = DISABLE",
+ " 8 = ATTACH",
+ " 9 = DETACH",
+ "",
+ "Trace,",
+ string.rep("-", time_col) .. "โข-------โข" .. string.rep("-", desc_col),
+ center("Time-stamp", time_col) .. "|" .. " Level " .. "|" .. center("Action", desc_col),
+ string.rep("-", time_col) .. "โข-------โข" .. string.rep("-", desc_col)
+ };
+
+ for _, entry in ipairs(health.log) do
+ if entry.kind ~= "trace" then
+ goto continue;
+ end
- local timer = vim.uv.new_timer();
+ ---@cast entry logs.trace
- vim.api.nvim_create_autocmd({
- "CursorMoved", "CursorMovedI"
- }, {
- group = self.augroup,
- buffer = buffer,
- callback = vim.schedule_wrap(function ()
- -- Set cursor
- cursor = vim.api.nvim_win_get_cursor(windows[1]);
- pcall(vim.api.nvim_win_set_cursor, self.window, cursor);
- end)
- });
+ table.insert(lines, string.format(
+ "%s|%s| %s",
+ center(
+ string.format("%-12s", string.rep(" ", entry.indent) .. entry.timestamp),
+ time_col
+ ),
+ center(tostring(entry.level or 0), 7),
+ entry.message
+ ));
- vim.api.nvim_create_autocmd({
- "BufHidden"
- }, {
- group = self.augroup,
- buffer = buffer,
- callback = vim.schedule_wrap(function ()
- self:close();
- end)
- });
- vim.api.nvim_create_autocmd({
- "BufHidden"
- }, {
- group = self.augroup,
- buffer = self.buffer,
- callback = vim.schedule_wrap(function ()
- markview.commands.splitDisable(self.attached_buffer);
- end)
- });
+ ::continue::
+ end
- vim.api.nvim_create_autocmd({
- "TextChanged", "TextChangedI"
- }, {
- group = self.augroup,
- buffer = buffer,
- callback = vim.schedule_wrap(function ()
- timer:stop();
- timer:start(50, 0, vim.schedule_wrap(function ()
- content = vim.api.nvim_buf_get_lines(buffer, 0, -1, false);
-
- -- Write text to the split buffer
- vim.bo[self.buffer].modifiable = true;
- vim.api.nvim_buf_clear_namespace(self.buffer, markview.renderer.namespace, 0, -1);
- vim.api.nvim_buf_set_lines(self.buffer, 0, -1, false, content);
- vim.bo[self.buffer].modifiable = false;
-
- if #content < markview.configuration.max_file_length then
- -- Buffer isn't too big. Render everything
- parsed_content = markview.parser.init(self.buffer, markview.configuration);
-
- markview.renderer.render(self.buffer, parsed_content, markview.configuration)
- else
- -- Buffer is too big, render only parts of it
- local start = math.max(0, cursor[1] - markview.configuration.render_distance);
- local stop = math.min(lines, cursor[1] + markview.configuration.render_distance);
-
- parsed_content = markview.parser.init(self.buffer, markview.configuration, start, stop);
-
- markview.renderer.render(self.buffer, parsed_content, markview.configuration)
- end
- end));
- end)
- });
+ table.insert(lines, string.rep("-", time_col) .. "โข-------โข" .. string.rep("-", desc_col))
+ table.insert(lines, "");
+ table.insert(lines, "vim:nomodifiable:nowrap:nospell:");
- return self;
- end
-};
+ local trace_file = io.open("trace.txt", "w");
-markview.commands = {
- attach = function (buf)
- vim.api.nvim_exec_autocmds("User", { pattern = "MarkviewEnter", buffer = buf })
+ if not trace_file then
+ return;
+ end
+
+ trace_file:write(table.concat(lines, "\n"));
+ trace_file:close();
+
+ ---_
end,
- detach = function (buf)
- vim.api.nvim_exec_autocmds("User", { pattern = "MarkviewLeave", buffer = buf })
+ ["traceShow"] = function (from, to)
+ health.trace_open(from, to);
end,
- toggleAll = function ()
- if markview.state.enable == true then
- markview.commands.disableAll();
- markview.state.enable = false;
- else
- markview.commands.enableAll();
- markview.state.enable = true;
- end
- end,
- enableAll = function ()
- markview.state.enable = true;
+ --- Registers a buffer to be preview-able.
+ ---@param buffer integer?
+ ["attach"] = function (buffer, state)
+ ---+${lua}
- for _, buf in ipairs(markview.attached_buffers) do
- if markview.splitView.window and buf == markview.splitView.attached_buffer and vim.api.nvim_win_is_valid(markview.splitView.window) then
- goto continue;
- elseif markview.splitView.window and buf == markview.splitView.buffer and vim.api.nvim_win_is_valid(markview.splitView.window) then
- goto continue;
- end
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
+
+ if markview.can_attach(buffer) == false then
+ --- Failed to attach.
+ return;
+ end
- local parsed_content = markview.parser.init(buf, markview.configuration);
- local windows = utils.find_attached_wins(buf);
+ health.notify("trace", {
+ level = 8,
+ message = string.format("Attached: %d", buffer)
+ });
+ health.__child_indent_in();
+
+ ---@type boolean Should preview be enabled on the buffer?
+ local enable = spec.get({ "preview", "enable" }, { fallback = true, ignore_enable = true });
+ ---@type boolean Should hybrid mode be enabled on the buffer?
+ local hm_enable = spec.get({ "preview", "enable_hybrid_mode" }, { fallback = true, ignore_enable = true });
+
+ table.insert(markview.state.attached_buffers, buffer);
+
+ if state then
+ markview.state.buffer_states[buffer] = state;
+ elseif markview.state.buffer_states[buffer] == nil then
+ markview.state.buffer_states[buffer] = {
+ enable = enable,
+ events = true,
+ hybrid_mode = hm_enable,
+ };
+ end
- if markview.configuration.callbacks and markview.configuration.callbacks.on_enable then
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_enable, buf, window);
- end
- end
+ vim.api.nvim_buf_set_keymap(buffer, "n", "gx", "Markview open", { desc = "Tree-sitter based link opener from `markview.nvim`." });
- markview.state.buf_states[buf] = true;
+ --- Execute the attaching callback.
+ markview.actions.__exec_callback("on_attach", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewAttach",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
- markview.renderer.clear(buf);
- markview.renderer.render(buf, parsed_content, markview.configuration);
+ if enable == true then
+ markview.actions.__exec_callback("on_enable", buffer, vim.fn.win_findbuf(buffer))
- ::continue::
+ --- Execute the enable/disable one too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewEnable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
+ markview.render(buffer);
+
+ if hm_enable == true then
+ --- Execute the hybrid mode enabling callback.
+ markview.actions.__exec_callback("on_hybrid_enable", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewHybridEnable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
+ else
+ --- Execute the hybrid mode disabling callback.
+ markview.actions.__exec_callback("on_hybrid_disable", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewHybridDisable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
+ end
+ else
+ markview.actions.__exec_callback("on_disable", buffer, vim.fn.win_findbuf(buffer))
+ markview.clear(buffer);
+
+ --- Execute the enable/disable one too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewDisable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
end
+
+ health.__child_indent_de();
+ ---_
end,
- disableAll = function ()
- for _, buf in ipairs(markview.attached_buffers) do
- if markview.splitView.window and buf == markview.splitView.attached_buffer and vim.api.nvim_win_is_valid(markview.splitView.window) then
- goto continue;
- elseif markview.splitView.window and buf == markview.splitView.buffer and vim.api.nvim_win_is_valid(markview.splitView.window) then
- goto continue;
- end
+ --- Detaches previewer from a buffer.
+ ---@param buffer integer?
+ ["detach"] = function (buffer)
+ ---+${lua}
- local windows = utils.find_attached_wins(buf);
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
- if markview.configuration.callbacks and markview.configuration.callbacks.on_disable then
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_disable, buf, window);
- end
- end
+ if markview.buf_is_safe(buffer) == false then
+ --- Something went wrong.
+ return;
+ elseif markview.can_attach(buffer) == true then
+ --- This buffer hasn't been attached to.
+ return;
+ end
- markview.state.buf_states[buf] = false;
- markview.renderer.clear(buf);
+ health.notify("trace", {
+ level = 9,
+ message = string.format("Detached: %d", buffer)
+ });
+ health.__child_indent_in();
+
+ --- Execute the attaching autocmd.
+ markview.actions.__exec_callback("on_detach", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewDetach",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
- ::continue::
+ --- Remove the entry.
+ --- DON'T REMOVE THE STATES THOUGH!
+ --- (We may need them in the future)
+ for i, buf in ipairs(markview.state.attached_buffers) do
+ if buf == buffer then
+ table.remove(markview.state.attached_buffers, i);
+ end
end
- markview.state.enable = false;
+ --- Clear decorations too!
+ markview.clear(buffer);
+ health.__child_indent_de()
+ ---_
end,
- toggle = function (buf)
- local buffer = tonumber(buf) or vim.api.nvim_get_current_buf();
+ ["disable"] = function (buffer)
+ ---+${lua}
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
- if not vim.list_contains(markview.attached_buffers, buffer) or not vim.api.nvim_buf_is_valid(buffer) then
+ if markview.actions.__is_attached(buffer) == false then
return;
- elseif markview.splitView.window and buf == markview.splitView.buffer and vim.api.nvim_win_is_valid(markview.splitView.window) then
+ elseif type(markview.state.buffer_states[buffer]) ~= "table" then
+ markview.state.buffer_states[buffer] = nil;
+ return;
+ elseif buffer == markview.state.splitview_source then
+ markview.state.buffer_states[buffer].enable = false;
+ markview.state.buffer_states[buffer].y = -999;
+
return;
end
- local state = markview.state.buf_states[buffer];
+ health.notify("trace", {
+ level = 7,
+ message = string.format("Disabled: %d", buffer)
+ });
+ health.__child_indent_in();
+
+ markview.state.buffer_states[buffer].enable = false;
+ markview.clear(buffer);
+
+ --- Execute the attaching autocmd.
+ markview.actions.__exec_callback("on_disable", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewDisable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
+
+ local mode = vim.api.nvim_get_mode().mode;
+ ---@type string[]
+ local hybd_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
- if state == true then
- markview.commands.disable(buffer)
- state = false;
- else
- markview.commands.enable(buffer);
- state = true;
+ if vim.list_contains(hybd_modes, mode) == false then
+ health.__child_indent_de();
+ return;
end
+
+ --- Execute the attaching autocmd.
+ markview.actions.__exec_callback("on_hybrid_disable", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewHybridDisable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
+ health.__child_indent_de();
+ ---_
end,
- enable = function (buf)
- local buffer = tonumber(buf) or vim.api.nvim_get_current_buf();
+ ["enable"] = function (buffer)
+ ---+${lua}
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
- if not vim.list_contains(markview.attached_buffers, buffer) or not vim.api.nvim_buf_is_valid(buffer) then
+ if markview.actions.__is_attached(buffer) == false then
+ return;
+ elseif type(markview.state.buffer_states[buffer]) ~= "table" then
+ markview.state.buffer_states[buffer] = nil;
+ return;
+ elseif buffer == markview.state.splitview_source then
+ markview.state.buffer_states[buffer].enable = true;
+ markview.splitview_render();
return;
end
- local windows = utils.find_attached_wins(buffer);
+ health.notify("trace", {
+ level = 6,
+ message = string.format("Enabled: %d", buffer)
+ });
+ health.__child_indent_in();
- markview.state.buf_states[buffer] = true;
+ markview.state.buffer_states[buffer].enable = true;
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_enable, buf, window);
- end
-
- local lines = vim.api.nvim_buf_line_count(buffer);
- local parsed_content;
+ local mode = vim.api.nvim_get_mode().mode;
+ ---@type string[]
+ local prev_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ ---@type string[]
+ local hybd_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
- if lines < markview.configuration.max_file_length then
- -- Buffer isn't too big. Render everything
- parsed_content = markview.parser.init(buffer, markview.configuration);
+ if vim.list_contains(prev_modes, mode) == false then
+ health.__child_indent_de();
+ return;
+ end
- markview.renderer.render(buffer, parsed_content, markview.configuration)
- else
- -- Buffer is too big, render only parts of it
- local cursor = vim.api.nvim_win_get_cursor(0);
- local start = math.max(0, cursor[1] - markview.configuration.render_distance);
- local stop = math.min(lines, cursor[1] + (markview.configuration.render_distance));
+ markview.render(buffer);
- parsed_content = markview.parser.init(buffer, markview.configuration, start, stop);
+ --- Execute the attaching autocmd.
+ markview.actions.__exec_callback("on_enable", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewEnable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
- markview.renderer.render(buffer, parsed_content, markview.configuration)
+ if vim.list_contains(hybd_modes, mode) == false then
+ health.__child_indent_de();
+ return;
end
+
+ --- Execute the attaching autocmd.
+ markview.actions.__exec_callback("on_hybrid_enable", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewHybridEnable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
+ health.__child_indent_de();
+ ---_
end,
- disable = function (buf)
- local buffer = tonumber(buf) or vim.api.nvim_get_current_buf();
+ ["hybridEnable"] = function (buffer)
+ ---+${lua}
- if not vim.list_contains(markview.attached_buffers, buffer) or not vim.api.nvim_buf_is_valid(buffer) then
+ buffer = buffer or vim.api.nvim_get_current_buf();
+
+ if markview.actions.__is_attached(buffer) == false then
return;
- end
+ elseif markview.state.buffer_states[buffer] then
+ markview.state.buffer_states[buffer].hybrid_mode = true;
+
+ if markview.state.buffer_states[buffer].enable == false then
+ return;
+ elseif buffer == markview.state.splitview_source then
+ return;
+ end
+
+ markview.render(buffer);
- local windows = utils.find_attached_wins(buffer);
+ local mode = vim.api.nvim_get_mode().mode;
+ ---@type string[]
+ local hybd_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_disable, buf, window);
+ if vim.list_contains(hybd_modes, mode) == false then
+ return;
+ end
+
+ --- Execute the attaching autocmd.
+ markview.actions.__exec_callback("on_hybrid_enable", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewHybridEnable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
end
- markview.renderer.clear(buffer);
- markview.state.buf_states[buffer] = false;
+ ---_
end,
- splitToggle = function (buf)
- local buffer = tonumber(buf) or vim.api.nvim_get_current_buf();
+ ["hybridDisable"] = function (buffer)
+ --+${lua}
- if markview.splitView.attached_buffer and vim.api.nvim_buf_is_valid(markview.splitView.attached_buffer) then
- if buffer == markview.splitView.attached_buffer then
- markview.commands.splitDisable(buf);
- else
- markview.commands.enable(markview.splitView.attached_buffer);
- markview.commands.splitEnable(buf);
+ buffer = buffer or vim.api.nvim_get_current_buf();
+
+ if markview.actions.__is_attached(buffer) == false then
+ return;
+ elseif markview.state.buffer_states[buffer] then
+ markview.state.buffer_states[buffer].hybrid_mode = false;
+
+ if markview.state.buffer_states[buffer].enable == false then
+ return;
+ elseif buffer == markview.state.splitview_source then
+ return;
end
- else
- markview.commands.splitEnable(buf);
+
+ markview.render(buffer);
+
+ local mode = vim.api.nvim_get_mode().mode;
+ ---@type string[]
+ local hybd_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
+
+ if vim.list_contains(hybd_modes, mode) == false then
+ return;
+ end
+
+ --- Execute the attaching autocmd.
+ markview.actions.__exec_callback("on_hybrid_disable", buffer, vim.fn.win_findbuf(buffer))
+ --- Execute the autocmd too.
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewHybridDisable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
end
+
+ ---_
end,
- splitDisable = function (buf)
- local buffer = tonumber(buf) or vim.api.nvim_get_current_buf();
+ ["splitOpen"] = function (buffer)
+ --++${lua}
+
+ ---@type integer
+ buffer = buffer or vim.api.nvim_get_current_buf();
- if not vim.list_contains(markview.attached_buffers, buffer) or not vim.api.nvim_buf_is_valid(buffer) then
+ if markview.buf_is_safe(buffer) == false then
return;
end
- markview.splitView:close();
- markview.state.buf_states[buffer] = true;
+ markview.actions.splitClose();
- local mode = vim.api.nvim_get_mode().mode;
+ if markview.actions.__is_enabled(buffer) == true then
+ markview.actions.__exec_callback("on_disable", buffer, vim.fn.win_findbuf(buffer));
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewDisable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
+ end
- if markview.state.enable == false or not vim.list_contains(markview.configuration.modes, mode) then
+ markview.state.splitview_source = buffer;
+ markview.actions.__splitview_setup();
+ markview.clear(buffer);
+
+ markview.actions.__exec_callback("on_splitview_open", buffer, markview.state.splitview_buffer, markview.state.splitview_window);
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewSplitviewOpen",
+ data = {
+ source = buffer,
+ preview_buffer = markview.state.splitview_buffer,
+ preview_window = markview.state.splitview_window
+ }
+ });
+
+ markview.splitview_render();
+ ---_
+ end,
+ ["splitClose"] = function ()
+ ---+${lua}
+ if type(markview.state.splitview_source) ~= "number" then
+ --- Splitview's source buffer isn't a number. Why?
+ --- Assuming it's `nil`, we should stop here.
return;
end
- local windows = utils.find_attached_wins(buffer);
+ --- FEAT, Allow `on_splitview_close` to take arguments
+ --- regarding splitview.
+ markview.actions.__exec_callback("on_splitview_close", buffer, markview.state.splitview_buffer, markview.state.splitview_window);
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewSplitviewClose",
+ data = {
+ source = markview.state.splitview_source,
+ preview_buffer = markview.state.splitview_buffer,
+ preview_window = markview.state.splitview_window
+ }
+ });
- local parsed_content = markview.parser.init(buffer, markview.configuration);
+ --- Attempt to close the window.
+ --- Also remove the reference to that window.
+ pcall(vim.api.nvim_win_close, markview.state.splitview_window, true);
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_enable, buf, window);
+ --- We should also clean up the preview buffer(if possible).
+ if markview.buf_is_safe(markview.state.splitview_buffer) == true then
+ markview.clear(markview.state.splitview_buffer);
+ vim.api.nvim_buf_set_lines(markview.state.splitview_buffer, 0, -1, false, {});
end
- markview.renderer.clear(buffer);
- markview.renderer.render(buffer, parsed_content, markview.configuration)
- end,
+ ---@type integer
+ local buffer = markview.state.splitview_source;
- splitEnable = function (buf)
- local buffer = tonumber(buf) or vim.api.nvim_get_current_buf();
+ markview.state.splitview_window = nil;
+ markview.state.splitview_source = nil;
- if not vim.list_contains(markview.attached_buffers, buffer) or not vim.api.nvim_buf_is_valid(buffer) then
+ if markview.buf_is_safe(buffer) == false then
+ --- Source buffer isn't safe for `markview` to work.
+ return;
+ elseif type(markview.state.buffer_states[buffer]) ~= "table" then
+ --- We never attached to the source buffer.
return;
end
- local windows = utils.find_attached_wins(buffer);
+ markview.actions.__exec_callback("on_enable", buffer, vim.fn.win_findbuf(buffer));
+ vim.api.nvim_exec_autocmds("User", {
+ pattern = "MarkviewEnable",
+ data = {
+ buffer = buffer,
+ windows = vim.fn.win_findbuf(buffer)
+ }
+ });
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_disable, buf, window);
+ --- Don't forget to render the preview if possible.
+ if markview.state.buffer_states[buffer].enable == true then
+ markview.render(buffer);
end
+ ---_
+ end
+
+ ---_
+};
- markview.renderer.clear(buffer);
- markview.state.buf_states[buffer] = false;
+--- Holds various functions that you can run
+--- vim `:Markview ...`.
+---@type { [string]: function }
+markview.commands = {
+ ---+${class}
- markview.splitView:init(buffer);
+ ["traceExport"] = function ()
+ markview.actions.traceExport();
end,
-
- hybridToggle = function ()
- if markview.state.hybrid_mode == false then
- markview.state.hybrid_mode = true;
+ ["traceShow"] = function (from, to)
+ if pcall(tonumber, from) and pcall(tonumber, to) then
+ health.trace_open(tonumber(from), tonumber(to));
else
- markview.state.hybrid_mode = false;
+ health.trace_open();
end
end,
- hybridEnable = function ()
- markview.state.hybrid_mode = true;
+
+ ["attach"] = function (buffer)
+ markview.actions.attach(buffer);
end,
- hybridDisable = function ()
- markview.state.hybrid_mode = false;
+ ["detach"] = function (buffer)
+ markview.actions.detach(buffer);
end,
-}
+ ["Toggle"] = function ()
+ ---+${class}
+ markview.clean();
-vim.api.nvim_create_autocmd({ "colorscheme" }, {
- callback = function ()
- if type(markview.configuration.highlight_groups) == "string" or vim.islist(markview.configuration.highlight_groups) then
- ---@diagnostic disable-next-line
- hls.create(markview.configuration.highlight_groups)
+ for _, buf in ipairs(markview.state.attached_buffers) do
+ markview.commands.toggle(buf);
end
- end
-})
+ ---_
+ end,
+ ["Enable"] = function ()
+ markview.clean();
-vim.api.nvim_create_user_command("Markview", function (opts)
- local fargs = opts.fargs;
+ for _, buf in ipairs(markview.state.attached_buffers) do
+ markview.actions.enable(buf);
+ end
+ end,
+ ["Disable"] = function ()
+ markview.clean();
- if #fargs < 1 then
- markview.commands.toggleAll();
- elseif #fargs == 1 and markview.commands[fargs[1]] then
- markview.commands[fargs[1]]();
- elseif #fargs == 2 and markview.commands[fargs[1]] then
- markview.commands[fargs[1]](fargs[2]);
- end
-end, {
- nargs = "*",
- desc = "Controls for Markview.nvim",
- complete = function (arg_lead, cmdline, _)
- if arg_lead == "" then
- if not cmdline:find("^Markview%s+%S+") then
- return vim.tbl_keys(markview.commands);
- elseif cmdline:find("^Markview%s+(%S+)%s*$") then
- for cmd, _ in cmdline:gmatch("Markview%s+(%S+)%s*(%S*)") do
- -- ISSUE: Find a better way to find commands that accept arguments
- if vim.list_contains({ "enable", "disable", "toggle", "splitToggle" }, cmd) then
- local bufs = {};
-
- for _, buf in ipairs(markview.attached_buffers) do
- table.insert(bufs, tostring(buf));
- end
-
- return bufs;
- end
- end
+ for _, buf in ipairs(markview.state.attached_buffers) do
+ markview.actions.disable(buf);
+ end
+ end,
+
+ ["Render"] = function ()
+ markview.clean();
+
+ for _, buf in ipairs(markview.state.attached_buffers) do
+ if markview.actions.__is_enabled(buf) then
+ markview.render(buf);
end
end
+ end,
+ ["Clear"] = function ()
+ markview.clean();
- for cmd, arg in cmdline:gmatch("Markview%s+(%S+)%s*(%S*)") do
- if arg_lead == cmd then
- local cmds = vim.tbl_keys(markview.commands);
- local completions = {};
+ for _, buf in ipairs(markview.state.attached_buffers) do
+ if markview.actions.__is_enabled(buf) then
+ markview.clear(buf);
+ end
+ end
+ end,
- for _, key in pairs(cmds) do
- if arg_lead == string.sub(key, 1, #arg_lead) then
- table.insert(completions, key)
- end
- end
+ ["render"] = function (buffer)
+ markview.clean();
+ buffer = buffer or vim.api.nvim_get_current_buf();
- return completions
- elseif arg_lead == arg then
- local buf_complete = {};
+ markview.render(buffer);
+ end,
+ ["clear"] = function (buffer)
+ markview.clean();
+ buffer = buffer or vim.api.nvim_get_current_buf();
- for _, buf in ipairs(markview.attached_buffers) do
- if tostring(buf):match(arg) then
- table.insert(buf_complete, tostring(buf))
- end
- end
+ markview.clear(buffer);
+ end,
- return buf_complete;
- end
+ ["toggleAll"] = function ()
+ health.notify("deprecation", {
+ option = ":Markview toggleAll",
+ alter = ":Markview Toggle",
+ silent = true
+ });
+
+ markview.commands.Toggle();
+ end,
+ ["enableAll"] = function ()
+ health.notify("deprecation", {
+ option = ":Markview enableAll",
+ alter = ":Markview Enable",
+ silent = true
+ });
+
+ markview.commands.Enable();
+ end,
+ ["disableAll"] = function ()
+ health.notify("deprecation", {
+ option = ":Markview disableAll",
+ alter = ":Markview Disable",
+ silent = true
+ });
+
+ markview.commands.Disable();
+ end,
+
+ ["toggle"] = function (buffer)
+ ---+${class}
+ buffer = buffer or vim.api.nvim_get_current_buf();
+ markview.clean();
+
+ local state = markview.state.buffer_states[buffer];
+
+ if state == nil then
+ return;
+ elseif state.enable == true then
+ markview.commands.disable(buffer);
+ else
+ markview.commands.enable(buffer);
end
- end
-});
-
-markview.unload = function (buffer)
- for index, buf in ipairs(markview.attached_buffers) do
- if buffer and buf == buffer then
- table.remove(markview.attached_buffers, index);
- elseif vim.api.nvim_buf_is_valid(buf) == false then
- table.remove(markview.attached_buffers, index);
+ ---_
+ end,
+ ["enable"] = function (buffer)
+ markview.actions.enable(buffer)
+ end,
+ ["disable"] = function (buffer)
+ markview.actions.disable(buffer)
+ end,
+
+ ["hybridToggle"] = function (buffer)
+ buffer = buffer or vim.api.nvim_get_current_buf();
+
+ if markview.actions.__is_attached(buffer) == false then
+ return;
+ elseif type(markview.state.buffer_states[buffer]) ~= "table" then
+ return;
+ elseif markview.state.buffer_states[buffer].hybrid_mode == true then
+ markview.actions.hybridDisable(buffer);
+ else
+ markview.actions.hybridEnable(buffer);
end
- end
+ end,
+ ["hybridDisable"] = function (buffer)
+ markview.actions.hybridDisable(buffer);
+ end,
+ ["hybridEnable"] = function (buffer)
+ markview.actions.hybridEnable(buffer);
+ end,
+
+ ["HybridToggle"] = function ()
+ markview.clean();
- for index, win in ipairs(markview.attached_windows) do
- if buffer and vim.api.nvim_win_is_valid(win) and vim.api.nvim_win_get_buf(win) == buffer then
- table.remove(markview.attached_windows, index);
- elseif vim.api.nvim_win_is_valid(win) == false then
- table.remove(markview.attached_windows, index);
+ for _, buf in ipairs(markview.state.attached_buffers) do
+ markview.commands.hybridToggle(buf);
end
- end
-end
+ end,
-markview.setup = function (user_config)
- if user_config and user_config.highlight_groups then
- if vim.islist(user_config.highlight_groups) then
- if vim.islist(markview.configuration.highlight_groups) then
- markview.configuration.highlight_groups = vim.list_extend(markview.configuration.highlight_groups, user_config.highlight_groups);
- else
- markview.configuration.highlight_groups = vim.list_extend(hls[markview.configuration.highlight_groups], user_config.highlight_groups);
- end
+ ["HybridDisable"] = function ()
+ markview.clean();
+
+ for _, buf in ipairs(markview.state.attached_buffers) do
+ markview.commands.hybridDisable(buf);
+ end
+ end,
+
+ ["HybridEnable"] = function ()
+ markview.clean();
+
+ for _, buf in ipairs(markview.state.attached_buffers) do
+ markview.commands.hybridEnable(buf);
+ end
+ end,
+
+ ["splitToggle"] = function ()
+ ---+${class}
+
+ if type(markview.state.splitview_source) ~= "number" then
+ markview.actions.splitOpen();
+ elseif markview.win_is_safe(markview.state.splitview_window) == false then
+ markview.actions.splitClose();
+ markview.actions.splitOpen();
else
- markview.configuration.highlight_groups = user_config.highlight_groups;
+ markview.actions.splitClose();
end
- end
+ ---_
+ end,
- ---@type markview.configuration
- -- Merged configuration tables
- markview.configuration = vim.tbl_deep_extend("force", markview.configuration, user_config or {});
+ ["splitRedraw"] = function ()
+ markview.splitview_render();
+ end,
- if type(markview.configuration.highlight_groups) == "string" or vim.islist(markview.configuration.highlight_groups) then
- ---@diagnostic disable-next-line
- hls.create(markview.configuration.highlight_groups);
- end
+ ["splitOpen"] = function (buffer)
+ markview.actions.splitOpen(buffer)
+ end,
- ts.inject(markview.configuration.injections);
+ ["splitClose"] = function ()
+ markview.actions.splitClose()
+ end,
- if markview.state.enable ~= true then
- return;
+ ["Start"] = function ()
+ markview.state.enable = true;
+ end,
+ ["Stop"] = function ()
+ markview.state.enable = false;
+ end,
+
+ ["open"] = function ()
+ require("markview.links").open();
end
- markview.commands.enableAll();
+ ---_
+};
+
+-------------------------------------------------------------------------------------------
+
+--- Plugin setup function(optional)
+---@param config table?
+markview.setup = function (config)
+ spec.setup(config);
+ highlights.setup(spec.get({ "highlight_groups" }, { fallback = {} }));
+ markview.commands.Render();
end
return markview;
diff --git a/lua/markview/colors.lua b/lua/markview/colors.lua
deleted file mode 100644
index 2d895bb..0000000
--- a/lua/markview/colors.lua
+++ /dev/null
@@ -1,310 +0,0 @@
-local colors = {};
-
----@deprecated
-colors.clamp = function (val, min, max)
- return math.min(math.max(val, min), max)
-end
-
----@deprecated
-colors.lerp = function (x, y, t)
- return x + ((y - x) * t);
-end
-
----@deprecated
-colors.name_to_hex = function (name)
- ---+ ##code##
- local lookup = {
- ["red"] = "#FF0000", ["lightred"] = "#FFBBBB", ["darkred"] = "#8B0000",
- ["green"] = "#00FF00", ["lightgreen"] = "#90EE90", ["darkgreen"] = "#006400", ["seagreen"] = "#2E8B57",
- ["blue"] = "#0000FF", ["lightblue"] = "#ADD8E6", ["darkblue"] = "#00008B", ["slateblue"] = "#6A5ACD",
- ["cyan"] = "#00FFFF", ["lightcyan"] = "#E0FFFF", ["darkcyan"] = "#008B8B",
- ["magenta"] = "#FF00FF", ["lightmagenta"] = "#FFBBFF", ["darkmagenta"] = "#8B008B",
- ["yellow"] = "#FFFF00", ["lightyellow"] = "#FFFFE0", ["darkyellow"] = "#BBBB00", ["brown"] = "#A52A2A",
- ["grey"] = "#808080", ["lightgrey"] = "#D3D3D3", ["darkgrey"] = "#A9A9A9",
- ["gray"] = "#808080", ["lightgray"] = "#D3D3D3", ["darkgray"] = "#A9A9A9",
- ["black"] = "#000000", ["white"] = "#FFFFFF",
- ["orange"] = "#FFA500", ["purple"] = "#800080", ["violet"] = "#EE82EE"
- };
-
- local lookup_nvim = {
- ["nvimdarkblue"] = "#004C73", ["nvimlightblue"] = "#A6DBFF",
- ["nvimdarkcyan"] = "#007373", ["nvimlightcyan"] = "#8CF8F7",
- ["nvimdarkgray1"] = "#07080D", ["nvimlightgray1"] = "#EEF1F8",
- ["nvimdarkgray2"] = "#14161B", ["nvimlightgray2"] = "#E0E2EA",
- ["nvimdarkgray3"] = "#2C2E33", ["nvimlightgray3"] = "#C4C6CD",
- ["nvimdarkgray4"] = "#4F5258", ["nvimlightgray4"] = "#9B9EA4",
- ["nvimdarkgrey1"] = "#07080D", ["nvimlightgrey1"] = "#EEF1F8",
- ["nvimdarkgrey2"] = "#14161B", ["nvimlightgrey2"] = "#E0E2EA",
- ["nvimdarkgrey3"] = "#2C2E33", ["nvimlightgrey3"] = "#C4C6CD",
- ["nvimdarkgrey4"] = "#4F5258", ["nvimlightgrey4"] = "#9B9EA4",
- ["nvimdarkgreen"] = "#005523", ["nvimlightgreen"] = "#B3F6C0",
- ["nvimdarkmagenta"] = "#470045", ["nvimlightmagenta"] = "#FFCAFF",
- ["nvimdarkred"] = "#590008", ["nvimlightred"] = "#FFC0B9",
- ["nvimdarkyellow"] = "#6B5300", ["nvimlightyellow"] = "#FCE094",
- };
- ---_
-
- return lookup[string.lower(name)] or lookup_nvim[string.lower(name)];
-end
-
----@deprecated
-colors.name_to_rgb = function (name)
- local hex = colors.name_to_hex(name);
-
- if not hex then
- return;
- end
-
- return colors.hex_to_rgb(hex);
-end
-
----@deprecated
-colors.num_to_hex = function (num)
- if not num then
- return;
- end
-
- if num == 0 then
- return "#000000";
- elseif num ~= nil then
- return string.format("#%06X", num);
- end
-end
-
----@deprecated
-colors.num_to_rgb = function (num)
- if not num then
- return;
- end
-
- local hex = string.format("%x", num);
-
- return {
- r = tonumber(hex:sub(1, 2), 16),
- g = tonumber(hex:sub(3, 4), 16),
- b = tonumber(hex:sub(5, 6), 16),
- }
-end
-
----@deprecated
-colors.hex_to_rgb = function (str)
- str = str:gsub("#", "");
-
- if #str == 3 then
- return {
- r = tonumber(str:sub(1, 1), 16),
- g = tonumber(str:sub(2, 2), 16),
- b = tonumber(str:sub(3, 3), 16),
- }
- elseif #str == 6 then
- return {
- r = tonumber(str:sub(1, 2), 16),
- g = tonumber(str:sub(3, 4), 16),
- b = tonumber(str:sub(5, 6), 16),
- }
- end
-end
-
----@deprecated
-colors.rgb_to_hex = function (tbl)
- return string.format("#%02X%02X%02X", tbl.r, tbl.g, tbl.b);
-end
-
-colors.get_hl_value = function (ns_id, hl_group, value)
- if vim.fn.hlexists(hl_group) == 0 then
- return;
- end
-
- local hl = vim.api.nvim_get_hl(ns_id, { name = hl_group, link = false, create = false });
-
- if value == "fg" then
- if type(hl.fg) == "string" and hl.fg:match("^[#]?(%x+)$") then
- return colors.name_to_hex(hl.fg)
- else
- return colors.num_to_hex(hl.fg)
- end
- elseif value == "bg" then
- if type(hl.bg) == "string" and hl.bg:match("^[#]?(%x+)$") then
- return colors.name_to_hex(hl.bg)
- else
- return colors.num_to_hex(hl.bg)
- end
- elseif value == "sp" then
- if type(hl.sp) == "string" and hl.sp:match("^[#]?(%x+)$") then
- return colors.name_to_hex(hl.sp)
- else
- return colors.num_to_hex(hl.sp)
- end
- else
- return hl[value];
- end
-end
-
----@deprecated
-colors.create_gradient = function (name_prefix, from, to, steps, mode)
- local start, stop;
-
- if type(from) == "table" then
- start = from;
- elseif type(from) == "string" then
- start = colors.hex_to_rgb(from);
- end
-
- if type(to) == "table" then
- stop = to;
- elseif type(to) == "string" then
- stop = colors.hex_to_rgb(to);
- end
-
- local _t = {};
-
- for s = 0, (steps - 1) do
- local r = colors.lerp(start.r, stop.r, s / (steps - 1));
- local g = colors.lerp(start.g, stop.g, s / (steps - 1));
- local b = colors.lerp(start.b, stop.b, s / (steps - 1));
-
- local _o = {};
-
- if mode == "fg" then
- _o.fg = colors.rgb_to_hex({ r = r, g = g, b = b });
- elseif mode == "bg" then
- _o.bg = colors.rgb_to_hex({ r = r, g = g, b = b });
- elseif mode == "both" then
- _o.bg = colors.rgb_to_hex({ r = r, g = g, b = b });
- _o.fg = colors.rgb_to_hex({ r = r, g = g, b = b });
- end
-
- table.insert(_t, {
- group_name = (name_prefix or "") .. tostring(s + 1),
- value = _o
- })
- end
-
- return _t;
-end
-
----@deprecated
-colors.mix = function (color_1, color_2, per_1, per_2)
- local c_1, c_2;
-
- if type(color_1) == "table" then
- c_1 = color_1;
- elseif type(color_1) == "string" and color_1:match("^[#]?(%x+)$") then
- c_1 = colors.hex_to_rgb(color_1);
- elseif type(color_1) == "string" then
- c_1 = colors.name_to_rgb(color_1);
- end
-
- if type(color_2) == "table" then
- c_2 = color_2;
- elseif type(color_2) == "string" and color_2:match("^[#]?(%x+)$") then
- c_2 = colors.hex_to_rgb(color_2);
- elseif type(color_2) == "string" then
- c_1 = colors.name_to_rgb(color_2);
- end
-
- if not c_1 or not c_2 then
- return;
- end
-
- local _r = colors.clamp((c_1.r * per_1) + (c_2.r * per_2), 1, 255);
- local _g = colors.clamp((c_1.g * per_1) + (c_2.g * per_2), 1, 255);
- local _b = colors.clamp((c_1.b * per_1) + (c_2.b * per_2), 1, 255);
-
- return colors.rgb_to_hex({ r = _r, g = _g, b = _b });
-end
-
----@deprecated
-colors.get_brightness = function (color)
- if type(color) == "string" and color:match("^[#]?(%x+)$") then
- color = colors.hex_to_rgb(color);
- elseif type(color_1) == "string" then
- color = colors.name_to_rgb(color);
- elseif type(color) == "number" then
- color = colors.num_to_rgb(color);
- end
-
- for key, value in pairs(color) do
- if value > 1 then
- color[key] = value / 255;
- end
- end
-
- return (color.r * 0.2126) + (color.g * 0.7152) + (color.b * 0.0722);
-end
-
----@deprecated
-colors.brightest = function (col_list, debug)
- if not col_list then
- return;
- elseif not vim.islist(col_list) then
- local tmp = {};
-
- for _, item in pairs(col_list) do
- table.insert(tmp,item);
- end
-
- col_list = tmp;
- end
-
- local _c = {};
-
- for _, col in ipairs(col_list) do
- if type(col) == "string" and col:match("^[#]?(%x+)$") then
- table.insert(_c, colors.hex_to_rgb(col));
- elseif type(col) == "string" then
- table.insert(_c, colors.name_to_rgb(col));
- elseif type(col) == "number" then
- table.insert(_c, colors.num_to_rgb(col));
- elseif type(col) == "table" then
- table.insert(_c, col);
- end
- end
-
-
- local _b = 0;
- local brightest;
-
- for _, c in ipairs(_c) do
- local brightness = colors.get_brightness(c) or 0;
-
- if brightness >= _b then
- _b = brightness;
- brightest = c;
- end
- end
-
- -- if debug then
- -- vim.print(colors.rgb_to_hex(brightest) == nil);
- -- end
-
- return colors.rgb_to_hex(brightest);
-end
-
----@deprecated
-colors.get = function (col_list)
- if not col_list then
- return;
- elseif not vim.islist(col_list) then
- local tmp = {};
-
- for _, item in pairs(col_list) do
- table.insert(tmp,item);
- end
-
- col_list = tmp;
- end
-
- return col_list[1];
-end
-
----@deprecated
-colors.bg = function ()
- return colors.get({
- colors.get_hl_value(0, "Normal", "bg"),
- colors.get_hl_value(0, "EndOfBuffer", "bg"),
- colors.get_hl_value(0, "EndOfBuffer", "fg"),
- })
-end
-
-return colors;
diff --git a/lua/markview/entities.lua b/lua/markview/entities.lua
new file mode 100644
index 0000000..2548b77
--- /dev/null
+++ b/lua/markview/entities.lua
@@ -0,0 +1,1693 @@
+--- HTML entities lookup table(s) for `markview.nvim`.
+---
+--- Sources:
+--- โข [freeformatter.com](https://www.freeformatter.com/html-entities.html)
+--- โข [symbl.cc](https://symbl.cc/en/html-entities/)
+---
+--- `lynx --dump` was used to get the text values from the sites
+--- and a few *macros* were used to turn them into lua tables.
+---
+--- Note: Table keys were later sorted using `vim.inspect()` &
+--- I/O functions.
+local entities = {};
+
+--- Map for entity number & entity.
+---@type { [integer]: string }
+entities.codes = {
+ ---+${lua}
+ [32] = "",
+ [33] = "!",
+ [34] = '"',
+ [35] = "#",
+ [36] = "$",
+ [37] = "%",
+ [38] = "&",
+ [39] = "'",
+ [40] = "(",
+ [41] = ")",
+ [42] = "*",
+ [43] = "+",
+ [44] = ",",
+ [45] = "-",
+ [46] = ".",
+ [47] = "/",
+ [48] = "0",
+ [49] = "1",
+ [50] = "2",
+ [51] = "3",
+ [52] = "4",
+ [53] = "5",
+ [54] = "6",
+ [55] = "7",
+ [56] = "8",
+ [57] = "9",
+ [58] = ":",
+ [59] = ";",
+ [60] = "<",
+ [61] = "=",
+ [62] = ">",
+ [63] = "?",
+ [64] = "@",
+ [65] = "A",
+ [66] = "B",
+ [67] = "C",
+ [68] = "D",
+ [69] = "E",
+ [70] = "F",
+ [71] = "G",
+ [72] = "H",
+ [73] = "I",
+ [74] = "J",
+ [75] = "K",
+ [76] = "L",
+ [77] = "M",
+ [78] = "N",
+ [79] = "O",
+ [80] = "P",
+ [81] = "Q",
+ [82] = "R",
+ [83] = "S",
+ [84] = "T",
+ [85] = "U",
+ [86] = "V",
+ [87] = "W",
+ [88] = "X",
+ [89] = "Y",
+ [90] = "Z",
+ [91] = "[",
+ [92] = "\\",
+ [93] = "]",
+ [94] = "^",
+ [95] = "_",
+ [96] = "`",
+ [97] = "a",
+ [98] = "b",
+ [99] = "c",
+ [100] = "d",
+ [101] = "e",
+ [102] = "f",
+ [103] = "g",
+ [104] = "h",
+ [105] = "i",
+ [106] = "j",
+ [107] = "k",
+ [108] = "l",
+ [109] = "m",
+ [110] = "n",
+ [111] = "o",
+ [112] = "p",
+ [113] = "q",
+ [114] = "r",
+ [115] = "s",
+ [116] = "t",
+ [117] = "u",
+ [118] = "v",
+ [119] = "w",
+ [120] = "x",
+ [121] = "y",
+ [122] = "z",
+ [123] = "{",
+ [124] = "|",
+ [125] = "}",
+ [126] = "~",
+ [137] = "๎",
+ [160] = " ",
+ [161] = "ยก",
+ [162] = "ยข",
+ [163] = "ยฃ",
+ [164] = "ยค",
+ [165] = "ยฅ",
+ [166] = "ยฆ",
+ [167] = "ยง",
+ [168] = "ยจ",
+ [169] = "ยฉ",
+ [170] = "ยช",
+ [171] = "ยซ",
+ [172] = "ยฌ",
+ [173] = "-",
+ [174] = "ยฎ",
+ [175] = "ยฏ",
+ [176] = "ยฐ",
+ [177] = "ยฑ",
+ [178] = "ยฒ",
+ [179] = "ยณ",
+ [180] = "ยด",
+ [181] = "ยต",
+ [182] = "ยถ",
+ [183] = "ยท",
+ [184] = "ยธ",
+ [185] = "ยน",
+ [186] = "ยบ",
+ [187] = "ยป",
+ [188] = "ยผ",
+ [189] = "ยฝ",
+ [190] = "ยพ",
+ [191] = "ยฟ",
+ [192] = "ร",
+ [193] = "ร",
+ [194] = "ร",
+ [195] = "ร",
+ [196] = "ร",
+ [197] = "ร
",
+ [198] = "ร",
+ [199] = "ร",
+ [200] = "ร",
+ [201] = "ร",
+ [202] = "ร",
+ [203] = "ร",
+ [204] = "ร",
+ [206] = "ร",
+ [207] = "ร",
+ [208] = "ร",
+ [209] = "ร",
+ [210] = "ร",
+ [211] = "ร",
+ [212] = "ร",
+ [213] = "ร",
+ [214] = "ร",
+ [215] = "ร",
+ [216] = "ร",
+ [217] = "ร",
+ [218] = "ร",
+ [219] = "ร",
+ [220] = "ร",
+ [221] = "ร",
+ [222] = "ร",
+ [223] = "ร",
+ [224] = "ร ",
+ [225] = "รก",
+ [226] = "รข",
+ [227] = "รฃ",
+ [228] = "รค",
+ [229] = "รฅ",
+ [230] = "รฆ",
+ [231] = "รง",
+ [232] = "รจ",
+ [233] = "รฉ",
+ [234] = "รช",
+ [235] = "รซ",
+ [236] = "รฌ",
+ [237] = "รญ",
+ [238] = "รฎ",
+ [239] = "รฏ",
+ [240] = "รฐ",
+ [241] = "รฑ",
+ [242] = "รฒ",
+ [243] = "รณ",
+ [244] = "รด",
+ [245] = "รต",
+ [246] = "รถ",
+ [247] = "รท",
+ [248] = "รธ",
+ [249] = "รน",
+ [250] = "รบ",
+ [251] = "รป",
+ [252] = "รผ",
+ [253] = "รฝ",
+ [254] = "รพ",
+ [255] = "รฟ",
+ [256] = "ฤ",
+ [257] = "ฤ",
+ [258] = "ฤ",
+ [259] = "ฤ",
+ [260] = "ฤ",
+ [261] = "ฤ
",
+ [262] = "ฤ",
+ [263] = "ฤ",
+ [264] = "ฤ",
+ [265] = "ฤ",
+ [266] = "ฤ",
+ [267] = "ฤ",
+ [268] = "ฤ",
+ [269] = "ฤ",
+ [270] = "ฤ",
+ [271] = "ฤ",
+ [272] = "ฤ",
+ [273] = "ฤ",
+ [274] = "ฤ",
+ [275] = "ฤ",
+ [278] = "ฤ",
+ [279] = "ฤ",
+ [280] = "ฤ",
+ [281] = "ฤ",
+ [282] = "ฤ",
+ [283] = "ฤ",
+ [284] = "ฤ",
+ [285] = "ฤ",
+ [286] = "ฤ",
+ [287] = "ฤ",
+ [288] = "ฤ ",
+ [289] = "ฤก",
+ [290] = "ฤข",
+ [292] = "ฤค",
+ [293] = "ฤฅ",
+ [294] = "ฤฆ",
+ [295] = "ฤง",
+ [296] = "ฤจ",
+ [297] = "ฤฉ",
+ [298] = "ฤช",
+ [299] = "ฤซ",
+ [302] = "ฤฎ",
+ [303] = "ฤฏ",
+ [304] = "ฤฐ",
+ [305] = "ฤฑ",
+ [306] = "ฤฒ",
+ [307] = "ฤณ",
+ [308] = "ฤด",
+ [309] = "ฤต",
+ [310] = "ฤถ",
+ [311] = "ฤท",
+ [312] = "ฤธ",
+ [313] = "ฤน",
+ [314] = "ฤบ",
+ [315] = "ฤป",
+ [316] = "ฤผ",
+ [317] = "ฤฝ",
+ [318] = "ฤพ",
+ [319] = "ฤฟ",
+ [320] = "ล",
+ [321] = "ล",
+ [322] = "ล",
+ [323] = "ล",
+ [324] = "ล",
+ [325] = "ล
",
+ [326] = "ล",
+ [327] = "ล",
+ [328] = "ล",
+ [329] = "ล",
+ [330] = "ล",
+ [331] = "ล",
+ [332] = "ล",
+ [333] = "ล",
+ [336] = "ล",
+ [337] = "ล",
+ [338] = "ล",
+ [339] = "ล",
+ [340] = "ล",
+ [341] = "ล",
+ [342] = "ล",
+ [343] = "ล",
+ [344] = "ล",
+ [345] = "ล",
+ [346] = "ล",
+ [347] = "ล",
+ [348] = "ล",
+ [349] = "ล",
+ [350] = "ล",
+ [351] = "ล",
+ [352] = "ล ",
+ [353] = "ลก",
+ [354] = "ลข",
+ [355] = "ลฃ",
+ [356] = "ลค",
+ [357] = "ลฅ",
+ [358] = "ลฆ",
+ [359] = "ลง",
+ [360] = "ลจ",
+ [361] = "ลฉ",
+ [362] = "ลช",
+ [363] = "ลซ",
+ [364] = "ลฌ",
+ [365] = "ลญ",
+ [366] = "ลฎ",
+ [367] = "ลฏ",
+ [368] = "ลฐ",
+ [369] = "ลฑ",
+ [370] = "ลฒ",
+ [371] = "ลณ",
+ [372] = "ลด",
+ [373] = "ลต",
+ [374] = "ลถ",
+ [375] = "ลท",
+ [376] = "ลธ",
+ [377] = "ลน",
+ [378] = "ลบ",
+ [379] = "ลป",
+ [380] = "ลผ",
+ [381] = "ลฝ",
+ [382] = "ลพ",
+ [402] = "ฦ",
+ [410] = "ห",
+ [710] = "ห",
+ [732] = "ห",
+ [913] = "ฮ",
+ [914] = "ฮ",
+ [915] = "ฮ",
+ [916] = "ฮ",
+ [917] = "ฮ",
+ [918] = "ฮ",
+ [919] = "ฮ",
+ [920] = "ฮ",
+ [921] = "ฮ",
+ [922] = "ฮ",
+ [923] = "ฮ",
+ [924] = "ฮ",
+ [925] = "ฮ",
+ [926] = "ฮ",
+ [927] = "ฮ",
+ [928] = "ฮ ",
+ [929] = "ฮก",
+ [931] = "ฮฃ",
+ [932] = "ฮค",
+ [933] = "ฮฅ",
+ [934] = "ฮฆ",
+ [935] = "ฮง",
+ [936] = "ฮจ",
+ [937] = "ฮฉ",
+ [945] = "ฮฑ",
+ [946] = "ฮฒ",
+ [947] = "ฮณ",
+ [948] = "ฮด",
+ [949] = "ฮต",
+ [950] = "ฮถ",
+ [951] = "ฮท",
+ [952] = "ฮธ",
+ [953] = "ฮน",
+ [954] = "ฮบ",
+ [955] = "ฮป",
+ [956] = "ฮผ",
+ [957] = "ฮฝ",
+ [958] = "ฮพ",
+ [959] = "ฮฟ",
+ [960] = "ฯ",
+ [961] = "ฯ",
+ [962] = "ฯ",
+ [963] = "ฯ",
+ [964] = "ฯ",
+ [965] = "ฯ
",
+ [966] = "ฯ",
+ [967] = "ฯ",
+ [968] = "ฯ",
+ [969] = "ฯ",
+ [977] = "ฯ",
+ [978] = "ฯ",
+ [982] = "ฯ",
+ [8208] = "โ",
+ [8211] = "โ",
+ [8212] = "โ",
+ [8213] = "โ",
+ [8214] = "โ",
+ [8216] = "โ",
+ [8217] = "โ",
+ [8218] = "โ",
+ [8220] = "โ",
+ [8221] = "โ",
+ [8222] = "โ",
+ [8224] = "โ ",
+ [8225] = "โก",
+ [8226] = "โข",
+ [8229] = "โฅ",
+ [8230] = "โฆ",
+ [8240] = "โฐ",
+ [8241] = "โฑ",
+ [8242] = "โฒ",
+ [8243] = "โณ",
+ [8244] = "โด",
+ [8245] = "โต",
+ [8249] = "โน",
+ [8250] = "โบ",
+ [8254] = "โพ",
+ [8257] = "โ",
+ [8259] = "โ",
+ [8260] = "โ",
+ [8271] = "โ",
+ [8279] = "โ",
+ [8364] = "โฌ",
+ [8450] = "โ",
+ [8453] = "โ
",
+ [8458] = "โ",
+ [8459] = "โ",
+ [8460] = "โ",
+ [8461] = "โ",
+ [8462] = "โ",
+ [8463] = "โ",
+ [8464] = "โ",
+ [8465] = "โ",
+ [8466] = "โ",
+ [8467] = "โ",
+ [8469] = "โ",
+ [8470] = "โ",
+ [8471] = "โ",
+ [8472] = "โ",
+ [8473] = "โ",
+ [8474] = "โ",
+ [8475] = "โ",
+ [8476] = "โ",
+ [8477] = "โ",
+ [8478] = "โ",
+ [8482] = "โข",
+ [8484] = "โค",
+ [8487] = "โง",
+ [8488] = "โจ",
+ [8489] = "โฉ",
+ [8492] = "โฌ",
+ [8493] = "โญ",
+ [8495] = "โฏ",
+ [8496] = "โฐ",
+ [8497] = "โฑ",
+ [8499] = "โณ",
+ [8500] = "โด",
+ [8501] = "โต",
+ [8502] = "โถ",
+ [8503] = "โท",
+ [8504] = "โธ",
+ [8517] = "โ
",
+ [8518] = "โ
",
+ [8519] = "โ
",
+ [8520] = "โ
",
+ [8531] = "โ
",
+ [8532] = "โ
",
+ [8533] = "โ
",
+ [8534] = "โ
",
+ [8535] = "โ
",
+ [8536] = "โ
",
+ [8537] = "โ
",
+ [8538] = "โ
",
+ [8539] = "โ
",
+ [8540] = "โ
",
+ [8541] = "โ
",
+ [8542] = "โ
",
+ [8592] = "โ",
+ [8593] = "โ",
+ [8594] = "โ",
+ [8595] = "โ",
+ [8596] = "โ",
+ [8629] = "โต",
+ [8634] = "โบ",
+ [8635] = "โป",
+ [8636] = "โผ",
+ [8637] = "โฝ",
+ [8638] = "โพ",
+ [8639] = "โฟ",
+ [8640] = "โ",
+ [8641] = "โ",
+ [8642] = "โ",
+ [8643] = "โ",
+ [8644] = "โ",
+ [8645] = "โ
",
+ [8646] = "โ",
+ [8647] = "โ",
+ [8648] = "โ",
+ [8649] = "โ",
+ [8650] = "โ",
+ [8651] = "โ",
+ [8652] = "โ",
+ [8653] = "โ",
+ [8654] = "โ",
+ [8655] = "โ",
+ [8656] = "โ",
+ [8657] = "โ",
+ [8658] = "โ",
+ [8659] = "โ",
+ [8660] = "โ",
+ [8661] = "โ",
+ [8662] = "โ",
+ [8663] = "โ",
+ [8664] = "โ",
+ [8665] = "โ",
+ [8666] = "โ",
+ [8667] = "โ",
+ [8668] = "โ",
+ [8669] = "โ",
+ [8676] = "โค",
+ [8677] = "โฅ",
+ [8693] = "โต",
+ [8701] = "โฝ",
+ [8702] = "โพ",
+ [8703] = "โฟ",
+ [8704] = "โ",
+ [8705] = "โ",
+ [8706] = "โ",
+ [8707] = "โ",
+ [8708] = "โ",
+ [8709] = "โ
",
+ [8711] = "โ",
+ [8712] = "โ",
+ [8713] = "โ",
+ [8715] = "โ",
+ [8716] = "โ",
+ [8719] = "โ",
+ [8720] = "โ",
+ [8721] = "โ",
+ [8722] = "โ",
+ [8723] = "โ",
+ [8724] = "โ",
+ [8726] = "โ",
+ [8727] = "โ",
+ [8728] = "โ",
+ [8730] = "โ",
+ [8733] = "โ",
+ [8734] = "โ",
+ [8735] = "โ",
+ [8736] = "โ ",
+ [8737] = "โก",
+ [8738] = "โข",
+ [8739] = "โฃ",
+ [8740] = "โค",
+ [8741] = "โฅ",
+ [8742] = "โฆ",
+ [8743] = "โง",
+ [8744] = "โจ",
+ [8745] = "โฉ",
+ [8746] = "โช",
+ [8747] = "โซ",
+ [8748] = "โฌ",
+ [8749] = "โญ",
+ [8750] = "โฎ",
+ [8751] = "โฏ",
+ [8752] = "โฐ",
+ [8753] = "โฑ",
+ [8754] = "โฒ",
+ [8755] = "โณ",
+ [8756] = "โด",
+ [8757] = "โต",
+ [8758] = "โถ",
+ [8759] = "โท",
+ [8760] = "โธ",
+ [8762] = "โบ",
+ [8763] = "โป",
+ [8764] = "โผ",
+ [8765] = "โฝ",
+ [8766] = "โพ",
+ [8767] = "โฟ",
+ [8768] = "โ",
+ [8769] = "โ",
+ [8770] = "โ",
+ [8771] = "โ",
+ [8772] = "โ",
+ [8773] = "โ
",
+ [8774] = "โ",
+ [8775] = "โ",
+ [8776] = "โ",
+ [8777] = "โ",
+ [8778] = "โ",
+ [8779] = "โ",
+ [8780] = "โ",
+ [8781] = "โ",
+ [8782] = "โ",
+ [8783] = "โ",
+ [8784] = "โ",
+ [8785] = "โ",
+ [8786] = "โ",
+ [8787] = "โ",
+ [8788] = "โ",
+ [8789] = "โ",
+ [8790] = "โ",
+ [8791] = "โ",
+ [8793] = "โ",
+ [8794] = "โ",
+ [8796] = "โ",
+ [8799] = "โ",
+ [8800] = "โ ",
+ [8801] = "โก",
+ [8802] = "โข",
+ [8804] = "โค",
+ [8805] = "โฅ",
+ [8806] = "โฆ",
+ [8807] = "โง",
+ [8808] = "โจ",
+ [8809] = "โฉ",
+ [8810] = "โช",
+ [8811] = "โซ",
+ [8812] = "โฌ",
+ [8813] = "โญ",
+ [8814] = "โฎ",
+ [8815] = "โฏ",
+ [8816] = "โฐ",
+ [8817] = "โฑ",
+ [8818] = "โฒ",
+ [8819] = "โณ",
+ [8820] = "โด",
+ [8821] = "โต",
+ [8822] = "โถ",
+ [8823] = "โท",
+ [8824] = "โธ",
+ [8825] = "โน",
+ [8826] = "โบ",
+ [8827] = "โป",
+ [8828] = "โผ",
+ [8829] = "โฝ",
+ [8830] = "โพ",
+ [8831] = "โฟ",
+ [8832] = "โ",
+ [8833] = "โ",
+ [8834] = "โ",
+ [8835] = "โ",
+ [8836] = "โ",
+ [8837] = "โ
",
+ [8838] = "โ",
+ [8839] = "โ",
+ [8840] = "โ",
+ [8841] = "โ",
+ [8842] = "โ",
+ [8843] = "โ",
+ [8845] = "โ",
+ [8846] = "โ",
+ [8847] = "โ",
+ [8848] = "โ",
+ [8849] = "โ",
+ [8850] = "โ",
+ [8851] = "โ",
+ [8852] = "โ",
+ [8853] = "โ",
+ [8854] = "โ",
+ [8855] = "โ",
+ [8856] = "โ",
+ [8857] = "โ",
+ [8858] = "โ",
+ [8859] = "โ",
+ [8861] = "โ",
+ [8862] = "โ",
+ [8863] = "โ",
+ [8864] = "โ ",
+ [8865] = "โก",
+ [8866] = "โข",
+ [8867] = "โฃ",
+ [8868] = "โค",
+ [8869] = "โฅ",
+ [8871] = "โง",
+ [8872] = "โจ",
+ [8873] = "โฉ",
+ [8874] = "โช",
+ [8875] = "โซ",
+ [8876] = "โฌ",
+ [8877] = "โญ",
+ [8878] = "โฎ",
+ [8879] = "โฏ",
+ [8880] = "โฐ",
+ [8882] = "โฒ",
+ [8883] = "โณ",
+ [8884] = "โด",
+ [8885] = "โต",
+ [8886] = "โถ",
+ [8887] = "โท",
+ [8888] = "โธ",
+ [8889] = "โน",
+ [8890] = "โบ",
+ [8891] = "โป",
+ [8893] = "โฝ",
+ [8894] = "โพ",
+ [8895] = "โฟ",
+ [8896] = "โ",
+ [8897] = "โ",
+ [8898] = "โ",
+ [8899] = "โ",
+ [8900] = "โ",
+ [8901] = "โ
",
+ [8902] = "โ",
+ [8903] = "โ",
+ [8904] = "โ",
+ [8905] = "โ",
+ [8906] = "โ",
+ [8907] = "โ",
+ [8908] = "โ",
+ [8909] = "โ",
+ [8910] = "โ",
+ [8911] = "โ",
+ [8912] = "โ",
+ [8913] = "โ",
+ [8914] = "โ",
+ [8915] = "โ",
+ [8916] = "โ",
+ [8917] = "โ",
+ [8918] = "โ",
+ [8919] = "โ",
+ [8920] = "โ",
+ [8921] = "โ",
+ [8922] = "โ",
+ [8923] = "โ",
+ [8926] = "โ",
+ [8927] = "โ",
+ [8928] = "โ ",
+ [8929] = "โก",
+ [8930] = "โข",
+ [8931] = "โฃ",
+ [8934] = "โฆ",
+ [8935] = "โง",
+ [8936] = "โจ",
+ [8937] = "โฉ",
+ [8938] = "โช",
+ [8939] = "โซ",
+ [8940] = "โฌ",
+ [8941] = "โญ",
+ [8942] = "โฎ",
+ [8943] = "โฏ",
+ [8944] = "โฐ",
+ [8945] = "โฑ",
+ [8946] = "โฒ",
+ [8947] = "โณ",
+ [8948] = "โด",
+ [8949] = "โต",
+ [8950] = "โถ",
+ [8951] = "โท",
+ [8953] = "โน",
+ [8954] = "โบ",
+ [8955] = "โป",
+ [8956] = "โผ",
+ [8957] = "โฝ",
+ [8958] = "โพ",
+ [8968] = "โ",
+ [8969] = "โ",
+ [8970] = "โ",
+ [8971] = "โ",
+ [9001] = "โฉ",
+ [9002] = "โช",
+ [9674] = "โ",
+ [9733] = "โ
",
+ [9734] = "โ",
+ [9742] = "๓ฐ ",
+ [9792] = "โ",
+ [9794] = "โ",
+ [9824] = "โ ",
+ [9827] = "โฃ",
+ [9829] = "โฅ",
+ [9830] = "โฆ",
+ [9834] = "โช",
+ [9837] = "โญ",
+ [9838] = "โฎ",
+ [9839] = "โฏ",
+ [10003] = "โ",
+ [10007] = "โ",
+ [10016] = "โ ",
+ [10038] = "โถ",
+ [10072] = "โ",
+ [10098] = "โฒ",
+ [10099] = "โณ",
+ [10229] = "โต",
+ [10230] = "โถ",
+ [10231] = "โท",
+ [10232] = "โธ",
+ [10233] = "โน",
+ [10234] = "โบ",
+ [10236] = "โผ",
+ [10239] = "โฟ",
+ [10498] = "โค",
+ [10499] = "โค",
+ [10500] = "โค",
+ [10501] = "โค
",
+ [10508] = "โค",
+ [10509] = "โค",
+ [10510] = "โค",
+ [10511] = "โค",
+ [10512] = "โค",
+ [10513] = "โค",
+ [10514] = "โค",
+ [10515] = "โค",
+ [10518] = "โค",
+ [10521] = "โค",
+ [10522] = "โค",
+ [10523] = "โค",
+ [10524] = "โค",
+ [10525] = "โค",
+ [10526] = "โค",
+ [10527] = "โค",
+ [10528] = "โค ",
+ [10531] = "โคฃ",
+ [10532] = "โคค",
+ [10533] = "โคฅ",
+ [10534] = "โคฆ",
+ [10535] = "โคง",
+ [10536] = "โคจ",
+ [10537] = "โคฉ",
+ [10538] = "โคช",
+ [10550] = "โคถ",
+ [10551] = "โคท",
+ [10552] = "โคธ",
+ [10553] = "โคน",
+ [10556] = "โคผ",
+ [10557] = "โคฝ",
+ [10565] = "โฅ
",
+ [10568] = "โฅ",
+ [10569] = "โฅ",
+ [10570] = "โฅ",
+ [10571] = "โฅ",
+ [10575] = "โฅ",
+ [10576] = "โฅ",
+ [10577] = "โฅ",
+ [10578] = "โฅ",
+ [10579] = "โฅ",
+ [10580] = "โฅ",
+ [10581] = "โฅ",
+ [10582] = "โฅ",
+ [10583] = "โฅ",
+ [10584] = "โฅ",
+ [10585] = "โฅ",
+ [10586] = "โฅ",
+ [10587] = "โฅ",
+ [10588] = "โฅ",
+ [10589] = "โฅ",
+ [10590] = "โฅ",
+ [10591] = "โฅ",
+ [10592] = "โฅ ",
+ [10593] = "โฅก",
+ [10594] = "โฅข",
+ [10595] = "โฅฃ",
+ [10596] = "โฅค",
+ [10597] = "โฅฅ",
+ [10598] = "โฅฆ",
+ [10599] = "โฅง",
+ [10600] = "โฅจ",
+ [10601] = "โฅฉ",
+ [10602] = "โฅช",
+ [10603] = "โฅซ",
+ [10604] = "โฅฌ",
+ [10605] = "โฅญ",
+ [10606] = "โฅฎ",
+ [10607] = "โฅฏ",
+ [10608] = "โฅฐ",
+ [10609] = "โฅฑ",
+ [10610] = "โฅฒ",
+ [10611] = "โฅณ",
+ [10612] = "โฅด",
+ [10613] = "โฅต",
+ [10614] = "โฅถ",
+ [10616] = "โฅธ",
+ [10617] = "โฅน",
+ [10619] = "โฅป",
+ [10620] = "โฅผ",
+ [10621] = "โฅฝ",
+ [10622] = "โฅพ",
+ [10623] = "โฅฟ"
+ ---_
+};
+
+--- Map for entity name & entity value.
+---@type { [string]: string }
+entities.names = {
+ ---+${lua}
+ AElig = "ร",
+ Aacute = "ร",
+ Abreve = "ฤ",
+ Acirc = "ร",
+ Agrave = "ร",
+ Alpha = "ฮ",
+ Amacr = "ฤ",
+ Aogon = "ฤ",
+ Aring = "ร
",
+ Atilde = "ร",
+ Auml = "ร",
+ Beta = "ฮ",
+ Cacute = "ฤ",
+ Cap = "โ",
+ Ccaron = "ฤ",
+ Ccedil = "ร",
+ Ccirc = "ฤ",
+ Cconint = "โฐ",
+ Cdot = "ฤ",
+ Cfr = "โญ",
+ Chi = "ฮง",
+ Colon = "โท",
+ Conint = "โฏ",
+ Copf = "โ",
+ Cup = "โ",
+ DD = "โ
",
+ DDotrahd = "โค",
+ Dagger = "โก",
+ Dcaron = "ฤ",
+ Delta = "ฮ",
+ DownArrowBar = "โค",
+ DownLeftRightVector = "โฅ",
+ DownLeftTeeVector = "โฅ",
+ DownLeftVectorBar = "โฅ",
+ DownRightTeeVector = "โฅ",
+ DownRightVectorBar = "โฅ",
+ Dstrok = "ฤ",
+ ENG = "ล",
+ ETH = "ร",
+ Eacute = "ร",
+ Ecaron = "ฤ",
+ Ecirc = "ร",
+ Edot = "ฤ",
+ Egrave = "ร",
+ Emacr = "ฤ",
+ Eogon = "ฤ",
+ Epsilon = "ฮ",
+ Escr = "โฐ",
+ Eta = "ฮ",
+ Euml = "ร",
+ Fscr = "โฑ",
+ Gamma = "ฮ",
+ Gbreve = "ฤ",
+ Gcedil = "ฤข",
+ Gcirc = "ฤ",
+ Gdot = "ฤ ",
+ Gg = "โ",
+ Gt = "โซ",
+ Hat = "^",
+ Hcirc = "ฤค",
+ Hfr = "โ",
+ Hopf = "โ",
+ Hstrok = "ฤฆ",
+ IJlig = "ฤฒ",
+ Idot = "ฤฐ",
+ Imacr = "ฤช",
+ Int = "โฌ",
+ Iogon = "ฤฎ",
+ Iota = "ฮ",
+ Iscr = "โ",
+ Itilde = "ฤจ",
+ Jcirc = "ฤด",
+ Kappa = "ฮ",
+ Kcedil = "ฤถ",
+ Lacute = "ฤน",
+ Lambda = "ฮ",
+ Lcaron = "ฤฝ",
+ Lcedil = "ฤป",
+ Lcirc = "ร",
+ LeftDownTeeVector = "โฅก",
+ LeftDownVectorBar = "โฅ",
+ LeftTeeVector = "โฅ",
+ LeftUpDownVector = "โฅ",
+ LeftUpTeeVector = "โฅ ",
+ LeftUpVectorBar = "โฅ",
+ LeftVectorBar = "โฅ",
+ Lgrave = "ร",
+ Ll = "โ",
+ Lmidot = "ฤฟ",
+ Lscr = "โ",
+ Lstrok = "ล",
+ Lt = "โช",
+ Luml = "ร",
+ Map = "โค
",
+ Mscr = "โณ",
+ Mu = "ฮ",
+ Nacute = "ล",
+ Ncaron = "ล",
+ Ncedil = "ล
",
+ Nopf = "โ",
+ NotCupCap = "โญ",
+ Ntilde = "ร",
+ Nu = "ฮ",
+ OElig = "ล",
+ Oacute = "ร",
+ Ocirc = "ร",
+ Odblac = "ล",
+ Ograve = "ร",
+ Omacr = "ล",
+ Omega = "ฮฉ",
+ Omicron = "ฮ",
+ Oslash = "ร",
+ Otilde = "ร",
+ Ouml = "ร",
+ Phi = "ฮฆ",
+ Pi = "ฮ ",
+ Popf = "โ",
+ Prime = "โณ",
+ Psi = "ฮจ",
+ Qopf = "โ",
+ RBarr = "โค",
+ Racute = "ล",
+ Rarrtl = "โค",
+ Rcaron = "ล",
+ Rcedil = "ล",
+ Rho = "ฮก",
+ RightDownTeeVector = "โฅ",
+ RightDownVectorBar = "โฅ",
+ RightTeeVector = "โฅ",
+ RightUpDownVector = "โฅ",
+ RightUpTeeVector = "โฅ",
+ RightUpVectorBar = "โฅ",
+ RightVectorBar = "โฅ",
+ Ropf = "โ",
+ RoundImplies = "โฅฐ",
+ Rscr = "โ",
+ Sacute = "ล",
+ Scaron = "ล ",
+ Scedil = "ล",
+ Scirc = "ล",
+ Sigma = "ฮฃ",
+ Star = "โ",
+ Sub = "โ",
+ Sup = "โ",
+ THORN = "ร",
+ Tau = "ฮค",
+ Tcaron = "ลค",
+ Tcedil = "ลข",
+ Theta = "ฮ",
+ Tstrok = "ลฆ",
+ Uacute = "ร",
+ Uarrocir = "โฅ",
+ Ubreve = "ลฌ",
+ Ucirc = "ร",
+ Udblac = "ลฐ",
+ Ugrave = "ร",
+ Umacr = "ลช",
+ Uogon = "ลฒ",
+ UpArrowBar = "โค",
+ Upsilon = "ฮฅ",
+ Uring = "ลฎ",
+ Utilde = "ลจ",
+ Uuml = "ร",
+ VDash = "โซ",
+ Vdash = "โฉ",
+ Vert = "โ",
+ VerticalSeparator = "โ",
+ Vvdash = "โช",
+ Wcirc = "ลด",
+ Xi = "ฮ",
+ Yacute = "ร",
+ Ycirc = "ลถ",
+ Yuml = "ลธ",
+ Zacute = "ลน",
+ Zcaron = "ลฝ",
+ Zdot = "ลป",
+ Zeta = "ฮ",
+ Zfr = "โจ",
+ Zopf = "โค",
+ aacute = "รก",
+ abreve = "ฤ",
+ ac = "โพ",
+ acd = "โฟ",
+ acirc = "รข",
+ acute = "ยด",
+ aelig = "รฆ",
+ agrave = "ร ",
+ alefsym = "โต",
+ alpha = "ฮฑ",
+ amacr = "ฤ",
+ amp = "&",
+ ["and"] = "โง",
+ ang = "โ ",
+ angmsd = "โก",
+ angrt = "โ",
+ angrtvb = "โพ",
+ anhsph = "โข",
+ aogon = "ฤ
",
+ apid = "โ",
+ apos = "'",
+ approxeq = "โ",
+ aring = "รฅ",
+ ast = "*",
+ asymp = "โ",
+ asympeq = "โ",
+ atilde = "รฃ",
+ auml = "รค",
+ awconint = "โณ",
+ barvee = "โฝ",
+ bcong = "โ",
+ bdquo = "โ",
+ because = "โต",
+ bernou = "โฌ",
+ beta = "ฮฒ",
+ beth = "โถ",
+ between = "โฌ",
+ bowtie = "โ",
+ bprime = "โต",
+ brvbar = "ยฆ",
+ bsemi = "โ",
+ bsim = "โฝ",
+ bsime = "โ",
+ bsol = "\\",
+ bull = "โข",
+ bump = "โ",
+ bumpe = "โ",
+ cacute = "ฤ",
+ cap = "โฉ",
+ caret = "โ",
+ ccaron = "ฤ",
+ ccedil = "รง",
+ ccirc = "ฤ",
+ cdot = "ฤ",
+ cedil = "ยธ",
+ cent = "ยข",
+ check = "โ",
+ chi = "ฯ",
+ circ = "ห",
+ cire = "โ",
+ clubs = "โฃ",
+ colon = ":",
+ colone = "โ",
+ comma = ",",
+ commat = "@",
+ comp = "โ",
+ compfn = "โ",
+ cong = "โ
",
+ conint = "โฎ",
+ coprod = "โ",
+ copy = "ยฉ",
+ copysr = "โ",
+ crarr = "โต",
+ cross = "โ",
+ ctdot = "โฏ",
+ cudarrl = "โคธ",
+ cuepr = "โ",
+ cuesc = "โ",
+ cularrp = "โคฝ",
+ cup = "โช",
+ cupdot = "โ",
+ curarrm = "โคผ",
+ curren = "ยค",
+ cuvee = "โ",
+ cuwed = "โ",
+ cwconint = "โฒ",
+ cwint = "โฑ",
+ dArr = "โ",
+ dHar = "โฅฅ",
+ dagger = "โ ",
+ daleth = "โธ",
+ darr = "โ",
+ dashv = "โฃ",
+ dcaron = "ฤ",
+ dd = "โ
",
+ ddarr = "โ",
+ deg = "ยฐ",
+ delta = "ฮด",
+ dfisht = "โฅฟ",
+ dharl = "โ",
+ dharr = "โ",
+ diamond = "โ",
+ diams = "โฆ",
+ disin = "โฒ",
+ divide = "รท",
+ divonx = "โ",
+ dollar = "$",
+ dstrok = "ฤ",
+ dtdot = "โฑ",
+ duarr = "โต",
+ duhar = "โฅฏ",
+ dzigrarr = "โฟ",
+ eDot = "โ",
+ eacute = "รฉ",
+ ecaron = "ฤ",
+ ecir = "โ",
+ ecirc = "รช",
+ ecolon = "โ",
+ edot = "ฤ",
+ ee = "โ
",
+ efDot = "โ",
+ egrave = "รจ",
+ ell = "โ",
+ emacr = "ฤ",
+ empty = "โ
",
+ eng = "ล",
+ eogon = "ฤ",
+ epar = "โ",
+ epsilon = "ฮต",
+ equals = "=",
+ equest = "โ",
+ equiv = "โก",
+ erDot = "โ",
+ erarr = "โฅฑ",
+ escr = "โฏ",
+ esdot = "โ",
+ esim = "โ",
+ eta = "ฮท",
+ eth = "รฐ",
+ euml = "รซ",
+ euro = "โฌ",
+ excl = "!",
+ exist = "โ",
+ female = "โ",
+ flat = "โญ",
+ fnof = "ฦ",
+ forall = "โ",
+ fork = "โ",
+ frac12 = "ยฝ",
+ frac13 = "โ
",
+ frac14 = "ยผ",
+ frac15 = "โ
",
+ frac16 = "โ
",
+ frac18 = "โ
",
+ frac23 = "โ
",
+ frac25 = "โ
",
+ frac34 = "ยพ",
+ frac35 = "โ
",
+ frac38 = "โ
",
+ frac45 = "โ
",
+ frac56 = "โ
",
+ frac58 = "โ
",
+ frac78 = "โ
",
+ frasl = "โ",
+ gE = "โง",
+ gamma = "ฮณ",
+ gbreve = "ฤ",
+ gcirc = "ฤ",
+ gdot = "ฤก",
+ ge = "โฅ",
+ gel = "โ",
+ gimel = "โท",
+ gl = "โท",
+ gnE = "โฉ",
+ gnsim = "โง",
+ grave = "`",
+ gscr = "โ",
+ gsim = "โณ",
+ gt = ">",
+ gtdot = "โ",
+ gtrarr = "โฅธ",
+ hArr = "โ",
+ hamilt = "โ",
+ harr = "โ",
+ harrcir = "โฅ",
+ hcirc = "ฤฅ",
+ hearts = "โฅ",
+ hellip = "โฆ",
+ hercon = "โน",
+ hoarr = "โฟ",
+ homtht = "โป",
+ horbar = "โ",
+ hstrok = "ฤง",
+ hybull = "โ",
+ hyphen = "โ",
+ iacute = "รญ",
+ icirc = "รฎ",
+ iexcl = "ยก",
+ igrave = "รฌ",
+ ii = "โ
",
+ iiint = "โญ",
+ iiota = "โฉ",
+ ijlig = "ฤณ",
+ imacr = "ฤซ",
+ image = "โ",
+ imath = "ฤฑ",
+ imof = "โท",
+ incare = "โ
",
+ infin = "โ",
+ int = "โซ",
+ intcal = "โบ",
+ iogon = "ฤฏ",
+ iota = "ฮน",
+ iquest = "ยฟ",
+ isin = "โ",
+ isinE = "โน",
+ isindot = "โต",
+ isins = "โด",
+ isinsv = "โณ",
+ itilde = "ฤฉ",
+ iuml = "รฏ",
+ jcirc = "ฤต",
+ kappa = "ฮบ",
+ kcedil = "ฤท",
+ kgreen = "ฤธ",
+ lAarr = "โ",
+ lArr = "โ",
+ lAtail = "โค",
+ lBarr = "โค",
+ lE = "โฆ",
+ lHar = "โฅข",
+ lacute = "ฤบ",
+ lambda = "ฮป",
+ lang = "โฉ",
+ laquo = "ยซ",
+ larr = "โ",
+ larrb = "โค",
+ larrbfs = "โค",
+ larrfs = "โค",
+ larrpl = "โคน",
+ larrsim = "โฅณ",
+ latail = "โค",
+ lbarr = "โค",
+ lbbrk = "โฒ",
+ lbrace = "{",
+ lbrack = "[",
+ lcaron = "ฤพ",
+ lcedil = "ฤผ",
+ lceil = "โ",
+ ldca = "โคถ",
+ ldquo = "โ",
+ ldrdhar = "โฅง",
+ ldrushar = "โฅ",
+ le = "โค",
+ leg = "โ",
+ lfisht = "โฅผ",
+ lfloor = "โ",
+ lg = "โถ",
+ lhard = "โฝ",
+ lharu = "โผ",
+ lharul = "โฅช",
+ llarr = "โ",
+ llhard = "โฅซ",
+ lmidot = "ล",
+ lnE = "โจ",
+ lnsim = "โฆ",
+ loarr = "โฝ",
+ lowast = "โ",
+ lowbar = "_",
+ loz = "โ",
+ lpar = "(",
+ lrarr = "โ",
+ lrhar = "โ",
+ lrhard = "โฅญ",
+ lrtri = "โฟ",
+ lsaquo = "โน",
+ lsim = "โฒ",
+ lsquo = "โ",
+ lstrok = "ล",
+ lt = "<",
+ ltdot = "โ",
+ lthree = "โ",
+ ltimes = "โ",
+ ltlarr = "โฅถ",
+ ltrie = "โด",
+ lurdshar = "โฅ",
+ luruhar = "โฅฆ",
+ mDDot = "โบ",
+ macr = "ยฏ",
+ male = "โ",
+ malt = "โ ",
+ mdash = "โ",
+ mho = "โง",
+ micro = "ยต",
+ mid = "โฃ",
+ middot = "ยท",
+ minus = "โ",
+ minusb = "โ",
+ minusd = "โธ",
+ mnplus = "โ",
+ models = "โง",
+ mu = "ฮผ",
+ mumap = "โธ",
+ nVDash = "โฏ",
+ nVdash = "โฎ",
+ nabla = "โ",
+ nacute = "ล",
+ nap = "โ",
+ napos = "ล",
+ natural = "โฎ",
+ nbsp = " ",
+ ncaron = "ล",
+ ncedil = "ล",
+ ncong = "โ",
+ ndash = "โ",
+ ne = "โ ",
+ neArr = "โ",
+ nearhk = "โคค",
+ nequiv = "โข",
+ nesear = "โคจ",
+ nexist = "โ",
+ nge = "โฑ",
+ ngsim = "โต",
+ ngt = "โฏ",
+ nhArr = "โ",
+ ni = "โ",
+ nis = "โผ",
+ nisd = "โบ",
+ nlArr = "โ",
+ nldr = "โฅ",
+ nle = "โฐ",
+ nlsim = "โด",
+ nlt = "โฎ",
+ nltri = "โช",
+ nltrie = "โฌ",
+ nmid = "โค",
+ ["not"] = "ยฌ",
+ notin = "โ",
+ notinvb = "โท",
+ notinvc = "โถ",
+ notni = "โ",
+ notnivb = "โพ",
+ notnivc = "โฝ",
+ npar = "โฆ",
+ npr = "โ",
+ nprcue = "โ ",
+ nrArr = "โ",
+ nrtri = "โซ",
+ nrtrie = "โญ",
+ nsc = "โ",
+ nsccue = "โก",
+ nsim = "โ",
+ nsime = "โ",
+ nsqsube = "โข",
+ nsqsupe = "โฃ",
+ nsub = "โ",
+ nsube = "โ",
+ nsup = "โ
",
+ nsupe = "โ",
+ ntgl = "โน",
+ ntilde = "รฑ",
+ ntlg = "โธ",
+ nu = "ฮฝ",
+ num = "#",
+ numero = "โ",
+ nvDash = "โญ",
+ nvHarr = "โค",
+ nvdash = "โฌ",
+ nvlArr = "โค",
+ nvrArr = "โค",
+ nwArr = "โ",
+ nwarhk = "โคฃ",
+ nwnear = "โคง",
+ oacute = "รณ",
+ oast = "โ",
+ ocir = "โ",
+ ocirc = "รด",
+ odash = "โ",
+ odblac = "ล",
+ odot = "โ",
+ oelig = "ล",
+ ograve = "รฒ",
+ olarr = "โบ",
+ oline = "โพ",
+ omacr = "ล",
+ omega = "ฯ",
+ omicron = "ฮฟ",
+ ominus = "โ",
+ oplus = "โ",
+ ["or"] = "โจ",
+ orarr = "โป",
+ ordf = "ยช",
+ ordm = "ยบ",
+ origof = "โถ",
+ oscr = "โด",
+ oslash = "รธ",
+ osol = "โ",
+ otilde = "รต",
+ otimes = "โ",
+ ouml = "รถ",
+ para = "ยถ",
+ parallel = "โฅ",
+ part = "โ",
+ percnt = "%",
+ period = ".",
+ permil = "โฐ",
+ perp = "โฅ",
+ pertenk = "โฑ",
+ phi = "ฯ",
+ phone = "๓ฐ ",
+ pi = "ฯ",
+ piv = "ฯ",
+ planck = "โ",
+ planckh = "โ",
+ plus = "+",
+ plusb = "โ",
+ plusdo = "โ",
+ plusmn = "ยฑ",
+ pound = "ยฃ",
+ pr = "โบ",
+ prcue = "โผ",
+ prime = "โฒ",
+ prnsim = "โจ",
+ prod = "โ",
+ prop = "โ",
+ prsim = "โพ",
+ prurel = "โฐ",
+ psi = "ฯ",
+ qprime = "โ",
+ quest = "?",
+ quot = '"',
+ rAarr = "โ",
+ rArr = "โ",
+ rAtail = "โค",
+ rBarr = "โค",
+ rHar = "โฅค",
+ racute = "ล",
+ radic = "โ",
+ rang = "โช",
+ raquo = "ยป",
+ rarr = "โ",
+ rarrap = "โฅต",
+ rarrb = "โฅ",
+ rarrbfs = "โค ",
+ rarrfs = "โค",
+ rarrpl = "โฅ
",
+ rarrsim = "โฅด",
+ ratail = "โค",
+ ratio = "โถ",
+ rbarr = "โค",
+ rbbrk = "โณ",
+ rbrace = "}",
+ rbrack = "]",
+ rcaron = "ล",
+ rcedil = "ล",
+ rceil = "โ",
+ rdca = "โคท",
+ rdldhar = "โฅฉ",
+ rdquo = "โ",
+ real = "โ",
+ reg = "ยฎ",
+ rfisht = "โฅฝ",
+ rfloor = "โ",
+ rhard = "โ",
+ rharu = "โ",
+ rharul = "โฅฌ",
+ rho = "ฯ",
+ rlarr = "โ",
+ rlhar = "โ",
+ roarr = "โพ",
+ rpar = ")",
+ rrarr = "โ",
+ rsaquo = "โบ",
+ rsquo = "โ",
+ rthree = "โ",
+ rtimes = "โ",
+ rtrie = "โต",
+ ruluhar = "โฅจ",
+ rx = "โ",
+ sacute = "ล",
+ sbquo = "โ",
+ sc = "โป",
+ scaron = "ลก",
+ sccue = "โฝ",
+ scedil = "ล",
+ scirc = "ล",
+ scnsim = "โฉ",
+ scsim = "โฟ",
+ sdot = "โ
",
+ sdotb = "โก",
+ seArr = "โ",
+ searhk = "โคฅ",
+ sect = "ยง",
+ semi = ";",
+ seswar = "โคฉ",
+ setminus = "โ",
+ sext = "โถ",
+ sharp = "โฏ",
+ shy = "-",
+ sigma = "ฯ",
+ sigmaf = "ฯ",
+ sim = "โผ",
+ sime = "โ",
+ simne = "โ",
+ simrarr = "โฅฒ",
+ sol = "/",
+ spades = "โ ",
+ sqcap = "โ",
+ sqcup = "โ",
+ sqsub = "โ",
+ sqsube = "โ",
+ sqsup = "โ",
+ sqsupe = "โ",
+ star = "โ",
+ starf = "โ
",
+ sub = "โ",
+ sube = "โ",
+ subne = "โ",
+ subrarr = "โฅน",
+ sum = "โ",
+ sung = "โช",
+ sup = "โ",
+ sup1 = "ยน",
+ sup2 = "ยฒ",
+ sup3 = "ยณ",
+ supe = "โ",
+ suplarr = "โฅป",
+ supne = "โ",
+ swArr = "โ",
+ swarhk = "โคฆ",
+ swnwar = "โคช",
+ szlig = "ร",
+ tau = "ฯ",
+ tcaron = "ลฅ",
+ tcedil = "ลฃ",
+ there4 = "โด",
+ theta = "ฮธ",
+ thetasym = "ฯ",
+ thorn = "รพ",
+ tilde = "ห",
+ times = "ร",
+ timesb = "โ ",
+ top = "โค",
+ tprime = "โด",
+ trade = "โข",
+ trie = "โ",
+ tstrok = "ลง",
+ uArr = "โ",
+ uHar = "โฅฃ",
+ uacute = "รบ",
+ uarr = "โ",
+ ubreve = "ลญ",
+ ucirc = "รป",
+ udarr = "โ
",
+ udblac = "ลฑ",
+ udhar = "โฅฎ",
+ ufisht = "โฅพ",
+ ugrave = "รน",
+ uharl = "โฟ",
+ uharr = "โพ",
+ umacr = "ลซ",
+ uml = "ยจ",
+ uogon = "ลณ",
+ uplus = "โ",
+ upsih = "ฯ",
+ upsilon = "ฯ
",
+ uring = "ลฏ",
+ utdot = "โฐ",
+ utilde = "ลฉ",
+ uuarr = "โ",
+ uuml = "รผ",
+ vArr = "โ",
+ vDash = "โจ",
+ vdash = "โข",
+ veebar = "โป",
+ veeeq = "โ",
+ vellip = "โฎ",
+ vert = "|",
+ vltri = "โฒ",
+ vrtri = "โณ",
+ wcirc = "ลต",
+ wedgeq = "โ",
+ weierp = "โ",
+ wreath = "โ",
+ xcap = "โ",
+ xcup = "โ",
+ xhArr = "โบ",
+ xharr = "โท",
+ xi = "ฮพ",
+ xlArr = "โธ",
+ xlarr = "โต",
+ xmap = "โผ",
+ xnis = "โป",
+ xrArr = "โน",
+ xrarr = "โถ",
+ xvee = "โ",
+ xwedge = "โ",
+ yacute = "รฝ",
+ ycirc = "ลท",
+ yen = "ยฅ",
+ yuml = "รฟ",
+ zacute = "ลบ",
+ zcaron = "ลพ",
+ zdot = "ลผ",
+ zeta = "ฮถ",
+ ziglarr = "โ",
+ zigrarr = "โ"
+ ---_
+};
+
+--- Checks for missing entities.
+---@return boolean
+---@return string[]
+entities.check = function ()
+ local _inv = {};
+
+ for name, val in pairs(entities.names) do
+ if not val then
+ table.insert(_inv, name);
+ end
+ end
+
+ return vim.tbl_isempty(_inv), inv;
+end
+
+--- Gets an entity from it's number/name.
+---@param val string
+---@return string?
+entities.get = function (val)
+ if tonumber(val) then
+ return entities.codes[tonumber(val)];
+ elseif entities.names[val] then
+ return entities.names[val];
+ end
+end
+
+return entities;
diff --git a/lua/markview/extras/checkboxes.lua b/lua/markview/extras/checkboxes.lua
index 8365585..93430a8 100644
--- a/lua/markview/extras/checkboxes.lua
+++ b/lua/markview/extras/checkboxes.lua
@@ -1,365 +1,794 @@
local checkboxes = {};
+local spec = require("markview.spec");
+local utils = require("markview.utils");
-local escape_string = function (input)
- if not input then
+---@class markcheck.config
+---
+---@field default string Default checkbox state.
+---@field remove_style
+---| "disable" Clears state.
+---| "checkbox" Removes checkbox.
+---| "list_item" Removes list item.
+---@field states string[][] List of sets containing various checkbox states.
+checkboxes.config = {
+ default = "X",
+ remove_style = "disable",
+
+ states = {
+ { " ", "/", "X" },
+ { "<", ">" },
+ { "?", "!", "*" },
+ { '"' },
+ { "l", "b", "i" },
+ { "S", "I" },
+ { "p", "c" },
+ { "f", "k", "w" },
+ { "u", "d" }
+ }
+};
+
+--- Holds checkbox states for different lines
+--- for each buffer.
+---@type { [integer]: { [integer]: string? } }
+checkboxes.cache = {};
+
+--- Cache the checkbox state of a specific line.
+---@param buffer integer
+---@param lnum integer
+---@param state string
+checkboxes.register_state = function (buffer, lnum, state)
+ if not checkboxes.cache[buffer] then
+ checkboxes.cache[buffer] = {};
+ elseif state == nil then
return;
end
- input = input:gsub("%%", "%%%");
+ checkboxes.cache[buffer][lnum] = state;
+end
+
+--- Gets the row, col coordinates for a given
+--- state
+---@param state string
+---@return [ integer, integer ]?
+checkboxes.get_state_coords = function (state)
+ for y, row in ipairs(checkboxes.config.states) do
+ for x, col in ipairs(row) do
+ if col == state then
+ return { x, y };
+ end
+ end
+ end
- input = input:gsub("%(", "%%(");
- input = input:gsub("%)", "%%)");
+ return nil;
+end
- input = input:gsub("%.", "%%.");
- input = input:gsub("%+", "%%+");
- input = input:gsub("%-", "%%-");
- input = input:gsub("%*", "%%*");
- input = input:gsub("%?", "%%?");
- input = input:gsub("%^", "%%^");
- input = input:gsub("%$", "%%$");
+--- Normalizes {num} between 0 & {max}
+---@param num number
+---@param max number
+---@return number
+local normalize = function (num, max)
+ if num > max then
+ num = num % max;
+ elseif num < 0 then
+ num = max + num;
+
+ if num < 0 then
+ num = max - (math.abs(num) % max)
+ end
- input = input:gsub("%[", "%%[");
- input = input:gsub("%]", "%%]");
+ elseif num == 0 then
+ num = max;
+ end
- return input;
+ return num == 0 and max or num;
end
-local str2bool = function (str)
- if not str then
- return false;
- elseif str == "true" then
- return true;
+---+${class, Checkbox toggle}
+
+--- Checkbox toggle sub-module.
+local toggler = {};
+
+--- Removes checkbox from a line.
+---@param buffer integer
+---@param lnum integer
+---@param line string
+---@return string
+---@return table
+toggler.__remove_checkbox = function (buffer, lnum, line)
+ ---+${func}
+ local before, state, after;
+
+ --- Pattern should change based on the list
+ --- item style.
+ if line:match("^[%s%>]*[%-%+%*]") then
+ before, state, after = line:match("^([%s%>]*[%-%+%*]%s+%[)(.?)(%].*)$");
+ else
+ before, state, after = line:match("^([%s%>]*%d+[%.%)]%s+%[)(.?)(%].*)$");
end
- return false;
-end
+ --- Cache state.
+ checkboxes.register_state(buffer, lnum, state);
+
+ --- Remove different things based on the
+ --- option's value.
+ if checkboxes.config.remove_style == "disable" then
+ return before .. " " .. after, { before, state, after };
+ elseif checkboxes.config.remove_style == "checkbox" then
+ return before:gsub("%s+%[$", "") .. " " .. after:gsub("^%]%s", ""), { before, state, after };
+ elseif checkboxes.config.remove_style == "list_item" then
+ if before:match("[%-%+%*]%s+%[$") then
+ return before:gsub("[%-%+%*]%s+%[$", "") .. after:gsub("^%]%s", ""), { before, state, after };
+ else
+ return before:gsub("%d+[%.%)]%s+%[$", "") .. after:gsub("^%]%s", ""), { before, state, after };
+ end
+ end
-checkboxes.configuraton = {
- remove_markers = true,
- default_marker = "-",
+ return line, { before, state, after };
+ ---_
+end
- default_state = "X",
+--- Adds checkbox to lines
+---@param buffer integer
+---@param lnum integer
+---@param line string
+---@return string
+---@return string[]
+toggler.__add_checkbox = function (buffer, lnum, line)
+ ---+${func}
+ local before, state, after;
+ local cached_state;
+
+ --- Get the cached state, if possible.
+ if checkboxes.cache[buffer] and checkboxes.cache[buffer][lnum] then
+ cached_state = checkboxes.cache[buffer][lnum];
+ end
- states = {
- { "X", " " },
- { "o", "-" },
- }
-}
+ --- Change the text differently depending on whether
+ --- it has [], [ ] or just the list item.
+ ---
+ --- This is based on the assumption that the checker
+ --- function didn't fail.
+ if line:match("^[%s%>]*[%-%+%*]%s+%[%]") or line:match("^[%s%>]*%d+[%.%)]%s+%[%]") then
+ if line:match("^[%s%>]*[%-%+%*]") then
+ before, state, after = line:match("^([%s%>]*[%-%+%*]%s+%[)(.?)(%].*)$");
+ else
+ before, state, after = line:match("^([%s%>]*%d+[%.%)]%s+%[)(.?)(%].*)$");
+ end
----@class mkv.extra.checkboxes.state
----
----@field marker? string
----@field checkbox? string
+ return before .. (checkboxes.config.default or "") .. after, { before, state, after };
+ elseif line:match("^[%s%>]*[%-%+%*]%s+%[ %]") or line:match("^[%s%>]*%d+[%.%)]%s+%[ %]") then
+ if line:match("^[%s%>]*[%-%+%*]") then
+ before, state, after = line:match("^([%s%>]*[%-%+%*]%s+%[)( )(%].*)$");
+ else
+ before, state, after = line:match("^([%s%>]*%d+[%.%)]%s+%[)( )(%].*)$");
+ end
----@type table
-checkboxes.state = {};
+ return before .. (cached_state or checkboxes.config.default or "") .. after, { before, state, after };
+ else
+ if line:match("^[%s%>]*[%-%+%*]") then
+ before, after = line:match("^([%s%>]*[%-%+%*])(.*)$");
+ else
+ before, after = line:match("^([%s%>]*%d+[%.%)])(.*)$");
+ end
-checkboxes.update = function (buffer, line, str, save)
- if not checkboxes.state[buffer] then
- checkboxes.state[buffer] = {};
+ return before .. string.format(" [%s]", cached_state or checkboxes.config.default or "") .. after, { before, state, after };
end
+ ---_
+end
- local checkbox = str:match("^[%>%s]*[%-%+%*]%s*%[(.)%]");
- local marker = str:match("^[%>%s]*([%-%+%*])")
- local group, state;
-
- if checkbox then
- for g, grp in ipairs(checkboxes.configuraton.states) do
- if vim.list_contains(grp, checkbox) then
- for s, ste in ipairs(grp) do
- if ste == checkbox then
- group, state = g, s;
- break;
- end
- end
+--- Function to run if the text has list item markers.
+---@param buffer integer
+---@param from integer
+---@param to integer
+---@param lines string[]
+---@return string[]
+toggler.__has_markers = function (buffer, from, to, lines)
+ ---+${func}
+ local state = "normal";
+ local tolerance = spec.get({ "experimental", "list_empty_line_tolerance" }, { fallback = 3 });
+ local empty_lines = 0;
+
+ --- Store the number of characters before the marker.
+ ---
+ --- WARN, this is assuming `expandtab` is in use!
+ --- FIXME, Find a better way to check if a line is
+ --- part of a list item or not.
+ local col_start = 0;
+
+ --- Does this line have a checkbox? Do we remove it?
+ ---@param line string
+ ---@return boolean
+ local function should_remove_checkbox(line)
+ if line:match("^[%s%>]*[%-%+%*]%s+%[%]") or line:match("^[%s%>]*%d+[%.%)]%s+%[%]") then
+ if checkboxes.config.remove_style == "disable" then
+ return false;
+ else
+ return true;
end
+ elseif line:match("^[%s%>]*[%-%+%*]%s+%[ %]") or line:match("^[%s%>]*%d+[%.%)]%s+%[ %]") then
+ if checkboxes.config.remove_style == "disable" then
+ return false;
+ else
+ return true;
+ end
+ elseif line:match("^[%s%>]*[%-%+%*]%s+%[.%]") or line:match("^[%s%>]*%d+[%.%)]%s+%[.%]") then
+ return true;
end
+
+ return false;
end
- if save ~= false then
- checkboxes.state[buffer][line] = vim.tbl_extend("force", checkboxes.state[buffer][line] or {}, {
- marker = marker,
- checkbox = checkbox,
+ --- Should this line have a checkbox?
+ ---@param line string
+ ---@return boolean
+ local function should_add_checkbox(line)
+ if checkboxes.config.remove_style == "disable" and line:match("^[%s%>]*[%-%+%*]%s+%[%]") or line:match("^[%s%>]*%d+[%.%)]%s+%[%]") then
+ return true;
+ elseif checkboxes.config.remove_style == "disable" and line:match("^[%s%>]*[%-%+%*]%s+%[ %]") or line:match("^[%s%>]*%d+[%.%)]%s+%[ %]") then
+ return true;
+ elseif line:match("^[%s%>]*[%-%+%*]%s+") or line:match("^[%s%>]*%d+[%.%)]%s+") then
+ --- Cache state here
+ return true;
+ end
- group = group, state = state
- });
+ return false;
end
- marker = escape_string(marker);
- checkbox = escape_string(checkbox);
+ for l, line in ipairs(lines) do
+ if should_remove_checkbox(line) then
+ empty_lines = 0;
+ state = "remove";
- return {
- marker = marker,
- checkbox = checkbox,
+ local replace, data = toggler.__remove_checkbox(buffer, from + (l - 1), line);
+ lines[l] = replace;
- group = group, state = state
- };
-end
+ col_start = vim.fn.strchars(data[1]:gsub("[%-%+%*]%s+%[$", ""):gsub("%d+[%.%)]%s+%[$", ""));
+ elseif should_add_checkbox(line) then
+ empty_lines = 0;
+ state = "add"; --- This is for future use.
-checkboxes.toggle = function (remove_markers, exit)
- local buffer = vim.api.nvim_get_current_buf();
- local from, to = vim.fn.getpos("v"), vim.fn.getpos(".");
- local hasMarkers = false;
+ local replace, data = toggler.__add_checkbox(buffer, from + (l - 1), line);
+ lines[l] = replace;
- if remove_markers == nil then
- remove_markers = checkboxes.configuraton.remove_markers;
- end
+ col_start = vim.fn.strchars(data[1]:gsub("[%-%+%*]%s+%[$", ""):gsub("%d+[%.%)]%s+%[$", ""));
+ elseif line:match("^[%s%>]*$") then
+ --- This will mimic the behavior of how
+ --- list items are rendered by the plugin.
+ if empty_lines >= tolerance then
+ state = "normal";
+ else
+ empty_lines = empty_lines + 1;
+ end
+ elseif state == "remove" then
+ local before = vim.fn.strcharpart(line, 0, col_start + 2);
- if exit == nil then
- exit = checkboxes.configuraton.exit;
+ if before:match("^[%s%>]*$") and checkboxes.config.remove_style == "list_item" then
+ lines[l] = vim.fn.strcharpart(line, 0, math.max(0, col_start - 2)) .. vim.fn.strcharpart(line, col_start);
+ elseif before:match("^[%s%>]*$") == nil then
+ state = "normal";
+ end
+ end
end
- from, to = math.min(from[2], to[2]), math.max(from[2], to[2])
+ return lines;
+ ---_
+end
- local text = vim.api.nvim_buf_get_lines(buffer, from - 1, to, false);
+--- Initializes the checkbox toggler on a specified
+--- range inside the given buffer.
+---@param buffer integer?
+---@param from integer?
+---@param to integer?
+toggler.init = function (buffer, from, to)
+ ---+${func}
+ buffer = buffer or vim.api.nvim_get_current_buf();
+
+ local pos = vim.fn.getpos;
+ local row_start, row_end;
+
+ if from and to then
+ row_start = math.min(from, to);
+ row_end = math.max(from, to);
+ elseif pos("v")[2] ~= pos(".")[2] then
+ row_start = math.min(pos("v")[2], pos(".")[2]) - 1;
+ row_end = math.max(pos("v")[2], pos(".")[2]);
+ else
+ row_start = pos(".")[2] - 1;
+ row_end = pos(".")[2];
+ end
- for _, line in ipairs(text) do
- if line:match("^[%>%s]*([%-%+%*])") then
- hasMarkers = true;
+ local lines = vim.api.nvim_buf_get_lines(buffer, row_start, row_end, false);
+ local contains_markers = false;
+
+ for _, line in ipairs(lines) do
+ if line:match("^[%s%>]*[%-%+%*]") or line:match("^[%s%>]*%d+[%.%)]") then
+ contains_markers = true;
break;
end
end
- local inside_item, removed_item, list_indent = false, false, "";
+ if contains_markers == true then
+ lines = toggler.__has_markers(buffer, row_start, row_end, lines);
+ else
+ return;
+ end
- for l, line in ipairs(text) do
- if hasMarkers == true then
- local data = checkboxes.update(buffer, from + (l - 1), line, true);
- local this = checkboxes.state[vim.api.nvim_get_current_buf()][from + l - 1];
+ vim.api.nvim_buf_set_lines(buffer, row_start, row_end, false, lines);
+ ---_
+end
- local indent = line:match("^([%>%s]*)");
+---_
+---+${class, Checkbox state changer}
- if inside_item == true and line == "" then
- inside_item = false;
- list_indent = "";
- end
+--- Checkbox state changer sub-module
+local changer = {};
- if data.checkbox then
- -- Checkbox exists,
- -- Remove the checkbox
- removed_item = true;
- inside_item = false;
+changer.init = function (buffer, from, to, x, y)
+ ---+${func}
- if remove_markers == true then
- text[l] = line:gsub(indent .. data.marker .. "%s+%[" .. data.checkbox .. "%]" .. "%s?", indent)
- else
- text[l] = line:gsub(indent .. data.marker .. "%s+%[" .. data.checkbox .. "%]", indent .. data.marker)
- end
- elseif data.marker then
- -- List marker exists,
- -- Add the checkbox
- removed_item = false;
- inside_item = true;
-
- if this.checkbox then
- text[l] = line:gsub(indent .. "%" .. data.marker .. "%s*", indent .. data.marker .. " [" .. this.checkbox .. "] ")
- else
- text[l] = line:gsub(indent .. "%" .. data.marker .. "%s*", indent .. data.marker .. " [" .. checkboxes.configuraton.default_state .. "] ")
- end
- elseif this.marker and this.checkbox then
- -- A previous marker existed
- -- Restore the marker & checkbox
- removed_item = false;
- inside_item = true;
-
- text[l] = line:gsub("^" .. indent, indent .. this.marker .. " [" .. this.checkbox .. "] ")
- elseif removed_item == true then
- text[l] = line:gsub("^" .. list_indent .. " ", "")
- elseif inside_item == true then
- text[l] = line:gsub("^" .. indent, list_indent .. " ")
- end
- elseif not line:match("^([%>%s]*)$") then
- checkboxes.update(buffer, from + l - 1, line, false);
+ --- Set some default values
+ buffer = buffer or vim.api.nvim_get_current_buf();
+ x = x or 0;
+ y = y or 0;
- local this = checkboxes.state[vim.api.nvim_get_current_buf()][from + l - 1] or {};
- local indent = line:match("^([%>%s]*)");
+ local pos = vim.fn.getpos;
+ local row_start, row_end;
- if this.checkbox then
- text[l] = line:gsub("^" .. indent, indent .. this.marker .. " [" .. this.checkbox .. "] ")
- else
- text[l] = line:gsub("^" .. indent, indent .. checkboxes.configuraton.default_marker .. " [" .. checkboxes.configuraton.default_state .. "] ")
- end
+ if from and to then
+ row_start = math.min(from, to);
+ row_end = math.max(from, to);
+ elseif pos("v")[2] ~= pos(".")[2] then
+ row_start = math.min(pos("v")[2], pos(".")[2]) - 1;
+ row_end = math.max(pos("v")[2], pos(".")[2]);
+ else
+ row_start = pos(".")[2] - 1;
+ row_end = pos(".")[2];
+ end
+
+ local lines = vim.api.nvim_buf_get_lines(buffer, row_start, row_end, false);
+
+ --- Changes the provided state and returns the
+ --- new state
+ ---@param state string
+ ---@param lnum integer
+ ---@return string
+ local change_state = function (state, lnum)
+ local coords = checkboxes.get_state_coords(state);
+
+ if coords == nil then
+ checkboxes.register_state(buffer, lnum, state);
+ return state;
end
+
+ coords[2] = normalize(coords[2] + y, #checkboxes.config.states);
+
+ local set = checkboxes.config.states[coords[2]];
+ coords[1] = normalize(coords[1] + x, #set);
+
+ checkboxes.register_state(buffer, lnum, set[coords[1]]);
+ return set[coords[1]];
end
- vim.api.nvim_buf_set_lines(buffer, from - 1, to, false, text);
+ for l, line in ipairs(lines) do
+ if line:match("^[%s%>]*[%-%+%*]%s+%[.%]") then
+ local _, chk_e, state = line:find("^[%s%>]*[%-%+%*%)]%s+%[(.)%]");
+ local new_state = change_state(state, (l - 1) + row_start);
- if exit ~= false then
- vim.api.nvim_input("");
+ lines[l] = line:sub(0, chk_e - 2) .. new_state .. line:sub(chk_e);
+ elseif line:match("^[%s%>]*%d+[%.%)]%s+%[.%]") then
+ local _, chk_e, state = line:find("^[%s%>]*%d+[%.%)]%s+%[(.)%]");
+ local new_state = change_state(state, (l - 1) + row_start);
+
+ lines[l] = line:sub(0, chk_e - 2) .. new_state .. line:sub(chk_e);
+ end
end
+
+ vim.api.nvim_buf_set_lines(buffer, row_start, row_end, false, lines);
+ ---_
end
-local scroll = function (array, index, scroll_past_end)
- if array[index] then
- return array[index];
+---_
+
+---+${class, Interactive checkbox state changer}
+
+local interactive = {};
+
+interactive.ui_ns = vim.api.nvim_create_namespace("markview-extras-checkboxes");
+interactive.source_buffer = nil;
+interactive.ui_buffer = vim.api.nvim_create_buf(false, true);
+interactive.ui_window = nil;
+
+interactive.keymaps = {};
+interactive.coordinate = nil;
+
+--- Draws the UI.
+interactive.__draw = function ()
+ ---+${func}
+
+ if not interactive.ui_buffer or vim.api.nvim_buf_is_valid(interactive.ui_buffer) == false then
+ interactive.ui_buffer = vim.api.nvim_create_buf(false, true);
end
- if scroll_past_end == true then
- if index < 1 then
- return array[#array - index]
- elseif index > #array then
- return array[index % #array];
- end
+ vim.api.nvim_buf_clear_namespace(interactive.ui_buffer, interactive.ui_ns, 0, -1);
+ vim.api.nvim_buf_set_lines(interactive.ui_buffer, 0, -1, false, { "" });
+
+ local width = 14;
+ local _v = {};
+
+ local set = checkboxes.config.states[interactive.coordinate[2]];
+ local x = interactive.coordinate[1];
+
+ if x - 1 < 1 or x - 1 > #set then
+ table.insert(_v, { " โข", "MarkviewGradient4" });
+ table.insert(_v, { "โ", "MarkviewGradient3" });
+ table.insert(_v, { "โข ", "MarkviewGradient4" });
+ else
+ table.insert(_v, { " โข", "MarkviewGradient4" });
+ table.insert(_v, { set[x - 1], "MarkviewGradient3" })
+ table.insert(_v, { "โข ", "MarkviewGradient4" });
end
- if index < 1 then
- return array[#array - index]
- elseif index > #array then
- return array[#array];
+ table.insert(_v, { "[", "MarkviewGradient6" });
+ table.insert(_v, { set[math.min(#set, x)], "MarkviewGradient9" })
+ table.insert(_v, { "]", "MarkviewGradient6" });
+
+ if x + 1 > #set then
+ table.insert(_v, { " โข", "MarkviewGradient4" });
+ table.insert(_v, { "โ", "MarkviewGradient3" });
+ table.insert(_v, { "โข ", "MarkviewGradient4" });
+ else
+ table.insert(_v, { " โข", "MarkviewGradient4" });
+ table.insert(_v, { set[x + 1], "MarkviewGradient3" })
+ table.insert(_v, { "โข ", "MarkviewGradient4" });
end
-end
-local tbl_clamp = function (tbl, index)
- return tbl[math.min(math.max(1, index), #tbl)];
-end
+ vim.api.nvim_buf_set_extmark(interactive.ui_buffer, interactive.ui_ns, 0, 0, {
+ virt_text_pos = "inline",
+ virt_text = _v
+ });
-checkboxes.forward = function (scroll_past_end)
- local buffer = vim.api.nvim_get_current_buf();
- local from, to = vim.fn.getpos("v"), vim.fn.getpos(".");
+ if not interactive.ui_window or vim.api.nvim_win_is_valid(interactive.ui_window) == false then
+ interactive.ui_window = vim.api.nvim_open_win(interactive.ui_buffer, false, {
+ relative = "cursor",
+ row = 1,
+ col = -1 * math.floor(width / 2),
- from, to = math.min(from[2], to[2]), math.max(from[2], to[2])
- local text = vim.api.nvim_buf_get_lines(buffer, from - 1, to, false);
+ width = width,
+ height = 1,
- for l, line in ipairs(text) do
- local data = checkboxes.update(buffer, from + l - 1, line, false);
+ -- focusable = false
+ });
+ else
+ vim.api.nvim_win_set_config(interactive.ui_window, {
+ relative = "cursor",
+ row = 1,
+ col = -1 * math.floor(width / 2),
- if data.checkbox then
- local next = scroll(checkboxes.configuraton.states[data.group], data.state + 1, scroll_past_end)
+ width = width,
+ height = 1,
- text[l] = line:gsub("%[" .. data.checkbox .. "%]", "[" .. next .. "]")
- end
+ -- focusable = false
+ });
end
- vim.api.nvim_buf_set_lines(buffer, from - 1, to, false, text);
+ local erange = interactive.edit_range;
+ local line = vim.api.nvim_buf_get_lines(interactive.source_buffer, erange[1], erange[1] + 1, false)[1];
+
+ vim.api.nvim_buf_set_text(
+ interactive.source_buffer,
+ erange[1],
+ #vim.fn.strcharpart(line, 0, erange[2]),
+ erange[1],
+ #vim.fn.strcharpart(line, 0, erange[3]),
+ { set[math.min(#set, x)] }
+ );
+ ---_
end
-checkboxes.backward = function (scroll_past_end)
- local buffer = vim.api.nvim_get_current_buf();
- local from, to = vim.fn.getpos("v"), vim.fn.getpos(".");
+--- Closes the interactive state changer
+--- window and restores keymaps.
+interactive.__close = function ()
+ pcall(vim.api.nvim_win_close, interactive.ui_window, true);
+
+ vim.api.nvim_buf_del_keymap(interactive.source_buffer, "n", "h");
+ vim.api.nvim_buf_del_keymap(interactive.source_buffer, "n", "j");
+ vim.api.nvim_buf_del_keymap(interactive.source_buffer, "n", "k");
+ vim.api.nvim_buf_del_keymap(interactive.source_buffer, "n", "l");
+
+ for _, keymap in ipairs(interactive.keymaps) do
+ vim.api.nvim_buf_set_keymap(
+ interactive.source_buffer,
+ keymap.mode,
+ keymap.lhs or "",
+ keymap.rhs or "",
+ {
+ callback = keymap.callback
+ }
+ );
+ end
+end
- from, to = math.min(from[2], to[2]), math.max(from[2], to[2])
- local text = vim.api.nvim_buf_get_lines(buffer, from - 1, to, false);
+--- Caches keymaps for h, j, k & l.
+---@param buffer integer
+interactive.__cache_keymaps = function (buffer)
+ ---+${func}
- for l, line in ipairs(text) do
- local data = checkboxes.update(buffer, from + l - 1, line, true);
+ for _, keymap in ipairs(vim.api.nvim_buf_get_keymap(buffer, "n")) do
+ if vim.list_contains({ "h", "j", "k", "l" }, keymap.lhs) then
+ table.insert(interactive.keymaps, keymap);
+ end
+ end
- if data.checkbox then
- local next = scroll(checkboxes.configuraton.states[data.group], data.state - 1, scroll_past_end)
+ vim.api.nvim_buf_set_keymap(buffer, "n", "h", "", {
+ callback = function ()
+ interactive.__h();
+ end
+ });
- text[l] = line:gsub("%[" .. data.checkbox .. "%]", "[" .. next .. "]")
+ vim.api.nvim_buf_set_keymap(buffer, "n", "j", "", {
+ callback = function ()
+ interactive.__j();
end
- end
+ });
- vim.api.nvim_buf_set_lines(buffer, from - 1, to, false, text);
-end
+ vim.api.nvim_buf_set_keymap(buffer, "n", "k", "", {
+ callback = function ()
+ interactive.__k();
+ end
+ });
+ vim.api.nvim_buf_set_keymap(buffer, "n", "l", "", {
+ callback = function ()
+ interactive.__l();
+ end
+ });
+ ---_
+end
-checkboxes.next = function (scroll_past_end)
- local buffer = vim.api.nvim_get_current_buf();
- local from, to = vim.fn.getpos("v"), vim.fn.getpos(".");
+---+${class, Various movements}
+interactive.__h = function ()
+ local set = checkboxes.config.states[interactive.coordinate[2]];
- from, to = math.min(from[2], to[2]), math.max(from[2], to[2])
- local text = vim.api.nvim_buf_get_lines(buffer, from - 1, to, false);
+ interactive.coordinate = {
+ normalize(interactive.coordinate[1] - 1, #set),
+ interactive.coordinate[2]
+ };
+ interactive.__draw();
+end
- for l, line in ipairs(text) do
- local data = checkboxes.update(buffer, from + l - 1, line, false);
+interactive.__l = function ()
+ local set = checkboxes.config.states[interactive.coordinate[2]];
- if data.checkbox then
- local next = tbl_clamp(scroll(checkboxes.configuraton.states, data.group + 1, scroll_past_end), data.state);
+ interactive.coordinate = {
+ normalize(interactive.coordinate[1] + 1, #set),
+ interactive.coordinate[2]
+ };
+ interactive.__draw();
+end
- text[l] = line:gsub("%[" .. data.checkbox .. "%]", "[" .. next .. "]")
- end
- end
+interactive.__j = function ()
+ interactive.coordinate = {
+ interactive.coordinate[1],
+ normalize(interactive.coordinate[2] + 1, #checkboxes.config.states),
+ };
+ interactive.__draw();
+end
- vim.api.nvim_buf_set_lines(buffer, from - 1, to, false, text);
+interactive.__k = function ()
+ interactive.coordinate = {
+ interactive.coordinate[1],
+ normalize(interactive.coordinate[2] - 1, #checkboxes.config.states),
+ };
+ interactive.__draw();
end
+---_
+
+--- Initiates an interactive checkbox state
+--- changer.
+interactive.init = function ()
+ ---+${func}
-checkboxes.previous = function (scroll_past_end)
local buffer = vim.api.nvim_get_current_buf();
- local from, to = vim.fn.getpos("v"), vim.fn.getpos(".");
+ local cursor = vim.api.nvim_win_get_cursor(0);
- from, to = math.min(from[2], to[2]), math.max(from[2], to[2])
- local text = vim.api.nvim_buf_get_lines(buffer, from - 1, to, false);
+ interactive.source_buffer = buffer;
- for l, line in ipairs(text) do
- local data = checkboxes.update(buffer, from + l - 1, line, false);
+ local line = vim.api.nvim_buf_get_lines(buffer, cursor[1] - 1, cursor[1], false)[1];
+ local state, col_start, col_end;
- if data.checkbox then
- local next = tbl_clamp(scroll(checkboxes.configuraton.states, data.group - 1, scroll_past_end), data.state);
+ if line:match("^[%s%>]*[%-%+%*]%s+%[.%]") then
+ local match = line:match("^[%s%>]*[%-%+%*]%s+%[.%]");
+ local len = vim.fn.strchars(match);
- text[l] = line:gsub("%[" .. data.checkbox .. "%]", "[" .. next .. "]")
- end
+ state = match:match("%[(.)%]$");
+ col_start = #vim.fn.strcharpart(match, 0, len - 2);
+ col_end = #vim.fn.strcharpart(match, 0, len - 1);
+ elseif line:match("^[%s%>]*%d+[%.%)]%s+%[.%]") then
+ local match = line:match("^[%s%>]*%d+[%.%)]%s+%[.%]");
+ local len = vim.fn.strchars(match);
+
+ state = match:match("%[(.)%]$");
+ col_start = #vim.fn.strcharpart(match, 0, len - 2);
+ col_end = #vim.fn.strcharpart(match, 0, len - 1);
+ else
+ return;
end
- vim.api.nvim_buf_set_lines(buffer, from - 1, to, false, text);
-end
+ if state == nil or checkboxes.get_state_coords(state) == nil then
+ return;
+ end
-checkboxes.setup = function ()
- vim.api.nvim_create_user_command("CheckboxToggle", function (opts)
- local remove_markers, exit_mode = true, true;
- local fargs = opts.fargs;
+ interactive.coordinate = checkboxes.get_state_coords(state)
+ interactive.edit_range = { cursor[1] - 1, col_start, col_end };
+ interactive.__draw();
+ interactive.__cache_keymaps(buffer);
- if #fargs > 0 then
- remove_markers = str2bool(fargs[1]);
- exit_mode = str2bool(fargs[2]);
+ local on_keypress;
+
+ on_keypress = vim.on_key(function (_, raw)
+ if not vim.list_contains({ "h", "j", "k", "l" }, raw) then
+ vim.on_key(nil, on_keypress);
+ interactive.__close();
end
+ end);
+ ---_
+end
- checkboxes.toggle(remove_markers, exit_mode)
- end, {
- nargs = "*",
- desc = "Toggles checkboxes"
- });
+---_
+
+checkboxes.toggler = toggler;
+checkboxes.change = changer;
+checkboxes.interactive = interactive;
+
+--- Commands for this module.
+checkboxes.__completion = utils.create_user_command_class({
+ default = {
+ completion = function (arg_lead)
+ local comp = {};
- vim.api.nvim_create_user_command("CheckboxPrevSet", function (opts)
- local scroll_past_end = true;
- local fargs = opts.fargs;
+ for _, item in ipairs({ "toggle", "change", "interactive" }) do
+ if item:match(arg_lead) then
+ table.insert(comp, item);
+ end
+ end
- if #fargs > 0 then
- scroll_past_end = str2bool(fargs[1]);
+ table.sort(comp);
+ return comp;
+ end,
+ action = function (params)
+ if params.line1 ~= params.line2 then
+ checkboxes.toggler.init(0, params.line1 - 1, params.line2);
+ else
+ checkboxes.toggler.init();
+ end
end
+ },
+ sub_commands = {
+ ["toggle"] = {
+ action = function (params)
+ if params.line1 ~= params.line2 then
+ checkboxes.toggler.init(0, params.line1 - 1, params.line2);
+ else
+ checkboxes.toggler.init();
+ end
+ end
+ },
+ ["change"] = {
+ action = function (params)
+ local x = tonumber(params.fargs[2]);
+ local y = tonumber(params.fargs[3]);
+
+ if params.line1 ~= params.line2 then
+ checkboxes.change.init(0, params.line1 - 1, params.line2, x, y);
+ else
+ checkboxes.change.init(0, nil, nil, x, y);
+ end
+ end
+ },
+ ["interactive"] = {
+ action = function ()
+ checkboxes.interactive.init();
+ end
+ },
+ }
+});
+
+--- New command
+vim.api.nvim_create_user_command("Checkbox", function (params)
+ checkboxes.__completion:exec(params)
+end, {
+ nargs = "*",
+ complete = function (...)
+ return checkboxes.__completion:comp(...)
+ end,
+ range = true
+});
+
+---+${lua, v24 commands}
+vim.api.nvim_create_user_command("CheckboxToggle", function (params)
+ require("markview.health").notify("deprecation", {
+ ignore = true,
+
+ option = ":CheckboxToggle",
+ alter = ":Checkbox toggle"
+ });
+
+ if params.line1 ~= params.line2 then
+ checkboxes.toggler.init(0, params.line1, params.line2);
+ else
+ checkboxes.toggler.init();
+ end
+end, { range = true});
+
+vim.api.nvim_create_user_command("CheckboxPrevSet", function (params)
+ require("markview.health").notify("deprecation", {
+ ignore = true,
- checkboxes.previous(scroll_past_end);
- end, {
- desc = "Goes to the previous state state"
+ option = ":CheckboxPrevSet",
+ alter = ":Checkbox change 0 -1"
});
- vim.api.nvim_create_user_command("CheckboxNextSet", function (opts)
- local scroll_past_end = true;
- local fargs = opts.fargs;
- if #fargs > 0 then
- scroll_past_end = str2bool(fargs[1]);
- end
+ if params.line1 ~= params.line2 then
+ checkboxes.change.init(0, params.line1, params.line2, 0, -1);
+ else
+ checkboxes.change.init(0, nil, nil, 0, -1);
+ end
+end, { range = true});
+
+vim.api.nvim_create_user_command("CheckboxNextSet", function (params)
+ require("markview.health").notify("deprecation", {
+ ignore = true,
- checkboxes.next(scroll_past_end);
- end, {
- desc = "Goes to the next state set"
+ option = ":CheckboxNextSet",
+ alter = ":Checkbox change 0 1"
});
- vim.api.nvim_create_user_command("CheckboxNext", function (opts)
- local scroll_past_end = true;
- local fargs = opts.fargs;
+ if params.line1 ~= params.line2 then
+ checkboxes.change.init(0, params.line1, params.line2, 0, 1);
+ else
+ checkboxes.change.init(0, nil, nil, 0, 1);
+ end
+end, { range = true});
- if #fargs > 0 then
- scroll_past_end = str2bool(fargs[1]);
- end
+vim.api.nvim_create_user_command("CheckboxPrev", function (params)
+ require("markview.health").notify("deprecation", {
+ ignore = true,
- checkboxes.forward(scroll_past_end);
- end, {
- desc = "Toggles checkboxes"
+ option = ":CheckboxPrev",
+ alter = ":Checkbox change -1 0"
});
- vim.api.nvim_create_user_command("CheckboxPrev", function (opts)
- local scroll_past_end = true;
- local fargs = opts.fargs;
- if #fargs > 0 then
- scroll_past_end = str2bool(fargs[1]);
- end
+ if params.line1 ~= params.line2 then
+ checkboxes.change.init(0, params.line1, params.line2, -1, 0);
+ else
+ checkboxes.change.init(0, nil, nil, -1, 0);
+ end
+end, { range = true});
+
+vim.api.nvim_create_user_command("CheckboxNext", function (params)
+ require("markview.health").notify("deprecation", {
+ ignore = true,
- checkboxes.backward(scroll_past_end);
- end, {
- desc = "Toggles checkboxes"
+ option = ":CheckboxNext",
+ alter = ":Checkbox change 1 0"
});
+
+ if params.line1 ~= params.line2 then
+ checkboxes.change.init(0, params.line1, params.line2, 1, 0);
+ else
+ checkboxes.change.init(0, nil, nil, 1, 0);
+ end
+end, { range = true});
+---_
+
+---@param config markcheck.config?
+checkboxes.setup = function (config)
+ if not config then
+ return;
+ end
+
+ checkboxes.config = vim.tbl_deep_extend("force", checkboxes.config, config);
end
return checkboxes;
diff --git a/lua/markview/extras/editor.lua b/lua/markview/extras/editor.lua
index 64cdf27..11f978c 100644
--- a/lua/markview/extras/editor.lua
+++ b/lua/markview/extras/editor.lua
@@ -1,525 +1,775 @@
local editor = {};
+local filetypes = require("markview.filetypes");
local utils = require("markview.utils");
-local languages = require("markview.languages");
---- Configuration table for the editor.
----@class markview.editor.configuraton
----
---- Table containing various text processors.
----
---- The key is the "node name" where this will run
---- The value is a function that receives the buffer ID
---- & the node itself
----
---- It should return a filetype, A list of lines to show
---- in the editor, the start & the end range of the lines
---- where the edited text will be added.
----
----@field processors { [string]: fun(buffer: integer, TSNode: table): string, string[], integer, integer }
----
---- Table containing various text appliers. Used on
---- the edited text before replacing them in the buffer.
----
----@field appliers { [string]: fun(buffer: integer, TSNode: table, lines: string[]): string[] }
----
---- A tuple containing the minimum width and the maximum width.
---- If the values are <1 then they are used as % of screen columns.
----
----@field width [ number, number ]
----
---- A tuple containing the minimum height and the maximum height.
---- If the values are <1 then they are used as % of screen lines.
----
----@field height [ number, number ]
----@field debounce integer Debounce delay for window resizing.
----
----@field border? string | string[] Window border.
----@field border_hl? string Window border highlight group.
----@field filename_hl? string Filename highlight group.
----@field lnum_hl? string Line number highlight group.
-editor.configuraton = {
- processors = {
- ["fenced_code_block"] = function (buffer, TSNode)
- local start, col, stop, _ = TSNode:range();
- local lines = vim.api.nvim_buf_get_lines(buffer, start, stop, false);
-
- local _, info = languages.get_fence(lines[1])
- local ft = languages.info(info);
- local _l = {};
-
- table.remove(lines, 1);
- table.remove(lines, #lines);
-
- for _, line in ipairs(lines) do
- table.insert(_l, line:sub(col, #line))
- end
+editor.config = {
+ --- Default configuration for
+ --- the editor
+ style = "float",
- return ft, _l, start + 1, stop - 1;
- end
+ min_width = math.max(math.floor(vim.o.columns * 0.5), 75),
+ max_width = math.max(math.floor(vim.o.columns * 0.75), 100),
+
+ min_height = 1,
+ max_height = 10,
+
+ create = {
+ ["markdown"] = {
+ init = function (buffer)
+ local win = utils.buf_getwin(buffer);
+ local row = vim.api.nvim_win_get_cursor(win)[1];
+
+ return { "```lua", "```" }, "lua", { row - 1, 0, row, 0 };
+ end,
+ formatter = function (buffer, range, lines)
+ local this_line = vim.api.nvim_buf_get_lines(buffer, range[1], range[1] + 1, false)[1];
+ local before = this_line:match("^[%s%>]*");
+
+ for l, line in ipairs(lines) do
+ lines[l] = before .. line;
+ end
+
+ return lines;
+ end,
+
+ language = function (input)
+ if input:match("^```%s*%{(%a+)(.*)%}") then
+ return input:match("^```%s*%{(%a+)(.*)%}");
+ elseif input:match("^```(%a+)") then
+ return input:match("^```(%a+)");
+ else
+ return "lua";
+ end
+ end
+ },
},
- appliers = {
- ["fenced_code_block"] = function (buffer, TSNode, lines)
- local start, _, _, _ = TSNode:range();
- local delimiter = vim.api.nvim_buf_get_lines(buffer, start, start + 1, false)[1];
+ edit = {
+ ["fenced_code_block"] = {
+ ---+${lua, Edits fenced code blocks in markdown}
+
+ parser = function (buffer, TSNode)
+ local range = { TSNode:range() };
+ local lines = vim.api.nvim_buf_get_lines(buffer, range[1] + 1, range[3] - 1, false);
+
+ local info_node = TSNode:named_child(1);
+ local language;
+
+ if info_node and info_node:named_child(0) then
+ local lang_node = info_node:named_child(0);
+
+ if lang_node and lang_node:type() == "language" then
+ language = vim.treesitter.get_node_text(lang_node, buffer);
+ end
+ end
+
+ for l, line in ipairs(lines) do
+ lines[l] = line:sub(range[2] + 1);
+ end
- local fence = languages.get_fence(delimiter)
- local before = delimiter:match("^(.-)" .. fence);
+ range[1] = range[1] + 1;
+ range[3] = range[3] - 1;
- for l, line in ipairs(lines) do
- lines[l] = (before or "") .. line
+ return lines, language, range;
+ end,
+ formatter = function (buffer, range, text)
+ local header = vim.api.nvim_buf_get_lines(buffer, range[1] - 1, range[1], false)[1] or "";
+ local before = header:match("^[%s%>]*");
+
+ for l, line in ipairs(text) do
+ text[l] = before .. line;
+ end
+
+ return text;
+ end,
+ on_open = function (window)
+ if type(window) ~= "number" then
+ return;
+ end
+
+ vim.wo[window].sidescrolloff = 0;
end
- return lines;
+ ---_
+ }
+ }
+};
+
+---+${lua, Editor section}
+
+--- Cached data for editor.
+---@class extras.editor.e_cache
+---
+---@field node_config table?
+---@field source integer?
+---@field range integer[]?
+---@field lines string[]?
+---@field ft string?
+---@field au_mode integer?
+---@field au_resi integer?
+---@field au_text integer?
+editor.e_cache = {
+ node_config = nil,
+ source = nil,
+ range = nil,
+ lines = nil,
+
+ ft = nil,
+
+ au_mode = nil,
+ au_resi = nil,
+ au_text = nil
+};
+
+editor.au = vim.api.nvim_create_augroup("extras/editor", { clear = true });
+editor.buffer = nil;
+editor.window = nil;
+
+--- Gets window coordinates.
+---@param lines string[]
+---@return { x: integer, y: integer, w: integer, h: integer }
+local window_coords = function (lines)
+ ---+${lua}
+
+ local total_width = vim.o.columns;
+ local total_height = vim.o.lines;
+
+ local win_width = editor.config.min_width;
+ local win_height = utils.clamp(#lines, editor.config.min_height, editor.config.max_height);
+
+ for _, line in ipairs(lines) do
+ local line_width = vim.fn.strdisplaywidth(line);
+
+ if line_width >= editor.config.max_width then
+ win_width = editor.config.max_width;
+ break;
+ elseif line_width > win_width then
+ win_width = line_width;
end
- },
+ end
+
+ return {
+ x = math.ceil((total_width - win_width) / 2),
+ y = math.ceil((total_height - win_height) / 2),
- width = { 0.5, 0.75 },
- height = { 3, 0.75 },
+ w = win_width,
+ h = win_height
+ };
- debounce = 50,
+ ---_
+end
+
+--- Closes open windows.
+editor.close_editor = function ()
+ ---+${lua}
- border = "rounded",
- border_hl = nil,
+ pcall(vim.api.nvim_win_close, editor.window, true);
+ editor.window = nil;
- filename_hl = nil,
- lnum_hl = nil,
+ pcall(vim.api.nvim_buf_set_lines, editor.buffer, 0, -1, false, {});
+
+ ---_
+end
- callback = function (buf, win)
- vim.wo[win].sidescrolloff = 0;
- vim.bo[buf].expandtab = true;
+--- Applies edited text to the buffer.
+editor.apply_edit = function ()
+ if not editor.e_cache.node_config then
+ return;
end
-}
---- Creates a new buffer when not available.
---- Otherwise, returns the current editor buffer.
----@return integer
-local set_buf = function ()
- if not editor.buffer or vim.api.nvim_buf_is_valid(editor.buffer) == false then
- local buf = vim.api.nvim_create_buf(false, true);
- return buf;
+ local lines = vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false);
+
+ if editor.e_cache.node_config.formatter then
+ lines = editor.e_cache.node_config.formatter(editor.e_cache.source, editor.e_cache.range, lines);
end
- return editor.buffer;
+ vim.api.nvim_buf_set_lines(editor.e_cache.source, editor.e_cache.range[1], editor.e_cache.range[3], false, lines);
end
---- Creates a new window when not available.
---- Otherwise, returns the current editor window
---- and switches to that window
----@param config table
----@return integer
-local set_win = function (config)
+--- Updates window dimensions.
+editor.update_winpos = function ()
+ ---+${lua}
+
if not editor.window or vim.api.nvim_win_is_valid(editor.window) == false then
- local win = vim.api.nvim_open_win(editor.buffer, true, config);
- pcall(editor.configuraton.callback, editor.buffer, win);
- return win;
- elseif vim.api.nvim_win_get_tabpage(editor.window) ~= vim.api.nvim_get_current_tabpage() then
- pcall(vim.api.nvim_win_close, editor.window, true);
-
- local win = vim.api.nvim_open_win(editor.buffer, true, config);
- pcall(editor.configuraton.callback, editor.buffer, win);
- return win;
+ editor.close_editor();
+ return;
end
- vim.api.nvim_win_set_config(editor.window, config);
- vim.api.nvim_set_current_win(editor.window);
+ local coords = window_coords(
+ vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false)
+ );
- pcall(editor.configuraton.callback, editor.buffer, editor.window);
- return editor.window;
-end
+ vim.api.nvim_win_set_config(editor.window, {
+ relative = "editor",
---- When value is <1 returns the value multiplied by
---- the multiplier result, otherwise returns the
---- main value.
----@param val number
----@param multiplier number
----@return number
-local get_val = function (val, multiplier)
- return val < 1 and math.floor(multiplier * val) or val;
+ width = coords.w,
+ height = coords.h,
+
+ row = coords.y,
+ col = coords.x
+ });
+
+ ---_
end
---- Gets the window dimensions
----@param lines string[]
----@param border string | string[]
----@return integer
----@return integer
----@return number
----@return number
-local win_dimensions = function (lines, border)
- local min_w = get_val(editor.configuraton.width[1], vim.o.columns);
- local min_h = get_val(editor.configuraton.height[1], vim.o.lines);
+--- Opens editor window.
+editor.open_editor = function ()
+ ---+${lua}
+
+ ---@type string[], string, integer[]
+ local lines, ft, edit_range = editor.e_cache.lines, editor.e_cache.ft, editor.e_cache.range;
+ local ft_data = filetypes.get(ft);
+
+ --- Title to show.
+ local title = {
+ { "โผ ", ft_data.border_hl },
+ { "Range: ", "Comment" },
+ { tostring(edit_range[1] + 1), "Special" },
+ { "-","Conceal" },
+ { tostring(edit_range[3]), "Special" },
+ { " โพ", ft_data.border_hl }
+ };
+ --- Footer to show.
+ --- Also shows tooltips.
+ local footer = {
+ { "โผ ", ft_data.border_hl },
+ { "q", "Special" },
+ { ": Quit, ", "Comment" },
+ { "", "Special" },
+ { ": Confirm", "Comment" },
+ { " โถโด ", ft_data.border_hl },
+ { ft_data.icon, ft_data.border_hl },
+ { ft_data.name, ft_data.border_hl },
+ { " โพ", ft_data.border_hl }
+ };
- local max_w = get_val(editor.configuraton.width[2], vim.o.columns);
- local max_h = get_val(editor.configuraton.height[2], vim.o.lines);
+ if not editor.buffer or vim.api.nvim_buf_is_valid(editor.buffer) == false then
+ ---+${lua, Prepares the buffer & needed autocmds}
- local w, h;
+ pcall(vim.api.nvim_del_autocmd, editor.e_cache.au_text);
+ pcall(vim.api.nvim_del_autocmd, editor.e_cache.au_resi);
+ pcall(vim.api.nvim_del_autocmd, editor.e_cache.au_mode);
- local current_w, current_h = 0, #lines;
+ editor.buffer = vim.api.nvim_create_buf(false, true);
+ local timer = vim.uv.new_timer();
- for _, line in ipairs(lines) do
- if vim.fn.strdisplaywidth(line) > current_w then
- current_w = vim.fn.strdisplaywidth(line);
- end
- end
+ editor.e_cache.au_mode = vim.api.nvim_create_autocmd({ "ModeChanged" }, {
+ group = editor.au,
+ buffer = editor.buffer,
- if border then
- current_w = current_w + 2;
- current_h = current_h + 2;
- end
+ callback = function ()
+ ---+${lua, Removes tooltips based on current VIM mode}
+
+ local mode = vim.api.nvim_get_mode().mode;
+
+ vim.api.nvim_win_set_config(editor.window, {
+ footer = mode == "n" and footer or {
+ { "โผ ", ft_data.border_hl },
+ { ft_data.icon, ft_data.border_hl },
+ { ft_data.name, ft_data.border_hl },
+ { " โพ", ft_data.border_hl }
+ },
+ footer_pos = "right"
+ });
- w = utils.clamp(current_w, min_w, max_w);
- h = utils.clamp(current_h, min_h, max_h);
+ ---_
+ end
+ });
- if border then
- w = w - 2;
- h = h - 2;
+ editor.e_cache.au_text = vim.api.nvim_create_autocmd({ "VimResized", "TextChanged", "TextChangedI" }, {
+ group = editor.au,
+ buffer = editor.buffer,
+
+ callback = function ()
+ ---+${lua, Updates window position & size}
+ timer:stop();
+ timer:start(editor.config.debounce or 100, 0, vim.schedule_wrap(editor.update_winpos));
+ ---_
+ end
+ });
+
+ ---_
end
- return math.floor((vim.o.columns - w) / 2), math.floor((vim.o.lines - h) / 2), w, h;
-end
+ vim.bo[editor.buffer].filetype = ft;
+ vim.api.nvim_buf_set_lines(editor.buffer, 0, -1, false, lines);
----@type integer? The buffer ID
-editor.buffer = nil;
----@type integer? The window ID
-editor.window = nil;
+ --- New coordinates for the window.
+ ---@type { x: integer, y: integer, w: integer, h: integer }
+ local coords = window_coords(lines);
----@type integer The autocmd group
-editor.augroup = vim.api.nvim_create_augroup("markview_editor", { clear = true });
+ ---+${lua, Creates/Updates window configuration}
+ if editor.window and vim.api.nvim_win_is_valid(editor.window) then
+ vim.api.nvim_win_set_config(editor.window, {
+ relative = "editor",
---- Opens the editor with the node under the cursor
-editor.open = function ()
- editor.buffer = set_buf();
+ width = coords.w,
+ height = coords.h,
- local buffer = vim.api.nvim_get_current_buf();
+ row = coords.y,
+ col = coords.x,
- if buffer == editor.buffer then
- return;
- end
+ border = "rounded",
+ style = "minimal",
- local TSNode = vim.treesitter.get_node({ ignore_injections = true });
+ title = title,
+ footer = footer,
- local processors = editor.configuraton.processors;
- local ft, lines;
- local from, to;
- local buf_start, buf_stop;
+ title_pos = "left",
+ footer_pos = "right"
+ });
+ else
+ editor.window = vim.api.nvim_open_win(editor.buffer, true, {
+ relative = "editor",
- local file = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buffer), ":t");
+ width = coords.w,
+ height = coords.h,
- while TSNode:parent() do
- local tp = TSNode:type();
+ row = coords.y,
+ col = coords.x,
- if processors[tp] and pcall(processors[tp], buffer, TSNode) then
- ft, lines, buf_start, buf_stop = processors[tp](buffer, TSNode);
- from, _, to, _ = TSNode:range();
- break;
- end
+ border = "rounded",
+ style = "minimal",
- TSNode = TSNode:parent();
+ title = title,
+ footer = footer,
+
+ title_pos = "left",
+ footer_pos = "right"
+ });
end
+ ---_
- if not lines then
- return;
+ --- Execute callback.
+ if editor.e_cache.node_config.on_open then
+ pcall(editor.e_cache.node_config.on_open, editor.window);
end
- vim.api.nvim_create_autocmd("BufLeave", {
- group = editor.augroup,
- buffer = editor.buffer,
+ if ft_data.border_hl then
+ vim.wo[editor.window].winhl = "FloatBorder:" .. ft_data.border_hl;
+ end
+ ---+${lua, Sets up keymaps}
+ vim.api.nvim_buf_set_keymap(editor.buffer, "n", "q", "", {
callback = function ()
- pcall(vim.api.nvim_win_close, editor.window, true);
+ editor.close_editor();
end
});
- local timer = vim.uv.new_timer();
+ vim.api.nvim_buf_set_keymap(editor.buffer, "n", "", "", {
+ callback = function ()
+ editor.apply_edit()
+ editor.close_editor();
+ end
+ });
+ ---_
- vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
- group = editor.augroup,
- buffer = editor.buffer,
+ --- Attaches LSP client.
+ vim.api.nvim_buf_call(editor.buffer, function ()
+ vim.cmd("LspStart");
+ end);
- callback = function ()
- timer:stop();
- timer:start(editor.configuraton.debounce, 0, vim.schedule_wrap(function ()
- local col, row, width, height = win_dimensions(vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false), editor.configuraton.border);
+ ---_
+end
- vim.api.nvim_win_set_config(editor.window, {
- relative = "editor",
- row = row,
- col = col,
+editor.edit = function ()
+ ---+${lua}
- width = width,
- height = height,
- });
- end))
- end
- });
+ editor.close_editor();
+ editor.e_cache.source = vim.api.nvim_get_current_buf();
- vim.api.nvim_buf_set_keymap(editor.buffer, "n", "", "", {
- callback = function ()
- local edited = vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false);
+ if editor.e_cache.source == editor.buffer then
+ return;
+ end
- if editor.configuraton.appliers and editor.configuraton.appliers[TSNode:type()] then
- edited = editor.configuraton.appliers[TSNode:type()](buffer, TSNode, edited);
- end
+ local ts_available = function ()
+ local ft = vim.bo[editor.e_cache.source].ft;
+ local language = vim.treesitter.language.get_lang(ft);
- vim.api.nvim_buf_set_lines(buffer, buf_start, buf_stop, false, edited);
- vim.api.nvim_set_current_buf(buffer);
+ if language == nil then
+ return false;
+ elseif utils.parser_installed(language) == false then
+ return false;
end
- })
- vim.api.nvim_buf_set_keymap(editor.buffer, "n", "", "", {
- callback = function ()
- pcall(vim.api.nvim_win_close, editor.window, true);
- end
- })
+ return true;
+ end
- vim.api.nvim_buf_set_keymap(editor.buffer, "n", "q", "", {
- callback = function ()
- pcall(vim.api.nvim_win_close, editor.window, true);
- end
- })
+ if ts_available() == false then
+ --- Tree-sitter not available.
+ return;
+ end
- vim.api.nvim_buf_set_lines(editor.buffer, 0, -1, false, lines);
- vim.bo[editor.buffer].filetype = ft;
+ local edit_conf = editor.config.edit;
+ local node = vim.treesitter.get_node();
- local col, row, width, height = win_dimensions(lines, editor.configuraton.border);
- local icon, hl = languages.get_icon(ft);
+ while node do
+ if edit_conf[node:type()] then
+ editor.e_cache.node_config = edit_conf[node:type()];
- hl = hl .. "Fg";
+ ---@type string[], string, integer[]
+ editor.e_cache.lines, editor.e_cache.ft, editor.e_cache.range = editor.e_cache.node_config.parser(editor.e_cache.source, node)
+ editor.open_editor();
+ break;
+ end
- editor.window = set_win({
- relative = "editor",
+ node = node:parent();
+ end
+
+ ---_
+end
- row = row,
- col = col,
+---_
+
+editor.c_cache = {
+ source = nil,
+ node_config = nil,
+ range = nil,
+ ft = nil,
+ delimiters = nil,
+
+ au_mode = nil,
+ au_resi = nil,
+ au_text = nil
+};
+
+editor.create_block = function ()
+ local lines = vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false);
+ table.insert(lines, 1, editor.c_cache.delimiters[1]);
+ table.insert(lines, editor.c_cache.delimiters[2]);
+
+ ---@type integer[]
+ local range = editor.c_cache.range;
+
+ if editor.c_cache.node_config.formatter then
+ lines = editor.c_cache.node_config.formatter(
+ editor.c_cache.source,
+ range,
+ lines
+ );
+ end
- width = width,
- height = height,
+ vim.api.nvim_buf_set_lines(editor.c_cache.source, range[1], range[3], false, lines);
+end
- border = editor.configuraton.border,
+editor.close_creator = function ()
+ ---+${lua}
- title = {
- { "โผ ", editor.configuraton.border_hl or hl },
- { file, editor.configuraton.filename_hl or "Conceal" },
- { ": ", "Conceal" },
- { tostring(from + 1), editor.configuraton.lnum_hl or "Special" },
- { "-","Conceal" },
- { tostring(to), editor.configuraton.lnum_hl or "Special" },
- { " โพ", editor.configuraton.border_hl or hl }
- },
- title_pos = "left",
+ pcall(vim.api.nvim_win_close, editor.window, true);
+ editor.window = nil;
- footer = {
- { "โผ ", editor.configuraton.border_hl or hl },
- { icon, hl },
- { languages.get_name(ft), hl },
- { " โพ", editor.configuraton.border_hl or hl }
- },
- footer_pos = "right"
- });
+ pcall(vim.api.nvim_buf_set_lines, editor.buffer, 0, -1, false, {});
- vim.wo[editor.window].winhl = "FloatBorder:" .. (editor.configuraton.border_hl or hl);
- vim.wo[editor.window].statuscolumn = "";
- vim.wo[editor.window].number = false;
- vim.wo[editor.window].relativenumber = false;
+ ---_
end
---- Creates a simple code block
-editor.create = function ()
- local buffer = vim.api.nvim_get_current_buf();
- local cursor = vim.api.nvim_win_get_cursor(0);
+editor.update_editor = function ()
+ ---+${lua}
- if buffer == editor.buffer then
- return;
- end
+ ---@type string, integer[]
+ local ft, edit_range = editor.c_cache.ft, editor.c_cache.range;
+ local ft_data = filetypes.get(ft);
- editor.buffer = set_buf();
+ local lines = vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false);
- local start_delim, end_delim = "```lua", "```";
- local lines, ft = { "" }, "lua";
+ vim.bo[editor.buffer].filetype = ft;
- vim.api.nvim_create_autocmd("BufLeave", { group = editor.augroup, buffer = editor.buffer, callback = function () pcall(vim.api.nvim_win_close, editor.window, true); end });
+ --- Title to show.
+ local title = {
+ { "โผ ", ft_data.border_hl },
+ { "Create: ", "Comment" },
+ { tostring(edit_range[1] + 1), "Special" },
+ { " โพ", ft_data.border_hl }
+ };
+ --- Footer to show.
+ --- Also shows tooltips.
+ local footer = {
+ { "โผ ", ft_data.border_hl },
+ { "T", "Special" },
+ { ": Top delim, ", "Comment" },
+ { "B", "Special" },
+ { ": Bottom delim, ", "Comment" },
+ { "", "Special" },
+ { ": Confirm", "Comment" },
+ { " โถโด ", ft_data.border_hl },
+ { ft_data.icon, ft_data.border_hl },
+ { ft_data.name, ft_data.border_hl },
+ { " โพ", ft_data.border_hl }
+ };
+
+ --- New coordinates for the window.
+ ---@type { x: integer, y: integer, w: integer, h: integer }
+ local coords = window_coords(lines);
+
+ ---+${lua, Creates/Updates window configuration}
+ if editor.window and vim.api.nvim_win_is_valid(editor.window) then
+ vim.api.nvim_win_set_config(editor.window, {
+ relative = "editor",
- local timer = vim.uv.new_timer();
+ width = coords.w,
+ height = coords.h,
- vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
- group = editor.augroup,
- buffer = editor.buffer,
+ row = coords.y,
+ col = coords.x,
- callback = function ()
- timer:stop();
- timer:start(editor.configuraton.debounce, 0, vim.schedule_wrap(function ()
- local col, row, width, height = win_dimensions(vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false), editor.configuraton.border);
- vim.api.nvim_win_set_config(editor.window, { relative = "editor", row = row, col = col, width = width, height = height });
- end))
- end
- });
+ border = "rounded",
+ style = "minimal",
- vim.api.nvim_buf_set_keymap(editor.buffer, "n", "", "", {
- callback = function ()
- local ln = vim.api.nvim_buf_get_lines(buffer, cursor[1] - 1, cursor[1], false)[1];
- local edited = vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false);
+ title = title,
+ footer = footer,
- local before = ln:match("^([%s%>]*)")
+ title_pos = "left",
+ footer_pos = "right"
+ });
+ else
+ editor.window = vim.api.nvim_open_win(editor.buffer, true, {
+ relative = "editor",
- local _o = {
- before .. start_delim,
- };
+ width = coords.w,
+ height = coords.h,
- for _, line in ipairs(edited) do
- table.insert(_o, before .. line);
- end
+ row = coords.y,
+ col = coords.x,
- table.insert(_o, before .. end_delim)
+ border = "rounded",
+ style = "minimal",
- vim.api.nvim_buf_set_lines(buffer, cursor[1], cursor[1], false, _o);
- vim.api.nvim_set_current_buf(buffer);
- end
- })
+ title = title,
+ footer = footer,
- vim.api.nvim_buf_set_keymap(editor.buffer, "n", "", "", {
- callback = function ()
- vim.ui.input({ prompt = "Start delimiter: ", default = start_delim }, function (input)
- if not input then
- return;
- end
+ title_pos = "left",
+ footer_pos = "right"
+ });
+ end
+ ---_
- start_delim = tostring(input);
- local fence, info = languages.get_fence(start_delim);
- ft = languages.info(info);
- end_delim = fence or end_delim;
- vim.bo[editor.buffer].filetype = ft
- local icon, hl = languages.get_icon(ft);
-
- hl = hl .. "Fg";
-
- editor.window = set_win({
- title = {
- { "โผ ", hl },
- { " Create on line: ", "Conceal" },
- { tostring(cursor[1]), editor.configuraton.lnum_hl or "Special" },
- { " ", "Conceal" },
- { " โพ", hl }
- },
+ if ft_data.border_hl then
+ vim.wo[editor.window].winhl = "FloatBorder:" .. ft_data.border_hl;
+ end
+
+ --- Attaches LSP client.
+ vim.api.nvim_buf_call(editor.buffer, function ()
+ vim.cmd("LspStop");
+ vim.cmd("LspStart");
+ end);
+
+ ---_
+end
- footer = {
- { "โผ ", hl },
- { icon, hl },
- { languages.get_name(ft), hl },
- { " โพ", hl }
+editor.open_creator = function ()
+ ---+${lua}
+
+ if not editor.buffer or vim.api.nvim_buf_is_valid(editor.buffer) == false then
+ ---+${lua, Prepares the buffer & needed autocmds}
+
+ pcall(vim.api.nvim_del_autocmd, editor.c_cache.au_text);
+ pcall(vim.api.nvim_del_autocmd, editor.c_cache.au_resi);
+ pcall(vim.api.nvim_del_autocmd, editor.c_cache.au_mode);
+
+ editor.buffer = vim.api.nvim_create_buf(false, true);
+ local timer = vim.uv.new_timer();
+
+ editor.c_cache.au_mode = vim.api.nvim_create_autocmd({ "ModeChanged" }, {
+ group = editor.au,
+ buffer = editor.buffer,
+
+ callback = function ()
+ ---+${lua, Removes tooltips based on current VIM mode}
+
+ local curr_ft = editor.c_cache.ft;
+ local new_data = filetypes.get(curr_ft);
+
+ local mode = vim.api.nvim_get_mode().mode;
+
+ vim.api.nvim_win_set_config(editor.window, {
+ footer = mode == "n" and {
+ { "โผ ", new_data.border_hl },
+ { "T", "Special" },
+ { ": Top delim, ", "Comment" },
+ { "B", "Special" },
+ { ": Bottom delim, ", "Comment" },
+ { "", "Special" },
+ { ": Confirm", "Comment" },
+ { " โถโด ", new_data.border_hl },
+ { new_data.icon, new_data.border_hl },
+ { new_data.name, new_data.border_hl },
+ { " โพ", new_data.border_hl }
+ } or {
+ { "โผ ", new_data.border_hl },
+ { new_data.icon, new_data.border_hl },
+ { new_data.name, new_data.border_hl },
+ { " โพ", new_data.border_hl }
},
footer_pos = "right"
});
- vim.wo[editor.window].winhl = "FloatBorder:" .. hl;
- end)
- end
- });
- vim.api.nvim_buf_set_keymap(editor.buffer, "n", "", "", {
- callback = function ()
- vim.ui.input({ prompt = "End delimiter: ", default = end_delim }, function (input)
- if not input then
- return;
- end
+ ---_
+ end
+ });
+
+ editor.c_cache.au_text = vim.api.nvim_create_autocmd({ "VimResized", "TextChanged", "TextChangedI" }, {
+ group = editor.au,
+ buffer = editor.buffer,
- end_delim = tostring(input);
- end)
+ callback = function ()
+ ---+${lua, Updates window position & size}
+ timer:stop();
+ timer:start(editor.config.debounce or 100, 0, vim.schedule_wrap(editor.update_winpos));
+ ---_
+ end
+ });
+
+ ---_
+ end
+
+ vim.api.nvim_buf_set_lines(editor.buffer, 0, -1, false, {});
+ editor.update_editor();
+
+ --- Execute callback.
+ if editor.c_cache.node_config.on_open then
+ pcall(editor.c_cache.node_config.on_open, editor.window);
+ end
+
+ ---+${lua, Sets up keymaps}
+ vim.api.nvim_buf_set_keymap(editor.buffer, "n", "q", "", {
+ callback = function ()
+ editor.close_creator();
end
});
- vim.api.nvim_buf_set_keymap(editor.buffer, "n", "", "", {
+ vim.api.nvim_buf_set_keymap(editor.buffer, "n", "", "", {
callback = function ()
- pcall(vim.api.nvim_win_close, editor.window, true);
+ editor.create_block();
+ editor.close_creator();
end
- })
+ });
- vim.api.nvim_buf_set_keymap(editor.buffer, "n", "q", "", {
+ vim.api.nvim_buf_set_keymap(editor.buffer, "n", "T", "", {
callback = function ()
- pcall(vim.api.nvim_win_close, editor.window, true);
- end
- })
+ local top = vim.fn.input("Editor, Top delimiter: ", editor.c_cache.delimiters[1]);
- vim.api.nvim_buf_set_lines(editor.buffer, 0, -1, false, lines);
- vim.bo[editor.buffer].filetype = ft;
+ if top ~= nil and top ~= "" then
+ editor.c_cache.delimiters[1] = top;
+ end
- local col, row, width, height = win_dimensions(lines, editor.configuraton.border);
- local icon, hl = languages.get_icon(ft);
+ editor.c_cache.ft = editor.c_cache.node_config.language(top);
+ editor.update_editor();
+ end
+ });
- hl = hl .. "Fg";
+ vim.api.nvim_buf_set_keymap(editor.buffer, "n", "B", "", {
+ callback = function ()
+ local bottom = vim.fn.input("Editor, Bottom delimiter: ", editor.c_cache.delimiters[2]);
- editor.window = set_win({
- relative = "editor",
+ if bottom ~= nil and bottom ~= "" then
+ editor.c_cache.delimiters[2] = bottom;
+ end
+ end
+ });
+ ---_
+ ---_
+end
- row = row,
- col = col,
+editor.create = function ()
+ editor.close_creator();
+ editor.c_cache.source = vim.api.nvim_get_current_buf();
+ editor.c_cache.lines = {};
- width = width,
- height = height,
+ if editor.c_cache.source == editor.buffer then
+ return;
+ end
- border = editor.configuraton.border,
+ local ft = vim.bo[editor.c_cache.source].ft;
- title = {
- { "โผ ", hl },
- { " Create on line: ", "Conceal" },
- { tostring(cursor[1]), editor.configuraton.lnum_hl or "Special" },
- { " ", "Conceal" },
- { " โพ", hl }
- },
+ if not editor.config.create[ft] then
+ return;
+ end
- footer = {
- { "โผ ", hl },
- { icon, hl },
- { languages.get_name(ft), hl },
- { " โพ", hl }
- },
- footer_pos = "right"
- });
+ editor.c_cache.node_config = editor.config.create[ft];
- vim.wo[editor.window].winhl = "FloatBorder:" .. hl;
- vim.wo[editor.window].statuscolumn = "";
- vim.wo[editor.window].number = false;
- vim.wo[editor.window].relativenumber = false;
+ editor.c_cache.delimiters, editor.c_cache.ft, editor.c_cache.range = editor.c_cache.node_config.init(editor.c_cache.source);
+ editor.open_creator();
end
---- Setup function
----@param config markview.editor.configuraton?
-editor.setup = function (config)
- editor.configuraton = vim.tbl_deep_extend("force", editor.configuraton, config or {});
- vim.api.nvim_create_user_command("CodeCreate", function ()
+editor.actions = {
+ ["create"] = function ()
editor.create();
- end, {
- desc = "Creates a code block"
- })
-
- vim.api.nvim_create_user_command("CodeEdit", function ()
- editor.open();
- end, {
- desc = "Opens the editor"
- })
-end
+ end,
+ ["edit"] = function ()
+ editor.edit();
+ end
+};
-vim.api.nvim_create_autocmd("VimResized", {
- group = editor.augroup,
- callback = function ()
- if not editor.window or vim.api.nvim_win_is_valid(editor.window) == false then
- return;
- elseif vim.api.nvim_win_get_tabpage(editor.window) ~= vim.api.nvim_get_current_tabpage() then
- return;
+editor.__completion = utils.create_user_command_class({
+ default = {
+ completion = function (arg_lead)
+ local comp = {};
+
+ for _, item in ipairs({ "create", "edit" }) do
+ if item:match(arg_lead) then
+ table.insert(comp, item);
+ end
+ end
+
+ table.sort(comp);
+ return comp;
+ end,
+ action = function ()
+ editor.edit();
end
+ },
+ sub_commands = {
+ ["create"] = {
+ action = function ()
+ editor.actions.create();
+ end
+ },
+ ["edit"] = {
+ action = function ()
+ editor.actions.edit();
+ end,
+ }
+ }
+});
+
+--- New command
+vim.api.nvim_create_user_command("Editor", function (params)
+ editor.__completion:exec(params)
+end, {
+ nargs = 1,
+ complete = function (...)
+ return editor.__completion:comp(...)
+ end
+});
- local col, row, width, height = win_dimensions(vim.api.nvim_buf_get_lines(editor.buffer, 0, -1, false), editor.configuraton.border);
+---+${lua, v24 commands}
+vim.api.nvim_create_user_command("CodeCreate", function ()
+ require("markview.health").notify("deprecation" , {
+ ignore = true,
- vim.api.nvim_win_set_config(editor.window, {
- relative = "editor",
+ option = ":CodeCreate",
+ alter = ":Code create"
+ });
- row = row,
- col = col,
+ editor.actions.create();
+end, {});
- width = width,
- height = height,
- });
- end
-})
+vim.api.nvim_create_user_command("CodeEdit", function ()
+ require("markview.health").notify("deprecation" , {
+ ignore = true,
+
+ option = ":CodeEdit",
+ alter = ":Code edit"
+ });
+
+ editor.actions.edit();
+end, {});
+---_
+
+editor.setup = function (config)
+ editor.config = vim.tbl_deep_extend("force", editor.config, config or {});
+end
return editor;
diff --git a/lua/markview/extras/headings.lua b/lua/markview/extras/headings.lua
index 0943821..4fe19e8 100644
--- a/lua/markview/extras/headings.lua
+++ b/lua/markview/extras/headings.lua
@@ -1,4 +1,5 @@
local headings = {};
+local utils = require("markview.utils");
--- Gets the heading under the cursor
---@return boolean
@@ -131,18 +132,74 @@ headings.decrease = function ()
end
end
-headings.setup = function ()
- vim.api.nvim_create_user_command("HeadingIncrease", function ()
- headings.increase();
- end, {
- desc = "Increases heading level"
+--- Commands for this module.
+headings.__completion = utils.create_user_command_class({
+ default = {
+ completion = function (arg_lead)
+ local comp = {};
+
+ for _, item in ipairs({ "decrease", "increase" }) do
+ if item:match(arg_lead) then
+ table.insert(comp, item);
+ end
+ end
+
+ table.sort(comp);
+ return comp;
+ end,
+ action = function ()
+ headings.increase();
+ end
+ },
+ sub_commands = {
+ ["decrease"] = {
+ action = function ()
+ headings.decrease();
+ end
+ },
+ ["increase"] = {
+ action = function ()
+ headings.increase();
+ end
+ }
+ }
+});
+
+--- New command
+vim.api.nvim_create_user_command("Heading", function (params)
+ headings.__completion:exec(params)
+end, {
+ nargs = 1,
+ complete = function (...)
+ return headings.__completion:comp(...)
+ end
+});
+
+---+${lua, v24 commands}
+vim.api.nvim_create_user_command("HeadingIncrease", function ()
+ require("markview.health").notify("deprecation", {
+ ignore = true,
+
+ option = ":HeadingIncrease",
+ alter = ":Heading increase"
});
- vim.api.nvim_create_user_command("HeadingDecrease", function ()
- headings.decrease()
- end, {
- desc = "Decreases heading level"
+ headings.increase();
+end, {});
+
+vim.api.nvim_create_user_command("HeadingDecrease", function ()
+ require("markview.health").notify("deprecation", {
+ ignore = true,
+
+ option = ":HeadingDecrease",
+ alter = ":Heading decrease"
});
+
+ headings.decrease()
+end, {});
+---_
+
+headings.setup = function ()
end
return headings;
diff --git a/lua/markview/filetypes.lua b/lua/markview/filetypes.lua
new file mode 100644
index 0000000..cf3b4db
--- /dev/null
+++ b/lua/markview/filetypes.lua
@@ -0,0 +1,766 @@
+local fts = {};
+
+fts.styles = {
+ ---+${class}
+ ["default"] = { name = nil, sign = "๓ฐปบ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐปบ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["nosyntax"] = { name = "Unknown", sign = "๓ฐกฏ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐกฏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+
+ ["abaqus"] = { name = "Abaqus", sign = "๓ฑ ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["amiga"] = { name = "Amiga", sign = "๓ฐน ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐน ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["asm"] = { name = "Assembly", sign = "๎ซ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["aspperl"] = { name = "ASP+Perl", sign = "๎ฉ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฉ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["aspvbs"] = { name = "ASP+VBScript", sign = "๎ฃ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฃ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["awk"] = { name = "AWK", sign = "๎ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["baan"] = { name = "BaaN", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["bash"] = { name = "Bash", sign = "๎ฏ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ฏ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["basic"] = { name = "BASIC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["bat"] = { name = "Bat", sign = "๓ฐญ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐญ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["bc"] = { name = "Basic Calculator", sign = "๓ฐช ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐช ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["bindzone"] = { name = "BIND Zone", sign = "๓ฐฒ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฒ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["bitbake"] = { name = "BitBake", sign = "๏ ", sign_hl = "MarkviewPalette0Sign", icon = "๏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["c"] = { name = "C", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["cfengine"] = { name = "CFEngine", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["cfg"] = { name = "Configuration", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ch"] = { name = "Change", sign = "๎ญ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ญ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["change"] = { name = "Change", sign = "๎ญ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ญ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["changelog"] = { name = "Changelog", sign = "๏ญ ", sign_hl = "MarkviewPalette3Sign", icon = "๏ญ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["chill"] = { name = "CHILL", sign = "๓ฐผช ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐผช ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cl"] = { name = "OpenCL", sign = "๎ก ", sign_hl = "MarkviewPalette0Sign", icon = "๎ก ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["clipper"] = { name = "Clipper", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["clojure"] = { name = "Clojure", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["conf"] = { name = "Configuration", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["context"] = { name = "Context", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["coq"] = { name = "Coq", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cpp"] = { name = "C++", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["crystal"] = { name = "Crystal", sign = "๎ฏ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["csh"] = { name = "C Shell", sign = "๎ฏ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ฏ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["cvs"] = { name = "CVS commit", sign = "๏ญ ", sign_hl = "MarkviewPalette3Sign", icon = "๏ญ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["cweb"] = { name = "CWEB", sign = "๓ฐ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["cynlib"] = { name = "CynLib", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["d"] = { name = "D", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dart"] = { name = "Dart", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["debchangelog"] = { name = "DebChangelog", sign = "๏ ", sign_hl = "MarkviewPalette1Sign", icon = "๏ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["debcontrol"] = { name = "DebControl", sign = "๏ ", sign_hl = "MarkviewPalette1Sign", icon = "๏ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["debcopyright"] = { name = "DebCopyright", sign = "๏ ", sign_hl = "MarkviewPalette1Sign", icon = "๏ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["def"] = { name = "Module-definition", sign = "๓ฐฒ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฒ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["diff"] = { name = "Diff", sign = "๎ซก ", sign_hl = "MarkviewPalette2Sign", icon = "๎ซก ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["diva"] = { name = "Diva", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dtd"] = { name = "Type Definition", sign = "๓ฑช ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฑช ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["dtrace"] = { name = "DTrace", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["edif"] = { name = "EDIF", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["eiffel"] = { name = "Eiffel", sign = "๓ฑซ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฑซ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["elixir"] = { name = "Elixir", sign = "๎ญ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ญ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["erlang"] = { name = "Erlang", sign = "๎ฑ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฑ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["euphoria3"] = { name = "Euphoria3", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["execline"] = { name = "Execline", sign = "๏ ", sign_hl = "MarkviewPalette2Sign", icon = "๏ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["expect"] = { name = "Expect", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["faust"] = { name = "Faust", sign = "๏ญ ", sign_hl = "MarkviewPalette0Sign", icon = "๏ญ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["fdcc"] = { name = "FDCC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["fennel"] = { name = "Fennel", sign = "๎ฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["fish"] = { name = "FISH", sign = "๓ฐปณ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐปณ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["foam"] = { name = "FoamFile", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["form"] = { name = "Form", sign = "๓ฐ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["forth"] = { name = "Forth", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["fortran"] = { name = "Fortran", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["freebasic"] = { name = "Free BASIC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["fsharp"] = { name = "F#", sign = "๎ง ", sign_hl = "MarkviewPalette5Sign", icon = "๎ง ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["fvwm"] = { name = "FVWM", sign = "๓ฑฃ ", sign_hl = "MarkviewPalette1Sign", icon = "๓ฑฃ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["fvwm2m4"] = { name = "FVWM", sign = "๓ฑฃ ", sign_hl = "MarkviewPalette1Sign", icon = "๓ฑฃ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["git"] = { name = "Git", sign = "๎ ", sign_hl = "MarkviewPalette2Sign", icon = "๎ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["gitsendemail"] = { name = "Git-send-mail", sign = "๓ฐบป ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฐบป ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["gnuplot"] = { name = "GNUPlot", sign = "๓ฐญ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐญ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["go"] = { name = "Golang", sign = "๎ง ", sign_hl = "MarkviewPalette5Sign", icon = "๎ง ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["godoc"] = { name = "Godoc", sign = "๓ฐ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["gomod"] = { name = "Gomod", sign = "๓ฐ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["gprof"] = { name = "Gprof", sign = "๓ฐ
", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ
", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["groovy"] = { name = "Groovy", sign = "๎ต ", sign_hl = "MarkviewPalette0Sign", icon = "๎ต ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["hare"] = { name = "Hare", sign = "๓ฐค ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐค ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["haredoc"] = { name = "HareDoc", sign = "๓ฐค ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐค ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+
+ ["8th"] = { name = "8th", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["a2ps"] = { name = "A2SP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["a65"] = { name = "A65", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["aap"] = { name = "AAP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["abap"] = { name = "ABAP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["abc"] = { name = "ABC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["abel"] = { name = "ABEL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["acedb"] = { name = "ACEDB", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ada"] = { name = "Ada", sign = "๎ต ", sign_hl = "MarkviewPalette1Sign", icon = "๎ต ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["aflex"] = { name = "AFleX", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["ahdl"] = { name = "AHDL", sign = "๓ฐพฒ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐพฒ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["aidl"] = { name = "AIDL", sign = "๓ฐฒ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐฒ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["alsaconf"] = { name = "AlsaConf", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["aml"] = { name = "AML", sign = "๓ฐญ ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฐญ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["ampl"] = { name = "AMPL", sign = "๓ฐช ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐช ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ant"] = { name = "ANT", sign = "๎ถบ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ถบ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["antlr"] = { name = "ANTLR", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["apache"] = { name = "Apache", sign = "๎ซ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["apachestyle"] = { name = "ApacheStyle", sign = "๎ซ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["aptconf"] = { name = "AptConf", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["arch"] = { name = "Arch", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["arduino"] = { name = "Arduino", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["art"] = { name = "ART", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["asciidoc"] = { name = "AsciiDoc", sign = "๓ฑช ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฑช ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["asm68k"] = { name = "Assembly", sign = "๎ซ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["asmh8300"] = { name = "Assembly", sign = "๎ซ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["asn"] = { name = "ASN", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["asterisk"] = { name = "Asterisk", sign = "๓ฑ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["asteriskvm"] = { name = "AsteriskVM", sign = "๓ฑ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["astro"] = { name = "Astro", sign = "๎ณ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ณ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["atlas"] = { name = "ATLAS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["autodoc"] = { name = "AutoDoc", sign = "๓ฑช ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฑช ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["autohotkey"] = { name = "AutoHotKey", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["autoit"] = { name = "AutoIt", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["automake"] = { name = "AutoMake", sign = "๎น ", sign_hl = "MarkviewPalette4Sign", icon = "๎น ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["ave"] = { name = "AVE", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["avra"] = { name = "AVRA", sign = "๎ซ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["ayacc"] = { name = "AYACC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["b"] = { name = "B", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["bdf"] = { name = "BDF", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["bib"] = { name = "BiBTeX", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["blank"] = { name = "Blank", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["bp"] = { name = "BP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["bsdl"] = { name = "BSDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["bst"] = { name = "BST", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["btm"] = { name = "BTM", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["bzl"] = { name = "BZL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["bzr"] = { name = "BZR", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cabal"] = { name = "Cabal", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["cabalconfig"] = { name = "CabalConfig", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["cabalproject"] = { name = "CabalProject", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["calendar"] = { name = "Calendar", sign = "๓ฐญ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐญ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["calender"] = { name = "Calendar", sign = "๓ฐญ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐญ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["catalog"] = { name = "Catalog", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cdl"] = { name = "CDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cdrdaoconf"] = { name = "CdrdaoAConf", sign = "๓ฐฅ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฅ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["cdrtoc"] = { name = "CdrdaoToc", sign = "๓ฐฅ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฅ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["cf"] = { name = "ColdFusion", sign = "๎
", sign_hl = "MarkviewPalette3Sign", icon = "๎
", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["cgdbrc"] = { name = "CGDBRC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["chaiscript"] = { name = "ChaiScript", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["chaskell"] = { name = "CHaskell", sign = "๎ท ", sign_hl = "MarkviewPalette5Sign", icon = "๎ท ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["chatito"] = { name = "Chatito", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["checkhealth"] = { name = "CheckHealth", sign = "๏ ", sign_hl = "MarkviewPalette1Sign", icon = "๏ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["cheetah"] = { name = "cheetah", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["chicken"] = { name = "Chicken", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["chordpro"] = { name = "ChordPro", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["chuck"] = { name = "Chuck", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["clean"] = { name = "Clean", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["cmake"] = { name = "CMake", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["cmakecache"] = { name = "CMakeCache", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cmod"] = { name = "CMod", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cmusrc"] = { name = "Cmusrc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cobol"] = { name = "Cobol", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["coco"] = { name = "Coco", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["colortest"] = { name = "ColorTest", sign = "๎ซ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["conaryrecipe"] = { name = "Conaryrecipe", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["config"] = { name = "Configuration", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["confini"] = { name = "Confini", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["corn"] = { name = "Corn", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["crm"] = { name = "CRM", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["crontab"] = { name = "CronTab", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cs"] = { name = "CS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["csc"] = { name = "CSC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["csdl"] = { name = "CSDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["csp"] = { name = "CSP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["css"] = { name = "CSS", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["cterm"] = { name = "CTERM", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ctrlh"] = { name = "CTRLH", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cucumber"] = { name = "Cucumber", sign = "๎ท ", sign_hl = "MarkviewPalette4Sign", icon = "๎ท ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["cuda"] = { name = "CUDA", sign = "๓ฐ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["cupl"] = { name = "CUPL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cuplsim"] = { name = "CUPL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cvsrc"] = { name = "CVS Rc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["cynpp"] = { name = "Cyn++", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["datascript"] = { name = "DataScript", sign = "๓ฑผ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฑผ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dcl"] = { name = "DCL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dictconf"] = { name = "Dict Config", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dictdconf"] = { name = "Dictd Config", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dircolors"] = { name = "Dir Colors", sign = "๎ซ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["dirpager"] = { name = "Directory", sign = "๎พ ", sign_hl = "MarkviewPalette5Sign", icon = "๎พ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["django"] = { name = "Django", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["dns"] = { name = "DNS/BIND Zone", sign = "๎ผ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ผ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dnsmasq"] = { name = "Dnsmasq Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["docbk"] = { name = "DocBook", sign = "๓ฐ ฎ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐ ฎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["docbksgml"] = { name = "DocBook SGML", sign = "๓ฐ ฎ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐ ฎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["docbkxml"] = { name = "DocBook XML", sign = "๓ฐ ฎ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐ ฎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["dockerfile"] = { name = "Dockerfile", sign = "๓ฐกจ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐกจ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["dosbatch"] = { name = "DOS Batch", sign = "๓ฐ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["dosini"] = { name = "DOS Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["dot"] = { name = "Dot", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["doxygen"] = { name = "Doxygen", sign = "๓ฐ ฎ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ฎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dracula"] = { name = "Dracula", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dsl"] = { name = "DSSSL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dtml"] = { name = "DTD", sign = "๓ฐ ฎ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ฎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dts"] = { name = "DTS/DTSI", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dune"] = { name = "Dune", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dylan"] = { name = "Dylan", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dylanintr"] = { name = "Dylan", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["dylanlid"] = { name = "Dylan", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ecd"] = { name = "ECD", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["editorconfig"] = { name = "EditorConfig", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["elf"] = { name = "ELF", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["elinks"] = { name = "ELinks", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["elm"] = { name = "Elm", sign = "๎ฌ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ฌ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["elmfilt"] = { name = "Elm Filter rules", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["eruby"] = { name = "eRuby", sign = "๎
", sign_hl = "MarkviewPalette1Sign", icon = "๎
", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["esmtprc"] = { name = "Esmtprc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["esqlc"] = { name = "ESQL-C", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["esterel"] = { name = "ESTEREL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["eterm"] = { name = "ETerm", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["euphoria4"] = { name = "Euphoria 4", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["eviews"] = { name = "Eviews", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["exim"] = { name = "Exim", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["exports"] = { name = "Exports", sign = "๓ฐ ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["falcon"] = { name = "Falcon", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["fan"] = { name = "Fantom", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["fasm"] = { name = "FASM", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["fgl"] = { name = "Informix 4GL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["flexwiki"] = { name = "FlexWiki", sign = "๓ฐ ฎ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ฎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["foxpro"] = { name = "FoxPro", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["framescript"] = { name = "FrameScript 4.0", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["fstab"] = { name = "Fstab", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gdb"] = { name = "GDB", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gdmo"] = { name = "GDMO", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gdresource"] = { name = "Gdresource", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gdscript"] = { name = "GDScript", sign = "๎ฎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ฎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["gdshader"] = { name = "GDShader", sign = "๎ฎ ", sign_hl = "MarkviewPalette2Sign", icon = "๎ฎ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["gedcom"] = { name = "Gedcom", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gemtext"] = { name = "Gemtext", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gift"] = { name = "Moodle GIFT", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gitattributes"] = { name = "Git attributes", sign = "๓ฐข ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฐข ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["gitcommit"] = { name = "Git commit", sign = "๎ฉ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฉ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["gitconfig"] = { name = "Git Config", sign = "๎ ", sign_hl = "MarkviewPalette2Sign", icon = "๎ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["gitignore"] = { name = "gitignore", sign = "๏ ", sign_hl = "MarkviewPalette0Sign", icon = "๏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["gitolite"] = { name = "Gitolite Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["gitrebase"] = { name = "Git rebase", sign = "๎ง ", sign_hl = "MarkviewPalette3Sign", icon = "๎ง ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["gkrellmrc"] = { name = "Gkrell theme", sign = "๓ฐ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["glsl"] = { name = "OpenGl Shader", sign = "๎ก ", sign_hl = "MarkviewPalette1Sign", icon = "๎ก ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["gnash"] = { name = "Gnash Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["gp"] = { name = "GP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gpg"] = { name = "GPG Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["grads"] = { name = "GrADS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["gretl"] = { name = "Gretl", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["groff"] = { name = "Groof", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["group"] = { name = "Group", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["grub"] = { name = "Grub Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["gsp"] = { name = "GSP", sign = "๓ฐ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["gtkrc"] = { name = "Gtk theme", sign = "๏ข ", sign_hl = "MarkviewPalette0Sign", icon = "๏ข ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["gvpr"] = { name = "Graphviz", sign = "๓ฑ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["gyp"] = { name = "GYP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["haml"] = { name = "Haml", sign = "๎ค ", sign_hl = "MarkviewPalette3Sign", icon = "๎ค ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["hamster"] = { name = "Hamster", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["haskell"] = { name = "Haskell", sign = "๎ท ", sign_hl = "MarkviewPalette6Sign", icon = "๎ท ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["haste"] = { name = "HASTE", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["hastepreproc"] = { name = "HASTE Preporcessor" ,sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["hb"] = { name = "Hyper Builder", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["help"] = { name = "VimDoc", sign = "๎
", sign_hl = "MarkviewPalette4Sign", icon = "๎
", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["help_it"] = { name = "VimDoc(Italian)", sign = "๎
", sign_hl = "MarkviewPalette2Sign", icon = "๎
", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["help_ru"] = { name = "VimDoc(Russian)", sign = "๎
", sign_hl = "MarkviewPalette1Sign", icon = "๎
", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["hercules"] = { name = "Hercules", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["hex"] = { name = "Intel Hex", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["hgcommit"] = { name = "Hg/Sl Commit", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["hlsplaylist"] = { name = "HLS Playlist", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["hog"] = { name = "Hog", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["hollywood"] = { name = "Hollywood", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["hostconf"] = { name = "Host.conf Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["hostsaccess"] = { name = "Host.? Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["html"] = { name = "HTML", sign = "๎ถ ", sign_hl = "MarkviewPalette2Sign", icon = "๎ถ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["htmlangular"] = { name = "Angular", sign = "๓ฐฒ ", sign_hl = "MarkviewPalette1Sign", icon = "๓ฐฒ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["htmlcheetah"] = { name = "Cheetah", sign = "๓ฐ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["htmldjango"] = { name = "Django", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["htmlm4"] = { name = "HTML", sign = "๎ถ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ถ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["htmlos"] = { name = "HTML", sign = "๎ถ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ถ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["hyprlang"] = { name = "Hyprland Config", sign = "๏ ", sign_hl = "MarkviewPalette4Sign", icon = "๏ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["hurl"] = { name = "Hurl", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["i3config"] = { name = "i3 Config", sign = "๏ ", sign_hl = "MarkviewPalette4Sign", icon = "๏ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["ia64"] = { name = "IA-64", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ibasic"] = { name = "IBasic", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["icemenu"] = { name = "IceWM Config", sign = "๎ฆ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฆ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["icon"] = { name = "Icon", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["idl"] = { name = "IDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["idlang"] = { name = "IDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["idris2"] = { name = "Idris2", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["indent"] = { name = "Indent Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["inform"] = { name = "Inform", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["initex"] = { name = "TeX", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["initng"] = { name = "Initng", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["inittab"] = { name = "Inittab", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ipfilter"] = { name = "IPFilter Config", sign = "๓ฐฒ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฒ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["ipkg"] = { name = "Ipkg", sign = "๓ฐ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["ishd"] = { name = "InstallShield Script", sign = "๎ผ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ผ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ist"] = { name = "MakeIndex Style", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["j"] = { name = "J", sign = "๓ฐซท ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐซท ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["jal"] = { name = "JAL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["jam"] = { name = "JAM", sign = "๓ฐซท ", sign_hl = "MarkviewPalette1Sign", icon = "๓ฐซท ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["jargon"] = { name = "Jargon", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["java"] = { name = "Java", sign = "๎ธ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ธ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["javacc"] = { name = "JavaCC", sign = "๓ฐนฉ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐนฉ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["javascript"] = { name = "Javascript", sign = "๏ฏ ", sign_hl = "MarkviewPalette3Sign", icon = "๏ฏ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["javascriptreact"] = { name = "React", sign = "๓ฐ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["jess"] = { name = "Jess", sign = "๓ฐช ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐช ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["jgraph"] = { name = "JGraph", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["jj"] = { name = "JJ", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["jovial"] = { name = "Jovial J73", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["jproperties"] = { name = "Java Properties", sign = "๎ธ ", sign_hl = "MarkviewPalette2Sign", icon = "๎ธ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["jq"] = { name = "JQ", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["json"] = { name = "JSON", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["json5"] = { name = "JSON", sign = "๓ฐฆ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐฆ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["jsonc"] = { name = "JSON", sign = "๓ฐฆ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฆ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["jsonnet"] = { name = "Jsonnet", sign = "๏ณ ", sign_hl = "MarkviewPalette0Sign", icon = "๏ณ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["jsp"] = { name = "JSP", sign = "๎ธ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ธ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["julia"] = { name = "JAL", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["karel"] = { name = "KAREL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["kconfig"] = { name = "Kconfig", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["kdl"] = { name = "KDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["kivy"] = { name = "Kivy", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["kix"] = { name = "KixTart", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["kotlin"] = { name = "Kotlin", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["krl"] = { name = "Kuka Robot Language", sign = "๓ฐฉ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฉ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["kscript"] = { name = "Kscript", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["kwt"] = { name = "Kimwitu++", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lace"] = { name = "Lace", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["latte"] = { name = "Latte", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["latex"] = { name = "LaTeX", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lc"] = { name = "Elsa", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ld"] = { name = "Ld Script", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ldapconf"] = { name = "Ldap Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["ldif"] = { name = "LDAP LDIF", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["less"] = { name = "Less", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["lex"] = { name = "Lex", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lf"] = { name = "Lf Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["lftp"] = { name = "Lftp Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["lhaskell"] = { name = "LHaskell", sign = "๎ท ", sign_hl = "MarkviewPalette3Sign", icon = "๎ท ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["libao"] = { name = "Libao Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["lidris2"] = { name = "Idris2", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lifelines"] = { name = "LifeLines", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lilo"] = { name = "Lilo Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["limits"] = { name = "Limits Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["liquid"] = { name = "Liquid", sign = "๎ฐ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ฐ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["lisp"] = { name = "Lisp", sign = "๎ฐ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฐ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["lite"] = { name = "Lite", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["litestep"] = { name = "LiteStep RC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["livebook"] = { name = "LiveBook", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["logcheck"] = { name = "Logcheck", sign = "๏ญ ", sign_hl = "MarkviewPalette3Sign", icon = "๏ญ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["loginaccess"] = { name = "Login.access Config", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["logindefs"] = { name = "Login.defs Config", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["logtalk"] = { name = "Logtalk", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lotos"] = { name = "LOTOS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lout"] = { name = "Lout", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lpc"] = { name = "LPC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lprolog"] = { name = "LambdaProlog", sign = "๎ก ", sign_hl = "MarkviewPalette1Sign", icon = "๎ก ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["lscript"] = { name = "LotusScript", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lsl"] = { name = "Linden Script", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lsp_markdown"] = { name = "LSP Message", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["lss"] = { name = "Lynx Style", sign = "๎ซ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["lua"] = { name = "Lua", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["luau"] = { name = "Luau", sign = "๓ฑจ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฑจ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["lynx"] = { name = "Lynx Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["lyrics"] = { name = "LyRiCs", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["m3build"] = { name = "Modula-3 Makefile", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["m3quake"] = { name = "Modula-3 Quake", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["m4"] = { name = "M4", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mail"] = { name = "Mail", sign = "๓ฐบป ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐบป ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["mailaliases"] = { name = "Alias database", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mailcap"] = { name = "Mailcap Config", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["make"] = { name = "Makefile", sign = "๎ณ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ณ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["mallard"] = { name = "Mallard", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["man"] = { name = "Man", sign = "๓ฐ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["manconf"] = { name = "Man Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["maple"] = { name = "Maple V", sign = "๓ฐฒ ", sign_hl = "MarkviewPalette1Sign", icon = "๓ฐฒ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["markdown"] = { name = "Markdown", sign = "๏ ", sign_hl = "MarkviewPalette0Sign", icon = "๏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["masm"] = { name = "MS Macro assembler", sign = "๎ซ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ซ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mason"] = { name = "HTML+Perl", sign = "๎ฉ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฉ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["master"] = { name = "Focus Master", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["matlab"] = { name = "MatLab", sign = "๎ ช ", sign_hl = "MarkviewPalette2Sign", icon = "๎ ช ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["maxima"] = { name = "Maxima", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mediawiki"] = { name = "MediaWiki", sign = "๓ฐฌ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฌ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mel"] = { name = "MEL", sign = "๎ ญ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ญ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["mermaid"] = { name = "Mermaid", sign = "๏ท ", sign_hl = "MarkviewPalette5Sign", icon = "๏ท ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["meson"] = { name = "Meson", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mf"] = { name = "METAFONT", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mgl"] = { name = "MGL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mgp"] = { name = "MaGic Point", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mib"] = { name = "SMI", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mix"] = { name = "MIX", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mma"] = { name = "Mathmetica", sign = "๓ฐฟ ", sign_hl = "MarkviewPalette1Sign", icon = "๓ฐฟ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["mmix"] = { name = "MMIX", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mmp"] = { name = "MMP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["modconf"] = { name = "modules.conf Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["model"] = { name = "Model", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["modsim3"] = { name = "Modsim โ
ข", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["modula2"] = { name = "Modula-2", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["modula3"] = { name = "Modula-3", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mojo"] = { name = "Mojo", sign = "๏ญ ", sign_hl = "MarkviewPalette1Sign", icon = "๏ญ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["monk"] = { name = "Monk", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["moo"] = { name = "MOO", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mp"] = { name = "MetaPost", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mplayerconf"] = { name = "Mplayer Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["mrxvtrc"] = { name = "mrxvtrc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["msidl"] = { name = "MS IDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["msmessages"] = { name = "MS Message", sign = "๓ฐก ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐก ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["msql"] = { name = "MSQL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mupad"] = { name = "MuPAD", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["murphi"] = { name = "Murphi", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mush"] = { name = "MUSHcode", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["muttrc"] = { name = "Mutt", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["mysql"] = { name = "MySQL", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["n1ql"] = { name = "N1QL", sign = "๎ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["named"] = { name = "BIND Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["nanorc"] = { name = "Nano Config", sign = "๎ ธ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ธ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["nasm"] = { name = "NASM", sign = "๎ท ", sign_hl = "MarkviewPalette6Sign", icon = "๎ท ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["nastran"] = { name = "NASTRAN Input", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["natural"] = { name = "NATURAL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ncf"] = { name = "Novell 'NCF' Batch", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["neomuttrc"] = { name = "NeoMutt", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["netrc"] = { name = "Netrc Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["nginx"] = { name = "nginx.conf Config", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["ninja"] = { name = "Ninja", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["nix"] = { name = "Nix", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["nqc"] = { name = "NQC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["nroff"] = { name = "Nroof/Groof", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["nsis"] = { name = "NSIS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["obj"] = { name = "3D wavefront obj", sign = "๏ฒ ", sign_hl = "MarkviewPalette2Sign", icon = "๏ฒ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["objc"] = { name = "Objective-C", sign = "๎ก ", sign_hl = "MarkviewPalette0Sign", icon = "๎ก ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["objcpp"] = { name = "Objective C++", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["obse"] = { name = "Oblivion Language", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ocaml"] = { name = "Ocaml", sign = "๎ก ", sign_hl = "MarkviewPalette2Sign", icon = "๎ก ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["occam"] = { name = "Occam", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["odin"] = { name = "Odin", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["omnimark"] = { name = "Omnimark", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ondir"] = { name = "Ondir", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["opam"] = { name = "OPAM", sign = "๓ฐ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["openroad"] = { name = "CA-OpenROAD", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["openscad"] = { name = "OpenSCAD", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["openvpn"] = { name = "OpenVPN", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["opl"] = { name = "OPL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ora"] = { name = "Oracle Config", sign = "๎ก ", sign_hl = "MarkviewPalette1Sign", icon = "๎ก ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["pacmanlog"] = { name = "pacman.log", sign = "๎ฒ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ฒ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["pamconf"] = { name = "Pam Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["pamenv"] = { name = "pam_env.conf Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["pandoc"] = { name = "Pandoc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["papp"] = { name = "Papp", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pascal"] = { name = "Pascal", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["passwd"] = { name = "Passwd", sign = "๓ฐ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["pbtxt"] = { name = "Protobuf", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pcap"] = { name = "Printcap", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pccts"] = { name = "PCCTS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pdf"] = { name = "PDF", sign = "๎ฝ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ฝ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["perl"] = { name = "Perl", sign = "๎ฉ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ฉ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pf"] = { name = "Packet filter Config", sign = "๏จ ", sign_hl = "MarkviewPalette3Sign", icon = "๏จ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["pfmain"] = { name = "Postfix Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["php"] = { name = "PHP", sign = "๓ฐ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["phtml"] = { name = "PHTML", sign = "๓ฐ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pic"] = { name = "PIC16F84 Assembler", sign = "๎ท ", sign_hl = "MarkviewPalette6Sign", icon = "๎ท ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pike"] = { name = "Pilrc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pilrc"] = { name = "FoamFile", sign = "๓ฑ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pine"] = { name = "Pine", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pinfo"] = { name = "Pinfo Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["plaintex"] = { name = "TeX", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["plm"] = { name = "PL/M", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["plp"] = { name = "PLP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["plsql"] = { name = "PL/SQL", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["po"] = { name = "Po", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pod"] = { name = "Perl POD", sign = "๎ฉ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ฉ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["poefilter"] = { name = "PoE item filter", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["poke"] = { name = "Poke", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["postscr"] = { name = "PostScript", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pov"] = { name = "PoV-Ray", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["povini"] = { name = "PoV-Ray", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ppd"] = { name = "PPD", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ppwiz"] = { name = "PPWizard", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["prescribe"] = { name = "Kyocera PreScribe2e", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["privoxy"] = { name = "Privoxy", sign = "๏
", sign_hl = "MarkviewPalette4Sign", icon = "๏
", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["procmail"] = { name = "Procmail", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["progress"] = { name = "Progress 4GL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["prolog"] = { name = "Prolog", sign = "๎ก ", sign_hl = "MarkviewPalette1Sign", icon = "๎ก ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["promela"] = { name = "ProMeLa", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["proto"] = { name = "Protocol", sign = "๓ฐฟ ", sign_hl = "MarkviewPalette0Sign", icon = "๓ฐฟ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["protocols"] = { name = "Protocols", sign = "๓ฐขฉ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฐขฉ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["ps1"] = { name = "PowerShell", sign = "๎กฌ ", sign_hl = "MarkviewPalette4Sign", icon = "๎กฌ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["ps1xml"] = { name = "PowerShell XML", sign = "๓ฐ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["psf"] = { name = "Product Spec", sign = "๏ ", sign_hl = "MarkviewPalette0Sign", icon = "๏ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["psl"] = { name = "Property Spec", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ptcap"] = { name = "Printcap/Termcap DB", sign = "๎ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["purifylog"] = { name = "Purify Log", sign = "๏ญ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ญ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pymanifest"] = { name = "PyPA manifest", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["pyrex"] = { name = "Pyrex", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["python"] = { name = "Python", sign = "๎ผ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ผ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["python2"] = { name = "Python 2", sign = "๎ผ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ผ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["qb64"] = { name = "QB64", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["qml"] = { name = "QML", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["quake"] = { name = "Quake", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["quarto"] = { name = "Quarto", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["query"] = { name = "Query", sign = "๓ฑ ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["r"] = { name = "R", sign = "๎ข ", sign_hl = "MarkviewPalette1Sign", icon = "๎ข ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["racc"] = { name = "Racc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["racket"] = { name = "Racket", sign = "๓ฐง ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐง ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["radiance"] = { name = "Radiance Scene", sign = "๏ฒ ", sign_hl = "MarkviewPalette2Sign", icon = "๏ฒ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["raku"] = { name = "Raku", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["raml"] = { name = "RAML", sign = "๓ฑ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rapid"] = { name = "ABB Rapid", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ratpoison"] = { name = "Ratpoison Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["rcs"] = { name = "RCS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rcslog"] = { name = "RCS log", sign = "๏ญ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ญ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["readline"] = { name = "Readline Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["rebol"] = { name = "Rebol", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["redif"] = { name = "ReDIF", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["registry"] = { name = "Windows Reg. export", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rego"] = { name = "Rego", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["remind"] = { name = "Remind", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["resolv"] = { name = "Resolver Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["reva"] = { name = "Reva Forth", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rexx"] = { name = "Rexx", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rhelp"] = { name = "R Help", sign = "๎ข ", sign_hl = "MarkviewPalette2Sign", icon = "๎ข ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["rib"] = { name = "RI Bytestream", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rmd"] = { name = "RMarkdown", sign = "๎ข ", sign_hl = "MarkviewPalette6Sign", icon = "๎ข ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rnc"] = { name = "Relax NG compact", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rng"] = { name = "RELAX NG", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rnoweb"] = { name = "R noweb", sign = "๎ข ", sign_hl = "MarkviewPalette5Sign", icon = "๎ข ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["robots"] = { name = "Robots", sign = "๓ฑง ", sign_hl = "MarkviewPalette1Sign", icon = "๓ฑง ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["routeros"] = { name = "RouterOS Script", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rpcgen"] = { name = "RPCGen", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rpl"] = { name = "RPL/2", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rrst"] = { name = "reST with R", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette1Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["rst"] = { name = "reST", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["rtf"] = { name = "Rich Text Format", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ruby"] = { name = "Ruby", sign = "๎
", sign_hl = "MarkviewPalette1Sign", icon = "๎
", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["rust"] = { name = "Rust", sign = "๓ฑ ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["samba"] = { name = "Samba Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["sas"] = { name = "SAS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sass"] = { name = "Sass", sign = "๎ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["sather"] = { name = "Sather/pSather", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sbt"] = { name = "SBT", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["scala"] = { name = "Scala", sign = "๎ท ", sign_hl = "MarkviewPalette1Sign", icon = "๎ท ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["scdoc"] = { name = "SCDoc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["scheme"] = { name = "Scheme", sign = "๎ฑ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ฑ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["scilab"] = { name = "Scilab", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["screen"] = { name = "Screen Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["scss"] = { name = "Sass", sign = "๎ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["sd"] = { name = "Streaming Descriptor", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sdc"] = { name = "SDC", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sdl"] = { name = "SDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sed"] = { name = "Sed", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sendpr"] = { name = "FreeBSD send-pr", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sensors"] = { name = "Libsensors Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["services"] = { name = "Services Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["setserial"] = { name = "Setserial Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["sexplib"] = { name = "Sexplib", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sgml"] = { name = "SGML", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sgmldecl"] = { name = "SGML", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sgmllnx"] = { name = "SGML-linuxdoc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["sh"] = { name = "Shell", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["shada"] = { name = "Shada", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sicad"] = { name = "SiCAD", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sieve"] = { name = "Sieve", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sil"] = { name = "Sil", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["simula"] = { name = "Simula", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sinda"] = { name = "Sinda", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sindacmp"] = { name = "Sinda", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sindaout"] = { name = "Sinda", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sisu"] = { name = "SiSU", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["skill"] = { name = "SKILL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sl"] = { name = "Renderman shader", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["slang"] = { name = "S-Lang", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["slice"] = { name = "Slice", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["slpconf"] = { name = "Service loc. Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["slpreg"] = { name = "Service loc. Reg.", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["slpspi"] = { name = "Service loc. SPI", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["slrnrc"] = { name = "Slrn Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["slrnsc"] = { name = "Slrn Scores", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sm"] = { name = "Sendmail", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["smarty"] = { name = "Smarty Template", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["smcl"] = { name = "SMCL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["smil"] = { name = "SMIL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["smith"] = { name = "SMITH", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sml"] = { name = "SML", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["snnsnet"] = { name = "SNNS network", sign = "๓ฐณ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐณ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["snnspat"] = { name = "SNNS pattern", sign = "๓ฐช ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐช ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["snnsres"] = { name = "SNNS result", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["snobol4"] = { name = "SNOBOL4", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["solidity"] = { name = "Solidity", sign = "๎ขฆ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ขฆ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["spec"] = { name = "SPEC", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["specman"] = { name = "SPECMAN E-LANGUAGE", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["spice"] = { name = "Spice", sign = "๎ชพ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ชพ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["splint"] = { name = "Splint", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["spup"] = { name = "Speedup", sign = "๎ฏ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ฏ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["spyce"] = { name = "SPYCE", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sql"] = { name = "SQL", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["sqlanywhere"] = { name = "SQL", sign = "๎ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["sqlforms"] = { name = "SQL", sign = "๓ฐ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sqlhana"] = { name = "SQL+Hana", sign = "๓ฐ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sqlinformix"] = { name = "SQL+Query", sign = "๓ฑ ", sign_hl = "MarkviewPalette4Sign", icon = "๓ฑ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["sqlj"] = { name = "Sqlj", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sqloracle"] = { name = "SQL+Oracle", sign = "๎ก ", sign_hl = "MarkviewPalette1Sign", icon = "๎ก ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["sqr"] = { name = "SQR", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["squid"] = { name = "Squid Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["squirrel"] = { name = "Squirrel", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["srec"] = { name = "Motorola S-Record", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["srt"] = { name = "SubRip", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["ssa"] = { name = "SubStation Alpha", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sshconfig"] = { name = "SSH Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["sshdconfig"] = { name = "SSHD Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["st"] = { name = "Smalltalk", sign = "๓ฐต
", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐต
", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["stata"] = { name = "Stata", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["stp"] = { name = "Stored Procedures", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["strace"] = { name = "Strace", sign = "๏ญ ", sign_hl = "MarkviewPalette3Sign", icon = "๏ญ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["structurizr"] = { name = "Structurizr DSL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["stylus"] = { name = "Stylus", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["sudoers"] = { name = "Sudoers Config", sign = "๎ท
", sign_hl = "MarkviewPalette3Sign", icon = "๎ท
", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["supercollider"] = { name = "SuperCollider", sign = "๓ฐง ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐง ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["svg"] = { name = "SVG", sign = "๓ฐก ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐก ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["svn"] = { name = "Subversion commit", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["swayconfig"] = { name = "Sway Config", sign = "๏ ", sign_hl = "MarkviewPalette3Sign", icon = "๏ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["swift"] = { name = "Swift", sign = "๎ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["swiftgyb"] = { name = "GUB on swift", sign = "๎ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["swig"] = { name = "SWIG", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["sysctl"] = { name = "sysctl.conf Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["systemd"] = { name = "systemd.unit", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["systemverilog"] = { name = "SystemVerilog", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tads"] = { name = "TADS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tak"] = { name = "TAK thermal modeling", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["takcmp"] = { name = "TAK model compare", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["takout"] = { name = "TAK model output", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tap"] = { name = "Verbose TAP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tar"] = { name = "Tar Listing", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["taskdata"] = { name = "Tsak data", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["taskedit"] = { name = "Tsak edit", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tasm"] = { name = "TASM", sign = "๎ท ", sign_hl = "MarkviewPalette6Sign", icon = "๎ท ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tcl"] = { name = "Tcl/Tk", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tcsh"] = { name = "Tcsh scripts", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["template"] = { name = "Template", sign = "๏ ", sign_hl = "MarkviewPalette6Sign", icon = "๏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["teraterm"] = { name = "Tera Term", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["terminfo"] = { name = "Terminfo", sign = "๎ฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๎ฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tex"] = { name = "TeX", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["texinfo"] = { name = "Texinfo", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["texmf"] = { name = "Web2C TeX", sign = "๎ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["text"] = { name = "Text", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tf"] = { name = "Tf", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tidy"] = { name = "HMTL Tidy Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["tilde"] = { name = "Tilde", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tli"] = { name = "TealInfo", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tmux"] = { name = "Tmux Config", sign = "๎ฏ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ฏ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["toml"] = { name = "TOML", sign = "๎ฒ ", sign_hl = "MarkviewPalette1Sign", icon = "๎ฒ ", icon_hl = "MarkviewIcon1", border_hl = "MarkviewPalette1Fg" },
+ ["tpp"] = { name = "TPP", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["trasys"] = { name = "TRASYS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["treetop"] = { name = "Treetop", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["trustees"] = { name = "Trustees", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tsalt"] = { name = "Telix SALT", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tsscl"] = { name = "TSS Command", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tssgm"] = { name = "TSS Geometry", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tssop"] = { name = "TSS Optics", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tt2"] = { name = "TT2", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["tt2html"] = { name = "HTML+TT2", sign = "๎ฉ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฉ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["tt2js"] = { name = "Javascript+TT2", sign = "๎ฉ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฉ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["ts"] = { name = "Typescript", sign = "๎ฃ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ฃ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["typescript"] = { name = "Typescript", sign = "๎ฃ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ฃ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["typescriptreact"] = { name = "React", sign = "๎บ ", sign_hl = "MarkviewPalette3Sign", icon = "๎บ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["typ"] = { name = "Typst", sign = "๎ชค ", sign_hl = "MarkviewPalette6Sign", icon = "๎ชค ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["uc"] = { name = "UnrealScript", sign = "๎ฃ ", sign_hl = "MarkviewPalette0Sign", icon = "๎ฃ ", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["uci"] = { name = "OpenWrt Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["udevconf"] = { name = "Udev Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["udevperm"] = { name = "Udev Permissions", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["udevrules"] = { name = "Udev rules", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["uil"] = { name = "Motif UIL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["unison"] = { name = "Unison", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["updatedb"] = { name = "updatedb.conf Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["upstart"] = { name = "Upstart job", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["vb"] = { name = "Visual Basic", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["vera"] = { name = "Vera", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["verilog"] = { name = "Verilog", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["verilogams"] = { name = "Verilog-AMS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["vgrindefs"] = { name = "Vgrindefs", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["vhdl"] = { name = "VHDL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["vim"] = { name = "Vim", sign = "๎
", sign_hl = "MarkviewPalette4Sign", icon = "๎
", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["viminfo"] = { name = "Viminfo", sign = "๎
", sign_hl = "MarkviewPalette0Sign", icon = "๎
", icon_hl = "MarkviewIcon0", border_hl = "MarkviewPalette0Fg" },
+ ["virata"] = { name = "Virata AConfig", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["vmasm"] = { name = "(VAX) Macro Assembly", sign = "๎ท ", sign_hl = "MarkviewPalette6Sign", icon = "๎ท ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["voscm"] = { name = "VOS CM macro", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["vrml"] = { name = "VRML97", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["vsejcl"] = { name = "JCL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["vue"] = { name = "Vue", sign = "๎ ", sign_hl = "MarkviewPalette4Sign", icon = "๎ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" },
+ ["wat"] = { name = "WebAssembly", sign = "๎ฃ ", sign_hl = "MarkviewPalette5Sign", icon = "๎ฃ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["wdiff"] = { name = "wDiff", sign = "๓ฐ ", sign_hl = "MarkviewPalette2Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon2", border_hl = "MarkviewPalette2Fg" },
+ ["wdl"] = { name = "wdl", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["web"] = { name = "WEB", sign = "๓ฐ ", sign_hl = "MarkviewPalette5Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon5", border_hl = "MarkviewPalette5Fg" },
+ ["webmacro"] = { name = "WebMacro", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["wget"] = { name = "Wget Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["wget2"] = { name = "Wget2 Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["wml"] = { name = "WML", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["wsml"] = { name = "WSML", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["wvdial"] = { name = "WvDial Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["xbl"] = { name = "XBL", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xcompose"] = { name = "XCompose", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xf86conf"] = { name = "XF86Config", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xhtml"] = { name = "XHTML", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xinetd"] = { name = "xinetd.conf Config", sign = "๎ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["xkb"] = { name = "XKB", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xmath"] = { name = "XMath", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xml"] = { name = "XML", sign = "๓ฐ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xmodmap"] = { name = "Xmodmap Definition", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xpm"] = { name = "X Pixmap", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xpm2"] = { name = "X Pixmap v2", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xquery"] = { name = "XQuery", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xs"] = { name = "XS", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xsd"] = { name = "XSD", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xslt"] = { name = "XSLT", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["xxd"] = { name = "XXD", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["yacc"] = { name = "Yacc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["yaml"] = { name = "YAML", sign = "๓ฐ
ฉ ", sign_hl = "MarkviewPalette3Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["z8a"] = { name = "asz80", sign = "๎ท ", sign_hl = "MarkviewPalette6Sign", icon = "๎ท ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["zathurarc"] = { name = "Zathurarc", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["zig"] = { name = "Zig", sign = "๎ฉ ", sign_hl = "MarkviewPalette3Sign", icon = "๎ฉ ", icon_hl = "MarkviewIcon3", border_hl = "MarkviewPalette3Fg" },
+ ["zimbu"] = { name = "Zimbu", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["zir"] = { name = "Zir", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["zserio"] = { name = "Zserio", sign = "๓ฐฏ ", sign_hl = "MarkviewPalette6Sign", icon = "๓ฐฏ ", icon_hl = "MarkviewIcon6", border_hl = "MarkviewPalette6Fg" },
+ ["zsh"] = { name = "Zsh", sign = "๏ ", sign_hl = "MarkviewPalette4Sign", icon = "๏ ", icon_hl = "MarkviewIcon4", border_hl = "MarkviewPalette4Fg" }
+ ---_
+};
+
+--- Gets Icons
+---@param ft string?
+---@return { name: string, sign: string, sign_hl: string, icon: string, icon_hl: string, border_hl: string }
+fts.get = function (ft)
+ local _ft = ft;
+
+ if vim.filetype.match({ filename = string.format("example.%s", _ft) }) then
+ _ft = vim.filetype.match({ filename = string.format("example.%s", _ft) });
+ end
+
+ local spec = require("markview.spec");
+ local provider_name = spec.get({ "preview", "icon_provider" }, { fallback = "internal" });
+ local conf = {};
+
+ if provider_name == "devicons" and pcall(require, "nvim-web-devicons") then
+ conf.icon, conf.icon_hl = require("nvim-web-devicons").get_icon(
+ string.format("example.%s", ft),
+ nil,
+ { default = true }
+ );
+
+ conf.icon = conf.icon .. " ";
+
+ conf.sign = conf.icon;
+ conf.sign_hl = conf.icon_hl;
+ conf.border_hl = conf.icon_hl;
+ elseif provider_name == "mini" and pcall(require, "mini.icons") then
+ conf.icon, conf.icon_hl = require("mini.icons").get(
+ "file",
+ string.format("example.%s", ft)
+ );
+
+ conf.icon = conf.icon .. " ";
+
+ conf.sign = conf.icon;
+ conf.sign_hl = conf.icon_hl;
+ conf.border_hl = conf.icon_hl;
+ else
+ conf = fts.styles[_ft] or fts.styles[ft] or fts.styles["default"];
+ end
+
+ local this_conf = fts.styles[_ft] or fts.styles[ft] or fts.styles.default;
+ conf.name = this_conf.name or ft or "Unknown";
+
+ return conf;
+end
+
+return fts;
diff --git a/lua/markview/health.lua b/lua/markview/health.lua
index d8495fc..70d917e 100644
--- a/lua/markview/health.lua
+++ b/lua/markview/health.lua
@@ -1,55 +1,656 @@
local health = {};
-local ts_available, treesitter_parsers = pcall(require, "nvim-treesitter.parsers");
+--- Logs for health check
+health.log = {};
-local devicons_loaded = pcall(require, "nvim-web-devicons");
-local mini_loaded = pcall(require, "mini.icons");
+health.ns = vim.api.nvim_create_namespace("markview/health");
+health.buffer = nil;
+health.window = nil;
---- Checks if a parser is available or not
----@param parser_name string
----@return boolean
-local function parser_installed(parser_name)
- return (ts_available and treesitter_parsers.has_parser(parser_name)) or pcall(vim.treesitter.query.get, parser_name, "highlights")
+--- Fixed version of deprecated options.
+health.fixed_config = nil;
+
+---@class health.log.deprecation
+---
+---@field kind "deprecation"
+---@field name string
+---@field command boolean
+---
+---@field alternative? string
+---@field tip? string
+
+health.child_indent = 0;
+
+--- Increases indent level of child messages.
+health.__child_indent_in = function ()
+ health.child_indent = health.child_indent + 1;
+end
+
+--- Decreases indent level of child messages.
+health.__child_indent_de = function ()
+ health.child_indent = math.max(0, health.child_indent - 1);
+end
+
+--- Fancy print()
+---@param handler string | nil
+---@param opts table
+health.notify = function (handler, opts)
+ ---+${lua}
+
+ --- Wrapper for tostring()
+ ---@param tbl string | [ string, string? ][]
+ ---@return string
+ local function to_string(tbl)
+ ---+${lua}
+ if vim.islist(tbl) == false then
+ return tostring(tbl);
+ end
+
+ ---@cast tbl [ string, string? ][]
+
+ local _t = "";
+
+ for _, item in ipairs(tbl) do
+ if type(item[1]) == "string" then
+ if type(item[2]) == "string" and item[2]:match("VirtualText") then
+ _t = _t .. item[1]:gsub("^%s", "{"):gsub("%s$", "}");
+ else
+ _t = _t .. item[1];
+ end
+ end
+ end
+
+ return _t;
+ ---_
+ end
+
+ if handler == "deprecation" then
+ ---+${lua}
+
+ ---@class notify.deprecation
+ ---
+ ---@field option string
+ ---@field ignore? boolean
+ ---@field alter? string Alternative.
+ ---@field tip? string Additional string.
+
+ ---@cast opts notify.deprecation
+
+ local chunks = {
+ { "๏ markview.nvim: ", "DiagnosticError" },
+ { string.format(" %s ", opts.option), "DiagnosticVirtualTextError" },
+ { " is deprecated. ", "Normal" },
+ };
+
+ if opts.alter then
+ chunks = vim.list_extend(chunks, {
+ { "Use ", "Normal" },
+ { string.format(" %s ", opts.alter), "DiagnosticVirtualTextHint" },
+ { " instead.", "Normal" },
+ });
+ end
+
+ if opts.tip then
+ chunks = vim.list_extend(chunks, {
+ { "\n" },
+ { " ๎ฉก Tip: ", "DiagnosticVirtualTextWarn" },
+ { " " },
+ });
+ chunks = vim.list_extend(chunks, opts.tip);
+ end
+
+ vim.api.nvim_echo(chunks, true, {});
+
+ ---@class log.deprecation
+ ---
+ ---@field kind "deprecation"
+ ---@field name string
+ ---@field ignore boolean
+ ---@field alternative? string
+ ---@field tip? string
+
+ table.insert(health.log, {
+ kind = "deprecation",
+ name = opts.option,
+ ignore = opts.ignore,
+
+ alternative = opts.alter,
+ tip = opts.tip and to_string(opts.tip) or nil
+ });
+ ---_
+ elseif handler == "type" then
+ ---+${lua}
+
+ ---@class notify.type
+ ---
+ ---@field option string
+ ---@field uses string
+ ---@field got string
+
+ ---@cast opts notify.type
+
+ local article_1 = "a ";
+ local article_2 = "a ";
+
+ if string.match(opts.uses, "^[aeiou]") then
+ article_1 = "an ";
+ elseif string.match(opts.uses, "^%A") then
+ article_1 = "";
+ end
+
+ if string.match(opts.got, "^[aeiou]") then
+ article_2 = "an ";
+ elseif string.match(opts.got, "^%A") then
+ article_2 = "";
+ end
+
+ vim.api.nvim_echo({
+ { "๏ markview.nvim: ", "DiagnosticWarn" },
+ { string.format(" %s ", opts.option), "DiagnosticVirtualTextInfo" },
+ { " is " .. article_1, "Normal" },
+ { string.format(" %s ", opts.uses), "DiagnosticVirtualTextHint" },
+ { ", not " .. article_2, "Normal" },
+ { string.format(" %s ", opts.got), "DiagnosticVirtualTextError" },
+ { ".", "Normal" }
+ }, true, {});
+
+ ---@class log.type
+ ---
+ ---@field kind "type_error"
+ ---@field option string
+ ---@field requires string
+ ---@field received string
+
+ table.insert(health.log, {
+ kind = "type_error",
+ option = opts.option,
+
+ requires = opts.uses,
+ received = opts.got
+ });
+
+ ---_
+ elseif handler == "hl" then
+ ---+${lua}
+
+ ---@class notify.hl
+ ---
+ ---@field group string
+ ---@field value any
+ ---@field message string
+
+ ---@cast opts notify.hl
+
+ local text = vim.split(vim.inspect(opts.value) or "", '\n', { trimempty = true });
+ local lines = {};
+
+ for l, line in ipairs(text) do
+ table.insert(lines, { string.format("% " .. #text .. "d", l), "Special" });
+ table.insert(lines, { " โ ", "Comment" });
+ table.insert(lines, { line, "Normal" });
+ table.insert(lines, { "\n" });
+ end
+
+ vim.api.nvim_echo(vim.list_extend({
+ { "๏ markview.nvim: ", "DiagnosticWarn" },
+ { "Failed to set ", "Normal" },
+ { string.format(" %s ", opts.group), "DiagnosticVirtualTextInfo" },
+ { ",\n", "Normal" }
+ }, lines), true, {});
+
+ ---@class log.hl
+ ---
+ ---@field kind "string"
+ ---@field group string
+ ---@field value any
+ ---@field message string
+
+ table.insert(health.log, {
+ kind = "hl",
+
+ group = opts.group,
+ value = opts.value,
+
+ message = opts.message
+ });
+ ---_
+ elseif handler == "trace" then
+ ---+${lua}
+
+ --- Tracing messages.
+ ---@class notify.trace
+ ---
+ ---@field level? integer
+ ---@field message [ string, string? ][] | string
+ ---@field indent? integer
+ ---@field child_indent? integer
+
+ ---@cast opts notify.trace
+
+ local config = {
+ { "๎ซ", "DiagnosticOk" },
+ { "๎ซ", "DiagnosticWarn" },
+ { "๎ซ", "DiagnosticOk" },
+
+ { "๎ชธ", "DiagnosticError" },
+ { "๎ฎ", "DiagnosticInfo" },
+
+ { "๏
", "DiagnosticHint" },
+ { "๏ ", "DiagnosticWarn" },
+
+ { "๏ ", "DiagnosticOk" },
+ { "๏ ", "DiagnosticError" },
+ };
+
+ local icon, hl = config[opts.level or 5][1], config[opts.level or 5][2];
+ local indent = string.rep(" ", opts.indent or health.child_indent or 0);
+
+ local notif;
+
+ if vim.islist(opts.message) then
+ notif = vim.list_extend({
+ { string.format("%s%s ", indent, icon), hl },
+ { os.date("%H:%m"), "Comment" },
+ { " | ", "Comment" },
+ }, opts.message);
+ else
+ notif = {
+ { string.format("%s%s ", indent, icon), hl },
+ { os.date("%H:%m"), "Comment" },
+ { " | ", "Comment" },
+ { opts.message or "", hl }
+ };
+ end
+
+ if vim.g.__mkv_dev == true then
+ vim.api.nvim_echo(notif, true, { verbose = true });
+ end
+
+ if opts.child_indent then
+ health.child_indent = opts.child_indent;
+ end
+
+ ---@class logs.trace
+ ---
+ ---@field kind "trace"
+ ---
+ ---@field ignore boolean
+ ---@field indent integer
+ ---@field timestamp string
+ ---@field message string
+ ---@field notification [ string, string? ][]
+ ---@field level integer
+
+ table.insert(health.log, {
+ kind = "trace",
+ ignore = true,
+ indent = opts.indent or health.child_indent,
+
+ timestamp = os.date("%k:%M:%S"),
+ message = to_string(opts.message),
+ notification = notif or {},
+ level = opts.level
+ })
+ ---_
+ else
+ ---@cast opts { message: [ string, string? ][] }
+ vim.api.nvim_echo(vim.list_extend({ { "๎ฎ markview.nvim: ", "DiagnosticInfo" } }, opts.message), true, {});
+ end
+ ---_
end
+--- Sets up the buffer & window for trace-view
+local function trace_view_setup ()
+ ---+${lua}
+
+ if not health.buffer then
+ health.buffer = vim.api.nvim_create_buf(false, true);
+
+ vim.api.nvim_create_autocmd({ "BufLeave" }, {
+ buffer = health.buffer,
+ callback = function ()
+ pcall(vim.api.nvim_win_close, health.window, true);
+ end
+ });
+ elseif vim.api.nvim_buf_is_valid(health.buffer) == false then
+ health.buffer = vim.api.nvim_create_buf(false, true);
+
+ vim.api.nvim_create_autocmd({ "BufLeave" }, {
+ buffer = health.buffer,
+ callback = function ()
+ pcall(vim.api.nvim_win_close, health.window, true);
+ end
+ });
+ end
+
+ local w = math.floor(vim.o.columns * 0.75);
+ local h = math.floor(vim.o.lines * 0.5);
+
+ if not health.window then
+ health.window = vim.api.nvim_open_win(health.buffer, true, {
+ relative = "editor",
+
+ row = math.ceil((vim.o.lines - h) / 2),
+ col = math.ceil((vim.o.columns - w) / 2),
+
+ width = w,
+ height = h,
+
+ style = "minimal",
+ });
+ elseif vim.api.nvim_win_is_valid(health.window) == false then
+ health.window = vim.api.nvim_open_win(health.buffer, true, {
+ relative = "editor",
+
+ row = math.ceil((vim.o.lines - h) / 2),
+ col = math.ceil((vim.o.columns - w) / 2),
+
+ width = w,
+ height = h,
+
+ style = "minimal"
+ });
+ else
+ vim.api.nvim_win_set_config(health.window, {
+ relative = "editor",
+
+ row = math.ceil((vim.o.lines - h) / 2),
+ col = math.ceil((vim.o.columns - w) / 2),
+
+ width = w,
+ height = h
+ });
+ end
+
+ vim.wo[health.window].cursorline = true;
+ vim.wo[health.window].statuscolumn = " ";
+
+ vim.api.nvim_buf_set_keymap(health.buffer, "n", "q", "", {
+ callback = function ()
+ pcall(vim.api.nvim_win_close, health.window, true);
+ end
+ });
+ ---_
+end
+
+--- Creates a new entry inside the trace-view buffer.
+local function create_entry(l)
+ ---+${lua}
+
+ if not health.log[l] then
+ return;
+ end
+
+ local highlights = {};
+ local text = "";
+
+ for _, entry in ipairs(health.log[l].notification or {}) do
+ local before = #text;
+ text = text .. entry[1];
+
+ if entry[2] then
+ table.insert(highlights, { before, #text, entry[2] });
+ end
+ end
+
+ vim.api.nvim_buf_set_lines(health.buffer, -1, -1, false, { text });
+
+ for _, hl in ipairs(highlights) do
+ vim.api.nvim_buf_add_highlight(
+ health.buffer,
+ health.ns,
+ hl[3],
+ vim.api.nvim_buf_line_count(health.buffer) - 1,
+ hl[1],
+ hl[2]
+ );
+ end
+
+ ---_
+end
+
+--- Opens trace-view window.
+health.trace_open = function (from, to)
+ ---+${lua}
+
+ trace_view_setup();
+ vim.api.nvim_win_set_config(health.window, {
+ border = {
+ { "โญ", "MarkviewPalette7Fg" },
+ { "โ", "MarkviewPalette7Fg" },
+ { "โฎ", "MarkviewPalette7Fg" },
+ { "โ", "MarkviewPalette7Fg" },
+ { "โฏ", "MarkviewPalette7Fg" },
+ { "โ", "MarkviewPalette7Fg" },
+ { "โฐ", "MarkviewPalette7Fg" },
+ { "โ", "MarkviewPalette7Fg" },
+ },
+
+ title = {
+ (type(from) == "number" and type(to) == "number") and {
+ string.format(" ๎ฎจ Markview: Traceback(%s-%s) ", from, to), "MarkviewPalette7"
+ } or {
+ " ๎ฎจ Markview: Traceback ", "MarkviewPalette7"
+ }
+ },
+ title_pos = "right",
+
+ footer = {
+ { " " },
+ { "[q]", "MarkviewPalette5" },
+ { "uit, ", "Comment" },
+ { "[r]", "MarkviewPalette5" },
+ { "eload, ", "Comment" },
+ { "[E]", "MarkviewPalette5" },
+ { "xport ", "Comment" },
+ },
+ footer_pos = "right",
+ });
+
+ vim.bo[health.buffer].modifiable = true;
+ vim.api.nvim_buf_set_lines(health.buffer, 0, -1, false, {});
+
+ local logs = health.log;
+
+ if type(from) == "number" and type(to) == "number" then
+ logs = vim.list_slice(health.log, from - 1, to - 1);
+ end
+
+ for l, log in ipairs(logs) do
+ if log.kind ~= "trace" then
+ goto continue
+ end
+
+ create_entry(l);
+
+ ::continue::
+ end
+
+ vim.api.nvim_buf_set_lines(health.buffer, 0, 1, false, {});
+ vim.bo[health.buffer].modifiable = false;
+
+ vim.api.nvim_buf_set_keymap(health.buffer, "n", "r", "", {
+ callback = function ()
+ vim.bo[health.buffer].modifiable = true;
+ vim.api.nvim_buf_set_lines(health.buffer, 0, -1, false, {});
+
+ for l, log in ipairs(health.log) do
+ if log.kind ~= "trace" then
+ goto continue
+ end
+
+ create_entry(l);
+
+ ::continue::
+ end
+
+ vim.api.nvim_buf_set_lines(health.buffer, 0, 1, false, {});
+ vim.bo[health.buffer].modifiable = false;
+ end
+ });
+ vim.api.nvim_buf_set_keymap(health.buffer, "n", "E", "Markview traceExport", {
+ callback = function ()
+ health.notify("msg", {
+ message = {
+ { "Exported logs to " },
+ { " trace.txt ", "DiagnosticVirtualTextHint" },
+ { "."}
+ }
+ });
+ vim.cmd("Markview traceExport");
+ end
+ });
+
+ ---_
+end
+
+--- Holds icons for different filetypes.
+---@type { [string]: string }
+health.supported_languages = {
+ ["html"] = "๎ถ ",
+ ["latex"] = "๎ ",
+ ["markdown"] = "๓ฐ ",
+ ["markdown_inline"] = "๓ฐ ",
+ ["typst"] = "๎ญฉ ",
+ ["yaml"] = "๓ฐฌ "
+}
+
+--- Health check function.
health.check = function ()
+ ---+${lua}
+
+ local spec = require("markview.spec");
+ local symbols = require("markview.symbols");
+ local utils = require("markview.utils");
+
local ver = vim.version();
- vim.health.start("Checking essentials:")
+ ------------------------------------------------------------------------------------------
+
+ vim.health.start("๐ป Neovim:")
if vim.fn.has("nvim-0.10.1") == 1 then
- vim.health.ok("Neovim version: " .. string.format("`%d.%d.%d`", ver.major, ver.minor, ver.patch));
+ vim.health.ok(
+ "Version: " .. string.format( "`%d.%d.%d`", ver.major, ver.minor, ver.patch )
+ );
elseif ver.major == 0 and ver.minor == 10 and ver.patch == 0 then
- vim.health.warn("Neovim version(may experience errors): " .. string.format("`%d.%d.%d`", ver.major, ver.minor, ver.patch));
+ vim.health.warn(
+ "Version(may experience bugs): " .. string.format( "`%d.%d.%d`", ver.major, ver.minor, ver.patch )
+ );
else
- vim.health.error("Unsupported neovim version. Minimum requirement `0.10.1`, found: " .. string.format("`%d.%d.%d`", ver.major, ver.minor, ver.patch));
+ vim.health.error(
+ "Version(unsupported): " .. string.format( "`%d.%d.%d`", ver.major, ver.minor, ver.patch ) .. " <= 0.10.1"
+ );
end
- if ts_available then
- vim.health.ok("`nvim-treesitter/nvim-treesitter` found!")
+ ------------------------------------------------------------------------------------------
+
+ vim.health.start("๐ก Parsers:")
+
+ if pcall(require, "nvim-treesitter") then
+ vim.health.ok("`nvim-treesitter/nvim-treesitter` found.");
else
- vim.health.warn("`nvim-treesitter/nvim-treesitter` wasn't found! Ignore this if you manually installed the parsers!")
+ vim.health.warn("`nvim-treesitter/nvim-treesitter` wasn't found.");
end
- vim.health.start("Checking parsers:")
-
- for _, parser in ipairs({ "markdown", "markdown_inline", "html", "latex" }) do
- if parser_installed(parser) then
- vim.health.ok("`" .. parser .. "` " .. "was found!");
+ for parser, icon in pairs(health.supported_languages) do
+ if utils.parser_installed(parser) then
+ vim.health.ok("`" .. icon .. parser .. "`" .. " parser was found.");
else
- vim.health.warn("`" .. parser .. "` " .. "wasn't found.");
+ vim.health.warn("`" .. icon .. parser .. "`" .. " parser wasn't found.");
end
end
- vim.health.start("Checking icon providers:");
+ ------------------------------------------------------------------------------------------
+
+ vim.health.start("โจ Icon providers:");
+
+ if pcall(require, "nvim-web-devicons") then
+ vim.health.ok("`nvim-tree/nvim-web-devicons` found.");
+ else
+ vim.health.info("`nvim-tree/nvim-web-devicons` not found.");
+ end
- if devicons_loaded then
- vim.health.ok("`nvim-tree/nvim-web-devicons` found!");
- elseif mini_loaded then
- vim.health.ok("`echasnovski/mini.icons` found!");
+ if pcall(require, "mini.icons") then
+ vim.health.ok("`echasnovski/mini.icons` found.");
else
- vim.health.warn("External icon providers weren't found! Using internal icon providers instead.")
+ vim.health.info("`echasnovski/mini.icons` not found.");
+ end
+
+ ------------------------------------------------------------------------------------------
+
+ vim.health.start("๐ง Configuration:");
+ local errors = false;
+
+ for _, entry in ipairs(health.log) do
+ if entry.type == "trace" or entry.ignore == true then
+ goto continue;
+ end
+
+ errors = true;
+
+ if entry.kind == "deprecation" then
+ local text = string.format("`%s` is deprecated!", entry.name);
+
+ if entry.alternative then
+ text = text .. string.format(" Use `%s` instead.", entry.alternative);
+ end
+
+ vim.health.warn(text);
+
+ if entry.tip then
+ vim.health.info(string.format("Tip: %s", entry.tip));
+ end
+ elseif entry.kind == "type_error" then
+ vim.health.warn(string.format("%s expects `%s`, not `%s`.", entrtype_errory.option, entry.requires, entry.receives));
+ elseif entry.kind == "hl" then
+ vim.health.warn(string.format("Failed to set highlight: `%s`. Error: %s.", entry.group, entry.message));
+ end
+
+ ::continue::
+ end
+
+
+ if health.fixed_config then
+ vim.health.info("A patched version of your config is available below:\n" .. vim.inspect(health.fixed_config));
+ elseif errors == false then
+ vim.health.ok("No errors found!")
+ end
+
+ ------------------------------------------------------------------------------------------
+
+ vim.health.start("๐ฌ Symbols:")
+ vim.health.info("๐ If any of the symbols aren't showing up then your font doesn't support it! You may want to `update your font`!");
+
+ vim.health.start("๐ LaTeX math symbols:");
+
+ for _ = 1, 5 do
+ local keys = vim.tbl_keys(symbols.entries);
+ local key = keys[math.floor(math.random() * #keys)];
+
+ vim.health.info( string.format("%-40s", "`" .. key .. "`" ) .. symbols.entries[key])
+ end
+
+ vim.health.start("๐ Typst math symbols:");
+
+ for _ = 1, 5 do
+ local keys = vim.tbl_keys(symbols.typst_entries);
+ local key = keys[math.floor(math.random() * #keys)];
+
+ vim.health.info( string.format("%-40s", "`" .. key .. "`" ) .. symbols.typst_entries[key])
+ end
+
+ vim.health.start("๐ค Text styles:");
+
+ vim.health.info("`Subscript` " .. symbols.tostring("subscripts", "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 + () ="));
+ vim.health.info("`Superscript` " .. symbols.tostring("superscripts", "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 + () ="));
+
+ vim.health.start("๐ข Math fonts:");
+
+ for font, _ in pairs(symbols.fonts) do
+ vim.health.info(string.format("%-20s" , "`" .. font .. "`") .. symbols.tostring(font, "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789"));
end
+ ---_
end
return health;
diff --git a/lua/markview/highlights.lua b/lua/markview/highlights.lua
index 62223a4..85e0542 100644
--- a/lua/markview/highlights.lua
+++ b/lua/markview/highlights.lua
@@ -1,15 +1,32 @@
---- Highlight group related helpers
+--- *Dynamic* highlight group related methods
+--- for `markview.nvim`.
+---
local highlights = {};
+local health = require("markview.health");
local utils = require("markview.utils");
-local exists = utils.hl_exists;
local lerp = utils.lerp;
local clamp = utils.clamp;
---- Returns RGB value from the provided input
+---+${func, Helper functions}
+
+--- Returns RGB value from the provided input.
+--- Supported input types,
+--- โข Hexadecimal values(`#FFFFFF` & `FFFFFF`).
+--- โข Number value of the hexadecimal color(from `nvim_get_hl()`).
+--- โข Color name(e.g. `red`, `green`).
+---
---@param input string | number[]
---@return number[]?
highlights.rgb = function (input)
+ ---+${func}
+
+ --- Lookup table for the regular color names.
+ --- For example,
+ --- โข `red` โ `#FF0000`.
+ --- โข `green` โ `#00FF00`.
+ ---
+ ---@type { [string]: string }
local lookup = {
---+ ${class, Color name lookup table}
["red"] = "#FF0000", ["lightred"] = "#FFBBBB", ["darkred"] = "#8B0000",
@@ -25,6 +42,12 @@ highlights.rgb = function (input)
---_
};
+ --- Lookup table for the Neovim-specific color names.
+ --- For example,
+ --- โข `nvimdarkblue` โ `#004C73`.
+ --- โข `nvimdarkred` โ `#590008`.
+ ---
+ ---@type { [string]: string }
local lookup_nvim = {
---+ ${class, Neovim's color lookup table}
["nvimdarkblue"] = "#004C73", ["nvimlightblue"] = "#A6DBFF",
@@ -45,8 +68,25 @@ highlights.rgb = function (input)
};
if type(input) == "string" then
- if input:match("%x%x%x%x%x%x$") then
- local r, g, b = input:match("(%x%x)(%x%x)(%x%x)$");
+ ---+${lua}
+
+ --- Match cases,
+ --- โข RR GG BB, # is optional.
+ --- โข R G B, # is optional.
+ --- โข Color name.
+ --- โข HSL values(as `{ h, s, l }`)
+
+ if input:match("^%#?(%x%x?)(%x%x?)(%x%x?)$") then
+ --- Pattern explanation:
+ --- #? RR? GG? BB?
+ --- String should have **3** parts & each part
+ --- should have a minimum of *1* & a maximum
+ --- of *2* characters.
+ ---
+ --- # is optional.
+ ---
+ ---@type string, string, string
+ local r, g, b = input:match("^%#?(%x%x?)(%x%x?)(%x%x?)$");
return { tonumber(r, 16), tonumber(g, 16), tonumber(b, 16) };
elseif lookup[input] then
@@ -58,124 +98,211 @@ highlights.rgb = function (input)
return { tonumber(r, 16), tonumber(g, 16), tonumber(b, 16) };
end
+
+ ---_
elseif type(input) == "number" then
+ ---+${lua}
+
+ --- Format the number into a hexadecimal string.
+ --- Then get the **r**, **g**, **b** parts.
+ ---
+ ---@type string, string, string
local r, g, b = string.format("%06x", input):match("(%x%x)(%x%x)(%x%x)$");
return { tonumber(r, 16), tonumber(g, 16), tonumber(b, 16) };
- elseif vim.islist(input) then
- local hue2rgb = function (p, q, t)
- if t < 0 then t = t + 1; end
- if t > 1 then t = t - 1; end
-
- if t < (1 / 6) then return p + (q - p) * 6 * t; end
- if t < (1 / 2) then return q; end
- if t < (2 / 3) then return p + (q - p) * 6 * (2 / 3 - t); end
-
- return p;
- end
-
- local r, g, b = input[3], input[3], input[3];
- if input[2] ~= 0 then
- local q = input[3] < 0.5 and input[3] * (1 + input[2]) or input[2] + input[3] - (input[2] * input[3]);
- local p = 2 * input[3] - q;
-
- r = hue2rgb(p, q, input[1] + (1 / 3));
- g = hue2rgb(p, q, input[1]);
- b = hue2rgb(p, q, input[1] - (1 / 3));
- end
-
- return { math.floor(r * 255), math.floor(g * 255), math.floor(b * 255) };
- end
-end
-
---- Gets a value from a list of highlight groups
----@param value string
----@param array table
----@return any?
-highlights.get = function (value, array)
- for _, item in ipairs(array) do
- if vim.fn.hlexists(item) and vim.api.nvim_get_hl(0, { name = item, link = false })[value] then
- return vim.api.nvim_get_hl(0, { name = item, link = false })[value];
- end
+ ---_
end
+ ---_
end
---- Mixes 2 colors RGB values
+--- Simple RGB *color-mixer* function.
+--- Supports mixing colors by % values.
+---
+--- NOTE: `per_1` & `per_2` are between
+--- **0** & **1**.
+---
---@param c_1 number[]
---@param c_2 number[]
---@param per_1 number
---@param per_2 number
---@return number[]
highlights.mix = function (c_1, c_2, per_1, per_2)
- local _r = clamp((c_1[1] * per_1) + (c_2[1] * per_2), 0, 255);
- local _g = clamp((c_1[2] * per_1) + (c_2[2] * per_2), 0, 255);
- local _b = clamp((c_1[3] * per_1) + (c_2[3] * per_2), 0, 255);
+ local _r = (c_1[1] * per_1) + (c_2[1] * per_2);
+ local _g = (c_1[2] * per_1) + (c_2[2] * per_2);
+ local _b = (c_1[3] * per_1) + (c_2[3] * per_2);
return { math.floor(_r), math.floor(_g), math.floor(_b) };
end
---- Turns an RGB value to its hexadecimal string
----@param color any
+--- RGB to hexadecimal string converter.
+---
+---@param color number[]
---@return string
-highlights.hex = function (color)
+highlights.rgb_to_hex = function (color)
return string.format("#%02x%02x%02x", math.floor(color[1]), math.floor(color[2]), math.floor(color[3]))
end
---- RGB to HSL converter
+--- RGB to HSL converter.
+--- Input: `{ r, g, b }` where,
+--- r โ [0, 255]
+--- g โ [0, 255]
+--- b โ [0, 255]
+---
+--- Return: `{ h, s, l }` where,
+--- h โ [0, 360]
+--- s โ [0, 1]
+--- l โ [0, 1]
+---
---@param color number[]
---@return number[]
-highlights.hsl = function (color)
- for c, val in ipairs(color) do
- if val > 1 then
- color[c] = val / 255;
- end
- end
+highlights.rgb_to_hsl = function (color)
+ ---+${func}
- local min, max = math.min(color[1], color[2], color[3]), math.max(color[1], color[2], color[3]);
- local hue, sature, lumen = nil, nil, (min + max) / 2;
- local delta = max - min;
+ local nR, nG, nB = color[1] / 255, color[2] / 255, color[3] / 255;
+ local min, max = math.min(nR, nG, nB), math.max(nR, nG, nB);
- if max == min then
- hue = 0;
- sature = 0;
+ local h, s, l;
+ l = (min + max) / 2;
+
+ if min == max then
+ s = 0;
+ elseif l <= 0.5 then
+ s = (max - min) / (max + min);
else
- sature = lumen > 0.5 and delta / (2 - max - min) or delta / (max + min);
-
- if max == color[1] then
- hue = (color[2] - color[3]) / delta + (color[2] < color[3] and 6 or 0);
- elseif max == color[2] then
- hue = (color[3] - color[1]) / delta + 2;
- elseif max == color[3] then
- hue = (color[1] - color[2]) / delta + 4;
- end
+ s = (max - min) / (2 - max - min);
+ end
+
+ if max == nR then
+ h = (nG - nB) / (max - min);
+ elseif max == nG then
+ h = 2 + (nB - nR) / (max - min);
+ else
+ h = 4 + (nR - nG) / (max - min);
+ end
- hue = hue / 6;
+ if h < 0 then
+ h = 1 - h;
end
- return { hue, sature, lumen };
+ return { h * 60, s, l };
+
+ ---_
end
---- Gets the luminosity of a RGB value
----@param color number[]
----@return number
-highlights.lumen = function (color)
- for c, val in ipairs(color) do
- if val > 1 then
- color[c] = val / 255;
+--- HSL to RGB converter.
+--- Input: `{ h, s, l }` where,
+--- h โ [0, 360]
+--- s โ [0, 1]
+--- l โ [0, 1]
+---
+--- Return: `{ r, g, b }` where,
+--- r โ [0, 255]
+--- g โ [0, 255]
+--- b โ [0, 255]
+---
+---@param color integer[]
+highlights.hsl_to_rgb = function (color)
+ ---+${func}
+
+ local h, s, l = color[1] / 360, color[2], color[3];
+
+ if s == 0 then
+ return { l * 255, l * 255, l * 255 };
+ end
+
+ local tmp_1, tmp_2;
+
+ if l < 0.5 then
+ tmp_1 = l * (1 + s);
+ else
+ tmp_1 = l + s - (l * s);
+ end
+
+ tmp_2 = (2 * l) - tmp_1;
+ local tR, tG, tB;
+
+ tR = h + 0.333;
+ tG = h;
+ tB = h - 0.333;
+
+ tR = tR < 0 and tR + 1 or tR;
+ tG = tG < 0 and tG + 1 or tG;
+ tB = tB < 0 and tB + 1 or tB;
+
+ local function checker (val)
+ if 6 * val < 1 then
+ return tmp_2 + (tmp_1 - tmp_2) * 6 * val;
+ elseif 2 * val < 1 then
+ return tmp_1;
+ elseif 3 * val < 2 then
+ return tmp_2 + (tmp_1 - tmp_2) * (0.666 - val) * 6;
+ else
+ return tmp_2;
end
end
- local min, max = math.min(color[1], color[2], color[3]), math.max(color[1], color[2], color[3]);
+ return {
+ clamp(checker(tR) * 255, 0, 255),
+ clamp(checker(tG) * 255, 0, 255),
+ clamp(checker(tB) * 255, 0, 255),
+ };
+
+ ---_
+end
+
+--- Deprecated RGB to HSL converter.
+---@param rgb integer[]
+---@return integer[]
+---@deprecated
+highlights.hsl = function (rgb)
+ vim.notify("[ markview.nvim ]: highlights.hsl is deprecated. Use 'highlights.rgb_to_hsl' instead", vim.log.levels.WARN);
+ return highlights.rgb_to_hsl(rgb);
+end
+
+--- Gets the luminosity of a RGB value.
+---
+--- Input: `{ r, g, b }` where,
+--- r โ [0, 255]
+--- g โ [0, 255]
+--- b โ [0, 255]
+---
+--- Return: `l` where,
+--- l โ [0, 1]
+---
+---@param input number[]
+---@return number
+highlights.lumen = function (input)
+ local min = math.min(input[1], input[2], input[3]);
+ local max = math.max(input[1], input[2], input[3]);
+
return (min + max) / 2;
end
---- Mixes 2 colors to fake opacity
+--- Mixes a color with it's background based on
+--- the provided `alpha`(between 0 & 1).
+---
+--- Input:
+--- fg: `{ r, g, b }` where,
+--- r โ [0, 255]
+--- g โ [0, 255]
+--- b โ [0, 255]
+---
+--- bg: `{ r, g, b }` where,
+--- r โ [0, 255]
+--- g โ [0, 255]
+--- b โ [0, 255]
+---
+--- alpha: `a` where,
+--- a โ [0, 1]
+---
---@param fg number[]
---@param bg number[]
---@param alpha number
---@return number[]
+---@deprecated
highlights.opacify = function (fg, bg, alpha)
+ vim.notify("[ markview.nvim ]: highlights.opacify is deprecated. Use 'highlights.mix' instead", vim.log.levels.WARN);
return {
math.floor((fg[1] * alpha) + (bg[1] * (1 - alpha))),
math.floor((fg[2] * alpha) + (bg[2] * (1 - alpha))),
@@ -183,1609 +310,1373 @@ highlights.opacify = function (fg, bg, alpha)
}
end
+--- Turns RGB color-space into XYZ.
+---
+--- Input: `{ r, g, b }` where,
+--- r โ [0, 255]
+--- g โ [0, 255]
+--- b โ [0, 255]
+---
+---@param color number[]
+---@return number[]
+highlights.rgb_to_xyz = function (color)
+ ---+${func}
+
+ local RGB = {};
----@type string[]
-highlights.created = {};
+ for c, channel in ipairs(color) do
+ local _ch = channel / 255;
---- Checks if the background is dark or not
----@param light any?
----@param dark any?
----@return boolean | any
-local isDark = function (light, dark)
- if light and dark then
- return vim.o.background == "dark" and dark or light;
+ if _ch <= 0.04045 then
+ _ch = _ch / 12.92;
+ else
+ _ch = ((_ch + 0.055) / 1.055)^2.4;
+ end
+
+ RGB[c] = _ch;
end
- return vim.o.background == "dark";
+ local matrix = {
+ 0.4124504, 0.3575761, 0.1804375,
+ 0.2126729, 0.7151522, 0.0721750,
+ 0.0193339, 0.1191920, 0.9503041
+ };
+
+ return {
+ (RGB[1] * matrix[1] + RGB[2] * matrix[2] + RGB[3] * matrix[3]) * 100,
+ (RGB[1] * matrix[4] + RGB[2] * matrix[5] + RGB[3] * matrix[6]) * 100,
+ (RGB[1] * matrix[7] + RGB[2] * matrix[8] + RGB[3] * matrix[9]) * 100
+ }
+ ---_
end
---- Creates highlight groups from an array of tables
----@param array markview.conf.hl[]
----@param list? "text" | "table"
-highlights.create = function (array, list)
- local _c = {};
+--- Turns XYZ color-space into RGB.
+---@param color number[]
+---@return number[]
+highlights.xyz_to_rgb = function (color)
+ ---+${func}
- if type(array) == "string" then
- if highlights[array] then
- array = highlights[array];
- else
- return;
- end
+ local XYZ = color;
+
+ for c, channel in ipairs(color) do
+ local _ch = channel / 100;
+ XYZ[c] = _ch;
end
- --- Create an array of usable tables
- for _, config in ipairs(array) do
- if type(config) ~= "table" then
- goto ignore;
- end
+ local rev_matrix = {
+ 3.2404542, -1.5371385, -0.4985314,
+ -0.9692660, 1.8760108, 0.0415560,
+ 0.0556434, -0.2040259, 1.0572252
+ };
- if config.group_name and config.value then
- table.insert(_c, config);
- elseif config.output then
- local _o = config.output(highlights);
+ local RGB = {
+ XYZ[1] * rev_matrix[1] + XYZ[2] * rev_matrix[2] + XYZ[3] * rev_matrix[3],
+ XYZ[1] * rev_matrix[4] + XYZ[2] * rev_matrix[5] + XYZ[3] * rev_matrix[6],
+ XYZ[1] * rev_matrix[7] + XYZ[2] * rev_matrix[8] + XYZ[3] * rev_matrix[9]
+ };
- if vim.islist(_o) then
- _c = vim.list_extend(_o, _c);
- elseif type(_o) == "table" and _o.group_name and _o.value then
- table.insert(_c, _o);
- end
+ for c, channel in ipairs(RGB) do
+ local _ch = channel;
+
+ if _ch <= 0.0031308 then
+ _ch = _ch * 12.92;
+ else
+ _ch = (1.055 * (_ch^(1 / 2.4))) - 0.055;
end
- ::ignore::
+ RGB[c] = utils.clamp(_ch * 255, 0, 255);
end
- local log_file;
+ return RGB;
+ ---_
+end
+
+--- Turns XYZ color-space into Lab.
+---@param color number[]
+---@return number[]
+highlights.xyz_to_lab = function (color)
+ ---+${func}
- if list then
- log_file = io.open("mkvhl.txt", "w");
+ local ref_point = { 95.047, 100, 108.883 };
- if log_file and list == "table" then
- log_file:write("{", "\n");
+ local f = function (t)
+ if t > (6 / 29)^3 then
+ return t^(1/3);
+ else
+ return ( (1 / 3) * t * ((6 / 29)^-2) ) + (4 / 29);
end
end
- -- Apply the new highlight groups
- for _, color in ipairs(_c) do
- if type(color.group_name) == "string" and type(color.value) == "table" then
- -- Add the prefix
- if not color.group_name:match("^Markview") then
- color.group_name = "Markview" .. color.group_name;
- end
+ return {
+ ( 116 * f(color[2] / ref_point[2]) ) - 16,
+ 500 * ( f(color[1] / ref_point[1]) - f(color[2] / ref_point[2]) ),
+ 200 * ( f(color[2] / ref_point[2]) - f(color[3] / ref_point[3]) )
+ };
+ ---_
+end
- vim.api.nvim_set_hl(0, color.group_name, color.value);
- table.insert(highlights.created, color.group_name)
-
- if log_file and list == "text" then
- log_file:write(color.group_name, "\n");
- elseif log_file and list == "table" then
- log_file:write(" {\n");
- log_file:write(" group_name = ", '"', color.group_name, '",', "\n");
- log_file:write(" value = {", "\n");
-
- for opt, value in pairs(color.value) do
- if type(value) == "string" then
- log_file:write(" ", opt, " = ", '"', value, '"', ",", "\n");
- else
- log_file:write(" ", opt, " = ", tostring(value), ",", "\n");
- end
- end
+--- Turns Lab color-space into XYZ.
+---@param color number[]
+---@return number[]
+highlights.lab_to_xyz = function (color)
+ ---+${func}
- log_file:write(" }", "\n");
- log_file:write(" },", "\n");
- end
+ local ref_point = { 95.047, 100, 108.883 };
+
+ local f_inv = function (t)
+ if t > (6 / 29) then
+ return t^3;
+ else
+ return 3 * ((6 / 29)^2) * (t - (4 / 29));
end
end
- if log_file then
- if log_file and list == "table" then
- log_file:write("}");
- end
+ local tmp = (color[1] + 16) / 116;
- log_file:close();
- end
+ return {
+ ref_point[1] * f_inv( tmp + (color[2] / 500) ),
+ ref_point[2] * f_inv(tmp),
+ ref_point[3] * f_inv( tmp - (color[3] / 200) )
+ };
+ ---_
end
---- Removes highlight groups
-highlights.remove = function ()
- for index, item in ipairs(highlights.created) do
- vim.api.nvim_set_hl(0, item, {});
- table.remove(highlights.created, index);
- end
+--- Turns RGB color-space into Lab.
+---@param RGB number[]
+---@return number[]
+highlights.rgb_to_lab = function (RGB)
+ local XYZ = highlights.rgb_to_xyz(RGB);
+ return highlights.xyz_to_lab(XYZ);
end
-highlights.color = function (property, list, light, dark)
- return highlights.rgb(highlights.get(property, list) or isDark(light, dark));
+--- Turns Lab color-space into RGB.
+---@param Lab number[]
+---@return number[]
+highlights.lab_to_rgb = function (Lab)
+ local XYZ = highlights.lab_to_xyz(Lab);
+ return highlights.xyz_to_rgb(XYZ);
end
+---_
-local headingGenerator = function (checks, light, dark, group_name, suffix)
- local fg = highlights.color("fg", checks, light, dark);
- local l = highlights.lumen(highlights.color("fg", { "Normal" }, "#FFFFFF", "#000000"));
+--- Holds info about highlight groups.
+---@type string[]
+highlights.created = {};
- local nr = highlights.rgb(highlights.get("bg", { "LineNr" }));
- local bg;
+--- Wrapper function for `nvim_set_hl()`.
+---@param name string
+---@param value table
+highlights.set_hl = function (name, value)
+ local success, err = pcall(vim.api.nvim_set_hl, 0, name, value);
- if l < 0.5 then
- bg = highlights.opacify(fg, highlights.rgb("#FFFFFF") --[=[@as number[]]=], 0.25)
- else
- bg = highlights.opacify(fg, highlights.rgb("#1e1e2e") --[=[@as number[]]=], 0.25)
+ if success == false then
+ health.notify("hl", {
+ group = name,
+ value = value,
+ message = err
+ });
end
-
- return {
- {
- group_name = group_name,
- value = {
- default = true,
- fg = highlights.hex(fg),
- bg = highlights.hex(bg)
- }
- },
- {
- group_name = group_name .. suffix,
- value = {
- default = true,
- fg = highlights.hex(fg),
- bg = nr and highlights.hex(nr) or nil
- }
- }
- };
end
-local hlGenerator = function (checks, light, dark, group_name)
- local fg = highlights.color("fg", checks, light, dark);
-
- return {
- {
- group_name = group_name,
- value = {
- default = true,
- fg = highlights.hex(fg),
- }
- }
- };
-end
+--- Creates highlight groups from an array of tables
+---@param array { [string]: config.hl | fun(): config.hl }
+highlights.create = function (array)
+ ---+${lua}
----@type markview.conf.hl[]
-highlights.dynamic = {
- ---+ ${hl, Block quotes}
- {
- output = function ()
- return hlGenerator({ "Comment" }, "#9ca0b0", "#6c7086", "BlockQuoteDefault");
- end
- },
- {
- output = function ()
- return hlGenerator({ "DiagnosticError" }, "#D20F39", "#F38BA8", "BlockQuoteError");
- end
- },
- {
- output = function ()
- local fg = highlights.color("bg", { "@comment.note" }, nil, nil) or highlights.color("fg", { "@comment.note" }, "#1e66f5", "#89b4fa");
-
- return {
- {
- group_name = "BlockQuoteNote",
- value = {
- default = true,
- fg = highlights.hex(fg),
- }
- }
- };
- end
- },
- {
- output = function ()
- return hlGenerator({ "DiagnosticOk" }, "#40a02b", "#a6e3a1", "BlockQuoteOk");
- end
- },
- {
- output = function ()
- return hlGenerator({ "Conditional", "Keyword" }, "#8839ef", "#cba6f7", "BlockQuoteSpecial");
- end
- },
- {
- output = function ()
- return hlGenerator({ "DiagnosticWarn" }, "#DF8E1D", "#F9E3AF", "BlockQuoteWarn");
+ if type(array) == "string" then
+ if not highlights[array] then
+ return;
end
- },
- ---_
- ---+ ${hl, Checkbox}
- {
- output = function ()
- return hlGenerator({ "Comment" }, "#9ca0b0", "#6c7086", "CheckboxCancelled");
- end
- },
- {
- output = function ()
- return hlGenerator({ "DiagnosticOk" }, "#40a02b", "#a6e3a1", "CheckboxChecked");
- end
- },
- {
- output = function ()
- return hlGenerator({ "DiagnosticWarn" }, "#DF8E1D", "#F9E3AF", "CheckboxPending");
- end
- },
- {
- output = function ()
- return hlGenerator({ "Conditional", "Keyword" }, "#8839ef", "#cba6f7", "CheckboxProgress");
- end
- },
- {
- output = function ()
- return hlGenerator({ "DiagnosticError" }, "#D20F39", "#F38BA8", "CheckboxUnchecked");
- end
- },
- {
- output = function (util)
- local fg = util.color("fg", { "Comment" }, "#9ca0b0", "#6c7086");
+ array = highlights[array];
+ end
- return {
- group_name = "CheckboxStriked",
- value = {
- fg = util.hex(fg),
- strikethrough = true
- }
- };
+ local hls = vim.tbl_keys(array) or {};
+ table.sort(hls);
+
+ for _, hl in ipairs(hls) do
+ local value = array[hl];
+
+ if not hl:match("^Markview") then
+ hl = "Markview" .. hl;
end
- },
- ---_
- ---+ ${hl, Code blocks}
- {
- output = function (util)
- local bg = util.hsl(util.color("bg", { "Normal" }, "#CDD6F4", "#1E1E2E"));
- local fg = util.color("fg", { "Comment" }, "#9ca0b0", "#6c7086");
-
- local nr = util.get("bg", { "LineNr" });
- local inl = vim.deepcopy(bg);
-
- local c1 = highlights.color("fg", {
- "markdownH1", "@markup.heading.1.markdown", "@markup.heading"
- }, "#F38BA8", "#D20F39")
- local c2 = highlights.color("fg", {
- "markdownH2", "@markup.heading.2.markdown", "@markup.heading"
- }, "#FAB387", "#FE640B")
- local c3 = highlights.color("fg", {
- "markdownH3", "@markup.heading.3.markdown", "@markup.heading"
- }, "#F9E2AF", "#DF8E1D")
- local c4 = highlights.color("fg", {
- "markdownH4", "@markup.heading.4.markdown", "@markup.heading"
- }, "#A6E3A1", "#40A02B")
- local c5 = highlights.color("fg", {
- "markdownH5", "@markup.heading.5.markdown", "@markup.heading"
- }, "#74C7EC", "#209FB5")
- local c6 = highlights.color("fg", {
- "markdownH6", "@markup.heading.6.markdown", "@markup.heading"
- }, "#B4BEFE", "#7287FD")
-
- if bg[3] > 0.5 then
- bg[3] = clamp(bg[3] - 0.05, 0.1, 0.9);
- inl[3] = clamp(inl[3] - 0.10, 0.1, 0.9);
+ if type(value) == "table" then
+ highlights.set_hl(hl, value);
+ else
+ local val = value();
+
+ if vim.islist(val) then
+ for _, item in ipairs(val) do
+ highlights.set_hl(item.group_name, item.value);
+ end
else
- bg[3] = clamp(bg[3] + 0.05, 0.1, 0.9);
- inl[3] = clamp(inl[3] + 0.10, 0.1, 0.9);
+ highlights.set_hl(hl, val);
end
-
- bg = util.hex(util.rgb(bg));
-
- return {
- {
- group_name = "Code",
- value = {
- default = true,
- bg = bg,
- }
- },
- {
- group_name = "CodeInfo",
- value = {
- default = true,
- bg = bg,
- fg = util.hex(fg),
- }
- },
-
- {
- group_name = "InlineCode",
- value = {
- default = true,
- bg = util.hex(util.rgb(inl)),
- }
- },
-
- {
- group_name = "Icon1",
- value = { default = true, bg = bg, fg = util.hex(c1) }
- },
- {
- group_name = "Icon1Sign",
- value = { default = true, bg = nr, fg = util.hex(c1) }
- },
- {
- group_name = "Icon1Fg",
- value = { default = true, fg = util.hex(c1) }
- },
- { group_name = "Icon2", value = { default = true, bg = bg, fg = util.hex(c2) } },
- { group_name = "Icon2Sign", value = { default = true, bg = nr, fg = util.hex(c2) } },
- { group_name = "Icon2Fg", value = { default = true, fg = util.hex(c2) } },
- { group_name = "Icon3", value = { default = true, bg = bg, fg = util.hex(c3) } },
- { group_name = "Icon3Sign", value = { default = true, bg = nr, fg = util.hex(c3) } },
- { group_name = "Icon3Fg", value = { default = true, fg = util.hex(c3) } },
- { group_name = "Icon4", value = { default = true, bg = bg, fg = util.hex(c4) } },
- { group_name = "Icon4Sign", value = { default = true, bg = nr, fg = util.hex(c4) } },
- { group_name = "Icon4Fg", value = { default = true, fg = util.hex(c4) } },
- { group_name = "Icon5", value = { default = true, bg = bg, fg = util.hex(c5) } },
- { group_name = "Icon5Sign", value = { default = true, bg = nr, fg = util.hex(c5) } },
- { group_name = "Icon5Fg", value = { default = true, fg = util.hex(c5) } },
- { group_name = "Icon6", value = { default = true, bg = bg, fg = util.hex(c6) } },
- { group_name = "Icon6Sign", value = { default = true, bg = nr, fg = util.hex(c6) } },
- { group_name = "Icon6Fg", value = { default = true, fg = util.hex(c6) } },
- }
end
- },
+ end
---_
+end
- ---+ ${hl, Heading 1}
- {
- output = function ()
- return headingGenerator(
- {
- "markdownH1", "@markup.heading.1.markdown", "@markup.heading"
- },
- "#F38BA8",
- "#D20F39",
-
- "Heading1",
- "Sign"
- );
- end
- },
- ---_
- ---+ ${hl, Heading 2}
- {
- output = function ()
- return headingGenerator(
- {
- "markdownH2", "@markup.heading.2.markdown", "@markup.heading"
- },
- "#FAB387",
- "#FE640B",
-
- "Heading2",
- "Sign"
- );
- end
- },
- ---_
- ---+ ${hl, Heading 3}
- {
- output = function ()
- return headingGenerator(
- {
- "markdownH3", "@markup.heading.3.markdown", "@markup.heading"
- },
- "#F9E2AF",
- "#DF8E1D",
-
- "Heading3",
- "Sign"
- );
- end
- },
- ---_
- ---+ ${hl, Heading 4}
- {
- output = function ()
- return headingGenerator(
- {
- "markdownH4", "@markup.heading.4.markdown", "@markup.heading"
- },
- "#A6E3A1",
- "#40A02B",
-
- "Heading4",
- "Sign"
- );
- end
- },
- ---_
- ---+ ${hl, Heading 5}
- {
- output = function ()
- return headingGenerator(
- {
- "markdownH5", "@markup.heading.5.markdown", "@markup.heading"
- },
- "#74C7EC",
- "#209FB5",
-
- "Heading5",
- "Sign"
- );
- end
- },
- ---_
- ---+ ${hl, Heading 6}
- {
- output = function ()
- return headingGenerator(
- {
- "markdownH6", "@markup.heading.6.markdown", "@markup.heading"
- },
- "#B4BEFE",
- "#7287FD",
-
- "Heading6",
- "Sign"
- );
+--- Is the background "dark"?
+--- Returns values based on this condition(when provided).
+---@param on_light any
+---@param on_dark any
+---@return any
+local is_dark = function (on_light, on_dark)
+ return vim.o.background == "dark" and (on_dark or true) or (on_light or false);
+end
+
+--- Gets {property} from a list of highlight groups.
+---@param property string
+---@param groups string[]
+---@param light any
+---@param dark any
+---@return any
+highlights.get_property = function (property, groups, light, dark)
+ ---+${lua}
+
+ local val;
+
+ for _, item in ipairs(groups) do
+ if
+ vim.fn.hlexists(item) and
+ vim.api.nvim_get_hl(0, { name = item, link = false })[property]
+ then
+ val = vim.api.nvim_get_hl(0, { name = item, link = false })[property];
+ break;
end
- },
+ end
+
+ if val then
+ return vim.list_contains({ "fg", "bg", "sp" }, property) and highlights.rgb(val) or val;
+ end
+
+ return vim.list_contains({ "fg", "bg", "sp" }, property) and highlights.rgb(is_dark(light, dark)) or is_dark(light, dark);
---_
+end
- ---+ ${hl, Horizontal rule}
- {
- output = function (util)
- local from = util.color("bg", { "Normal" }, "#1E1E2E", "#CDD6F4");
- local to = util.color("fg", { "Title" }, "#1e66f5", "#89b4fa");
-
- local _o = {};
-
- for l = 0, 9 do
- local _r = lerp(from[1], to[1], l / 9);
- local _g = lerp(from[2], to[2], l / 9);
- local _b = lerp(from[3], to[3], l / 9);
-
- table.insert(_o, {
- group_name = "Gradient" .. (l + 1),
- value = {
- default = true,
- fg = util.hex({ _r, _g, _b })
- }
- });
- end
+--- Gets color properties from a highlight group.
+---@param opt string
+---@param fallback any
+---@param on_light any
+---@param on_dark any
+---@return any
+---@deprecated
+highlights.color = function (opt, fallback, on_light, on_dark)
+ vim.notify("[ markview.nvim ]: highlights.color is deprecated. Use 'highlights.get_property' instead", vim.log.levels.WARN);
+ highlights.get_property(opt, fallback, on_light, on_dark);
+end
- return _o;
- end
- },
+--- Generates a heading highlight group.
+---@return config.hl
+---@deprecated
+highlights.generate_heading = function (opts)
+ ---+${lua}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ opts.bg_fallbacks or { "Normal" },
+ opts.light_bg or "#FFFFFF",
+ opts.dark_bg or "#000000"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ opts.fallbacks,
+ opts.light_fg or "#000000",
+ opts.dark_fg or "#FFFFFF"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = opts.alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
+ };
---_
+end
+
+--- Generates a highlight group.
+---@param opts { source_opt: string?, output_opt: string?, hl_opts: config.hl?, source: string[], fallback_light: string, fallback_dark: string }
+---@return config.hl
+highlights.hl_generator = function (opts)
+ local hi = highlights.get_property(
+ opts.source_opt or "fg",
+ opts.source or { "Normal" },
+ opts.fallback_light or "#000000",
+ opts.fallback_dark or "#FFFFFF"
+ );
+
+ return vim.tbl_extend("force", {
+ [opts.output_opt or "fg"] = highlights.rgb_to_hex(hi)
+ }, opts.hl_opts or {})
+end
+
+---@type { [string]: function }
+highlights.dynamic = {
+ ---+${lua}
+
+ ["0P"] = function ()
+ ---+${hl}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#EFF1F5",
+ "#1E1E2E"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ { "Comment" },
+ "#9CA0B0",
+ "#6C7086"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = vim.g.__mkv_palette_alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local nr_bg = vim.api.nvim_get_hl(0, { name = "LineNr", link = false }).bg
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ {
+ group_name = "MarkviewPalette0",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette0Fg",
+ value = {
+ default = true,
+
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette0Bg",
+ value = {
+ default = true,
- ---+ ${hl, Links}
- {
- output = function (util)
- return {
- group_name = "Hyperlink",
+ bg = highlights.rgb_to_hex(res_bg),
+ }
+ },
+ {
+ group_name = "MarkviewPalette0Sign",
value = {
default = true,
- link = "@markup.link.label.markdown_inline"
+
+ bg = nr_bg,
+ fg = highlights.rgb_to_hex(h_fg)
}
}
- end
- },
- {
- output = function (util)
- return {
- group_name = "ImageLink",
+ };
+ ---_
+ end,
+ ["1P"] = function ()
+ ---+${hl}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#EFF1F5",
+ "#1E1E2E"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ { "markdownH1", "@markup.heading.1.markdown", "@markup.heading" },
+ "#D20F39",
+ "#F38BA8"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = vim.g.__mkv_palette_alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local nr_bg = vim.api.nvim_get_hl(0, { name = "LineNr", link = false }).bg
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ {
+ group_name = "MarkviewPalette1",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette1Fg",
+ value = {
+ default = true,
+
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette1Bg",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ }
+ },
+ {
+ group_name = "MarkviewPalette1Sign",
value = {
default = true,
- link = "@markup.link.label.markdown_inline"
+
+ bg = nr_bg,
+ fg = highlights.rgb_to_hex(h_fg)
}
}
- end
- },
- {
- output = function (util)
- return {
- group_name = "Email",
+ };
+ ---_
+ end,
+ ["2P"] = function ()
+ ---+${hl}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#EFF1F5",
+ "#1E1E2E"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ { "markdownH2", "@markup.heading.2.markdown", "@markup.heading" },
+ "#FAB387",
+ "#FE640B"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = vim.g.__mkv_palette_alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local nr_bg = vim.api.nvim_get_hl(0, { name = "LineNr", link = false }).bg
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ {
+ group_name = "MarkviewPalette2",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette2Fg",
+ value = {
+ default = true,
+
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette2Bg",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ }
+ },
+ {
+ group_name = "MarkviewPalette2Sign",
value = {
default = true,
- link = "@markup.link.url.markdown_inline"
+
+ bg = nr_bg,
+ fg = highlights.rgb_to_hex(h_fg)
}
}
- end
- },
- ---_
+ };
+ ---_
+ end,
+ ["3P"] = function ()
+ ---+${hl}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#EFF1F5",
+ "#1E1E2E"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ { "markdownH3", "@markup.heading.3.markdown", "@markup.heading" },
+ "#DF8E1D",
+ "#F9E2AF"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = vim.g.__mkv_palette_alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local nr_bg = vim.api.nvim_get_hl(0, { name = "LineNr", link = false }).bg
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ {
+ group_name = "MarkviewPalette3",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette3Fg",
+ value = {
+ default = true,
+
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette3Bg",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ }
+ },
+ {
+ group_name = "MarkviewPalette3Sign",
+ value = {
+ default = true,
- ---+ ${hl, Latex}
- {
- output = function (util)
- local sub = util.color("bg", { "DiagnosticWarn" }, "#DF8E1D", "#F9E3AF");
- local sup = util.color("bg", { "DiagnosticOk" }, "#40a02b", "#a6e3a1");
-
- local bg = util.color("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
-
- return {
- {
- group_name = "LatexSubscript",
- value = {
- default = true,
- fg = util.hex(util.opacify(sub, bg, 0.6)),
- italic = true
- }
- },
- {
- group_name = "LatexSuperscript",
- value = {
- default = true,
- fg = util.hex(util.opacify(sup, bg, 0.6)),
- italic = true
- }
+ bg = nr_bg,
+ fg = highlights.rgb_to_hex(h_fg)
}
}
- end
- },
- ---_
+ };
+ ---_
+ end,
+ ["4P"] = function ()
+ ---+${hl}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#EFF1F5",
+ "#1E1E2E"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ { "markdownH4", "@markup.heading.4.markdown", "@markup.heading" },
+ "#40A02B",
+ "#A6E3A1"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = vim.g.__mkv_palette_alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local nr_bg = vim.api.nvim_get_hl(0, { name = "LineNr", link = false }).bg
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ {
+ group_name = "MarkviewPalette4",
+ value = {
+ default = true,
- ---+ ${hl, List items}
- {
- output = function ()
- return hlGenerator({ "DiagnosticWarn" }, "#DF8E1D", "#F9E3AF", "ListItemMinus");
- end
- },
- {
- output = function ()
- return hlGenerator({ "DiagnosticOk" }, "#40a02b", "#a6e3a1", "ListItemPlus");
- end
- },
- {
- output = function ()
- local fg = highlights.color("bg", { "@comment.note" }, nil, nil) or highlights.color("fg", { "@comment.note" }, "#1e66f5", "#89b4fa");
-
- return {
- {
- group_name = "MarkviewListItemStar",
- value = {
- default = true,
- fg = highlights.hex(fg),
- }
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
}
- };
- end
- },
- ---_
+ },
+ {
+ group_name = "MarkviewPalette4Fg",
+ value = {
+ default = true,
- ---+ ${hl, Tables}
- {
- output = function ()
- local fg = highlights.color("bg", { "@comment.note" }, nil, nil) or highlights.color("fg", { "@comment.note" }, "#1e66f5", "#89b4fa");
- local headerFg = highlights.color("fg", { "DiagnosticInfo" }, nil, nil) or highlights.color("fg", { "@comment.note" }, "#179299", "#94e2d5");
-
- return {
- {
- group_name = "TableHeader",
- value = {
- default = true,
- fg = highlights.hex(headerFg),
- }
- },
- {
- group_name = "TableBorder",
- value = {
- default = true,
- fg = highlights.hex(fg),
- }
- },
- {
- group_name = "TableAlignCenter",
- value = {
- default = true,
- fg = highlights.hex(headerFg),
- }
- },
- {
- group_name = "TableAlignLeft",
- value = {
- default = true,
- fg = highlights.hex(headerFg),
- }
- },
- {
- group_name = "TableAlignRight",
- value = {
- default = true,
- fg = highlights.hex(headerFg),
- }
+ fg = highlights.rgb_to_hex(h_fg)
}
- };
- end
- },
- ---_
-};
+ },
+ {
+ group_name = "MarkviewPalette4Bg",
+ value = {
+ default = true,
----@type markview.conf.hl[]
-highlights.dark = {
- ---+ ${hl, Dark static highlight group}
- {
- group_name = "MarkviewTableHeader",
- value = {
- default = true,
- fg = "#89dceb",
- }
- },
- {
- group_name = "MarkviewTableBorder",
- value = {
- default = true,
- fg = "#89b4fa",
- }
- },
- {
- group_name = "MarkviewTableAlignCenter",
- value = {
- default = true,
- fg = "#89dceb",
- }
- },
- {
- group_name = "MarkviewTableAlignLeft",
- value = {
- default = true,
- fg = "#89dceb",
- }
- },
- {
- group_name = "MarkviewTableAlignRight",
- value = {
- default = true,
- fg = "#89dceb",
- }
- },
- {
- group_name = "MarkviewListItemStar",
- value = {
- default = true,
- fg = "#89b4fa",
- }
- },
- {
- group_name = "MarkviewListItemPlus",
- value = {
- default = true,
- fg = "#a6e3a1",
- }
- },
- {
- group_name = "MarkviewListItemMinus",
- value = {
- default = true,
- fg = "#f9e2af",
- }
- },
- {
- group_name = "MarkviewLatexSubscript",
- value = {
- fg = "#a1947b",
- default = true,
- italic = true,
- }
- },
- {
- group_name = "MarkviewLatexSuperscript",
- value = {
- fg = "#6f9473",
- default = true,
- italic = true,
- }
- },
- {
- group_name = "MarkviewGradient1",
- value = {
- default = true,
- fg = "#1e1e2e",
- }
- },
- {
- group_name = "MarkviewGradient2",
- value = {
- default = true,
- fg = "#292e44",
- }
- },
- {
- group_name = "MarkviewGradient3",
- value = {
- default = true,
- fg = "#353f5b",
- }
- },
- {
- group_name = "MarkviewGradient4",
- value = {
- default = true,
- fg = "#415072",
- }
- },
- {
- group_name = "MarkviewGradient5",
- value = {
- default = true,
- fg = "#4d6088",
- }
- },
- {
- group_name = "MarkviewGradient6",
- value = {
- default = true,
- fg = "#59719f",
- }
- },
- {
- group_name = "MarkviewGradient7",
- value = {
- default = true,
- fg = "#6582b6",
- }
- },
- {
- group_name = "MarkviewGradient8",
- value = {
- default = true,
- fg = "#7192cc",
- }
- },
- {
- group_name = "MarkviewGradient9",
- value = {
- default = true,
- fg = "#7da3e3",
- }
- },
- {
- group_name = "MarkviewGradient10",
- value = {
- default = true,
- fg = "#89b4fa",
- }
- },
- {
- group_name = "MarkviewHeading6",
- value = {
- bg = "#434662",
- default = true,
- fg = "#b4befe",
- }
- },
- {
- group_name = "MarkviewHeading6Sign",
- value = {
- default = true,
- fg = "#b4befe",
- }
- },
- {
- group_name = "MarkviewHeading5",
- value = {
- bg = "#33485d",
- default = true,
- fg = "#74c7ec",
- }
- },
- {
- group_name = "MarkviewHeading5Sign",
- value = {
- default = true,
- fg = "#74c7ec",
- }
- },
- {
- group_name = "MarkviewHeading4",
- value = {
- bg = "#404f4a",
- default = true,
- fg = "#a6e3a1",
- }
- },
- {
- group_name = "MarkviewHeading4Sign",
- value = {
- default = true,
- fg = "#a6e3a1",
- }
- },
- {
- group_name = "MarkviewHeading3",
- value = {
- bg = "#544f4e",
- default = true,
- fg = "#f9e2af",
- }
- },
- {
- group_name = "MarkviewHeading3Sign",
- value = {
- default = true,
- fg = "#f9e2af",
- }
- },
- {
- group_name = "MarkviewHeading2",
- value = {
- bg = "#554344",
- default = true,
- fg = "#fab387",
- }
- },
- {
- group_name = "MarkviewHeading2Sign",
- value = {
- default = true,
- fg = "#fab387",
- }
- },
- {
- group_name = "MarkviewHeading1",
- value = {
- bg = "#53394c",
- default = true,
- fg = "#f38ba8",
- }
- },
- {
- group_name = "MarkviewHeading1Sign",
- value = {
- default = true,
- fg = "#f38ba8",
- }
- },
- {
- group_name = "MarkviewCode",
- value = {
- default = true,
- bg = "#28283d",
- }
- },
- {
- group_name = "MarkviewCodeInfo",
- value = {
- bg = "#28283d",
- default = true,
- fg = "#9399b2",
- }
- },
- {
- group_name = "MarkviewInlineCode",
- value = {
- default = true,
- bg = "#32324c",
- }
- },
- {
- group_name = "MarkviewIcon1",
- value = {
- bg = "#28283d",
- default = true,
- fg = "#f38ba8",
- }
- },
- {
- group_name = "MarkviewIcon1Sign",
- value = {
- default = true,
- fg = "#f38ba8",
- }
- },
- {
- group_name = "MarkviewIcon1Fg",
- value = {
- default = true,
- fg = "#f38ba8",
- }
- },
- {
- group_name = "MarkviewIcon2",
- value = {
- bg = "#28283d",
- default = true,
- fg = "#fab387",
- }
- },
- {
- group_name = "MarkviewIcon2Sign",
- value = {
- default = true,
- fg = "#fab387",
- }
- },
- {
- group_name = "MarkviewIcon2Fg",
- value = {
- default = true,
- fg = "#fab387",
- }
- },
- {
- group_name = "MarkviewIcon3",
- value = {
- bg = "#28283d",
- default = true,
- fg = "#f9e2af",
- }
- },
- {
- group_name = "MarkviewIcon3Sign",
- value = {
- default = true,
- fg = "#f9e2af",
- }
- },
- {
- group_name = "MarkviewIcon3Fg",
- value = {
- default = true,
- fg = "#f9e2af",
- }
- },
- {
- group_name = "MarkviewIcon4",
- value = {
- bg = "#28283d",
- default = true,
- fg = "#a6e3a1",
- }
- },
- {
- group_name = "MarkviewIcon4Sign",
- value = {
- default = true,
- fg = "#a6e3a1",
- }
- },
- {
- group_name = "MarkviewIcon4Fg",
- value = {
- default = true,
- fg = "#a6e3a1",
- }
- },
- {
- group_name = "MarkviewIcon5",
- value = {
- bg = "#28283d",
- default = true,
- fg = "#74c7ec",
- }
- },
- {
- group_name = "MarkviewIcon5Sign",
- value = {
- default = true,
- fg = "#74c7ec",
- }
- },
- {
- group_name = "MarkviewIcon5Fg",
- value = {
- default = true,
- fg = "#74c7ec",
- }
- },
- {
- group_name = "MarkviewIcon6",
- value = {
- bg = "#28283d",
- default = true,
- fg = "#b4befe",
- }
- },
- {
- group_name = "MarkviewIcon6Sign",
- value = {
- default = true,
- fg = "#b4befe",
- }
- },
- {
- group_name = "MarkviewIcon6Fg",
- value = {
+ bg = highlights.rgb_to_hex(res_bg),
+ }
+ },
+ {
+ group_name = "MarkviewPalette4Sign",
+ value = {
+ default = true,
+
+ bg = nr_bg,
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ }
+ };
+ ---_
+ end,
+ ["5P"] = function ()
+ ---+${hl}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#EFF1F5",
+ "#1E1E2E"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ { "markdownH5", "@markup.heading.5.markdown", "@markup.heading" },
+ "#209FB5",
+ "#74C7EC"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = vim.g.__mkv_palette_alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local nr_bg = vim.api.nvim_get_hl(0, { name = "LineNr", link = false }).bg
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ {
+ group_name = "MarkviewPalette5",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette5Fg",
+ value = {
+ default = true,
+
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette5Bg",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ }
+ },
+ {
+ group_name = "MarkviewPalette5Sign",
+ value = {
+ default = true,
+
+ bg = nr_bg,
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ }
+ };
+ ---_
+ end,
+ ["6P"] = function ()
+ ---+${hl}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#EFF1F5",
+ "#1E1E2E"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ { "markdownH6", "@markup.heading.6.markdown", "@markup.heading" },
+ "#7287FD",
+ "#B4BEFE"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = vim.g.__mkv_palette_alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local nr_bg = vim.api.nvim_get_hl(0, { name = "LineNr", link = false }).bg
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ {
+ group_name = "MarkviewPalette6",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette6Fg",
+ value = {
+ default = true,
+
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette6Bg",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ }
+ },
+ {
+ group_name = "MarkviewPalette6Sign",
+ value = {
+ default = true,
+
+ bg = nr_bg,
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ }
+ };
+ ---_
+ end,
+ ["7P"] = function ()
+ ---+${hl}
+ local vim_bg = highlights.rgb_to_lab(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#EFF1F5",
+ "#1E1E2E"
+ ));
+ local h_fg = highlights.rgb_to_lab(highlights.get_property(
+ "fg",
+ { "@conditional", "@keyword.conditional", "Conditional" },
+ "#8839EF",
+ "#CBA6F7"
+ ));
+
+ local l_bg = highlights.lumen(highlights.lab_to_rgb(vim_bg));
+ local alpha = vim.g.__mkv_palette_alpha or (l_bg > 0.5 and 0.15 or 0.25);
+
+ local nr_bg = vim.api.nvim_get_hl(0, { name = "LineNr", link = false }).bg
+ local res_bg = highlights.lab_to_rgb(highlights.mix(h_fg, vim_bg, alpha, 1 - alpha));
+
+ vim_bg = highlights.lab_to_rgb(vim_bg);
+ h_fg = highlights.lab_to_rgb(h_fg);
+
+ return {
+ {
+ group_name = "MarkviewPalette7",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette7Fg",
+ value = {
+ default = true,
+
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ },
+ {
+ group_name = "MarkviewPalette7Bg",
+ value = {
+ default = true,
+
+ bg = highlights.rgb_to_hex(res_bg),
+ }
+ },
+ {
+ group_name = "MarkviewPalette7Sign",
+ value = {
+ default = true,
+
+ bg = nr_bg,
+ fg = highlights.rgb_to_hex(h_fg)
+ }
+ }
+ };
+ ---_
+ end,
+
+ ---+${hl, Block quotes}
+ ["BlockQuoteDefault"] = function ()
+ return {
default = true,
- fg = "#b4befe",
- }
- },
- {
- group_name = "MarkviewCheckboxUnchecked",
- value = {
+ link = "MarkviewPalette0Fg"
+ };
+ end,
+
+ ["BlockQuoteError"] = function ()
+ return {
default = true,
- fg = "#f38ba8",
- }
- },
- {
- group_name = "MarkviewCheckboxProgress",
- value = {
+ link = "MarkviewPalette1Fg"
+ };
+ end,
+
+ ["BlockQuoteNote"] = function ()
+ return {
default = true,
- fg = "#cba6f7",
- }
- },
- {
- group_name = "MarkviewCheckboxPending",
- value = {
+ link = "MarkviewPalette5Fg"
+ };
+ end,
+
+ ["BlockQuoteOk"] = function ()
+ return {
default = true,
- fg = "#f9e2af",
- }
- },
- {
- group_name = "MarkviewCheckboxChecked",
- value = {
+ link = "MarkviewPalette4Fg"
+ };
+ end,
+
+ ["BlockQuoteSpecial"] = function ()
+ return {
default = true,
- fg = "#a6e3a1",
- }
- },
- {
- group_name = "MarkviewCheckboxCancelled",
- value = {
+ link = "MarkviewPalette3Fg"
+ };
+ end,
+
+ ["BlockQuoteWarn"] = function ()
+ return {
default = true,
- fg = "#9399b2",
- }
- },
- {
- group_name = "MarkviewCheckboxStriked",
- value = {
+ link = "MarkviewPalette2Fg"
+ };
+ end,
+ ---_
+ ---+${hl, Checkboxes}
+ ["CheckboxCancelled"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette0Fg"
+ };
+ end,
+ ["CheckboxChecked"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette4Fg"
+ };
+ end,
+ ["CheckboxPending"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette2Fg"
+ };
+ end,
+ ["CheckboxProgress"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette6Fg"
+ };
+ end,
+ ["CheckboxUnchecked"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette1Fg"
+ };
+ end,
+ ["CheckboxStriked"] = function ()
+ return {
default = true,
strikethrough = true,
- bg = "#28283d",
- }
- },
- {
- group_name = "MarkviewBlockQuoteWarn",
- value = {
- default = true,
- fg = "#f9e2af",
- }
- },
- {
- group_name = "MarkviewBlockQuoteSpecial",
- value = {
- default = true,
- fg = "#cba6f7",
- }
- },
- {
- group_name = "MarkviewBlockQuoteOk",
- value = {
- default = true,
- fg = "#a6e3a1",
- }
- },
- {
- group_name = "MarkviewBlockQuoteNote",
- value = {
- default = true,
- fg = "#89b4fa",
- }
- },
- {
- group_name = "MarkviewBlockQuoteError",
- value = {
- default = true,
- fg = "#f38ba8",
- }
- },
- {
- group_name = "MarkviewBlockQuoteDefault",
- value = {
- default = true,
- fg = "#9399b2",
- }
- },
- {
- group_name = "MarkviewHyperlink",
- value = {
- link = "@markup.link.label.markdown_inline",
- default = true,
- }
- },
- {
- group_name = "MarkviewImageLink",
- value = {
- link = "@markup.link.label.markdown_inline",
- default = true,
- }
- },
- {
- group_name = "MarkviewEmail",
- value = {
- link = "@markup.link.url.markdown_inline",
- default = true,
- }
- },
+ fg = vim.api.nvim_get_hl(0, { name = "MarkviewPalette0Fg" }).fg
+ };
+ end,
---_
-};
+ ---+${hl, Code blocks & Inline codes/Injections}
+ ["Code"] = function ()
+ local vim_bg = highlights.rgb_to_hsl(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#FFFFFF",
+ "#000000"
+ ));
+
+ if vim_bg[3] > 0.5 then
+ vim_bg[3] = clamp(vim_bg[3] - 0.05, 0.1, 0.9);
+ else
+ vim_bg[3] = clamp(vim_bg[3] + 0.05, 0.1, 0.9);
+ end
----@type markview.conf.hl[]
-highlights.light = {
- ---+ ${hl, Light static highlight groups}
- {
- group_name = "MarkviewTableHeader",
- value = {
- fg = "#04a5e5",
- default = true,
- }
- },
- {
- group_name = "MarkviewTableBorder",
- value = {
- fg = "#1e66f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewTableAlignCenter",
- value = {
- fg = "#04a5e5",
- default = true,
- }
- },
- {
- group_name = "MarkviewTableAlignLeft",
- value = {
- fg = "#04a5e5",
- default = true,
- }
- },
- {
- group_name = "MarkviewTableAlignRight",
- value = {
- fg = "#04a5e5",
- default = true,
- }
- },
- {
- group_name = "MarkviewListItemStar",
- value = {
- fg = "#1e66f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewListItemPlus",
- value = {
- fg = "#40a02b",
- default = true,
- }
- },
- {
- group_name = "MarkviewListItemMinus",
- value = {
- fg = "#df8e1d",
- default = true,
- }
- },
- {
- group_name = "MarkviewLatexSubscript",
- value = {
- italic = true,
- fg = "#e5b573",
- default = true,
- }
- },
- {
- group_name = "MarkviewLatexSuperscript",
- value = {
- italic = true,
- fg = "#86c07b",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient1",
- value = {
- fg = "#eff1f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient2",
- value = {
- fg = "#d7e1f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient3",
- value = {
- fg = "#c0d2f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient4",
- value = {
- fg = "#a9c2f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient5",
- value = {
- fg = "#92b3f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient6",
- value = {
- fg = "#7aa3f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient7",
- value = {
- fg = "#6394f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient8",
- value = {
- fg = "#4c84f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient9",
- value = {
- fg = "#3575f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewGradient10",
- value = {
- fg = "#1e66f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading6",
- value = {
- bg = "#dbe1fe",
- fg = "#7287fd",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading6Sign",
- value = {
- fg = "#7287fd",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading5",
- value = {
- bg = "#c7e7ec",
- fg = "#209fb5",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading5Sign",
- value = {
- fg = "#209fb5",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading4",
- value = {
- bg = "#cfe7ca",
- fg = "#40a02b",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading4Sign",
- value = {
- fg = "#40a02b",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading3",
- value = {
- bg = "#f7e2c6",
- fg = "#df8e1d",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading3Sign",
- value = {
- fg = "#df8e1d",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading2",
- value = {
- bg = "#fed8c2",
- fg = "#fe640b",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading2Sign",
- value = {
- fg = "#fe640b",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading1",
- value = {
- bg = "#f3c3cd",
- fg = "#d20f39",
- default = true,
- }
- },
- {
- group_name = "MarkviewHeading1Sign",
- value = {
- fg = "#d20f39",
- default = true,
- }
- },
- {
- group_name = "MarkviewCode",
- value = {
- bg = "#dfe3eb",
- default = true,
- }
- },
- {
- group_name = "MarkviewCodeInfo",
- value = {
- default = true,
- fg = "#7c7f93",
- bg = "#dfe3eb",
- }
- },
- {
- group_name = "MarkviewInlineCode",
- value = {
- bg = "#cfd5e1",
- default = true,
- }
- },
- {
- group_name = "MarkviewIcon1",
- value = {
- default = true,
- fg = "#d20f39",
- bg = "#dfe3eb",
- }
- },
- {
- group_name = "MarkviewIcon1Sign",
- value = {
- default = true,
- fg = "#d20f39",
- }
- },
- {
- group_name = "MarkviewIcon1Fg",
- value = {
- fg = "#d20f39",
- default = true,
- }
- },
- {
- group_name = "MarkviewIcon2",
- value = {
- default = true,
- fg = "#fe640b",
- bg = "#dfe3eb",
- }
- },
- {
- group_name = "MarkviewIcon2Sign",
- value = {
- default = true,
- fg = "#fe640b",
- }
- },
- {
- group_name = "MarkviewIcon2Fg",
- value = {
- fg = "#fe640b",
- default = true,
- }
- },
- {
- group_name = "MarkviewIcon3",
- value = {
- default = true,
- fg = "#df8e1d",
- bg = "#dfe3eb",
- }
- },
- {
- group_name = "MarkviewIcon3Sign",
- value = {
- default = true,
- fg = "#df8e1d",
- }
- },
- {
- group_name = "MarkviewIcon3Fg",
- value = {
- fg = "#df8e1d",
- default = true,
- }
- },
- {
- group_name = "MarkviewIcon4",
- value = {
- default = true,
- fg = "#40a02b",
- bg = "#dfe3eb",
- }
- },
- {
- group_name = "MarkviewIcon4Sign",
- value = {
- default = true,
- fg = "#40a02b",
- }
- },
- {
- group_name = "MarkviewIcon4Fg",
- value = {
- fg = "#40a02b",
- default = true,
- }
- },
- {
- group_name = "MarkviewIcon5",
- value = {
- default = true,
- fg = "#209fb5",
- bg = "#dfe3eb",
- }
- },
- {
- group_name = "MarkviewIcon5Sign",
- value = {
- default = true,
- fg = "#209fb5",
- }
- },
- {
- group_name = "MarkviewIcon5Fg",
- value = {
- fg = "#209fb5",
- default = true,
- }
- },
- {
- group_name = "MarkviewIcon6",
- value = {
- default = true,
- fg = "#7287fd",
- bg = "#dfe3eb",
- }
- },
- {
- group_name = "MarkviewIcon6Sign",
- value = {
- default = true,
- fg = "#7287fd",
- }
- },
- {
- group_name = "MarkviewIcon6Fg",
- value = {
- fg = "#7287fd",
- default = true,
- }
- },
- {
- group_name = "MarkviewCheckboxUnchecked",
- value = {
- fg = "#d20f39",
- default = true,
- }
- },
- {
- group_name = "MarkviewCheckboxProgress",
- value = {
- fg = "#8839ef",
- default = true,
- }
- },
- {
- group_name = "MarkviewCheckboxPending",
- value = {
- fg = "#df8e1d",
- default = true,
- }
- },
- {
- group_name = "MarkviewCheckboxChecked",
- value = {
- fg = "#40a02b",
- default = true,
- }
- },
- {
- group_name = "MarkviewCheckboxCancelled",
- value = {
- fg = "#7c7f93",
- default = true,
- }
- },
- {
- group_name = "MarkviewCheckboxStriked",
- value = {
- bg = "#dfe3eb",
- strikethrough = true,
- default = true,
- }
- },
- {
- group_name = "MarkviewBlockQuoteWarn",
- value = {
- fg = "#df8e1d",
- default = true,
- }
- },
- {
- group_name = "MarkviewBlockQuoteSpecial",
- value = {
- fg = "#8839ef",
- default = true,
- }
- },
- {
- group_name = "MarkviewBlockQuoteOk",
- value = {
- fg = "#40a02b",
- default = true,
- }
- },
- {
- group_name = "MarkviewBlockQuoteNote",
- value = {
- fg = "#1e66f5",
- default = true,
- }
- },
- {
- group_name = "MarkviewBlockQuoteError",
- value = {
- fg = "#d20f39",
+ vim_bg = highlights.hsl_to_rgb(vim_bg);
+
+ return {
+ bg = highlights.rgb_to_hex(vim_bg)
+ };
+ end,
+ ["CodeInfo"] = function ()
+ local vim_bg = highlights.rgb_to_hsl(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#FFFFFF",
+ "#000000"
+ ));
+ local code_fg = highlights.get_property(
+ "fg",
+ { "Comment" },
+ "#9CA0B0",
+ "#6C7086"
+ );
+
+ if vim_bg[3] > 0.5 then
+ vim_bg[3] = clamp(vim_bg[3] - 0.05, 0.1, 0.9);
+ else
+ vim_bg[3] = clamp(vim_bg[3] + 0.05, 0.1, 0.9);
+ end
+
+ vim_bg = highlights.hsl_to_rgb(vim_bg);
+
+ return {
+ bg = highlights.rgb_to_hex(vim_bg),
+ fg = highlights.rgb_to_hex(code_fg)
+ };
+ end,
+ ["CodeFg"] = function ()
+ local vim_bg = highlights.rgb_to_hsl(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#FFFFFF",
+ "#000000"
+ ));
+
+ if vim_bg[3] > 0.5 then
+ vim_bg[3] = clamp(vim_bg[3] - 0.05, 0.1, 0.9);
+ else
+ vim_bg[3] = clamp(vim_bg[3] + 0.05, 0.1, 0.9);
+ end
+
+ vim_bg = highlights.hsl_to_rgb(vim_bg);
+
+ return {
+ fg = highlights.rgb_to_hex(vim_bg)
+ };
+ end,
+ ["InlineCode"] = function ()
+ local vim_bg = highlights.rgb_to_hsl(highlights.get_property(
+ "bg",
+ { "Normal" },
+ "#FFFFFF",
+ "#000000"
+ ));
+
+ if vim_bg[3] > 0.5 then
+ vim_bg[3] = clamp(vim_bg[3] - 0.1, 0.1, 0.9);
+ else
+ vim_bg[3] = clamp(vim_bg[3] + 0.1, 0.1, 0.9);
+ end
+
+ vim_bg = highlights.hsl_to_rgb(vim_bg);
+
+ return {
+ bg = highlights.rgb_to_hex(vim_bg)
+ };
+ end,
+
+
+ ["Icon0"] = function ()
+ return highlights.hl_generator({
+ source = { "MarkviewPalette0" },
+ light_fg = "#FE640B",
+ dark_fg = "#FAB387",
+
+ hl_opts = {
+ bg = vim.api.nvim_get_hl(0, { name = "MarkviewCode", link = false }).bg
+ }
+ });
+ end,
+
+ ["Icon1"] = function ()
+ return highlights.hl_generator({
+ source = { "MarkviewPalette1" },
+ light_fg = "#FE640B",
+ dark_fg = "#FAB387",
+
+ hl_opts = {
+ bg = vim.api.nvim_get_hl(0, { name = "MarkviewCode", link = false }).bg
+ }
+ });
+ end,
+
+ ["Icon2"] = function ()
+ return highlights.hl_generator({
+ source = { "MarkviewPalette2" },
+ light_fg = "#FE640B",
+ dark_fg = "#FAB387",
+
+ hl_opts = {
+ bg = vim.api.nvim_get_hl(0, { name = "MarkviewCode", link = false }).bg
+ }
+ });
+ end,
+
+ ["Icon3"] = function ()
+ return highlights.hl_generator({
+ source = { "MarkviewPalette3" },
+ light_fg = "#F9E2AF",
+ dark_fg = "#DF8E1D",
+
+ hl_opts = {
+ bg = vim.api.nvim_get_hl(0, { name = "MarkviewCode", link = false }).bg
+ }
+ });
+ end,
+
+ ["Icon4"] = function ()
+ return highlights.hl_generator({
+ source = { "MarkviewPalette4" },
+ light_fg = "#A6E3A1",
+ dark_fg = "#40A02B",
+
+ hl_opts = {
+ bg = vim.api.nvim_get_hl(0, { name = "MarkviewCode", link = false }).bg
+ }
+ });
+ end,
+
+ ["Icon5"] = function ()
+ return highlights.hl_generator({
+ source = { "MarkviewPalette5" },
+ light_fg = "#74C7EC",
+ dark_fg = "#209FB5",
+
+ hl_opts = {
+ bg = vim.api.nvim_get_hl(0, { name = "MarkviewCode", link = false }).bg
+ }
+ });
+ end,
+
+ ["Icon6"] = function ()
+ return highlights.hl_generator({
+ source = { "MarkviewPalette6" },
+ light_fg = "#B4BEFE",
+ dark_fg = "#7287FD",
+
+ hl_opts = {
+ bg = vim.api.nvim_get_hl(0, { name = "MarkviewCode", link = false }).bg
+ }
+ });
+ end,
+ ---_
+ ---+${hl, Headings}
+ ["Heading1"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette1"
+ };
+ end,
+ ["Heading2"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette2"
+ };
+ end,
+ ["Heading3"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette3"
+ };
+ end,
+ ["heading4"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette4"
+ };
+ end,
+ ["Heading5"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette5"
+ };
+ end,
+ ["Heading6"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette6"
+ };
+ end,
+
+
+ ["Heading1Sign"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette1Sign"
+ };
+ end,
+ ["Heading2Sign"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette2Sign"
+ };
+ end,
+ ["Heading3Sign"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette3Sign"
+ };
+ end,
+ ["heading4Sign"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette4Sign"
+ };
+ end,
+ ["Heading5Sign"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette5Sign"
+ };
+ end,
+ ["Heading6Sign"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette6Sign"
+ };
+ end,
+ ---_
+
+ ["Gradient0"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex(from);
+ };
+ end,
+ ["Gradient1"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+ local to = highlights.get_property("fg", { "Title" }, "#1e66f5", "#89b4fa");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex({
+ lerp(from[1], to[1], 1 / 9),
+ lerp(from[2], to[2], 1 / 9),
+ lerp(from[3], to[3], 1 / 9),
+ });
+ };
+ end,
+ ["Gradient2"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+ local to = highlights.get_property("fg", { "Title" }, "#1e66f5", "#89b4fa");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex({
+ lerp(from[1], to[1], 2 / 9),
+ lerp(from[2], to[2], 2 / 9),
+ lerp(from[3], to[3], 2 / 9),
+ });
+ };
+ end,
+ ["Gradient3"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+ local to = highlights.get_property("fg", { "Title" }, "#1e66f5", "#89b4fa");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex({
+ lerp(from[1], to[1], 3 / 9),
+ lerp(from[2], to[2], 3 / 9),
+ lerp(from[3], to[3], 3 / 9),
+ });
+ };
+ end,
+ ["Gradient4"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+ local to = highlights.get_property("fg", { "Title" }, "#1e66f5", "#89b4fa");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex({
+ lerp(from[1], to[1], 4 / 9),
+ lerp(from[2], to[2], 4 / 9),
+ lerp(from[3], to[3], 4 / 9),
+ });
+ };
+ end,
+ ["Gradient5"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+ local to = highlights.get_property("fg", { "Title" }, "#1e66f5", "#89b4fa");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex({
+ lerp(from[1], to[1], 5 / 9),
+ lerp(from[2], to[2], 5 / 9),
+ lerp(from[3], to[3], 5 / 9),
+ });
+ };
+ end,
+ ["Gradient6"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+ local to = highlights.get_property("fg", { "Title" }, "#1e66f5", "#89b4fa");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex({
+ lerp(from[1], to[1], 6 / 9),
+ lerp(from[2], to[2], 6 / 9),
+ lerp(from[3], to[3], 6 / 9),
+ });
+ };
+ end,
+ ["Gradient7"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+ local to = highlights.get_property("fg", { "Title" }, "#1e66f5", "#89b4fa");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex({
+ lerp(from[1], to[1], 7 / 9),
+ lerp(from[2], to[2], 7 / 9),
+ lerp(from[3], to[3], 7 / 9),
+ });
+ };
+ end,
+ ["Gradient8"] = function ()
+ local from = highlights.get_property("bg", { "Normal" }, "#CDD6F4", "#1E1E2E");
+ local to = highlights.get_property("fg", { "Title" }, "#1e66f5", "#89b4fa");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex({
+ lerp(from[1], to[1], 8 / 9),
+ lerp(from[2], to[2], 8 / 9),
+ lerp(from[3], to[3], 8 / 9),
+ });
+ };
+ end,
+ ["Gradient9"] = function ()
+ local to = highlights.get_property("fg", { "Title" }, "#CDD6F4", "#1E1E2E");
+
+ return {
+ default = true,
+ fg = highlights.rgb_to_hex(to);
+ };
+ end,
+
+ ---+${hl, Links}
+ ["Hyperlink"] = function ()
+ return {
+ default = true,
+ link = "@markup.link.label.markdown_inline"
+ }
+ end,
+
+ ["Image"] = function ()
+ return {
+ default = true,
+ link = "@markup.link.label.markdown_inline"
+ }
+ end,
+
+ ["Email"] = function ()
+ return {
+ default = true,
+ link = "@markup.link.url.markdown_inline"
+ }
+ end,
+ ---_
+ ---+${hl, Latex}
+ ["Subscript"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette3Fg"
+ };
+ end,
+ ["Superscript"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette6Fg"
+ };
+ end,
+ ---_
+ ---+${hl, List Items}
+ ["ListItemMinus"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette2Fg"
+ };
+ end,
+ ["ListItemPlus"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette4Fg"
+ };
+ end,
+ ["ListItemStar"] = function ()
+ return {
+ default = true,
+ link = "MarkviewPalette6Fg"
+ };
+ end,
+ ---_
+ ---+${hl, Tables}
+ ["TableHeader"] = function ()
+ return {
default = true,
- }
- },
- {
- group_name = "MarkviewBlockQuoteDefault",
- value = {
- fg = "#7c7f93",
+ link = "@markup.heading.markdown"
+ };
+ end,
+
+ ["TableBorder"] = function ()
+ return {
default = true,
- }
- },
- {
- group_name = "MarkviewHyperlink",
- value = {
- link = "@markup.link.label.markdown_inline",
+ link = "MarkviewPalette5Fg"
+ };
+ end,
+
+ ["TableAlignLeft"] = function ()
+ return {
default = true,
+ link = "@markup.heading.markdown"
}
- },
- {
- group_name = "MarkviewImageLink",
- value = {
- link = "@markup.link.label.markdown_inline",
+ end,
+
+ ["TableAlignCenter"] = function ()
+ return {
default = true,
+ link = "@markup.heading.markdown"
}
- },
- {
- group_name = "MarkviewEmail",
- value = {
- link = "@markup.link.url.markdown_inline",
+ end,
+
+ ["TableAlignRight"] = function ()
+ return {
default = true,
+ link = "@markup.heading.markdown"
}
- },
+ end,
+ ---_
---_
-}
+};
+
+highlights.groups = highlights.dynamic;
+
+--- Setup function.
+---@param opt { [string]: config.hl }?
+highlights.setup = function (opt)
+ if type(opt) == "table" then
+ highlights.groups = vim.tbl_extend("force", highlights.groups, opt);
+ end
+
+ highlights.create(highlights.groups);
+end
return highlights;
diff --git a/lua/markview/html_renderer.lua b/lua/markview/html_renderer.lua
deleted file mode 100644
index 7d633da..0000000
--- a/lua/markview/html_renderer.lua
+++ /dev/null
@@ -1,367 +0,0 @@
-local html = {};
-
-html.namespace = nil;
-
----@type table HTML entities lookup table
-html.entities = {
- ---+ ${class, HTML entities lookup table}
- 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 = "โ"
- ---_
-}
-
---- Gets an HTML entity & it's character width
----@param string string
----@return string
-html.get_entity = function (string)
- return html.entities[string];
-end
---- Sets the namespace
----@param ns integer
-html.set_namespace = function (ns)
- html.namespace = ns;
-end
-
---- Fixes a highlight group name
----@param hl string?
----@return string?
-local set_hl = function (hl)
- if type(hl) ~= "string" then
- return;
- end
-
- if vim.fn.hlexists("Markview" .. hl) == 1 then
- return "Markview" .. hl;
- elseif vim.fn.hlexists("Markview_" .. hl) == 1 then
- return "Markview_" .. hl;
- else
- return hl;
- end
-end
-
---- Renders HTML tags
----@param buffer integer
----@param content table
----@param user_config markview.html.tags
-html.render_inline = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- local html_conf = user_config.default or {};
-
- if user_config.configs[string.lower(content.tag)] then
- html_conf = user_config.configs[string.lower(content.tag)];
- end
-
- if html_conf.conceal ~= false then
- vim.api.nvim_buf_set_extmark(buffer, html.namespace, content.row_start, content.start_tag_col_start, {
- end_col = content.start_tag_col_end,
- conceal = ""
- });
- vim.api.nvim_buf_set_extmark(buffer, html.namespace, content.row_start, content.end_tag_col_start, {
- end_col = content.end_tag_col_end,
- conceal = ""
- });
- end
-
- if html_conf.hl then
- vim.api.nvim_buf_add_highlight(buffer, html.namespace, html_conf.hl, content.row_start, content.start_tag_col_end, content.end_tag_col_start);
- end
-end
-
---- Renders HTML entities
----@param buffer integer
----@param content table
----@param user_config markview.html.entities
-html.render_entities = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- local filtered_entity = content.text:gsub("[&;]", "");
- local entity = html.get_entity(filtered_entity);
-
-
- if not entity then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, html.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { entity, set_hl(user_config.hl) }
- },
-
- end_col = content.col_end,
- conceal = ""
- });
-end
-
---- Renders latex
----@param render_type string
----@param buffer integer
----@param content table
----@param config_table markview.configuration
-html.render = function (render_type, buffer, content, config_table)
- if not config_table or not config_table.html then
- return;
- elseif config_table.html and config_table.html.enable == false then
- return;
- end
-
- ---@type markview.conf.html
- local conf = config_table.html;
-
- if render_type == "html_inline" then
- pcall(html.render_inline, buffer, content, conf.tags);
- elseif render_type == "html_entity" then
- pcall(html.render_entities, buffer, content, conf.entities);
- end
-end
-
-return html;
diff --git a/lua/markview/keymaps.lua b/lua/markview/keymaps.lua
deleted file mode 100644
index 96a0d6c..0000000
--- a/lua/markview/keymaps.lua
+++ /dev/null
@@ -1,81 +0,0 @@
-local keymaps = {};
-
----@type table[] A list `parsed contents` containing different types of links
-keymaps.views = {};
-keymaps.on_bufs = {};
-
-keymaps.create_command = function (buffer)
- vim.api.nvim_buf_create_user_command(buffer, "MarkOpen", function ()
- local buf_links = keymaps.views[buffer] or {};
- local cursor = vim.api.nvim_win_get_cursor(0);
-
- --- Iterate over all the available links
- for _, link in ipairs(buf_links) do
- --- Cursor isn't on the line of the link
- if link.row_start + 1 ~= cursor[1] then
- goto continue;
- end
-
- --- Cursor isn't on the column range of the link
- if cursor[2] < link.col_start or cursor[2] > link.col_end then
- goto continue;
- end
-
- --- Modify the address and open it in `vim.ui.open()`
- local cmd, err = vim.ui.open(vim.fn.fnamemodify(link.address, ":~"))
-
- if err then
- vim.notify("[ Markview.nvim ] : Failed to open: " .. link.address, vim.diagnostic.severity.WARN)
- break;
- end
-
- if cmd then
- cmd:wait();
- break;
- end
-
- ::continue::
- end
-
- local def_cmd, def_err = vim.ui.open(vim.fn.expand(""))
-
- if def_err then
- vim.notify("[ Markview.nvim ] : Failed to open: " .. vim.fn.expand(""), vim.diagnostic.severity.WARN)
- end
-
- if def_cmd then
- def_cmd:wait();
- end
- end, {})
-end
-
-keymaps.createKeymap = function (buffer)
- vim.api.nvim_buf_set_keymap(buffer, "n", "gx", "MarkOpen", {
- desc = "Opens the link under cursor"
- })
-end
-
---- Initializes the keymaps
----@param buffer integer
----@param parsed_content table
----@param config_table table?
-keymaps.init = function (buffer, parsed_content, config_table)
- if parsed_content ~= nil then
- keymaps.views[buffer] = {};
- end
-
- for _, content in ipairs(parsed_content --[[@as table]]) do
- if content.type:match("^link_") then
- table.insert(keymaps.views[buffer], content);
- end
- end
-
- if not vim.list_contains(keymaps.on_bufs, buffer) then
- keymaps.createKeymap(buffer);
- keymaps.create_command(buffer);
-
- table.insert(keymaps.on_bufs, buffer)
- end
-end
-
-return keymaps;
diff --git a/lua/markview/languages.lua b/lua/markview/languages.lua
deleted file mode 100644
index 24bf001..0000000
--- a/lua/markview/languages.lua
+++ /dev/null
@@ -1,487 +0,0 @@
-local languages = {};
-
---- Table for icon & sign highlight group
----@type { [string]: string[]} }
-languages.hls = {
- default = { "MarkviewIcon5", "MarkviewIcon5Sign" },
-
- ["c"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["cpp"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["java"] = { "MarkviewIcon1", "MarkviewIcon1Sign" },
- ["py"] = { "MarkviewIcon2", "MarkviewIcon2Sign" },
- ["js"] = { "MarkviewIcon3", "MarkviewIcon3Sign" },
- ["ts"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["rb"] = { "MarkviewIcon1", "MarkviewIcon1Sign" },
- ["php"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["cs"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["swift"] = { "MarkviewIcon2", "MarkviewIcon2Sign" },
- ["kt"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["go"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["rs"] = { "MarkviewIcon2", "MarkviewIcon2Sign" },
- ["r"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["pl"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["lua"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["sh"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["bash"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["ps1"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["scala"] = { "MarkviewIcon1", "MarkviewIcon1Sign" },
- ["hs"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["jl"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["clj"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["dart"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["grrovy"]= { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["erl"] = { "MarkviewIcon1", "MarkviewIcon1Sign" },
- ["ex"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["elm"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["f90"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["ml"] = { "MarkviewIcon2", "MarkviewIcon2Sign" },
- ["sql"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["p"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["nim"] = { "MarkviewIcon3", "MarkviewIcon3Sign" },
- ["coffee"]= { "MarkviewIcon2", "MarkviewIcon2Sign" },
- ["fs"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["hx"] = { "MarkviewIcon2", "MarkviewIcon2Sign" },
- ["asp"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["cl"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["gd"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["glsl"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["h"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["hpp"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["hrl"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["mjs"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["md"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["styl"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["toml"] = { "MarkviewIcon1", "MarkviewIcon1Sign" },
- ["vim"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["wxs"] = { "MarkviewIcon3", "MarkviewIcon3Sign" },
- ["yaml"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["zsh"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["exs"] = { "MarkviewIcon6", "MarkviewIcon6Sign" },
- ["fnl"] = { "MarkviewIcon3", "MarkviewIcon3Sign" },
- ["gsl"] = { "MarkviewIcon4", "MarkviewIcon4Sign" },
- ["gs"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
- ["scss"] = { "MarkviewIcon2", "MarkviewIcon2Sign" },
- ["zig"] = { "MarkviewIcon3", "MarkviewIcon3Sign" },
- ["html"] = { "MarkviewIcon1", "MarkviewIcon1Sign" },
- ["css"] = { "MarkviewIcon5", "MarkviewIcon5Sign" },
-};
-
---- Icons table for various filetypes
----@type { [string]: string }
-languages.icons = {
- default = "๓ฐฎ ",
-
- ["c"] = "๎ ",
- ["cpp"] = "๎ ",
- ["java"] = "๎ธ ",
- ["py"] = "๎ ",
- ["js"] = "๎ ",
- ["ts"] = "๎จ ",
- ["rb"] = "๎พ ",
- ["php"] = "๎ ",
- ["cs"] = "๎ ",
- ["swift"] = "๎ ",
- ["kt"] = "๎ด ",
- ["go"] = "๎ง ",
- ["rs"] = "๎ ",
- ["r"] = "๓ฐ ",
- ["pl"] = "๎ฉ ",
- ["lua"] = "๎ ",
- ["sh"] = "๎ฏ ",
- ["bash"] = "๎ฏ ",
- ["ps1"] = "๓ฐจ ",
- ["scala"] = "๎ท ",
- ["hs"] = "๓ฐฒ ",
- ["jl"] = "๎ค ",
- ["clj"] = "๎ ",
- ["dart"] = "๎ ",
- ["groovy"] = "๎ต ",
- ["erl"] = "๎ฑ ",
- ["ex"] = "๎ญ",
- ["elm"] = "๎ฌ ",
- ["f90"] = "๓ฑ ",
- ["ml"] = "๎บ ",
- ["sql"] = "๎ ",
- ["p"] = "๎ก ",
- ["nim"] = "๎ท ",
- ["coffee"] = "๎ ",
- ["fs"] = "๎ง ",
- ["hx"] = "๎ฆ ",
- ["asp"] = "๓ฐชฎ ",
- ["cl"] = "๎ฐ ",
- ["gd"] = "๎ ",
- ["glsl"] = "๓ฑ ",
- ["h"] = "๎ ",
- ["hpp"] = "๎ ",
- ["hrl"] = "๎ฑ ",
- ["mjs"] = "๓ฐ ",
- ["md"] = "๎ฌ ",
- ["styl"] = "๎ ",
- ["toml"] = "๎ฒ ",
- ["vim"] = "๎
",
- ["wxs"] = "๎บ ",
- ["yaml"] = "๏ ",
- ["zsh"] = "๎ฏ ",
- ["exs"] = "๎ ",
- ["fnl"] = "๎ฏ ",
- ["gsl"] = "๓ฐฟฆ ",
- ["gs"] = "๓ฐญ ",
- ["scss"] = "๎ ",
- ["zig"] = "๎ฉ ",
- ["text"] = "๓ฐ ",
- ["htmx"] = "๎ซ ",
- ["json"] = "๓ฐ
ฉ ",
- ["html"] = "๏ป ",
- ["css"] = "๎ "
-};
-
----@type table Language name to filetype mapping
-languages.reverse_map = {
- ["c"] = "c",
- ["c_plus_plus"] = "cpp",
- ["java"] = "java",
- ["python"] = "py",
- ["javascript"] = "js",
- ["typescript"] = "ts",
- ["ruby"] = "rb",
- ["php"] = "php",
- ["c_sharp"] = "cs",
- ["swift"] = "swift",
- ["kotlin"] = "kt",
- ["go"] = "go",
- ["rust"] = "rs",
- ["r"] = "r",
- ["perl"] = "pl",
- ["lua"] = "lua",
- ["shell"] = "sh",
- ["powershell"] = "ps1",
- ["scala"] = "scala",
- ["haskell"] = "hs",
- ["visual_basic"] = "vb",
- ["julia"] = "jl",
- ["clojure"] = "clj",
- ["dart"] = "dart",
- ["groovy"] = "groovy",
- ["matlab"] = "m",
- ["erlang"] = "erl",
- ["elixir"] = "ex",
- ["elm"] = "elm",
- ["fortran"] = "f90",
- ["ocaml"] = "ml",
- ["verilog"] = "v",
- ["vhdl"] = "vhd",
- ["sql"] = "sql",
- ["ada"] = "adb",
- ["prolog"] = "p",
- ["tcl"] = "tcl",
- ["scheme"] = "scm",
- ["nim"] = "nim",
- ["awk"] = "awk",
- ["coffeescript"] = "coffee",
- ["f_sharp"] = "fs",
- ["pascal"] = "pas",
- ["haxe"] = "hx",
- ["haxe_shader_language"] = "hxsl",
- ["haxe_project"] = "hxproj",
- ["xquery"] = "x",
- ["idl"] = "idp",
- ["interface_definition_language"] = "idl",
- ["asp"] = "asp",
- ["lisp"] = "lsp",
- ["common_lisp"] = "cl",
- ["opencl"] = "cl",
- ["d"] = "d",
- ["gdscript"] = "gd",
- ["glsl"] = "glsl",
- ["c_header"] = "h",
- ["c_plus_plus_header"] = "hpp",
- ["erlang_header"] = "hrl",
- ["lisp_identifier"] = "lid",
- ["node_js_es_module"] = "mjs",
- ["markdown"] = "md",
- ["n"] = "n",
- ["processing"] = "pde",
- ["qml"] = "qml",
- ["red"] = "red",
- ["reason"] = "re",
- ["racket"] = "rkt",
- ["supercollider"] = "sc",
- ["solidity"] = "sol",
- ["smalltalk"] = "st",
- ["stylus"] = "styl",
- ["scheme_source"] = "sx",
- ["isabelle"] = "thy",
- ["toml"] = "toml",
- ["vala"] = "vala",
- ["vala_api"] = "vapi",
- ["vimscript"] = "vim",
- ["wix"] = "wxs",
- ["xslt"] = "xt",
- ["yaml"] = "yaml",
- ["zcml"] = "zcml",
- ["zenscript"] = "zs",
- ["zsh"] = "zsh",
- ["basic"] = "bas",
- ["batch"] = "bat",
- ["blitzmax"] = "bmx",
- ["boo"] = "boo",
- ["bluespec_systemverilog"] = "bsv",
- ["c2hs"] = "chs",
- ["clips"] = "clp",
- ["batch_script"] = "cmd",
- ["cobol"] = "cob",
- ["cobol_legacy"] = "cbl",
- ["camal"] = "cma",
- ["crmscript"] = "crm",
- ["eiffel"] = "e",
- ["eagle"] = "ea",
- ["emberscript"] = "em",
- ["elixir_script"] = "exs",
- ["f"] = "f",
- ["fennel"] = "fnl",
- ["g"] = "g",
- ["gds"] = "gd",
- ["gsl"] = "glf",
- ["google_apps_script"] = "gs",
- ["hcl"] = "hcl",
- ["haxe_project_file"] = "hxproj",
- ["agda"] = "lagda",
- ["lean"] = "lean",
- ["lassoscript"] = "ls",
- ["lasso"] = "lss",
- ["maxscript"] = "mc",
- ["mumps"] = "mu",
- ["myghty"] = "myt",
- ["runoff"] = "rno",
- ["sass"] = "scss",
- ["smarty"] = "tpl",
- ["ur"] = "ur",
- ["vbscript"] = "vbproj",
- ["wolfram"] = "wlk",
- ["xpl"] = "xpl",
- ["xquery_file"] = "xqy",
- ["xs"] = "xs",
- ["txt"] = "text",
-};
-
----@type table Filetype to language name mapping
-languages.patterns = {
- ["c"] = "C",
- ["cpp"] = "C++",
- ["java"] = "Java",
- ["py"] = "Python",
- ["js"] = "JavaScript",
- ["ts"] = "TypeScript",
- ["rb"] = "Ruby",
- ["php"] = "PHP",
- ["cs"] = "C#",
- ["swift"] = "Swift",
- ["kt"] = "Kotlin",
- ["go"] = "Go",
- ["rs"] = "Rust",
- ["r"] = "R",
- ["pl"] = "Perl",
- ["lua"] = "Lua",
- ["sh"] = "Shell",
- ["ps1"] = "PowerShell",
- ["scala"] = "Scala",
- ["hs"] = "Haskell",
- ["vb"] = "Visual Basic",
- ["jl"] = "Julia",
- ["clj"] = "Clojure",
- ["dart"] = "Dart",
- ["groovy"] = "Groovy",
- ["m"] = "MATLAB",
- ["erl"] = "Erlang",
- ["ex"] = "Elixir",
- ["elm"] = "Elm",
- ["f90"] = "Fortran",
- ["ml"] = "OCaml",
- ["v"] = "Verilog",
- ["vhd"] = "VHDL",
- ["sql"] = "SQL",
- ["adb"] = "Ada",
- ["p"] = "Prolog",
- ["tcl"] = "Tcl",
- ["scm"] = "Scheme",
- ["nim"] = "Nim",
- ["awk"] = "AWK",
- ["coffee"] = "CoffeeScript",
- ["fs"] = "F#",
- ["pas"] = "Pascal",
- ["hx"] = "Haxe",
- ["hxsl"] = "Haxe Shader Language",
- ["hxproj"] = "Haxe Project",
- ["x"] = "XQuery",
- ["idp"] = "IDL",
- ["idl"] = "Interface Definition Language",
- ["ada"] = "Ada",
- ["asp"] = "ASP",
- ["lsp"] = "Lisp",
- ["cl"] = "Common Lisp",
- ["d"] = "D",
- ["g"] = "G",
- ["gd"] = "GDScript",
- ["glsl"] = "GLSL",
- ["h"] = "Header",
- ["hpp"] = "Header",
- ["hrl"] = "Header",
- ["lid"] = "Lisp Identifier",
- ["mjs"] = "Node.js ES Module",
- ["md"] = "Markdown",
- ["n"] = "N",
- ["pde"] = "Processing",
- ["qml"] = "QML",
- ["red"] = "Red",
- ["re"] = "Reason",
- ["rkt"] = "Racket",
- ["sc"] = "SuperCollider",
- ["sol"] = "Solidity",
- ["st"] = "Smalltalk",
- ["styl"] = "Stylus",
- ["sx"] = "Scheme Source",
- ["thy"] = "Isabelle",
- ["toml"] = "TOML",
- ["vala"] = "Vala",
- ["vapi"] = "Vala API",
- ["vim"] = "Vimscript",
- ["wxs"] = "WiX",
- ["xt"] = "XSLT",
- ["yaml"] = "YAML",
- ["yml"] = "YAML",
- ["zcml"] = "ZCML",
- ["zs"] = "ZenScript",
- ["zsh"] = "Zsh",
- ["bas"] = "BASIC",
- ["bat"] = "Batch",
- ["bmx"] = "BlitzMax",
- ["boo"] = "Boo",
- ["bsv"] = "Bluespec SystemVerilog",
- ["chs"] = "C2HS",
- ["clp"] = "CLIPS",
- ["cmd"] = "Batch script",
- ["cob"] = "COBOL",
- ["cbl"] = "COBOL",
- ["cma"] = "CAMAL",
- ["crm"] = "CrmScript",
- ["e"] = "Eiffel",
- ["ea"] = "Eagle",
- ["em"] = "EmberScript",
- ["exs"] = "Elixir",
- ["f"] = "F",
- ["fnl"] = "Fennel",
- ["glf"] = "GSL",
- ["gs"] = "Google Apps Script",
- ["hcl"] = "HCL",
- ["lagda"] = "Agda",
- ["lean"] = "Lean",
- ["ls"] = "LassoScript",
- ["lss"] = "Lasso",
- ["mc"] = "MAXScript",
- ["mu"] = "MUMPS",
- ["myt"] = "Myghty",
- ["rno"] = "RUNOFF",
- ["scss"] = "Sass",
- ["tpl"] = "Smarty",
- ["ur"] = "Ur",
- ["vbproj"] = "VBScript",
- ["wlk"] = "Wolfram",
- ["xpl"] = "XPL",
- ["xqy"] = "XQuery",
- ["xquery"] = "XQuery",
- ["xs"] = "XS",
- ["z"] = "Z",
- ["css"] = "CSS",
- ["html"] = "HTML"
-};
-
---- Known language info string patterns
----@type string[]
-languages.info_patterns = {
- -- {{ lang }} params
- "%{%{([^%}]*)%}%}%s*(.*)$",
- -- Myst code blocks (code, code-block, code-cell) with language
- -- https://mystmd.org/guide/code#code-blocks
- "%{code%S*%}%s*(%S+)$",
- -- Other {}-wrapped directive with unknown processing
- "%{([^%}]*)%}%s*(.*)$",
- -- Language string and additional info
- -- https://spec.commonmark.org/0.31.2/#example-143
- "(%S-)%s+(.*)$",
- -- Language string without additional info or no language
- -- https://spec.commonmark.org/0.31.2/#example-143
- "(%S*)%s*$",
-}
-
---- Known code-block fences
----@type string[]
-languages.fences = {"`", "~"}
-
---- Gets the language name from a string
----@param name string
----@return string
-languages.get_name = function (name)
- if not name or name == "" then
- return "Unknown";
- elseif languages.patterns[name] then
- return languages.patterns[name];
- end
-
- local _u = string.gsub(name, "^%l", string.upper);
- return _u;
-end
-
---- Gets the filetype from a string
----@param name string
----@return string
-languages.get_ft = function (name)
- if not name or name == "" then
- return "Unknown";
- elseif languages.reverse_map[name] then
- return languages.reverse_map[name];
- else
- return name;
- end
-end
-
---- Gets an icon from a filetype
----@param ft string
----@return string # The icon
----@return string # The icon's hl
----@return string # The sign's hl
-languages.get_icon = function (ft)
- ---@diagnostic disable-next-line
- local hl, sign = unpack(languages.hls[ft] or languages.hls.default);
-
- return languages.icons[ft] or languages.icons.default, hl, sign;
-end
-
---- Extract fenced code block header
----@param line string
----@return string|nil fence the matched fence string
----@return string info the matched info string
-languages.get_fence = function(line)
- for _, char in pairs(languages.fences) do
- --- Match any supported fence, optionnaly indented or quoted
- local fence, info = line:match("^>*%s*(" .. string.rep(char, 3) .. "+)%s*(.-)%s*$");
- if fence ~= nil then
- return fence, info;
- end
- end
- return nil, ""
-end
-
---- Extract language and parameters from an infostring
----@param info string the info string to parse
----@return string language the extracted language
----@return string|nil # Some optional extra data
-languages.info = function (info)
- for _, pattern in pairs(languages.info_patterns) do
- local lang, extra = info:match(pattern);
- if lang then
- return lang, extra;
- end
- end
-end
-
-return languages;
diff --git a/lua/markview/latex_renderer.lua b/lua/markview/latex_renderer.lua
deleted file mode 100644
index 10c9b1f..0000000
--- a/lua/markview/latex_renderer.lua
+++ /dev/null
@@ -1,2185 +0,0 @@
---- A simple latex renderer for `markview.nvim`.
-local latex = {};
-
----@type integer? Namespace used to render stuff, initially nil
-latex.namespace = nil;
-
---- Sets the namespace
----@param ns integer
-latex.set_namespace = function (ns)
- latex.namespace = ns;
-end
-
---- Fixes a highlight group name
----@param hl string?
----@return string?
-local set_hl = function (hl)
- if type(hl) ~= "string" then
- return;
- end
-
- if vim.fn.hlexists("Markview" .. hl) == 1 then
- return "Markview" .. hl;
- elseif vim.fn.hlexists("Markview_" .. hl) == 1 then
- return "Markview_" .. hl;
- else
- return hl;
- end
-end
-
----@type { [string]: string } Unicode superscript symbols reference table
-latex.superscripts = {
- ---+ ${class, Superscript symbols}
- ---+ ${class, Numbers}
- ["0"] = "โฐ",
- ["1"] = "ยน",
- ["2"] = "ยฒ",
- ["3"] = "ยณ",
- ["4"] = "โด",
- ["5"] = "โต",
- ["6"] = "โถ",
- ["7"] = "โท",
- ["8"] = "โธ",
- ["9"] = "โน",
- ---_
-
- ---+ ${class, Symbols}
- ["+"] = "โบ",
- ["-"] = "โป",
- ["="] = "โผ",
- ["("] = "โฝ",
- [")"] = "โพ",
- ---_
-
- ---+ ${class, Whitespaces}
- [" "] = " ",
- [" "] = " ",
- ---_
-
- ---+ ${class, Small letters}
- ["a"] = "แต",
- ["b"] = "แต",
- ["c"] = "แถ",
- ["d"] = "แต",
- ["e"] = "แต",
- ["f"] = "แถ ",
- ["g"] = "แต",
- ["h"] = "สฐ",
- ["i"] = "โฑ",
- ["j"] = "สฒ",
- ["k"] = "แต",
- ["l"] = "หก",
- ["m"] = "แต",
- ["n"] = "โฟ",
- ["o"] = "แต",
- ["p"] = "แต",
- ["q"] = "แถฃ",
- ["r"] = "สณ",
- ["s"] = "หข",
- ["t"] = "แต",
- ["u"] = "แต",
- ["v"] = "แต",
- ["w"] = "สท",
- ["x"] = "หฃ",
- ["y"] = "สธ",
- ["z"] = "แถป",
- ---_
-
- ---+ ${class, Capital letters}
- ["A"] = "แต",
- ["B"] = "แต",
- ["C"] = "แถ",
- ["D"] = "แต",
- ["E"] = "แต",
- ["F"] = "แถ ",
- ["G"] = "แต",
- ["H"] = "สฐ",
- ["I"] = "โฑ",
- ["J"] = "สฒ",
- ["K"] = "แต",
- ["L"] = "หก",
- ["M"] = "แต",
- ["N"] = "โฟ",
- ["O"] = "แต",
- ["P"] = "แต",
- ["Q"] = "แถฟ",
- ["R"] = "สณ",
- ["S"] = "หข",
- ["T"] = "แต",
- ["U"] = "แต",
- ["V"] = "แต",
- ["W"] = "สท",
- ["X"] = "หฃ",
- ["Y"] = "สธ",
- ["Z"] = "แถป",
- ---_
- ---_
-};
-
----@type { [string]: string } Latex operators
-latex.operators = {
- ---+ ${class, Operator names}
- ["arccos"] = "๐๐๐๐๐๐",
- ["arcsin"] = "๐๐๐๐๐๐",
- ["arctan"] = "๐๐๐๐๐๐",
- ["arg"] = "๐๐๐",
- ["cos"] = "๐๐๐",
- ["csc"] = "๐๐๐",
- ["cosh"] = "๐๐๐๐",
- ["cot"] = "๐๐๐",
- ["coth"] = "๐๐๐๐",
- ["deg"] = "๐๐๐",
- ["det"] = "๐๐๐",
- ["dim"] = "๐๐๐",
- ["exp"] = "๐๐ก๐",
- ["gcd"] = "๐๐๐",
- ["hom"] = "๐๐๐",
- ["inf"] = "๐๐๐",
- ["ker"] = "๐๐๐",
- ["lg"] = "๐๐",
- ["lim"] = "๐๐๐",
- ["liminf"] = "๐๐๐ ๐๐๐",
- ["limsup"] = "๐๐๐ ๐๐๐",
- ["ln"] = "๐๐",
- ["log"] = "๐๐๐",
- ["max"] = "๐๐๐ก",
- ["min"] = "๐๐๐",
- ["Pr"] = "๐ฟ๐",
- ["sec"] = "๐๐๐",
- ["sin"] = "๐๐๐",
- ["sinh"] = "๐๐๐๐",
- ["sup"] = "๐๐๐",
- ["tan"] = "๐๐๐",
- ["tanh"] = "๐๐๐๐",
-
- ["lvert"] = "|",
- ["lVert"] = "โ",
- ["sqrt"] = "โ",
- ---_
-}
-
----@type { [string]: string | fun(buf: integer): string } Latex symbols reference table
-latex.symbols = {
- ---+ ${class, Various symbols & fonts}
- ["year"] = function () return tostring(os.date("*t").year); end,
- ["day"] = function () return tostring(os.date("*t").day); end,
- ["today"] = function () return os.date("%d %B, %Y") --[[ @as string ]]; end,
-
- ["to"] = "โถ",
-
- ---+ ${class, Function names}
- ["arccos"] = "๐๐๐๐๐๐",
- ["arcsin"] = "๐๐๐๐๐๐",
- ["arctan"] = "๐๐๐๐๐๐",
- ["arg"] = "๐๐๐",
- ["cos"] = "๐๐๐",
- ["csc"] = "๐๐๐",
- ["cosh"] = "๐๐๐๐",
- ["cot"] = "๐๐๐",
- ["coth"] = "๐๐๐๐",
- ["deg"] = "๐๐๐",
- ["det"] = "๐๐๐",
- ["dim"] = "๐๐๐",
- ["exp"] = "๐๐ก๐",
- ["gcd"] = "๐๐๐",
- ["hom"] = "๐๐๐",
- ["inf"] = "๐๐๐",
- ["ker"] = "๐๐๐",
- ["lg"] = "๐๐",
- ["lim"] = "๐๐๐",
- ["liminf"] = "๐๐๐ ๐๐๐",
- ["limsup"] = "๐๐๐ ๐๐๐",
- ["ln"] = "๐๐",
- ["log"] = "๐๐๐",
- ["max"] = "๐๐๐ก",
- ["min"] = "๐๐๐",
- ["Pr"] = "๐ฟ๐",
- ["sec"] = "๐๐๐",
- ["sin"] = "๐๐๐",
- ["sinh"] = "๐๐๐๐",
- ["sup"] = "๐๐๐",
- ["tan"] = "๐๐๐",
- ["tanh"] = "๐๐๐๐",
- ---_
-
- ["#"] = "#",
- ["$"] = "$",
- ["%"] = "%",
- ["_"] = "_",
- ["{"] = "{",
- ["}"] = "}",
-
- ["lbrack"] = "[",
- ["backslash"] = "\\",
- ["rbrack"] = "]",
- ["sphat"] = "^",
- ["lbrace"] = "{",
- ["vert"] = "|",
- ["lvert"] = "|",
- ["rvert"] = "|",
- ["Vert"] = "โ",
- ["lVert"] = "โ",
- ["rVert"] = "โ",
- ["rbrace"] = "}",
- ["sptilde"] = "~",
-
- ["cent"] = "ยข",
- ["pounds"] = "ยฃ",
- ["yen"] = "ยฅ",
-
- ["spddot"] = "ยจ",
- ["neg"] = "ยฌ",
- ["circledR"] = "ยฎ",
- ["pm"] = "ยฑ",
- ["Micro"] = "ยต",
- ["times"] = "ร",
- ["eth"] = "รฐ",
- ["div"] = "รท",
-
- ["imath"] = "ฤฑ",
- ["jmath"] = "ศท",
-
- ["grave"] = " ฬ",
- ["acute"] = " ฬ",
- ["hat"] = " ฬ",
- ["tilde"] = " ฬ",
- ["bar"] = " ฬ",
- ["overline"] = " ฬ
",
- ["breve"] = " ฬ",
- ["dot"] = " ฬ",
- ["ddot"] = " ฬ",
- ["mathring"] = " ฬ",
- ["check"] = " ฬ",
-
- ["utilde"] = " ฬฐ",
- ["underbar"] = " ฬฑ",
- ["underline"] = " ฬฒ",
-
- ["not"] = " ฬธ",
-
- ["Gamma"] = "ฮ",
- ["Delta"] = "ฮ",
- ["Theta"] = "ฮ",
- ["Lambda"] = "ฮ",
- ["Xi"] = "ฮ",
- ["Pi"] = "ฮ ",
- ["Sigma"] = "ฮฃ",
- ["Upsilon"] = "ฮฅ",
- ["Phi"] = "ฮฆ",
- ["Psi"] = "ฮจ",
- ["Omega"] = "ฮฉ",
-
- ["alpha"] = "ฮฑ",
- ["beta"] = "ฮฒ",
- ["gamma"] = "ฮณ",
- ["delta"] = "ฮด",
- ["varepsilon"] = "ฮต",
- ["zeta"] = "ฮถ",
- ["eta"] = "ฮท",
- ["theta"] = "ฮธ",
- ["iota"] = "ฮน",
- ["kappa"] = "ฮบ",
- ["lambda"] = "ฮป",
- ["mu"] = "ฮผ",
- ["nu"] = "ฮฝ",
- ["xi"] = "ฮพ",
- ["pi"] = "ฯ",
- ["rho"] = "ฯ",
- ["varsigma"] = "ฯ",
- ["sigma"] = "ฯ",
- ["tau"] = "ฯ",
- ["upsilon"] = "ฯ
",
- ["varphi"] = "ฯ",
- ["chi"] = "ฯ",
- ["psi"] = "ฯ",
- ["omega"] = "ฯ",
- ["varbeta"] = "ฯ",
- ["vartheta"] = "ฯ",
- ["phi"] = "ฯ",
- ["varpi"] = "ฯ",
- ["Qoppa"] = "ฯ",
- ["qoppa"] = "ฯ",
- ["Stigma"] = "ฯ",
- ["stigma"] = "ฯ",
- ["Digamma"] = "ฯ",
- ["digamma"] = "ฯ",
- ["Koppa"] = "ฯ",
- ["koppa"] = "ฯ",
- ["Sampi"] = "ฯ ",
- ["sampi"] = "ฯก",
- ["varkappa"] = "ฯฐ",
- ["varrho"] = "ฯฑ",
- ["epsilon"] = "ฯต",
- ["backepsilon"] = "ฯถ",
- ["Euler"] = "โ",
-
- ["|"] = "โ",
- ["dagger"] = "โ ",
- ["ddagger"] = "โก",
- ["bullet"] = "โข",
- ["ldots"] = "โฆ",
- ["prime"] = "โฒ",
- ["second"] = "โณ",
- ["third"] = "โด",
- ["fourth"] = "โ",
- ["backprime"] = "โต",
- ["cat"] = "โ",
- ["lvec"] = "xโ",
- ["vec"] = "xโ",
- ["LVec"] = "xโ",
- ["Vec"] = "xโ",
- ["dddot"] = "xโ",
- ["ddddot"] = "xโ",
- ["overleftrightarrow"] = "xโก",
- ["underleftarrow"] = "xโฎ",
- ["underrightarrow"] = "xโฏ",
-
- ["lm"] = "โ",
- ["ell"] = "โ",
- ["wp"] = "โ",
- ["re"] = "โ",
- ["tcohm"] = "โฆ",
- ["mho"] = "โง",
- ["Angstroem"] = "โซ",
- ["Finv"] = "โฒ",
- ["hslash"] = "โ",
- ["aleph"] = "โต",
- ["beth"] = "โถ",
- ["gimel"] = "โท",
- ["daleth"] = "โธ",
- ["Yup"] = "โ
",
- ["invamp"] = "โ
",
-
- ["CapitalDifferentialD"] = "โ
",
- ["DifferentialD"] = "โ
",
- ["DifferentialE"] = "โ
",
- ["ComplexI"] = "โ
",
- ["ComplexJ"] = "โ
",
-
- ["mathbb_pi"] = "โผ",
- ["mathbb_Pi"] = "โฟ",
- ["mathbb_Sigma"] = "โ
",
- ["mathbb_gamma"] = "โฝ",
- ["mathbb_Gamma"] = "โพ",
-
- ["leftarrow"] = "โ",
- ["uparrow"] = "โ",
- ["rightarrow"] = "โ",
- ["downarrow"] = "โ",
- ["leftrightarrow"] = "โ",
- ["updownarrow"] = "โ",
- ["nwarrow"] = "โ",
- ["nearrow"] = "โ",
- ["swarrow"] = "โ",
- ["searrow"] = "โ",
-
- ["nleftarrow"] = "โ",
- ["nrightarrow"] = "โ",
- ["twoheadleftarrow"] = "โ",
- ["twoheadrightarrow"] = "โ ",
-
- ["leftarrowtail"] = "โข",
- ["rightarrowtail"] = "โฃ",
-
- ["mapsfrom"] = "โค",
- ["MapsUp"] = "โฅ",
- ["mapsto"] = "โฆ",
- ["MapsDown"] = "โง",
-
- ["hookleftarrow"] = "โฉ",
- ["hookrightarrow"] = "โช",
-
- ["looparrowleft"] = "โซ",
- ["looparrowright"] = "โฌ",
-
- ["leftrightsquigarrow"] = "โญ",
- ["nleftrightarrow"] = "โฎ",
-
- ["lightning"] = "โฏ",
- ["Lsh"] = "โฐ",
- ["Rsh"] = "โฑ",
- ["dlsh"] = "โฒ",
- ["drsh"] = "โณ",
-
- ["curvearrowleft"] = "โถ",
- ["curvearrowright"] = "โท",
-
- ["circlearrowleft"] = "โบ",
- ["circlearrowright"] = "โป",
-
- ["leftharpoonup"] = "โผ",
- ["upharpoonright"] = "โพ",
- ["upharpoonleft"] = "โฟ",
- ["rightharpoonup"] = "โ",
- ["rightharpoondown"] = "โ",
- ["downharpoonright"] = "โ",
- ["downharpoonleft"] = "โ",
-
- ["rightleftarrows"] = "โ",
- ["updownarrows"] = "โ
",
- ["leftrightarrows"] = "โ",
- ["downuparrows"] = "โต",
-
- ["leftleftarrows"] = "โ",
- ["upuparrows"] = "โ",
- ["rightrightarrows"] = "โ",
- ["downdownarrows"] = "โ",
-
- ["leftrightharpoons"] = "โ",
- ["rightleftharpoons"] = "โ",
-
- ["nLeftarrow"] = "โ",
- ["nLeftrightarrow"] = "โ",
- ["nRightarrow"] = "โ",
-
- ["Leftarrow"] = "โ",
- ["Uparrow"] = "โ",
- ["Rightarrow"] = "โ",
- ["Downarrow"] = "โ",
-
- ["Nwarrow"] = "โ",
- ["Nearrow"] = "โ",
- ["Swarrow"] = "โ",
- ["Searrow"] = "โ",
-
- ["Lleftarrow"] = "โ",
- ["Rrightarrow"] = "โ",
- ["leftsquigarrow"] = "โ",
- ["rightsquigarrow"] = "โ",
-
- ["dashleftarrow"] = "โ ",
- ["dashrightarrow"] = "โข",
-
- ["LeftArrowBar"] = "โค",
- ["RightArrowBar"] = "โฅ",
-
- ["pfun"] = "โธ",
- ["ffun"] = "โป",
-
- ["leftarrowtriangle"] = "โฝ",
- ["rightarrowtriangle"] = "โพ",
- ["leftrightarrowtriangle"] = "โฟ",
-
- ["complement"] = "โ",
- ["partial"] = "โ",
- ["exists"] = "โ",
- ["nexists"] = "โ",
- ["varnothing"] = "โ
",
- ["nabla"] = "โ",
- ["in"] = "โ",
- ["notin"] = "โ",
- ["ni"] = "โ",
- ["nni"] = "โ",
- ["prod"] = "โ",
- ["coprod"] = "โ",
- ["sum"] = "โ",
- ["mp"] = "โ",
- ["dotplus"] = "โ",
- ["slash"] = "โ",
- ["smallsetminus"] = "โ",
- ["ast"] = "โ",
- ["circ"] = "โ",
-
- ["sqrt"] = "โ",
- ["sqrt_3"] = "โ",
- ["sqrt_4"] = "โ",
-
- ["propto"] = "โ",
- ["infty"] = "โ",
- ["rightangle"] = "โ",
- ["angle"] = "โ ",
- ["measuredangle"] = "โก",
- ["sphericalangle"] = "โข",
- ["mid"] = "โฃ",
- ["nmid"] = "โค",
- ["parallel"] = "โฅ",
- ["nparallel"] = "โฆ",
- ["wedge"] = "โง",
- ["vee"] = "โจ",
- ["cap"] = "โฉ",
- ["cup"] = "โช",
-
- ["int"] = "โซ",
- ["iint"] = "โฌ",
- ["iiint"] = "โญ",
- ["oint"] = "โฎ",
- ["oiint"] = "โฏ",
- ["oiiint"] = "โฐ",
- ["varointclockwise"] = "โฒ",
- ["ointctrclockwise"] = "โณ",
-
- ["therefore"] = "โด",
- ["because"] = "โต",
- ["Proportion"] = "โท",
- ["eqcolon"] = "โน",
- ["sim"] = "โผ",
- ["nsim"] = "โ",
- ["backsim"] = "โฝ",
- ["AC"] = "โฟ",
- ["wr"] = "โ",
- ["eqsim"] = "โ",
- ["simeq"] = "โ",
- ["nsimeq"] = "โ",
- ["cong"] = "โ
",
- ["ncong"] = "โ",
- ["approx"] = "โ",
- ["napprox"] = "โ",
- ["approxeq"] = "โ",
- ["asymp"] = "โ",
-
- ["Bumpeq"] = "โ",
- ["bumpeq"] = "โ",
-
- ["doteq"] = "โ",
- ["Doteq"] = "โ",
- ["fallingdotseq"] = "โ",
- ["risingdotseq"] = "โ",
- ["coloneq"] = "โ",
- -- ["eqcolon"] = "โ", Name conflict
- ["eqcirc"] = "โ",
- ["circeq"] = "โ",
- ["corresponds"] = "โ",
- ["triangleq"] = "โ",
- ["neq"] = "โ ",
- ["equiv"] = "โก",
- ["nequiv"] = "โข",
-
- ["leq"] = "โค",
- ["geq"] = "โฅ",
- ["leqq"] = "โฆ",
- ["geqq"] = "โง",
- ["lneqq"] = "โจ",
- ["gneqq"] = "โฉ",
- ["ll"] = "โช",
- ["gg"] = "โซ",
- ["between"] = "โฌ",
- ["notasymp"] = "โญ",
- ["nless"] = "โฎ",
- ["ngtr"] = "โฏ",
- ["nleq"] = "โฐ",
- ["ngeq"] = "โฑ",
- ["lesssim"] = "โฒ",
- ["gtrsim"] = "โณ",
- ["NotLessTilde"] = "โด",
- ["NotGreaterTilde"] = "โต",
- ["lessgtr"] = "โถ",
- ["gtrless"] = "โท",
- ["NotGreaterLess"] = "โน",
- ["prec"] = "โบ",
- ["succ"] = "โป",
- ["preccurlyeq"] = "โผ",
- ["succcurlyeq"] = "โฝ",
- ["precsim"] = "โพ",
- ["succsim"] = "โฟ",
- ["nprec"] = "โ",
- ["nsucc"] = "โ",
-
- ["subset"] = "โ",
- ["supset"] = "โ",
- ["nsubset"] = "โ",
- ["nsupset"] = "โ
",
- ["subseteq"] = "โ",
- ["supseteq"] = "โ",
- ["nsubseteq"] = "โ",
- ["nsupseteq"] = "โ",
- ["subsetneq"] = "โ",
- ["supsetneq"] = "โ",
- ["uplus"] = "โ",
-
- ["sqsubset"] = "โ",
- ["sqsupset"] = "โ",
- ["sqsubseteq"] = "โ",
- ["sqsupseteq"] = "โ",
- ["sqcap"] = "โ",
- ["sqcup"] = "โ",
-
- ["oplus"] = "โ",
- ["ominus"] = "โ",
- ["otimes"] = "โ",
- ["oslash"] = "โ",
- ["odot"] = "โ",
-
- ["circledcirc"] = "โ",
- ["circledast"] = "โ",
- ["circleddash"] = "โ",
-
- ["boxplus"] = "โ",
- ["boxminus"] = "โ",
- ["boxtimes"] = "โ ",
- ["boxdot"] = "โก",
-
- ["vdash"] = "โข",
- ["dashv"] = "โฃ",
- ["top"] = "โค",
- ["bot"] = "โฅ",
- ["models"] = "โง",
- ["vDash"] = "โจ",
- ["Vdash"] = "โฉ",
- ["Vvdash"] = "โช",
- ["VDash"] = "โซ",
- ["nvdash"] = "โฌ",
- ["nvDash"] = "โญ",
- ["nVdash"] = "โฎ",
- ["nVDash"] = "โฏ",
-
- ["vartriangleleft"] = "โฒ",
- ["vartriangleright"] = "โณ",
- ["trianglelefteq"] = "โด",
- ["trianglerighteq"] = "โต",
-
- ["multimapdotbothA"] = "โถ",
- ["multimapdotbothB"] = "โท",
- ["multimap"] = "โธ",
-
- ["intercal"] = "โบ",
- ["veebar"] = "โป",
- ["barwedge"] = "โผ",
- ["bigwedge"] = "โ",
- ["bigvee"] = "โ",
- ["bigcap"] = "โ",
- ["bigcup"] = "โ",
- ["diamond"] = "โ",
- ["cdot"] = "โ
",
- ["star"] = "*",
- ["divideontimes"] = "โ",
- ["bowtie"] = "โ",
- ["ltimes"] = "โ",
- ["rtimes"] = "โ",
- ["leftthreetimes"] = "โ",
- ["rightthreetimes"] = "โ",
- ["backsimeq"] = "โ",
- ["curlyvee"] = "โ",
- ["curlywedge"] = "โ",
-
- ["Subset"] = "โ",
- ["Supset"] = "โ",
- ["Cap"] = "โ",
- ["Cup"] = "โ",
- ["pitchfork"] = "โ",
- ["hash"] = "โ",
- ["lessdot"] = "โ",
- ["gtrdot"] = "โ",
- ["lll"] = "โ",
- ["ggg"] = "โ",
- ["lesseqgtr"] = "โ",
- ["gtreqless"] = "โ",
- ["curlyeqprec"] = "โ",
- ["curlyeqsucc"] = "โ",
- ["npreceq"] = "โ ",
- ["nsucceq"] = "โก",
- ["nsqsubseteq"] = "โข",
- ["nsqsupseteq"] = "โฃ",
- ["lnsim"] = "โฆ",
- ["gnsim"] = "โง",
- ["precnsim"] = "โจ",
- ["succnsim"] = "โฉ",
- ["ntriangleleft"] = "โช",
- ["ntriangleright"] = "โซ",
- ["ntrianglelefteq"] = "โฌ",
- ["ntrianglerighteq"] = "โญ",
-
- ["vdots"] = "โฎ",
- ["cdots"] = "โฏ",
- ["iddots"] = "โฐ",
- ["ddots"] = "โฑ",
-
- ["barin"] = "โถ",
- ["diameter"] = "โ",
- ["invdiameter"] = "โ",
-
- ["lceil"] = "โ",
- ["rceil"] = "โ",
- ["lfloor"] = "โ",
- ["rfloor"] = "โ",
- ["invneg"] = "โ",
- ["wasylozenge"] = "โ",
- ["ulcorner"] = "โ",
- ["urcorner"] = "โ",
- ["llcorner"] = "โ",
- ["lrcorner"] = "โ",
- ["frown"] = "โข",
- ["smile"] = "โฃ",
- ["APLinv"] = "โน",
-
- ["notslash"] = "โฟ",
- ["notbackslash"] = "โ",
- ["APLleftarrowbox"] = "โ",
- ["APLrightarrowbox"] = "โ",
- ["APLuparrowbox"] = "โ",
- ["APLdownarrowbox"] = "โ",
- ["APLcomment"] = "โ",
- ["APLinput"] = "โ",
- ["APLlog"] = "โ",
-
- ["overparen"] = "โ",
- ["underparen"] = "โ",
- ["overbrace"] = "โ",
- ["underbrace"] = "โ",
-
- ["bigtriangleup"] = "โณ",
- ["blacktriangleup"] = "โด",
- ["smalltriangleup"] = "โต",
- ["RHD"] = "โถ",
- ["rhd"] = "โท",
- ["blacktriangleright"] = "โธ",
- ["smalltriangleright"] = "โน",
- ["bigtriangledown"] = "โฝ",
- ["blacktriangledown"] = "โพ",
- ["smalltriangledown"] = "โฟ",
- ["LHD"] = "โ",
- ["lhd"] = "โ",
- ["blacktriangleleft"] = "โ",
- ["smalltriangleleft"] = "โ",
- ["Diamondblack"] = "โ",
- ["Diamond"] = "โ",
- ["lozenge"] = "โ",
- ["Circle"] = "โ",
- ["CIRCLE"] = "โ",
- ["LEFTcircle"] = "โ",
- ["RIGHTcircle"] = "โ",
- ["LEFTCIRCLE"] = "โ",
- ["RIGHTCIRCLE"] = "โ",
- ["boxbar"] = "โซ",
- ["square"] = "โป",
- ["blacksquare"] = "โผ",
- ["bigstar"] = "โ
",
- ["Sun"] = "โ",
- ["Square"] = "โ",
- ["CheckedBox"] = "โ",
- ["XBox"] = "โ",
- ["steaming"] = "โ",
- ["pointright"] = "โ",
- ["skull"] = "โ ",
- ["radiation"] = "โข",
- ["biohazard"] = "โฃ",
- ["yinyang"] = "โฏ",
- ["frownie"] = "๐",
- ["smiley"] = "๐",
- ["sun"] = "โผ",
- ["rightmoon"] = "โฝ",
- ["leftmoon"] = "โพ",
- ["swords"] = "โ",
- ["warning"] = "โ ",
- ["pencil"] = "โ",
- ["checkmark"] = "โ",
- ["ballotx"] = "โ",
- ["arrowbullet"] = "โข",
-
- ["perp"] = "โ",
- ["Lbag"] = "โ
",
- ["Rbag"] = "โ",
- ["Diamonddot"] = "โ",
- ["multimapinv"] = "โ",
- ["llbracket"] = "โฆ",
- ["rrbracket"] = "โง",
- ["langle"] = "โจ",
- ["rangle"] = "โฉ",
- ["lang"] = "โช",
- ["rang"] = "โซ",
- ["lgroup"] = "โฎ",
- ["rgroup"] = "โฏ",
-
- ["longleftarrow"] = "โต",
- ["longrightarrow"] = "โถ",
- ["longleftrightarrow"] = "โท",
- ["Longleftarrow"] = "โธ",
- ["Longrightarrow"] = "โน",
- ["Longleftrightarrow"] = "โบ",
- ["longmapsfrom"] = "โป",
- ["longmapsto"] = "โผ",
- ["Longmapsfrom"] = "โฝ",
- ["Longmapsto"] = "โพ",
- ["psur"] = "โค",
- ["Mapsfrom"] = "โค",
- ["Mapsto"] = "โค",
- ["UpArrowBar"] = "โค",
- ["DownArrowBar"] = "โค",
- ["pinj"] = "โค",
- ["finj"] = "โค",
- ["bij"] = "โค",
- ["leadsto"] = "โคณ",
- ["leftrightharpoon"] = "โฅ",
- ["rightleftharpoon"] = "โฅ",
- ["leftrightharpoondown"] = "โฅ",
- ["leftupdownharpoon"] = "โฅ",
- ["LeftVectorBar"] = "โฅ",
- ["RightVectorBar"] = "โฅ",
- ["RightUpVectorBar"] = "โฅ",
- ["RightDownVectorBar"] = "โฅ",
- ["DownLeftVectorBar"] = "โฅ",
- ["DownRightVectorBar"] = "โฅ",
- ["LeftDownVectorBar"] = "โฅ",
- ["LeftTeeVector"] = "โฅ",
- ["RightTeeVector"] = "โฅ",
- ["RightUpTeeVector"] = "โฅ",
- ["RightDownTeeVector"] = "โฅ",
- ["DownLeftTeeVector"] = "โฅ",
- ["DownRightTeeVector"] = "โฅ",
- ["LeftUpTeeVector"] = "โฅ ",
- ["LeftDownTeeVector"] = "โฅก",
- ["leftleftharpoons"] = "โฅข",
- ["upupharpoons"] = "โฅฃ",
- ["rightrightharpoons"] = "โฅค",
- ["downdownharpoons"] = "โฅฅ",
- ["leftbarharpoon"] = "โฅช",
- ["barleftharpoon"] = "โฅซ",
- ["rightbarharpoon"] = "โฅฌ",
- ["barrightharpoon"] = "โฅญ",
- ["updownharpoons"] = "โฅฎ",
- ["downupharpoons"] = "โฅฏ",
- ["strictfi"] = "โฅผ",
- ["strictif"] = "โฅฝ",
- ["VERT"] = "โฆ",
- ["spot"] = "โฆ",
- ["Lparen"] = "โฆ
",
- ["Rparen"] = "โฆ",
- ["limg"] = "โฆ",
- ["rimg"] = "โฆ",
- ["lblot"] = "โฆ",
- ["rblot"] = "โฆ",
- ["circledless"] = "โง",
- ["circledbslash"] = "โฆธ",
- ["circledgtr"] = "โง",
- ["boxslash"] = "โง",
- ["boxbslash"] = "โง
",
- ["boxast"] = "โง",
- ["boxcircle"] = "โง",
- ["boxbox"] = "โง",
- ["LeftTriangleBar"] = "โง",
- ["RightTriangleBar"] = "โง",
- ["multimapboth"] = "โง",
- ["blacklozenge"] = "โงซ",
- ["setminus"] = "โงต",
- ["zhide"] = "โงน",
-
- ["bigodot"] = "โจ",
- ["bigoplus"] = "โจ",
- ["bigotimes"] = "โจ",
- ["biguplus"] = "โจ",
- ["bigsqcap"] = "โจ
",
- ["bigsqcup"] = "โจ",
- ["varprod"] = "โจ",
- ["iiiint"] = "โจ",
- ["fint"] = "โจ",
- ["sqint"] = "โจ",
- ["Join"] = "โจ",
- ["zcmp"] = "โจ",
- ["zpipe"] = "โจ ",
- ["zproject"] = "โจก",
- ["fcmp"] = "โจพ",
- ["amalg"] = "โจฟ",
- ["doublebarwedge"] = "โฉ",
- ["dsub"] = "โฉค",
- ["rsub"] = "โฉฅ",
- ["Coloneqq"] = "โฉด",
- ["Equal"] = "โฉต",
- ["Same"] = "โฉถ",
-
- ["leqslant"] = "โฉฝ",
- ["geqslant"] = "โฉพ",
- ["lessapprox"] = "โช
",
- ["gtrapprox"] = "โช",
- ["lneq"] = "โช",
- ["gneq"] = "โช",
- ["lnapprox"] = "โช",
- ["gnapprox"] = "โช",
- ["lesseqqgtr"] = "โช",
- ["gtreqqless"] = "โช",
- ["eqslantless"] = "โช",
- ["eqslantgtr"] = "โช",
- ["NestedLessLess"] = "โชก",
- ["NestedGreaterGreater"] = "โชข",
- ["leftslice"] = "โชฆ",
- ["rightslice"] = "โชง",
- ["preceq"] = "โชฏ",
- ["succeq"] = "โชฐ",
- ["preceqq"] = "โชณ",
- ["succeqq"] = "โชด",
- ["precapprox"] = "โชท",
- ["succapprox"] = "โชธ",
- ["precnapprox"] = "โชน",
- ["succnapprox"] = "โชบ",
- ["llcurly"] = "โชป",
- ["ggcurly"] = "โชผ",
-
- ["subseteqq"] = "โซ
",
- ["supseteqq"] = "โซ",
- ["subsetneqq"] = "โซ",
- ["supsetneqq"] = "โซ",
-
- ["Top"] = "โซช",
- ["Bot"] = "โซซ",
- ["interleave"] = "โซด",
- ["biginterleave"] = "โซผ",
- ["sslash"] = "โซฝ",
-
- ---+ ${class, Mathematical bold symbols}
- ["mathbf_0"] = "๐",
- ["mathbf_1"] = "๐",
- ["mathbf_2"] = "๐",
- ["mathbf_3"] = "๐",
- ["mathbf_4"] = "๐",
- ["mathbf_5"] = "๐",
- ["mathbf_6"] = "๐",
- ["mathbf_7"] = "๐",
- ["mathbf_8"] = "๐",
- ["mathbf_9"] = "๐",
-
- ["mathbf_A"] = "๐",
- ["mathbf_B"] = "๐",
- ["mathbf_C"] = "๐",
- ["mathbf_D"] = "๐",
- ["mathbf_E"] = "๐",
- ["mathbf_F"] = "๐
",
- ["mathbf_G"] = "๐",
- ["mathbf_H"] = "๐",
- ["mathbf_I"] = "๐",
- ["mathbf_J"] = "๐",
- ["mathbf_K"] = "๐",
- ["mathbf_L"] = "๐",
- ["mathbf_M"] = "๐",
- ["mathbf_N"] = "๐",
- ["mathbf_O"] = "๐",
- ["mathbf_P"] = "๐",
- ["mathbf_Q"] = "๐",
- ["mathbf_R"] = "๐",
- ["mathbf_S"] = "๐",
- ["mathbf_T"] = "๐",
- ["mathbf_U"] = "๐",
- ["mathbf_V"] = "๐",
- ["mathbf_W"] = "๐",
- ["mathbf_X"] = "๐",
- ["mathbf_Y"] = "๐",
- ["mathbf_Z"] = "๐",
-
- ["mathbf_a"] = "๐",
- ["mathbf_b"] = "๐",
- ["mathbf_c"] = "๐",
- ["mathbf_d"] = "๐",
- ["mathbf_e"] = "๐",
- ["mathbf_f"] = "๐",
- ["mathbf_g"] = "๐ ",
- ["mathbf_h"] = "๐ก",
- ["mathbf_i"] = "๐ข",
- ["mathbf_j"] = "๐ฃ",
- ["mathbf_k"] = "๐ค",
- ["mathbf_l"] = "๐ฅ",
- ["mathbf_m"] = "๐ฆ",
- ["mathbf_n"] = "๐ง",
- ["mathbf_o"] = "๐จ",
- ["mathbf_p"] = "๐ฉ",
- ["mathbf_q"] = "๐ช",
- ["mathbf_r"] = "๐ซ",
- ["mathbf_s"] = "๐ฌ",
- ["mathbf_t"] = "๐ญ",
- ["mathbf_u"] = "๐ฎ",
- ["mathbf_v"] = "๐ฏ",
- ["mathbf_w"] = "๐ฐ",
- ["mathbf_x"] = "๐ฑ",
- ["mathbf_y"] = "๐ฒ",
- ["mathbf_z"] = "๐ณ",
- ---_
-
- ---+ ${class, Mathematical bold italic symbols}
- ["mathbfit_A"] = "๐จ",
- ["mathbfit_B"] = "๐ฉ",
- ["mathbfit_C"] = "๐ช",
- ["mathbfit_D"] = "๐ซ",
- ["mathbfit_E"] = "๐ฌ",
- ["mathbfit_F"] = "๐ญ",
- ["mathbfit_G"] = "๐ฎ",
- ["mathbfit_H"] = "๐ฏ",
- ["mathbfit_I"] = "๐ฐ",
- ["mathbfit_J"] = "๐ฑ",
- ["mathbfit_K"] = "๐ฒ",
- ["mathbfit_L"] = "๐ณ",
- ["mathbfit_M"] = "๐ด",
- ["mathbfit_N"] = "๐ต",
- ["mathbfit_O"] = "๐ถ",
- ["mathbfit_P"] = "๐ท",
- ["mathbfit_Q"] = "๐ธ",
- ["mathbfit_R"] = "๐น",
- ["mathbfit_S"] = "๐บ",
- ["mathbfit_T"] = "๐ป",
- ["mathbfit_U"] = "๐ผ",
- ["mathbfit_V"] = "๐ฝ",
- ["mathbfit_W"] = "๐พ",
- ["mathbfit_X"] = "๐ฟ",
- ["mathbfit_Y"] = "๐",
- ["mathbfit_Z"] = "๐",
-
- ["mathbfit_a"] = "๐",
- ["mathbfit_b"] = "๐",
- ["mathbfit_c"] = "๐",
- ["mathbfit_d"] = "๐
",
- ["mathbfit_e"] = "๐",
- ["mathbfit_f"] = "๐",
- ["mathbfit_g"] = "๐",
- ["mathbfit_h"] = "๐",
- ["mathbfit_i"] = "๐",
- ["mathbfit_j"] = "๐",
- ["mathbfit_k"] = "๐",
- ["mathbfit_l"] = "๐",
- ["mathbfit_m"] = "๐",
- ["mathbfit_n"] = "๐",
- ["mathbfit_o"] = "๐",
- ["mathbfit_p"] = "๐",
- ["mathbfit_q"] = "๐",
- ["mathbfit_r"] = "๐",
- ["mathbfit_s"] = "๐",
- ["mathbfit_t"] = "๐",
- ["mathbfit_u"] = "๐",
- ["mathbfit_v"] = "๐",
- ["mathbfit_w"] = "๐",
- ["mathbfit_x"] = "๐",
- ["mathbfit_y"] = "๐",
- ["mathbfit_z"] = "๐",
- ---_
-
- ---+ ${class, Mathematical script symbols}
- ["mathcal_A"] = "๐",
- ["mathcal_B"] = "โฌ",
- ["mathcal_C"] = "๐",
- ["mathcal_D"] = "๐",
- ["mathcal_E"] = "โฐ",
- ["mathcal_F"] = "โฑ",
- ["mathcal_G"] = "๐ข",
- ["mathcal_H"] = "โ",
- ["mathcal_I"] = "โ",
- ["mathcal_J"] = "๐ฅ",
- ["mathcal_K"] = "๐ฆ",
- ["mathcal_L"] = "โ",
- ["mathcal_M"] = "โณ",
- ["mathcal_N"] = "๐ฉ",
- ["mathcal_O"] = "๐ช",
- ["mathcal_P"] = "๐ซ",
- ["mathcal_Q"] = "๐ฌ",
- ["mathcal_R"] = "โ",
- ["mathcal_S"] = "๐ฎ",
- ["mathcal_T"] = "๐ฏ",
- ["mathcal_U"] = "๐ฐ",
- ["mathcal_V"] = "๐ฑ",
- ["mathcal_W"] = "๐ฒ",
- ["mathcal_X"] = "๐ณ",
- ["mathcal_Y"] = "๐ด",
- ["mathcal_Z"] = "๐ต",
-
- ["mathcal_a"] = "๐ถ",
- ["mathcal_b"] = "๐ท",
- ["mathcal_c"] = "๐ธ",
- ["mathcal_d"] = "๐น",
- ["mathcal_e"] = "โฏ",
- ["mathcal_f"] = "๐ป",
- ["mathcal_g"] = "โ",
- ["mathcal_h"] = "๐ฝ",
- ["mathcal_i"] = "๐พ",
- ["mathcal_j"] = "๐ฟ",
- ["mathcal_k"] = "๐",
- ["mathcal_l"] = "๐",
- ["mathcal_m"] = "๐",
- ["mathcal_n"] = "๐",
- ["mathcal_o"] = "โด",
- ["mathcal_p"] = "๐
",
- ["mathcal_q"] = "๐",
- ["mathcal_r"] = "๐",
- ["mathcal_s"] = "๐",
- ["mathcal_t"] = "๐",
- ["mathcal_u"] = "๐",
- ["mathcal_v"] = "๐",
- ["mathcal_w"] = "๐",
- ["mathcal_x"] = "๐",
- ["mathcal_y"] = "๐",
- ["mathcal_z"] = "๐",
- ---_
-
- ---+ ${class, Mathematical FRAKTUR symbols}
- ["mathfrak_A"] = "๐",
- ["mathfrak_B"] = "๐
",
- ["mathfrak_C"] = "โญ",
- ["mathfrak_D"] = "๐",
- ["mathfrak_E"] = "๐",
- ["mathfrak_F"] = "๐",
- ["mathfrak_G"] = "๐",
- ["mathfrak_H"] = "โ",
- ["mathfrak_I"] = "โ",
- ["mathfrak_J"] = "๐",
- ["mathfrak_K"] = "๐",
- ["mathfrak_L"] = "๐",
- ["mathfrak_M"] = "๐",
- ["mathfrak_N"] = "๐",
- ["mathfrak_O"] = "๐",
- ["mathfrak_P"] = "๐",
- ["mathfrak_Q"] = "๐",
- ["mathfrak_R"] = "โ",
- ["mathfrak_S"] = "๐",
- ["mathfrak_T"] = "๐",
- ["mathfrak_U"] = "๐",
- ["mathfrak_V"] = "๐",
- ["mathfrak_W"] = "๐",
- ["mathfrak_X"] = "๐",
- ["mathfrak_Y"] = "๐",
- ["mathfrak_Z"] = "โจ",
-
- ["mathfrak_a"] = "๐",
- ["mathfrak_b"] = "๐",
- ["mathfrak_c"] = "๐ ",
- ["mathfrak_d"] = "๐ก",
- ["mathfrak_e"] = "๐ข",
- ["mathfrak_f"] = "๐ฃ",
- ["mathfrak_g"] = "๐ค",
- ["mathfrak_h"] = "๐ฅ",
- ["mathfrak_i"] = "๐ฆ",
- ["mathfrak_j"] = "๐ง",
- ["mathfrak_k"] = "๐จ",
- ["mathfrak_l"] = "๐ฉ",
- ["mathfrak_m"] = "๐ช",
- ["mathfrak_n"] = "๐ซ",
- ["mathfrak_o"] = "๐ฌ",
- ["mathfrak_p"] = "๐ญ",
- ["mathfrak_q"] = "๐ฎ",
- ["mathfrak_r"] = "๐ฏ",
- ["mathfrak_s"] = "๐ฐ",
- ["mathfrak_t"] = "๐ฑ",
- ["mathfrak_u"] = "๐ฒ",
- ["mathfrak_v"] = "๐ณ",
- ["mathfrak_w"] = "๐ด",
- ["mathfrak_x"] = "๐ต",
- ["mathfrak_y"] = "๐ถ",
- ["mathfrak_z"] = "๐ท",
- ---_
-
- ---+ ${class, Mathematical DOUBLE-STRUCK symbols}
- ["mathbb_0"] = "๐",
- ["mathbb_1"] = "๐",
- ["mathbb_2"] = "๐",
- ["mathbb_3"] = "๐",
- ["mathbb_4"] = "๐",
- ["mathbb_5"] = "๐",
- ["mathbb_6"] = "๐",
- ["mathbb_7"] = "๐",
- ["mathbb_8"] = "๐ ",
- ["mathbb_9"] = "๐ก",
-
- ["mathbb_A"] = "๐ธ",
- ["mathbb_B"] = "๐น",
- ["mathbb_C"] = "โ",
- ["mathbb_D"] = "๐ป",
- ["mathbb_E"] = "๐ผ",
- ["mathbb_F"] = "๐ฝ",
- ["mathbb_G"] = "๐พ",
- ["mathbb_H"] = "โ",
- ["mathbb_I"] = "๐",
- ["mathbb_J"] = "๐",
- ["mathbb_K"] = "๐",
- ["mathbb_L"] = "๐",
- ["mathbb_M"] = "๐",
- ["mathbb_N"] = "โ",
- ["mathbb_O"] = "๐",
- ["mathbb_P"] = "โ",
- ["mathbb_Q"] = "โ",
- ["mathbb_R"] = "โ",
- ["mathbb_S"] = "๐",
- ["mathbb_T"] = "๐",
- ["mathbb_U"] = "๐",
- ["mathbb_V"] = "๐",
- ["mathbb_W"] = "๐",
- ["mathbb_X"] = "๐",
- ["mathbb_Y"] = "๐",
- ["mathbb_Z"] = "โค",
-
- ["mathbb_a"] = "๐",
- ["mathbb_b"] = "๐",
- ["mathbb_c"] = "๐",
- ["mathbb_d"] = "๐",
- ["mathbb_e"] = "๐",
- ["mathbb_f"] = "๐",
- ["mathbb_g"] = "๐",
- ["mathbb_h"] = "๐",
- ["mathbb_i"] = "๐",
- ["mathbb_j"] = "๐",
- ["mathbb_k"] = "๐",
- ["mathbb_l"] = "๐",
- ["mathbb_m"] = "๐",
- ["mathbb_n"] = "๐",
- ["mathbb_o"] = "๐ ",
- ["mathbb_p"] = "๐ก",
- ["mathbb_q"] = "๐ข",
- ["mathbb_r"] = "๐ฃ",
- ["mathbb_s"] = "๐ค",
- ["mathbb_t"] = "๐ฅ",
- ["mathbb_u"] = "๐ฆ",
- ["mathbb_v"] = "๐ง",
- ["mathbb_w"] = "๐จ",
- ["mathbb_x"] = "๐ฉ",
- ["mathbb_y"] = "๐ช",
- ["mathbb_z"] = "๐ซ",
- ---_
-
- ---+ ${class, Mathematical SANS-SERIF bold symbols}
- ["mathsfbf_0"] = "๐ฌ",
- ["mathsfbf_1"] = "๐ญ",
- ["mathsfbf_2"] = "๐ฎ",
- ["mathsfbf_3"] = "๐ฏ",
- ["mathsfbf_4"] = "๐ฐ",
- ["mathsfbf_5"] = "๐ฑ",
- ["mathsfbf_6"] = "๐ฒ",
- ["mathsfbf_7"] = "๐ณ",
- ["mathsfbf_8"] = "๐ด",
- ["mathsfbf_9"] = "๐ต",
-
- ["mathsfbf_A"] = "๐",
- ["mathsfbf_B"] = "๐",
- ["mathsfbf_C"] = "๐",
- ["mathsfbf_D"] = "๐",
- ["mathsfbf_E"] = "๐",
- ["mathsfbf_F"] = "๐",
- ["mathsfbf_G"] = "๐",
- ["mathsfbf_H"] = "๐",
- ["mathsfbf_I"] = "๐",
- ["mathsfbf_J"] = "๐",
- ["mathsfbf_K"] = "๐",
- ["mathsfbf_L"] = "๐",
- ["mathsfbf_M"] = "๐ ",
- ["mathsfbf_N"] = "๐ก",
- ["mathsfbf_O"] = "๐ข",
- ["mathsfbf_P"] = "๐ฃ",
- ["mathsfbf_Q"] = "๐ค",
- ["mathsfbf_R"] = "๐ฅ",
- ["mathsfbf_S"] = "๐ฆ",
- ["mathsfbf_T"] = "๐ง",
- ["mathsfbf_U"] = "๐จ",
- ["mathsfbf_V"] = "๐ฉ",
- ["mathsfbf_W"] = "๐ช",
- ["mathsfbf_X"] = "๐ซ",
- ["mathsfbf_Y"] = "๐ฌ",
- ["mathsfbf_Z"] = "๐ญ",
-
- ["mathsfbf_a"] = "๐ฎ",
- ["mathsfbf_b"] = "๐ฏ",
- ["mathsfbf_c"] = "๐ฐ",
- ["mathsfbf_d"] = "๐ฑ",
- ["mathsfbf_e"] = "๐ฒ",
- ["mathsfbf_f"] = "๐ณ",
- ["mathsfbf_g"] = "๐ด",
- ["mathsfbf_h"] = "๐ต",
- ["mathsfbf_i"] = "๐ถ",
- ["mathsfbf_j"] = "๐ท",
- ["mathsfbf_k"] = "๐ธ",
- ["mathsfbf_l"] = "๐น",
- ["mathsfbf_m"] = "๐บ",
- ["mathsfbf_n"] = "๐ป",
- ["mathsfbf_o"] = "๐ผ",
- ["mathsfbf_p"] = "๐ฝ",
- ["mathsfbf_q"] = "๐พ",
- ["mathsfbf_r"] = "๐ฟ",
- ["mathsfbf_s"] = "๐",
- ["mathsfbf_t"] = "๐",
- ["mathsfbf_u"] = "๐",
- ["mathsfbf_v"] = "๐",
- ["mathsfbf_w"] = "๐",
- ["mathsfbf_x"] = "๐
",
- ["mathsfbf_y"] = "๐",
- ["mathsfbf_z"] = "๐",
- ---_
-
- ---+ ${class, Mathematical SANS-SERIF italic symbols}
- ["mathsfit_A"] = "๐",
- ["mathsfit_B"] = "๐",
- ["mathsfit_C"] = "๐",
- ["mathsfit_D"] = "๐",
- ["mathsfit_E"] = "๐",
- ["mathsfit_F"] = "๐",
- ["mathsfit_G"] = "๐",
- ["mathsfit_H"] = "๐",
- ["mathsfit_I"] = "๐",
- ["mathsfit_J"] = "๐",
- ["mathsfit_K"] = "๐",
- ["mathsfit_L"] = "๐",
- ["mathsfit_M"] = "๐",
- ["mathsfit_N"] = "๐",
- ["mathsfit_O"] = "๐",
- ["mathsfit_P"] = "๐",
- ["mathsfit_Q"] = "๐",
- ["mathsfit_R"] = "๐",
- ["mathsfit_S"] = "๐",
- ["mathsfit_T"] = "๐",
- ["mathsfit_U"] = "๐",
- ["mathsfit_V"] = "๐",
- ["mathsfit_W"] = "๐",
- ["mathsfit_X"] = "๐",
- ["mathsfit_Y"] = "๐ ",
- ["mathsfit_Z"] = "๐ก",
-
- ["mathsfit_a"] = "๐ข",
- ["mathsfit_b"] = "๐ฃ",
- ["mathsfit_c"] = "๐ค",
- ["mathsfit_d"] = "๐ฅ",
- ["mathsfit_e"] = "๐ฆ",
- ["mathsfit_f"] = "๐ง",
- ["mathsfit_g"] = "๐จ",
- ["mathsfit_h"] = "๐ฉ",
- ["mathsfit_i"] = "๐ช",
- ["mathsfit_j"] = "๐ซ",
- ["mathsfit_k"] = "๐ฌ",
- ["mathsfit_l"] = "๐ญ",
- ["mathsfit_m"] = "๐ฎ",
- ["mathsfit_n"] = "๐ฏ",
- ["mathsfit_o"] = "๐ฐ",
- ["mathsfit_p"] = "๐ฑ",
- ["mathsfit_q"] = "๐ฒ",
- ["mathsfit_r"] = "๐ณ",
- ["mathsfit_s"] = "๐ด",
- ["mathsfit_t"] = "๐ต",
- ["mathsfit_u"] = "๐ถ",
- ["mathsfit_v"] = "๐ท",
- ["mathsfit_w"] = "๐ธ",
- ["mathsfit_x"] = "๐น",
- ["mathsfit_y"] = "๐บ",
- ["mathsfit_z"] = "๐ป",
- ---_
-
- ---+ ${class, Mathematical SANS-SERIF bold italic symbols}
- ["mathsfbfit_A"] = "๐ผ",
- ["mathsfbfit_B"] = "๐ฝ",
- ["mathsfbfit_C"] = "๐พ",
- ["mathsfbfit_D"] = "๐ฟ",
- ["mathsfbfit_E"] = "๐",
- ["mathsfbfit_F"] = "๐",
- ["mathsfbfit_G"] = "๐",
- ["mathsfbfit_H"] = "๐",
- ["mathsfbfit_I"] = "๐",
- ["mathsfbfit_J"] = "๐
",
- ["mathsfbfit_K"] = "๐",
- ["mathsfbfit_L"] = "๐",
- ["mathsfbfit_M"] = "๐",
- ["mathsfbfit_N"] = "๐",
- ["mathsfbfit_O"] = "๐",
- ["mathsfbfit_P"] = "๐",
- ["mathsfbfit_Q"] = "๐",
- ["mathsfbfit_R"] = "๐",
- ["mathsfbfit_S"] = "๐",
- ["mathsfbfit_T"] = "๐",
- ["mathsfbfit_U"] = "๐",
- ["mathsfbfit_V"] = "๐",
- ["mathsfbfit_W"] = "๐",
- ["mathsfbfit_X"] = "๐",
- ["mathsfbfit_Y"] = "๐",
- ["mathsfbfit_Z"] = "๐",
-
- ["mathsfbfit_a"] = "๐",
- ["mathsfbfit_b"] = "๐",
- ["mathsfbfit_c"] = "๐",
- ["mathsfbfit_d"] = "๐",
- ["mathsfbfit_e"] = "๐",
- ["mathsfbfit_f"] = "๐",
- ["mathsfbfit_g"] = "๐",
- ["mathsfbfit_h"] = "๐",
- ["mathsfbfit_i"] = "๐",
- ["mathsfbfit_j"] = "๐",
- ["mathsfbfit_k"] = "๐ ",
- ["mathsfbfit_l"] = "๐ก",
- ["mathsfbfit_m"] = "๐ข",
- ["mathsfbfit_n"] = "๐ฃ",
- ["mathsfbfit_o"] = "๐ค",
- ["mathsfbfit_p"] = "๐ฅ",
- ["mathsfbfit_q"] = "๐ฆ",
- ["mathsfbfit_r"] = "๐ง",
- ["mathsfbfit_s"] = "๐จ",
- ["mathsfbfit_t"] = "๐ฉ",
- ["mathsfbfit_u"] = "๐ช",
- ["mathsfbfit_v"] = "๐ซ",
- ["mathsfbfit_w"] = "๐ฌ",
- ["mathsfbfit_x"] = "๐ญ",
- ["mathsfbfit_y"] = "๐ฎ",
- ["mathsfbfit_z"] = "๐ฏ",
- ---_
-
- ---+ ${class, Mathematical mono-space symbols}
- ["mathtt_0"] = "๐ถ",
- ["mathtt_1"] = "๐ท",
- ["mathtt_2"] = "๐ธ",
- ["mathtt_3"] = "๐น",
- ["mathtt_4"] = "๐บ",
- ["mathtt_5"] = "๐ป",
- ["mathtt_6"] = "๐ผ",
- ["mathtt_7"] = "๐ฝ",
- ["mathtt_8"] = "๐พ",
- ["mathtt_9"] = "๐ฟ",
-
- ["mathtt_A"] = "๐ฐ",
- ["mathtt_B"] = "๐ฑ",
- ["mathtt_C"] = "๐ฒ",
- ["mathtt_D"] = "๐ณ",
- ["mathtt_E"] = "๐ด",
- ["mathtt_F"] = "๐ต",
- ["mathtt_G"] = "๐ถ",
- ["mathtt_H"] = "๐ท",
- ["mathtt_I"] = "๐ธ",
- ["mathtt_J"] = "๐น",
- ["mathtt_K"] = "๐บ",
- ["mathtt_L"] = "๐ป",
- ["mathtt_M"] = "๐ผ",
- ["mathtt_N"] = "๐ฝ",
- ["mathtt_O"] = "๐พ",
- ["mathtt_P"] = "๐ฟ",
- ["mathtt_Q"] = "๐",
- ["mathtt_R"] = "๐",
- ["mathtt_S"] = "๐",
- ["mathtt_T"] = "๐",
- ["mathtt_U"] = "๐",
- ["mathtt_V"] = "๐
",
- ["mathtt_W"] = "๐",
- ["mathtt_X"] = "๐",
- ["mathtt_Y"] = "๐",
- ["mathtt_Z"] = "๐",
-
- ["mathtt_a"] = "๐",
- ["mathtt_b"] = "๐",
- ["mathtt_c"] = "๐",
- ["mathtt_d"] = "๐",
- ["mathtt_e"] = "๐",
- ["mathtt_f"] = "๐",
- ["mathtt_g"] = "๐",
- ["mathtt_h"] = "๐",
- ["mathtt_i"] = "๐",
- ["mathtt_j"] = "๐",
- ["mathtt_k"] = "๐",
- ["mathtt_l"] = "๐",
- ["mathtt_m"] = "๐",
- ["mathtt_n"] = "๐",
- ["mathtt_o"] = "๐",
- ["mathtt_p"] = "๐",
- ["mathtt_q"] = "๐",
- ["mathtt_r"] = "๐",
- ["mathtt_s"] = "๐",
- ["mathtt_t"] = "๐",
- ["mathtt_u"] = "๐",
- ["mathtt_v"] = "๐",
- ["mathtt_w"] = "๐ ",
- ["mathtt_x"] = "๐ก",
- ["mathtt_y"] = "๐ข",
- ["mathtt_z"] = "๐ฃ"
- ---_
- ---_
-};
-
----@type { [string]: markview.operators.config } Configuration table for latex operators
-latex.operator_conf = {
- ---+ ${class, Trigonometric functions}
- sin = {
- operator = {
- conceal = "",
-
- virt_text_pos = "inline",
- virt_text = { { latex.operators.sin, "Special" } }
- },
- args = {
- {
- before = {
- virt_text_pos = "inline",
- virt_text = { { " " } }
- }
- }
- }
- },
- cos = {
- operator = {
- conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.cos, "Special" } }
- },
- args = {
- {
- before = { virt_text_pos = "inline", virt_text = { { " " } } }
- }
- }
- },
- tan = {
- operator = {
- conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.tan, "Special" } }
- },
- args = {
- {
- before = { virt_text_pos = "inline", virt_text = { { " " } } }
- }
- }
- },
-
- csc = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.csc, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- sec = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.sec, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- cot = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.cot, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
-
- sinh = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.sinh, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- cosh = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.cosh, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- tanh = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.tanh, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- coth = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.coth, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
-
- arcsin = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.arcsin, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- arccos = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.arccos, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- arctan = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.arctan, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- ---_
-
- ---+ ${class, Logarithmic functions}
- ln = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.ln, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- log = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.log, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- exp = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.exp, "Special" } } },
- args = { { before = { virt_text_pos = "inline", virt_text = { { " " } } } } }
- },
- ---_
-
- lvert = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.lvert, "@operator.latex" } } }
- },
- lVert = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.lVert, "@operator.latex" } } }
- },
-
- sqrt = {
- operator = { conceal = "", virt_text_pos = "inline", virt_text = { { latex.operators.sqrt, "@operator.latex" } } }
- },
-
- frac = {
- operator = {
- conceal = ""
- },
- args = {
- {
- after = function (_, content)
- if content.inside then
- return { virt_text_pos = "inline", virt_text = { { latex.symbols.div } } }
- end
-
- return { virt_text_pos = "inline", virt_text = { { latex.symbols.div, "@operator.latex" } } }
- end
- }
- }
- },
-
- set = {
- operator = { conceal = "" }
- }
-}
-
---- Renders brackets
----@param buffer integer
----@param content table
----@param user_config markview.latex.brackets
-latex.render_brackets = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = content.has_operator and { { "(", set_hl(user_config.hl) } } or nil,
-
- hl_mode = "combine",
- end_col = content.col_start + 1,
- conceal = ""
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end - 1, {
- virt_text_pos = "inline",
- virt_text = content.has_operator and { { ")", set_hl(user_config.hl) } } or nil,
-
- hl_mode = "combine",
- end_col = content.col_end,
- conceal = ""
- });
-end
-
---- Renders superscript text
----@param buffer integer
----@param content table
----@param user_config markview.latex.superscript
-latex.render_superscript = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- local numbers = {
- ["0"] = "โฐ", ["1"] = "ยน", ["2"] = "ยฒ",
- ["3"] = "ยณ", ["4"] = "โด", ["5"] = "โต",
- ["6"] = "โถ", ["7"] = "โท", ["8"] = "โธ",
- ["9"] = "โน"
- };
-
- local internal = content.text;
- local skip = 1;
-
- if content.text:match("^%^[^{]$") then
- internal = content.text:match("^%^(.+)$")
-
- if internal:match("^([%s%d]+)$") then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- end_col = content.col_start + 1,
- conceal = ""
- });
- else
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = { { "^(", set_hl(user_config.hl) } },
-
- end_col = content.col_start + 1,
- conceal = "",
-
- hl_mode = "combine"
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end, {
- virt_text_pos = "inline",
- virt_text = { { ")", set_hl(user_config.hl) } },
-
- hl_mode = "combine"
- });
- end
- elseif content.text:match("^%^%{(.+)%}$") and user_config.conceal_brackets ~= false then
- skip = 2;
- internal = content.text:match("^%^%{(.+)%}$")
-
- if internal:match("^([%s%d]+)$") then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- end_col = content.col_start + 2,
- conceal = ""
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end - 1, {
- end_col = content.col_end,
- conceal = ""
- });
- elseif content.special_syntax then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = { { " " } },
-
- end_col = content.col_start + 2,
- conceal = "",
-
- hl_mode = "combine"
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end - 1, {
- end_col = content.col_end,
- conceal = ""
- });
- else
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = { { "^(", set_hl(user_config.hl) } },
-
- end_col = content.col_start + 2,
- conceal = "",
-
- hl_mode = "combine"
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end - 1, {
- virt_text_pos = "inline",
- virt_text = { { ")", set_hl(user_config.hl) } },
-
- end_col = content.col_end,
- conceal = "",
-
- hl_mode = "combine"
- });
- end
- end
-
- if internal:match("^([%d%s]+)$") then
- local _v = {};
-
- for num in internal:gmatch(".") do
- table.insert(_v, {
- numbers[num] or num,
- set_hl(user_config.hl)
- });
- end
-
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start + skip, {
- virt_text_pos = "overlay",
- virt_text = _v,
-
- hl_mode = "combine"
- });
- elseif user_config.hl then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start + 1, {
- hl_group = set_hl(user_config.hl),
-
- end_col = content.col_end,
- hl_mode = "combine"
- });
- end
-end
-
---- Renders subscript text
----@param buffer integer
----@param content table
----@param user_config markview.latex.subscript
-latex.render_subscript = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- local numbers = {
- ["0"] = "โ", ["1"] = "โ", ["2"] = "โ",
- ["3"] = "โ", ["4"] = "โ", ["5"] = "โ
",
- ["6"] = "โ", ["7"] = "โ", ["8"] = "โ",
- ["9"] = "โ"
- };
-
- local internal = content.text;
- local skip = 1;
-
- if content.text:match("^%_[^{]$") then
- internal = content.text:match("^%_(.+)$")
-
- if internal:match("^([%s%d]+)$") then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- end_col = content.col_start + 1,
- conceal = ""
- });
- else
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = { { "_(", set_hl(user_config.hl) } },
-
- end_col = content.col_start + 1,
- conceal = "",
-
- hl_mode = "combine"
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end, {
- virt_text_pos = "inline",
- virt_text = { { ")", set_hl(user_config.hl) } },
-
- hl_mode = "combine"
- });
- end
- elseif content.text:match("^%_%{(.+)%}$") and user_config.conceal_brackets ~= false then
- skip = 2;
- internal = content.text:match("^%_%{(.+)%}$")
-
- if internal:match("^([%s%d]+)$") then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- end_col = content.col_start + 2,
- conceal = ""
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end - 1, {
- end_col = content.col_end,
- conceal = ""
- });
- elseif content.special_syntax then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = { { " " } },
-
- end_col = content.col_start + 2,
- conceal = "",
-
- hl_mode = "combine"
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end - 1, {
- end_col = content.col_end,
- conceal = ""
- });
- else
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = { { "_(", set_hl(user_config.hl) } },
-
- end_col = content.col_start + 2,
- conceal = "",
-
- hl_mode = "combine"
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end - 1, {
- virt_text_pos = "inline",
- virt_text = { { ")", set_hl(user_config.hl) } },
-
- end_col = content.col_end,
- conceal = "",
-
- hl_mode = "combine"
- });
- end
- end
-
- if internal:match("^([%d%s]+)$") then
- local _v = {};
-
- for num in internal:gmatch(".") do
- table.insert(_v, {
- numbers[num] or num,
- set_hl(user_config.hl)
- });
- end
-
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start + skip, {
- virt_text_pos = "overlay",
- virt_text = _v,
-
- hl_mode = "combine"
- });
- elseif user_config.hl then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start + 1, {
- hl_group = set_hl(user_config.hl),
-
- end_col = content.col_end,
- hl_mode = "combine"
- });
- end
-end
-
---- Renders symbols
----@param buffer integer
----@param content table
----@param user_config markview.conf.latex
-latex.render_symbol = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- elseif not content.text then
- return;
- end
-
- local symbol_conf = user_config.symbols;
-
- if not symbol_conf or symbol_conf.enable == false then
- return;
- end
-
- local get = function (val)
- if pcall(val, buffer) then
- return val(buffer);
- end
-
- return val;
- end
-
- local get_hl = function (val)
- if not symbol_conf.groups or not val then
- return set_hl(symbol_conf.hl);
- end
-
- for _, group in ipairs(symbol_conf.groups) do
- if vim.islist(group.match) and vim.list_contains(group.match, val) then
- return set_hl(group.hl);
- elseif pcall(group.match --[[ @as function ]], val) and group.match(val) == true then
- return set_hl(group.hl);
- end
- end
-
- return set_hl(symbol_conf.hl);
- end
-
- local _t = get(latex.symbols[content.text]);
-
- if not _t then
- return;
- end
-
- local hl = get_hl(content.text);
-
- if content.inside and user_config[content.inside] and user_config[content.inside].hl then
- hl = user_config[content.inside].hl;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { _t, set_hl(hl) }
- },
-
- hl_mode = "combine",
- end_col = content.col_end,
- conceal = ""
- });
-end
-
---- Renders operators
----@param buffer integer
----@param content table
----@param user_config markview.latex.operators
-latex.render_operator = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- elseif not content.text then
- return;
- end
-
- local get = function (val, ...)
- if pcall(val, buffer, ...) then
- return val(buffer, ...);
- end
-
- return val;
- end
-
- local operator_conf = user_config.configs[content.name];
-
- -- Operator doesn't have a config
- -- skip it
- if not operator_conf then
- return;
- end
-
- if operator_conf.operator then
- vim.api.nvim_buf_set_extmark(
- buffer,
- latex.namespace,
- content.row_start,
- content.col_start,
- vim.tbl_extend("force", operator_conf.operator, {
- end_col = content.col_start + 1 + #content.name,
- hl_mode = "combine"
- })
- )
- end
-
- if vim.islist(operator_conf.args) then
- for a, arg in ipairs(content.args) do
- if not operator_conf.args[a] then
- goto noConf;
- end
-
- local arg_conf = vim.deepcopy(operator_conf.args[a] or {});
-
- if arg_conf.before then
- arg_conf.before = get(arg_conf.before, arg);
-
- vim.api.nvim_buf_set_extmark(
- buffer,
- latex.namespace,
- arg.row_start,
- arg.col_start,
- vim.tbl_extend("force", arg_conf.before, {
- hl_mode = "combine"
- })
- )
- end
-
- if arg_conf.scope then
- arg_conf.scope = get(arg_conf.scope, arg);
-
- vim.api.nvim_buf_set_extmark(
- buffer,
- latex.namespace,
- arg.row_start,
- arg.col_start,
- vim.tbl_extend("force", arg_conf.scope, {
- hl_mode = "combine",
- end_col = arg.col_end
- })
- )
- end
-
- if arg_conf.after then
- arg_conf.after = get(arg_conf.after, arg);
-
- vim.api.nvim_buf_set_extmark(
- buffer,
- latex.namespace,
- arg.row_end,
- arg.col_end,
- vim.tbl_extend("force", arg_conf.after, {
- hl_mode = "combine"
- })
- )
- end
-
- ::noConf::
- end
- end
-end
-
---- Renders fonts
----@param buffer integer
----@param content table
----@param user_config markview.latex.symbols
-latex.render_font = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- elseif not content.text then
- return;
- end
-
- local get = function (val)
- if pcall(val, buffer) then
- return val(buffer);
- end
-
- return val;
- end
-
- local col = content.col_start + vim.fn.strchars(content.font) + 2;
-
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- end_col = col - 1,
- conceal = ""
- });
-
- content.text = content.text:gsub("[%{%}]", "|");
-
- for m in content.text:gmatch("\\(%a+)") do
- content.text = content.text:gsub("\\(%a+)", string.rep("|", vim.fn.strchars(m) + 1))
- end
-
- for letter in content.text:gmatch(".") do
- if latex.symbols[content.font .. "_" .. letter] then
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, col, {
- virt_text_pos = "overlay",
- virt_text = { { get(latex.symbols[content.font .. "_" .. letter]) } },
-
- hl_mode = "combine"
- });
- end
-
- col = col + 1;
- end
-end
-
---- Renders inline math
----@param buffer integer
----@param content table
----@param user_config { enable: boolean }
-latex.render_inline = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- end_col = content.col_start + #"$",
- conceal = ""
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end, content.col_end - #"$", {
- end_col = content.col_end,
- conceal = ""
- });
-end
-
---- Renders LaTeX blocks
----@param buffer integer
----@param content table
----@param user_config markview.latex.block
-latex.render_block = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- end_col = content.col_start + 2,
-
- line_hl_group = set_hl(user_config.hl),
- conceal = ""
- });
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_end - 1, content.col_end - 2, {
- virt_text_pos = "right_align",
- virt_text = {
- user_config.text
- },
-
- end_col = content.col_end,
- conceal = "",
-
- line_hl_group = set_hl(user_config.hl),
- hl_mode = "combine"
- });
-
- for l = content.row_start + 1, (content.row_end - 1) - 1, 1 do
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, l, content.col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", user_config.pad_amount or 3) }
- },
-
- line_hl_group = set_hl(user_config.hl),
- end_row = l,
- });
- end
-end
-
-latex.render_specials = {
- ["text"] = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, latex.namespace, content.row_start, content.col_start, {
- end_col = content.col_start + 5,
- conceal = ""
- });
- end
-}
-
---- Renders latex
----@param render_type string
----@param buffer integer
----@param content table
----@param config_table markview.configuration
-latex.render = function (render_type, buffer, content, config_table)
- if not config_table or not config_table.latex then
- return;
- elseif config_table.latex and config_table.latex.enable == false then
- return;
- end
-
- ---@type markview.conf.latex
- local conf = config_table.latex;
-
- if conf.symbols and type(conf.symbols.overwrite) == "table" then
- for name, symbol in pairs(conf.symbols.overwrite) do
- latex.symbols[name] = symbol;
- end
- end
-
- if render_type == "latex_inline" then
- pcall(latex.render_inline, buffer, content, conf.inline)
- elseif render_type == "latex_block" then
- pcall(latex.render_block, buffer, content, conf.block)
- elseif render_type == "latex_bracket" then
- pcall(latex.render_brackets, buffer, content, conf.brackets)
- elseif render_type == "latex_superscript" then
- pcall(latex.render_superscript, buffer, content, conf.superscript)
- elseif render_type == "latex_subscript" then
- pcall(latex.render_subscript, buffer, content, conf.subscript)
- elseif render_type == "latex_font" then
- pcall(latex.render_font, buffer, content, conf.symbols)
- elseif render_type == "latex_symbol" then
- pcall(latex.render_symbol, buffer, content, conf)
- elseif render_type == "latex_operator" then
- pcall(latex.render_operator, buffer, content, conf.operators)
- elseif render_type == "latex_special_syntax" then
- pcall(latex.render_specials[content.name], buffer, content, conf.operators)
- end
-end
-
-return latex;
diff --git a/lua/markview/links.lua b/lua/markview/links.lua
new file mode 100644
index 0000000..73e5976
--- /dev/null
+++ b/lua/markview/links.lua
@@ -0,0 +1,304 @@
+--- A simple link opener for `markview.nvim`.
+---
+--- This is a `tree-sitter` based wrapper
+--- for `vim.ui.input()`.
+local links = {};
+local health = require("markview.health");
+local spec = require("markview.spec");
+
+--- Tree-sitter node processor.
+---@type { [string]: fun(buffer: integer, node: table): string? }
+local processors = {};
+
+---+${lua}
+
+---@param buffer integer
+---@param node table
+---@return string?
+processors.email_autolink = function (buffer, node)
+ local address = vim.treesitter.get_node_text(node, buffer);
+ address = address:gsub("^%<", ""):gsub("%>$", "");
+
+ return string.format("mailto:%s", address);
+end
+
+---@param buffer integer
+---@param node table
+---@return string?
+processors.inline_link = function (buffer, node)
+ local address = node:child(4);
+
+ if address == nil then
+ return;
+ end
+
+ return vim.treesitter.get_node_text(address, buffer);
+end
+
+---@param buffer integer
+---@param node table
+---@return string?
+processors.link_reference_definition = function (buffer, node)
+ local address = node:named_child(1);
+
+ if address == nil then
+ return;
+ end
+
+ return vim.treesitter.get_node_text(address, buffer);
+end
+
+---@param buffer integer
+---@param node table
+---@return string?
+processors.shortcut_link = function (buffer, node)
+ local range = { node:range() };
+ local text = vim.treesitter.get_node_text(node, buffer);
+
+ local before = vim.api.nvim_buf_get_lines(buffer, range[1], range[1] + 1, false)[1];
+ before = before:sub(0, range[2]);
+
+ local after = vim.api.nvim_buf_get_lines(buffer, range[3], range[3] + 1, false)[1];
+ after = after:sub(range[4]);
+
+ if ( range[1] == range[3] ) and before:match("%[$") and after:match("^%]") then
+ -- Obsidian internal links or embed files.
+ return text:gsub("^%[", ""):gsub("%]$", "");
+ else
+ return text:gsub("\n", ""):gsub("^%[", ""):gsub("%]$", "");
+ end
+end
+
+---@param buffer integer
+---@param node table
+---@return string?
+processors.image = function (buffer, node)
+ local address = node:named_child(1);
+
+ if address == nil then
+ return;
+ end
+
+ return vim.treesitter.get_node_text(address, buffer);
+end
+
+---@param buffer integer
+---@param node table
+---@return string?
+processors.uri_autolink = function (buffer, node)
+ local address = vim.treesitter.get_node_text(node, buffer);
+ address = address:gsub("^%<", ""):gsub("%>$", "");
+
+ return address;
+end
+
+---@param buffer integer
+---@param node table
+---@return string?
+processors.url = function (buffer, node)
+ return vim.treesitter.get_node_text(node, buffer);
+end
+
+---_
+
+--- [ Stuff ] ------------------------------------------------------------------------------
+
+--- Checks if {address} is a text file or not.
+---@param address string
+---@return boolean
+links.__text_file = function (address)
+ ---+${lua}
+
+ local file = io.open(address, "rb");
+
+ if file == nil then
+ --- File doesn't exist.
+ return false;
+ end
+
+ ---@type integer
+ local read_bytes = spec.get({ "experimental", "read_chunk_size" }, { fallback = 1024 });
+ ---@type string
+ local bytes = file:read(read_bytes);
+
+ file:close();
+
+ if bytes == nil then
+ --- Unreadable or Empty file.
+ return false;
+ elseif bytes:find("\x00") then
+ --- Null byte?
+ return false;
+ end
+
+ local bom = bytes:sub(1, 3);
+
+ if bom == "\xEF\xBB\xBF" then
+ return true;
+ elseif bom == "\xFF\xFE" or bom == "\xFE\xFF" then
+ return true;
+ end
+
+ local valid, invalid = 0, 0;
+
+ for b = 1, #bytes do
+ local byte = string.byte(bytes, b);
+
+ if byte >= 32 and byte <= 126 then
+ valid = valid + 1;
+ elseif vim.list_contains({ 9, 10, 13 }, byte) then
+ valid = valid + 1;
+ else
+ invalid = invalid + 1;
+ end
+ end
+
+ local validity_threshold = 0.9;
+
+ if (valid / #bytes) >= validity_threshold then
+ return true;
+ else
+ return false;
+ end
+ ---_
+end
+
+--- Internal functions to open links.
+---@param buffer integer
+---@param address string?
+links.__open = function (buffer, address)
+ ---+${lua}
+ if type(address) ~= "string" then
+ vim.api.nvim_buf_call(buffer, function ()
+ address = vim.fn.expand("");
+ end);
+ end
+
+ ---@cast address string
+
+ --- Checks if a {path} can be opened.
+ ---@param path string
+ ---@return boolean
+ local function can_open (path)
+ ---+${lua}
+
+ local stat = vim.uv.fs_stat(path)
+
+ if stat == nil then
+ return false;
+ elseif stat.type ~= "file" then
+ return false;
+ end
+
+ return true;
+ ---_
+ end
+
+ --- Wrapper for `vim.ui.open`.
+ ---@param path string
+ local ui_open = function (path)
+ ---+${lua}
+
+ local cmd, err = vim.ui.open(path);
+
+ if cmd then
+ cmd:wait();
+ elseif err then
+ health.notify("msg", {
+ message = { err, "DiagnosticError" }
+ });
+ end
+ ---_
+ end
+
+ if can_open(address) == false then
+ --- {address} isn't a file or it doesn't
+ --- exist.
+ ui_open(address);
+ elseif links.__text_file(address) == true then
+ local command = spec.get({ "experimental", "file_open_command" }, { fallback = "tabnew" });
+
+ --- Text file. Open inside Neovim.
+ vim.cmd(string.format("%s %s", command, address));
+ else
+ --- This is a file, but not a text file.
+ ui_open(address);
+ end
+ ---_
+end
+
+--- `Tree-sitter` based link opener.
+---@param buffer integer
+links.treesitter = function (buffer)
+ ---+${lua}
+
+ local utils = require("markview.utils");
+ local node;
+
+ if vim.api.nvim_get_current_buf() == buffer then
+ node = vim.treesitter.get_node({ ignore_injections = false });
+ else
+ local primary_win = utils.buf_getwin(buffer);
+ local cursor = vimm.api.nvim_win_get_cursor(primary_win);
+
+ node = vim.treesitter.get_node({ bufnr = buffer, pos = cursor, ignore_injections = true });
+ end
+
+ while node do
+ if pcall(processors[node:type()], buffer, node) then
+ local link = processors[node:type()](buffer, node);
+
+ links.__open(buffer, link);
+ return;
+ end
+
+ node = node:parent();
+ end
+ ---_
+end
+
+--- Opens the link under the cursor.
+---
+--- Initially uses tree-sitter to find
+--- a valid link.
+---
+--- Fallback to the `` if no node
+--- was found.
+links.open = function ()
+ ---+${lua}
+
+ local utils = require("markview.utils");
+ local buffer = vim.api.nvim_get_current_buf();
+
+ local ts_available = function ()
+ local ft = vim.bo[buffer].ft;
+ local language = vim.treesitter.language.get_lang(ft);
+
+ if language == nil then
+ return false;
+ elseif utils.parser_installed(language) == false then
+ return false;
+ end
+
+ return true;
+ end
+
+ if ts_available() == true then
+ --- Use tree-sitter based link detector.
+ links.treesitter(buffer);
+ else
+ health.notify("msg", {
+ message = {
+ { " tree-sitter parsers ", "DiagnosticVirtualTextHint" },
+ { " not found! Using " },
+ { " ", "DiagnosticVirtualTextInfo" },
+ { "." }
+ }
+ });
+
+ links.__open(buffer);
+ end
+ ---_
+end
+
+return links;
diff --git a/lua/markview/parser.lua b/lua/markview/parser.lua
index c724c3f..2b5572e 100644
--- a/lua/markview/parser.lua
+++ b/lua/markview/parser.lua
@@ -1,1349 +1,135 @@
local parser = {};
-local lang = require("markview.languages")
+local health = require("markview.health");
-local ts_available, treesitter_parsers = pcall(require, "nvim-treesitter.parsers");
+parser.html = require("markview.parsers.html");
+parser.markdown = require("markview.parsers.markdown");
+parser.markdown_inline = require("markview.parsers.markdown_inline");
+parser.html = require("markview.parsers.html");
+parser.latex = require("markview.parsers.latex");
+parser.typst = require("markview.parsers.typst");
+parser.yaml = require("markview.parsers.yaml");
---- Checks if a parser is available or not
----@param parser_name string
----@return boolean
-local function parser_installed(parser_name)
- return (ts_available and treesitter_parsers.has_parser(parser_name)) or pcall(vim.treesitter.query.get, parser_name, "highlights")
-end
-
----@type markview.configuration | {}
-parser.cached_conf = {};
-parser.avoid_ranges = {};
-
-parser.escape_string = function (input)
- input = input:gsub("%%", "%%%");
-
- input = input:gsub("%(", "%%(");
- input = input:gsub("%)", "%%)");
-
- input = input:gsub("%.", "%%.");
- input = input:gsub("%+", "%%+");
- input = input:gsub("%-", "%%-");
- input = input:gsub("%*", "%%*");
- input = input:gsub("%?", "%%?");
- input = input:gsub("%^", "%%^");
- input = input:gsub("%$", "%%$");
-
- input = input:gsub("%[", "%%[");
- input = input:gsub("%]", "%%]");
+parser.ignore_ranges = {};
- return input;
-end
-
-parser.get_md_len = function (text)
- local final_string = text;
- local len = vim.fn.strdisplaywidth(text);
-
- for str_a, internal, str_b in final_string:gmatch("([*]+)([^*]+)([*]+)") do
- local valid_signs = math.max(vim.fn.strdisplaywidth(str_a), vim.fn.strdisplaywidth(str_b));
+--- Cached contents
+parser.cached = {};
- for s = 1, valid_signs do
- local a = str_a:sub(s, s);
- local b = str_b:reverse():sub(s, s);
+parser.create_ignore_range = function (language, items)
+ local _r = {};
- if a == b then
- len = len - 2;
-
- final_string = final_string:gsub(a .. parser.escape_string(internal) .. b, internal);
- end
+ if language == "markdown" then
+ for _, item in ipairs(items["markdown_code_block"] or {}) do
+ table.insert(_r, { item.range.row_start, item.range.row_end })
end
- end
-
- for str_a, internal, str_b in final_string:gmatch("([_]+)([^_]+)([_]+)") do
- local valid_signs = math.max(vim.fn.strdisplaywidth(str_a), vim.fn.strdisplaywidth(str_b));
-
- for s = 1, valid_signs do
- local a = str_a:sub(s, s);
- local b = str_b:reverse():sub(s, s);
-
- if a == b then
- len = len - 2;
-
- final_string = final_string:gsub(a .. parser.escape_string(internal) .. b, internal);
- end
+ elseif language == "typst" then
+ for _, item in ipairs(items["typst_raw_block"] or {}) do
+ table.insert(_r, { item.range.row_start, item.range.row_end })
end
end
- for inline_code in final_string:gmatch("`([^`]+)`") do
- len = len - 2;
-
- local _r = inline_code:gsub("[%[%]%(%)%*%_]", "X")
- final_string = final_string:gsub("`" .. parser.escape_string(inline_code) .. "`", _r);
- end
-
- --- Image links: 
- for link, address in final_string:gmatch("%!%[(.-)%]%((.-)%)") do
- len = len - vim.fn.strdisplaywidth("![]()" .. address);
-
- final_string = final_string:gsub("%!%[" .. link .. "%]%(" .. address .. "%)", link);
- end
-
- --- Image links: ![link][address]
- for link, address in final_string:gmatch("%!%[(.-)%]%[(.-)%]") do
- len = len - vim.fn.strdisplaywidth("![]");
-
- final_string = final_string:gsub("%!%[" .. link .. "%]%[" .. address .. "%]", link .. "|" .. address .. "|");
- end
-
- --- Links: [link](address)
- for link, address in final_string:gmatch("%[(.-)%]%((.-)%)") do
- len = len - vim.fn.strdisplaywidth("[]()" .. address);
-
- final_string = final_string:gsub("%[" .. link .. "%]%(" .. address .. "%)", link);
- end
-
- --- Links: [link][address]
- for link, address in final_string:gmatch("%[(.-)%]%[(.-)%]") do
- len = len - vim.fn.strdisplaywidth("[][]" .. address);
-
- final_string = final_string:gsub("%[" .. link .. "%]%[" .. address .. "%]", link);
- end
-
- for pattern in final_string:gmatch("%[([^%]]+)%]") do
- len = len - 2;
- final_string = final_string:gsub( "[" .. pattern .. "]", pattern);
- end
-
- return len, final_string;
+ parser.ignore_ranges = vim.list_extend(parser.ignore_ranges, _r);
+ return _r;
end
-parser.filter_lines = function (buffer, from, to)
- local captured_lines = vim.api.nvim_buf_get_lines(buffer, from, to, false);
- local filtered_lines = {};
- local indexes = {};
- local spaces = {};
- local align_spaces = {};
- local start_pos = {};
-
- local withinCodeBlock, insideDescription = false, nil;
- local parent_marker;
-
- local tolarence = 3;
- local found = 0;
-
- local code_block_indent = 0;
- local desc_indent = 0;
- local current_fence = "";
-
- local start = 0;
-
- for l, line in ipairs(captured_lines) do
- if l == 1 then
- --- Marker list item
- if line:match(">%s-([+%-*])") then
- local sp = vim.fn.strchars(line:match(">(%s-)[+%-*]"));
- local before = sp % 2 ~= 0 and line:match("(.*>%s)") or line:match("(.*>)");
-
- start = #before;
- line = line:gsub(before, "");
- table.insert(start_pos, start);
- --- Numbered list item
- elseif line:match(">%s-(%d+)[%)%.]") then
- local sp = vim.fn.strchars(line:match(">(%s-)%d+[%)%.]"));
- local before = sp % 2 ~= 0 and line:match("(.*>%s)") or line:match("(.*>)");
-
- start = #before;
- line = line:gsub(before, "");
- table.insert(start_pos, start)
- end
- elseif l ~= 1 then
- --- Another list item found, stop calculating
- if line:match(">%s-([+%-*])") then
- break;
- elseif line:match(">%s-(%d+)[%)%.]") then
- break;
+parser.deep_extend = function (tbl_1, tbl_2)
+ for k, v in pairs(tbl_2) do
+ if tbl_1[k] then
+ if vim.islist(v) and vim.islist(tbl_1[k]) then
+ tbl_1[k] = vim.list_extend(tbl_1[k], v);
+ elseif type(v) == "table" and type(tbl_1[k]) == "table" then
+ tbl_1[k] = parser.deep_extend(tbl_1[k], v);
+ else
+ tbl_1[k] = v;
end
else
- line = line:sub(start, #line);
- table.insert(start_pos, start);
- end
-
- if l ~= 1 and withinCodeBlock == false then
- if line:match("^%s*([+%-*])") then
- break;
- elseif line:match("^%s*(%d+[%.%)])") then
- break;
- end
- end
-
- if found >= tolarence then
- break;
- end
-
- local spaces_before = vim.fn.strchars(line:match("^(%s*)"));
-
- if line:match("^%s*([+%-*])") then
- parent_marker = line:match("^%s*([+%-*])");
- elseif line:match("^%s*(%d+[%.%)])") then
- parent_marker = line:match("^%s*(%d+[%)%.])");
- end
-
- local fence = lang.get_fence(line)
- if fence and withinCodeBlock ~= true then
- withinCodeBlock = true;
- current_fence = fence;
- code_block_indent = spaces_before;
- elseif withinCodeBlock == true and line:match(current_fence) then
- withinCodeBlock = false;
- current_fence = "";
- elseif withinCodeBlock == true then
- spaces_before = code_block_indent;
- goto withinElement;
- end
-
- if withinCodeBlock ~= true and line:match("^%s*[+%-*](%s+%[.-%])") then
- insideDescription = true;
- desc_indent = vim.fn.strchars(line:match("^%s*[+%-*](%s+%[.-%])"));
- elseif withinCodeBlock ~= true and insideDescription == true and spaces_before < desc_indent then
- insideDescription = false;
- end
-
- if not line:match("^%s*([+%-*])") and
- not line:match("^%s*(%d+[%.%)])") and parent_marker
- then
- spaces_before = math.max(0, spaces_before - vim.fn.strchars((parent_marker or "") .. " "));
-
- if fence then
- code_block_indent = spaces_before;
- elseif insideDescription == true then
- align_spaces[l] = 2;
- spaces_before = math.max(-10, spaces_before - desc_indent - 2);
- end
- end
-
- ::withinElement::
-
- table.insert(filtered_lines, line);
- table.insert(indexes, l);
- table.insert(spaces, spaces_before);
-
- if line == "" then
- found = found + 1;
+ tbl_1[k] = v;
end
end
- return filtered_lines, indexes, spaces, align_spaces, start_pos;
+ return tbl_1;
end
-parser.get_list_end_range = function (buffer, from, to, marker)
- local captured_lines = vim.api.nvim_buf_get_lines(buffer, from, to, false);
-
- local width = 0;
- local height = from - 1;
-
- local tolarence = 3;
- local found = 0;
+parser.should_ignore = function (TSTree)
+ local t_start, _, t_stop, _ = TSTree:root():range();
-
- for l, line in ipairs(captured_lines) do
- if l ~= 1 and line:match(marker) then
- break;
- end
-
- if found >= tolarence then
- break;
+ for _, range in ipairs(parser.ignore_ranges) do
+ if t_start >= range[1] and t_stop <= range[2] then
+ return true;
end
-
- width = vim.fn.strchars(line);
-
- if line == "" then
- found = found + 1;
- end
-
- height = height + 1;
end
- return width, height == from - 1 and from or height;
+ return false;
end
-parser.has_parent = function (node, matches, limit)
- local iteration = 0;
-
- while node:parent() do
- if limit and iteration > limit then
- return;
- end
-
- if vim.list_contains(matches, node:type()) then
- return node:type();
- end
-
- iteration = iteration + 1;
- node = node:parent();
- end
-end
-
-parser.parsed_content = {};
-
---- Function to parse the markdown document
----
----@param buffer number
----@param TStree any
-parser.md = function (buffer, TStree, from, to)
- if not parser_installed("markdown") then
- return;
- end
-
- --- "__inside_code_block" is still experimental
- ---@diagnostic disable
- if not parser.cached_conf or
- parser.cached_conf.__inside_code_block ~= true
- then
- ---@diagnostic enable
- local root = TStree:root();
- local root_r_start, _, root_r_end, _ = root:range();
- local buf_lines = vim.api.nvim_buf_line_count(buffer);
-
- if root_r_start ~= 0 or root_r_end ~= buf_lines then
- return;
- end
- end
-
- local scanned_queries = vim.treesitter.query.parse("markdown", [[
- ((setext_heading) @setext_heading)
-
- (atx_heading [
- (atx_h1_marker)
- (atx_h2_marker)
- (atx_h3_marker)
- (atx_h4_marker)
- (atx_h5_marker)
- (atx_h6_marker)
- ] @heading)
-
- ((fenced_code_block) @code)
+parser.content = {};
+parser.sorted = {};
- ((block_quote) @block_quote)
-
- ((thematic_break) @horizontal_rule)
-
- ((pipe_table) @table)
-
- ((task_list_marker_unchecked) @checkbox_off)
- ((task_list_marker_checked) @checkbox_on)
-
- ((list_item) @list_item)
- ]]);
-
- -- The last 2 _ represent the metadata & query
- for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TStree:root(), buffer, from, to) do
- local capture_name = scanned_queries.captures[capture_id];
- local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
- local row_start, col_start, row_end, col_end = capture_node:range();
-
- if capture_name == "setext_heading" then
- local title = capture_node:named_child(0);
- local t_start, _, t_end, _ = title:range();
-
- local underline = vim.treesitter.get_node_text(capture_node:named_child(1), buffer);
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "heading_s",
-
- marker = underline,
- title = vim.api.nvim_buf_get_lines(buffer, t_start, t_end, false),
-
- level = capture_text:match("=") and 1 or 2,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name == "heading" then
- local parent = capture_node:parent();
-
- local heading_txt = capture_node:next_sibling();
- local title = heading_txt ~= nil and vim.treesitter.get_node_text(heading_txt, buffer) or nil;
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "heading",
-
- level = vim.fn.strchars(capture_text),
-
- line = vim.treesitter.get_node_text(parent, buffer),
- marker = capture_text,
- title = title,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name == "code" then
- local line_lens = {};
- local lines = {};
- local highest_len = 0;
-
- local block_start = vim.api.nvim_buf_get_lines(buffer, row_start, row_start + 1, false)[1];
-
- local _, info = lang.get_fence(block_start);
- local language_string, additional_info = lang.info(info)
-
- local code_lines = vim.api.nvim_buf_get_lines(buffer, row_start + 1, row_end - 1, false);
-
- for _, this_code in ipairs(code_lines) do
- local len = vim.fn.strdisplaywidth(this_code) or 0;
-
- if vim.list_contains(parser.cached_conf.filetypes or {}, string.lower(lang.get_name(language_string))) then
- len = parser.get_md_len(this_code)
- end
-
- if len > highest_len then
- highest_len = len;
- end
-
- table.insert(lines, this_code)
- table.insert(line_lens, len);
- end
-
- -- So that we don't accidentally parse the wrong range
- -- Note: We won't parse only the inside of the code block
- table.insert(parser.avoid_ranges, { row_start + 1, row_end - 1 });
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "code_block",
- language = language_string,
-
- info_string = vim.fn.strcharpart(block_start, col_start),
- block_info = additional_info,
-
- line_lengths = line_lens,
- largest_line = highest_len,
- lines = lines,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- })
- elseif capture_name == "block_quote" then
- local quote_markers = {};
- local quote_lines = {};
-
- local largest_len = 0;
-
- -- NOTE: row index is 0-based
- for number = 0, (row_end - row_start) - 1 do
- local txt = vim.api.nvim_buf_get_lines(buffer, row_start + number, row_start + number + 1, false)[1];
- table.insert(quote_lines, txt);
-
- if txt ~= nil then
- if vim.fn.strchars(txt) > largest_len then
- largest_len = vim.fn.strchars(txt);
- end
-
- txt = txt:match("^(>%s*)(.*)$");
- table.insert(quote_markers, txt);
- end
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "block_quote",
- markers = quote_markers,
- lines = quote_lines,
-
- row_start = row_start,
- row_end = row_end,
- -- Use hacks on renderer.lua instead
- -- The node ends on the next line after the block quote
- -- We will not count it
-
- line_width = col_start + 1,
- col_start = col_start,
- col_end = largest_len
- })
- elseif capture_name == "horizontal_rule" then
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "horizontal_rule",
- text = capture_text,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- })
- elseif capture_name == "table" then
- local rows = {};
- local table_structure = {};
- local alignments = {};
-
- local line_positions = {};
- local col_widths = {};
-
- for row in capture_node:iter_children() do
- if row:type() == "block_continuation" then
- goto ignore;
- end
-
- local tmp = {};
- local row_text = vim.treesitter.get_node_text(row, buffer)
- local r_row_start, r_col_start, r_row_end, r_col_end = row:range();
-
- local line = vim.api.nvim_buf_get_lines(buffer, r_row_start, r_row_start + 1, false)[1];
-
- --- Separator gets counted from the start of the line
- --- So, we will instead count the number of spaces at the start
- table.insert(line_positions, {
- row_start = r_row_start,
- col_start = r_col_start == 0 and vim.fn.strdisplaywidth(row_text:match("^(%s*)")) or r_col_start,
- row_end = r_row_end,
- col_end = r_col_end
- })
- if row:type() == "pipe_table_header" then
- table.insert(table_structure, "header");
- elseif row:type() == "pipe_table_delimiter_row" then
- for col in row:iter_children() do
- local txt = vim.treesitter.get_node_text(col, buffer);
-
- if txt ~= "|" then
- local char_s = txt:sub(0, 1);
- local char_e = txt:sub(#txt, -1)
-
- if txt:match(":") == nil then
- table.insert(alignments, "left");
- elseif char_s == ":" and char_e == ":" then
- table.insert(alignments, "center");
- elseif char_s == ":" then
- table.insert(alignments, "left");
- elseif char_e == ":" then
- table.insert(alignments, "right");
- end
-
- -- TODO: This needs rework
- if line:match("|([^|]+)|") then
- local col_content = line:match("|([^|]+)|");
- line = vim.fn.strcharpart(line, vim.fn.strchars("|" .. col_content));
-
- table.insert(col_widths, vim.fn.strdisplaywidth(col_content));
- elseif line:match("|([^|]+)$") then
- local col_content = line:match("|([^|]+)$");
- line = vim.fn.strcharpart(line, vim.fn.strchars("|" .. col_content));
-
- table.insert(col_widths, vim.fn.strdisplaywidth(col_content));
- end
- end
- end
-
- table.insert(table_structure, "separator");
- elseif row:type() == "pipe_table_row" then
- table.insert(table_structure, "content");
- else
- table.insert(table_structure, "unknown");
- end
-
- local t_col = nil;
-
- for col in vim.treesitter.get_node_text(row, buffer):gmatch("|([^|\n]*)") do
- if col:match("\\$") then
- t_col = col .. "|";
- elseif col ~= "" then
- table.insert(tmp, "|")
- table.insert(tmp, (t_col or "") .. col)
-
- t_col = nil;
- end
- end
-
- table.insert(tmp, "|");
- table.insert(rows, tmp);
-
- ::ignore::
- end
-
- local s_start, s_end;
-
- -- This is a workaround for hybrid-mode
- --
- -- When ,`use_virt_lines` is true the table will take the
- -- line above it and the line below it.
- --
- -- So we must adjust the ranges to match the render.
- --
- -- Don't worry, the renderer will use the __r ones in that
- -- case
- if parser.cached_conf and parser.cached_conf.tables and parser.cached_conf.tables.block_decorator ~= false and parser.cached_conf.tables.use_virt_lines == false then
- s_start = row_start;
- s_end = row_end;
-
- row_start = row_start - 1;
- row_end = row_end + 1;
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "table",
-
- row_type = table_structure;
- rows = rows,
-
- col_widths = col_widths,
- content_alignments = alignments,
- content_positions = line_positions,
-
- __r_start = s_start,
- __r_end = s_end,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end,
- })
- elseif capture_name == "list_item" then
- local is_checkbox = function (text)
- if not text then
- return false;
- elseif not parser.cached_conf or not parser.cached_conf.checkboxes or not parser.cached_conf.checkboxes.custom then
- return false;
- end
-
- text = text:gsub("[%[%]]", "");
-
- for _, state in ipairs(parser.cached_conf.checkboxes.custom) do
- ---@diagnostic disable-next-line
- if state.match == text then
- return true;
- elseif state.match_string == text then
- return true;
- end
- end
-
- if text == " " or text == "X" or text == "x" then
- return true;
- else
- return false;
- end
- end
-
- local marker = capture_node:named_child(0);
- local marker_text = vim.treesitter.get_node_text(marker, buffer);
-
- local symbol = marker_text:gsub("%s", "");
-
- -- Escape special characters
- symbol = symbol:gsub("%)", "%%)")
-
- local list_lines, lines, spaces, align_spaces, starts = parser.filter_lines(buffer, row_start, row_end);
- local spaces_before_marker = list_lines[1]:match("^(%s*)" .. symbol .. "%s*");
-
- local checkbox = list_lines[1]:match(parser.escape_string(marker_text) .. "%s*(%[.%])");
- local c_end, _ = parser.get_list_end_range(buffer, row_start, row_end, symbol)
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "list_item",
- marker_symbol = vim.treesitter.get_node_text(marker, buffer),
- is_checkbox = is_checkbox(checkbox),
-
- list_candidates = lines,
- list_lines = list_lines,
-
- starts = starts,
- spaces = spaces,
- align_spaces = align_spaces,
- conceal_spaces = vim.fn.strchars(spaces_before_marker),
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = c_end
- })
- elseif capture_name == "checkbox_off" then
- local list_item;
-
- for _, extmark in ipairs(parser.parsed_content) do
- if extmark.type == "list_item" and extmark.row_start == row_start then
- list_item = extmark;
- break;
- end
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "checkbox",
- state = "incomplete",
-
- list_item = list_item,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- })
- elseif capture_name == "checkbox_on" then
- local list_item;
-
- for _, extmark in ipairs(parser.parsed_content) do
- if extmark.type == "list_item" and extmark.row_start == row_start then
- list_item = extmark;
- break;
- end
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "checkbox",
- state = "complete",
-
- list_item = list_item,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- })
- end
- end
-end
-
---- Function to parse inline_markdown
+--- Initializes the parsers on the specified buffer
+--- Parsed data is stored as a "view" in renderer.lua
---
---@param buffer number
----@param TStree any
-parser.md_inline = function (buffer, TStree, from, to)
- if not parser_installed("markdown_inline") then
- return;
- end
-
- --- "__inside_code_block" is still experimental
- ---@diagnostic disable
- if not parser.cached_conf or
- parser.cached_conf.__inside_code_block ~= true
- then
- ---@diagnostic enable
- local root = TStree:root();
- local root_r_start, _, root_r_end, _ = root:range();
-
- for _, range in ipairs(parser.avoid_ranges) do
- if root_r_start >= range[1] and root_r_end <= range[2] then
- return;
- end
- end
- end
-
- local scanned_queries = vim.treesitter.query.parse("markdown_inline", [[
- ((shortcut_link) @callout)
-
- ([
- (inline_link)
- (full_reference_link)
- ] @hyperlink)
-
- ((email_autolink) @email)
- ((image) @image)
-
- ((code_span) @code)
-
- ((entity_reference) @entity)
-
- ((backslash_escape) @escaped)
- ]]);
-
- -- The last 2 _ represent the metadata & query
- for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TStree:root(), buffer, from, to) do
- local capture_name = scanned_queries.captures[capture_id];
- local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
- local row_start, col_start, row_end, col_end = capture_node:range();
-
- if capture_name == "callout" then
- local line = vim.api.nvim_buf_get_lines(buffer, row_start, row_start + 1, false)[1];
- local before, after = line:sub(1, col_start), line:sub(col_end + 1);
-
- if capture_text:match("%[(.)%]") then
- for _, extmark in ipairs(parser.parsed_content) do
- if extmark.type == "list_item" and extmark.row_start == row_start then
- local marker = capture_text:match("%[(.)%]");
- marker = parser.escape_string(marker)
-
- local start_line = extmark.list_lines[1] or "";
- local list_start = extmark.starts[1] or 0;
- local atStart = start_line:match("[+%-*]%s+%[(" .. marker .. ")%]%s+");
-
- local chk_start, _ = start_line:find("%[(" .. marker .. ")%]");
-
- if not atStart or not chk_start or (list_start + chk_start) - 1 ~= col_start then
- goto invalid;
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "checkbox",
- state = capture_text:match("%[(.)%]"),
-
- list_item = extmark,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
-
- break;
- end
-
- ::invalid::
- end
- elseif capture_text:match("%[%^(.+)%]") then
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "link_footnote",
- text = capture_text:match("%[(.+)%]"),
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif before:match("%[$") and after:match("^%]") then
- capture_text = capture_text:gsub("^%[", ""):gsub("%]$", "")
- local alias;
-
- if capture_text:match("^.-|(.+)$") then
- alias = capture_text:match("^.-|(.+)$");
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "link_internal",
-
- text = capture_text,
- alias = alias,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end,
- });
- elseif before:match("%> ?$") then
- local title = string.match(line or "", "%](.*)$")
-
- for _, extmark in ipairs(parser.parsed_content) do
- if extmark.type == "block_quote"
- and extmark.row_start == row_start
- and extmark.col_start == col_start - before:match("(%> ?)$"):len()
- then
- extmark.callout = string.match(capture_text, "%[!(.-)%]");
- extmark.title = title;
-
- extmark.line_width = vim.fn.strchars(line);
-
- break;
- end
- end
- end
- elseif capture_name == "hyperlink" then
- local link_text = "";
- local link_address;
-
- if capture_node:named_child(0) and capture_node:named_child(0):type() == "link_text" then
- link_text = vim.treesitter.get_node_text(capture_node:named_child(0), buffer);
- end
-
- if capture_node:named_child(1) and (capture_node:named_child(1):type() == "link_destination" or capture_node:named_child(1):type() == "link_label") then
- link_address = vim.treesitter.get_node_text(capture_node:named_child(1), buffer);
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "link_hyperlink",
-
- text = link_text,
- address = link_address,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end,
- })
- elseif capture_name == "email" then
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "link_email",
-
- text = capture_text:gsub("^([<])", ""):gsub("([>])$", ""),
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end,
- })
- elseif capture_name == "image" then
- local desc = capture_node:named_child(0);
- local sibl = capture_node:named_child(1);
-
- local link_text = vim.treesitter.get_node_text(desc, buffer);
- local link_address = ""
-
- if sibl then
- link_address = vim.treesitter.get_node_text(sibl, buffer);
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "link_image",
-
- text = link_text,
- address = link_address,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- })
- elseif capture_name == "code" then
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "inline_code",
-
- text = string.gsub(capture_text, "`", ""),
-
- 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
- })
- elseif capture_name == "escaped" then
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "escaped",
-
- text = capture_text,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- })
- end
- end
-end
-
-parser.html = function (buffer, TStree, from, to)
- if not parser_installed("html") then
- return;
- end
+---@param from integer?
+---@param to integer?
+---@param cache boolean?
+parser.init = function (buffer, from, to, cache)
+ -- Clear the previous contents
+ parser.content = {};
+ parser.sorted = {};
+ parser.ignore_ranges = {};
- --- "__inside_code_block" is still experimental
- ---@diagnostic disable
- if not parser.cached_conf or
- parser.cached_conf.__inside_code_block ~= true
+ if
+ not pcall(vim.treesitter.get_parser, buffer) or
+ not vim.treesitter.get_parser(buffer)
then
- ---@diagnostic enable
- for _, tbl in ipairs(parser.parsed_content) do
- if not tbl.type == "code_block" then
- goto skip;
- end
-
- local root = TStree:root();
- local root_r_start, _, _, _ = root:range();
-
- if root_r_start >= tbl.row_start and root_r_start <= tbl.row_end then
- return;
- end
-
- ::skip::
- end
+ return parser.content, parser.sorted;
end
- local scanned_queries = vim.treesitter.query.parse("html", [[
- ((element) @elem)
- ]]);
-
- for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TStree:root(), buffer, from, to) do
- local capture_name = scanned_queries.captures[capture_id];
- local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
- local row_start, col_start, row_end, col_end = capture_node:range();
-
- if capture_name == "elem" then
- local node_childs = capture_node:named_child_count();
-
- local start_tag = capture_node:named_child(0);
- local end_tag = capture_node:named_child(node_childs - 1);
-
- if start_tag:type() == "start_tag" and end_tag:type() == "end_tag" and row_start == row_end then
- local _, ts_col_start, _, ts_col_end = start_tag:range();
- local _, te_col_start, _, te_col_end = end_tag:range();
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "html_inline",
+ ---+${lua, Announce start of parsing}
+ ---@type integer Start time
+ local start = vim.uv.hrtime();
- tag = vim.treesitter.get_node_text(start_tag, buffer):gsub("[>]", ""),
- text = capture_text,
+ health.notify("trace", {
+ level = 1,
+ message = string.format("Parsing(start): %d", buffer)
+ });
+ health.__child_indent_in();
+ ---_
- start_tag_col_start = ts_col_start,
- start_tag_col_end = ts_col_end,
+ vim.treesitter.get_parser(buffer):parse(true);
+ local root_parser = vim.treesitter.get_parser(buffer);
- end_tag_col_start = te_col_start,
- end_tag_col_end = te_col_end,
+ root_parser:for_each_tree(function (TSTree, language_tree)
+ language_tree:parse(true);
- row_start = row_start,
- row_end = row_end,
+ local language = language_tree:lang();
+ local content, sorted = {}, {};
- col_start = col_start,
- col_end = col_end
- })
- end
+ if parser[language] and not parser.should_ignore(TSTree) then
+ content, sorted = parser[language].parse(buffer, TSTree, from, to);
+ parser.create_ignore_range(language, sorted)
end
- end
-end
-
-parser.latex = function (buffer, TStree, from, to)
- if not parser_installed("latex") then
- return;
- end
- --- "__inside_code_block" is still experimental
- ---@diagnostic disable
- if not parser.cached_conf or
- parser.cached_conf.__inside_code_block ~= true
- then
- ---@diagnostic enable
- for _, tbl in ipairs(parser.parsed_content) do
- if not tbl.type == "code_block" then
- goto skip;
- end
-
- local root = TStree:root();
- local root_r_start, _, _, _ = root:range();
-
- if root_r_start >= tbl.row_start and root_r_start <= tbl.row_end then
- return;
- end
+ parser.content[language] = vim.list_extend(parser.content[language] or {}, content);
+ parser.sorted[language] = parser.deep_extend(parser.sorted[language] or {}, sorted);
+ end)
- ::skip::
- end
+ if cache ~= false then
+ parser.cached[buffer] = parser.sorted;
end
- local scanned_queries = vim.treesitter.query.parse("latex", [[
- ((curly_group) @bracket)
-
- ;; Various fonts
- ((generic_command
- .
- command: ((command_name) @c (#eq? @c "\\mathbf"))
- arg: (curly_group)
- .
- ) @font_mathbf)
-
- ((generic_command . command: ((command_name) @c (#eq? @c "\\mathbfit")) arg: (curly_group) .) @font_mathbfit)
- ((generic_command . command: ((command_name) @c (#eq? @c "\\mathcal")) arg: (curly_group) .) @font_mathcal)
- ((generic_command . command: ((command_name) @c (#eq? @c "\\mathfrak")) arg: (curly_group) .) @font_mathfrak)
- ((generic_command . command: ((command_name) @c (#eq? @c "\\mathbb")) arg: (curly_group) .) @font_mathbb)
- ((generic_command . command: ((command_name) @c (#eq? @c "\\mathsfbf")) arg: (curly_group) .) @font_mathsfbf)
- ((generic_command . command: ((command_name) @c (#eq? @c "\\mathsfit")) arg: (curly_group) .) @font_mathsfit)
- ((generic_command . command: ((command_name) @c (#eq? @c "\\mathsfbfit")) arg: (curly_group) .) @font_mathsfbfit)
- ((generic_command . command: ((command_name) @c (#eq? @c "\\mathtt")) arg: (curly_group) .) @font_mathtt)
-
-
- ((generic_command
- .
- command: (command_name)
- .
- ) @symbol)
-
- ((generic_command
- .
- command: (command_name)
- (curly_group)+
- ) @operator_block)
-
- ((text_mode) @special_text)
-
- ((superscript) @superscript)
- ((subscript) @subscript)
-
- ((inline_formula) @inline)
- ((displayed_equation) @block)
- ]]);
-
- for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TStree:root(), buffer, from, to) do
- local capture_name = scanned_queries.captures[capture_id];
- local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
- local row_start, col_start, row_end, col_end = capture_node:range();
-
- if capture_name == "inline" then
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_inline",
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name == "block" then
- --- row_end is increased by 1 so that this works similar to
- --- "fenced_code_block"
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_block",
-
- row_start = row_start,
- row_end = row_end + 1,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name == "bracket" then
- local text = vim.api.nvim_buf_get_lines(buffer, row_start, row_start + 1, false)[1];
- text = string.sub(text, 1, col_start);
-
- local has_operator = false;
-
- if text:match("%^$") and capture_text:match("^%{(.+)%}$") then
- -- Superscript
- goto invalidBracket;
- elseif text:match("%_$") and capture_text:match("^%{(.+)%}$") then
- -- Subscript
- goto invalidBracket;
- elseif text:match("\\(%a-)$") and vim.fn.strchars(capture_text) > 3 then
- local name = text:match("\\(%a-)$");
-
- --- Special operators
- if vim.list_contains({ "set" }, name) then
- goto invalidBracket;
- end
-
- has_operator = true;
- elseif text:match("%}$") and vim.fn.strchars(capture_text) > 3 then
- has_operator = true;
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_bracket",
-
- inside = parser.has_parent(capture_node, { "subscript", "superscript" }),
- has_operator = has_operator,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
-
- ::invalidBracket::
- elseif capture_name:match("^font%_(.-)") then
- capture_name = capture_name:gsub("^font%_", "");
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_font",
- font = capture_name,
-
- text = capture_text:match("%\\" .. capture_name .. "%{(.+)%}$"),
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name:match("^special%_(.-)") then
- capture_name = capture_name:gsub("^special%_", "");
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_special_syntax",
- name = capture_name,
-
- text = capture_text:match("%\\" .. capture_name .. "%{(.+)%}$"),
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name == "operator_block" then
- local operator = capture_node:named_child(0);
- local operator_name = vim.treesitter.get_node_text(operator, buffer):gsub("^\\", "");
+ ---+${lua, Announce end of parsing}
+ ---@type integer End time
+ local now = vim.uv.hrtime();
- local args = {};
-
- for n = 1, capture_node:named_child_count() - 1, 1 do
- local arg = capture_node:named_child(n);
- local r_start, c_start, r_end, c_end = arg:range();
-
- table.insert(args, {
- node = arg,
- text = vim.treesitter.get_node_text(arg, buffer),
-
- inside = parser.has_parent(capture_node, { "subscript", "superscript" }),
- row_start = r_start,
- row_end = r_end,
-
- col_start = c_start,
- col_end = c_end
- })
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_operator",
-
- name = operator_name,
- text = capture_text,
- args = args,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name == "symbol" then
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_symbol",
-
- inside = parser.has_parent(capture_node, { "subscript", "superscript" }),
- text = capture_text:match("%\\(.-)%{?$"),
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name == "superscript" then
- local text = vim.api.nvim_buf_get_lines(buffer, row_start, row_start + 1, false)[1];
- text = string.sub(text, 1, col_start);
-
- local special_syntax = false;
-
- if text:match("\\sum%_%{(.-)%}$") then
- special_syntax = true;
- elseif text:match("\\prod%_%{(.-)%}$") then
- special_syntax = true;
- elseif text:match("\\int%_%{(.-)%}$") then
- special_syntax = true;
- elseif text:match("\\oint%_%{(.-)%}$") then
- special_syntax = true;
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_superscript",
-
- special_syntax = special_syntax,
- text = capture_text,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- elseif capture_name == "subscript" then
- local text = vim.api.nvim_buf_get_lines(buffer, row_start, row_start + 1, false)[1];
- text = string.sub(text, 1, col_start);
-
- local special_syntax = false;
-
- if text:match("\\lim$") then
- special_syntax = true;
- elseif text:match("\\sum$") then
- special_syntax = true;
- elseif text:match("\\prod$") then
- special_syntax = true;
- elseif text:match("\\int$") then
- special_syntax = true;
- elseif text:match("\\oint$") then
- special_syntax = true;
- end
-
- table.insert(parser.parsed_content, {
- node = capture_node,
- type = "latex_subscript",
-
- special_syntax = special_syntax,
- text = capture_text,
-
- row_start = row_start,
- row_end = row_end,
-
- col_start = col_start,
- col_end = col_end
- });
- end
- end
+ health.__child_indent_de();
+ health.notify("trace", {
+ level = 3,
+ message = string.format("Parsing(end, %dms): %d", (now - start) / 1e6, buffer)
+ });
+ ---_
+ return parser.content, parser.sorted;
end
---- Initializes the parsers on the specified buffer
---- Parsed data is stored as a "view" in renderer.lua
----
----@param buffer number
----@param config_table markview.configuration
----@param from integer?
----@param to integer?
-parser.init = function (buffer, config_table, from, to)
- local root_parser = vim.treesitter.get_parser(buffer);
- root_parser:parse(true);
-
- if config_table then
- parser.cached_conf = config_table;
- end
-
- -- Clear the previous contents
- parser.parsed_content = {};
-
- root_parser:for_each_tree(function (TStree, language_tree)
- local tree_language = language_tree:lang();
-
- if tree_language == "markdown" then
- parser.md(buffer, TStree, from, to)
- elseif tree_language == "markdown_inline" then
- parser.md_inline(buffer, TStree, from, to);
- elseif tree_language == "html" then
- parser.html(buffer, TStree, from, to);
- elseif tree_language == "latex" then
- parser.latex(buffer, TStree, from, to);
- end
- end)
-
- return parser.parsed_content;
-end
+parser.parse = parser.init;
return parser;
diff --git a/lua/markview/parsers/html.lua b/lua/markview/parsers/html.lua
new file mode 100644
index 0000000..5103122
--- /dev/null
+++ b/lua/markview/parsers/html.lua
@@ -0,0 +1,208 @@
+--- HTML parser for `markview.nvim`.
+local html = {};
+
+--- Queried contents
+---@type table[]
+html.content = {};
+
+--- Queried contents, but sorted
+---@type { [string]: table }
+html.sorted = {}
+
+--- Wrapper for `table.insert()`.
+---@param data table
+html.insert = function (data)
+ ---+${func}
+ table.insert(html.content, data);
+
+ if not html.sorted[data.class] then
+ html.sorted[data.class] = {};
+ end
+
+ table.insert(html.sorted[data.class], data);
+ ---_
+end
+
+--- Heading element parser
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+html.heading = function (buffer, TSNode, text, range)
+ ---+${func}
+
+ ---@type table The opening tag.
+ local tag = vim.treesitter.get_node_text(TSNode:named_child(0):named_child(0), buffer);
+
+ ---@type __html.headings
+ html.insert({
+ class = "html_heading",
+ level = tonumber(tag:match("^h(%d)$")),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Container element parser
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+html.element = function (buffer, TSNode, text, range)
+ ---+${func}
+ local opening_tag, closing_tag;
+
+ for child in TSNode:iter_children() do
+ if child:type() == "start_tag" then
+ if
+ vim.treesitter.get_node_text(child, buffer):match("^%$")
+ then
+ return;
+ end
+
+ opening_tag = child;
+ elseif child:type() == "end_tag" then
+ closing_tag = child;
+ end
+ end
+
+ if not opening_tag then
+ --- Broken elements should be skipped.
+ return;
+ end
+
+ ---@type __html.container_elements
+ html.insert({
+ class = "html_container_element",
+ name = string.lower(vim.treesitter.get_node_text(opening_tag:child(1), buffer) or ""),
+
+ opening_tag = {
+ text = vim.treesitter.get_node_text(opening_tag, buffer),
+ range = { opening_tag:range() }
+ },
+ closing_tag = closing_tag and {
+ text = vim.treesitter.get_node_text(closing_tag, buffer),
+ range = { closing_tag:range() }
+ } or nil,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Void element parser
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+html.element_void = function (buffer, TSNode, text, range)
+ ---+${func}
+ local tag = TSNode:child(0);
+
+ ---@type __html.void_elements
+ html.insert({
+ class = "html_void_element",
+ name = string.lower(vim.treesitter.get_node_text(tag:child(1), buffer) or ""),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- HTML parser
+---@param buffer integer
+---@param TSTree table
+---@param from integer?
+---@param to integer?
+---@return table[]
+---@return table
+html.parse = function (buffer, TSTree, from, to)
+ ---+${func}
+ -- Clear the previous contents
+ html.sorted = {};
+ html.content = {};
+
+ local scanned_queries = vim.treesitter.query.parse("html", [[
+ (((element
+ (start_tag
+ (
+ ((tag_name) @heading.name)
+ (#match? @heading.name "^[hH][0-6]$")
+ ) @heading.start)
+ (end_tag
+ (
+ (tag_name) @heading.end
+ )))
+ ) @html.heading)
+
+ ((element
+ .
+ (start_tag)
+ .) @html.element_void)
+
+ (((element
+ (start_tag ((tag_name) @element.start))
+ (end_tag ((tag_name) @element.end)))
+ ) @html.element)
+ ]]);
+
+ for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TSTree:root(), buffer, from, to) do
+ local capture_name = scanned_queries.captures[capture_id];
+
+ if not capture_name:match("^html%.") then
+ goto continue;
+ end
+
+ ---@type string?
+ local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
+ local r_start, c_start, r_end, c_end = capture_node:range();
+
+ if capture_text == nil then
+ goto continue;
+ end
+
+ if not capture_text:match("\n$") then
+ capture_text = capture_text .. "\n";
+ end
+
+ local lines = {};
+
+ for line in capture_text:gmatch("(.-)\n") do
+ table.insert(lines, line);
+ end
+
+ ---@type boolean, string
+ local success, error = pcall(
+ html[capture_name:gsub("^html%.", "")],
+
+ buffer,
+ capture_node,
+ lines,
+ {
+ row_start = r_start,
+ col_start = c_start,
+
+ row_end = r_end,
+ col_end = c_end
+ }
+ );
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = error
+ });
+ end
+
+ ::continue::
+ end
+
+ return html.content, html.sorted;
+ ---_
+end
+
+return html;
diff --git a/lua/markview/parsers/latex.lua b/lua/markview/parsers/latex.lua
new file mode 100644
index 0000000..c022b78
--- /dev/null
+++ b/lua/markview/parsers/latex.lua
@@ -0,0 +1,615 @@
+--- HTML parser for `markview.nvim`
+local latex = {};
+local utils = require("markview.utils")
+
+--- `string.gsub()` with support for multiple patterns.
+---@param text string
+---@param gsubs string[]
+---@return string
+local function bulk_gsub (text, gsubs)
+ local _o = text or "";
+
+ for _, g in ipairs(gsubs) do
+ g = utils.escape_string(g);
+ _o = _o:gsub(g, "");
+ end
+
+ return _o;
+end
+
+--- Checks if the given node is inside of `\text{}`.
+---@param TSNode table
+---@return boolean
+local function within_text_mode(TSNode)
+ while TSNode do
+ if TSNode:type() == "text_mode" then
+ return true;
+ end
+
+ TSNode = TSNode:parent();
+ end
+
+ return false;
+end
+
+--- Queried content.
+---@type table[]
+latex.content = {};
+
+--- Sorted queried content.
+---@type { [string]: table[] }
+latex.sorted = {};
+
+--- Custom `table.insert()` function.
+---@param data any
+latex.insert = function (data)
+ table.insert(latex.content, data);
+
+ if not latex.sorted[data.class] then
+ latex.sorted[data.class] = {};
+ end
+
+ table.insert(latex.sorted[data.class], data);
+end
+
+--- LaTeX block parser.
+---@param buffer integer
+---@param text string[]
+---@param range node.range
+latex.block = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local parent = TSNode:parent();
+
+ while parent do
+ if vim.list_contains({ "displayed_equation", "inline_formula" }, parent:type()) then
+ break;
+ end
+
+ parent = parent:parent();
+ end
+
+ local from = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_start + 1, false)[1]:sub(0, range.col_start);
+ local to = vim.api.nvim_buf_get_lines(buffer, range.row_end, range.row_end + 1, true)[1]:sub(range.col_end + 1);
+ local inline = false;
+
+ if text[1]:match("^%\\%[") then
+ if from:len() > 1 and from:match("[^%s]") then
+ -- Non-whitespace character before \[.
+ inline = true;
+ elseif text[1]:match("^%\\%[.+") then
+ -- Text after \[.
+ inline = true;
+ elseif to:len() > 1 and to:match("[^%s]") then
+ -- Non-whitespace character after \].
+ inline = true;
+ elseif text[#text]:match("[^%s]+%\\%]$") then
+ -- Text before \].
+ inline = true;
+ end
+ elseif text[1]:match("%$%$") then
+ if from:len() > 1 and from:match("[^%s]") then
+ -- Non-whitespace before $$.
+ inline = true;
+ elseif text[1]:match("^%$%$.+") then
+ -- Text after starting $$.
+ inline = true;
+ elseif to:len() > 1 and to:match("[^%s]") then
+ -- Non-whitespace character after closing $$.
+ inline = true;
+ elseif text[#text]:match("[^%s]+%$%$$") then
+ -- Text before closing $$.
+ inline = true;
+ end
+ else
+ return;
+ end
+
+ if parent and inline then
+ return;
+ end
+
+ ---@class __latex.blocks
+ latex.insert({
+ class = inline == true and "latex_inline" or "latex_block",
+ marker = "$$",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- LaTeX command parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+latex.command = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local args = {};
+ local nodes = TSNode:field("arg");
+
+ local command_node = TSNode:field("command")[1];
+ local command_name = vim.treesitter.get_node_text(command_node, buffer);
+
+ if within_text_mode(TSNode) then
+ return;
+ elseif
+ command_name:len() == 2 or
+ command_name:match("^\\math")
+ then
+ return;
+ end
+
+ for _, arg in ipairs(nodes) do
+ table.insert(args, {
+ text = vim.treesitter.get_node_text(arg, buffer),
+ range = { arg:range() }
+ });
+ end
+
+ ---@type __latex.commands
+ latex.insert({
+ class = "latex_command",
+
+ command = {
+ name = (command_name or ""):sub(2),
+ range = command_node and { command_node:range() }
+ },
+ args = args,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- LaTeX escaped character parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+latex.escaped = function (_, TSNode, text, range)
+ ---+${lua}
+ if within_text_mode(TSNode) then
+ return;
+ end
+
+ ---@type __latex.escapes
+ latex.insert({
+ class = "latex_escaped",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- LaTeX font parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+latex.font = function (buffer, TSNode, text, range)
+ ---+${lua}
+ if within_text_mode(TSNode) then
+ return;
+ end
+
+ local cmd = TSNode:field("command")[1];
+
+ if cmd == nil then
+ return;
+ end
+
+ range.font = { cmd:range() };
+
+ ---@class __latex.fonts
+ latex.insert({
+ class = "latex_font",
+ name = vim.treesitter.get_node_text(cmd, buffer):gsub("\\", ""),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Inline LaTeX parser.
+---@param text string[]
+---@param range node.range
+latex.inline = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local parent = TSNode:parent();
+
+ while parent do
+ if vim.list_contains({ "displayed_equation", "inline_formula" }, parent:type()) then
+ break;
+ end
+
+ parent = parent:parent();
+ end
+
+ local from = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_start + 1, false)[1]:sub(0, range.col_start);
+ local to = vim.api.nvim_buf_get_lines(buffer, range.row_end, range.row_end + 1, true)[1]:sub(range.col_end + 1);
+ local inline = false;
+
+ local marker;
+
+ if text[1]:match("^%\\%(") then
+ marker = "\\(";
+
+ if from:len() > 1 and from:match("[^%s]") then
+ -- Non-whitespace character before \(.
+ inline = true;
+ elseif text[1]:match("^%\\%(.+") then
+ -- Text after \(.
+ inline = true;
+ elseif to:len() > 1 and to:match("[^%s]") then
+ -- Non-whitespace character after \).
+ inline = true;
+ elseif text[#text]:match("[^%s]+%\\%)$") then
+ -- Text before \).
+ inline = true;
+ end
+ elseif text[1]:match("^%$") then
+ marker = "$";
+
+ if from:len() > 1 and from:match("[^%s]") then
+ -- Non-whitespace before $$.
+ inline = true;
+ elseif text[1]:match("^%$.+") then
+ -- Text after starting $$.
+ inline = true;
+ elseif to:len() > 1 and to:match("[^%s]") then
+ -- Non-whitespace character after closing $$.
+ inline = true;
+ elseif text[#text]:match("[^%s]+%$$") then
+ -- Text before closing $$.
+ inline = true;
+ end
+ else
+ return;
+ end
+
+ if parent and inline then
+ return;
+ end
+
+ ---@type __latex.inlines
+ latex.insert({
+ class = inline == true and "latex_inline" or "latex_block",
+ marker = marker,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- {} parser.
+---@param buffer integer
+---@param text string[]
+---@param range node.range
+latex.parenthesis = function (buffer, TSNode, text, range)
+ ---+${lua}
+ if within_text_mode(TSNode) then
+ return;
+ end
+
+ local line = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_start + 1, false)[1];
+ local before = line:sub(0, range.col_start);
+
+ if before:match("%^$") or before:match("%_$") then
+ return;
+ elseif before:match("%\\(%a+)$") or before:match("%}%s*$") then
+ return;
+ end
+
+ ---@type __latex.parenthesis
+ latex.insert({
+ class = "latex_parenthesis",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Subscript parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+latex.subscript = function (_, TSNode, text, range)
+ ---+${lua}
+
+ local node = TSNode;
+ local level, preview = 0, true;
+
+ local supported_symbols = {
+ "\\beta",
+ "\\gamma",
+ "\\rho",
+ "\\epsilon",
+ "\\chi"
+ }
+
+ for _, line in ipairs(text) do
+ if bulk_gsub(line, supported_symbols):match("%\\") then
+ preview = false;
+ break;
+ end
+ end
+
+ while node do
+ if node:type() == "text_mode" then
+ return;
+ elseif node:type() == "subscript" then
+ level = level + 1;
+ end
+
+ node = node:parent();
+ end
+
+ latex.insert({
+ class = "latex_subscript",
+ parenthesis = text[1]:match("^%_%{") ~= nil,
+
+ preview = preview,
+ level = level,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Superscript parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+latex.superscript = function (_, TSNode, text, range)
+ ---+${lua}
+
+ local node = TSNode;
+ local level, preview = 0, true;
+
+ local supported_symbols = {
+ "\\alpha",
+ "\\beta",
+ "\\gamma",
+ "\\delta",
+ "\\epsilon",
+ "\\theta",
+ "\\iota",
+ "\\Phi",
+ "\\varphi",
+ "\\chi"
+ }
+
+ for _, line in ipairs(text) do
+ if bulk_gsub(line, supported_symbols):match("%\\") then
+ preview = false;
+ break;
+ end
+ end
+
+ while node do
+ if node:type() == "text_mode" then
+ return;
+ elseif node:type() == "superscript" then
+ level = level + 1;
+ end
+
+ node = node:parent();
+ end
+
+ latex.insert({
+ class = "latex_superscript",
+ parenthesis = text[1]:match("^%^%{") ~= nil,
+
+ preview = preview,
+ level = level,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Symbol parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+latex.symbol = function (_, TSNode, text, range)
+ ---+${lua}
+
+ local node = TSNode;
+ local style;
+
+ while node do
+ if node:type() == "text_mode" then
+ return;
+ elseif vim.list_contains({ "subscript", "superscript" }, node:type()) then
+ style = node:type() .. "s";
+ break;
+ end
+
+ node = node:parent();
+ end
+
+ ---@type __latex.symbols
+ latex.insert({
+ class = "latex_symbol",
+ name = text[1]:sub(2),
+ style = style,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Text mode parser.
+---@param text string[]
+---@param range node.range
+latex.text = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __latex.text
+ latex.insert({
+ class = "latex_text",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Word parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+latex.word = function (_, TSNode, text, range)
+ ---+${lua}
+ if within_text_mode(TSNode) then
+ return;
+ end
+
+ ---@type __latex.word
+ latex.insert({
+ class = "latex_word",
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- LaTeX parser function.
+---@param buffer integer
+---@param TSTree table
+---@param from integer?
+---@param to integer?
+---@return table[]
+---@return table
+latex.parse = function (buffer, TSTree, from, to)
+ ---+${lua}
+
+ --- Clear the previous contents
+ latex.sorted = {};
+ latex.content = {};
+
+ local scanned_queries = vim.treesitter.query.parse("latex", [[
+ ((curly_group) @latex.parenthesis)
+
+ ([(operator) (word)] @latex.word
+ (#match? @latex.word "^[^\\\\]+$"))
+
+ ((generic_command
+ .
+ command: (
+ ((command_name) @escaped.name)
+ (#match? @escaped.name "^\\\\.$")
+ )
+ .
+ ) @latex.escaped)
+
+ ((generic_command
+ .
+ command: (
+ ((command_name) @symbol.name)
+ (#match? @symbol.name "^\\\\[a-zA-Z]+$")
+ )
+ .
+ ) @latex.symbol)
+
+ ((generic_command
+ .
+ command: (command_name)
+ (curly_group)+
+ ) @latex.command)
+
+ ((generic_command
+ .
+ command: (
+ (command_name) @font.cmd
+ (#match? @font.cmd "^\\\\math")
+ )
+ arg: (curly_group)
+ .
+ ) @latex.font)
+
+ ((displayed_equation) @latex.block)
+
+ ((inline_formula) @latex.inline)
+
+ ((text_mode) @latex.text)
+
+ ((superscript) @latex.superscript)
+
+ ((subscript) @latex.subscript)
+ ]]);
+
+ for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TSTree:root(), buffer, from, to) do
+ ---@type string
+ local capture_name = scanned_queries.captures[capture_id];
+
+ --- Capture groups used internally.
+ --- Do not parse them.
+ if not capture_name:match("^latex%.") then
+ goto continue
+ end
+
+ ---@type string?
+ local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
+ local r_start, c_start, r_end, c_end = capture_node:range();
+
+ if capture_text == nil then
+ goto continue;
+ end
+
+ --- If a node doesn't end with \n, Add it.
+ if not capture_text:match("\n$") then
+ capture_text = capture_text .. "\n";
+ end
+
+ --- Turn the texts into list of lines.
+ ---@type string[]
+ local lines = {};
+
+ for line in capture_text:gmatch("(.-)\n") do
+ table.insert(lines, line);
+ end
+
+ ---@type boolean, string
+ local success, error = pcall(
+ latex[capture_name:gsub("^latex%.", "")],
+
+ buffer,
+ capture_node,
+ lines,
+ {
+ row_start = r_start,
+ col_start = c_start,
+
+ row_end = r_end,
+ col_end = c_end
+ }
+ );
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = error
+ });
+ end
+
+ ::continue::
+ end
+
+ return latex.content, latex.sorted;
+ ---_
+end
+
+return latex;
diff --git a/lua/markview/parsers/markdown.lua b/lua/markview/parsers/markdown.lua
new file mode 100644
index 0000000..5658335
--- /dev/null
+++ b/lua/markview/parsers/markdown.lua
@@ -0,0 +1,696 @@
+--- Markdown parser for `markview.nvim`
+local markdown = {};
+
+local spec = require("markview.spec");
+local utils = require("markview.utils");
+
+local inline = require("markview.parsers.markdown_inline");
+
+--- Queried contents
+---@type table[]
+markdown.content = {};
+
+--- Queried contents, but sorted
+markdown.sorted = {}
+
+--- Cached values.
+markdown.cache = {
+ table_ends = {}
+}
+
+--- `table.insert()` with extra steps.
+---@param data any
+markdown.insert = function (data)
+ table.insert(markdown.content, data);
+
+ if not markdown.sorted[data.class] then
+ markdown.sorted[data.class] = {};
+ end
+
+ table.insert(markdown.sorted[data.class], vim.tbl_extend("force", data, {
+ id = #markdown.content
+ }));
+end
+
+
+--- ATX heading parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+markdown.atx_heading = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local marker = TSNode:named_child(0);
+
+ if text[1]:match("^%s+") then
+ --- BUG, `markdown` parser includes spaces before #.
+ --- So we should modify the range do that it starts at #.
+ range.col_start = range.col_start + text[1]:match("^%s+"):len();
+ end
+
+ ---@type __markdown.atx
+ markdown.insert({
+ class = "markdown_atx_heading",
+
+ marker = vim.treesitter.get_node_text(marker, buffer):gsub("%s", ""),
+ text = text,
+
+ range = range
+ });
+ ---_
+end
+
+--- Setext heading parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+markdown.setext_heading = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local marker = TSNode:named_child(1);
+
+ markdown.insert({
+ class = "markdown_setext_heading",
+
+ marker = vim.treesitter.get_node_text(marker, buffer),
+ text = text,
+
+ range = range
+ });
+ ---_
+end
+
+--- Block quote parser
+---@param buffer integer
+---@param TSNode table
+---@param lines string[]
+---@param range __block_quotes.range
+markdown.block_quote = function (buffer, TSNode, lines, range)
+ ---+${lua}
+
+ local text = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_end, false);
+
+ if lines[1]:match("^[^%>]+") then
+ range.col_start = range.col_start + lines[1]:match("^[^%>]+"):len();
+ end
+
+ for l, line in ipairs(text) do
+ --- We want to get text after the start column.
+ text[l] = line:sub(range.col_start + 1);
+ end
+
+ local call_start, call_end, callout = text[1]:find("^%>%s?%[%!(.-)%]");
+ local title_start, title_end, title = text[1]:find("^%>%s?%[%!.-%]%s(.+)$");
+
+ if callout then
+ range.callout_start = range.col_start + call_start;
+ range.callout_end = range.col_start + call_end;
+ end
+
+ if title then
+ range.title_start = range.col_start + title_start;
+ range.title_end = range.col_start + title_end;
+ end
+
+ ---@type __markdown.block_quotes
+ markdown.insert({
+ class = "markdown_block_quote",
+ __nested = TSNode:parent() ~= nil,
+
+ callout = callout,
+ title = title,
+ text = text,
+
+ range = range
+ });
+ ---_
+end
+
+markdown.checkbox = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __markdown.checkboxes
+ markdown.insert({
+ class = "markdown_checkbox",
+ state = text[1]:match("^%[(.)%]"),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Code block parser
+---@param range __code_blocks.range
+markdown.code_block = function (buffer, TSNode, _, range)
+ ---+${lua}
+
+ --- Parser is unreliable.
+ --- Use buffer lines.
+ ---@type string[]
+ local text = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_end, false);
+
+ --- Modify the text so that only the text
+ --- inside the node's range is visible.
+ for l, line in ipairs(text) do
+ text[l] = line:sub(range.col_start + 1);
+ end
+
+ local language, info_string;
+ local info_node = TSNode:named_child(1);
+
+ if info_node and info_node:type() == "info_string" then
+ --- Info string found
+ local lang_node = info_node:named_child(0);
+
+ if lang_node then
+ language = vim.treesitter.get_node_text(lang_node, buffer);
+ range.language = { lang_node:range() };
+ end
+
+ info_string = vim.treesitter.get_node_text(info_node, buffer);
+ range.info_string = { info_node:range() };
+ end
+
+ local start_delim = TSNode:child(0);
+ local end_delim = TSNode:child(TSNode:child_count() - 1);
+
+ ---@type __markdown.code_blocks
+ markdown.insert({
+ class = "markdown_code_block",
+
+ language = language,
+ info_string = info_string,
+ delimiters = {
+ start_delim and vim.treesitter.get_node_text(start_delim, buffer) or "",
+ end_delim and vim.treesitter.get_node_text(end_delim, buffer) or "",
+ },
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Horizontal rule parser.
+---@param text string[]
+---@param range node.range
+markdown.hr = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __markdown.horizontal_rules
+ markdown.insert({
+ class = "markdown_hr",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Reference link definition parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range __reference_definitions.range
+markdown.link_ref = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ --- [link]: destination
+ --- 0 1 2
+ --- These 3 nodes always exist.
+
+ local n_label = TSNode:child(0);
+ local n_desc = TSNode:child(2);
+
+ ---@type string, string
+ local label, desc;
+
+ if n_label then
+ label = vim.treesitter.get_node_text(n_label, buffer):gsub("^%[", ""):gsub("%]$", "");
+ range.label = { n_label:range() };
+ end
+
+ if n_desc then
+ desc = vim.treesitter.get_node_text(n_desc, buffer);
+ range.description = { n_desc:range() };
+ end
+
+ ---@type __markdown.reference_definitions
+ markdown.insert({
+ class = "markdown_link_ref_definition",
+
+ label = label,
+ description = desc,
+
+ text = text,
+ range = range
+ });
+
+ if label and desc then
+ inline.cache.link_ref[label] = desc;
+ end
+ ---_
+end
+
+--- List item parser.
+---@param buffer integer
+---@param range node.range
+markdown.list_item = function (buffer, TSNode, _, range)
+ ---+${lua}
+
+ ---@type string[]
+ local text = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_end, false);
+
+ local tolerance_limit = spec.get({ "experimental", "list_empty_line_tolerance" }) or 3; ---@diagnostic disable-line
+ local marker, before, indent, checkbox;
+
+ if text[1]:match("^[%>%s]*([%-%+%*])%s?") then
+ marker = text[1]:match("^[%>%s]*([%-%+%*])%s?");
+ checkbox = text[1]:match("^[%>%s]*[%-%+%*]%s+%[(.)%]")
+ elseif text[1]:match("^[%>%s]*(%d+[%.%)])%s?") then
+ marker = text[1]:match("^[%>%s]*(%d+[%.%)])%s?");
+ checkbox = text[1]:match("^[%>%s]*%d+[%.%)]%s+%[(.)%]");
+ end
+
+ if not marker then
+ return;
+ end
+
+ before = text[1]:match("^[%s%>]*%>") or "";
+
+ if before:match("%>$") then
+ local tmp = text[1]:gsub(
+ "^" .. utils.escape_string(before),
+ ""
+ );
+
+ if tmp:match("^%s") then
+ before = before .. " ";
+ tmp = tmp:gsub("^%s", "");
+ end
+
+ indent = tmp:match("^%s*");
+ else
+ indent = text[1]:match("^%s*");
+ end
+
+ range.col_start = before:len();
+
+ local list_tolerance, nested_tolerance = 0, 0;
+ local nested_indent = 0;
+ local skip = false;
+
+ local candidates = {};
+
+ for l, line in ipairs(text) do
+ ---+${lua}
+
+ if list_tolerance >= tolerance_limit then
+ break;
+ end
+
+ line = line:sub(range.col_start);
+
+ if l == 1 then
+ table.insert(candidates, (l - 1));
+ elseif
+ line:match("^(%s*)[%-%+%*]%s")
+ then
+ nested_indent = line:match("^(%s*)[%-%+%*]%s"):len();
+ nested_tolerance = 0;
+
+ skip = true;
+ elseif
+ line:match("^(%s*)%d+[%.%)]%s")
+ then
+ nested_indent = line:match("^(%s*)%d+[%.%)]%s"):len();
+ nested_tolerance = 0;
+
+ skip = true;
+ elseif skip == true then
+ local line_indent = line:match("^%s*"):len();
+
+ if list_tolerance >= tolerance_limit then
+ skip = false;
+ nested_indent = 0;
+
+ table.insert(candidates, (l - 1));
+ elseif line == "" then
+ nested_tolerance = nested_tolerance + 1;
+ elseif line_indent <= nested_indent then
+ skip = false;
+ nested_indent = 0;
+
+ table.insert(candidates, (l - 1));
+ else
+ nested_tolerance = 0;
+ end
+ else
+ if list_tolerance >= tolerance_limit then
+ break;
+ elseif line == "" then
+ list_tolerance = list_tolerance + 1;
+ else
+ table.insert(candidates, (l - 1));
+ end
+ end
+ ---_
+ end
+
+ local node = TSNode;
+ local block = false;
+
+ while node do
+ if node:type() == "block_quote" then
+ block = true;
+ break;
+ end
+
+ node = node:parent();
+ end
+
+ ---@type __markdown.list_items
+ markdown.insert({
+ class = "markdown_list_item",
+ __block = block,
+
+ candidates = candidates,
+ marker = marker:gsub("%s", ""),
+ checkbox = checkbox,
+ indent = #(indent or ""),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Minus metadata parser.
+---@param text string[]
+---@param range node.range
+markdown.metadata_minus = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __markdown.metadata_minus
+ table.insert(markdown.content, {
+ class = "markdown_metadata_minus",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Plus metadata parser.
+---@param text string[]
+---@param range node.range
+markdown.metadata_plus = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __markdown.metadata_plus
+ table.insert(markdown.content, {
+ class = "markdown_metadata_plus",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+markdown.section = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local heading = TSNode:child(0);
+ local heading_text = vim.treesitter.get_node_text(heading, buffer);
+
+ ---@type __markdown.sections
+ table.insert(markdown.content, {
+ class = "markdown_section",
+ level = heading_text:match("^%s*(#+)"):len(),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Checks if a table is overlapping with another table.
+---
+--- NOTE: It is assumed that the file is being parser from the
+--- top.
+---
+---@param row_start integer
+---@return boolean
+---@return boolean
+local function overlap (row_start)
+ ---+${lua}
+
+ local top_border, border_overlap = true, false;
+
+ for _, item in ipairs(markdown.sorted.markdown_table or {}) do
+ if item.range.row_end == row_start then
+ markdown.content[item.id].bottom_border = false;
+ top_border = false;
+ break;
+ elseif item.range.row_end == row_start - 1 then
+ markdown.content[item.id].border_overlap = true;
+ top_border = false;
+ break;
+ end
+ end
+
+ return top_border, border_overlap;
+ ---_
+end
+
+--- Table parser.
+---@param text string[]
+---@param range node.range
+markdown.table = function (_, _, text, range)
+ ---+${lua}
+
+ local header, separator, rows = {}, {}, {};
+ local aligns = {};
+
+ if text[1] and text[1]:match("^%s+") then
+ range.col_start = range.col_start + text[1]:match("^%s+"):len();
+ end
+
+ local function line_processor (line)
+ local _o = {};
+ local y = 0;
+
+ line = line:gsub("\\|", " ");
+
+ for sep, col in line:gmatch("(|)([^|]+)") do
+ table.insert(_o, {
+ class = "separator",
+
+ text = sep,
+
+ col_start = y,
+ col_end = y + #sep,
+ });
+
+ y = y + #sep;
+ col = col:gsub("MKVescapedPIPE", "\\|")
+
+ table.insert(_o, {
+ class = "column",
+
+ text = col,
+
+ col_start = y,
+ col_end = y + #col,
+ })
+
+ y = y + #col;
+ end
+
+ if line:match("|$") then
+ table.insert(_o, {
+ class = "separator",
+
+ text = "|",
+
+ col_start = y,
+ col_end = y + 1,
+ });
+ else
+ table.insert(_o, {
+ class = "missing_seperator",
+
+ text = "|",
+
+ col_start = y,
+ col_end = y,
+ });
+ end
+
+ return _o;
+ end
+
+ for l, line in ipairs(text) do
+ local row_text = line:gsub("\\|", "MKVescapedPIPE");
+
+ if l == 1 then
+ header = line_processor(row_text);
+ elseif l == 2 then
+ separator = line_processor(row_text);
+
+ for _, col in ipairs(separator) do
+ col = col.text;
+
+ if not col:match("^[%s%-%:]+$") then
+ goto continue;
+ end
+
+ if col:match("^%s*:") and col:match(":%s*$") then
+ table.insert(aligns, "center");
+ elseif col:match("^%s*:") then
+ table.insert(aligns, "left");
+ elseif col:match(":%s*$") then
+ table.insert(aligns, "right");
+ else
+ table.insert(aligns, "default");
+ end
+
+ ::continue::
+ end
+ else
+ table.insert(rows, line_processor(row_text))
+ end
+ end
+
+ local top_border, border_overlap = overlap(range.row_start);
+
+ ---@type __markdown.tables
+ markdown.insert({
+ class = "markdown_table",
+
+ top_border = top_border,
+ bottom_border = true,
+ border_overlap = border_overlap,
+
+ alignments = aligns,
+
+ header = header,
+ separator = separator,
+ rows = rows,
+
+ text = text,
+ range = range
+ });
+ table.insert(markdown.cache.table_ends, range.row_end);
+ ---_
+end
+
+--- Markdown parser.
+---@param buffer integer
+---@param TSTree table
+---@param from integer?
+---@param to integer?
+---@return table[]
+---@return table
+markdown.parse = function (buffer, TSTree, from, to)
+ ---+${lua}
+
+ -- Clear the previous contents
+ markdown.sorted = {}
+ markdown.content = {};
+
+ markdown.cache.table_ends = {};
+ inline.cache = {
+ checkbox = {},
+ link_ref = {}
+ };
+
+ local scanned_queries = vim.treesitter.query.parse("markdown", [[
+ ((section
+ (atx_heading)) @markdown.section)
+
+ ((atx_heading) @markdown.atx_heading)
+
+ ((block_quote) @markdown.block_quote)
+
+ ([
+ (task_list_marker_unchecked)
+ (task_list_marker_checked)
+ ] @markdown.checkbox)
+
+ ((fenced_code_block) @markdown.code_block)
+
+ ((thematic_break) @markdown.hr)
+
+ ((list_item) @markdown.list_item)
+
+ ((minus_metadata) @markdown.metadata_minus)
+
+ ((setext_heading) @markdown.setext_heading)
+
+ ((plus_metadata) @markdown.metadata_plus)
+
+ ((pipe_table) @markdown.table)
+
+ ((link_reference_definition) @markdown.link_ref)
+ ]]);
+
+ for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TSTree:root(), buffer, from, to) do
+ local capture_name = scanned_queries.captures[capture_id];
+
+ if not capture_name:match("^markdown%.") then
+ goto continue;
+ end
+
+ ---@type string?
+ local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
+ local r_start, c_start, r_end, c_end = capture_node:range();
+
+ if capture_text == nil then
+ goto continue;
+ end
+
+ if not capture_text:match("\n$") then
+ capture_text = capture_text .. "\n";
+ end
+
+ local lines = {};
+
+ for line in capture_text:gmatch("(.-)\n") do
+ table.insert(lines, line);
+ end
+
+ ---@type boolean, string
+ local success, error = pcall(
+ markdown[capture_name:gsub("^markdown%.", "")],
+
+ buffer,
+ capture_node,
+ lines,
+ {
+ row_start = r_start,
+ col_start = c_start,
+
+ row_end = r_end,
+ col_end = c_end
+ }
+ );
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = error
+ });
+ end
+
+ ::continue::
+ end
+
+ return markdown.content, markdown.sorted;
+ ---_
+end
+
+return markdown;
diff --git a/lua/markview/parsers/markdown_inline.lua b/lua/markview/parsers/markdown_inline.lua
new file mode 100644
index 0000000..acbaf78
--- /dev/null
+++ b/lua/markview/parsers/markdown_inline.lua
@@ -0,0 +1,677 @@
+local inline = {};
+
+--- Queried contents
+---@type table[]
+inline.content = {};
+
+--- Queried contents, but sorted
+inline.sorted = {}
+
+inline.insert = function (data)
+ table.insert(inline.content, data);
+
+ if not inline.sorted[data.class] then
+ inline.sorted[data.class] = {};
+ end
+
+ table.insert(inline.sorted[data.class], data);
+end
+
+--- Cached stuff
+---@type { checkbox: { [integer]: table } }
+inline.cache = {
+ checkbox = {},
+ link_ref = {}
+}
+
+--- Checkbox parser.
+---@param buffer integer
+---@param range node.range
+inline.checkbox = function (buffer, _, text, range)
+ ---+${lua}
+
+ local line = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_start + 1, false)[1];
+
+ local before = line:sub(0, range.col_start);
+ local inner = line:sub(range.col_start + 1, range.col_end - 1);
+
+ if before:match("^[%s%>]*[%-%+%*]%s$") == nil and before:match("^[%s%>]*%d+[%.%)]%s$") == nil then
+ return;
+ end
+
+ ---@type __inline.checkboxes
+ inline.insert({
+ class = "inline_checkbox",
+ state = inner:gsub("[%[%]]", ""),
+
+ text = text,
+ range = range
+ });
+
+ --- Cache the current checkbox.
+ --- TODO, Has no use *yet*.
+ inline.cache.checkbox[range.row_start] = inline.content[#inline.content];
+ ---_
+end
+
+--- Inline code parser.
+---@param text string[]
+---@param range node.range
+inline.code_span = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __inline.inline_codes
+ inline.insert({
+ class = "inline_code_span",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Embed file link parser.
+---@param text string[]
+---@param range inline_link.range
+inline.embed_file = function (_, _, text, range)
+ ---+${lua}
+ if text[1]:match("%#%^(.+)%]%]$") then
+ local file, block = text[1]:match("^%!%[%[(.*)%#%^(.+)%]%]$");
+ range.label = { range.row_start, range.col_start + 3, range.row_end, range.col_end - 2 };
+
+ range.block = { range.row_start, range.col_start + 3 + #file + 2, range.row_end, range.col_end - 2 };
+
+ if file ~= "" then
+ range.file = { range.row_start, range.col_start + 3, range.row_end, range.col_start + 3 + #file };
+ else
+ file = nil;
+ end
+
+ ---@type __inline.embed_files
+ inline.insert({
+ class = "inline_link_block_ref",
+ file = file,
+ block = block,
+ label = string.format("%s#^%s", file, block),
+
+ text = text,
+ range = range
+ });
+ else
+ ---@type __inline.embed_files
+ inline.insert({
+ class = "inline_link_embed_file",
+ label = text[1]:match("%[%[([^%[+])%]%]"),
+
+ text = text,
+ range = range
+ });
+ end
+ ---_
+end
+
+--- Email parser.
+---@param text string[]
+---@param range inline_link.range
+inline.email = function (_, _, text, range)
+ ---+${lua}
+
+ range.label = { range.row_start, range.col_start + 1, range.row_end, range.col_end - 1 };
+
+ ---@type __inline.emails
+ inline.insert({
+ class = "inline_link_email",
+ label = text[1]:sub(range.col_start + 2, range.col_end - 1),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Github like emoji shorthand parser.
+---@param range node.range
+inline.emojis = function (_, TSNode, text, range)
+ ---+${lua}
+
+ local parent = TSNode:parent();
+
+ while parent do
+ if parent:type() == "inline" then
+ return;
+ end
+
+ parent = parent:parent();
+ end
+
+ local utils = require("markview.utils");
+ local lines = text;
+
+ for l, line in ipairs(lines) do
+ local col_start = l == 1 and range.col_start or 0;
+
+ local _line = line;
+ _line = _line:gsub("%`.-%`", function (s)
+ return string.rep("Y", vim.fn.strchars(s));
+ end);
+
+ for short_code in _line:gmatch("%:[%a%d%_%+%-]+%:") do
+ local c_s, c_e = _line:find(short_code, 0, #_line, true);
+
+ ---@type __inline.emojis
+ inline.insert({
+ class = "inline_emoji",
+ name = short_code:gsub(":", ""),
+ text = { short_code },
+
+ range = {
+ row_start = range.row_start + (l - 1),
+ col_start = col_start + c_s - 1,
+
+ row_end = range.row_start + (l - 1),
+ col_end = col_start + c_e
+ }
+ });
+
+ _line = _line:gsub(utils.escape_string(short_code), function (s)
+ return string.rep("X", vim.fn.strchars(s));
+ end, 1);
+ end
+ end
+ ---_
+end
+
+--- Uri autolink parser.
+---@param text string[]
+---@param range node.range
+inline.entity = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __inline.entities
+ inline.insert({
+ class = "inline_entity",
+ name = text[1]:gsub("[^%a%d]", ""),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Uri autolink parser.
+---@param text string[]
+---@param range node.range
+inline.escaped = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __inline.escaped
+ inline.insert({
+ class = "inline_escaped",
+
+ text = text[1]:sub(range.col_start + 1, range.col_end - 1),
+ range = range
+ });
+ ---_
+end
+
+--- Footnote parser.
+---@param text string[]
+---@param range inline_link.range
+inline.footnote = function (_, _, text, range)
+ ---+${lua}
+
+ local label = table.concat(text, ""):gsub("^%[%^", ""):gsub("%]$", "");
+ range.label = { range.row_start, range.col_start + 2, range.row_end, range.col_end - 1 };
+
+ ---@type __inline.footnotes
+ inline.insert({
+ class = "inline_footnote",
+
+ text = text[1],
+ label = label,
+
+ range = range
+ });
+ ---_
+end
+
+--- Highlight parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+inline.highlights = function (_, TSNode, text, range)
+ ---+${lua}
+
+ local parent = TSNode:parent();
+
+ while parent do
+ if parent:type() == "inline" then
+ return;
+ end
+
+ parent = parent:parent();
+ end
+
+ local utils = require("markview.utils");
+ local lines = text;
+
+ for l, line in ipairs(lines) do
+ local col_start = l == 1 and range.col_start or 0;
+
+ local _line = line;
+ _line = _line:gsub("%`.-%`", function (s)
+ return string.rep("Y", vim.fn.strchars(s));
+ end);
+
+ for highlight in _line:gmatch("%=%=[^=]+%=%=") do
+ local c_s, c_e = _line:find(highlight, 0, #_line, true);
+
+ ---@type __inline.highlights
+ inline.insert({
+ class = "inline_highlight",
+ text = { highlight },
+
+ range = {
+ row_start = range.row_start + (l - 1),
+ col_start = col_start + c_s - 1,
+
+ row_end = range.row_start + (l - 1),
+ col_end = col_start + c_e
+ }
+ });
+
+ _line = _line:gsub(utils.escape_string(highlight), function (s)
+ return string.rep("X", vim.fn.strchars(s));
+ end, 1);
+ end
+ end
+ ---_
+end
+
+--- Image link parser.
+---@param TSNode table
+---@param text string[]
+---@param range inline_link.range
+inline.image = function (buffer, TSNode, text, range)
+ ---+${lua}
+ if text[1]:match("^%!%[%[") and text[1]:match("%]%]$") then
+ --- This is an embed file,
+ --- Not an image!
+ inline.embed_file(buffer, TSNode, text, range);
+ return;
+ end
+
+ ---@cast range inline_link.range
+
+ local link_label;
+ local link_desc;
+
+ for child in TSNode:iter_children() do
+ if child:type() == "image_description" then
+ link_label = vim.treesitter.get_node_text(child, buffer):gsub("[%[%]%(%)]", "");
+ range.label = { child:range() };
+ elseif child:type() == "link_label" or child:type() == "link_destination" then
+ link_desc = vim.treesitter.get_node_text(child, buffer):gsub("[%[%]%(%)]", "");
+ range.description = { child:range() };
+ end
+ end
+
+ range.label = range.label or { range.row_start, range.col_start + 2, range.row_end, range.col_start - 3 };
+
+ ---@type __inline.images
+ inline.insert({
+ class = "inline_link_image",
+
+ text = text,
+ description = link_desc,
+ label = link_label,
+
+ range = range
+ });
+ ---_
+end
+
+--- Hyperlink parser.
+---@param buffer integer
+---@param text string[]
+---@param range inline_link.range
+inline.hyperlink = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local link_desc;
+ local link_label;
+
+ for child in TSNode:iter_children() do
+ if child:type() == "link_text" then
+ link_label = vim.treesitter.get_node_text(child, buffer):gsub("[%[%]%(%)]", "");
+ range.label = { child:range() };
+ elseif child:type() == "link_label" or child:type() == "link_destination" then
+ link_desc = vim.treesitter.get_node_text(child, buffer):gsub("[%[%]%(%)]", "");
+ range.description = { child:range() };
+ end
+ end
+
+ range.label = range.label or { range.row_start, range.col_start + 1, range.row_end, range.col_start - 1 };
+
+ ---@type __inline.hyperlinks
+ inline.insert({
+ class = "inline_link_hyperlink",
+
+ text = text,
+ description = link_desc,
+ label = link_label,
+
+ range = range
+ });
+ ---_
+end
+
+--- Uri autolink parser.
+---@param text string[]
+---@param range inline_link.range
+inline.internal_link = function (_, _, text, range)
+ ---+${lua}
+ if string.match(text[1], "%#%^.+$") ~= nil then
+ --- Embed files
+ local file, block = text[1]:match("^%[%[(.*)%#%^(.+)$");
+ range.label = { range.row_start, range.col_start + 2, range.row_end, range.col_end - 2 };
+
+ range.block = { range.row_start, range.col_start + 2 + #file + 2, range.row_end, range.col_end - 2 };
+
+ if file ~= "" then
+ range.file = { range.row_start, range.col_start + 2, range.row_end, range.col_start + 2 + #file };
+ else
+ file = nil;
+ end
+
+ ---@type __inline.block_references
+ inline.insert({
+ class = "inline_link_block_ref",
+ file = file,
+ block = block,
+ label = string.format("%s#^%s", file, block),
+
+ text = text,
+
+ range = range
+ });
+ else
+ local label = text[1]:match("^%[%[(.+)%]%]");
+ local alias_start, alias_end, alias = text[1]:find("%|([^%|]+)%]%]$");
+
+ if type(alias) == "string" and type(alias_start) == "number" and type(alias_end) == "number" then
+ range.alias = { range.row_start, range.col_start + alias_start, range.row_end, range.col_end - 1 };
+ end
+
+ range.label = { range.row_start, range.col_start + 2, range.row_end, range.col_end - 2 };
+
+ ---@type __inline.internal_links
+ inline.insert({
+ class = "inline_link_internal",
+
+ text = text,
+ alias = alias,
+ label = label,
+
+ range = range
+ });
+ end
+ ---_
+end
+
+--- Reference link parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range inline_link.range
+inline.reference_link = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local link_desc;
+ local link_label;
+
+ for child in TSNode:iter_children() do
+ if child:type() == "link_text" then
+ link_label = vim.treesitter.get_node_text(child, buffer):gsub("[%[%]%(%)]", "");
+ range.label = { child:range() };
+ elseif child:type() == "link_label" or child:type() == "link_destination" then
+ link_desc = vim.treesitter.get_node_text(child, buffer):gsub("[%[%]%(%)]", "");
+ range.description = { child:range() };
+ end
+ end
+
+ range.label = range.label or { range.row_start, range.col_start + 1, range.row_end, range.col_end - 3 };
+
+ inline.insert({
+ class = "inline_link_hyperlink",
+
+ text = text,
+ description = link_desc,
+ label = link_label,
+
+ range = range
+ });
+ ---_
+end
+
+--- Shortcut link parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range inline_link.range
+inline.shortcut_link = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local s_line = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_start + 1, false)[1];
+ local e_line = vim.api.nvim_buf_get_lines(buffer, range.row_end, range.row_end + 1, false)[1];
+
+ local before = s_line:sub(0, range.col_start);
+ local after = e_line:sub(range.col_end);
+
+ if text[1]:match("^%[%^") then
+ --- Footnote
+ return;
+ elseif before:match("^[%s%>]*[%+%-%*]%s+$") and text[1]:match("^%[.%]$") then
+ --- Checkbox
+ return;
+ elseif before:match("^[%s%>]*%d+[%.%)]%s+$") and text[1]:match("^%[.%]$") then
+ --- Checkbox (ordered list item)
+ return;
+ elseif before:match("%>%s*$") then
+ --- Callout
+ return;
+ elseif before:match("%!%[$") and after:match("^%]") then
+ --- Embed file
+ return;
+ elseif before:match("%[$") and after:match("^%]") then
+ if range.row_start ~= range.row_end then
+ goto invalid_link;
+ end
+
+ text[1] = "[" .. text[1];
+ text[#text] = text[#text] .. "]";
+
+ range.col_start = range.col_start - 1;
+ range.col_end = range.col_end + 1;
+
+ --- Obsidian internal link
+ inline.internal_link(buffer, TSNode, text, range);
+ return;
+ end
+
+ ::invalid_link::
+
+ local link_desc;
+ local link_label;
+
+ for child in TSNode:iter_children() do
+ if child:type() == "link_text" then
+ link_label = vim.treesitter.get_node_text(child, buffer):gsub("[%[%]%(%)]", "");
+ range.label = { child:range() };
+ elseif child:type() == "link_label" or child:type() == "link_destination" then
+ link_desc = vim.treesitter.get_node_text(child, buffer):gsub("[%[%]%(%)]", "");
+ range.description = { child:range() };
+ end
+ end
+
+ range.label = range.label or { range.row_start, range.col_start + 1, range.row_end, range.col_start - 1 };
+
+ inline.insert({
+ class = "inline_link_shortcut",
+ label = link_label,
+ description = link_desc,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Uri autolink parser.
+---@param TSNode table
+---@param text string[]
+---@param range inline_link.range
+inline.uri_autolink = function (_, TSNode, text, range)
+ ---+${lua}
+
+ range.label = { range.row_start, range.col_start + 1, range.row_end, range.col_end - 1 };
+
+ inline.insert({
+ class = "inline_link_uri_autolink",
+ node = TSNode,
+
+ text = text,
+ label = text[1]:sub(range.col_start + 1, range.col_end - 1),
+
+ range = range
+ });
+ ---_
+end
+
+--- Inline markdown parser.
+---@param buffer integer
+---@param TSTree table
+---@param from integer?
+---@param to integer?
+---@return table[]
+---@return table
+inline.parse = function (buffer, TSTree, from, to)
+ ---+${lua}
+
+ inline.sorted = {};
+ inline.content = {};
+
+ local pre_queries = vim.treesitter.query.parse("markdown_inline", [[
+ (
+ (shortcut_link) @markdown_inline.checkbox
+ (#match? @markdown_inline.checkbox "^\\[.\\]$")) ; Fix the match pattern to match literal [ & ]
+ ]]);
+
+ for capture_id, capture_node, _, _ in pre_queries:iter_captures(TSTree:root(), buffer, from, to) do
+ local capture_name = pre_queries.captures[capture_id];
+ local r_start, c_start, r_end, c_end = capture_node:range();
+
+ local capture_text = vim.api.nvim_buf_get_lines(buffer, r_start, r_start == r_end and r_end + 1 or r_end, false);
+
+ inline[capture_name:gsub("^markdown_inline%.", "")](buffer, capture_node, capture_text, {
+ row_start = r_start,
+ col_start = c_start,
+
+ row_end = r_end,
+ col_end = c_end
+ });
+ end
+
+ local scanned_queries = vim.treesitter.query.parse("markdown_inline", [[
+ ((inline) @markdown_inline.highlights
+ (#match? @markdown_inline.highlights "\\=\\=.+\\=\\="))
+
+ ((inline) @markdown_inline.emojis
+ (#match? @markdown_inline.emojis "\\:.+\\:"))
+
+ ((email_autolink) @markdown_inline.email)
+
+ ((image) @markdown_inline.image)
+
+ ([
+ (inline_link)
+ (collapsed_reference_link)] @markdown_inline.hyperlink)
+
+ ((full_reference_link
+ (link_text)
+ (link_label)) @markdown_inline.reference_link)
+
+ ((shortcut_link
+ (link_text) @footnote.text
+ (#match? @footnote.text "^\\^")) @markdown_inline.footnote)
+
+ ((shortcut_link) @markdown_inline.shortcut_link)
+
+ ((uri_autolink) @markdown_inline.uri_autolink)
+
+ ((code_span) @markdown_inline.code_span)
+
+ ([
+ (entity_reference)
+ (numeric_character_reference)] @markdown_inline.entity)
+
+ ((backslash_escape) @markdown_inline.escaped)
+ ]]);
+
+ for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TSTree:root(), buffer, from, to) do
+ local capture_name = scanned_queries.captures[capture_id];
+
+ if not capture_name:match("^markdown_inline") then
+ goto continue;
+ end
+
+ ---@type string?
+ local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
+ local r_start, c_start, r_end, c_end = capture_node:range();
+
+ if capture_text == nil then
+ goto continue;
+ end
+
+ --- Doesn't end with a newline. Add it.
+ if not capture_text:match("\n$") then
+ capture_text = capture_text .. "\n";
+ end
+
+ local lines = {};
+
+ for line in capture_text:gmatch("(.-)\n") do
+ table.insert(lines, line);
+ end
+
+ ---@type boolean, string
+ local success, error = pcall(
+ inline[capture_name:gsub("^markdown_inline%.", "")],
+ buffer,
+ capture_node,
+ lines,
+
+ {
+ row_start = r_start,
+ col_start = c_start,
+
+ row_end = r_end,
+ col_end = c_end
+ }
+ );
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = error
+ });
+ end
+
+ ::continue::
+ end
+
+ return inline.content, inline.sorted;
+ ---_
+end
+
+return inline;
diff --git a/lua/markview/parsers/typst.lua b/lua/markview/parsers/typst.lua
new file mode 100644
index 0000000..a60ee0f
--- /dev/null
+++ b/lua/markview/parsers/typst.lua
@@ -0,0 +1,652 @@
+local typst = {};
+local utils = require("markview.utils");
+
+typst.cache = {
+ list_item_number = 0
+};
+
+--- Queried contents
+---@type table[]
+typst.content = {};
+
+--- Queried contents, but sorted
+typst.sorted = {}
+
+typst.insert = function (data)
+ table.insert(typst.content, data);
+
+ if not typst.sorted[data.class] then
+ typst.sorted[data.class] = {};
+ end
+
+ table.insert(typst.sorted[data.class], data);
+end
+
+--- Typst code parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.code = function (buffer, TSNode, text, range)
+ ---+${func}
+ local node = TSNode:parent();
+
+ while node do
+ if node:type() == "code" then
+ --- If the node is inside another
+ --- code node, skip it.
+ return;
+ end
+
+ node = node:parent();
+ end
+
+ local from = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_start + 1, false)[1]:sub(0, range.col_start);
+ local to = vim.api.nvim_buf_get_lines(buffer, range.row_end, range.row_end + 1, false)[1]:sub(range.col_end + 1);
+ local inline = false;
+
+ if from:match("^(.+)$") or to:match("^(.+)") then
+ inline = true;
+ end
+
+ if inline == true then
+ ---@type __typst.code_spans
+ typst.insert({
+ class = "typst_code_span",
+
+ text = text,
+ range = range
+ });
+ else
+ ---@type __typst.code_block
+ typst.insert({
+ class = "typst_code_block",
+
+ text = text,
+ range = range
+ });
+ end
+ ---_
+end
+
+--- Typst emphasized text parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.emphasis = function (_, TSNode, text, range)
+ ---+${lua}
+
+ local _n = TSNode:parent();
+
+ while _n do
+ if vim.list_contains({ "raw_span", "raw_blck", "code", "field" }, _n:type()) then
+ return;
+ end
+
+ _n = _n:parent();
+ end
+
+ ---@type __typst.emphasis
+ typst.insert({
+ class = "typst_emphasis",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst escaped character parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.escaped = function (_, TSNode, text, range)
+ ---+${func}
+
+ local node = TSNode:parent();
+
+ while node do
+ if node:type() == "code" then
+ return;
+ end
+
+ node = node:parent();
+ end
+
+ ---@type __typst.escapes
+ typst.insert({
+ class = "typst_escaped",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst heading parser.
+---@param text string[]
+---@param range node.range
+typst.heading = function (_, _, text, range)
+ ---+${func}
+
+ local level = text[1]:match("^(%=+)"):len();
+
+ ---@type __typst.headings
+ typst.insert({
+ class = "typst_heading",
+ level = level,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst label parser.
+---@param text string[]
+---@param range node.range
+typst.label = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __typst.labels
+ typst.insert({
+ class = "typst_label",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst list item parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.list_item = function (buffer, TSNode, text, range)
+ ---+${func}
+ local line = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_start + 1, false)[1]:sub(0, range.col_start);
+ local marker = text[1]:match("^([%-%+])") or text[1]:match("^(%d+%.)");
+ local number;
+
+ if marker == "+" then
+ local prev_item = TSNode:prev_sibling();
+ local item_text = prev_item and vim.treesitter.get_node_text(prev_item, buffer) or "";
+
+ if
+ not prev_item or
+ (
+ prev_item:type() == "item" and
+ item_text:match("^(%+)")
+ )
+ then
+ typst.cache.list_item_number = typst.cache.list_item_number + 1;
+ else
+ typst.cache.list_item_number = 1;
+ end
+
+ number = typst.cache.list_item_number;
+ end
+
+ local row_end = range.row_start - 1;
+
+ for l, ln in ipairs(text) do
+ if l ~= 1 and ( ln:match("^%s*([%+%-])") or ln:match("^%s*(%d)%.") ) then
+ break
+ end
+
+ row_end = row_end + 1;
+ end
+
+ range.row_end = row_end;
+
+ ---@type __typst.list_items
+ typst.insert({
+ class = "typst_list_item",
+ indent = line:match("(%s*)$"):len(),
+ marker = marker,
+ number = number,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst list item parser.
+---@param buffer integer
+---@param text string[]
+---@param range node.range
+typst.math = function (buffer, _, text, range)
+ ---+${func}
+
+ local from, to = vim.api.nvim_buf_get_lines(buffer, range.row_start, range.row_start + 1, false)[1]:sub(0, range.col_start), vim.api.nvim_buf_get_lines(buffer, range.row_end, range.row_end + 1, true)[1]:sub(0, range.col_end);
+ local inline = false;
+
+ if from:match("^(%s*)$") == nil then
+ inline = true;
+ elseif to:match("^(%s*)%$$") == nil then
+ inline = true;
+ elseif text[1]:match("%$$") == nil then
+ inline = true;
+ end
+
+ ---@type __typst.maths
+ typst.insert({
+ class = inline == true and "typst_math_span" or "typst_math_block",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst url links parser.
+---@param text string[]
+---@param range inline_link.range
+typst.link_url = function (_, _, text, range)
+ ---+${lua}
+
+ range.label = { range.row_start, range.col_start, range.row_end, range.col_end }
+
+ ---@type __typst.url_links
+ typst.insert({
+ class = "typst_link_url",
+ label = text[1],
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst reference link parser.
+---@param text string[]
+---@param range inline_link.range
+typst.link_ref = function (_, _, text, range)
+ ---+${lua}
+
+ range.label = { range.row_start, range.col_start + 1, range.row_end, range.col_end };
+
+ ---@type __typst.reference_links
+ typst.insert({
+ class = "typst_link_ref",
+ label = text[1]:gsub("^%@", ""),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst code block parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.raw_block = function (buffer, TSNode, text, range)
+ ---+${func}
+
+ local lang_node = TSNode:field("lang")[1];
+ local language;
+
+ if lang_node then
+ language = vim.treesitter.get_node_text(lang_node, buffer);
+ end
+
+ for l, line in ipairs(text) do
+ if l == 1 then goto continue; end
+ text[l] = line:sub(range.col_start + 1);
+ ::continue::
+ end
+
+ ---@type __typst.raw_blocks
+ typst.insert({
+ class = "typst_raw_block",
+ language = language,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst inline code parser.
+---@param text string[]
+---@param range node.range
+typst.raw_span = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __typst.raw_spans
+ typst.insert({
+ class = "typst_raw_span",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst strong text parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.strong = function (_, TSNode, text, range)
+ ---+${lua}
+
+ local _n = TSNode:parent();
+
+ while _n do
+ if vim.list_contains({ "raw_span", "raw_blck", "code", "field" }, _n:type()) then
+ return;
+ end
+
+ _n = _n:parent();
+ end
+
+ ---@type __typst.strong
+ typst.insert({
+ class = "typst_strong",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst subscript parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.subscript = function (_, TSNode, text, range)
+ ---+${func}
+ local par = TSNode:type() == "group";
+ local lvl = 0;
+
+ local _n = TSNode;
+
+ while _n do
+ if _n:field("sub")[1] then
+ lvl = lvl + 1;
+ end
+
+ _n = _n:parent();
+ end
+
+ range.col_start = range.col_start - 1;
+
+ ---@type __typst.subscripts
+ typst.insert({
+ class = "typst_subscript",
+ parenthesis = par,
+
+ level = lvl,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+
+--- Typst superscript parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.superscript = function (_, TSNode, text, range)
+ ---+${func}
+ local par = TSNode:type() == "group";
+ local lvl = 0;
+ local pre = true;
+
+ local _n = TSNode;
+
+ while _n do
+ if _n:field("sup")[1] then
+ lvl = lvl + 1;
+ end
+
+ _n = _n:parent();
+ end
+
+ range.col_start = range.col_start - 1;
+
+ ---@type __typst.superscripts
+ typst.insert({
+ class = "typst_superscript",
+ parenthesis = par,
+
+ preview = pre,
+ level = lvl,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst symbol parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.symbol = function (_, TSNode, text, range)
+ ---+${func}
+ for _, line in ipairs(text) do
+ if not line:match("^[%a%.]+$") then
+ return;
+ end
+ end
+
+ local _n = TSNode:parent();
+ local style;
+
+ while _n do
+ if vim.list_contains({ "raw_span", "raw_blck", "code", "field" }, _n:type()) then
+ return;
+ elseif vim.list_contains({ "sub", "sup" }, _n:type()) then
+ end
+
+ _n = _n:parent();
+ end
+
+ typst.insert({
+ class = "typst_symbol",
+ name = text[1],
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst code block parser.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range inline_link.range
+typst.term = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ if TSNode:field("term")[1] == nil then
+ return;
+ end
+
+ for l, line in ipairs(text) do
+ if l == 1 then
+ goto continue;
+ end
+
+ text[l] = line:sub(range.col_start + 1);
+ ::continue::
+ end
+
+ range.label = { TSNode:field("term")[1]:range() };
+
+ ---@type __typst.terms
+ typst.insert({
+ class = "typst_term",
+ label = vim.treesitter.get_node_text(
+ TSNode:field("term")[1],
+ buffer
+ ),
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst regular text parser.
+---@param text string[]
+---@param range node.range
+typst.text = function (_, _, text, range)
+ ---+${lua}
+
+ ---@type __typst.text
+ typst.insert({
+ class = "typst_text",
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Typst single word symbol parser.
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+typst.idet = function (_, TSNode, text, range)
+ ---+${funx}
+ local symbols = require("markview.symbols");
+ if not symbols.typst_entries[text[1]] then return; end
+
+ local _n = TSNode:parent();
+
+ while _n do
+ if vim.list_contains({ "raw_span", "raw_blck", "code", "field" }, _n:type()) then
+ return;
+ end
+
+ _n = _n:parent();
+ end
+
+ ---@type __typst.symbols
+ typst.insert({
+ class = "typst_symbol",
+ name = text[1],
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- Parser for typst.
+---@param buffer integer
+---@param TSTree table
+---@param from integer?
+---@param to integer?
+---@return table[]
+---@return table
+typst.parse = function (buffer, TSTree, from, to)
+ ---+${lua}
+
+ typst.cache = {
+ list_item_number = 0
+ };
+
+ -- Clear the previous contents
+ typst.sorted = {};
+ typst.content = {};
+
+ local scanned_queries = vim.treesitter.query.parse("typst", [[
+ ((attach
+ sub: (_) @typst.subscript))
+
+ ((attach
+ sup: (_) @typst.superscript))
+
+ ((field) @typst.symbol)
+
+ ([
+ (number)
+ (symbol)
+ (letter)
+ ] @typst.text)
+
+ ((ident) @typst.idet)
+
+ ((heading) @typst.heading)
+ ((escape) @typst.escaped)
+ ((item) @typst.list_item)
+
+ ((code) @typst.code)
+ ((math) @typst.math)
+
+ ((url) @typst.link_url)
+
+ ((strong) @typst.strong)
+ ((emph) @typst.emphasis)
+ ((raw_span) @typst.raw_span)
+ ((raw_blck) @typst.raw_block)
+
+ ((label) @typst.label)
+ ((ref) @typst.link_ref)
+ ((term) @typst.term)
+ ]]);
+
+ for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TSTree:root(), buffer, from, to) do
+ local capture_name = scanned_queries.captures[capture_id];
+
+ if not capture_name:match("^typst%.") then
+ goto continue
+ end
+
+ ---@type string?
+ local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
+ local r_start, c_start, r_end, c_end = capture_node:range();
+
+ if capture_text == nil then
+ goto continue;
+ end
+
+ if not capture_text:match("\n$") then
+ capture_text = capture_text .. "\n";
+ end
+
+ local lines = {};
+
+ for line in capture_text:gmatch("(.-)\n") do
+ table.insert(lines, line);
+ end
+
+ local success, error = pcall(
+ typst[capture_name:gsub("^typst%.", "")],
+
+ buffer,
+ capture_node,
+ lines,
+ {
+ row_start = r_start,
+ col_start = c_start,
+
+ row_end = r_end,
+ col_end = c_end
+ }
+ );
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = error
+ });
+ end
+
+ ::continue::
+ end
+
+ return typst.content, typst.sorted;
+ ---_
+end
+
+return typst;
diff --git a/lua/markview/parsers/yaml.lua b/lua/markview/parsers/yaml.lua
new file mode 100644
index 0000000..5a382f1
--- /dev/null
+++ b/lua/markview/parsers/yaml.lua
@@ -0,0 +1,206 @@
+local yaml = {};
+
+--- Queried contents
+---@type table[]
+yaml.content = {};
+
+--- Queried contents, but sorted
+yaml.sorted = {}
+
+yaml.insert = function (data)
+ table.insert(yaml.content, data);
+
+ if not yaml.sorted[data.class] then
+ yaml.sorted[data.class] = {};
+ end
+
+ table.insert(yaml.sorted[data.class], data);
+end
+
+--- YAML property.
+---@param buffer integer
+---@param TSNode table
+---@param text string[]
+---@param range node.range
+yaml.property = function (buffer, TSNode, text, range)
+ ---+${lua}
+
+ local key, value = TSNode:field("key")[1], TSNode:field("value")[1];
+
+ local key_text = key and vim.treesitter.get_node_text(key, buffer) or nil;
+ local value_text = value and vim.treesitter.get_node_text(value, buffer) or nil;
+
+ --- Checks if {str} matches any of the
+ --- date patterns.
+ ---@param str string?
+ ---@return boolean
+ local function is_date (str)
+ ---+${lua}
+ if type(str) ~= "string" then
+ return false;
+ end
+
+ local spec = require("markview.spec");
+ local formats = spec.get({ "experimental", "date_formats" }, { fallback = {} });
+
+ for _, format in ipairs(formats) do
+ if string.match(str, format) then
+ return true;
+ end
+ end
+
+ return false;
+ ---_
+ end
+
+ --- Checks if {str} matches any of the
+ --- date & time patterns.
+ ---@param str string?
+ ---@return boolean
+ local function is_date_time (str)
+ ---+${lua}
+ if type(str) ~= "string" then
+ return false;
+ end
+
+ local spec = require("markview.spec");
+ local formats = spec.get({ "experimental", "date_time_formats" }, { fallback = {} });
+
+ for _, format in ipairs(formats) do
+ if string.match(str, format) then
+ return true;
+ end
+ end
+
+ return false;
+ ---_
+ end
+
+ --- Checks if this node contains
+ --- a list.
+ local function is_list()
+ ---+${lua}
+ if type(value) ~= "table" then
+ return false;
+ elseif value:child(0) == nil then
+ --- `value:` has no node.
+ return false;
+ elseif value:child(0):child(0) == nil then
+ return false;
+ elseif value:child(0):child(0):type() ~= "block_sequence" then
+ return false;
+ end
+
+ return true;
+ ---_
+ end
+
+ local value_type = "unknown";
+
+ if is_date_time(value_text) == true then
+ value_type = "date_&_time";
+ elseif is_date(value_text) == true then
+ value_type = "date";
+ elseif is_list() == true then
+ value_type = "list";
+ elseif tonumber(value_text) ~= nil then
+ value_type = "number";
+ elseif value_text == "true" or value_text == "false" then
+ value_type = "checkbox";
+ elseif type(value_text) == "string" then
+ value_type = "text";
+ elseif value_type == nil then
+ value_type = "nil";
+ end
+
+ if range.col_end == 0 then
+ range.row_end = range.row_start + #text - 1;
+ end
+
+ ---@type __yaml.properties
+ yaml.insert({
+ class = "yaml_property",
+ type = value_type,
+
+ key = key_text,
+ value = value_text,
+
+ text = text,
+ range = range
+ });
+ ---_
+end
+
+--- YAML parser.
+---@param buffer integer
+---@param TSTree table
+---@param from integer?
+---@param to integer?
+---@return table[]
+---@return table
+yaml.parse = function (buffer, TSTree, from, to)
+ ---+${lua}
+
+ -- Clear the previous contents
+ yaml.sorted = {};
+ yaml.content = {};
+
+ local scanned_queries = vim.treesitter.query.parse("yaml", [[
+ ((block_mapping_pair) @yaml.property)
+ ]]);
+
+ for capture_id, capture_node, _, _ in scanned_queries:iter_captures(TSTree:root(), buffer, from, to) do
+ local capture_name = scanned_queries.captures[capture_id];
+
+ if not capture_name:match("^yaml%.") then
+ goto continue
+ end
+
+ ---@type string?
+ local capture_text = vim.treesitter.get_node_text(capture_node, buffer);
+ local r_start, c_start, r_end, c_end = capture_node:range();
+
+ if capture_text == nil then
+ goto continue;
+ end
+
+ if not capture_text:match("\n$") then
+ capture_text = capture_text .. "\n";
+ end
+
+ local lines = {};
+
+ for line in capture_text:gmatch("(.-)\n") do
+ table.insert(lines, line);
+ end
+
+ local success, error = pcall(
+ yaml[capture_name:gsub("^yaml%.", "")],
+
+ buffer,
+ capture_node,
+ lines,
+ {
+ row_start = r_start,
+ col_start = c_start,
+
+ row_end = r_end,
+ col_end = c_end
+ }
+ );
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = error
+ });
+ end
+
+ ::continue::
+ end
+
+ return yaml.content, yaml.sorted;
+ ---_
+end
+
+return yaml;
diff --git a/lua/markview/presets.lua b/lua/markview/presets.lua
index 89d4dff..05088b1 100644
--- a/lua/markview/presets.lua
+++ b/lua/markview/presets.lua
@@ -1,6 +1,5 @@
local presets = {};
----@type { [string]: markview.conf.checkboxes }
presets.checkboxes = {
legacy = {
---+ ${conf, Old checkboxes}
@@ -66,6 +65,7 @@ presets.checkboxes = {
---_
},
+ ---@deprecated
minimal = {
---+ ${conf, Minimal style checkboxes}
enable = true,
@@ -195,7 +195,7 @@ presets.headings = {
sign = "๓ฐ ", sign_hl = "MarkviewHeading1Sign",
padding_left = " ", padding_right = " ",
- icon = "๓ฐผ ", hl = "MarkviewHeading1",
+ icon = "๓ฐผ ", hl = "MarkviewHeading1",
},
heading_2 = {
@@ -203,31 +203,31 @@ presets.headings = {
sign = "๓ฐ ", sign_hl = "MarkviewHeading2Sign",
padding_left = " ", padding_right = " ",
- icon = "๓ฐจ ", hl = "MarkviewHeading2",
+ icon = "๓ฐจ ", hl = "MarkviewHeading2",
},
heading_3 = {
style = "label",
padding_left = " ", padding_right = " ",
- icon = "๓ฐผ ", hl = "MarkviewHeading3",
+ icon = "๓ฐผ ", hl = "MarkviewHeading3",
},
heading_4 = {
style = "label",
padding_left = " ", padding_right = " ",
- icon = "๓ฐฒ ", hl = "MarkviewHeading4",
+ icon = "๓ฐฒ ", hl = "MarkviewHeading4",
},
heading_5 = {
style = "label",
padding_left = " ", padding_right = " ",
- icon = "๓ฐผ ", hl = "MarkviewHeading5",
+ icon = "๓ฐผ ", hl = "MarkviewHeading5",
},
heading_6 = {
style = "label",
padding_left = " ", padding_right = " ",
- icon = "๓ฐด ", hl = "MarkviewHeading6",
+ icon = "๓ฐด ", hl = "MarkviewHeading6",
}
---_
},
@@ -242,7 +242,7 @@ presets.headings = {
align = "center",
padding_left = " ", padding_right = " ",
- icon = "๓ฐผ ", hl = "MarkviewHeading1",
+ icon = "๓ฐผ ", hl = "MarkviewHeading1",
},
heading_2 = {
@@ -251,35 +251,35 @@ presets.headings = {
align = "center",
padding_left = " ", padding_right = " ",
- icon = "๓ฐจ ", hl = "MarkviewHeading2",
+ icon = "๓ฐจ ", hl = "MarkviewHeading2",
},
heading_3 = {
style = "label",
align = "center",
padding_left = " ", padding_right = " ",
- icon = "๓ฐผ ", hl = "MarkviewHeading3",
+ icon = "๓ฐผ ", hl = "MarkviewHeading3",
},
heading_4 = {
style = "label",
align = "center",
padding_left = " ", padding_right = " ",
- icon = "๓ฐฒ ", hl = "MarkviewHeading4",
+ icon = "๓ฐฒ ", hl = "MarkviewHeading4",
},
heading_5 = {
style = "label",
align = "center",
padding_left = " ", padding_right = " ",
- icon = "๓ฐผ ", hl = "MarkviewHeading5",
+ icon = "๓ฐผ ", hl = "MarkviewHeading5",
},
heading_6 = {
style = "label",
align = "center",
padding_left = " ", padding_right = " ",
- icon = "๓ฐด ", hl = "MarkviewHeading6",
+ icon = "๓ฐด ", hl = "MarkviewHeading6",
}
---_
},
@@ -294,8 +294,8 @@ presets.headings = {
sign = "๓ฐ ", sign_hl = "MarkviewHeading1Sign",
padding_left = " ", padding_right = " ๎ป๎บ๎ผ๎ป๎บ๎ผ๎ป๎บ",
- corner_right = "๎ผ", corner_right_hl = "MarkviewHeading1Sign",
- icon = "๓ฐผ ", hl = "MarkviewHeading1",
+ corner_right = "๎ผ", corner_right_hl = "MarkviewPalette1Fg",
+ hl = "MarkviewHeading1",
},
heading_2 = {
@@ -303,36 +303,36 @@ presets.headings = {
sign = "๓ฐ ", sign_hl = "MarkviewHeading2Sign",
padding_left = " ", padding_right = " ๎บ๎ผ๎ป๎บ๎ผ๎ป๎บ",
- corner_right = "๎ผ", corner_right_hl = "MarkviewHeading2Sign",
- icon = "๓ฐจ ", hl = "MarkviewHeading2",
+ corner_right = "๎ผ", corner_right_hl = "MarkviewPalette2Fg",
+ hl = "MarkviewHeading2",
},
heading_3 = {
style = "label",
padding_left = " ", padding_right = " ๎ป๎บ๎ผ๎ป๎บ",
- corner_right = "๎ผ", corner_right_hl = "MarkviewHeading3Sign",
- icon = "๓ฐผ ", hl = "MarkviewHeading3",
+ corner_right = "๎ผ", corner_right_hl = "MarkviewPalette3Fg",
+ hl = "MarkviewHeading3",
},
heading_4 = {
style = "label",
padding_left = " ", padding_right = " ๎บ๎ผ๎ป๎บ",
- corner_right = "๎ผ", corner_right_hl = "MarkviewHeading4Sign",
- icon = "๓ฐฒ ", hl = "MarkviewHeading4",
+ corner_right = "๎ผ", corner_right_hl = "MarkviewPalette4Fg",
+ hl = "MarkviewHeading4",
},
heading_5 = {
style = "label",
padding_left = " ", padding_right = " ๎ป๎บ",
- corner_right = "๎ผ", corner_right_hl = "MarkviewHeading5Sign",
- icon = "๓ฐผ ", hl = "MarkviewHeading5",
+ corner_right = "๎ผ", corner_right_hl = "MarkviewPalette5Fg",
+ hl = "MarkviewHeading5",
},
heading_6 = {
style = "label",
padding_left = " ", padding_right = " ๎บ",
- corner_right = "๎ผ", corner_right_hl = "MarkviewHeading6Sign",
- icon = "๓ฐด ", hl = "MarkviewHeading6",
+ corner_right = "๎ผ", corner_right_hl = "MarkviewPalette6Fg",
+ hl = "MarkviewHeading6",
}
---_
},
@@ -346,8 +346,8 @@ presets.headings = {
sign = "๓ฐ ", sign_hl = "MarkviewHeading1Sign",
padding_left = " ", padding_right = " ๎ฑ๎๎ฐ๎ฑ๎๎ฐ๎ฑ๎",
- corner_right = "๎ฐ", corner_right_hl = "MarkviewHeading1Sign",
- icon = "๓ฐผ ", hl = "MarkviewHeading1",
+ corner_right = "๎ฐ", corner_right_hl = "MarkviewPalette1Fg",
+ hl = "MarkviewHeading1",
},
heading_2 = {
@@ -355,36 +355,36 @@ presets.headings = {
sign = "๓ฐ ", sign_hl = "MarkviewHeading2Sign",
padding_left = " ", padding_right = " ๎๎ฐ๎ฑ๎๎ฐ๎ฑ๎",
- corner_right = "๎ฐ", corner_right_hl = "MarkviewHeading2Sign",
- icon = "๓ฐจ ", hl = "MarkviewHeading2",
+ corner_right = "๎ฐ", corner_right_hl = "MarkviewPalette2Fg",
+ hl = "MarkviewHeading2",
},
heading_3 = {
style = "label",
padding_left = " ", padding_right = " ๎ฑ๎๎ฐ๎ฑ๎",
- corner_right = "๎ฐ", corner_right_hl = "MarkviewHeading3Sign",
- icon = "๓ฐผ ", hl = "MarkviewHeading3",
+ corner_right = "๎ฐ", corner_right_hl = "MarkviewPalette3Fg",
+ hl = "MarkviewHeading3",
},
heading_4 = {
style = "label",
padding_left = " ", padding_right = " ๎๎ฐ๎ฑ๎",
- corner_right = "๎ฐ", corner_right_hl = "MarkviewHeading4Sign",
- icon = "๓ฐฒ ", hl = "MarkviewHeading4",
+ corner_right = "๎ฐ", corner_right_hl = "MarkviewPalette4Fg",
+ hl = "MarkviewHeading4",
},
heading_5 = {
style = "label",
padding_left = " ", padding_right = " ๎ฑ๎",
- corner_right = "๎ฐ", corner_right_hl = "MarkviewHeading5Sign",
- icon = "๓ฐผ ", hl = "MarkviewHeading5",
+ corner_right = "๎ฐ", corner_right_hl = "MarkviewPalette5Fg",
+ hl = "MarkviewHeading5",
},
heading_6 = {
style = "label",
padding_left = " ", padding_right = " ๎",
- corner_right = "๎ฐ", corner_right_hl = "MarkviewHeading6Sign",
- icon = "๓ฐด ", hl = "MarkviewHeading6",
+ corner_right = "๎ฐ", corner_right_hl = "MarkviewPalette6Fg",
+ hl = "MarkviewHeading6",
}
---_
},
@@ -643,4 +643,93 @@ presets.horizontal_rules = {
}
};
+presets.tables = {
+ none = {
+ ---+${lua}
+ parts = {
+ top = { " ", " ", " ", " " },
+ header = { " ", " ", " " },
+ separator = { " ", "-", " ", " " },
+ row = { " ", " ", " " },
+ bottom = { " ", " ", " ", " " },
+
+ overlap = { " ", " ", " ", " " },
+
+ align_left = "-",
+ align_right = "-",
+ align_center = { "-", "-" }
+ }
+ ---_
+ },
+
+ single = {
+ ---+${lua}
+ parts = {
+ top = { "โ", "โ", "โ", "โฌ" },
+ header = { "โ", "โ", "โ" },
+ separator = { "โ", "โ", "โค", "โผ" },
+ row = { "โ", "โ", "โ" },
+ bottom = { "โ", "โ", "โ", "โด" },
+
+ overlap = { "โ", "โ", "โฅ", "โฟ" },
+
+ align_left = "โผ",
+ align_right = "โพ",
+ align_center = { "โด", "โถ" }
+ }
+ ---_
+ },
+ double = {
+ ---+${lua}
+ parts = {
+ top = { "โ", "โ", "โ", "โฆ" },
+ header = { "โ", "โ", "โ" },
+ separator = { "โ ", "โ", "โฃ", "โฌ" },
+ row = { "โ", "โ", "โ" },
+ bottom = { "โ", "โ", "โ", "โฉ" },
+
+ overlap = { "โ", "โ", "โข", "โซ" },
+
+ align_left = "โ",
+ align_right = "โ",
+ align_center = { "โ", "โ" }
+ }
+ ---_
+ },
+ rounded = {
+ ---+${lua}
+ parts = {
+ top = { "โญ", "โ", "โฎ", "โฌ" },
+ header = { "โ", "โ", "โ" },
+ separator = { "โ", "โ", "โค", "โผ" },
+ row = { "โ", "โ", "โ" },
+ bottom = { "โฐ", "โ", "โฏ", "โด" },
+
+ overlap = { "โ", "โ", "โฅ", "โฟ" },
+
+ align_left = "โผ",
+ align_right = "โพ",
+ align_center = { "โด", "โถ" }
+ }
+ ---_
+ },
+ solid = {
+ ---+${lua}
+ parts = {
+ top = { "โ", "โ", "โ", "โ" },
+ header = { "โ", "โ", "โ" },
+ separator = { "โ", "โ", "โ", "โ" },
+ row = { "โ", "โ", "โ" },
+ bottom = { "โ", "โ", "โ", "โ" },
+
+ overlap = { "โ", "โ", "โ", "โ" },
+
+ align_left = "โ",
+ align_right = "โ",
+ align_center = { "โ", "โ" }
+ }
+ ---_
+ }
+};
+
return presets;
diff --git a/lua/markview/renderer.lua b/lua/markview/renderer.lua
index 7a47640..a8b6514 100644
--- a/lua/markview/renderer.lua
+++ b/lua/markview/renderer.lua
@@ -1,2285 +1,530 @@
local renderer = {};
-local devicons_loaded, devicons = pcall(require, "nvim-web-devicons");
-local mini_loaded, MiniIcons = pcall(require, "mini.icons");
-
---- Checks if a parser is available or not
----@param parser_name string
----@return boolean
-local function parser_installed(parser_name)
- return (ts_available and treesitter_parsers.has_parser(parser_name)) or pcall(vim.treesitter.query.get, parser_name, "highlights")
-end
-
-local utils = require("markview.utils");
-local languages = require("markview.languages");
-local latex_renderer = require("markview.latex_renderer");
-local html_renderer = require("markview.html_renderer");
-
---- Gets the icon from the language
----@param language string
----@param config_table markview.conf.code_blocks
----@return string Icon
----@return string? Highlight group
----@return string? Sign Highlight group
-renderer.get_icon = function (language, config_table)
- if type(config_table.icons) ~= "string" or config_table.icons == "" then
- return "", "Normal";
- end
-
- if config_table.icons == "devicons" and devicons_loaded then
- return devicons.get_icon(nil, language, { default = true })
- elseif config_table.icons == "mini" and mini_loaded then
- local icon, hl = MiniIcons.get("extension", language);
- return icon, hl;
- elseif config_table.icons == "internal" then
- return languages.get_icon(language);
- end
+local health = require("markview.health");
- return "๓ฐกฏ", "Normal";
-end
+renderer.html = require("markview.renderers.html");
+renderer.markdown = require("markview.renderers.markdown");
+renderer.markdown_inline = require("markview.renderers.markdown_inline");
+renderer.latex = require("markview.renderers.latex");
+renderer.yaml = require("markview.renderers.yaml");
+renderer.typst = require("markview.renderers.typst");
-local tbl_map = function (value)
- if not vim.islist(value) then
- return value;
- end
+renderer.cache = {};
- local _o = {
- top = {},
- header = {},
- separator = {},
- row = {},
- bottom = {},
-
- align_left = nil,
- align_right = nil,
- align_center = {}
- };
-
- -- / - \ v
- -- > | < +
- -- \ _ / ^
- -- ' ' l r
-
- for p, part in ipairs(value) do
- if vim.list_contains({ 1, 2, 3, 4 }, p) then
- _o.top[p] = part;
-
- if p == 2 then
- _o.separator[2] = part;
- end
- elseif p == 5 then
- _o.separator[1] = part;
- elseif p == 6 then
- _o.header[1] = part;
- _o.header[2] = part;
- _o.header[3] = part;
-
- _o.row[1] = part;
- _o.row[2] = part;
- _o.row[3] = part;
- elseif p == 7 then
- _o.separator[3] = part;
- elseif p == 8 then
- _o.separator[4] = part;
- elseif vim.list_contains({ 9, 10, 11, 12 }, p) then
- _o.bottom[p - 8] = part;
- elseif vim.list_contains({ 13, 14 }, p) then
- _o.align_right[p - 12] = part;
- elseif p == 15 then
- _o.align_left = part;
- else
- _o.align_right = part;
- end
- end
-
- _o.overlap = _o.separator;
- return _o;
-end
-
-renderer.get_link_icon = function (config, text, icon)
- --- Pattern to detect emojis
- local emoji_pattern = "[\227\128\128-\227\128\191\226\128\147-\226\128\154\240\159\152\128-\240\159\152\191\240\160\128\128-\240\191\191\194\128-\244\143\191\191]";
-
- if config.__emoji_link_compatability ~= false and text:match("^" .. emoji_pattern) then
- return "";
- else
- return icon;
- end
-end
+renderer.__filter_cache = {
+ config = nil,
+ result = nil
+};
---- Returns a value with the specified index from entry
---- If index is nil then return the last value
---- If entry isn't a table then return it
+--- Maps a `class` to an option name.
+---@class mkv.option_maps
---
----@param entry any
----@param index number
----@return any
-local tbl_clamp = function (entry, index)
- if type(entry) ~= "table" then
- return entry;
- end
-
- if index <= #entry then
- return entry[index];
- end
-
- return entry[#entry];
-end
-
---- Gets the configuration of a link
----@param conf markview.links.config
----@param text string
----@return any
-local get_link_conf = function (conf, text)
- if not conf.custom then
- return conf;
- end
-
- local _t = conf;
-
- for _, tbl in ipairs(conf.custom) do
- --- This will be removed in the next update
- ---@diagnostic disable-next-line
- if tbl.match and string.match(text, tbl.match) then
- _t = vim.tbl_extend("force", _t, tbl);
- elseif tbl.match_string and string.match(text, tbl.match_string) then
- _t = vim.tbl_extend("force", _t, tbl);
- end
- end
-
- return _t;
-end
-
-local set_hl = function (hl)
- if type(hl) ~= "string" then
- return;
- end
-
- if vim.fn.hlexists("Markview" .. hl) == 1 then
- return "Markview" .. hl;
- elseif vim.fn.hlexists("Markview_" .. hl) == 1 then
- return "Markview_" .. hl;
- else
- return hl;
- end
-end
-
---- Checks if table border exists on a line
----@param extmark table
----@param config markview.conf.tables
----@return boolean
-local isTableBorder = function (extmark, config)
- if not extmark or (not config or config.enable == false) then
- return false;
- end
-
- local hl = config.parts.bottom;
-
- for i, v in ipairs(hl) do
- hl[i] = set_hl(v);
- end
-
- for _, item in ipairs(extmark[4].virt_text) do
- if vim.list_contains(hl, item[1]) then
- return true;
- end
- end
-
- return false;
-end
-
--- NOTE: Table cells with list chars in a link or image are overindented
-local sub_indent_chars = function(text)
- return text:gsub("[+-*]", " ")
-end
-
-local display_width = function (text, config)
- local d_width = vim.fn.strdisplaywidth(text);
- local inl_conf = config.inline_codes;
-
- local final_string = sub_indent_chars(text);
-
- ---@type markview.links.config?
- local lnk_conf = config.links ~= nil and config.links.hyperlinks or nil;
- ---@type markview.links.config?
- local int_lnk_conf = config.links ~= nil and config.links.internal_links or nil;
- ---@type markview.links.config?
- local img_conf = config.links ~= nil and config.links.images or nil;
- ---@type markview.links.config?
- local email_conf = config.links ~= nil and config.links.emails or nil;
-
-
- local html_conf = config.html;
-
- --- Without inline parser inline these syntaxes shouldn't occur
- if not parser_installed("markdown_inline") then
- goto noMdInline;
- end
-
- for escaped_char in final_string:gmatch("\\([\\%.%*%_%{%}%[%]%<%>%(%)%#%+%-%`%!%|%$])") do
- if config.escaped ~= nil and config.escaped.enable ~= false then
- final_string = final_string:gsub("\\" .. escaped_char, " ");
- d_width = d_width - 1;
- else
- final_string = final_string:gsub("\\" .. escaped_char, " ");
- end
- end
-
- for inline_code in final_string:gmatch("`([^`]+)`") do
- d_width = d_width - (vim.fn.strdisplaywidth("`" .. inline_code .. "`"));
-
- if inl_conf ~= nil and inl_conf.enable ~= false then
- d_width = d_width + vim.fn.strdisplaywidth(table.concat({
- inl_conf.corner_left or "",
- inl_conf.padding_left or "",
-
- inline_code or "",
-
- inl_conf.padding_right or "",
- inl_conf.corner_right or ""
- }));
-
- local escaped = inline_code:gsub("%p", "%%%1");
-
- final_string = final_string:gsub("`" .. escaped .. "`", table.concat({
- inl_conf.corner_left or "",
- inl_conf.padding_left or "",
-
- inline_code:gsub(".", "|"),
-
- inl_conf.padding_right or "",
- inl_conf.corner_right or ""
- }));
- end
- end
-
- --- Image link(normal)
- for link, address in final_string:gmatch("!%[([^%]]+)%]%(([^%)]+)%)") do
- d_width = d_width - vim.fn.strdisplaywidth("");
-
- if not img_conf or img_conf.enable == false then
- final_string = final_string:gsub("!%[" .. link .. "%]%(" .. address .. "%)", link);
- goto continue;
- end
-
- local _c = get_link_conf(img_conf, link);
-
- d_width = d_width + vim.fn.strdisplaywidth(table.concat({
- _c.corner_left or "",
- _c.padding_left or "",
- renderer.get_link_icon(img_conf, link, _c.icon or ""),
- _c.padding_right or "",
- _c.corner_right or ""
- }));
-
- final_string = final_string:gsub("!%[" .. link .. "%]%(" .. address .. "%)", table.concat({
- _c.corner_left or "",
- _c.padding_left or "",
- renderer.get_link_icon(img_conf, link, _c.icon or ""),
- link,
- _c.padding_right or "",
- _c.corner_right or ""
- }));
-
- ::continue::
- end
-
- -- Image link: labels
- for link, address in final_string:gmatch("!%[([^%]]+)%]%[([^%)]+)%]") do
- if not img_conf or img_conf.enable == false then
- d_width = d_width - vim.fn.strdisplaywidth("![]");
- final_string = final_string:gsub("!%[" .. link .. "%]%[" .. address .. "%]", link .. "|" .. address .. "|");
-
- goto continue;
- end
-
- d_width = d_width - vim.fn.strdisplaywidth("![" .. "][" .. address .. "]");
-
- local _c = get_link_conf(img_conf, link);
-
- d_width = d_width + vim.fn.strdisplaywidth(table.concat({
- _c.corner_left or "",
- _c.padding_left or "",
- renderer.get_link_icon(img_conf, link, _c.icon or ""),
- _c.padding_right or "",
- _c.corner_right or ""
- }));
-
- final_string = final_string:gsub("!%[" .. link .. "%]%[" .. address .. "%]", table.concat({
- _c.corner_left or "",
- _c.padding_left or "",
- renderer.get_link_icon(img_conf, link, _c.icon or ""),
- link,
- _c.padding_right or "",
- _c.corner_right or ""
- }));
-
- ::continue::
- end
-
- --- Internal links
- --- Alias isn't supported by the parser!
- for link in final_string:gmatch("%[%[(.-)%]%]") do
- d_width = d_width - vim.fn.strdisplaywidth("[[" .. "]]");
-
- local alias = link:match("^.-|(.+)$")
-
- if not int_lnk_conf or int_lnk_conf.enable == false then
- final_string = final_string:gsub("%[" .. link .. "%]", "");
- goto continue;
- end
-
- local cnf = alias and get_link_conf(int_lnk_conf, alias) or int_lnk_conf;
-
- d_width = d_width + vim.fn.strdisplaywidth(table.concat({
- cnf.corner_left or "",
- cnf.padding_left or "",
- renderer.get_link_icon(int_lnk_conf, link, cnf.icon or ""),
- cnf.padding_right or "",
- cnf.corner_right or ""
- }));
-
- final_string = final_string:gsub("%[%[" .. link .. "%]%]", table.concat({
- cnf.corner_left or "",
- cnf.padding_left or "",
- renderer.get_link_icon(int_lnk_conf, link, cnf.icon or ""),
- alias or link,
- cnf.padding_right or "",
- cnf.corner_right or ""
- }));
-
- ::continue::
- end
-
- -- Hyperlinks: normal
- for link, address in final_string:gmatch("%[([^%]]+)%]%(([^%)]+)%)") do
- d_width = d_width - vim.fn.strdisplaywidth("[" .. "](" .. address .. ")");
-
- if not lnk_conf or lnk_conf.enable == false then
- final_string = final_string:gsub("%[" .. link .. "%]%(" .. address .. "%)", link);
- goto continue;
- end
-
- local cnf = get_link_conf(lnk_conf, address);
-
- d_width = d_width + vim.fn.strdisplaywidth(table.concat({
- cnf.corner_left or "",
- cnf.padding_left or "",
- renderer.get_link_icon(lnk_conf, link, cnf.icon or ""),
- cnf.padding_right or "",
- cnf.corner_right or ""
- }));
-
- final_string = final_string:gsub("%[" .. link .. "%]%(" .. address .. "%)", table.concat({
- cnf.corner_left or "",
- cnf.padding_left or "",
- renderer.get_link_icon(lnk_conf, link, cnf.icon or ""),
- link,
- cnf.padding_right or "",
- cnf.corner_right or ""
- }));
-
- ::continue::
- end
-
- -- Hyperlink: full_reference_link
- for link, address in final_string:gmatch("%[(.-)%]%[(.-)%]") do
- d_width = d_width - vim.fn.strdisplaywidth("[" .. "][" .. address .. "]");
-
- if not lnk_conf or lnk_conf.enable == false then
- final_string = final_string:gsub("%[" .. link .. "%]%[" .. address .. "%]", link);
- goto continue;
+---@field html { [string]: string[] }
+---@field latex { [string]: string[] }
+---@field markdown { [string]: string[] }
+---@field markdown_inline { [string]: string[] }
+---@field typst { [string]: string[] }
+---@field yaml { [string]: string[] }
+renderer.option_maps = {
+ ---+${lua}
+
+ html = {
+ container_elements = { "html_container_element" },
+ headings = { "html_heading" },
+ void_elements = { "html_void_element" },
+ },
+ latex = {
+ blocks = { "latex_block" },
+ commands = { "latex_command" },
+ escapes = { "latex_escaped" },
+ fonts = { "latex_font" },
+ inlines = { "latex_inline" },
+ parenthesis = { "latex_parenthesis" },
+ subscripts = { "latex_subscript" },
+ superscripts = { "latex_superscript" },
+ symbols = { "latex_symbol" },
+ text = { "latex_text" },
+ },
+ markdown = {
+ block_quotes = { "markdown_block_quote" },
+ code_blocks = { "markdown_code_block" },
+ headings = { "markdown_atx_heading", "markdown_setext_heading" },
+ horizontal_rules = { "markdown_hr" },
+ list_items = { "markdown_list_item" },
+ metadata_minus = { "markdown_metadata_minus" },
+ metadata_plus = { "markdown_metadata_plus" },
+ tables = { "markdown_table" },
+ reference_definitions = { "markdown_link_ref_definition" },
+
+ checkboxes = { "markdown_checkbox" },
+ },
+ markdown_inline = {
+ checkboxes = { "inline_checkbox" },
+ inline_codes = { "inline_code_span" },
+ entities = { "inline_entity" },
+ escapes = { "inline_escaped" },
+ footnotes = { "inline_footnote" },
+ highlights = { "inline_highlight" },
+ block_references = { "inline_link_block_ref" },
+ embed_files = { "inline_embed_files" },
+ emails = { "inline_link_email" },
+ hyperlinks = { "inline_link_hyperlink", "inline_link_shortcut" },
+ images = { "inline_link_hyperlink" },
+ uri_autolinks = { "inline_link_uri_autolink" },
+ internal_links = { "inline_link_internal" },
+ },
+ typst = {
+ code_blocks = { "typst_code_block" },
+ code_spans = { "typst_code_span" },
+ escapes = { "typst_escaped" },
+ headings = { "typst_heading" },
+ labels = { "typst_label" },
+ list_items = { "typst_list_item" },
+ reference_links = { "typst_link_ref" },
+ url_links = { "typst_link_url" },
+ math_blocks = { "typst_math_blocks" },
+ math_spans = { "typst_math_spans" },
+ raw_blocks = { "typst_raw_block" },
+ raw_spans = { "typst_raw_span" },
+ subscripts = { "typst_subscript" },
+ superscripts = { "typst_superscript" },
+ symbols = { "typst_symbol" },
+ terms = { "typst_terms" },
+ },
+ yaml = {
+ properties = { "yaml_property" },
+ }
+ ---_
+};
+
+--- Creates node class filters for hybrid mode.
+---@param filter preview.ignore?
+---@return { [string]: string[] }
+local create_filter = function (filter)
+ ---+${lua}
+ local spec = require("markview.spec");
+
+ --- Ignore queries.
+ ---@type preview.ignore
+ local filters = filter or spec.get({ "preview", "ignore_previews" }, { fallback = {} });
+
+ --- To save time, do not recalculate these if the
+ --- configuration hasn't changed.
+ if vim.deep_equal(renderer.__filter_cache.config, filters) == true then
+ --- Configuration has most likely not changed.
+ --- Return the cached value.
+ return renderer.__filter_cache.result;
+ end
+
+ --- Resulting filter.
+ local _f = {};
+
+ --- Checks if a value is valid by matching all
+ --- the provided queries against it.
+ ---@param value string
+ ---@param queries string[]
+ ---@return boolean
+ local is_valid = function (value, queries)
+ ---+${lua}
+
+ for q, query in ipairs(queries or {}) do
+ --- Queries that were already passed.
+ local passed = vim.list_slice(queries, 0, q - 1);
+
+ if string.match(query, "^%!") then
+ if value == string.sub(query, 2) then
+ --- Part of negation query.
+ return false;
+ elseif vim.list_contains(passed, value) then
+ --- Already part of the query.
+ return true;
+ end
+ elseif value == query then
+ --- Valid value.
+ return true;
+ else
+ --- Invalid value.
+ return false;
+ end
end
- local cnf = get_link_conf(lnk_conf, address);
-
- d_width = d_width + vim.fn.strdisplaywidth(table.concat({
- cnf.corner_left or "",
- cnf.padding_left or "",
- renderer.get_link_icon(lnk_conf, link, cnf.icon or ""),
- cnf.padding_right or "",
- cnf.corner_right or ""
- }));
-
- final_string = final_string:gsub("%[" .. link .. "%]%[" .. address .. "%]", table.concat({
- cnf.corner_left or "",
- cnf.padding_left or "",
- renderer.get_link_icon(lnk_conf, link, cnf.icon or ""),
- link,
- cnf.padding_right or "",
- cnf.corner_right or ""
- }));
-
- ::continue::
- end
-
- for pattern in final_string:gmatch("%[([^%]]+)%]") do
- d_width = d_width - 3;
- final_string = final_string:gsub( "[" .. pattern .. "]", pattern);
+ --- All conditions matched!
+ return true;
+ ---_
end
- for str_a, internal, str_b in final_string:gmatch("([*]+)([^*]+)([*]+)") do
- local min_signs = vim.fn.strdisplaywidth(str_a) > vim.fn.strdisplaywidth(str_b) and vim.fn.strdisplaywidth(str_a) or vim.fn.strdisplaywidth(str_b);
+ --- Creates a list of valid options for {language}.
+ ---@param language string
+ ---@param options string[]
+ ---@return string[]
+ local function language_filter (language, options)
+ ---+${lua}
- local start_pos, _ = final_string:find("([*]+)[^*]+([*]+)");
+ ---@type string[] Filters for this language.
+ local queries = filters[language];
- local c_before = final_string:sub(start_pos - 1, start_pos - 1);
-
- -- Needs more flexibility
- if c_before == "[" or c_before == "`" then
- goto invalid
+ if vim.islist(queries) == false then
+ --- Filter is invalid.
+ return options;
+ elseif #queries == 0 then
+ --- Filter is empty.
+ return {};
end
- for s = 1, min_signs do
- local a = str_a:sub(s, s);
- local b = str_b:reverse():sub(s, s);
-
- if a == b then
- d_width = d_width - 2;
+ ---@type string[] Valid options.
+ local _m = {};
- final_string = final_string:gsub(a .. internal .. b, internal);
+ for _, item in ipairs(options) do
+ if is_valid(item, queries) == true then
+ table.insert(_m, item);
end
end
- ::invalid::
- end
-
- for username, domain, tdl in final_string:gmatch("<([%w._%+-]+)@([%w.-]+)%.([%w.-]+)>") do
- if not email_conf or email_conf.enable == false then
- break;
- end
-
- d_width = d_width - vim.fn.strdisplaywidth("<" .. ">");
-
- local _e = get_link_conf(email_conf, username .. "@" .. domain .. "." .. tdl);
-
- d_width = d_width + vim.fn.strdisplaywidth(table.concat({
- _e.corner_left or "",
- _e.padding_left or "",
- _e.icon or "",
- _e.padding_right or "",
- _e.corner_right or ""
- }));
-
- final_string = final_string:gsub("<" .. username .. "@" .. domain .. "." .. tdl .. ">", table.concat({
- _e.corner_left or "",
- _e.padding_left or "",
- _e.icon or "",
-
- username, "@", domain, ".", tdl,
-
- _e.padding_right or "",
- _e.corner_right or ""
- }));
+ return _m;
+ ---_
end
- ::noMdInline::
-
- --- Without HTML parser these syntaxes shouldn't occur
- if not parser_installed("html") then
- return d_width, vim.fn.strdisplaywidth(text), final_string;
- end
-
- for entity_name, semicolon in final_string:gmatch("&([%a%d]+)(;?)") do
- if not html_conf or html_conf.enable == false then
- break;
- elseif not html_conf.entities or html_conf.entities.enable == false then
- break;
- end
-
- local entity = html_renderer.get_entity(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.strdisplaywidth("&" .. 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.strdisplaywidth("&" .. entity_name);
- d_width = d_width + vim.fn.strdisplaywidth(entity);
+ --- Registers a new entry to {language}.
+ ---@param language string
+ ---@param classes string[]
+ local function register (language, classes)
+ ---+${lua}
+ if vim.islist(_f[language]) == false then
+ _f[language] = {};
end
- ::invalid::
- end
-
- return d_width, vim.fn.strdisplaywidth(text), final_string;
-end
-
-
---- Renderer for table headers
----@param buffer integer
----@param content table
----@param config_table markview.configuration
-local table_header = function (buffer, content, config_table)
- local tbl_conf = config_table.tables;
-
- if not tbl_conf.parts or (not tbl_conf.parts.header or not tbl_conf.parts.top) then
- return;
- end
-
- local top = tbl_conf.parts.top;
- local header = tbl_conf.parts.header;
-
- local top_hl = tbl_conf.hls.top;
- local header_hl = tbl_conf.hls.header;
-
- local row_start = content.__r_start or content.row_start;
- local col_start = content.col_start;
-
- local curr_col = 0;
- local curr_tbl_col = 1;
-
- local virt_txt = {};
-
- local above_line = vim.api.nvim_buf_get_lines(buffer, row_start - 1, row_start, false);
- local start_line = vim.api.nvim_buf_get_lines(buffer, row_start, row_start + 1, false);
-
- --- If a table border is on the current line
- --- we should get it here
- local current = vim.api.nvim_buf_get_extmarks(buffer,
- renderer.namespace,
- { row_start, math.min(col_start, #start_line[1]) },
- { row_start, math.min(col_start, #start_line[1]) - 1 },
- { details = true }
- )[1];
-
- -- If there's a table border already on the line
- -- delete it
- if above_line[1] then
- local prev = vim.api.nvim_buf_get_extmarks(buffer,
- renderer.namespace,
- { row_start - 1, math.min(col_start, #above_line[1]) },
- { row_start - 1, math.min(col_start, #above_line[1]) - 1 },
- { details = true }
- )[1];
-
- -- If there's a table border already on the previous line
- -- delete it
- if isTableBorder(prev, tbl_conf) then
- vim.api.nvim_buf_del_extmark(buffer, renderer.namespace, prev[1]);
-
- if tbl_conf.use_virt_lines == false then
- top = tbl_conf.parts.overlap or tbl_conf.parts.separator;
- top_hl = tbl_conf.hls.overlap or tbl_conf.hls.separator;
+ for _, class in ipairs(classes or {}) do
+ if type(class) == "string" and vim.list_contains(_f[language], class) == false then
+ table.insert(_f[language], class);
end
- -- If there's a table border already on the current line
- -- delete it
- elseif isTableBorder(current, tbl_conf) then
- vim.api.nvim_buf_del_extmark(buffer, renderer.namespace, current[1]);
end
+ ---_
end
- if content.content_positions and content.content_positions[1] then
- col_start = content.content_positions[1].col_start;
- end
-
- for index, col in ipairs(content.rows[1]) do
- if index == 1 then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { header[1], set_hl(top_hl[1]) }
- },
-
- end_col = col_start + 1,
- conceal = ""
- });
-
- table.insert(virt_txt, { top[1], set_hl(top_hl[1]) })
- curr_col = curr_col + 1
- elseif index == #content.rows[1] then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { header[3], set_hl(header_hl[3]) }
- },
-
- end_col = col_start + curr_col + 1,
- conceal = ""
- });
-
- table.insert(virt_txt, { top[3], set_hl(top_hl[3]) })
-
- if tbl_conf.block_decorator ~= false and config_table.tables.use_virt_lines == true then
- -- Add extra spaces to match the tables position
- if content.content_positions and content.content_positions[1] then
- table.insert(virt_txt, 1, { string.rep(" ", content.content_positions[1].col_start) })
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, 0, {
- virt_lines_above = true,
- virt_lines = {
- virt_txt
- }
- });
- elseif tbl_conf.block_decorator ~= false and row_start > 0 then
- if not above_line[1] then
- goto noAboveLine;
- elseif isTableBorder(current, tbl_conf) then
- goto noAboveLine;
- end
-
- if vim.fn.strchars(above_line[1]) < col_start then
- table.insert(virt_txt, 1, { string.rep(" ", col_start - vim.fn.strchars(above_line[1])) })
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start - 1, math.min(col_start, #above_line[1]), {
- virt_text_pos = "inline",
- virt_text = virt_txt
- });
-
- ::noAboveLine::
- end
-
- curr_col = curr_col + 1
- elseif col == "|" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { header[2], set_hl(header_hl[2]) }
- },
-
- end_col = col_start + curr_col + 1,
- conceal = ""
- });
-
- table.insert(virt_txt, { top[4], set_hl(top_hl[4]) })
- curr_col = curr_col + 1
- else
- local width, actual_width = display_width(col, config_table);
- local align = content.content_alignments[curr_tbl_col];
-
- -- Extracted width of separator
- local tbl_col_width = math.max(content.col_widths[curr_tbl_col], tbl_conf.col_min_width or 0);
-
- -- The column number of headers must match the
- -- column number of separators
- --
- -- No need to add unnecessary condition
- if tbl_col_width then
- actual_width = math.min(math.max(actual_width, tbl_col_width), tbl_col_width);
- end
+ for language, maps in pairs(renderer.option_maps) do
+ --- Copy the values as we don't want to
+ --- accidentally modify the mapping table.
+ local valid_options = language_filter(language, vim.tbl_keys(maps));
- if width < actual_width then
- if align == "left" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col + #col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", (actual_width - width)) }
- }
- });
- elseif align == "right" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", (actual_width - width)) }
- }
- });
- else
- local before, after = math.floor((actual_width - width) / 2), math.ceil((actual_width - width) / 2);
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col + #col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", after) }
- }
- });
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", before) }
- }
- });
- end
- end
-
- table.insert(virt_txt, { string.rep(top[2], actual_width), set_hl(top_hl[2]) })
- curr_col = curr_col + #col;
- curr_tbl_col = curr_tbl_col + 1;
+ if vim.islist(_f[language]) == false then
+ _f[language] = {};
end
- end
-end
-
---- Renderer for table separator
----@param buffer integer
----@param content table
----@param user_config markview.configuration
----@param r_num integer
-local table_seperator = function (buffer, content, user_config, r_num)
- local tbl_conf = user_config.tables;
-
- if not tbl_conf.parts or not tbl_conf.parts.separator then
- return;
- end
-
- local separator = tbl_conf.parts.separator;
- local align_left = tbl_conf.parts.align_left;
- local align_right = tbl_conf.parts.align_right;
- local align_center = tbl_conf.parts.align_center;
- local separator_hl = tbl_conf.hls.separator;
- local align_left_hl = tbl_conf.hls.align_left;
- local align_right_hl = tbl_conf.hls.align_right;
- local align_center_hl = tbl_conf.hls.align_center;
-
- local row_start = content.__r_start or content.row_start;
- local col_start = content.col_start;
-
- local curr_col = 0;
- local curr_tbl_col = 1;
-
- if content.content_positions and content.content_positions[r_num] then
- col_start = content.content_positions[r_num].col_start;
- end
-
- for index, col in ipairs(content.rows[r_num]) do
- if index == 1 then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { separator[1], set_hl(separator_hl[1]) }
- },
-
- end_col = col_start + 1,
- conceal = ""
- });
-
- curr_col = curr_col + 1;
- elseif index == #content.rows[1] then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { separator[3], set_hl(separator_hl[3]) }
- },
-
- end_col = col_start + curr_col + 1,
- conceal = ""
- });
-
- curr_col = curr_col + 1;
- elseif col == "|" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { separator[4], set_hl(separator_hl[4]) }
- },
-
- end_col = col_start + curr_col + 1,
- conceal = ""
- });
-
- curr_col = curr_col + 1;
- else
- local align = content.content_alignments[curr_tbl_col];
- local tbl_col_width = math.max(content.col_widths[curr_tbl_col], tbl_conf.col_min_width or 0);
-
- if col:match(":") then
- if align == "left" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { align_left, set_hl(align_left_hl) },
- { string.rep(separator[2], tbl_col_width - 1), set_hl(separator_hl[2]) }
- },
-
- end_col = col_start + curr_col + vim.fn.strchars(col) + 1,
- conceal = ""
- });
- elseif align == "right" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(separator[2], tbl_col_width - 1), set_hl(separator_hl[2]) },
- { align_right, set_hl(align_right_hl) }
- },
-
- end_col = col_start + curr_col + vim.fn.strchars(col) + 1,
- conceal = ""
- });
- elseif align == "center" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { align_center[1], set_hl(align_center_hl[1]) },
- { string.rep(separator[2], tbl_col_width - 2), set_hl(separator_hl[2]) },
- { align_center[2], set_hl(align_center_hl[2]) }
- },
-
- end_col = col_start + curr_col + vim.fn.strchars(col) + 1,
- conceal = ""
- });
- end
- else
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + (r_num - 1), col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(separator[2], tbl_col_width), set_hl(separator_hl[4]) }
- },
-
- end_col = col_start + curr_col + vim.fn.strchars(col) + 1,
- conceal = ""
- });
- end
-
- curr_col = curr_col + vim.fn.strchars(col);
- curr_tbl_col = curr_tbl_col + 1;
+ for _, option in ipairs(valid_options) do
+ local nodes = maps[option];
+ register(language, nodes);
end
end
-end
---- Renderer for table footers
----@param buffer integer
----@param content table
----@param config_table markview.configuration
-local table_footer = function (buffer, content, config_table)
- local tbl_conf = config_table.tables;
-
- if not tbl_conf.parts or (not tbl_conf.parts.row or not tbl_conf.parts.bottom) then
- return;
- end
-
- local row = tbl_conf.parts.row;
- local bottom = tbl_conf.parts.bottom;
-
- local row_hl = tbl_conf.hls.row;
- local bottom_hl = tbl_conf.hls.bottom;
-
- local row_end = content.__r_end or content.row_end;
- local col_start = content.col_start;
-
- local curr_col = 0;
- local curr_tbl_col = 1;
-
- local virt_txt = {};
-
- if content.content_positions and content.content_positions[#content.content_positions] then
- col_start = content.content_positions[#content.content_positions].col_start;
- end
-
- for index, col in ipairs(content.rows[#content.rows]) do
- if index == 1 then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { row[1], set_hl(row_hl[1]) }
- },
-
- end_col = col_start + 1,
- conceal = ""
- });
-
- table.insert(virt_txt, { bottom[1], set_hl(bottom_hl[1]) })
- curr_col = curr_col + 1
- elseif index == #content.rows[#content.rows] then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { row[2], set_hl(row_hl[2]) }
- },
-
- end_col = col_start + curr_col + 1,
- conceal = ""
- });
-
- table.insert(virt_txt, { bottom[3], set_hl(bottom_hl[3]) })
-
- if tbl_conf.block_decorator ~= false and config_table.tables.use_virt_lines == true then
- if content.content_positions and content.content_positions[#content.content_positions] then
- table.insert(virt_txt, 1, { string.rep(" ", content.content_positions[#content.content_positions].col_start) })
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, 0, {
- virt_lines_above = false,
- virt_lines = {
- virt_txt
- }
- });
- elseif tbl_conf.block_decorator ~= false and content.row_start < vim.api.nvim_buf_line_count(buffer) then
- local below_line = vim.api.nvim_buf_get_lines(buffer, row_end, row_end + 1, false);
-
- if not below_line[1] then
- goto noBelowLine;
- end
-
- if vim.fn.strchars(below_line[1]) < col_start then
- table.insert(virt_txt, 1, { string.rep(" ", col_start - vim.fn.strchars(below_line[1])) })
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end, math.min(col_start, #below_line[1]), {
- virt_text_pos = "inline",
- virt_text = virt_txt
- });
-
- ::noBelowLine::
- end
+ --- Cache values.
+ renderer.__filter_cache.config = filters;
+ renderer.__filter_cache.result = _f;
- curr_col = curr_col + 1
- elseif col == "|" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { row[2], set_hl(row_hl[2]) }
- },
-
- end_col = col_start + curr_col + 1,
- conceal = ""
- });
-
- table.insert(virt_txt, { bottom[4], set_hl(bottom_hl[4]) })
- curr_col = curr_col + 1
- else
- local width, actual_width = display_width(col, config_table);
- local align = content.content_alignments[curr_tbl_col];
-
- -- Extracted width of separator
- local tbl_col_width = math.max(content.col_widths[curr_tbl_col], tbl_conf.col_min_width or 0);
-
- if #content.rows[#content.rows] == #content.rows[2] and tbl_col_width then
- actual_width = math.min(math.max(actual_width, tbl_col_width), tbl_col_width);
- end
-
- if width < actual_width then
- if align == "left" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col + #col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", (actual_width - width)) }
- }
- });
- elseif align == "right" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", (actual_width - width)) }
- }
- });
- else
- local before, after = math.floor((actual_width - width) / 2), math.ceil((actual_width - width) / 2);
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col + #col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", after) }
- }
- });
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_end - 1, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", before) }
- }
- });
- end
- end
-
- table.insert(virt_txt, { string.rep(bottom[2], actual_width), set_hl(bottom_hl[2]) })
- curr_col = curr_col + #col;
- curr_tbl_col = curr_tbl_col + 1;
- end
- end
+ return _f;
+ ---_
end
---- Renderer for table contents
----@param buffer integer
----@param content table
----@param config_table markview.configuration
----@param r_num integer
-local table_content = function (buffer, content, config_table, r_num)
- local tbl_conf = config_table.tables;
+--- Range modifiers for various nodes.
+---@type { [string]: fun(range: node.range): node.range }
+renderer.range_modifiers = {
+ ---+${lua}
+ markdown_atx_heading = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
- if not tbl_conf.parts or (not tbl_conf.parts.row or not tbl_conf.parts.bottom) then
- return;
- end
+ return _r;
+ end,
+ markdown_setext_heading = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
- local row = tbl_conf.parts.row;
- local row_hl = tbl_conf.hls.row;
+ return _r;
+ end,
+ markdown_code_block = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
- local row_start = content.__r_start or content.row_start;
- local col_start = content.col_start;
+ return _r;
+ end,
+ markdown_block_quote = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
- local curr_col = 0;
- local curr_tbl_col = 1;
+ return _r;
+ end,
+ markdown_hr = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
- if content.content_positions and content.content_positions[r_num] then
- col_start = content.content_positions[r_num].col_start;
- end
+ return _r;
+ end,
+ markdown_list_item = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
- for index, col in ipairs(content.rows[r_num]) do
- if index == 1 then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + r_num - 1, col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { row[1], set_hl(row_hl[1]) }
- },
-
- end_col = col_start + 1,
- conceal = ""
- });
-
- curr_col = curr_col + 1
- elseif index == #content.rows[1] then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + r_num - 1, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { row[3], set_hl(row_hl[3]) }
- },
-
- end_col = col_start + curr_col + 1,
- conceal = ""
- });
-
- curr_col = curr_col + 1
- elseif col == "|" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + r_num - 1, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { row[2], set_hl(row_hl[2]) }
- },
-
- end_col = col_start + curr_col + 1,
- conceal = ""
- });
-
- curr_col = curr_col + 1
- else
- local width, actual_width = display_width(col, config_table);
- local align = content.content_alignments[curr_tbl_col];
-
- -- Extracted width of separator
- local tbl_col_width = math.max(content.col_widths[curr_tbl_col], tbl_conf.col_min_width or 0);
-
- if #content.rows[r_num] == #content.rows[2] and tbl_col_width then
- actual_width = math.min(math.max(actual_width, tbl_col_width), tbl_col_width);
- end
-
- if width < actual_width then
- if align == "left" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + r_num - 1, col_start + curr_col + #col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", (actual_width - width)) }
- }
- });
- elseif align == "right" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + r_num - 1, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", (actual_width - width)) }
- }
- });
- else
- local before, after = math.floor((actual_width - width) / 2), math.ceil((actual_width - width) / 2);
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + r_num - 1, col_start + curr_col + #col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", after) }
- }
- });
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, row_start + r_num - 1, col_start + curr_col, {
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", before) }
- }
- });
- end
- end
-
- curr_col = curr_col + #col;
- curr_tbl_col = curr_tbl_col + 1;
- end
- end
-end
+ return _r;
+ end,
+ markdown_metadata_minus = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
-renderer.namespace = vim.api.nvim_create_namespace("markview");
-latex_renderer.set_namespace(renderer.namespace);
-html_renderer.set_namespace(renderer.namespace);
+ return _r;
+ end,
+ markdown_metadata_plus = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
-renderer.views = {};
+ return _r;
+ end,
+ markdown_table = function (range)
+ local _r = vim.deepcopy(range)
+ _r.row_end = _r.row_end - 1;
---- Renderer for custom headings
----@param buffer number
----@param content any
----@param config markview.conf.headings
-renderer.render_headings = function (buffer, content, config)
- if not config or config.enable == false then
- return;
+ return _r;
end
+ ---_
+};
- ---@type (markview.h.simple | markview.h.label | markview.h.icon)
- local conf = config["heading_" .. content.level] or {};
- local shift = config.shift_width or vim.bo[buffer].shiftwidth;
-
- -- Do not proceed if config doesn't exist for a heading
- if not conf then
- return;
+--- Fixes node ranges for `hybrid mode`.
+---@param class string
+---@param range node.range
+---@return node.range
+renderer.fix_range = function (class, range)
+ if renderer.range_modifiers[class] == nil then
+ return range;
end
- if conf.style == "simple" then
- -- Adds a simple background
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- line_hl_group = set_hl(conf.hl),
-
- hl_mode = "combine"
- });
- elseif conf.style == "label" then
- local conceal_start = string.match(content.line, "^[#]+(%s*)");
- local line_length = #content.line;
-
- local spaces = shift * (content.level - 1);
-
- if conf.align then
- if conf.align == "left" then
- spaces = 0;
- elseif conf.align == "center" then
- local win = utils.find_attached_wins(buffer)[1] or vim.api.nvim_get_current_win();
- local textoff = config.textoff or vim.fn.getwininfo(win)[1].textoff;
-
- local w = vim.api.nvim_win_get_width(win) - textoff;
-
- local t = vim.fn.strdisplaywidth(table.concat({
- conf.corner_left or "",
- conf.padding_left or "",
- conf.icon or "",
-
- content.title,
-
- conf.padding_right or "",
- conf.corner_right or "",
- }));
-
- spaces = math.floor((w - t) / 2);
- else
- local win = utils.find_attached_wins(buffer)[1] or vim.api.nvim_get_current_win();
- local textoff = config.textoff or vim.fn.getwininfo(win)[1].textoff;
-
- local w = vim.api.nvim_win_get_width(win) - textoff;
-
- local t = vim.fn.strdisplaywidth(table.concat({
- conf.corner_left or "",
- conf.padding_left or "",
- conf.icon or "",
-
- content.title,
-
- conf.padding_right or "",
- conf.corner_right or "",
- }));
-
- spaces = w - t;
- end
- end
-
- -- Heading rules
- -- 1. Must start at the first column
- -- 2. Must have 1 space between the marker and the title
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", spaces) },
-
- { conf.corner_left or "", set_hl(conf.corner_left_hl) or set_hl(conf.hl) },
- { conf.padding_left or "", set_hl(conf.padding_left_hl) or set_hl(conf.hl) },
- { conf.icon or "", set_hl(conf.icon_hl) or set_hl(conf.hl) }
- },
-
- sign_text = conf.sign, sign_hl_group = set_hl(conf.sign_hl),
- hl_mode = "combine",
-
- end_col = content.level + vim.fn.strchars(conceal_start),
- conceal = ""
- });
-
- vim.api.nvim_buf_add_highlight(buffer, renderer.namespace, set_hl(conf.hl), content.row_start, 0, line_length);
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, line_length, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "overlay",
- virt_text = {
- { conf.padding_right or "", set_hl(conf.padding_right_hl) or set_hl(conf.hl) },
- { conf.corner_right or "", set_hl(conf.corner_right_hl) or set_hl(conf.hl) }
- },
-
- hl_mode = "combine"
- });
- elseif conf.style == "icon" then
- local conceal_start = string.match(content.line, "^[#]+(%s*)");
-
- -- Heading rules
- -- 1. Must start at the first column
- -- 2. Must have 1 space between the marker and the title
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(conf.shift_char or " ", shift * (content.level - 1)), set_hl(conf.shift_hl) },
-
- { conf.icon or "", set_hl(conf.icon_hl) or set_hl(conf.hl) },
- },
-
- sign_text = conf.sign, sign_hl_group = set_hl(conf.sign_hl),
- line_hl_group = set_hl(conf.hl),
- hl_mode = "combine",
-
- end_col = content.level + vim.fn.strchars(conceal_start),
- conceal = ""
- });
- end
+ return renderer.range_modifiers[class](range);
end
---- Renders setext headings
----@param buffer integer
+--- Filters provided content.
+--- [Used for hybrid mode]
---@param content table
----@param config markview.conf.headings
-renderer.render_headings_s = function (buffer, content, config)
- if not config or config.enable == false then
- return;
- end
-
- ---@type markview.h.decorated | markview.h.simple
- local conf = content.marker:match("=") and config["setext_1"] or config["setext_2"];
-
- -- Do not proceed if setext headings don't have configuration
- if not conf then
- return;
- end
-
- if conf.style == "simple" then
- -- Adds a simple background
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- line_hl_group = set_hl(conf.hl),
-
- hl_mode = "combine",
- end_row = content.row_end - 1
- });
- elseif conf.style == "decorated" or conf.style == "github" then
- local mid = math.floor((content.row_end - content.row_start - 2) / 2);
-
- for i = 0, (content.row_end - content.row_start) - 1 do
- if i == mid then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + i, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { conf.icon or "", set_hl(conf.icon_hl or conf.hl) }
- },
-
- sign_text = conf.sign, sign_hl_group = set_hl(conf.sign_hl),
- line_hl_group = set_hl(conf.hl),
- hl_mode = "combine",
- });
- elseif i < (content.row_end - content.row_start) - 1 then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + i, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", vim.fn.strchars(conf.icon or "")), set_hl(conf.hl) }
- },
-
- line_hl_group = set_hl(conf.hl),
- hl_mode = "combine",
- });
- else
- local line = content.marker:match("=") and (conf.border or conf.line or "=") or (conf.border or conf.line or "-");
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + i, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "overlay",
- virt_text = {
- { string.rep(line, vim.o.columns), set_hl(conf.border_hl or conf.line_hl or conf.hl) }
- },
-
- line_hl_group = set_hl(conf.hl),
- hl_mode = "combine",
- });
- end
+---@param filter table?
+---@param clear [ integer, integer ]
+---@return table
+renderer.filter = function (content, filter, clear)
+ ---+${lua}
+
+ --- Checks if {pos} is inside of {range}.
+ ---@param range node.range
+ ---@param pos [ integer, integer ]
+ ---@return boolean
+ local within = function (range, pos)
+ ---+${lua}
+ if type(range) ~= "table" then
+ return false;
+ elseif type(range.row_start) ~= "number" or type(range.row_end) ~= "number" then
+ return false;
+ elseif vim.islist(pos) == false then
+ return false;
+ elseif type(pos[1]) ~= "number" or type(pos[2]) ~= "number" then
+ return false;
+ elseif pos[1] >= range.row_start and pos[2] <= range.row_end then
+ return true;
end
- end
-end
-
---- Renderer for custom code blocks
----@param buffer number
----@param content any
----@param config_table markview.conf.code_blocks
-renderer.render_code_blocks = function (buffer, content, config_table)
- if not config_table or config_table.enable == false then
- return;
- end
-
- local language = languages.get_ft(content.language);
- local icon, hl, sign_hl = renderer.get_icon(language, config_table);
- local sign = icon;
-
- icon = icon or "";
- if icon ~= "" and not icon:match("(%s)$") then
- icon = icon .. " ";
+ return false;
+ ---_
end
- icon = " " .. icon;
-
- local languageName;
+ ---@type [ integer, integer ] Range to clear.
+ local clear_range = vim.deepcopy(clear);
- if config_table.language_names ~= nil then
- for match, replace in pairs(config_table.language_names) do
- if language == match then
- languageName = replace;
- goto nameFound;
- end
+ --- Updates the range to clear.
+ ---@param new [ integer, integer ]
+ local range_update = function (new)
+ ---+${lua}
+ if new[1] <= clear_range[1] and new[2] >= clear_range[2] then
+ clear_range[1] = new[1];
+ clear_range[2] = new[2];
end
+ ---_
end
- languageName = languages.get_name(language)
- ::nameFound::
-
- if config_table.style == "simple" then
- if config_table.language_direction == nil or config_table.language_direction == "left" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { icon, set_hl(hl or config_table.hl) },
- { languageName .. " ", set_hl(config_table.language_hl or hl or config_table.hl) },
- },
-
- line_hl_group = set_hl(config_table.info_hl or config_table.hl),
-
- sign_text = config_table.sign == true and sign or nil,
- sign_hl_group = set_hl(config_table.sign_hl or sign_hl or hl),
- });
- elseif config_table.language_direction == "right" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + vim.fn.strchars(content.info_string), {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "right_align",
- virt_text = {
- { " ", set_hl(config_table.hl) },
- { icon, set_hl(hl or config_table.hl) },
- { languageName .. " ", set_hl(config_table.language_hl or hl or config_table.hl) },
- { " ", set_hl(config_table.hl) },
- },
-
- line_hl_group = set_hl(config_table.info_hl or config_table.hl),
-
- sign_text = config_table.sign == true and sign or nil,
- sign_hl_group = set_hl(config_table.sign_hl or sign_hl or hl)
- });
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + 1, content.col_start, {
- line_hl_group = set_hl(config_table.hl),
-
- -- NOTE: The node actually ends in the next line after the code block
- end_row = content.row_end - 1, end_col = content.col_end
- });
- elseif config_table.style == "minimal" or config_table.style == "block" or config_table.style == "language" then
- local block_length = content.largest_line;
-
- if type(config_table.min_width) == "number" and config_table.min_width > block_length then
- block_length = config_table.min_width
- end
-
- local lang_width = vim.fn.strchars(icon .. languageName .. " ");
-
- if config_table.language_direction == nil or config_table.language_direction == "left" then
- local rendered_info = vim.fn.strcharpart(content.block_info or "", 0, block_length - lang_width + ((config_table.pad_amount or 1) * 2) - 4);
-
- if content.block_info ~= "" and vim.fn.strchars(content.block_info) > (block_length - lang_width - ((content.pad_amount or 1) * 2)) then
- rendered_info = rendered_info .. "...";
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- end_col = content.col_start + vim.fn.strchars(content.info_string),
- conceal = ""
- });
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + vim.fn.strlen(content.language), {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { icon, set_hl(hl or config_table.hl) },
- { languageName .. " ", set_hl(config_table.language_hl or hl or config_table.hl) },
- { string.rep(config_table.pad_char or " ", block_length - lang_width - 1 - vim.fn.strchars(rendered_info) + ((config_table.pad_amount or 1) * 2)), set_hl(config_table.hl) },
- { rendered_info, set_hl(config_table.info_hl or config_table.hl) },
- { config_table.pad_char or " ", set_hl(config_table.hl) },
- },
-
- sign_text = config_table.sign == true and sign or nil,
- sign_hl_group = set_hl(config_table.sign_hl or sign_hl or hl),
- });
- elseif config_table.language_direction == "right" then
- local rendered_info = vim.fn.strcharpart(content.block_info or "", 0, block_length - lang_width + ((config_table.pad_amount or 1) * 2) - 4);
-
- if content.block_info ~= "" and vim.fn.strchars(content.block_info) > (block_length - lang_width - ((content.pad_amount or 1) * 2)) then
- rendered_info = rendered_info .. "...";
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
+ --- Node filters.
+ ---@type preview.ignore
+ local result_filters = create_filter(filter);
- end_col = content.col_start + vim.fn.strchars(content.info_string),
- conceal = ""
- });
+ ---@type { [string]: table }
+ local indexes = {};
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + vim.fn.strchars(content.info_string), {
- undo_restore = false, invalidate = true,
+ --- Create a range to clear.
+ for lang, items in pairs(content) do
+ ---+${lua}
- virt_text_pos = "inline",
- virt_text = {
- { rendered_info, set_hl(config_table.info_hl or config_table.hl) },
- { string.rep(config_table.pad_char or " ", block_length - lang_width - vim.fn.strchars(rendered_info) + ((config_table.pad_amount or 1) * 2)), set_hl(config_table.hl) },
- { icon, set_hl(hl or config_table.hl) },
- { languageName .. " ", set_hl(config_table.language_hl or hl or config_table.hl) },
- },
+ --- Filter for this language.
+ ---@type string[]?
+ local lang_filter = result_filters[lang];
- sign_text = config_table.sign == true and sign or nil,
- sign_hl_group = set_hl(config_table.sign_hl or sign_hl or hl)
- });
+ if lang_filter == nil then
+ goto continue;
end
- -- The text on the final line
- -- We need to get the tail section to see if it contains ```
- local block_end_line = vim.api.nvim_buf_get_lines(buffer, content.row_end - 1, content.row_end, false)[1];
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end - 1, vim.fn.strchars(block_end_line or ""), {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(config_table.pad_char or " ", (block_length) + ((config_table.pad_amount or 1) * 2)), set_hl(config_table.hl) },
- },
-
- hl_mode = "combine",
- });
-
- -- NOTE: The last line with ``` doesn't need this so we don't add it to that line
- for line, text in ipairs(content.lines) do
- -- NOTE: Nested code blocks have a different start position
- local length = content.line_lengths[line] - content.col_start;
- local position = #text;
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + line, math.min(content.col_start, position), {
- undo_restore = false, invalidate = true,
-
- hl_group = set_hl(config_table.hl),
-
- end_row = content.row_start + line,
- end_col = #text,
- });
+ indexes[lang] = {};
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + line, position, {
- undo_restore = false, invalidate = true,
+ for n, node in ipairs(items) do
+ if vim.list_contains(lang_filter, node.class) then
+ local range = renderer.fix_range(node.class, node.range);
+ table.insert(indexes[lang], { n, range, node.class });
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(config_table.pad_char or " ", block_length - math.max(0, length)), set_hl(config_table.hl) },
- { string.rep(config_table.pad_char or " ", config_table.pad_amount or 1), set_hl(config_table.hl) }
- }
- })
-
- -- NOTE: If the line is smaller than the start position of the code block then subtract it
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + line, length < 0 and content.col_start + length or content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(config_table.pad_char or " ", text == "" and content.col_start or 0) },
- { string.rep(config_table.pad_char or " ", config_table.pad_amount or 1), set_hl(config_table.hl) }
- }
- })
- end
- end
-end
-
---- Renderer for the custom block quotes
----@param buffer integer
----@param content table
----@param config_table markview.conf.block_quotes
-renderer.render_block_quotes = function (buffer, content, config_table)
- local qt_config;
-
- if not config_table or config_table.enable == false then
- return;
- end
-
- if content.callout ~= nil then
- for _, callout in ipairs(config_table.callouts) do
- if type(callout.match_string) == "string" and string.upper(callout.match_string --[[@as string]]) == content.callout:upper() then
- qt_config = callout;
- elseif vim.islist(callout.match_string) then
- for _, alias in ipairs(callout.match_string --[[@as string[] ]]) do
- if type(alias) == "string" and alias:upper() == content.callout:upper() then
- qt_config = callout;
- end
+ if within(node.range, clear_range) == true then
+ range_update({ range.row_start, range.row_end });
end
end
end
- if qt_config == nil then
- qt_config = config_table.default;
- end
- else
- qt_config = config_table.default;
- end
-
- -- Config for a block quote is not available
- if not qt_config then
- return;
- end
-
- local list_clamp = function (val, index)
- if not vim.islist(val) then
- return set_hl(val);
- end
-
- return set_hl(val[math.min(#val, index)]);
- end
-
- if (qt_config.title == true or qt_config.custom_title) and content.title ~= "" then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { tbl_clamp(qt_config.border, 1), list_clamp(qt_config.hl or qt_config.border_hl, 1) },
- { " " },
- { qt_config.icon or qt_config.custom_icon, list_clamp(qt_config.preview_hl or qt_config.callout_preview_hl or qt_config.hl, 1) },
- },
-
- end_col = content.col_start + vim.fn.strdisplaywidth(">[!" .. content.callout .. "]"),
- conceal = ""
- });
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- hl_group = list_clamp(qt_config.hl or qt_config.preview_hl or qt_config.callout_preview_hl or qt_config.hl, 1),
- end_col = #content.lines[1],
- });
- elseif qt_config.preview ~= nil or qt_config.callout_preview ~= nil then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { tbl_clamp(qt_config.border, 1), list_clamp(qt_config.hl or qt_config.border_hl, 1) },
- { " " },
- { qt_config.preview or qt_config.callout_preview, list_clamp(qt_config.preview_hl or qt_config.hl or qt_config.callout_preview_hl, 1) },
- },
-
- end_col = content.line_width,
- conceal = ""
- });
- else
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { tbl_clamp(qt_config.border, 1), list_clamp(qt_config.hl or qt_config.border_hl, 1) },
- },
-
- end_col = content.col_start + vim.fn.strchars(tbl_clamp(qt_config.border or "", 1)),
- conceal = ""
- });
- end
-
- for line = 1, content.row_end - content.row_start - 1 do
- local end_col = content.col_start;
-
- -- NOTE: If the line is smaller than the border then use the lines width
- if vim.fn.strchars(tbl_clamp(qt_config.border, 1)) > vim.fn.strchars(content.lines[line]) then
- end_col = end_col + vim.fn.strchars(content.lines[line])
- else
- end_col = end_col + vim.fn.strchars(tbl_clamp(qt_config.border, 1));
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start + line, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { tbl_clamp(qt_config.border, line + 1), list_clamp(qt_config.hl or qt_config.border_hl, line + 1) }
- },
-
- end_col = end_col,
- conceal = "",
-
- hl_mode = "combine"
- });
+ ::continue::
+ ---_
end
-end
---- Renders custom horizontal rules
----@param buffer integer
----@param content table
----@param config_table markview.conf.hrs
-renderer.render_horizontal_rules = function (buffer, content, config_table)
- local virt_text = {};
+ --- Remove the nodes inside the `clear_range`.
+ for lang, references in pairs(indexes) do
+ ---+${lua}
- if not config_table or config_table.enable == false then
- return;
- end
+ --- Amount of nodes removed in this language.
+ --- Used for offsetting the index for later nodes.
+ local removed = 0;
- for _, part in ipairs(config_table.parts or {}) do
- if part.type == "repeating" then
- local repeat_time = 0;
+ for _, ref in ipairs(references) do
+ local range = ref[2];
+ -- vim.print(range.row_start .. ":" .. range.row_end)
- if type(part.repeat_amount) == "function" and pcall(part.repeat_amount --[[@as function]], buffer) then
- repeat_time = part.repeat_amount(buffer);
- elseif type(part.repeat_amount) == "number" then
- repeat_time = part.repeat_amount --[[@as number]];
+ if range.row_start >= clear_range[1] and range.row_end <= clear_range[2] then
+ table.remove(content[lang], ref[1] - removed);
+ removed = removed + 1;
end
-
- if part.direction == "left" or part.direction == nil then
- for r = 1, repeat_time do
- table.insert(virt_text, {
- tbl_clamp(part.text or "โ", r),
- set_hl(tbl_clamp(part.hl, r))
- })
- end
- else
- for r = 1, repeat_time do
- table.insert(virt_text, {
- -- NOTE: The value can't be 0
- tbl_clamp(part.text or "โ", (repeat_time - r) + 1),
- set_hl(tbl_clamp(part.hl, (repeat_time - r) + 1))
- })
- end
- end
-
- elseif part.type == "text" then
- table.insert(virt_text, {
- part.text, set_hl(part.hl)
- })
end
+ ---_
end
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- virt_text_pos = "overlay",
- virt_text = virt_text,
-
- end_col = vim.fn.strchars(content.text),
- conceal = ""
- });
+ return content;
+ ---_
end
---- Renderer for custom links
----@param buffer integer
----@param content table
----@param config_table markview.conf.links
-renderer.render_links = function (buffer, content, config_table)
- if not config_table or config_table.enable == false then
- return;
- elseif config_table and config_table.hyperlinks and config_table.hyperlinks.enable == false then
- return;
- end
-
- local lnk_conf = config_table.hyperlinks;
-
- for _, conf in ipairs(config_table.hyperlinks.custom or {}) do
- --- TODO, Remove this in the next update
- ---@diagnostic disable-next-line
- if conf.match and string.match(content.address or "", conf.match) then
- lnk_conf = vim.tbl_extend("force", lnk_conf or {}, conf);
- break;
- elseif conf.match_string and string.match(content.address or "", conf.match_string) then
- lnk_conf = vim.tbl_extend("force", lnk_conf or {}, conf);
- break;
- end
- end
-
- -- Do not render links with no config
- if not lnk_conf then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + 1, {
- virt_text_pos = "inline",
- virt_text = {
- { lnk_conf.corner_left or "", set_hl(lnk_conf.corner_left_hl) or set_hl(lnk_conf.hl) },
- { lnk_conf.padding_left or "", set_hl(lnk_conf.padding_left_hl) or set_hl(lnk_conf.hl) },
- { renderer.get_link_icon(lnk_conf, content.text, lnk_conf.icon or ""), set_hl(lnk_conf.icon_hl) or set_hl(lnk_conf.hl) },
- },
-
- end_col = content.col_start,
- conceal = ""
- });
-
- vim.api.nvim_buf_add_highlight(buffer, renderer.namespace, set_hl(lnk_conf.hl) or "", content.row_start, content.col_start, content.col_end);
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end, content.col_end, {
- virt_text_pos = "inline",
- virt_text = {
- { lnk_conf.padding_right or "", set_hl(lnk_conf.padding_right_hl) or set_hl(lnk_conf.hl) },
- { lnk_conf.corner_right or "", set_hl(lnk_conf.corner_right_hl) or set_hl(lnk_conf.hl) },
- },
-
- end_col = content.col_start,
- conceal = ""
- });
-end
-
---- Renderer for custom links
+--- Renders things
---@param buffer integer
----@param content table
----@param config_table markview.conf.links
-renderer.render_internal_links = function (buffer, content, config_table)
- if not config_table or config_table.enable == false then
- return;
- elseif config_table and config_table.internal_links and config_table.internal_links.enable == false then
- return;
- end
-
- local lnk_conf = config_table.internal_links;
-
- for _, conf in ipairs(config_table.internal_links.custom or {}) do
- --- TODO, Remove this in the next update
- ---@diagnostic disable-next-line
- if conf.match and string.match(content.alias or "", conf.match) then
- lnk_conf = vim.tbl_extend("force", lnk_conf or {}, conf);
- break;
- elseif conf.match_string and string.match(content.alias or "", conf.match_string) then
- lnk_conf = vim.tbl_extend("force", lnk_conf or {}, conf);
- break;
- end
- end
-
- -- Do not render links with no config
- if not lnk_conf then
- return;
- end
+renderer.render = function (buffer, parsed_content)
+ ---+${lua}
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start - 1, {
- virt_text_pos = "inline",
- virt_text = {
- { lnk_conf.corner_left or "", set_hl(lnk_conf.corner_left_hl) or set_hl(lnk_conf.hl) },
- { lnk_conf.padding_left or "", set_hl(lnk_conf.padding_left_hl) or set_hl(lnk_conf.hl) },
- { renderer.get_link_icon(lnk_conf, content.text, lnk_conf.icon or ""), set_hl(lnk_conf.icon_hl) or set_hl(lnk_conf.hl) },
- },
+ renderer.cache = {};
- end_col = content.alias and (content.col_end - (#content.alias + 1)) or (content.col_start + 1),
- conceal = ""
- });
-
- vim.api.nvim_buf_add_highlight(buffer, renderer.namespace, set_hl(lnk_conf.hl) or "", content.row_start, content.col_start, content.col_end);
+ ---+${lua, Announce start of rendering}
+ ---@type integer
+ local start = vim.uv.hrtime();
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end, content.col_end - 1, {
- virt_text_pos = "inline",
- virt_text = {
- { lnk_conf.padding_right or "", set_hl(lnk_conf.padding_right_hl) or set_hl(lnk_conf.hl) },
- { lnk_conf.corner_right or "", set_hl(lnk_conf.corner_right_hl) or set_hl(lnk_conf.hl) },
- },
-
- end_col = content.col_end + 1,
- conceal = ""
+ health.notify("trace", {
+ level = 1,
+ message = string.format("Rendering(main): %d", buffer)
});
-end
---- Renderer for custom emails
----@param buffer integer
----@param content table
----@param config_table markview.conf.links
-renderer.render_email_links = function (buffer, content, config_table)
- if not config_table or config_table.enable == false then
- return;
- elseif config_table and config_table.emails and config_table.emails.enable == false then
- return;
- end
+ health.__child_indent_in();
+ ---_
- local email_conf = config_table.emails;
-
- for _, conf in ipairs(config_table.emails.custom or {}) do
- --- TODO, Remove this in the next update
- ---@diagnostic disable-next-line
- if conf.match and string.match(content.address or "", conf.match) then
- email_conf = vim.tbl_extend("force", email_conf or {}, conf);
- break;
- elseif conf.match_string and string.match(content.address or "", conf.match_string) then
- email_conf = vim.tbl_extend("force", email_conf or {}, conf);
- break;
+ for lang, content in pairs(parsed_content) do
+ if renderer[lang] then
+ local c = renderer[lang].render(buffer, content);
+ renderer.cache = vim.tbl_extend("force", renderer.cache, c or {});
end
end
- if not email_conf then
- return;
- end
+ ---+${lua, Announce end of main render}
+ local post = vim.uv.hrtime();
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { email_conf.corner_left or "", set_hl(email_conf.corner_left_hl) or set_hl(email_conf.hl) },
- { email_conf.padding_left or "", set_hl(email_conf.padding_left_hl) or set_hl(email_conf.hl) },
- { email_conf.icon or "", set_hl(email_conf.icon_hl) or set_hl(email_conf.hl) },
- },
-
- end_col = content.col_start + 1,
- conceal = ""
+ health.notify("trace", {
+ level = 3,
+ message = string.format("Render(main): %dms", (post - start) / 1e6)
});
+ ---_
- vim.api.nvim_buf_add_highlight(buffer, renderer.namespace, set_hl(email_conf.hl) or "", content.row_start, content.col_start, content.col_end);
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end, content.col_end - 1, {
- virt_text_pos = "inline",
- virt_text = {
- { email_conf.padding_right or "", set_hl(email_conf.padding_right_hl) or set_hl(email_conf.hl) },
- { email_conf.corner_right or "", set_hl(email_conf.corner_right_hl) or set_hl(email_conf.hl) },
- },
-
- end_col = content.col_end,
- conceal = ""
- });
-end
-
---- Renderer for custom image links
----@param buffer number
----@param content any
----@param config_table markview.conf.links
-renderer.render_img_links = function (buffer, content, config_table)
- if not config_table or config_table.enable == false then
- return;
- elseif config_table and config_table.images and config_table.images.enable == false then
- return;
- end
-
- local img_conf = config_table.images;
-
- for _, conf in ipairs(config_table.images.custom or {}) do
- --- TODO, Remove this in the next update
- ---@diagnostic disable-next-line
- if conf.match and string.match(content.address or "", conf.match) then
- img_conf = vim.tbl_extend("force", img_conf or {}, conf);
- break;
- elseif conf.match_string and string.match(content.address or "", conf.match_string) then
- img_conf = vim.tbl_extend("force", img_conf or {}, conf);
- break;
+ for lang, content in pairs(renderer.cache) do
+ if renderer[lang] then
+ renderer[lang].post_render(buffer, content);
end
end
+ ---+${lua, Announce end of rendering}
+ local now = vim.uv.hrtime();
- if not img_conf then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + 1, {
- virt_text_pos = "inline",
- virt_text = {
- { img_conf.corner_left or "", set_hl(img_conf.corner_left_hl) or set_hl(img_conf.hl) },
- { img_conf.padding_left or "", set_hl(img_conf.padding_left_hl) or set_hl(img_conf.hl) },
- { renderer.get_link_icon(img_conf, content.text, img_conf.icon or ""), set_hl(img_conf.icon_hl) or set_hl(img_conf.hl) },
- },
-
- end_col = content.col_start,
- conceal = ""
- });
-
- vim.api.nvim_buf_add_highlight(buffer, renderer.namespace, set_hl(img_conf.hl) or "", content.row_start, content.col_start, content.col_end);
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_end, content.col_end - vim.fn.strchars(content.address), {
- virt_text_pos = "inline",
- virt_text = {
- { img_conf.padding_right or "", set_hl(img_conf.padding_right_hl) or set_hl(img_conf.hl) },
- { img_conf.corner_right or "", set_hl(img_conf.corner_right_hl) or set_hl(img_conf.hl) },
- },
-
- end_col = content.col_end,
- conceal = ""
- });
-end
-
---- Renderer for custom inline codes
----@param buffer integer
----@param content table
----@param config_table markview.conf.inline_codes
-renderer.render_inline_codes = function (buffer, content, config_table)
- if not config_table or config_table.enable == false then
- return;
- end
-
- -- NOTE: The ` are hidden by default
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start + 1, {
- virt_text_pos = "inline",
- virt_text = {
- { config_table.corner_left or "", set_hl(config_table.corner_left_hl) or set_hl(config_table.hl) },
- { config_table.padding_left or "", set_hl(config_table.padding_left_hl) or set_hl(config_table.hl) },
- },
+ --- Announce end of post rendering.
+ health.notify("trace", {
+ level = 3,
+ message = string.format("Render(post): %dms", (now - post) / 1e6)
});
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- hl_group = set_hl(config_table.hl),
- end_col = content.col_end
+ health.__child_indent_de();
+ health.notify("trace", {
+ level = 3,
+ message = string.format("Rendering(end, %dms): %d", (now - start) / 1e6, buffer)
});
+ ---_
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_end - 1, {
- virt_text_pos = "inline",
- virt_text = {
- { config_table.padding_right or "", set_hl(config_table.padding_right_hl) or set_hl(config_table.hl) },
- { config_table.corner_right or "", set_hl(config_table.corner_right_hl) or set_hl(config_table.hl) },
- },
- });
+ ---_
end
---- Renderer for custom image links
----@param buffer integer
----@param content table
----@param config_table markview.conf.list_items
-renderer.render_lists = function (buffer, content, config_table)
- if not config_table or config_table.enable == false then
- return;
- end
-
- local ls_conf = {};
-
- if string.match(content.marker_symbol, "-") then
- ls_conf = config_table.marker_minus or {};
- elseif string.match(content.marker_symbol, "+") then
- ls_conf = config_table.marker_plus or {};
- elseif string.match(content.marker_symbol, "*") then
- ls_conf = config_table.marker_star or {};
- elseif string.match(content.marker_symbol, "[%.]") then
- ls_conf = config_table.marker_dot or {};
- elseif string.match(content.marker_symbol, "[%)]") then
- ls_conf = config_table.marker_parenthesis or {};
- end
-
- -- Do not render list types with no configuration
- if not ls_conf then
- return;
- end
-
- local use_text = ls_conf.text or content.marker_symbol;
-
- if ls_conf.add_padding == true then
- local shift = config_table.shift_width or vim.bo[buffer].shiftwidth;
-
- for l, line in ipairs(content.list_lines) do
- local line_num = content.row_start + (l - 1);
- local before = content.spaces[l] or 0;
-
- if vim.list_contains(content.list_candidates, l) and l == 1 then
- local conceal_end = content.col_start + vim.fn.strchars(content.marker_symbol) - 1;
- local offset = 0;
-
- if content.marker_symbol:match("^%d+") then
- conceal_end = (content.starts[l] or 0) + vim.fn.strchars(content.list_lines[1]:match("^%s*"));
- use_text = "";
- end
-
- if content.is_checkbox == true then
- conceal_end = content.col_start + vim.fn.strchars(content.marker_symbol);
- use_text = "";
- end
-
- local level = math.floor(before / (config_table.indent_size or 2)) + 1;
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, line_num, content.starts[l] or 0, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", (level * shift) - offset) },
- { vim.trim(use_text), set_hl(ls_conf.hl) or "Special" }
- },
-
- end_col = conceal_end,
- conceal = ""
- })
- elseif vim.list_contains(content.list_candidates, l) then
- local line_len = vim.fn.strchars(line);
-
- local level = math.floor(before / (config_table.indent_size or 2)) + 1;
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, line_num, content.starts[l] or 0, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { string.rep(" ", level * shift) },
- { string.rep(" ", content.align_spaces[l] or 0) },
- },
-
- end_col = line_len < before and line_len + (content.align_spaces[l] or 0) or before + (content.align_spaces[l] or 0),
- conceal = ""
- })
- end
- end
- else
- local start = content.starts[1] or 0;
- local before = content.spaces[1] or 0;
-
- if content.is_checkbox == true then
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, start + before, {
- undo_restore = false, invalidate = true,
-
- end_col = start + before + vim.fn.strdisplaywidth(content.marker_symbol),
- conceal = ""
- });
- else
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, start + before, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "overlay",
- virt_text = {
- { vim.trim(use_text), set_hl(ls_conf.hl) or "Special" }
- }
- });
- end
- end
-end
-
---- Renderer for custom checkbox
----@param buffer number
----@param content any
----@param config_table markview.conf.checkboxes
-renderer.render_checkboxes = function (buffer, content, config_table)
- if not config_table or config_table.enable == false then
- return;
- end
-
- local chk_config = {};
-
- if content.state == "complete" then
- chk_config = config_table.checked;
- elseif content.state == "incomplete" then
- chk_config = config_table.unchecked;
- elseif vim.islist(config_table.custom) then
- for _, config in ipairs(config_table.custom) do
- ---@diagnostic disable-next-line
- if content.state == config.match then
- chk_config = config;
- elseif content.state == config.match_string then
- chk_config = config;
- end
- end
- end
-
- if not chk_config or type(chk_config.text) ~= "string" then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- undo_restore = false, invalidate = true,
-
- virt_text_pos = "inline",
- virt_text = {
- { chk_config.text, set_hl(chk_config.hl) }
- },
-
- end_col = content.col_end,
- conceal = "",
+renderer.clear = function (buffer, from, to)
+ local langs = { "html", "latex", "markdown", "markdown_inline", "typst", "yaml" };
+ local start = vim.uv.hrtime();
- hl_mode = "combine"
+ ---+${lua, Announce start of clearing}
+ health.notify("trace", {
+ level = 1,
+ message = string.format("Clearing: %d", buffer)
});
+ health.__child_indent_in();
+ ---_
- if not chk_config.scope_hl or not content.list_item then
- return;
- end
-
- for l = content.list_item.row_start, content.list_item.row_end - 1 do
- local col_start = content.col_start;
-
- if l == content.list_item.row_start then
- col_start = content.col_end + 1;
+ for _, lang in ipairs(langs) do
+ if renderer[lang] then
+ renderer[lang].clear(buffer, from, to);
end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, l, col_start, {
- undo_restore = false, invalidate = true,
-
- end_col = #content.list_item.list_lines[l - content.list_item.row_start + 1],
-
- hl_group = chk_config.scope_hl,
- });
end
-end
---- Renderer for custom table
----@param buffer number
----@param content any
----@param user_config markview.configuration
-renderer.render_tables = function (buffer, content, user_config)
- if not user_config.tables or user_config.tables.enable == false then
- return;
- end
+ ---+${lua, Announce end of clearing}
+ local now = vim.uv.hrtime();
- user_config.tables.parts = tbl_map(user_config.tables.parts or user_config.tables.text);
- user_config.tables.hls = tbl_map(user_config.tables.hls or user_config.tables.hl);
-
- for row_number, _ in ipairs(content.rows) do
- if content.row_type[row_number] == "header" then
- pcall(table_header, buffer, content, user_config);
- elseif content.row_type[row_number] == "separator" then
- pcall(table_seperator, buffer, content, user_config, row_number)
- elseif content.row_type[row_number] == "content" and row_number == #content.rows then
- pcall(table_footer, buffer, content, user_config)
- else
- pcall(table_content, buffer, content, user_config, row_number)
- end
- end
-end
-
---- Renders escaped characters
----@param buffer integer
----@param content table
----@param user_config { enable: boolean }
-renderer.render_escaped = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- end_col = content.col_start + #"\\",
- conceal = ""
+ health.__child_indent_de();
+ health.notify("trace", {
+ level = 3,
+ message = string.format("Clearing(end, %dms): %d", (now - start) / 1e6, buffer)
});
+ ---_
end
---- Footnote renderer
----@param buffer integer
----@param content table
----@param user_config markview.conf.footnotes
-renderer.render_footnotes = function (buffer, content, user_config)
- if not user_config or user_config.enable == false then
- return;
- end
+renderer.range = function (content)
+ local _f, _t = nil, nil;
+ local range_processoer = {
+ ["markdown_table"] = function (range)
+ local use_virt = require("markview.spec").get({ "markdown", "tables", "use_virt_lines" }, { fallback = false });
- local _o = content.text:match("%^(.+)$");
-
- if user_config.superscript ~= false and _o:match("^([%s%a%d%(%)%+%-%=]+)$") then
- local tmp = "";
-
- for letter in _o:gmatch(".") do
- tmp = tmp .. latex_renderer.superscripts[letter];
- end
-
- _o = tmp;
- end
-
- vim.api.nvim_buf_set_extmark(buffer, renderer.namespace, content.row_start, content.col_start, {
- virt_text_pos = "inline",
- virt_text = {
- { _o, set_hl(user_config.hl) }
- },
-
- end_col = content.col_end,
- conceal = ""
- });
-end
+ if use_virt ~= true then
+ range.row_start = range.row_start - 1;
+ range.row_end = range.row_end + 1;
+ end
---- Renders things
----@param buffer integer
----@param parsed_content table[]
----@param config_table markview.configuration
----@param conceal_start? integer
----@param conceal_stop? integer
-renderer.render = function (buffer, parsed_content, config_table, conceal_start, conceal_stop)
- for _, content in ipairs(parsed_content) do
- local type = content.type;
- local fold_closed = vim.fn.foldclosed(content.row_start + 1);
-
- if fold_closed ~= -1 then
- goto extmark_skipped;
+ return range;
end
+ }
- -- Unlike `conceal_start`, `conceal_stop` is 1-indexed
- -- Do not render things inside the un-conceal range
- if conceal_start and conceal_stop and content.row_start >= conceal_start and content.row_end <= (conceal_stop - 1) then
- goto extmark_skipped;
- end
+ for _, lang in pairs(content) do
+ for _, item in ipairs(lang) do
+ local range = vim.deepcopy(item.range);
- if type == "heading_s" then
- pcall(renderer.render_headings_s, buffer, content, config_table.headings);
- elseif type == "heading" then
- pcall(renderer.render_headings, buffer, content, config_table.headings)
- elseif type == "code_block" then
- pcall(renderer.render_code_blocks, buffer, content, config_table.code_blocks)
- elseif type == "block_quote" then
- pcall(renderer.render_block_quotes, buffer, content, config_table.block_quotes);
- elseif type == "horizontal_rule" then
- pcall(renderer.render_horizontal_rules, buffer, content, config_table.horizontal_rules);
- elseif type == "inline_code" then
- pcall(renderer.render_inline_codes, buffer, content, config_table.inline_codes)
- elseif type == "list_item" then
- 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 == "escaped" then
- pcall(renderer.render_escaped, buffer, content, config_table.escaped);
- elseif type:match("^link_") then
- local link_type = type:gsub("^link_", "");
-
- if link_type == "hyperlink" then
- pcall(renderer.render_links, buffer, content, config_table.links);
- elseif link_type == "internal" then
- pcall(renderer.render_internal_links, buffer, content, config_table.links);
- elseif link_type == "image" then
- pcall(renderer.render_img_links, buffer, content, config_table.links);
- elseif link_type == "email" then
- pcall(renderer.render_email_links, buffer, content, config_table.links);
- elseif link_type == "footnote" then
- pcall(renderer.render_footnotes, buffer, content, config_table.footnotes);
+ -- Change the range when specific options
+ -- are set.
+ if range_processoer[item.class] then
+ range = range_processoer[item.class](range);
end
- elseif type:match("^html_") then
- pcall(html_renderer.render, type, buffer, content, config_table);
- elseif type:match("^(latex_)") then
- pcall(latex_renderer.render, type, buffer, content, config_table);
- end
- ::extmark_skipped::
- end
-end
-
---- Clears a namespace within the range in a buffer
----@param buffer integer
----@param from? integer
----@param to? integer
-renderer.clear = function (buffer, from, to)
- vim.api.nvim_buf_clear_namespace(buffer, renderer.namespace, from or 0, to or -1)
-end
-
-renderer.get_content_range = function (parsed_content)
- local max_range = { nil, nil };
-
- for _, content in ipairs(parsed_content) do
- if not max_range[1] or (content.row_start) < max_range[1] then
- max_range[1] = content.row_start;
- end
+ if not _f or item.range.row_start < _f then
+ _f = item.range.row_start;
+ end
- if not max_range[2] or (content.row_end) > max_range[2] then
- max_range[2] = content.row_end;
+ if not _t or item.range.row_end > _t then
+ _t = item.range.row_end;
+ end
end
end
- if not max_range[1] or not max_range[2] then
- return;
- end
-
- if max_range[1] == max_range[2] then
- max_range[2] = max_range[2] + 1;
- end
-
- return max_range;
+ return _f, _t;
end
return renderer;
diff --git a/lua/markview/renderers/html.lua b/lua/markview/renderers/html.lua
new file mode 100644
index 0000000..329b5be
--- /dev/null
+++ b/lua/markview/renderers/html.lua
@@ -0,0 +1,233 @@
+local html = {};
+
+local utils = require("markview.utils");
+local spec = require("markview.spec");
+
+html.ns = vim.api.nvim_create_namespace("markview/html");
+
+--- Renders container elements
+---@param buffer integer
+---@param item __html.container_elements
+html.container_element = function (buffer, item)
+ ---+${func}
+
+ ---@type html.container_elements?
+ local main_config = spec.get({ "html", "container_elements" }, { fallback = nil });
+
+ if not main_config then
+ return;
+ end
+
+ ---@type container_elements.opts?
+ local config = utils.match(main_config, item.name, {
+ ignore_keys = { "enable" },
+ default = false,
+ eval_args = { buffer, item }
+ });
+
+ if not config then
+ return;
+ end
+
+ if item.opening_tag and config.on_opening_tag then
+ local open_conf = spec.get({ "on_opening_tag" }, { source = config, eval_args = { item.opening_tag } });
+ local range = item.opening_tag.range;
+
+ if pcall(config.opening_tag_offset, range) then
+ range = config.opening_tag_offset(range);
+ end
+
+
+ vim.api.nvim_buf_set_extmark(
+ buffer,
+ html.ns,
+ range[1],
+ range[2],
+ vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+
+ end_row = range[3],
+ end_col = range[4]
+ }, open_conf)
+ )
+ end
+
+ if config.on_node then
+ local node_conf = spec.get({ "on_node" }, { source = config, eval_args = { item } });
+ local range = {
+ item.range.row_start, item.range.col_start,
+ item.range.row_end, item.range.col_end
+ };
+
+ if pcall(config.node_offset, range) then
+ range = config.node_offset(range);
+ end
+
+ vim.api.nvim_buf_set_extmark(
+ buffer,
+ html.ns,
+ range[1],
+ range[2],
+ vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+
+ end_row = range[3],
+ end_col = range[4]
+ }, node_conf)
+ )
+ end
+
+ if item.closing_tag and config.on_closing_tag then
+ local close_conf = spec.get({ "on_closing_tag" }, { source = config, eval_args = { item.closing_tag } });
+ local range = item.closing_tag.range;
+
+ if pcall(config.closing_tag_offset, range) then
+ range = config.closing_tag_offset(range);
+ end
+
+ vim.api.nvim_buf_set_extmark(
+ buffer,
+ html.ns,
+ range[1],
+ range[2],
+ vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+
+ end_row = range[3],
+ end_col = range[4]
+ }, close_conf)
+ )
+ end
+ ---_
+end
+
+--- Renders headings.
+---@param buffer integer
+---@param item __html.headings
+html.heading = function (buffer, item)
+ ---+${func}
+
+ ---@type html.headings
+ local main_config = spec.get({ "html", "headings" }, { fallback = nil });
+
+ if not main_config then
+ return;
+ elseif not spec.get({ "heading_" .. item.level }, { source = main_config }) then
+ return;
+ end
+
+ local range = item.range;
+
+ ---@type config.extmark
+ local config = spec.get({ "heading_" .. item.level }, { source = main_config, eval_args = { buffer, item } });
+
+ vim.api.nvim_buf_set_extmark(
+ buffer,
+ html.ns,
+
+ range.row_start,
+ range.col_start,
+ vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+
+ end_row = range.row_end,
+ end_col = range.col_end,
+ }, config)
+ );
+ ---_
+end
+
+--- Renders void elements
+---@param buffer integer
+---@param item __html.void_elements
+html.void_element = function (buffer, item)
+ ---+${func}
+
+ ---@type html.void_elements?
+ local main_config = spec.get({ "html", "void_elements" }, { fallback = nil });
+
+ if not main_config then
+ return;
+ end
+
+ ---@type void_elements.opts
+ local config = utils.match(main_config, item.name, { default = false, eval_args = { buffer, item } })
+
+ if not main_config then
+ return;
+ end
+
+ if config.on_node then
+ local node_conf = spec.get({ "on_node" }, { source = config, eval_args = { item } });
+ local range = {
+ item.range.row_start, item.range.col_start,
+ item.range.row_end, item.range.col_end
+ };
+
+ if pcall(config.node_offset, range) then
+ range = config.node_offset(range);
+ end
+
+ vim.api.nvim_buf_set_extmark(
+ buffer,
+ html.ns,
+ range[1],
+ range[2],
+ vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+
+ end_row = range[3],
+ end_col = range[4]
+ }, node_conf)
+ )
+ end
+ ---_
+end
+
+--- Renders HTML elements
+---@param buffer integer
+---@param content table[]
+html.render = function (buffer, content)
+ ---+${func}
+ html.cache = {
+ font_regions = {},
+ style_regions = {
+ superscripts = {},
+ subscripts = {}
+ },
+ };
+
+ local custom = spec.get({ "renderers" }, { fallback = {} });
+
+ for _, item in ipairs(content or {}) do
+ local success, err;
+
+ if custom[item.class] then
+ success, err = pcall(custom[item.class], html.ns, buffer, item);
+ else
+ success, err = pcall(html[item.class:gsub("^html_", "")], buffer, item);
+ end
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = {
+ { " r/html.lua: ", "DiagnosticVirtualTextInfo" },
+ { " " },
+ { err, "DiagnosticError" }
+ }
+ });
+ end
+ end
+ ---_
+end
+
+--- Clears decorations of HTML elements
+---@param buffer integer
+---@param from integer
+---@param to integer
+html.clear = function (buffer, from, to)
+ vim.api.nvim_buf_clear_namespace(buffer, html.ns, from or 0, to or -1);
+end
+
+return html;
diff --git a/lua/markview/renderers/latex.lua b/lua/markview/renderers/latex.lua
new file mode 100644
index 0000000..d7f5900
--- /dev/null
+++ b/lua/markview/renderers/latex.lua
@@ -0,0 +1,830 @@
+local latex = {};
+
+local symbols = require("markview.symbols");
+local spec = require("markview.spec");
+local utils = require("markview.utils");
+
+--- Cached values.
+---@type __latex.cache
+latex.cache = {
+ font_regions = {},
+ style_regions = {
+ superscripts = {},
+ subscripts = {}
+ },
+};
+
+--- Namespace for LaTeX previews.
+---@type integer
+latex.ns = vim.api.nvim_create_namespace("markview/latex");
+
+---@param buffer integer
+---@param item __latex.blocks
+latex.block = function (buffer, item)
+ ---+${func}
+ local range = item.range;
+
+ ---@type latex.blocks_static?
+ local config = spec.get({ "latex", "blocks" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #(item.marker or "$$"),
+ conceal = "",
+
+ virt_text_pos = "right_align",
+ virt_text = { { config.text or "", utils.set_hl(config.text_hl or config.hl) } },
+
+ hl_mode = "combine",
+ line_hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_end, math.max(0, range.col_end - #(item.marker or "$$")), {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ line_hl_group = utils.set_hl(config.hl)
+ });
+
+ for l = 1, #item.text - 2 do
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start + l, math.min(#item.text[l + 1], range.col_start), {
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(config.pad_char or "", config.pad_amount or 0), utils.set_hl(config.hl) }
+ },
+
+ line_hl_group = utils.set_hl(config.hl)
+ });
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.commands
+latex.command = function (buffer, item)
+ --+${func}
+
+ ---@type latex.commands?
+ local main_config = spec.get({ "latex", "commands" }, { fallback = nil });
+ local config;
+
+ local command_name;
+
+ if item.command == nil or item.command.name == nil then
+ return;
+ else
+ command_name = string.format("^%s$", utils.escape_string(item.command.name));
+ end
+
+ if not main_config then
+ return;
+ else
+ ---@type commands.opts
+ config = utils.match(main_config, command_name, { default = false });
+
+ if type(config) ~= "table" or vim.tbl_isempty(config) == true then
+ return;
+ end
+ end
+
+ --- Check if this command is valid.
+ if spec.get({ "condition" }, { source = config, eval_args = { item } }) == false then
+ return;
+ end
+
+ if config.on_command then
+ local range = item.command.range;
+ local extmark = spec.get({ "on_command" }, { source = config, eval_args = { item.command } });
+
+ if not extmark then
+ goto invalid_extmark;
+ end
+
+ if pcall(config.command_offset, range) then
+ range = config.command_offset(range);
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range[1], range[2], vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+ end_row = range[3],
+ end_col = range[4]
+ }, extmark));
+
+ ::invalid_extmark::
+ end
+
+ if not config.on_args then return; end
+
+ local on_args = spec.get({ "on_args" }, { source = config, eval_args = { item.command } });
+
+ for a, arg in ipairs(item.args) do
+ if not on_args[a] then
+ goto continue;
+ end
+
+ ---@type commands.arg_opts
+ local arg_conf = on_args[a];
+
+ if arg_conf.on_before then
+ local b_conf = spec.get({ "on_before" }, { source = arg_conf, fallback = {}, eval_args = { arg } });
+ local range = arg.range;
+
+ if pcall(arg_conf.before_offset, range) then
+ range = arg_conf.before_offset(range);
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range[1], range[2], vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+ }, b_conf));
+ end
+
+ if arg_conf.on_content then
+ local c_conf = spec.get({ "on_content" }, { source = arg_conf, fallback = {}, eval_args = { arg } });
+ local range = arg.range;
+
+ if pcall(arg_conf.content_offset, range) then
+ range = arg_conf.content_offset(range);
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range[1], range[2], vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+ end_row = arg.range[3],
+ end_col = arg.range[4]
+ }, c_conf));
+ end
+
+ if arg_conf.on_after then
+ local a_conf = spec.get({ "on_after" }, { source = arg_conf, fallback = {}, eval_args = { arg } });
+ local range = arg.range;
+
+ if pcall(arg_conf.after_offset, range) then
+ range = arg_conf.after_offset(range);
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range[3], range[4], vim.tbl_extend("force", {
+ undo_restore = false, invalidate = true,
+ }, a_conf));
+ end
+
+ ::continue::
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.escapes
+latex.escaped = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.escapes?
+ local config = spec.get({ "latex", "escapes" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = ""
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.fonts
+latex.font = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.fonts?
+ local main_config = spec.get({ "latex", "fonts" }, { fallback = nil });
+
+ if main_config == nil then
+ return;
+ elseif symbols.fonts[item.name] == nil then
+ return;
+ end
+
+ ---@type fonts.opts?
+ local config = utils.match(main_config, item.name, { eval_args = { buffer, item } });
+
+ if config == nil then
+ return;
+ elseif vim.tbl_isempty(config) == true then
+ return;
+ end
+
+ table.insert(latex.cache.font_regions, item);
+
+ local range = item.range;
+ ---@type integer[]
+ local font = range.font;
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, font[1], font[2], {
+ undo_restore = false, invalidate = true,
+ end_row = font[3],
+ end_col = font[4] + 1,
+ conceal = "",
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+ });
+
+ if config.hl == nil then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(config.hl)
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.inlines
+latex.inline = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.inlines_static?
+ local config = spec.get({ "latex", "inlines" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #item.marker,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ if #item.text > 1 then
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start + #item.text[1], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) }
+ }
+ });
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(config.hl),
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_end, range.col_end - (#item.marker or 0), {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ if #item.text > 1 then
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_end, 0, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ }
+ });
+ end
+
+ for l = 1, #item.text - 2 do
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start + l, 0, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ }
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start + l, #item.text[l + 1], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) }
+ }
+ });
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.parenthesis
+latex.parenthesis = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.parenthesis?
+ local config = spec.get({ "latex", "parenthesis" }, { fallback = nil });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ --- Left parenthesis
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = ""
+ });
+
+ --- Right parenthesis
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = ""
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.subscripts
+latex.subscript = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.subscripts?
+ local config = spec.get({ "latex", "subscripts" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+ local hl;
+
+ if vim.islist(config.hl) then
+ hl = config.hl[utils.clamp(item.level, 1, #config.hl)];
+ elseif type(config.hl) == "string" then
+ hl = config.hl;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + (item.parenthesis and 2 or 1),
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = item.preview == false and { { "โ(", utils.set_hl(hl) } } or nil,
+
+ hl_mode = "combine"
+ });
+
+ if item.parenthesis then
+ table.insert(latex.cache.style_regions.subscripts, item);
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = item.preview == false and { { ")", utils.set_hl(hl) } } or nil,
+
+ hl_mode = "combine"
+ });
+ elseif symbols.subscripts[item.text[1]:sub(2)] then
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start + 1, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "overlay",
+ virt_text = { { symbols.subscripts[item.text[1]:sub(2)], utils.set_hl(hl) } },
+
+ hl_mode = "combine"
+ });
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(hl)
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.superscripts
+latex.superscript = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.superscripts?
+ local config = spec.get({ "latex", "superscripts" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + (item.parenthesis and 2 or 1),
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = item.preview == false and { { "โ(", utils.set_hl(config.hl) } } or nil,
+
+ hl_mode = "combine"
+ });
+
+ if item.parenthesis then
+ if item.preview then
+ table.insert(latex.cache.style_regions.superscripts, item);
+ else
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(config.hl)
+ });
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = item.preview == false and { { ")", utils.set_hl(config.hl) } } or nil,
+
+ hl_mode = "combine"
+ });
+ elseif symbols.superscripts[item.text[1]:sub(2)] then
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start + 1, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "overlay",
+ virt_text = { { symbols.superscripts[item.text[1]:sub(2)], utils.set_hl(config.hl) } },
+
+ hl_mode = "combine"
+ });
+ end
+ ---_
+end
+
+--------------------------------------------------------------------------------------------
+
+--- Gets text style.
+---@param buffer integer
+---@param range node.range
+---@param opts { symbol: string?, text: string? }
+---@return string | nil
+---@return string | nil
+local get_style = function (buffer, range, opts)
+ ---+${lua}
+ opts = opts or {};
+
+ local function is_smaller (range_1, range_2)
+ local r_diff_1 = range_1.row_end - range_1.row_start;
+ local r_diff_2 = range_2.row_end - range_2.row_start;
+
+ local c_diff_1 = range_1.col_end - range_1.col_start;
+ local c_diff_2 = range_2.col_end - range_2.col_start;
+
+ if r_diff_1 ~= r_diff_2 then
+ return r_diff_2 > r_diff_1 and 1 or 2;
+ else
+ return c_diff_2 > c_diff_1 and 1 or 2;
+ end
+ end
+
+ local function result_text (tbl)
+ tbl = tbl or {};
+
+ if opts.symbol then
+ return tbl[opts.symbol] or symbols.entries[opts.symbol];
+ elseif opts.text then
+ local _t = "";
+
+ for letter in opts.text:gmatch(".") do
+ if tbl[letter] then
+ _t = _t .. tbl[letter];
+ else
+ _t = _t .. letter;
+ end
+ end
+
+ return _t;
+ end
+ end
+
+ local _o;
+ local text, hl;
+ local styles = latex.cache.style_regions or {};
+
+ ---+${lua, Get the smallest style node that contains this range}
+ for _, entry in ipairs(styles.subscripts or {}) do
+ if utils.within_range(entry.range, range) then
+ if _o == nil then
+ _o = entry;
+ elseif is_smaller(entry.range, _o.range) == 1 then
+ _o = entry;
+ end
+ end
+ end
+
+ for _, entry in ipairs(styles.superscripts or {}) do
+ if utils.within_range(entry.range, range) then
+ if _o == nil then
+ _o = entry;
+ elseif is_smaller(entry.range, _o.range) == 1 then
+ _o = entry;
+ end
+ end
+ end
+
+ for _, entry in ipairs(latex.cache.font_regions or {}) do
+ if utils.within_range(entry.range, range) then
+ if _o == nil then
+ _o = entry;
+ elseif is_smaller(entry.range, _o.range) == 1 then
+ _o = entry;
+ end
+ end
+ end
+ ---_
+
+ if _o == nil then
+ if opts.symbol then
+ text = result_text(symbols.entries);
+ elseif opts.text then
+ text = result_text(symbols.fonts.default);
+ end
+ elseif _o.class == "latex_subscript" then
+ ---@type latex.subscripts?
+ local config = spec.get({ "latex", "subscripts" }, { fallback = nil, eval_args = { buffer, _o } });
+
+ if not config then
+ return;
+ end
+
+ if vim.islist(config.hl) then
+ ---@type string
+ hl = config.hl[utils.clamp(_o.level, 1, #config.hl)];
+ elseif type(config.hl) == "string" then
+ ---@type string | nil
+ hl = config.hl;
+ end
+
+ text = result_text(symbols.subscripts);
+ elseif _o.class == "latex_superscript" then
+ ---@type latex.subscripts?
+ local config = spec.get({ "latex", "superscripts" }, { fallback = nil, eval_args = { buffer, _o } });
+
+ if not config then
+ return;
+ end
+
+ if vim.islist(config.hl) then
+ ---@type string
+ hl = config.hl[utils.clamp(_o.level, 1, #config.hl)];
+ elseif type(config.hl) == "string" then
+ ---@type string | nil
+ hl = config.hl;
+ end
+
+ text = result_text(symbols.superscripts);
+ elseif _o.class == "latex_font" then
+ ---@type latex.fonts?
+ local main_config = spec.get({ "latex", "fonts" }, { fallback = nil });
+
+ if main_config == nil then
+ return;
+ elseif symbols.fonts[_o.name] == nil then
+ return;
+ end
+
+ ---@type fonts.opts?
+ local config = utils.match(main_config, _o.name, { eval_args = { buffer, item } });
+
+ if config == nil then
+ return;
+ elseif vim.tbl_isempty(config) == true then
+ return;
+ end
+
+ ---@type string | nil
+ hl = config.hl;
+ text = result_text( symbols.fonts[_o.name] ) or result_text( symbols.fonts.default );
+ end
+
+ return text, hl;
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.symbols
+latex.symbol = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.symbols?
+ local config = spec.get({ "latex", "symbols" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ elseif not item.name or not symbols.entries[item.name] then
+ return;
+ end
+
+ local range = item.range;
+ local _o, hl = get_style(buffer, range, { symbol = item.name });
+
+ if type(hl) ~= "string" then
+ hl = config.hl;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = { { _o or "", utils.set_hl(hl) } },
+
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.text
+latex.text = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.texts?
+ local config = spec.get({ "latex", "texts" }, { fallback = nil });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #"\\text{",
+ conceal = ""
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = ""
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __latex.word
+latex.word = function (buffer, item)
+ ---+${func}
+
+ ---@type latex.fonts?
+ local config = spec.get({ "latex", "fonts" }, { fallback = nil });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+ local _o, hl = get_style(buffer, range, { text = item.text[1] or "" });
+
+ if _o == nil then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, latex.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = { { _o, utils.set_hl(hl) } },
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+--- Renders LaTeX preview.
+---@param buffer integer
+---@param content table[]
+latex.render = function (buffer, content)
+ --- Clean up previous caches.
+ latex.cache = {
+ font_regions = {},
+ style_regions = {
+ superscripts = {},
+ subscripts = {}
+ },
+ };
+
+ local custom = spec.get({ "renderers" }, { fallback = {} });
+ local post = {};
+
+ for _, item in ipairs(content or {}) do
+ if vim.list_contains({ "latex_word", "latex_symbol" }, item.class) == true then
+ table.insert(post, item);
+ else
+ local success, err;
+
+ if custom[item.class] then
+ success, err = pcall(custom[item.class], latex.ns, buffer, item);
+ else
+ success, err = pcall(latex[item.class:gsub("^latex_", "")], buffer, item);
+ end
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = {
+ { " r/latex.lua: ", "DiagnosticVirtualTextInfo" },
+ { " " },
+ { err, "DiagnosticError" }
+ }
+ });
+ end
+ end
+ end
+
+ for _, item in ipairs(post) do
+ local success, err;
+
+ if custom[item.class] then
+ success, err = pcall(custom[item.class], latex.ns, buffer, item);
+ else
+ success, err = pcall(latex[item.class:gsub("^latex_", "")], buffer, item);
+ end
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = {
+ { " r/latex.lua: ", "DiagnosticVirtualTextInfo" },
+ { " " },
+ { err, "DiagnosticError" }
+ }
+ });
+ end
+ end
+end
+
+--- Clears LaTeX previews.
+---@param buffer integer
+---@param from integer?
+---@param to integer!
+latex.clear = function (buffer, from, to)
+ vim.api.nvim_buf_clear_namespace(buffer, latex.ns, from or 0, to or -1);
+end
+
+return latex;
diff --git a/lua/markview/renderers/markdown.lua b/lua/markview/renderers/markdown.lua
new file mode 100644
index 0000000..e943447
--- /dev/null
+++ b/lua/markview/renderers/markdown.lua
@@ -0,0 +1,3792 @@
+local markdown = {};
+local inline = require("markview.renderers.markdown_inline");
+
+local spec = require("markview.spec");
+local utils = require("markview.utils");
+
+local filetypes = require("markview.filetypes");
+local entities = require("markview.entities");
+local symbols = require("markview.symbols");
+
+--- Forces the {index} to be between 1 & the length of {value}.
+---@param value any | any[]
+---@param index integer
+---@return any
+local function tbl_clamp(value, index)
+ if vim.islist(value) == false then
+ return value;
+ elseif index > #value then
+ return value[#value];
+ end
+
+ return value[index];
+end
+
+--- Holds nodes for post-process effects.
+---@type table[]
+markdown.cache = {};
+
+local concat = function (list)
+ for i, item in ipairs(list) do
+ list[i] = utils.escape_string(item);
+ end
+
+ return table.concat(list);
+end
+
+--- Cached configuration to increase performance.
+markdown.__inline_config = {
+ codes = spec.get({ "markdown_inline", "inline_codes"}, { fallback = nil }),
+ hyper = spec.get({ "markdown_inline", "hyperlinks" }, { fallback = nil }),
+ image = spec.get({ "markdown_inline", "images" }, { fallback = nil }),
+ email = spec.get({ "markdown_inline", "emails" }, { fallback = nil }),
+ embed = spec.get({ "markdown_inline", "embed_files" }, { fallback = nil }),
+ blref = spec.get({ "markdown_inline", "block_references" }, { fallback = nil }),
+ int = spec.get({ "markdown_inline", "internal_links" }, { fallback = nil }),
+ uri = spec.get({ "markdown_inline", "uri_autolinks" }, { fallback = nil }),
+ esc = spec.get({ "markdown_inline", "escapes" }, { fallback = nil }),
+ ent = spec.get({ "markdown_inline", "entities" }, { fallback = nil }),
+ emo = spec.get({ "markdown_inline", "emoji_shorthands" }, { fallback = nil }),
+ hls = spec.get({ "markdown_inline", "highlights" }, { fallback = nil }),
+};
+
+--- Reloads cached configuration.
+markdown.__new_config = function ()
+ markdown.__inline_config = {
+ codes = spec.get({ "markdown_inline", "inline_codes"}, { fallback = nil }),
+ hyper = spec.get({ "markdown_inline", "hyperlinks" }, { fallback = nil }),
+ image = spec.get({ "markdown_inline", "images" }, { fallback = nil }),
+ email = spec.get({ "markdown_inline", "emails" }, { fallback = nil }),
+ embed = spec.get({ "markdown_inline", "embed_files" }, { fallback = nil }),
+ blref = spec.get({ "markdown_inline", "block_references" }, { fallback = nil }),
+ int = spec.get({ "markdown_inline", "internal_links" }, { fallback = nil }),
+ uri = spec.get({ "markdown_inline", "uri_autolinks" }, { fallback = nil }),
+ esc = spec.get({ "markdown_inline", "escapes" }, { fallback = nil }),
+ ent = spec.get({ "markdown_inline", "entities" }, { fallback = nil }),
+ emo = spec.get({ "markdown_inline", "emoji_shorthands" }, { fallback = nil }),
+ hls = spec.get({ "markdown_inline", "highlights" }, { fallback = nil }),
+ };
+end
+
+--- Gets the preview text from a string containing markdown
+--- syntax.
+---
+--- >[!NOTE]
+--- > This is slower than `tree-sitter` and is less accurate.
+--- > Use only when there are no alternatives.
+---@param str string
+---@return string
+---@return integer
+markdown.output = function (str, buffer)
+ ---+${func}
+ local decorations = 0;
+
+ --- Checks if syntax exists in {str}.
+ ---@return boolean
+ local function has_syntax ()
+ ---+${lua, Conditions}
+ if str:match("`(.-)`") then
+ return true;
+ elseif str:match("\\([%\\%*%_%{%}%[%]%(%)%#%+%-%.%!%%<%>$])") then
+ return true;
+ elseif str:match("([%*]+)(.-)([%*]+)") then
+ return true;
+ elseif str:match("%~%~(.-)%~%~") then
+ return true;
+ elseif str:match("%&([%d%a%#]+);") then
+ return true;
+ elseif str:match(":([%a%d%_%+%-]+):") then
+ return true;
+ elseif str:match("%=%=(.-)%=%=") then
+ return true;
+ elseif str:match("%!%[%[([^%]]+)%]%]") then
+ return true;
+ elseif str:match("%[%[%#%^([^%]]+)%]%]") then
+ return true;
+ elseif str:match("%[%[([^%]]+)%]%]") then
+ return true;
+ elseif str:match("%!%[([^%]]*)%]([%(%[])([^%)]*)([%)%]])") then
+ return true;
+ elseif str:match("%!%[([^%]]*)%]") then
+ return true;
+ elseif str:match("%[([^%]]*)%]([%(%[])([^%)]*)([%)%]])") then
+ return true;
+ elseif str:match("%[([^%]]+)%]") then
+ return true;
+ elseif str:match("%<([^%s%@]-)@(%S+)%>") then
+ return true;
+ elseif str:match("%<(%S+)%>") then
+ return true;
+ end
+ ---_
+
+ return false;
+ end
+
+ --- If no syntax items are found and no highlight exits
+ if has_syntax() == false then
+ return str, decorations;
+ end
+
+ --- Inline codes config
+ local codes = markdown.__inline_config.codes;
+ local hyper = markdown.__inline_config.hyper;
+ local image = markdown.__inline_config.image;
+ local email = markdown.__inline_config.email;
+ local embed = markdown.__inline_config.embed;
+ local blref = markdown.__inline_config.blref;
+ local int = markdown.__inline_config.int;
+ local uri = markdown.__inline_config.url;
+ local esc = markdown.__inline_config.esc;
+ local ent = markdown.__inline_config.ent;
+ local emo = markdown.__inline_config.emo;
+ local hls = markdown.__inline_config.hls;
+
+
+ str = str:gsub("\\%`", " ");
+
+ for inline_code in str:gmatch("`(.-)`") do
+ ---+${custom, Handle inline codes}
+ if not codes or codes.enable == false then
+ str = str:gsub(
+ concat({
+ "`",
+ utils.escape_string(inline_code),
+ "`"
+ }),
+ concat({ content })
+ );
+ else
+ local _codes = spec.get({}, {
+ source = codes,
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_code_span",
+ text = string.format("`%s`", inline_code)
+ }
+ }
+ });
+
+ str = str:gsub(
+ concat({
+ "`",
+ inline_code,
+ "`"
+ }),
+ concat({
+ _codes.corner_left or "",
+ _codes.padding_left or "",
+ inline_code:gsub(".", "X"),
+ _codes.padding_right or "",
+ _codes.corner_left or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _codes.corner_left or "",
+ _codes.padding_left or "",
+ _codes.padding_right or "",
+ _codes.corner_left or ""
+ }));
+ end
+ ---_
+ end
+
+ for escaped in str:gmatch("\\([%\\%*%_%{%}%[%]%(%)%#%+%-%.%!%%<%>$])") do
+ if not esc then
+ break;
+ end
+
+ str = str:gsub(concat({ "\\", escaped }), " ", 1);
+ end
+
+ for latex in str:gmatch("%$([^%$]*)%$") do
+ ---+${custom, Handle LaTeX blocks}
+ str = str:gsub(
+ concat({
+ "$",
+ latex,
+ "$"
+ }),
+ concat({
+ "$",
+ string.rep("X", vim.fn.strdisplaywidth(latex)),
+ "$"
+ }),
+ 1
+ );
+ ---_
+ end
+
+ for str_b, content, str_a in str:gmatch("([%*]+)(.-)([%*]+)") do
+ ---+${custom, Handle italics & bold text}
+ if content == "" then
+ goto continue;
+ elseif #str_b ~= #str_a then
+ local min = math.min(#str_b, #str_a);
+ str_b = str_b:sub(0, min);
+ str_a = str_a:sub(0, min);
+ end
+
+ str = str:gsub(
+ concat({
+ str_b,
+ content,
+ str_a
+ }),
+ content,
+ 1
+ );
+
+ ::continue::
+ ---_
+ end
+
+ for striked in str:gmatch("%~%~(.-)%~%~") do
+ ---+${custom, Handle strike-through text}
+ str = str:gsub(
+ concat({
+ "~~",
+ striked,
+ "~~"
+ }),
+ concat({
+ striked
+ }),
+ 1
+ );
+ ---_
+ end
+
+ for entity in str:gmatch("%&([%d%a%#]+);") do
+ ---+${custom, Handle entities}
+ if not emo then
+ break;
+ elseif not entities.get(entity:gsub("%#", "")) then
+ goto continue;
+ end
+
+ str = str:gsub(
+ concat({
+ "&",
+ entity,
+ ";"
+ }),
+ concat({
+ entities.get(entity:gsub("%#", ""))
+ })
+ );
+
+ ::continue::
+ ---_
+ end
+
+ for emoji in str:gmatch(":([%a%d%_%+%-]+):") do
+ ---+${lua, Handles emoji shorthands}
+ if not ent then
+ break;
+ elseif not symbols.shorthands[emoji] then
+ goto continue;
+ end
+
+ str = str:gsub(
+ concat({
+ ":",
+ emoji,
+ ":"
+ }),
+ concat({
+ symbols.shorthands[emoji]
+ })
+ );
+
+ ::continue::
+ ---_
+ end
+
+ for highlight in str:gmatch("%=%=(.-)%=%=") do
+ ---+${custom, Handle highlighted text}
+ if not hls then goto continue; end
+
+ local _hls = utils.match(
+ hls,
+ highlight,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_highlight",
+ text = highlight
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "==",
+ highlight,
+ "=="
+ }),
+ concat({
+ _hls.corner_left or "",
+ _hls.padding_left or "",
+ _hls.icon or "",
+ string.rep("X", vim.fn.strdisplaywidth(highlight)),
+ _hls.padding_right or "",
+ _hls.corner_left or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _hls.corner_left or "",
+ _hls.padding_left or "",
+ _hls.icon or "",
+ _hls.padding_right or "",
+ _hls.corner_left or ""
+ }));
+
+ ::continue::
+ ---_
+ end
+
+ for ref in str:gmatch("%!%[%[([^%]]+)%]%]") do
+ ---+${custom, Handle embed files & block references}
+ if ref:match("%#%^(.+)") and blref then
+ local _blref = utils.match(
+ blref,
+ ref,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_block_ref",
+ text = string.format("![[%s]]", ref),
+
+ label = ref:match("%#%^(.+)$")
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "![[",
+ ref,
+ "]]"
+ }),
+ concat({
+ _blref.corner_left or "",
+ _blref.padding_left or "",
+ _blref.icon or "",
+ string.rep("X", vim.fn.strdisplaywidth(ref)),
+ _blref.padding_right or "",
+ _blref.corner_right or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _blref.corner_left or "",
+ _blref.padding_left or "",
+ _blref.icon or "",
+ _blref.padding_right or "",
+ _blref.corner_right or ""
+ }));
+ elseif embed then
+ local _embed = utils.match(
+ embed,
+ ref,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_embed_file",
+ text = string.format("![[%s]]", ref),
+
+ label = ref
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "![[",
+ ref,
+ "]]"
+ }), concat({
+ _embed.corner_left or "",
+ _embed.padding_left or "",
+ _embed.icon or "",
+ string.rep("X", vim.fn.strdisplaywidth(ref)),
+ _embed.padding_right or "",
+ _embed.corner_right or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _embed.corner_left or "",
+ _embed.padding_left or "",
+ _embed.icon or "",
+ _embed.padding_right or "",
+ _embed.corner_right or ""
+ }));
+ end
+ ---_
+ end
+
+ for ref in str:gmatch("%[%[%#%^([^%]]+)%]%]") do
+ ---+${custom, Handle block references}
+ if not blref then goto continue; end
+
+ local _blref = utils.match(
+ blref,
+ ref,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_block_ref",
+ text = string.format("[[%s]]", ref),
+
+ label = ref:match("%#%^(.+)$")
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "[[#^",
+ ref,
+ "]]"
+ }),
+ concat({
+ _blref.corner_left or "",
+ _blref.padding_left or "",
+ _blref.icon or "",
+ string.rep("X", vim.fn.strdisplaywidth(ref)),
+ _blref.padding_right or "",
+ _blref.corner_right or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _blref.corner_left or "",
+ _blref.padding_left or "",
+ _blref.icon or "",
+ _blref.padding_right or "",
+ _blref.corner_right or ""
+ }));
+
+ ::continue::
+ ---_
+ end
+
+ for link in str:gmatch("%[%[([^%]]+)%]%]") do
+ ---+${custom, Handle internal links}
+ if not int then
+ str = str:gsub(
+ concat({
+ "[[",
+ link,
+ "]]"
+ }),
+ concat({
+ " ",
+ (alias or link):gsub(".", "X"),
+ " "
+ })
+ );
+ else
+ local alias = link:match("%|(.+)$");
+ local _int = utils.match(
+ int,
+ link,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_internal",
+ text = string.format("[[%s]]", link),
+
+ label = link,
+ alias = alias
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "[[",
+ link,
+ "]]"
+ }),
+ concat({
+ _int.corner_left or "",
+ _int.padding_left or "",
+ _int.icon or "",
+ (alias or link):gsub(".", "X"),
+ _int.padding_right or "",
+ _int.corner_right or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _int.corner_left or "",
+ _int.padding_left or "",
+ _int.icon or "",
+ _int.padding_right or "",
+ _int.corner_right or ""
+ }));
+ end
+ ---_
+ end
+
+ for link, p_s, address, p_e in str:gmatch("%!%[([^%]]*)%]([%(%[])([^%)]*)([%)%]])") do
+ ---+${custom, Handle image links}
+ if not image then
+ str = str:gsub(
+ concat({
+ "![",
+ link,
+ "]",
+ address
+ }),
+ concat({ link })
+ );
+ else
+ local _image = utils.match(
+ image,
+ address,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_image",
+ text = string.format("![%s]%s%s%s", link, p_s, address, p_e),
+
+ label = address,
+ description = link
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "![",
+ link,
+ "]",
+ p_s,
+ address,
+ p_e
+ }),
+ concat({
+ _image.corner_left or "",
+ _image.padding_left or "",
+ _image.icon or "",
+ string.rep("X", vim.fn.strdisplaywidth(link)),
+ _image.padding_right or "",
+ _image.corner_right or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _image.corner_left or "",
+ _image.padding_left or "",
+ _image.icon or "",
+ _image.padding_right or "",
+ _image.corner_right or ""
+ }));
+ end
+ ---_
+ end
+
+ for link in str:gmatch("%!%[([^%]]*)%]") do
+ ---+${custom, Handle image links without address}
+ if not image then
+ str = str:gsub(
+ concat({
+ "![",
+ link,
+ "]",
+ }),
+ concat({
+ string.rep("X", vim.fn.strdisplaywidth(link)),
+ })
+ );
+ else
+ local _image = utils.match(
+ image,
+ address,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_image",
+ text = string.format("![%s]", link),
+
+ label = nil,
+ description = link
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "![",
+ link,
+ "]",
+ }), concat({
+ _image.corner_left or "",
+ _image.padding_left or "",
+ _image.icon or "",
+ string.rep("X", vim.fn.strdisplaywidth(link)),
+ _image.padding_right or "",
+ _image.corner_right or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _image.corner_left or "",
+ _image.padding_left or "",
+ _image.icon or "",
+ _image.padding_right or "",
+ _image.corner_right or ""
+ }));
+ end
+ ---_
+ end
+
+ for link, p_s, address, p_e in str:gmatch("%[([^%]]*)%]([%(%[])([^%)]*)([%)%]])") do
+ ---+${custom, Handle hyperlinks}
+ if not hyper then
+ str = str:gsub(
+ concat({
+ "[",
+ link,
+ "]",
+ address
+ }),
+ concat({
+ string.rep("X", vim.fn.strdisplaywidth(link)),
+ })
+ );
+ else
+ local _hyper = utils.match(
+ hyper,
+ address,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_hyperlink",
+ text = string.format("[%s]%s%s%s", link, p_s, address, p_e),
+
+ label = address,
+ description = link
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "[",
+ link,
+ "]",
+ p_s,
+ address,
+ p_e
+ }), concat({
+ _hyper.corner_left or "",
+ _hyper.padding_left or "",
+ _hyper.icon or "",
+ string.rep("X", vim.fn.strdisplaywidth(link)),
+ _hyper.padding_right or "",
+ _hyper.corner_right or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _hyper.corner_left or "",
+ _hyper.padding_left or "",
+ _hyper.icon or "",
+ _hyper.padding_right or "",
+ _hyper.corner_right or ""
+ }));
+ end
+ ---_
+ end
+
+ for link in str:gmatch("%[([^%]]+)%]") do
+ ---+${custom, Handle shortcut links}
+ if not hyper then
+ str = str:gsub(
+ concat({
+ "[",
+ link,
+ "]",
+ }),
+ concat({
+ string.rep("X", link:len())
+ })
+ );
+ else
+ local _hyper = utils.match(
+ hyper,
+ link,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_shortcut",
+ text = string.format("[%s]", link),
+
+ label = link
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "[",
+ link,
+ "]",
+ }), concat({
+ _hyper.corner_left or "",
+ _hyper.padding_left or "",
+ _hyper.icon or "",
+ string.rep("X", link:len()),
+ _hyper.padding_right or "",
+ _hyper.corner_right or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _hyper.corner_left or "",
+ _hyper.padding_left or "",
+ _hyper.icon or "",
+ _hyper.padding_right or "",
+ _hyper.corner_right or ""
+ }));
+ end
+ ---_
+ end
+
+ for address, domain in str:gmatch("%<([^%s%@]-)@(%S+)%>") do
+ ---+${custom, Handle emails}
+ if not email then
+ break;
+ end
+
+ local _email = utils.match(
+ email,
+ string.format("%s@%s", address, domain),
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_email",
+ text = string.format("<%s@%s>", address, domain),
+
+ label = string.format("%s@%s", address, domain)
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "<",
+ address,
+ "@",
+ domain,
+ ">"
+ }),
+ concat({
+ _email.corner_left or "",
+ _email.padding_left or "",
+ _email.icon or "",
+ string.rep("X", address:len()),
+ "Y",
+ string.rep("X", domain:len()),
+ _email.padding_right or "",
+ _email.corner_left or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _email.corner_left or "",
+ _email.padding_left or "",
+ _email.icon or "",
+ _email.padding_right or "",
+ _email.corner_left or ""
+ }));
+ ---_
+ end
+
+ for address in str:gmatch("%<(%S+)%>") do
+ ---+${custom, Handle uri autolinks}
+ if not uri then
+ break;
+ elseif not address:match("^ht") and not address:match("%:%/%/") then
+ goto continue;
+ end
+
+ local _uri = utils.match(
+ uri,
+ address,
+ {
+ fallback = {},
+ eval_args = {
+ buffer,
+ {
+ class = "inline_link_uri_autolink",
+ text = string.format("<%s>", address),
+
+ label = address
+ }
+ }
+ }
+ );
+
+ str = str:gsub(
+ concat({
+ "<",
+ address,
+ ">"
+ }), concat({
+ _uri.corner_left or "",
+ _uri.padding_left or "",
+ _uri.icon or "",
+ string.rep("X", address:len()),
+ _uri.padding_right or "",
+ _uri.corner_left or ""
+ })
+ );
+
+ decorations = decorations + vim.fn.strdisplaywidth(table.concat({
+ _uri.corner_left or "",
+ _uri.padding_left or "",
+ _uri.icon or "",
+ _uri.padding_right or "",
+ _uri.corner_left or ""
+ }));
+
+ ::continue::
+ ---_
+ end
+
+ return str, decorations;
+ ---_
+end
+
+--- Applies text transformation based on the **filetype**.
+---
+--- Uses for getting the output text of filetypes that contain
+--- special syntaxes(e.g. JSON, Markdown).
+markdown.get_visual_text = {
+ ---+${class}
+ ["Markdown"] = function (str)
+ ---+${lua}
+
+ str = str:gsub("\\%`", " ");
+
+ for inline_code in str:gmatch("`(.-)`") do
+ ---+${custom, Handle inline codes}
+ str = str:gsub(concat({
+ "`",
+ inline_code,
+ "`"
+ }), inline_code);
+ ---_
+ end
+
+ for str_b, content, str_a in str:gmatch("([*]+)(.-)([*]+)") do
+ ---+${custom, Handle italics & bold text}
+ if content == "" then
+ goto continue;
+ elseif #str_b ~= #str_a then
+ local min = math.min(#str_b, #str_a);
+ str_b = str_b:sub(0, min);
+ str_a = str_a:sub(0, min);
+ end
+
+ str_b = utils.escape_string(str_b);
+ content = utils.escape_string(content);
+ str_a = utils.escape_string(str_a);
+
+ str = str:gsub(str_b .. content .. str_a, utils.escape_string(content):gsub(".", "X"))
+
+ ::continue::
+ ---_
+ end
+
+ for striked in str:gmatch("%~%~(.-)%~%~") do
+ ---+${custom, Handle strike-through text}
+ str = str:gsub(concat({
+ "~~",
+ striked,
+ "~~"
+ }), concat({
+ utils.escape_string(striked):gsub(".", "X"),
+ }));
+ ---_
+ end
+
+ for escaped in str:gmatch("\\([%\\%*%_%{%}%[%]%(%)%#%+%-%.%!%%<%>$])") do
+ str = str:gsub(concat({
+ "\\",
+ escaped
+ }), " ");
+ end
+
+ for link, m1, address, m2 in str:gmatch("%!%[([^%)]*)%]([%(%[])([^%)]*)([%)%]])") do
+ ---+${custom, Handle image links}
+ str = str:gsub(concat({
+ "![",
+ link,
+ "]",
+ m1,
+ address,
+ m2
+ }), link);
+ ---_
+ end
+
+ for link in str:gmatch("%!%[([^%)]*)%]") do
+ ---+${custom, Handle image links without address}
+ str = str:gsub(concat({
+ "![",
+ link,
+ "]",
+ }), concat({
+ utils.escape_string(link):gsub(".", "X"),
+ }))
+ ---_
+ end
+
+ for link, m1, address, m2 in str:gmatch("%[([^%)]*)%]([%(%[])([^%)]*)([%)%]])") do
+ ---+${custom, Handle hyperlinks}
+ str = str:gsub(concat({
+ "[",
+ link,
+ "]",
+ m1,
+ address,
+ m2
+ }), link:gsub(".", "X"));
+ ---_
+ end
+
+ for link in str:gmatch("%[([^%)]+)%]") do
+ ---+${custom, Handle shortcut links}
+ str = str:gsub(concat({
+ "[",
+ link,
+ "]",
+ }), concat({
+ utils.escape_string(link):gsub(".", "X"),
+ }))
+ ---_
+ end
+
+ return str;
+ ---_
+ end,
+ ["JSON"] = function (str)
+ return str:gsub('"', "");
+ end,
+
+ --- Gets the visual text from the source text.
+ ---@param self table
+ ---@param ft string?
+ ---@param line string
+ ---@return string
+ init = function (self, ft, line)
+ if ft == nil or self[ft] == nil then
+ --- Filetype isn't available or
+ --- transformation not available.
+ return line;
+ elseif pcall(self[ft], line) == false then
+ --- Text transformation failed!
+ return line;
+ end
+
+ return self[ft](line);
+ end
+ ---_
+};
+
+---@type integer Namespace for markdown.
+markdown.ns = vim.api.nvim_create_namespace("markview/markdown");
+
+--- Renders atx headings.
+---@param buffer integer
+---@param item __markdown.atx
+markdown.atx_heading = function (buffer, item)
+ ---+${func, Renders ATX headings}
+
+ ---@type markdown.headings?
+ local main_config = spec.get({ "markdown", "headings" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not main_config then
+ return;
+ elseif not spec.get({ "heading_" .. #item.marker }, { source = main_config, eval_args = { buffer, item } }) then
+ return;
+ end
+
+ ---@type headings.atx
+ local config = spec.get({ "heading_" .. #item.marker }, { source = main_config, eval_args = { buffer, item } });
+ local shift_width = spec.get({ "shift_width" }, { source = main_config, fallback = 1, eval_args = { buffer, item } });
+
+ local range = item.range;
+
+ if config.style == "simple" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ line_hl_group = utils.set_hl(config.hl)
+ });
+ elseif config.style == "label" then
+ local space = "";
+
+ if config.align then
+ local win = vim.fn.win_findbuf(buffer)[1];
+ local res = markdown.output(item.text[1], buffer):gsub("^#+%s", "");
+
+ local wid = vim.fn.strdisplaywidth(table.concat({
+ config.corner_left or "",
+ config.padding_left or "",
+
+ config.icon or "",
+ res,
+
+ config.padding_right or "",
+ config.corner_right or "",
+ }));
+
+ local w_wid = vim.api.nvim_win_get_width(win or 0) - vim.fn.getwininfo(win or 0)[1].textoff;
+
+ if config.align == "left" then
+ space = "";
+ elseif config.align == "center" then
+ space = string.rep(" ", math.floor((w_wid - wid) / 2));
+ elseif config.align == "right" then
+ space = string.rep(" ", w_wid - wid);
+ end
+ else
+ space = string.rep(" ", #item.marker * shift_width);
+ end
+
+ --- DO NOT USE `hl_mode = "combine"`
+ --- It causes color bleeding.
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #item.marker + (#item.text[1] > #item.marker and 1 or 0),
+ conceal = "",
+ sign_text = config.sign,
+ sign_hl_group = utils.set_hl(config.sign_hl),
+ virt_text_pos = "inline",
+ virt_text = {
+ { space },
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) },
+ }
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_start,
+ end_col = range.col_start + #(item.text[1] or ""),
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + #(item.text[1] or ""), {
+ undo_restore = false, invalidate = true,
+ conceal = "",
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ }
+ });
+ elseif config.style == "icon" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #item.marker + (#item.text[1] > #item.marker and 1 or 0),
+ conceal = "",
+ sign_text = config.sign,
+ sign_hl_group = utils.set_hl(config.sign_hl),
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", #item.marker * shift_width) },
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) },
+ },
+ line_hl_group = utils.set_hl(config.hl),
+
+ hl_mode = "combine"
+ });
+ end
+ ---_
+end
+
+--- Renders block quotes, callouts & alerts.
+---@param buffer integer
+---@param item __markdown.block_quotes
+markdown.block_quote = function (buffer, item)
+ ---+${func, Renders Block quotes & Callouts/Alerts}
+
+ ---@type markdown.block_quotes?
+ local main_config = spec.get({ "markdown", "block_quotes" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if
+ not main_config or
+ not main_config.default
+ then
+ return;
+ end
+
+ ---@type block_quotes.opts
+ local config;
+
+ if item.callout then
+ config = spec.get(
+ { string.lower(item.callout) },
+ { source = main_config, eval_args = { buffer, item } }
+ ) or spec.get(
+ { string.upper(item.callout) },
+ { source = main_config, eval_args = { buffer, item } }
+ ) or spec.get(
+ { item.callout },
+ { source = main_config, eval_args = { buffer, item } }
+ ) or spec.get(
+ { "default" },
+ { source = main_config, eval_args = { buffer, item } }
+ );
+ else
+ config = spec.get({ "default" }, { source = main_config, eval_args = { buffer, item } });
+ end
+
+ if item.callout then
+ if item.title and config.title == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.callout_start, {
+ end_col = range.callout_end,
+ conceal = "",
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { " " },
+ { config.icon, utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine",
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.title_start, {
+ end_col = range.title_end,
+ undo_restore = false, invalidate = true,
+ hl_group = utils.set_hl(config.hl),
+
+ hl_mode = "combine",
+ });
+ elseif config.preview then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.callout_start, {
+ end_col = range.callout_end,
+ conceal = "",
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+ virt_text_pos = "inline",
+ virt_text = {
+ { " " },
+ { config.preview, utils.set_hl(config.preview_hl or config.hl) }
+ },
+
+ hl_mode = "combine",
+ });
+ end
+ end
+
+ for l = range.row_start, range.row_end - 1, 1 do
+ local l_index = l - (range.row_start) + 1;
+
+ local line = item.text[l_index];
+ local line_len = #line;
+
+ if line:match("^%>") then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, range.col_start, {
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ end_col = range.col_start + math.min(1, line_len),
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ tbl_clamp(config.border, l_index),
+ utils.set_hl(tbl_clamp(config.border_hl, l_index) or config.hl)
+ }
+ },
+
+ hl_mode = "combine",
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, range.col_start, {
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ tbl_clamp(config.border, l_index),
+ utils.set_hl(tbl_clamp(config.border_hl, l_index) or config.hl)
+ },
+ { " " }
+ },
+
+ hl_mode = "combine",
+ });
+ end
+ end
+
+ ---@type integer, integer Start & end fold level.
+ local foldlevel_s, foldlevel_e;
+
+ vim.api.nvim_buf_call(buffer, function ()
+ foldlevel_s = vim.fn.foldlevel(range.row_start + 1);
+ foldlevel_e = vim.fn.foldlevel(range.row_end + 1);
+ end)
+
+ if foldlevel_s ~= 0 or foldlevel_e ~= 0 then
+ --- Text was folded.
+ return;
+ end
+
+ --- TODO: Feat
+ local win = utils.buf_getwin(buffer);
+
+ if main_config.wrap == true and vim.wo[win].wrap == true then
+ --- When `wrap` is enabled, run post-processing effects.
+ table.insert(markdown.cache, item);
+ end
+ ---_
+end
+
+--- Renders [ ], [x] & [X].
+---@param buffer integer
+---@param item __inline.checkboxes
+markdown.checkbox = function (buffer, item)
+ --- Wrapper for the inline checkbox renderer function.
+ --- Used for [ ] & [X] checkboxes.
+ inline.checkbox(buffer, item)
+end
+
+--- Renders fenced code blocks.
+---@param buffer integer
+---@param item __markdown.code_blocks
+markdown.code_block = function (buffer, item)
+ ---+${func, Renders Code blocks}
+
+ ---@type markdown.code_blocks_static?
+ local config = spec.get({ "markdown", "code_blocks" }, { fallback = nil, eval_args = { buffer, item } });
+
+ local delims = item.delimiters;
+ local range = item.range;
+
+ local info_range = range.info_string or {};
+
+ if not config then
+ return;
+ end
+
+ local decorations = filetypes.get(item.language);
+ local label = { string.format(" %s%s ", decorations.icon, decorations.name), config.label_hl or decorations.icon_hl };
+ local win = utils.buf_getwin(buffer);
+
+ --- Column end for concealing code block language string.
+ ---@return integer
+ local function lang_conceal_to ()
+ ---+${lua}
+ if item.info_string == nil then
+ return range.col_start + #delims[1];
+ elseif item.info_string:match("^%{[^%}]+%}%s?") then
+ --- Info string: {lang}
+ local _to = item.info_string:match("^%{[^%}]+%}%s?"):len();
+ return info_range[2] + _to;
+ else
+ --- Info string: ```lang`
+ local _to = item.info_string:match("^%S+%s?"):len();
+ return info_range[2] + _to;
+ end
+ ---_
+ end
+
+ --- Gets highlight configuration for a line.
+ ---@param line string
+ ---@return code_blocks.opts_static
+ local function get_line_config(line)
+ ---+${lua}
+
+ local line_conf = utils.match(config, item.language, {
+ eval_args = { buffer, line },
+ def_fallback = {
+ block_hl = config.border_hl,
+ pad_hl = config.border_hl
+ },
+ fallback = {
+ block_hl = config.border_hl,
+ pad_hl = config.border_hl
+ }
+ });
+
+ return line_conf;
+ ---_
+ end
+
+ --- Renders simple style code blocks.
+ local function render_simple()
+ ---+${lua}
+
+ local conceal_to = lang_conceal_to();
+
+ if config.label_direction == nil or config.label_direction == "left" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ end_col = conceal_to,
+ conceal = "",
+
+ sign_text = config.sign == true and decorations.sign or nil,
+ sign_hl_group = utils.set_hl(config.sign_hl or decorations.sign_hl),
+
+ virt_text_pos = "inline",
+ virt_text = { label },
+
+ line_hl_group = utils.set_hl(config.border_hl)
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ end_col = conceal_to,
+ conceal = "",
+
+ sign_text = config.sign == true and decorations.sign or nil,
+ sign_hl_group = utils.set_hl(config.sign_hl or decorations.sign_hl),
+
+ virt_text_pos = "right_align",
+ virt_text = { label },
+
+ line_hl_group = utils.set_hl(config.border_hl)
+ });
+ end
+
+ if item.info_string then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, info_range[1], info_range[2], {
+ undo_restore = false, invalidate = true,
+
+ end_row = info_range[3],
+ end_col = #item.text[1],
+
+ hl_group = utils.set_hl(config.info_hl or config.border_hl)
+ });
+ end
+
+ --- Background
+ for l = range.row_start + 1, range.row_end - 2 do
+ local line = item.text[(l - range.row_start) + 1];
+ local line_config = get_line_config(line);
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+ end_row = l,
+
+ line_hl_group = utils.set_hl(line_config.block_hl)
+ });
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, (range.col_start + #item.text[#item.text]) - #delims[2], {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #item.text[#item.text],
+ conceal = "",
+
+ line_hl_group = utils.set_hl(config.border_hl)
+ });
+ ---_
+ end
+
+ --- Renders block style code blocks.
+ local function render_block ()
+ ---+${lua}
+
+ local pad_amount = config.pad_amount or 0;
+ local block_width = config.min_width or 60;
+
+ local line_widths = {};
+
+ --- Get maximum length of the lines within the code block
+ for l, line in ipairs(item.text) do
+ local final = markdown.get_visual_text:init(decorations.name, line);
+
+ if l ~= 1 and l ~= #item.text then
+ table.insert(line_widths, vim.fn.strdisplaywidth(final));
+
+ if vim.fn.strdisplaywidth(final) > (block_width - (2 * pad_amount)) then
+ block_width = vim.fn.strdisplaywidth(final) + (2 * pad_amount);
+ end
+ end
+ end
+
+ local label_width = utils.virt_len({ label });
+ local conceal_to = lang_conceal_to();
+
+ --- Render top
+ if config.label_direction == nil or config.label_direction == "left" then
+ ---+${Left aligned label}
+ local avail_top = block_width - (label_width + 2);
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ end_col = conceal_to,
+ conceal = "",
+
+ sign_text = config.sign == true and decorations.sign or nil,
+ sign_hl_group = utils.set_hl(config.sign_hl or decorations.sign_hl),
+
+ virt_text_pos = "inline",
+ virt_text = { label }
+ });
+
+ if not item.info_string then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + #delims[1], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(config.pad_char or " ", block_width - label_width),
+ utils.set_hl(config.border_hl)
+ }
+ }
+ });
+ goto no_info;
+ end
+
+ local relative_y = conceal_to - info_range[2];
+ local info_width = #item.info_string - relative_y;
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, info_range[1], info_range[2], {
+ undo_restore = false, invalidate = true,
+
+ end_row = info_range[3],
+ end_col = range.col_start + #item.text[1],
+
+ hl_group = utils.set_hl(config.info_hl or config.border_hl)
+ });
+
+ if info_width >= avail_top then
+ --- Exceeds.
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, conceal_to + avail_top, {
+ undo_restore = false, invalidate = true,
+
+ end_col = info_range[4],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { "โฆ", utils.set_hl(config.info_hl or config.border_hl) },
+ { " ", utils.set_hl(config.border_hl) }
+ }
+ });
+ else
+ local spaces = avail_top - info_width + 2;
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + #item.text[1], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(config.pad_char or " ", spaces),
+ utils.set_hl(config.border_hl)
+ }
+ }
+ });
+ end
+
+ ::no_info::
+ ---_
+ else
+ ---+${Right aligned label}
+ local avail_top = block_width - (label_width + 3);
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ end_col = conceal_to,
+ conceal = "",
+
+ sign_text = config.sign == true and decorations.sign or nil,
+ sign_hl_group = utils.set_hl(config.sign_hl or decorations.sign_hl),
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ " ",
+ utils.set_hl(config.border_hl)
+ }
+ }
+ });
+
+ if not item.info_string then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + #delims[1], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(config.pad_char or " ", avail_top + 2),
+ utils.set_hl(config.border_hl)
+ },
+ label
+ }
+ });
+ goto no_info;
+ end
+
+ local relative_y = conceal_to - info_range[2];
+ local info_width = #item.info_string - relative_y;
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, info_range[1], info_range[2], {
+ undo_restore = false, invalidate = true,
+
+ end_row = info_range[3],
+ end_col = range.col_start + #item.text[1],
+
+ hl_group = utils.set_hl(config.info_hl or config.border_hl)
+ });
+
+ if info_width >= avail_top then
+ --- Exceeds.
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, conceal_to + avail_top, {
+ undo_restore = false, invalidate = true,
+
+ end_col = info_range[4],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { "โฆ", utils.set_hl(config.info_hl or config.border_hl) },
+ { " ", utils.set_hl(config.border_hl) },
+ label
+ }
+ });
+ else
+ local spaces = avail_top - info_width + 2;
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + #item.text[1], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(config.pad_char or " ", spaces),
+ utils.set_hl(config.border_hl)
+ },
+ label
+ }
+ });
+ end
+
+ ::no_info::
+ ---_
+ end
+
+ --- Line padding
+ for l, width in ipairs(line_widths) do
+ ---+${lua}
+
+ local line = item.text[l + 1];
+ local line_config = get_line_config(line);
+
+ if width ~= 0 then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + l, line ~= "" and range.col_start or 0, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", pad_amount),
+ utils.set_hl(line_config.pad_hl)
+ }
+ },
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + l, range.col_start + #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", block_width - (( 2 * pad_amount) + width)),
+ utils.set_hl(line_config.block_hl)
+ },
+ {
+ string.rep(" ", pad_amount),
+ utils.set_hl(line_config.pad_hl)
+ }
+ },
+ });
+
+ --- Background
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + l, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #line,
+
+ hl_group = utils.set_hl(line_config.block_hl)
+ });
+ else
+ local buf_line = vim.api.nvim_buf_get_lines(buffer, range.row_start + l, range.row_start + l + 1, false)[1];
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + l, #buf_line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", range.col_start - #buf_line)
+ },
+ {
+ string.rep(" ", pad_amount),
+ utils.set_hl(line_config.pad_hl)
+ },
+ {
+ string.rep(" ", block_width - (2 * pad_amount)),
+ utils.set_hl(line_config.block_hl)
+ },
+ {
+ string.rep(" ", pad_amount),
+ utils.set_hl(line_config.pad_hl)
+ },
+ },
+ });
+ end
+ ---_
+ end
+
+ --- Render bottom
+ if item.text[#item.text] ~= "" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, (range.col_start + #item.text[#item.text]) - #delims[2], {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #item.text[#item.text],
+ conceal = ""
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start + #item.text[#item.text], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", block_width),
+ utils.set_hl(config.border_hl)
+ }
+ }
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", block_width),
+ utils.set_hl(config.border_hl)
+ }
+ }
+ });
+ end
+ ---_
+ end
+
+ if config.style == "simple" or ( vim.o.wrap == true or vim.wo[win].wrap == true ) then
+ render_simple();
+ elseif config.style == "block" then
+ render_block()
+ end
+ ---_
+end
+
+--- Renders horizontal rules/line breaks.
+---@param buffer integer
+---@param item __markdown.horizontal_rules
+markdown.hr = function (buffer, item)
+ ---+${func, Horizontal rules}
+
+ ---@type markdown.horizontal_rules?
+ local config = spec.get({ "markdown", "horizontal_rules" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ local virt_text = {};
+ local function val(opt, index, wrap)
+ if vim.islist(opt) == false then
+ return opt;
+ elseif #opt < index then
+ if wrap == true then
+ local mod = index % #opt;
+ return mod == 0 and opt[#opt] or opt[mod];
+ else
+ return opt[#opt];
+ end
+ elseif index < 0 then
+ return opt[1];
+ end
+
+ return opt[index];
+ end
+
+ for _, part in ipairs(config.parts) do
+ if part.type == "text" then
+ table.insert(virt_text, { part.text, utils.set_hl(part.hl --[[ @as string ]]) });
+ elseif part.type == "repeating" then
+ local rep = spec.get({ "repeat_amount" }, { source = part, fallback = 1, eval_args = { buffer, item } });
+ local hl_rep = spec.get({ "repeat_hl" }, { source = part, fallback = false, eval_args = { buffer, item } });
+ local txt_rep = spec.get({ "repeat_text" }, { source = part, fallback = false, eval_args = { buffer, item } });
+
+ for r = 1, rep, 1 do
+ if part.direction == "right" then
+ table.insert(virt_text, {
+ val(part.text, (rep - r) + 1, txt_rep),
+ val(part.hl, (rep - r) + 1, hl_rep)
+ });
+ else
+ table.insert(virt_text, {
+ val(part.text, r, txt_rep),
+ val(part.hl, r, hl_rep)
+ });
+ end
+ end
+ end
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, 0, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "overlay",
+ virt_text = virt_text,
+
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+--- Renders reference link definitions.
+---@param buffer integer
+---@param item __markdown.reference_definitions
+markdown.link_ref_definition = function (buffer, item)
+ ---+${func}
+
+ ---@type markdown.reference_definitions?
+ local main_config = spec.get({ "markdown", "reference_definitions" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic_static?
+ local config = utils.match(
+ main_config,
+ item.description or "",
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if not config then
+ return;
+ end
+
+ local r_label = range.label;
+
+ ---+${class}
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, r_label[1], r_label[2], {
+ undo_restore = false, invalidate = true,
+ end_col = r_label[2] + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, r_label[1], r_label[2], {
+ undo_restore = false, invalidate = true,
+ end_row = r_label[3],
+ end_col = r_label[4],
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, r_label[3], r_label[4] - 1, {
+ undo_restore = false, invalidate = true,
+ end_row = r_label[3],
+ end_col = r_label[4],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ --_
+ ---_
+end
+
+--- Renders list items
+---@param buffer integer
+---@param item __markdown.list_items
+markdown.list_item = function (buffer, item)
+ ---+${func, Renders List items}
+
+ ---@type markdown.list_items?
+ local main_config = spec.get({ "markdown", "list_items" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type list_items.ordered | list_items.unordered
+ local config;
+ local shift_width, indent_size = main_config.shift_width or 1, main_config.indent_size or 1;
+
+ if item.marker == "-" then
+ config = spec.get({ "marker_minus" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ elseif item.marker == "+" then
+ config = spec.get({ "marker_plus" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ elseif item.marker == "*" then
+ config = spec.get({ "marker_star" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ elseif item.marker:match("%d+%.") then
+ config = spec.get({ "marker_dot" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ elseif item.marker:match("%d+%)") then
+ config = spec.get({ "marker_parenthesis" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ end
+
+ if not config then
+ return;
+ end
+
+ if config.add_padding then
+ for _, l in ipairs(item.candidates) do
+ local from, to = range.col_start, range.col_start + item.indent;
+
+ if item.text[l + 1]:len() < to then
+ to = from;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + l, from, {
+ undo_restore = false, invalidate = true,
+ end_col = to,
+ conceal = "",
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", (math.ceil(item.indent / indent_size) + 1) * shift_width) }
+ }
+ });
+ end
+ end
+
+ --- Evaluation arguments for checkboxes.
+ --- Used for turning function values into static values.
+ local chk_args = {
+ buffer,
+ {
+ class = "inline_checkbox",
+
+ text = item.checkbox,
+ range = nil
+ }
+ };
+
+ --- Gets checkbox state
+ ---@param state string?
+ ---@return checkboxes.opts?
+ local function get_state (state)
+ local checkboxes = spec.get({ "markdown_inline", "checkboxes" }, { fallback = nil });
+
+ if state == nil or checkboxes == nil then
+ return;
+ end
+
+ if state == "x" or state == "X" then
+ return spec.get({ "checked" }, { source = checkboxes, eval_args = chk_args });
+ elseif state == " " then
+ return spec.get({ "unchecked" }, { source = checkboxes, eval_args = chk_args });
+ end
+
+ local _state = utils.escape_string(state) or "";
+ return utils.match(checkboxes, "^" .. _state .. "$", { default = false, ignore_keys = { "checked", "unchecked", "enable" }, eval_args = chk_args });
+ end
+
+ local checkbox = get_state(item.checkbox);
+
+ if checkbox and config.conceal_on_checkboxes == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + (item.indent + #item.marker + 1),
+ conceal = ""
+ });
+
+ if not checkbox.scope_hl then
+ goto exit;
+ end
+
+ for l, line in ipairs(item.text) do
+ if l == 1 then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + (item.indent + #item.marker + 5), {
+ undo_restore = false, invalidate = true,
+ end_col = #item.text[1],
+
+ hl_group = utils.set_hl(checkbox.scope_hl)
+ });
+ elseif line ~= "" then
+ local spaces = line:match("^([%>%s]*)");
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + (l - 1), #spaces, {
+ undo_restore = false, invalidate = true,
+ end_col = #item.text[l],
+
+ hl_group = utils.set_hl(checkbox.scope_hl)
+ });
+ end
+ end
+ elseif item.marker:match("[%+%-%*]") then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + (item.indent + #item.marker),
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.text, utils.set_hl(config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ end
+
+ ::exit::
+
+ ---@type integer, integer Start & end fold level.
+ local foldlevel_s, foldlevel_e;
+
+ vim.api.nvim_buf_call(buffer, function ()
+ foldlevel_s = vim.fn.foldlevel(range.row_start + 1);
+ foldlevel_e = vim.fn.foldlevel(range.row_end + 1);
+ end)
+
+ if foldlevel_s ~= 0 or foldlevel_e ~= 0 then
+ --- Text was folded.
+ return;
+ end
+
+ local win = utils.buf_getwin(buffer);
+
+ --- BUG, Post-processing effects become inaccurate when
+ --- list items are inside block quotes.
+ if main_config.wrap == true and vim.wo[win].wrap == true then
+ --- When `wrap` is enabled, run post-processing effects.
+ table.insert(markdown.cache, item);
+ end
+ ---_
+end
+
+--- Renders metadatas.
+---@param buffer integer
+---@param item __markdown.metadata_minus
+markdown.metadata_minus = function (buffer, item)
+ ---+${func, Renders YAML metadata blocks}
+
+ ---@type markdown.metadata_minus_static?
+ local config = spec.get({ "markdown", "metadata_minus" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, 0, {
+ undo_restore = false, invalidate = true,
+ end_col = #item.text[1],
+ conceal = "",
+
+ virt_text_pos = "overlay",
+ virt_text = config.border_top and {
+ {
+ string.rep(
+ config.border_top,
+ vim.api.nvim_win_get_width(
+ utils.buf_getwin(buffer)
+ )
+ ),
+ utils.set_hl(config.border_top_hl or config.border_hl or config.hl)
+ }
+ } or nil
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, 0, {
+ undo_restore = false, invalidate = true,
+ end_col = #item.text[#item.text],
+ conceal = "",
+
+ virt_text_pos = "overlay",
+ virt_text = config.border_bottom and {
+ {
+ string.rep(
+ config.border_bottom,
+ vim.api.nvim_win_get_width(
+ utils.buf_getwin(buffer)
+ )
+ ),
+ utils.set_hl(config.border_bottom_hl or config.border_hl or config.hl)
+ }
+ } or nil
+ });
+
+ if not config.hl then return; end
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + 1, 0, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end - 1,
+
+ line_hl_group = utils.set_hl(config.hl)
+ });
+ ---_
+end
+
+--- Renders + metadatas.
+---@param buffer integer
+---@param item __markdown.metadata_plus
+markdown.metadata_plus = function (buffer, item)
+ ---+${func, Renders TOML metadata blocks}
+
+ ---@type markdown.metadata_plus_static?
+ local config = spec.get({ "markdown", "metadata_plus" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, 0, {
+ undo_restore = false, invalidate = true,
+ end_col = #item.text[1],
+ conceal = "",
+
+ virt_text_pos = "overlay",
+ virt_text = config.border_top and {
+ {
+ string.rep(
+ config.border_top,
+ vim.api.nvim_win_get_width(
+ utils.buf_getwin(buffer)
+ )
+ ),
+ utils.set_hl(config.border_top_hl or config.border_hl or config.hl)
+ }
+ } or nil
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, 0, {
+ undo_restore = false, invalidate = true,
+ end_col = #item.text[#item.text],
+ conceal = "",
+
+ virt_text_pos = "overlay",
+ virt_text = config.border_bottom and {
+ {
+ string.rep(
+ config.border_bottom,
+ vim.api.nvim_win_get_width(
+ utils.buf_getwin(buffer)
+ )
+ ),
+ utils.set_hl(config.border_bottom_hl or config.border_hl or config.hl)
+ }
+ } or nil
+ });
+
+ if not config.hl then return; end
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + 1, 0, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end - 1,
+
+ line_hl_group = utils.set_hl(config.hl)
+ });
+ ---_
+end
+
+--- Render org mode like section indentations.
+---@param buffer integer
+---@param item __markdown.sections
+markdown.section = function (buffer, item)
+ ---+${lua}
+
+ ---@type markdown.headings?
+ local main_config = spec.get({ "markdown", "headings" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if main_config == nil then
+ return;
+ elseif main_config.org_indent ~= true then
+ --- Org indent mode disabled.
+ return;
+ end
+
+ local shift_width = main_config.org_shift_width or main_config.shift_width or 0;
+ local shift_char = main_config.org_shift_char or " ";
+
+ local range = item.range;
+
+ for l = range.row_start + 1, range.row_end do
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(shift_char, shift_width * (item.level - 1)) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+
+ ---@type integer, integer Start & end fold level.
+ local foldlevel_s, foldlevel_e;
+
+ vim.api.nvim_buf_call(buffer, function ()
+ foldlevel_s = vim.fn.foldlevel(range.row_start + 1);
+ foldlevel_e = vim.fn.foldlevel(range.row_end + 1);
+ end)
+
+ if foldlevel_s ~= 0 or foldlevel_e ~= 0 then
+ --- Text was folded.
+ return;
+ end
+
+ local win = utils.buf_getwin(buffer);
+
+ if main_config.org_indent_wrap == true and vim.wo[win].wrap == true then
+ --- When `wrap` is enabled, run post-processing effects.
+ table.insert(markdown.cache, item);
+ end
+ ---_
+end
+
+--- Renders setext headings.
+---@param buffer integer
+---@param item __markdown.setext
+markdown.setext_heading = function (buffer, item)
+ ---+${func, Renders Setext headings}
+
+ ---@type markdown.headings?
+ local main_config = spec.get({ "markdown", "headings" }, { fallback = nil, eval_args = { buffer, item } });
+ local lvl = item.marker:match("%=") and 1 or 2;
+
+ if not main_config then
+ return;
+ elseif not spec.get({ "setext_" .. lvl }, { source = main_config }) then
+ return;
+ end
+
+ ---@type headings.setext
+ local config = spec.get({ "setext_" .. lvl }, { source = main_config });
+ local range = item.range;
+
+ if config.style == "simple" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ sign_text = config.sign,
+ sign_hl_group = utils.set_hl(config.sign_hl),
+ end_row = range.row_end,
+ end_col = range.col_end,
+ line_hl_group = utils.set_hl(config.hl)
+ });
+ elseif config.style == "decorated" then
+ if config.icon then
+ for l = 1, (range.row_end - range.row_start) - 1 do
+ local line = item.text[l];
+
+ if
+ math.floor((range.row_end - range.row_start) / 2) == 0 or
+ l == math.floor((range.row_end - range.row_start) / 2)
+ then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + (l - 1), math.min(#line, range.col_start), {
+ undo_restore = false, invalidate = true,
+ sign_text = config.sign,
+ sign_hl_group = utils.set_hl(config.sign_hl),
+ line_hl_group = utils.set_hl(config.hl),
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ config.icon,
+ utils.set_hl(config.icon_hl or config.hl)
+ }
+ },
+
+ hl_mode = "combine",
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + (l - 1), math.min(#line, range.col_start), {
+ undo_restore = false, invalidate = true,
+ line_hl_group = utils.set_hl(config.hl),
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", vim.fn.strdisplaywidth(config.icon)),
+ utils.set_hl(config.icon_hl or config.hl)
+ }
+ },
+
+ hl_mode = "combine",
+ });
+ end
+ end
+ end
+
+ if config.border then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end - 1,
+ end_col = range.col_end,
+ line_hl_group = utils.set_hl(config.hl),
+ virt_text_pos = "overlay",
+ virt_text = {
+ {
+ string.rep(config.border, vim.o.columns),
+ utils.set_hl(config.border_hl or config.hl)
+ }
+ },
+
+ hl_mode = "combine",
+ });
+ end
+ end
+ ---_
+end
+
+--- Renders tables.
+---@param buffer integer
+---@param item __markdown.tables
+markdown.table = function (buffer, item)
+ ---+${func, Renders Tables}
+
+ ---@type markdown.tables_static?
+ local config = spec.get({ "markdown", "tables" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ local is_wrapped = false;
+
+ if not config then
+ return;
+ else
+ local win = utils.buf_getwin(buffer);
+
+ if type(win) ~= "number" then
+ --- Window doesn't exist.
+ return;
+ elseif vim.wo[win].wrap == true then
+ --- BUG, wrap breaks table rendering.
+ is_wrapped = true;
+ end
+
+ local left_col;
+
+ vim.api.nvim_win_call(win, function ()
+ --- TODO, Find a more performant way to
+ --- get this value.
+ left_col = vim.fn.winsaveview().leftcol;
+ end)
+
+ if type(left_col) == "number" and left_col > range.col_start then
+ return;
+ end
+ end
+
+ ---@type integer[] Visible column widths(may be inaccurate).
+ local col_widths = {};
+
+ --- Holds text for the different table cells.
+ ---
+ ---@type { header: string[], rows: string[][] }
+ local visible_texts = {
+ header = {},
+ rows = {}
+ };
+
+ ---@type integer[] Invisible width used for text wrapping in Neovim.
+ local vim_width = {};
+
+ ---+${custom, Get the width of the column(s)}
+
+ ---@type integer Current column number.
+ local c = 1;
+
+ markdown.__new_config();
+
+ ---+${custom, Calculate heading column widths}
+ for _, col in ipairs(item.header) do
+ if col.class == "column" then
+ local o, dec = markdown.output(col.text, buffer);
+
+ o = vim.fn.strdisplaywidth(o);
+ table.insert(visible_texts.header, o);
+
+ if not col_widths[c] or col_widths[c] < o then
+ col_widths[c] = o;
+ end
+
+ local vim_col_width = vim.fn.strdisplaywidth(col.text) + (dec or 0);
+
+ if not vim_width[c] then
+ vim_width[c] = vim_col_width;
+ elseif vim_col_width > vim_width[c] then
+ vim_width[c] = vim_col_width;
+ end
+
+ c = c + 1;
+ end
+ end
+ ---_
+
+ ---+${custom, Calculate separator column widths}
+ c = 1;
+
+ for _, col in ipairs(item.separator) do
+ if col.class == "column" then
+ local o = vim.fn.strdisplaywidth(col.text);
+
+ if not col_widths[c] or col_widths[c] < o then
+ col_widths[c] = o;
+ end
+
+ local vim_col_width = vim.fn.strdisplaywidth(col.text);
+
+ if not vim_width[c] then
+ vim_width[c] = vim_col_width;
+ elseif vim_col_width > vim_width[c] then
+ vim_width[c] = vim_col_width;
+ end
+
+ c = c + 1;
+ end
+ end
+ ---_
+
+ ---+${custom, Calculate various row's column widths}
+ for r, row in ipairs(item.rows) do
+ c = 1;
+ table.insert(visible_texts.rows, {})
+
+ for _, col in ipairs(row) do
+ if col.class == "column" then
+ local o, dec = markdown.output(col.text, buffer);
+
+ o = vim.fn.strdisplaywidth(o);
+ table.insert(visible_texts.rows[r], o);
+
+ if not col_widths[c] or col_widths[c] < o then
+ col_widths[c] = o;
+ end
+
+ local vim_col_width = vim.fn.strdisplaywidth(col.text) + (dec or 0);
+
+ if not vim_width[c] then
+ vim_width[c] = vim_col_width;
+ elseif vim_col_width > vim_width[c] then
+ vim_width[c] = vim_col_width;
+ end
+
+ c = c + 1;
+ end
+ end
+ end
+ ---_
+ ---_
+
+ if is_wrapped == true then
+ ---+${lua}
+
+ local win = utils.buf_getwin(buffer);
+ local width = vim.api.nvim_win_get_width(win);
+
+ local table_width = 1;
+
+ for _, col in ipairs(vim_width) do
+ table_width = table_width + 1 + col;
+ end
+
+ if table_width >= width * 0.9 then
+ --- Most likely the text was wrapped somewhere.
+ --- TODO, Check if a more accurate(& faster) method exists or not.
+ return;
+ end
+
+ ---_
+ end
+
+ ---@type tables.parts
+ local parts = config.parts;
+ ---@type tables.parts
+ local hls = config.hl;
+
+ local function get_border(from, index)
+ if not parts or not parts[from] then
+ return "", nil;
+ end
+
+ local hl;
+
+ if hls and hls[from] then
+ hl = hls[from][index];
+ end
+
+ return parts[from][index], hl;
+ end
+
+ local function bottom_part (index)
+ if config.block_decorator == true and
+ config.use_virt_lines == false and
+ item.border_overlap == true
+ then
+ return get_border("overlap", index)
+ end
+
+ return get_border("bottom", index)
+ end
+
+ c = 1;
+ local tmp = {};
+
+ for p, part in ipairs(item.header) do
+ if part.class == "separator" then
+ ---+${custom, Handle | in the header}
+ local border, border_hl = get_border("header", 2);
+ local top, top_hl = get_border("top", 4);
+
+ if p == 1 then
+ border, border_hl = get_border("header", 1);
+ top, top_hl = get_border("top", 1);
+ elseif p == #item.header then
+ border, border_hl = get_border("header", 3);
+ top, top_hl = get_border("top", 3);
+ end
+
+ table.insert(tmp, {
+ top,
+ is_wrapped and "@punctuation.special.markdown" or utils.set_hl(top_hl)
+ });
+
+ if is_wrapped == false then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + part.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { border, utils.set_hl(border_hl) }
+ },
+
+ hl_mode = "combine"
+ })
+ end
+
+
+ if p == #item.header and config.block_decorator == true then
+ local prev_line = range.row_start == 0 and 0 or #vim.api.nvim_buf_get_lines(buffer, range.row_start - 1, range.row_start, false)[1];
+
+ if config.use_virt_lines == true then
+ table.insert(tmp, 1, { string.rep(" ", range.col_start) });
+ elseif range.row_start > 0 and prev_line < range.col_start then
+ table.insert(tmp, 1, { string.rep(" ", range.col_start - prev_line) });
+ end
+
+ if config.use_virt_lines == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_lines_above = true,
+ virt_lines = { tmp },
+
+ hl_mode = "combine"
+ })
+ elseif item.top_border == true and range.row_start > 0 then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start - 1, math.min(range.col_start, prev_line), {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = tmp,
+
+ hl_mode = "combine"
+ })
+ end
+ end
+ ---_
+ elseif part.class == "missing_seperator" then
+ ---+${custom, Handle missing last |}
+ local border, border_hl = get_border("header", 3);
+ local top, top_hl = get_border("top", 3);
+
+ table.insert(tmp, {
+ top,
+ is_wrapped and "@punctuation.special.markdown" or utils.set_hl(top_hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + part.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ border,
+ is_wrapped and "@punctuation.special.markdown" or utils.set_hl(border_hl)
+ }
+ },
+
+ hl_mode = "combine"
+ })
+
+ if p == #item.header and config.block_decorator == true then
+ local prev_line = range.row_start == 0 and 0 or #vim.api.nvim_buf_get_lines(buffer, range.row_start - 1, range.row_start, false)[1];
+
+ if config.use_virt_lines == true then
+ table.insert(tmp, 1, {
+ string.rep(" ", range.col_start)
+ });
+ elseif range.row_start > 0 and prev_line < range.col_start then
+ table.insert(tmp, 1, {
+ string.rep(" ", range.col_start - prev_line)
+ });
+ end
+
+ if config.use_virt_lines == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_lines_above = true,
+ virt_lines = { tmp },
+
+ hl_mode = "combine"
+ })
+ elseif range.row_start > 0 and item.top_border == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start - 1, math.min(prev_line, range.col_start), {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = tmp,
+
+ hl_mode = "combine"
+ })
+ end
+ end
+ ---_
+ elseif part.class == "column" then
+ ---+${custom, Handle columns of text inside the header}
+ local visible_width = visible_texts.header[c];
+ local column_width = col_widths[c];
+
+ local top, top_hl = get_border("top", 2);
+
+ table.insert(tmp, {
+ string.rep(top, column_width),
+ is_wrapped and "@punctuation.special.markdown" or utils.set_hl(top_hl)
+ });
+
+ if visible_width < column_width then
+ if item.alignments[c] == "default" or item.alignments[c] == "left" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + part.col_end, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", column_width - visible_width) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ elseif item.alignments[c] == "right" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", column_width - visible_width) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", math.ceil((column_width - visible_width) / 2)) }
+ },
+
+ right_gravity = true,
+ hl_mode = "combine"
+ });
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start, range.col_start + part.col_end, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", math.floor((column_width - visible_width) / 2)) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+ end
+
+ c = c + 1;
+ ---_
+ end
+ end
+
+ c = 1;
+
+ for s, sep in ipairs(item.separator) do
+ local x = range.row_start + 1;
+ local y = range.col_start + sep.col_start;
+
+ if sep.class == "separator" then
+ ---+${custom, Handle | in the header}
+
+ if is_wrapped == true then
+ goto continue;
+ end
+
+ local border, border_hl = get_border("separator", 4);
+
+ if s == 1 then
+ border, border_hl = get_border("separator", 1);
+ elseif s == #item.separator then
+ border, border_hl = get_border("separator", 3);
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { border, utils.set_hl(border_hl) }
+ },
+
+ hl_mode = "combine"
+ })
+ ---_
+ elseif sep.class == "missing_seperator" then
+ ---+${custom, Handle missing last |}
+ local border, border_hl = get_border("separator", 3);
+
+ if is_wrapped == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { "|", "@punctuation.special.markdown" }
+ },
+
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { border, utils.set_hl(border_hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ end
+ ---_
+ elseif sep.class == "column" then
+ local border, border_hl = get_border("separator", 2);
+ local align, align_hl;
+
+ local width = vim.fn.strdisplaywidth(sep.text);
+ local left = col_widths[c] - width;
+
+ if is_wrapped == true then
+ ---+${lua, Wrapping enabled}
+ if left > 0 then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, (range.col_start + sep.col_end) - 2, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep("-", left),
+ "@punctuation.special.markdown"
+ }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+ ---_
+ elseif item.alignments[c] == "default" then
+ ---+${custom, Normal columns}
+ if left > 0 then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ {
+ string.rep(border, width),
+ utils.set_hl(border_hl)
+ },
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, range.col_start + sep.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(border, left), utils.set_hl(border_hl) },
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ {
+ string.rep(border, width),
+ utils.set_hl(border_hl)
+ }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+ ---_
+ elseif item.alignments[c] == "left" then
+ ---+${custom, Left aligned columns}
+ align = parts.align_left or "";
+ align_hl = hls.align_left;
+
+ if left > 0 then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ { align, utils.set_hl(align_hl) },
+ {
+ string.rep(border, width - 1),
+ utils.set_hl(border_hl)
+ },
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, range.col_start + sep.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(border, left), utils.set_hl(border_hl) },
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ { align, utils.set_hl(align_hl) },
+ {
+ string.rep(border, width - 1),
+ utils.set_hl(border_hl)
+ }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+ ---_
+ elseif item.alignments[c] == "right" then
+ ---+${custom, Right aligned columns}
+ align = parts.align_right or "";
+ align_hl = hls.align_right;
+
+ if left > 0 then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ {
+ string.rep(border, width),
+ utils.set_hl(border_hl)
+ },
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, range.col_start + sep.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(border, left - 1), utils.set_hl(border_hl) },
+ { align, utils.set_hl(align_hl) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ {
+ string.rep(border, width - 1),
+ utils.set_hl(border_hl)
+ },
+ { align, utils.set_hl(align_hl) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+ ---_
+ elseif item.alignments[c] == "center" then
+ ---+${custom, Center aligned columns}
+ align = parts.align_center or { "", "" };
+ align_hl = hls.align_center or {};
+
+ if left > 0 then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ { align[1], utils.set_hl(align_hl[1]) },
+ {
+ string.rep(border, width - 1),
+ utils.set_hl(border_hl)
+ },
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, range.col_start + sep.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(border, left - 1), utils.set_hl(border_hl) },
+ { align[2], utils.set_hl(align_hl[2]) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, x, y, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + sep.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ { align[1], utils.set_hl(align_hl[1]) },
+ {
+ string.rep(border, width - 2),
+ utils.set_hl(border_hl)
+ },
+ { align[2], utils.set_hl(align_hl[2]) },
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+ ---_
+ end
+
+ c = c + 1;
+ end
+
+ ::continue::
+ end
+
+ for r, row in ipairs(item.rows) do
+ if r == #item.rows then
+ break;
+ end
+
+ c = 1;
+
+ for _, part in ipairs(row) do
+ if part.class == "separator" then
+ ---+${custom, Handle | in the header}
+ local border, border_hl = get_border("row", 2);
+
+ if s == 1 then
+ border, border_hl = get_border("row", 1);
+ elseif s == #item.separator then
+ border, border_hl = get_border("row", 3);
+ end
+
+ if is_wrapped == false then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + 1 + r, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + part.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { border, utils.set_hl(border_hl) }
+ },
+
+ hl_mode = "combine"
+ })
+ end
+ ---_
+ elseif part.class == "missing_seperator" then
+ ---+${custom, Handle missing last |}
+ local border, border_hl = get_border("row", 3);
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + 1 + r, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ is_wrapped and {
+ "|",
+ "@punctuation.special.markdown"
+ } or {
+ border,
+ utils.set_hl(border_hl)
+ }
+ },
+
+ hl_mode = "combine"
+ })
+ ---_
+ elseif part.class == "column" then
+ ---+${custom, Handle columns of text inside the header}
+ local visible_width = visible_texts.rows[r][c];
+ local column_width = col_widths[c];
+
+ if visible_width < column_width then
+ if item.alignments[c] == "default" or item.alignments[c] == "left" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + (r + 1), range.col_start + part.col_end, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", column_width - visible_width) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ elseif item.alignments[c] == "right" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + (r + 1), range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", column_width - visible_width) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + (r + 1), range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", math.ceil((column_width - visible_width) / 2)) }
+ },
+
+ right_gravity = true,
+ hl_mode = "combine"
+ });
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + (r + 1), range.col_start + part.col_end, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", math.floor((column_width - visible_width) / 2)) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+ end
+
+ c = c + 1;
+ ---_
+ end
+ end
+ end
+
+ c = 1;
+ tmp = {};
+
+ for p, part in ipairs(item.rows[#item.rows] or {}) do
+ if part.class == "separator" then
+ ---+${custom, Handle | in the header}
+ local border, border_hl = get_border("row", 2);
+ local bottom, bottom_hl = bottom_part(4);
+
+ if p == 1 then
+ border, border_hl = get_border("row", 1);
+ bottom, bottom_hl = bottom_part(1);
+ elseif p == #item.header then
+ border, border_hl = get_border("row", 3);
+ bottom, bottom_hl = bottom_part(3);
+ end
+
+ table.insert(tmp, {
+ bottom,
+ is_wrapped and "@punctuation.special.markdown" or utils.set_hl(bottom_hl)
+ });
+
+ if is_wrapped == false then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + part.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { border, utils.set_hl(border_hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ end
+
+ if p == #item.header and config.block_decorator == true then
+ local next_line = range.row_end == vim.api.nvim_buf_line_count(buffer) and 0 or #vim.api.nvim_buf_get_lines(buffer, range.row_end, range.row_end + 1, false)[1];
+
+ if config.use_virt_lines == true then
+ table.insert(tmp, 1, { string.rep(" ", range.col_start) });
+ elseif next_line < vim.api.nvim_buf_line_count(buffer) and next_line < range.col_start then
+ table.insert(tmp, 1, { string.rep(" ", range.col_start - next_line) });
+ end
+
+ if config.use_virt_lines == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end, math.min(next_line, range.col_start), {
+ virt_lines_above = true,
+ virt_lines = { tmp },
+
+ hl_mode = "combine"
+ })
+ elseif range.row_end <= vim.api.nvim_buf_line_count(buffer) and item.bottom_border == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end, math.min(next_line, range.col_start), {
+ virt_text_pos = "inline",
+ virt_text = tmp,
+
+ hl_mode = "combine"
+ })
+ end
+ end
+ ---_
+ elseif part.class == "missing_seperator" then
+ ---+${custom, Handle missing last |}
+ local border, border_hl = get_border("row", 3);
+ local bottom, bottom_hl = bottom_part(3);
+
+ table.insert(tmp, { bottom, utils.set_hl(bottom_hl) });
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + part.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { border, utils.set_hl(border_hl) }
+ },
+
+ hl_mode = "combine"
+ })
+
+ if p == #item.header and config.block_decorator == true then
+ local next_line = range.row_end == vim.api.nvim_buf_line_count(buffer) and 0 or #vim.api.nvim_buf_get_lines(buffer, range.row_end, range.row_end + 1, false)[1];
+
+ if config.use_virt_lines == true then
+ table.insert(tmp, 1, { string.rep(" ", range.col_start) });
+ elseif next_line < vim.api.nvim_buf_line_count(buffer) and next_line < range.col_start then
+ table.insert(tmp, 1, { string.rep(" ", range.col_start - next_line) });
+ end
+
+ if config.use_virt_lines == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end, math.min(next_line, range.col_start), {
+ virt_lines_above = true,
+ virt_lines = { tmp },
+
+ hl_mode = "combine"
+ })
+ elseif range.row_end <= vim.api.nvim_buf_line_count(buffer) and item.bottom_border == true then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end, math.min(next_line, range.col_start), {
+ virt_text_pos = "inline",
+ virt_text = tmp,
+
+ hl_mode = "combine"
+ })
+ end
+ end
+ ---_
+ elseif part.class == "column" then
+ ---+${custom, Handle columns of text inside the last row}
+ local visible_width = visible_texts.rows[#visible_texts.rows][c];
+ local column_width = col_widths[c];
+
+ local bottom, bottom_hl = bottom_part(2);
+
+ table.insert(tmp, {
+ string.rep(bottom, column_width),
+ is_wrapped and "@punctuation.special.markdown" or utils.set_hl(bottom_hl)
+ });
+
+ if visible_width < column_width then
+ if item.alignments[c] == "default" or item.alignments[c] == "left" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start + part.col_end, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", column_width - visible_width) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ elseif item.alignments[c] == "right" then
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", column_width - visible_width) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start + part.col_start, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", math.ceil((column_width - visible_width) / 2)) }
+ },
+
+ right_gravity = true,
+ hl_mode = "combine"
+ });
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_end - 1, range.col_start + part.col_end, {
+ undo_restore = false, invalidate = true,
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", math.floor((column_width - visible_width) / 2)) }
+ },
+
+ right_gravity = false,
+ hl_mode = "combine"
+ });
+ end
+ end
+
+ c = c + 1;
+ ---_
+ end
+ end
+ ---_
+end
+
+
+ -----------------------------------------------------------------------------------------
+
+
+--- Places where the list items were wrapped.
+---@type { [integer]: integer[] }
+markdown.__list_wraps = {};
+
+local get_extmark = function (buffer, lnum, col)
+ local extmarks = vim.api.nvim_buf_get_extmarks(buffer, markdown.ns, { lnum, col }, { lnum, col + 1 }, {
+ details = true,
+ type = "virt_text"
+ });
+
+ return extmarks[1];
+end
+
+local register_wrap = function (lnum, col)
+ if vim.islist(markdown.__list_wraps[lnum]) == false then
+ markdown.__list_wraps[lnum] = {};
+ end
+
+ table.insert(markdown.__list_wraps[lnum], col);
+end
+
+local has_wrap = function (lnum, col)
+ if vim.islist(markdown.__list_wraps[lnum]) == false then
+ return false;
+ else
+ return vim.list_contains(markdown.__list_wraps[lnum], col);
+ end
+end
+
+--- Renders wrapped block quotes, callouts & alerts.
+---@param buffer integer
+---@param item __markdown.block_quotes
+markdown.__block_quote = function (buffer, item)
+ ---+${func, Post renderer for wrapped block quotes}
+
+ ---@type markdown.block_quotes?
+ local main_config = spec.get({ "markdown", "block_quotes" }, { fallback = nil });
+ ---@type string[]
+ local keys = vim.tbl_keys(main_config);
+ local range = item.range;
+
+ if main_config == nil or not main_config.default then
+ return;
+ elseif
+ item.callout and
+ not vim.list_contains(keys, string.lower(item.callout)) and
+ not vim.list_contains(keys, string.upper(item.callout)) and
+ not vim.list_contains(keys, item.callout)
+ then
+ return;
+ end
+
+ local config;
+
+ if item.callout then
+ ---@type block_quotes.opts
+ config = spec.get(
+ { string.lower(item.callout) },
+ { source = main_config, eval_args = { buffer, item } }
+ ) or spec.get(
+ { string.upper(item.callout) },
+ { source = main_config, eval_args = { buffer, item } }
+ ) or spec.get(
+ { item.callout },
+ { source = main_config, eval_args = { buffer, item } }
+ );
+ else
+ ---@type block_quotes.opts
+ config = spec.get({ "default" }, { source = main_config, eval_args = { buffer, item } });
+ end
+
+ local win = utils.buf_getwin(buffer);
+
+ local width = vim.api.nvim_win_get_width(win);
+ local textoff = vim.fn.getwininfo(win)[1].textoff;
+ local winx = vim.api.nvim_win_get_position(win)[2];
+
+ for l = range.row_start, range.row_end - 1, 1 do
+ local l_index = (l - range.row_start) + 1;
+
+ local line = item.text[l_index];
+ local start = false;
+
+ if vim.fn.strdisplaywidth(line) <= width - textoff then
+ -- Lines that are too short should be skipped.
+ goto skip_line;
+ end
+
+ for c = 1, vim.fn.strdisplaywidth(line) do
+ --- `l` should be 1-indexed.
+ ---@type integer
+ local x = vim.fn.screenpos(win, l + 1, c).col - (winx + textoff);
+
+ if x == 1 then
+ if start == false then
+ start = true;
+ goto continue;
+ end
+
+ local extmark = get_extmark(buffer, l, c - 1);
+ register_wrap(l, c - 1);
+
+ if extmark ~= nil then
+ local id = extmark[1];
+ local virt_text = extmark[4].virt_text;
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, c - 1, {
+ id = id,
+
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = vim.list_extend(virt_text, {
+ { string.rep(" ", item.__nested and 0 or range.col_start) },
+ {
+ tbl_clamp(config.border, l_index),
+ utils.set_hl(tbl_clamp(config.border_hl, l_index) or config.hl)
+ },
+ { " " }
+ }),
+
+ hl_mode = "combine",
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, c - 1, {
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", item.__nested and 0 or range.col_start) },
+ {
+ tbl_clamp(config.border, l_index),
+ utils.set_hl(tbl_clamp(config.border_hl, l_index) or config.hl)
+ },
+ { " " }
+ },
+
+ hl_mode = "combine",
+ });
+ end
+ end
+
+ ::continue::
+ end
+
+ ::skip_line::
+ end
+ ---_
+end
+
+--- Renders wrapped block quotes, callouts & alerts.
+---@param buffer integer
+---@param item __markdown.list_items
+markdown.__list_item = function (buffer, item)
+ ---+${lua}
+
+ ---@type markdown.list_items?
+ local main_config = spec.get({ "markdown", "list_items" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type list_items.ordered | list_items.unordered
+ local config;
+ local shift_width, indent_size = main_config.shift_width or 1, main_config.indent_size or 1;
+
+ if item.marker == "-" then
+ config = spec.get({ "marker_minus" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ elseif item.marker == "+" then
+ config = spec.get({ "marker_plus" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ elseif item.marker == "*" then
+ config = spec.get({ "marker_star" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ elseif item.marker:match("%d+%.") then
+ config = spec.get({ "marker_dot" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ elseif item.marker:match("%d+%)") then
+ config = spec.get({ "marker_parenthesis" }, {
+ source = main_config,
+ eval_args = { buffer, item }
+ });
+ end
+
+ if config == nil then
+ return;
+ end
+
+ --- Evaluation arguments for checkboxes.
+ --- Used for turning function values into static values.
+ local chk_args = {
+ buffer,
+ {
+ class = "inline_checkbox",
+
+ text = item.checkbox,
+ range = nil
+ }
+ };
+
+ --- Gets checkbox state
+ ---@param state string?
+ ---@return checkboxes.opts?
+ local function get_state (state)
+ local checkboxes = spec.get({ "markdown_inline", "checkboxes" }, { fallback = nil });
+
+ if state == nil or checkboxes == nil then
+ return;
+ end
+
+ if state == "x" or state == "X" then
+ return spec.get({ "checked" }, { source = checkboxes, eval_args = chk_args });
+ elseif state == " " then
+ return spec.get({ "unchecked" }, { source = checkboxes, eval_args = chk_args });
+ end
+
+ return utils.match(checkboxes, state, { eval_args = chk_args });
+ end
+
+ local checkbox = get_state(item.checkbox);
+ local pad_width = (math.floor(item.indent / indent_size) + 1) * shift_width;
+
+ if config.conceal_on_checkboxes == true and checkbox and checkbox.text then
+ pad_width = pad_width + vim.fn.strdisplaywidth(checkbox.text);
+ else
+ pad_width = pad_width + vim.fn.strdisplaywidth(item.marker) + 1;
+ end
+
+ local win = utils.buf_getwin(buffer);
+
+ local width = vim.api.nvim_win_get_width(win);
+ local textoff = vim.fn.getwininfo(win)[1].textoff;
+ local winx = vim.api.nvim_win_get_position(win)[2];
+
+ for _, l in ipairs(item.candidates) do
+ local line = item.text[l + 1];
+ local start = false;
+
+ if vim.fn.strdisplaywidth(line) <= width - textoff then
+ -- Lines that are too short should be skipped.
+ goto skip_line;
+ end
+
+ for c = 1, vim.fn.strdisplaywidth(line) do
+ --- `l` should be 1-indexed.
+ ---@type integer
+ local x = vim.fn.screenpos(win, range.row_start + l + 1, c).col - (winx + textoff);
+
+ if x == 1 then
+ if start == false then
+ start = true;
+ goto continue;
+ end
+
+ local extmark = get_extmark(buffer, range.row_start + l, c - 1);
+ local has_space = has_wrap(range.row_start + l, c - 1);
+ -- register_wrap(range.row_start + l, c - 1);
+
+ if extmark ~= nil then
+ local id = extmark[1];
+ local virt_text = extmark[4].virt_text;
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + l, c - 1, {
+ id = id,
+
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = vim.list_extend(virt_text, {
+ { string.rep(" ", has_space and pad_width - 1 or pad_width) }
+ }),
+
+ hl_mode = "combine",
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, range.row_start + l, c - 1, {
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", has_space and pad_width - 1 or pad_width) }
+ },
+
+ hl_mode = "combine",
+ });
+ end
+ end
+
+ ::continue::
+ end
+
+ ::skip_line::
+ end
+ ---_
+end
+
+--- Renders wrapped block quotes, callouts & alerts.
+---@param buffer integer
+---@param item __markdown.sections
+markdown.__section = function (buffer, item)
+ ---+${lua}
+
+ ---@type markdown.headings?
+ local main_config = spec.get({ "markdown", "headings" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if main_config == nil then
+ return;
+ elseif main_config.org_indent ~= true then
+ --- Org indent mode disabled.
+ return;
+ end
+
+ local shift_width = main_config.org_shift_width or main_config.shift_width or 0;
+ local shift_char = main_config.org_shift_char or " ";
+
+ local win = utils.buf_getwin(buffer);
+
+ local width = vim.api.nvim_win_get_width(win);
+ local textoff = vim.fn.getwininfo(win)[1].textoff;
+ local winx = vim.api.nvim_win_get_position(win)[2];
+
+ local range = item.range;
+
+ for l = range.row_start, range.row_end, 1 do
+ local l_index = (l - range.row_start) + 1;
+
+ local line = item.text[l_index];
+ local start = false;
+
+ if vim.fn.strdisplaywidth(line) <= width - textoff then
+ -- Lines that are too short should be skipped.
+ goto skip_line;
+ end
+
+ for c = 1, vim.fn.strdisplaywidth(line) do
+ --- `l` should be 1-indexed.
+ ---@type integer
+ local x = vim.fn.screenpos(win, l + 1, c).col - (winx + textoff);
+
+ if x == 1 then
+ if start == false then
+ start = true;
+ goto continue;
+ end
+
+ local extmark = get_extmark(buffer, l, c - 1);
+ register_wrap(l, c - 1);
+
+ if extmark ~= nil then
+ local id = extmark[1];
+ local virt_text = extmark[4].virt_text;
+
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, c - 1, {
+ id = id,
+
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = vim.list_extend(virt_text, {
+ { string.rep(shift_char, shift_width * (item.level - 1)) }
+ }),
+
+ hl_mode = "combine",
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, c - 1, {
+ undo_restore = false, invalidate = true,
+ right_gravity = false,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(shift_char, shift_width * (item.level - 1)) }
+ },
+
+ hl_mode = "combine",
+ });
+ end
+ -- vim.api.nvim_buf_set_extmark(buffer, markdown.ns, l, c - 1, {
+ -- undo_restore = false, invalidate = true,
+ -- right_gravity = false,
+ --
+ -- virt_text_pos = "inline",
+ -- virt_text = {
+ -- { string.rep(shift_char, shift_width * (item.level - 1)) }
+ -- },
+ --
+ -- hl_mode = "combine",
+ -- });
+ end
+
+ ::continue::
+ end
+
+ ::skip_line::
+ end
+ ---_
+end
+
+ -----------------------------------------------------------------------------------------
+
+
+--- Renders markdown preview.
+---@param buffer integer
+---@param content table
+---@return table
+markdown.render = function (buffer, content)
+ markdown.cache = {};
+
+ local custom = spec.get({ "renderers" }, { fallback = {} });
+
+ for _, item in ipairs(content or {}) do
+ local success, err;
+
+ if custom[item.class] then
+ success, err = pcall(custom[item.class], buffer, item);
+ else
+ success, err = pcall(markdown[item.class:gsub("^markdown_", "")], buffer, item);
+ end
+
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = {
+ { " r/markdown.lua: ", "DiagnosticVirtualTextInfo" },
+ { " " },
+ { err, "DiagnosticError" }
+ }
+ });
+ end
+ end
+
+ return { markdown = markdown.cache };
+end
+
+--- Post-process effect renderer.
+---@param buffer integer
+---@param content table
+markdown.post_render = function (buffer, content)
+ markdown.__list_wraps = {};
+
+ local custom = spec.get({ "renderers" }, { fallback = {} });
+
+ for _, item in ipairs(content or {}) do
+ local success, err;
+
+ if custom[item.class] then
+ success, err = pcall(custom["__" .. item.class], markdown.ns, buffer, item);
+ else
+ success, err = pcall(markdown["__" .. item.class:gsub("^markdown_", "")], buffer, item);
+ end
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = {
+ { " r/markdown.lua: ", "DiagnosticVirtualTextInfo" },
+ { " " },
+ { err, "DiagnosticError" }
+ }
+ });
+ end
+ end
+end
+
+
+------------------------------------------------------------------------------------------
+
+--- Clears markdown previews.
+---@param buffer integer
+---@param from integer?
+---@param to integer?
+markdown.clear = function (buffer, from, to)
+ vim.api.nvim_buf_clear_namespace(buffer, markdown.ns, from or 0, to or -1);
+end
+
+return markdown;
diff --git a/lua/markview/renderers/markdown_inline.lua b/lua/markview/renderers/markdown_inline.lua
new file mode 100644
index 0000000..66852e5
--- /dev/null
+++ b/lua/markview/renderers/markdown_inline.lua
@@ -0,0 +1,1107 @@
+local inline = {};
+
+local spec = require("markview.spec");
+local utils = require("markview.utils");
+local entities = require("markview.entities");
+
+local symbols = require("markview.symbols");
+
+inline.ns = vim.api.nvim_create_namespace("markview/inline");
+
+--- Render checkbox.
+---@param buffer integer
+---@param item __inline.checkboxes
+inline.checkbox = function (buffer, item)
+ ---+${func, Renders Checkboxes}
+
+ ---@type inline.checkboxes?
+ local main_config = spec.get({ "markdown_inline", "checkboxes" }, { fallback = nil });
+
+ if not main_config then
+ return;
+ end
+
+ ---@type { text: string, hl: string?, scope_hl: string? }
+ local config;
+ local state = item.state or "";
+ local range = item.range;
+
+ if ( state == "X" or state == "x" ) and spec.get({ "checked" }, { source = main_config, eval_args = { buffer, item } }) then
+ config = spec.get({ "checked" }, { source = main_config, eval_args = { buffer, item } });
+ elseif state == " " and spec.get({ "unchecked" }, { source = main_config, eval_args = { buffer, item } }) then
+ config = spec.get({ "unchecked" }, { source = main_config, eval_args = { buffer, item } });
+ elseif spec.get({ state }, { source = main_config, eval_args = { buffer, item } }) then
+ config = spec.get({ state }, { source = main_config, eval_args = { buffer, item } });
+ else
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.text, utils.set_hl(config.hl) }
+ }
+ });
+ ---_
+end
+
+--- Render inline codes.
+---@param buffer integer
+---@param item __inline.inline_codes
+inline.code_span = function (buffer, item)
+ ---+${func, Render Inline codes}
+
+ ---@type config.inline_generic?
+ local config = spec.get({ "markdown_inline", "inline_codes" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start + 1, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end - 1,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ if range.row_start == range.row_end then
+ return;
+ end
+
+ for l, line in ipairs(item.text) do
+ if l == 1 then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start + (l - 1), range.col_start + #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ elseif l == #item.text then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start + (l - 1), 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start + (l - 1), 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start + (l - 1), #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ end
+ end
+ ---_
+end
+
+--- Render entity reference.
+---@param buffer integer
+---@param item __inline.entities
+inline.entity = function (buffer, item)
+ ---+${func, Renders Character entities}
+ local config = spec.get({ "markdown_inline", "entities" }, { fallback = nil });
+ local range = item.range;
+
+ if not config then
+ return;
+ elseif not entities.get(item.name) then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { entities.get(item.name), utils.set_hl(config.hl) }
+ }
+ });
+ ---_
+end
+
+--- Render escaped characters.
+---@param buffer integer
+---@param item __inline.escapes
+inline.escaped = function (buffer, item)
+ ---+${func, Render Escaped characters}
+
+ ---@type { enable: boolean }?
+ local config = spec.get({ "markdown_inline", "escapes" }, { fallback = nil });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = ""
+ });
+ ---_
+end
+
+--- Render footnotes.
+---@param buffer integer
+---@param item __inline.footnotes
+inline.footnote = function (buffer, item)
+ ---+${func}
+
+ ---@type inline.footnotes?
+ local main_config = spec.get({ "markdown_inline", "footnotes" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic?
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if config == nil then
+ return;
+ end
+
+ ---+${custom, Draw the parts for the autolinks}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 2,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+ ---_
+end
+
+--- Render ==highlights==.
+---@param buffer integer
+---@param item __inline.highlights
+inline.highlight = function (buffer, item)
+ ---+${func, Render Email links}
+
+ ---@type inline.highlights?
+ local main_config = spec.get({ "markdown_inline", "highlights" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic?
+ local config = utils.match(
+ main_config,
+ table.concat(item.text, "\n"),
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if config == nil then
+ return;
+ end
+
+ ---+${custom, Draw the parts for the email}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 2,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start + 2, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end - 2,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_end - 2, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+ ---_
+end
+
+--- Renders :emojis:.
+---@param buffer integer
+---@param item __inline.emojis
+inline.emoji = function (buffer, item)
+ ---+${lua}
+
+ local config = spec.get({ "markdown_inline", "emoji_shorthands" }, { fallback = nil });
+ local range = item.range;
+
+ if not config then
+ return;
+ elseif not symbols.shorthands[item.name] then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { symbols.shorthands[item.name], utils.set_hl(config.hl) }
+ }
+ });
+ ---_
+end
+
+--- Render [[#^block_references]].
+---@param buffer integer
+---@param item __inline.block_references
+inline.link_block_ref = function (buffer, item)
+ ---+${func, Render Obsidian's block reference links}
+
+ ---@type inline.block_references?
+ local main_config = spec.get({ "markdown_inline", "block_references" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic?
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if not config then
+ return;
+ end
+
+ ---+${custom, Draw the parts for the embed file links}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.label[2],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ if config.file_hl and vim.islist(range.file) then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.file[1], range.file[2], {
+ undo_restore = false, invalidate = true,
+ end_row = range.file[3],
+ end_col = range.file[4],
+ hl_group = utils.set_hl(config.file_hl)
+ });
+ end
+
+ if config.block_hl and vim.islist(range.block) then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.block[1], range.block[2], {
+ undo_restore = false, invalidate = true,
+ end_row = range.block[3],
+ end_col = range.block[4],
+ hl_group = utils.set_hl(config.block_hl)
+ });
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, vim.islist(range.alias) and range.alias[4] or (range.col_end - 2), {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+ ---_
+end
+
+--- Render ![[embed_files]].
+---@param buffer integer
+---@param item __inline.embed_files
+inline.link_embed_file = function (buffer, item)
+ ---+${func, Render Obsidian's embed file links}
+
+ ---@type inline.embed_files?
+ local main_config = spec.get({ "markdown_inline", "embed_files" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ ---+${custom, Draw the parts for the embed file links}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 2,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_end - 2, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+ ---_
+end
+
+--- Render .
+---@param buffer integer
+---@param item __inline.emails
+inline.link_email = function (buffer, item)
+ ---+${func, Render Email links}
+
+ ---@type inline.emails?
+ local main_config = spec.get({ "markdown_inline", "emails" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ ---+${custom, Draw the parts for the email}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start + 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end - 1,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+ ---_
+end
+
+--- Render [hyperlink].
+---@param buffer integer
+---@param item __inline.hyperlinks
+inline.link_hyperlink = function (buffer, item)
+ ---+${func, Render normal links}
+
+ ---@type inline.hyperlinks?
+ local main_config = spec.get({ "markdown_inline", "hyperlinks" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic
+ local config = utils.match(
+ main_config,
+ item.description,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ ---@type integer[]
+ local r_label = range.label;
+
+ ---+${custom, Draw the parts for the shortcut links}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, r_label[1], r_label[2] - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = r_label[2],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, r_label[1], r_label[2], {
+ undo_restore = false, invalidate = true,
+ end_row = r_label[3],
+ end_col = r_label[4],
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, r_label[3], r_label[4], {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+
+ if r_label[1] == r_label[3] then
+ return;
+ end
+
+ for l = r_label[1], r_label[3] do
+ local line = item.text[(l - range.row_start) + 1];
+
+ if l == r_label[1] then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, l, range.col_start + #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ elseif l == r_label[3] then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, l, #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ end
+ end
+ ---_
+end
+
+--- Render .
+---@param buffer integer
+---@param item __inline.images
+inline.link_image = function (buffer, item)
+ ---+${func, Render Image links}
+
+ ---@type inline.images?
+ local main_config = spec.get({ "markdown_inline", "images" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic
+ local config = utils.match(
+ main_config,
+ item.description,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ ---@type string[]
+ local r_label = range.label;
+
+ ---+${custom, Draw the parts for the image links}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, r_label[1], r_label[2] - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = r_label[2],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, r_label[1], r_label[2], {
+ undo_restore = false, invalidate = true,
+ end_row = r_label[3],
+ end_col = r_label[4],
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, r_label[3], r_label[4], {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+
+ if r_label[1] == r_label[3] then
+ return;
+ end
+
+ for l = r_label[1], r_label[3] do
+ local line = item.text[(l - range.row_start) + 1];
+
+ if l == r_label[1] then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, l, range.col_start + #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ elseif l == r_label[3] then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, l, #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ end
+ end
+ ---_
+end
+
+--- Render [[internal_links]].
+---@param buffer integer
+---@param item __inline.internal_links
+inline.link_internal = function (buffer, item)
+ ---+${func, Render Obsidian's internal links}
+
+ ---@type inline.internal_links?
+ local main_config = spec.get({ "markdown_inline", "internal_links" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ ---+${custom, Draw the parts for the internal links}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = vim.islist(range.alias) and range.alias[2] or (range.col_start + 2),
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, vim.islist(range.alias) and range.alias[4] or (range.col_end - 2), {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+ ---_
+end
+
+--- Render [shortcut_link].
+---@param buffer integer
+---@param item __inline.hyperlinks
+inline.link_shortcut = function (buffer, item)
+ ---+${func, Render Shortcut links}
+
+ ---@type inline.hyperlinks?
+ local main_config = spec.get({ "markdown_inline", "hyperlinks" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ ---+${custom, Draw the parts for the shortcut links}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start + 1, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end - 1,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+
+ if range.row_start == range.row_end then
+ return;
+ end
+
+ for l, line in ipairs(item.text) do
+ if l == 1 then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start + (l - 1), range.col_start + #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ elseif l == #item.text then
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start + (l - 1), 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start + (l - 1), 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start + (l - 1), #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ end
+ end
+ ---_
+end
+
+--- Render
+---@param buffer integer
+---@param item __inline.uri_autolinks
+inline.link_uri_autolink = function (buffer, item)
+ ---+${func, Render URI links}
+
+ ---@type inline.uri_autolinks?
+ local main_config = spec.get({ "markdown_inline", "uri_autolinks" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ ---+${custom, Draw the parts for the autolinks}
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, inline.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+ ---_
+end
+
+--- Renders inline markdown.
+---@param buffer integer
+---@param content table[]
+inline.render = function (buffer, content)
+ local custom = spec.get({ "renderers" }, { fallback = {} });
+
+ for _, item in ipairs(content or {}) do
+ local success, err;
+
+ if custom[item.class] then
+ success, err = pcall(custom[item.class], inline.ns, buffer, item);
+ else
+ success, err = pcall(inline[item.class:gsub("^inline_", "")], buffer, item);
+ end
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = {
+ { " r/markdown_inline.lua: ", "DiagnosticVirtualTextInfo" },
+ { " " },
+ { err, "DiagnosticError" }
+ }
+ });
+ end
+ end
+end
+
+--- Clears markdown inline previews.
+---@param buffer integer
+---@param from integer?
+---@param to integer?
+inline.clear = function (buffer, from, to)
+ vim.api.nvim_buf_clear_namespace(buffer, inline.ns, from or 0, to or -1);
+end
+
+return inline;
diff --git a/lua/markview/renderers/typst.lua b/lua/markview/renderers/typst.lua
new file mode 100644
index 0000000..210efe0
--- /dev/null
+++ b/lua/markview/renderers/typst.lua
@@ -0,0 +1,1576 @@
+local typst = {};
+
+local symbols = require("markview.symbols");
+local spec = require("markview.spec");
+local utils = require("markview.utils");
+
+local filetypes = require("markview.filetypes");
+
+typst.cache = {
+ superscripts = {},
+ subscripts = {}
+};
+
+--- Applies text transformation based on the **filetype**.
+---
+--- Uses for getting the output text of filetypes that contain
+--- special syntaxes(e.g. JSON, Markdown).
+typst.get_visual_text = {
+ ---+${class}
+ ["Markdown"] = function (str)
+ ---+${lua}
+
+ str = str:gsub("\\%`", " ");
+
+ for inline_code in str:gmatch("`(.-)`") do
+ ---+${custom, Handle inline codes}
+ str = str:gsub(concat({
+ "`",
+ inline_code,
+ "`"
+ }), inline_code);
+ ---_
+ end
+
+ for escaped in str:gmatch("\\([%\\%*%_%{%}%[%]%(%)%#%+%-%.%!%%<%>$])") do
+ str = str:gsub(concat({
+ "\\",
+ escaped
+ }), " ");
+ end
+
+ for link, _, address, _ in str:gmatch("%!%[([^%)]*)%]([%(%[])([^%)]*)([%)%]])") do
+ ---+${custom, Handle image links}
+ str = str:gsub(concat({
+ "![",
+ link,
+ "]",
+ address,
+ }), concat({ link }))
+ ---_
+ end
+
+ for link in str:gmatch("%!%[([^%)]*)%]") do
+ ---+${custom, Handle image links without address}
+ str = str:gsub(concat({
+ "![",
+ link,
+ "]",
+ }), concat({
+ utils.escape_string(link):gsub(".", "X"),
+ }))
+ ---_
+ end
+
+ for link, _, address, _ in str:gmatch("%[([^%)]*)%]([%(%[])([^%)]*)([%)%]])") do
+ ---+${custom, Handle hyperlinks}
+ str = str:gsub(concat({
+ "[",
+ link,
+ "]",
+ address
+ }), concat({ utils.escape_string(link):gsub(".", "X") }))
+ ---_
+ end
+
+ for link in str:gmatch("%[([^%)]+)%]") do
+ ---+${custom, Handle shortcut links}
+ str = str:gsub(concat({
+ "[",
+ link,
+ "]",
+ }), concat({
+ utils.escape_string(link):gsub(".", "X"),
+ }))
+ ---_
+ end
+
+ for str_b, content, str_a in str:gmatch("([*]+)(.-)([*]+)") do
+ ---+${custom, Handle italics & bold text}
+ if content == "" then
+ goto continue;
+ elseif #str_b ~= #str_a then
+ local min = math.min(#str_b, #str_a);
+ str_b = str_b:sub(0, min);
+ str_a = str_a:sub(0, min);
+ end
+
+ str_b = utils.escape_string(str_b);
+ content = utils.escape_string(content);
+ str_a = utils.escape_string(str_a);
+
+ str = str:gsub(str_b .. content .. str_a, utils.escape_string(content):gsub(".", "X"))
+
+ ::continue::
+ ---_
+ end
+
+ for striked in str:gmatch("%~%~(.-)%~%~") do
+ ---+${custom, Handle strike-through text}
+ str = str:gsub(concat({
+ "~~",
+ striked,
+ "~~"
+ }), concat({
+ utils.escape_string(striked):gsub(".", "X"),
+ }));
+ ---_
+ end
+
+ return str;
+ ---_
+ end,
+ ["JSON"] = function (str)
+ return str:gsub('"', "");
+ end,
+
+ --- Gets the visual text from the source text.
+ ---@param self table
+ ---@param ft string?
+ ---@param line string
+ ---@return string
+ init = function (self, ft, line)
+ if ft == nil or self[ft] == nil then
+ --- Filetype isn't available or
+ --- transformation not available.
+ return line;
+ elseif pcall(self[ft], line) == false then
+ --- Text transformation failed!
+ return line;
+ end
+
+ return self[ft](line);
+ end
+ ---_
+};
+
+typst.ns = vim.api.nvim_create_namespace("markview/typst");
+
+---@param buffer integer
+---@param item __typst.code_block
+typst.code_block = function (buffer, item)
+ ---+${func, Renders Code blocks}
+
+ local config = spec.get({ "typst", "code_blocks" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ if config.style == "simple" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "right_align",
+ virt_text = {
+ { config.text, utils.set_hl(config.text_hl or config.hl) },
+ },
+
+ sign_text = config.sign == true and sign or nil,
+ sign_hl_group = utils.set_hl(config.sign_hl or config.hl)
+ });
+
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end, end_col = range.col_end,
+ line_hl_group = utils.set_hl(config.hl),
+ });
+ elseif config.style == "block" then
+ local pad_amount = config.pad_amount or 3;
+ local block_width = config.min_width - (2 * pad_amount);
+
+ --- Get maximum length of the lines within the code block
+ for l, line in ipairs(item.text) do
+ if (l ~= 1 and l ~= #item.text) and vim.fn.strdisplaywidth(line) > block_width then
+ block_width = vim.fn.strdisplaywidth(line);
+ end
+ end
+
+ if config.text_direction == nil or config.text_direction == "left" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ virt_lines_above = true,
+ virt_lines = {
+ {
+ { string.rep(" ", range.col_start) },
+ { config.pad_char or " ", utils.set_hl(config.hl) },
+ { config.text or "", utils.set_hl(config.text_hl or config.hl) },
+ { string.rep(config.pad_char or " ", block_width + (pad_amount - 1) - (vim.fn.strdisplaywidth(config.text or ""))), utils.set_hl(config.hl) },
+ { string.rep(config.pad_char or " ", pad_amount), utils.set_hl(config.hl) },
+ }
+ },
+
+ sign_text = config.sign,
+ sign_hl_group = utils.set_hl(config.sign_hl or config.hl),
+ });
+ elseif config.text_direction == "right" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ virt_lines_above = true,
+ virt_lines = {
+ {
+ { string.rep(" ", range.col_start) },
+ { string.rep(config.pad_char or " ", pad_amount), utils.set_hl(config.hl) },
+ { string.rep(config.pad_char or " ", block_width + (pad_amount - 1) - (vim.fn.strdisplaywidth(config.text or ""))), utils.set_hl(config.hl) },
+ { config.text or "", utils.set_hl(config.text_hl or config.hl) },
+ { config.pad_char or " ", utils.set_hl(config.hl) },
+ }
+ },
+
+ sign_text = config.sign,
+ sign_hl_group = utils.set_hl(config.sign_hl or config.hl),
+ });
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_lines = {
+ {
+ { string.rep(" ", range.col_start) },
+ { string.rep(config.pad_char or " ", pad_amount), utils.set_hl(config.hl) },
+ { string.rep(config.pad_char or " ", block_width), utils.set_hl(config.hl) },
+ { string.rep(config.pad_char or " ", pad_amount), utils.set_hl(config.hl) },
+ }
+ }
+ });
+
+ for l = range.row_start, range.row_end, 1 do
+ local line = item.text[(l + 1) - range.row_start];
+ local final = line;
+
+ --- Left padding
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(config.pad_char or " ", pad_amount), utils.set_hl(config.hl) }
+ },
+ });
+
+ --- Right padding
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, range.col_start + #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(config.pad_char or " ", block_width - vim.fn.strdisplaywidth(final)), utils.set_hl(config.hl) },
+ { string.rep(config.pad_char or " ", pad_amount), utils.set_hl(config.hl) }
+ },
+ });
+
+ --- Background color
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #line,
+ hl_group = utils.set_hl(config.hl)
+ });
+ end
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.code_spans
+typst.code_span = function (buffer, item)
+ ---+${lua}
+
+ ---@type typst.code_spans_static?
+ local config = spec.get({ "typst", "code_spans" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(config.hl),
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ if range.row_start == range.row_end then
+ return;
+ end
+
+ for l = range.row_start, range.row_end do
+ local line = item.text[(l - range.row_start) + 1];
+
+ if l == range.row_start then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, range.col_start + #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ elseif l == range.row_end then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+ right_gravity = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ end
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.emphasis
+typst.emphasis = function (buffer, item)
+ ---+${lua}
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = ""
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = ""
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.escapes
+typst.escaped = function (buffer, item)
+ ---+${lua}
+
+ ---@type typst.escapes?
+ local config = spec.get({ "typst", "escapes" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.headings
+typst.heading = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.headings?
+ local main_config = spec.get({ "typst", "headings" }, { fallback = nil });
+
+ if not main_config then
+ return;
+ elseif not spec.get({ "heading_" .. item.level }, { source = main_config, eval_args = { buffer, item } }) then
+ return;
+ end
+
+ local range = item.range;
+ ---@type headings.typst
+ local config = spec.get({ "heading_" .. item.level }, { source = main_config, eval_args = { buffer, item } });
+
+ if config.style == "simple" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ line_hl_group = utils.set_hl(config.hl)
+ });
+ elseif config.style == "icon" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + item.level + 1,
+ conceal = "",
+ sign_text = config.sign,
+ sign_hl_group = utils.set_hl(config.sign_hl),
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", item.level * spec.get({ "typst", "headings", "shift_width" }, { fallback = 1 })) },
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) },
+ },
+ line_hl_group = utils.set_hl(config.hl),
+
+ hl_mode = "combine"
+ });
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.labels
+typst.label = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.labels?
+ local main_config = spec.get({ "typst", "labels" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic_static?
+ local config = utils.match(
+ main_config,
+ item.text[1]:gsub("^%@", ""),
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(config.hl),
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.list_items
+typst.list_item = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.list_items?
+ local main_config = spec.get({ "typst", "list_items" }, { fallback = nil });
+ ---@type list_items.ordered | list_items.unordered | nil
+ local config;
+
+ if not main_config then return; end
+
+ if item.marker == "-" then
+ config = spec.get({ "marker_minus" }, { source = main_config, eval_args = { buffer, item } });
+ elseif item.marker == "+" then
+ config = spec.get({ "marker_plus" }, { source = main_config, eval_args = { buffer, item } });
+ elseif item.marker:match("%d+%.") then
+ config = spec.get({ "marker_dot" }, { source = main_config, eval_args = { buffer, item } });
+ end
+
+ if not config then
+ return;
+ end
+
+ local indent = main_config.indent_size;
+ local shift = main_config.shift_width;
+
+ local range = item.range;
+
+ if config.add_padding == true then
+ for l = range.row_start, range.row_end do
+ local line = item.text[(l - range.row_start) + 1];
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, math.min(#line, range.col_start - item.indent), {
+ undo_restore = false, invalidate = true,
+ end_col = math.min(#line, range.col_start),
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(" ", math.ceil((item.indent / indent) + 1) * shift) }
+ }
+ });
+ end
+ end
+
+ if item.marker == "-" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ { config.text or "", utils.set_hl(config.hl) }
+ }
+ });
+ elseif item.marker == "+" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.format(config.text or "%d.", item.number), utils.set_hl(config.hl) }
+ }
+ });
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.reference_links
+typst.link_ref = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.reference_links?
+ local main_config = spec.get({ "typst", "reference_links" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic_static?
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(config.hl),
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.url_links
+typst.link_url = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.url_links?
+ local main_config = spec.get({ "typst", "url_links" }, { fallback = nil });
+
+ if not main_config then
+ return;
+ end
+
+ ---@type config.inline_generic_static?
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) }
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.maths
+typst.math_block = function (buffer, item)
+ ---+${func}
+ local range = item.range;
+
+ ---@type typst.math_blocks?
+ local config = spec.get({ "typst", "math_blocks" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "right_align",
+ virt_text = { { config.text or "", utils.set_hl(config.text_hl or config.hl) } },
+
+ hl_mode = "combine",
+ line_hl_group = utils.set_hl(config.hl)
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, math.max(0, range.col_end - 1), {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ line_hl_group = utils.set_hl(config.hl)
+ });
+
+ for l = 1, #item.text - 2 do
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start + l, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { string.rep(config.pad_char or "", config.pad_amount or 0), utils.set_hl(config.hl) }
+ },
+
+ line_hl_group = utils.set_hl(config.hl)
+ });
+ end
+ ---_
+end
+
+typst.math_span = function (buffer, item)
+ ---+${lua}
+
+ ---@type config.inline_generic_static?
+ local config = spec.get({ "typst", "math_spans" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ if range.row_start ~= range.row_end then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start + #item.text[1], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) }
+ }
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, 0, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ }
+ });
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(config.hl),
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ for l = 1, #item.text - 2 do
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start + l, math.min(#item.text[l + 1], 0), {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ }
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start + l, #item.text[l + 1], {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) }
+ }
+ });
+ end
+
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.raw_blocks
+typst.raw_block = function (buffer, item)
+ ---+${func, Renders Code blocks}
+
+ ---@type typst.raw_blocks_static?
+ local config = spec.get({ "typst", "raw_blocks" }, { fallback = nil, eval_args = { buffer, item } });
+ local range = item.range;
+
+ if not config then
+ return;
+ end
+
+ local decorations = filetypes.get(item.language);
+ local label = { string.format(" %s%s ", decorations.icon, decorations.name), config.label_hl or decorations.icon_hl };
+ local win = utils.buf_getwin(buffer);
+
+ --- Gets highlight configuration for a line.
+ ---@param line string
+ ---@return code_blocks.opts_static
+ local function get_line_config(line)
+ ---+${lua}
+
+ local line_conf = utils.match(config, item.language, {
+ eval_args = { buffer, line },
+ def_fallback = {
+ block_hl = config.border_hl,
+ pad_hl = config.border_hl
+ },
+ fallback = {
+ block_hl = config.border_hl,
+ pad_hl = config.border_hl
+ }
+ });
+
+ return line_conf;
+ ---_
+ end
+
+ local function render_simple ()
+ ---+${lua}
+ if config.label_direction == nil or config.label_direction == "left" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ end_col = range.col_start + 3,
+ conceal = "",
+
+ sign_text = config.sign == true and decorations.sign or nil,
+ sign_hl_group = utils.set_hl(config.sign_hl or decorations.sign_hl),
+
+ virt_text_pos = "inline",
+ virt_text = { label },
+
+ line_hl_group = utils.set_hl(config.border_hl)
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+
+ end_col = range.col_start + 3,
+ conceal = "",
+
+ sign_text = config.sign == true and decorations.sign or nil,
+ sign_hl_group = utils.set_hl(config.sign_hl or decorations.sign_hl),
+
+ virt_text_pos = "right_align",
+ virt_text = { label },
+
+ line_hl_group = utils.set_hl(config.border_hl)
+ });
+ end
+
+ --- Background
+ for l = range.row_start + 1, range.row_end - 1 do
+ local line = item.text[(l - range.row_start) + 1];
+ local line_config = get_line_config(line);
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, l, 0, {
+ undo_restore = false, invalidate = true,
+ end_row = l,
+
+ line_hl_group = utils.set_hl(line_config.block_hl)
+ });
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 3, {
+ undo_restore = false, invalidate = true,
+
+ end_col = range.col_end,
+ conceal = "",
+
+ line_hl_group = utils.set_hl(config.border_hl)
+ });
+ ---_
+ end
+
+ local function render_block ()
+ ---+${lua}
+
+ local pad_amount = config.pad_amount or 0;
+ local block_width = config.min_width or 60;
+
+ local line_widths = {};
+
+ --- Get maximum length of the lines within the code block
+ for l, line in ipairs(item.text) do
+ local final;
+
+ if item.language == "md" then
+ --- Bug ```md doesn't get recognized as markdown.
+ final = typst.get_visual_text:init("", line);
+ else
+ final = typst.get_visual_text:init(decorations.name, line);
+ end
+
+ if l ~= 1 and l ~= #item.text then
+ table.insert(line_widths, vim.fn.strdisplaywidth(final));
+
+ if vim.fn.strdisplaywidth(final) > (block_width - (2 * pad_amount)) then
+ block_width = vim.fn.strdisplaywidth(final) + (2 * pad_amount);
+ end
+ end
+ end
+
+ local label_width = utils.virt_len({ label });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ end_col = range.col_start + #item.text[1],
+ conceal = "",
+
+ sign_text = config.sign == true and decorations.sign or nil,
+ sign_hl_group = utils.set_hl(config.sign_hl or decorations.sign_hl),
+ });
+
+ if config.label_direction == nil or config.label_direction == "left" then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start + #item.text[1], {
+ virt_text_pos = "inline",
+ virt_text = {
+ label,
+ {
+ string.rep(config.pad_char or " ", block_width - label_width)
+ }
+ }
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start + #item.text[1], {
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(config.pad_char or " ", block_width - label_width),
+ utils.set_hl(config.border_hl)
+ },
+ label
+ }
+ });
+ end
+
+ --- Line padding
+ for l, width in ipairs(line_widths) do
+ ---+${lua}
+
+ local line = item.text[l + 1];
+ local line_config = get_line_config(line);
+
+ if width ~= 0 then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start + l, line ~= "" and range.col_start or 0, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", pad_amount),
+ utils.set_hl(line_config.pad_hl)
+ }
+ },
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start + l, range.col_start + #line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", block_width - (( 2 * pad_amount) + width)),
+ utils.set_hl(line_config.block_hl)
+ },
+ {
+ string.rep(" ", pad_amount),
+ utils.set_hl(line_config.pad_hl)
+ }
+ },
+ });
+
+ --- Background
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start + l, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + #line,
+
+ hl_group = utils.set_hl(line_config.block_hl)
+ });
+ else
+ local buf_line = vim.api.nvim_buf_get_lines(buffer, range.row_start + l, range.row_start + l + 1, false)[1];
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start + l, #buf_line, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", range.col_start - #buf_line)
+ },
+ {
+ string.rep(" ", pad_amount),
+ utils.set_hl(line_config.pad_hl)
+ },
+ {
+ string.rep(" ", block_width - (2 * pad_amount)),
+ utils.set_hl(line_config.block_hl)
+ },
+ {
+ string.rep(" ", pad_amount),
+ utils.set_hl(line_config.pad_hl)
+ },
+ },
+ });
+ end
+ ---_
+ end
+
+ --- Bottom border
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 3, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = ""
+ });
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end, {
+ undo_restore = false, invalidate = true,
+
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ string.rep(" ", block_width),
+ utils.set_hl(config.border_hl)
+ }
+ }
+ });
+
+ ---_
+ end
+
+ if config.style == "simple" or ( vim.o.wrap == true or vim.wo[win].wrap == true ) then
+ render_simple();
+ elseif config.style == "block" then
+ render_block()
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.raw_spans
+typst.raw_span = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.raw_spans_static?
+ local config = spec.get({ "typst", "raw_spans" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.corner_left or "", utils.set_hl(config.corner_left_hl or config.hl) },
+ { config.padding_left or "", utils.set_hl(config.padding_left_hl or config.hl) },
+ { config.icon or "", utils.set_hl(config.icon_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(config.hl),
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.padding_right or "", utils.set_hl(config.padding_right_hl or config.hl) },
+ { config.corner_right or "", utils.set_hl(config.corner_right_hl or config.hl) },
+ },
+
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.strong
+typst.strong = function (buffer, item)
+ ---+${lua}
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = ""
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = ""
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.subscripts
+typst.subscript = function (buffer, item)
+ -- ---+${func}
+
+ ---@type typst.subscripts?
+ local config = spec.get({ "typst", "subscripts" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+ ---@type string?
+ local hl;
+
+ if type(config.hl) == "string" then
+ hl = config.hl --[[ @as string ]];
+ elseif vim.islist(config.hl) == true then
+ hl = config.hl[utils.clamp(item.level, 1, #config.hl)];
+ end
+
+ local previewable = true;
+
+ local invalid_symbols = vim.list_extend(vim.tbl_keys(symbols.typst_entries), vim.tbl_keys(symbols.typst_shorthands));
+ local valid_symbols = vim.tbl_keys(symbols.subscripts);
+
+ local lines = vim.deepcopy(item.text);
+
+ lines[1] = string.gsub(lines[1], "^%{", "");
+ lines[#lines] = string.gsub(lines[#lines], "%}$", "");
+
+ for _, line in ipairs(lines) do
+ if utils.str_contains(line, invalid_symbols) == true then
+ previewable = false;
+ break;
+ elseif utils.str_contains(line, valid_symbols) == false then
+ previewable = false;
+ break;
+ end
+ end
+
+ ---+${Lua, Render markers}
+ if item.parenthesis == true then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 2,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = previewable == false and {
+ { config.marker_left or "โ(", utils.set_hl(hl) }
+ } or nil,
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = previewable == false and {
+ { config.marker_right or ")", utils.set_hl(hl) }
+ } or nil,
+
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = previewable == false and {
+ { config.marker_left or "โ", utils.set_hl(hl) }
+ } or nil,
+
+ hl_mode = "combine"
+ });
+ end
+ ---_
+
+ if previewable == true then
+ table.insert(typst.cache.subscripts, item);
+ else
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(hl)
+ });
+ end
+ -- ---_
+end
+
+---@param buffer integer
+---@param item __typst.superscripts
+typst.superscript = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.superscripts?
+ local config = spec.get({ "typst", "superscripts" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+ ---@type string?
+ local hl;
+
+ if type(config.hl) == "string" then
+ hl = config.hl --[[ @as string ]];
+ elseif vim.islist(config.hl) == true then
+ hl = config.hl[utils.clamp(item.level, 1, #config.hl)];
+ end
+
+ local previewable = true;
+
+ local invalid_symbols = vim.list_extend(vim.tbl_keys(symbols.typst_entries), vim.tbl_keys(symbols.typst_shorthands));
+ local valid_symbols = vim.tbl_keys(symbols.superscripts);
+
+ local lines = vim.deepcopy(item.text);
+
+ lines[1] = string.gsub(lines[1], "^%{", "");
+ lines[#lines] = string.gsub(lines[#lines], "%}$", "");
+
+ for _, line in ipairs(lines) do
+ if utils.str_contains(line, invalid_symbols) == true then
+ previewable = false;
+ break;
+ elseif utils.str_contains(line, valid_symbols) == false then
+ previewable = false;
+ break;
+ end
+ end
+
+ ---+${Lua, Render markers}
+ if item.parenthesis == true then
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 2,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = previewable == false and {
+ { config.marker_left or "โ(", utils.set_hl(hl) }
+ } or nil,
+
+ hl_mode = "combine"
+ });
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_end, range.col_end - 1, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = previewable == false and {
+ { config.marker_right or ")", utils.set_hl(hl) }
+ } or nil,
+
+ hl_mode = "combine"
+ });
+ else
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = previewable == false and {
+ { config.marker_left or "โ", utils.set_hl(hl) }
+ } or nil,
+
+ hl_mode = "combine"
+ });
+ end
+ ---_
+
+ if previewable == true then
+ table.insert(typst.cache.superscripts, item);
+ else
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ hl_group = utils.set_hl(hl)
+ });
+ end
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.symbols
+typst.symbol = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.symbols?
+ local config = spec.get({ "typst", "symbols" }, { fallback = nil, eval_args = { buffer, item } });
+
+ if not config then
+ return;
+ elseif not item.name or not symbols.typst_entries[item.name] then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_end,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { symbols.typst_entries[item.name], utils.set_hl(config.hl) }
+ },
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.terms
+typst.term = function (buffer, item)
+ ---+${func}
+
+ ---@type typst.terms?
+ local main_config = spec.get({ "typst", "terms" }, { fallback = nil });
+
+ if not main_config then
+ return;
+ end
+
+ ---@type term.opts?
+ local config = utils.match(
+ main_config,
+ item.label,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if not config then
+ return;
+ end
+
+ local range = item.range;
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_col = range.col_start + 2,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { config.text or "", utils.set_hl(config.hl) }
+ }
+ });
+ ---_
+end
+
+---@param buffer integer
+---@param item __typst.text
+typst.text = function (buffer, item)
+ ---+${func}
+
+ local range = item.range;
+ local style;
+
+ local function modify_style(new_style)
+ if style == nil then
+ return true;
+ elseif new_style.range and utils.within_range(style.range, new_style.range) == true then
+ return true;
+ end
+
+ return false;
+ end
+
+ --- Check for subscript styles.
+ for _, node in ipairs(typst.cache.subscripts or {}) do
+ if utils.within_range(node.range, range) and modify_style(node) == true then
+ style = node;
+ break;
+ end
+ end
+
+ --- Check for superscript styles.
+ for _, node in ipairs(typst.cache.superscripts or {}) do
+ if utils.within_range(node.range, range) and modify_style(node) == true then
+ style = node;
+ break;
+ end
+ end
+
+ local virt_text, virt_hl;
+
+ if style == nil then
+ --- No styles were found.
+ return;
+ elseif style.class == "typst_subscript" then
+ local config = spec.get({ "typst", "subscripts", "hl" }, { fallback = nil, eval_args = { buffer, style } });
+
+ virt_text = symbols.tostring("subscripts", item.text[1])
+ virt_hl = config.hl;
+ elseif style.class == "typst_superscript" then
+ local config = spec.get({ "typst", "superscripts", "hl" }, { fallback = nil, eval_args = { buffer, style } });
+
+ virt_text = symbols.tostring("superscripts", item.text[1])
+ virt_hl = config.hl;
+ else
+ --- Unknown style.
+ return;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, typst.ns, range.row_start, range.col_start, {
+ undo_restore = false, invalidate = true,
+ end_row = range.row_end,
+ end_col = range.col_end,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ { virt_text, utils.set_hl(virt_hl) }
+ },
+ hl_mode = "combine"
+ });
+ ---_
+end
+
+--- Renders typst previews.
+---@param buffer integer
+---@param content table[]
+typst.render = function (buffer, content)
+ typst.cache = {
+ superscripts = {},
+ subscripts = {}
+ };
+
+ local custom = spec.get({ "renderers" }, { fallback = {} });
+
+ for _, item in ipairs(content or {}) do
+ local success, err;
+
+ if custom[item.class] then
+ success, err = pcall(custom[item.class], typst.ns, buffer, item);
+ else
+ success, err = pcall(typst[item.class:gsub("^typst_", "")], buffer, item);
+ end
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = {
+ { " r/typst.lua: ", "DiagnosticVirtualTextInfo" },
+ { " " },
+ { err, "DiagnosticError" }
+ }
+ });
+ end
+ end
+end
+
+--- Clear typst previews.
+---@param buffer integer
+---@param from integer?
+---@param to integer?
+typst.clear = function (buffer, from, to)
+ vim.api.nvim_buf_clear_namespace(buffer, typst.ns, from or 0, to or -1);
+end
+
+return typst;
diff --git a/lua/markview/renderers/yaml.lua b/lua/markview/renderers/yaml.lua
new file mode 100644
index 0000000..4c592e3
--- /dev/null
+++ b/lua/markview/renderers/yaml.lua
@@ -0,0 +1,111 @@
+local yaml = {};
+
+local spec = require("markview.spec");
+local utils = require("markview.utils");
+
+yaml.cache = {};
+
+yaml.ns = vim.api.nvim_create_namespace("markview/yaml");
+
+---@param buffer integer
+---@param item __yaml.properties
+yaml.property = function (buffer, item)
+ ---+${func}
+ local main_config = spec.get({ "yaml", "properties" }, { fallback = nil });
+ local range = item.range;
+
+ if not main_config then
+ return;
+ end
+
+ local config = utils.match(
+ main_config,
+ item.key,
+ {
+ eval_args = { buffer, item }
+ }
+ );
+
+ if config == nil then
+ return;
+ elseif config.use_types == true then
+ --- Merge with data type configuration
+ --- if the config has `use_types == true`.
+ config = vim.tbl_extend("force", spec.get(
+ { "data_types", item.type },
+ {
+ source = main_config,
+ eval_args = { buffer, item }
+ }
+ ), config);
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, yaml.ns, range.row_start, range.col_start, {
+ virt_text_pos = "inline",
+ virt_text = {
+ {
+ config.text or "",
+ utils.set_hl(config.hl)
+ }
+ }
+ });
+
+ for l = range.row_start + 1, range.row_end do
+ local border, border_hl;
+
+ if l == range.row_end and config.border_bottom then
+ border = config.border_bottom;
+ border_hl = config.border_bottom_hl or config.border_hl or config.hl;
+ elseif l == range.row_start + 1 and config.border_top then
+ border = config.border_top;
+ border_hl = config.border_top_hl or config.border_hl or config.hl;
+ elseif config.border_middle then
+ border = config.border_middle;
+ border_hl = config.border_middle_hl or config.border_hl or config.hl;
+ else
+ border = string.rep(" ", vim.fn.strdisplaywidth(config.text[item.type]))
+ border_hl = config.border_hl or config.hl;
+ end
+
+ vim.api.nvim_buf_set_extmark(buffer, yaml.ns, l, math.min(range.col_start, #item.text[(l - range.row_start) + 1]), {
+ virt_text_pos = "inline",
+ virt_text = {
+ { border or "", utils.set_hl(border_hl) }
+ }
+ });
+ end
+ ---_
+end
+
+yaml.render = function (buffer, content)
+ yaml.cache = {};
+
+ local custom = spec.get({ "renderers" }, { fallback = {} });
+
+ for _, item in ipairs(content or {}) do
+ local success, err;
+
+ if custom[item.class] then
+ success, err = pcall(custom[item.class], yaml.ns, buffer, item);
+ else
+ success, err = pcall(yaml[item.class:gsub("^yaml_", "")], buffer, item);
+ end
+
+ if success == false then
+ require("markview.health").notify("trace", {
+ level = 4,
+ message = {
+ { " r/yaml.lua: ", "DiagnosticVirtualTextInfo" },
+ { " " },
+ { err, "DiagnosticError" }
+ }
+ });
+ end
+ end
+end
+
+yaml.clear = function (buffer, from, to)
+ vim.api.nvim_buf_clear_namespace(buffer, yaml.ns, from or 0, to or -1);
+end
+
+return yaml;
diff --git a/lua/markview/spec.lua b/lua/markview/spec.lua
new file mode 100644
index 0000000..319ffae
--- /dev/null
+++ b/lua/markview/spec.lua
@@ -0,0 +1,3486 @@
+--- Configuration specification file
+--- for `markview.nvim`.
+---
+--- It has the following tasks,
+--- โข Maintain backwards compatibility
+--- โข Check for issues with config
+local spec = {};
+local health = require("markview.health");
+local symbols = require("markview.symbols");
+
+--- Creates a configuration table for a LaTeX command.
+---@param name string Command name(Text to show).
+---@param text_pos? "overlay" | "inline" `virt_text_pos` extmark options.
+---@param cmd_conceal? integer Characters to conceal.
+---@param cmd_hl? string Highlight group for the command.
+---@return commands.opts
+local operator = function (name, text_pos, cmd_conceal, cmd_hl)
+ ---+${func}
+ return {
+ condition = function (item)
+ return #item.args == 1;
+ end,
+
+
+ on_command = function (item)
+ return {
+ end_col = item.range[2] + (cmd_conceal or 1),
+ conceal = "",
+
+ virt_text_pos = text_pos or "overlay",
+ virt_text = {
+ { symbols.tostring("default", name), cmd_hl or "@keyword.function" }
+ },
+
+ hl_mode = "combine"
+ }
+ end,
+
+ on_args = {
+ {
+ on_before = function (item)
+ return {
+ end_col = item.range[2] + 1,
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ { "(", "@punctuation.bracket" }
+ },
+
+ hl_mode = "combine"
+ }
+ end,
+
+ after_offset = function (range)
+ return { range[1], range[2], range[3], range[4] - 1 };
+ end,
+
+ on_after = function (item)
+ return {
+ end_col = item.range[4],
+
+ virt_text_pos = "overlay",
+ virt_text = {
+ { ")", "@punctuation.bracket" }
+ },
+
+ hl_mode = "combine"
+ }
+ end
+ }
+ }
+ };
+ ---_
+end
+
+spec.warnings = {};
+
+--- `vim.notify()` with extra steps.
+---@param chunks [ string, string? ][]
+---@param opts { silent: boolean, level: integer? }
+spec.notify = function (chunks, opts)
+ if not opts then opts = {}; end
+
+ local highlights = {
+ [vim.log.levels.DEBUG] = "DiagnosticInfo",
+ [vim.log.levels.ERROR] = "DiagnosticError",
+ [vim.log.levels.INFO] = "DiagnosticInfo",
+ [vim.log.levels.OFF] = "Comment",
+ [vim.log.levels.TRACE] = "DiagnosticInfo",
+ [vim.log.levels.WARN] = "DiagnosticWarn"
+ };
+
+ vim.api.nvim_echo(
+ vim.list_extend(
+ {
+ {
+ "๓ฐ markview",
+ highlights[opts.level or vim.log.levels.WARN]
+ },
+ { ": " }
+ },
+ chunks
+ ),
+ true,
+ {}
+ );
+
+ if opts.silent ~= true then
+ table.insert(spec.warnings, opts);
+ end
+end
+
+---@type mkv.config
+spec.default = {
+ ---+${conf}
+
+ experimental = {
+ ---+${conf}
+
+ read_chunk_size = 1024,
+
+ file_open_command = "tabnew",
+ list_empty_line_tolerance = 3,
+
+ date_formats = {
+ "^%d%d%d%d%-%d%d%-%d%d$", --- YYYY-MM-DD
+ "^%d%d%-%d%d%-%d%d%d%d$", --- DD-MM-YYYY, MM-DD-YYYY
+ "^%d%d%-%d%d%-%d%d$", --- DD-MM-YY, MM-DD-YY, YY-MM-DD
+
+ "^%d%d%d%d%/%d%d%/%d%d$", --- YYYY/MM/DD
+ "^%d%d%/%d%d%/%d%d%d%d$", --- DD/MM/YYYY, MM/DD/YYYY
+
+ "^%d%d%d%d%.%d%d%.%d%d$", --- YYYY.MM.DD
+ "^%d%d%.%d%d%.%d%d%d%d$", --- DD.MM.YYYY, MM.DD.YYYY
+
+ "^%d%d %a+ %d%d%d%d$", --- DD Month YYYY
+ "^%a+ %d%d %d%d%d%d$", --- Month DD, YYYY
+ "^%d%d%d%d %a+ %d%d$", --- YYYY Month DD
+
+ "^%a+%, %a+ %d%d%, %d%d%d%d$", --- Day, Month DD, YYYY
+ },
+
+ date_time_formats = {
+ "^%a%a%a %a%a%a %d%d %d%d%:%d%d%:%d%d ... %d%d%d%d$", --- UNIX date time
+ "^%d%d%d%d%-%d%d%-%d%dT%d%d%:%d%d%:%d%dZ$", --- ISO 8601
+ }
+
+ ---_
+ };
+
+ highlight_groups = {},
+
+ preview = {
+ ---+${conf}
+
+ enable = true,
+
+ callbacks = {
+ ---+${func}
+
+ on_attach = function (_, wins)
+ ---+${lua}
+
+ --- Initial state for attached buffers.
+ ---@type string
+ local attach_state = spec.get({ "preview", "enable" }, { fallback = true, ignore_enable = true });
+
+ if attach_state == false then
+ --- Attached buffers will not have their previews
+ --- enabled.
+ --- So, don't set options.
+ return;
+ end
+
+ for _, win in ipairs(wins) do
+ --- Preferred conceal level should
+ --- be 3.
+ vim.wo[win].conceallevel = 3;
+ end
+
+ ---_
+ end,
+
+ on_detach = function (_, wins)
+ ---+${lua}
+ for _, win in ipairs(wins) do
+ --- Only set `conceallevel`.
+ --- `concealcursor` will be
+ --- set via `on_hybrid_disable`.
+ vim.wo[win].conceallevel = 0;
+ end
+ ---_
+ end,
+
+ on_enable = function (_, wins)
+ ---+${lua}
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].conceallevel = 3;
+ end
+
+ ---_
+ end,
+
+ on_disable = function (_, wins)
+ ---+${lua}
+ for _, win in ipairs(wins) do
+ vim.wo[win].conceallevel = 0;
+ end
+ ---_
+ end,
+
+ on_hybrid_enable = function (_, wins)
+ ---+${lua}
+
+ ---@type string[]
+ local preview_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ ---@type string[]
+ local hybrid_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
+
+ local concealcursor = "";
+
+ for _, mode in ipairs(preview_modes) do
+ if vim.list_contains(hybrid_modes, mode) == false and vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].concealcursor = concealcursor;
+ end
+
+ ---_
+ end,
+
+ on_hybrid_disable = function (_, wins)
+ ---+${lua}
+
+ ---@type string[]
+ local preview_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ local concealcursor = "";
+
+ for _, mode in ipairs(preview_modes) do
+ if vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ vim.wo[win].concealcursor = concealcursor;
+ end
+
+ ---_
+ end,
+
+ on_mode_change = function (_, wins, current_mode)
+ ---+${lua}
+
+ ---@type string[]
+ local preview_modes = spec.get({ "preview", "modes" }, { fallback = {} });
+ ---@type string[]
+ local hybrid_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {} });
+
+ local concealcursor = "";
+
+ for _, mode in ipairs(preview_modes) do
+ if vim.list_contains(hybrid_modes, mode) == false and vim.list_contains({ "n", "v", "i", "c" }, mode) then
+ concealcursor = concealcursor .. mode;
+ end
+ end
+
+ for _, win in ipairs(wins) do
+ if vim.list_contains(preview_modes, current_mode) then
+ vim.wo[win].conceallevel = 3;
+ vim.wo[win].concealcursor = concealcursor;
+ else
+ vim.wo[win].conceallevel = 0;
+ vim.wo[win].concealcursor = "";
+ end
+ end
+ ---_
+ end,
+
+ on_splitview_open = function (_, _, win)
+ ---+${lua}
+ vim.wo[win].conceallevel = 3;
+ vim.wo[win].concealcursor = "n";
+ ---_
+ end
+ ---_
+ },
+ debounce = 150,
+ icon_provider = "internal",
+
+ draw_range = { 2 * vim.o.lines, 2 * vim.o.lines },
+ edit_range = { 0, 0 },
+
+ modes = { "n", "no", "c" },
+ hybrid_modes = {},
+ linewise_hybrid_mode = false,
+ max_buf_lines = 1000,
+
+ filetypes = { "markdown", "quarto", "rmd", "typst" },
+ ignore_buftypes = { "nofile" },
+ ignore_previews = {},
+
+ splitview_winopts = {
+ split = "right"
+ }
+
+ ---_
+ },
+
+ renderers = {},
+
+ markdown = {
+ ---+${lua}
+
+ enable = true,
+
+ block_quotes = {
+ ---+${class}
+ enable = true,
+ wrap = true,
+
+ default = {
+ border = "โ",
+ hl = "MarkviewBlockQuoteDefault"
+ },
+
+ ---+${conf}
+ ["ABSTRACT"] = {
+ preview = "๓ฑซ Abstract",
+ hl = "MarkviewBlockQuoteNote",
+
+ title = true,
+ icon = "๓ฑซ",
+
+ border = "โ"
+ },
+ ["SUMMARY"] = {
+ hl = "MarkviewBlockQuoteNote",
+ preview = "๓ฑซ Summary",
+
+ title = true,
+ icon = "๓ฑซ",
+
+ border = "โ"
+ },
+ ["TLDR"] = {
+ hl = "MarkviewBlockQuoteNote",
+ preview = "๓ฑซ Tldr",
+
+ title = true,
+ icon = "๓ฑซ",
+
+ border = "โ"
+ },
+ ["TODO"] = {
+ hl = "MarkviewBlockQuoteNote",
+ preview = "๎ Todo",
+
+ title = true,
+ icon = "๎",
+
+ border = "โ"
+ },
+ ["INFO"] = {
+ hl = "MarkviewBlockQuoteNote",
+ preview = "๎ช Info",
+
+ custom_title = true,
+ icon = "๎",
+
+ border = "โ"
+ },
+ ["SUCCESS"] = {
+ hl = "MarkviewBlockQuoteOk",
+ preview = "๓ฐ Success",
+
+ title = true,
+ icon = "๓ฐ ",
+
+ border = "โ"
+ },
+ ["CHECK"] = {
+ hl = "MarkviewBlockQuoteOk",
+ preview = "๓ฐ Check",
+
+ title = true,
+ icon = "๓ฐ ",
+
+ border = "โ"
+ },
+ ["DONE"] = {
+ hl = "MarkviewBlockQuoteOk",
+ preview = "๓ฐ Done",
+
+ title = true,
+ icon = "๓ฐ ",
+
+ border = "โ"
+ },
+ ["QUESTION"] = {
+ hl = "MarkviewBlockQuoteWarn",
+ preview = "๓ฐ Question",
+
+ title = true,
+ icon = "๓ฐ",
+
+ border = "โ"
+ },
+ ["HELP"] = {
+ hl = "MarkviewBlockQuoteWarn",
+ preview = "๓ฐ Help",
+
+ title = true,
+ icon = "๓ฐ",
+
+ border = "โ"
+ },
+ ["FAQ"] = {
+ hl = "MarkviewBlockQuoteWarn",
+ preview = "๓ฐ Faq",
+
+ title = true,
+ icon = "๓ฐ",
+
+ border = "โ"
+ },
+ ["FAILURE"] = {
+ hl = "MarkviewBlockQuoteError",
+ preview = "๓ฐ
Failure",
+
+ title = true,
+ icon = "๓ฐ
",
+
+ border = "โ"
+ },
+ ["FAIL"] = {
+ hl = "MarkviewBlockQuoteError",
+ preview = "๓ฐ
Fail",
+
+ title = true,
+ icon = "๓ฐ
",
+
+ border = "โ"
+ },
+ ["MISSING"] = {
+ hl = "MarkviewBlockQuoteError",
+ preview = "๓ฐ
Missing",
+
+ title = true,
+ icon = "๓ฐ
",
+
+ border = "โ"
+ },
+ ["DANGER"] = {
+ hl = "MarkviewBlockQuoteError",
+ preview = "๏ญ Danger",
+
+ title = true,
+ icon = "๏ญ",
+
+ border = "โ"
+ },
+ ["ERROR"] = {
+ hl = "MarkviewBlockQuoteError",
+ preview = "๏ญ Error",
+
+ title = true,
+ icon = "๏ญ",
+
+ border = "โ"
+ },
+ ["BUG"] = {
+ hl = "MarkviewBlockQuoteError",
+ preview = "๏ฏ Bug",
+
+ title = true,
+ icon = "๏ฏ",
+
+ border = "โ"
+ },
+ ["EXAMPLE"] = {
+ hl = "MarkviewBlockQuoteSpecial",
+ preview = "๓ฑซ Example",
+
+ title = true,
+ icon = "๓ฑซ",
+
+ border = "โ"
+ },
+ ["QUOTE"] = {
+ hl = "MarkviewBlockQuoteDefault",
+ preview = "๏ Quote",
+
+ title = true,
+ icon = "๏",
+
+ border = "โ"
+ },
+ ["CITE"] = {
+ hl = "MarkviewBlockQuoteDefault",
+ preview = "๏ Cite",
+
+ title = true,
+ icon = "๏",
+
+ border = "โ"
+ },
+ ["HINT"] = {
+ hl = "MarkviewBlockQuoteOk",
+ preview = "๏ Hint",
+
+ title = true,
+ icon = "๏",
+
+ border = "โ"
+ },
+ ["ATTENTION"] = {
+ hl = "MarkviewBlockQuoteWarn",
+ preview = "๎ฉฌ Attention",
+
+ title = true,
+ icon = "๏",
+
+ border = "โ"
+ },
+
+
+ ["NOTE"] = {
+ match_string = "NOTE",
+ hl = "MarkviewBlockQuoteNote",
+ preview = "๓ฐฝ Note",
+
+ border = "โ"
+ },
+ ["TIP"] = {
+ match_string = "TIP",
+ hl = "MarkviewBlockQuoteOk",
+ preview = "๏ Tip",
+
+ border = "โ"
+ },
+ ["IMPORTANT"] = {
+ match_string = "IMPORTANT",
+ hl = "MarkviewBlockQuoteSpecial",
+ preview = "๎ญ Important",
+
+ border = "โ"
+ },
+ ["WARNING"] = {
+ match_string = "WARNING",
+ hl = "MarkviewBlockQuoteWarn",
+ preview = "๎ฉฌ Warning",
+
+ border = "โ"
+ },
+ ["CAUTION"] = {
+ match_string = "CAUTION",
+ hl = "MarkviewBlockQuoteError",
+ preview = "๓ฐณฆ Caution",
+
+ border = "โ"
+ }
+ ---_
+
+ ---_
+ },
+
+ code_blocks = {
+ ---+${conf, Code blocks}
+
+ enable = true,
+
+ style = "block",
+
+ label_direction = "right",
+
+ border_hl = "MarkviewCode",
+ info_hl = "MarkviewCodeInfo",
+
+ min_width = 60,
+ pad_amount = 2,
+ pad_char = " ",
+
+ sign = true,
+
+ default = {
+ block_hl = "MarkviewCode",
+ pad_hl = "MarkviewCode"
+ },
+
+ ["diff"] = {
+ block_hl = function (_, line)
+ if line:match("^%+") then
+ return "MarkviewPalette4";
+ elseif line:match("^%-") then
+ return "MarkviewPalette1";
+ else
+ return "MarkviewCode";
+ end
+ end,
+ pad_hl = "MarkviewCode"
+ }
+
+ ---_
+ },
+
+ headings = {
+ ---+ ${class, Headings}
+
+ enable = true,
+
+ shift_width = 1,
+
+ org_indent = false,
+ org_indent_wrap = true,
+ org_shift_char = " ",
+ org_shift_width = 1,
+
+ heading_1 = {
+ ---+ ${conf, Heading 1}
+ style = "icon",
+ sign = "๓ฐ ", sign_hl = "MarkviewHeading1Sign",
+
+ icon = "๓ฐผ ", hl = "MarkviewHeading1",
+ ---_
+ },
+ heading_2 = {
+ ---+ ${conf, Heading 2}
+ style = "icon",
+ sign = "๓ฐ ", sign_hl = "MarkviewHeading2Sign",
+
+ icon = "๓ฐจ ", hl = "MarkviewHeading2",
+ ---_
+ },
+ heading_3 = {
+ ---+ ${conf, Heading 3}
+ style = "icon",
+
+ icon = "๓ฐผ ", hl = "MarkviewHeading3",
+ ---_
+ },
+ heading_4 = {
+ ---+ ${conf, Heading 4}
+ style = "icon",
+
+ icon = "๓ฐฒ ", hl = "MarkviewHeading4",
+ ---_
+ },
+ heading_5 = {
+ ---+ ${conf, Heading 5}
+ style = "icon",
+
+ icon = "๓ฐผ ", hl = "MarkviewHeading5",
+ ---_
+ },
+ heading_6 = {
+ ---+ ${conf, Heading 6}
+ style = "icon",
+
+ icon = "๓ฐด ", hl = "MarkviewHeading6",
+ ---_
+ },
+
+ setext_1 = {
+ ---+ ${conf, Setext heading 1}
+ style = "decorated",
+
+ sign = "๓ฐ ", sign_hl = "MarkviewHeading1Sign",
+ icon = " ๎ชซ ", hl = "MarkviewHeading1",
+ border = "โ"
+ ---_
+ },
+ setext_2 = {
+ ---+ ${conf, Setext heading 2}
+ style = "decorated",
+
+ sign = "๓ฐ ", sign_hl = "MarkviewHeading2Sign",
+ icon = " ๎ชช ", hl = "MarkviewHeading2",
+ border = "โ"
+ ---_
+ }
+
+ ---_
+ },
+
+ horizontal_rules = {
+ ---+ ${class, Horizontal rules}
+ enable = true,
+
+ parts = {
+ {
+ ---+ ${conf, Left portion}
+
+ type = "repeating",
+ direction = "left",
+
+ repeat_amount = function (buffer)
+ local utils = require("markview.utils");
+ local window = utils.buf_getwin(buffer)
+
+ local width = vim.api.nvim_win_get_width(window)
+ local textoff = vim.fn.getwininfo(window)[1].textoff;
+
+ return math.floor((width - textoff - 3) / 2);
+ end,
+
+ text = "โ",
+
+ hl = {
+ "MarkviewGradient1", "MarkviewGradient1",
+ "MarkviewGradient2", "MarkviewGradient2",
+ "MarkviewGradient3", "MarkviewGradient3",
+ "MarkviewGradient4", "MarkviewGradient4",
+ "MarkviewGradient5", "MarkviewGradient5",
+ "MarkviewGradient6", "MarkviewGradient6",
+ "MarkviewGradient7", "MarkviewGradient7",
+ "MarkviewGradient8", "MarkviewGradient8",
+ "MarkviewGradient9", "MarkviewGradient9"
+ }
+ ---_
+ },
+ {
+ type = "text",
+
+ text = " ๎ชช ",
+ hl = "MarkviewIcon3Fg"
+ },
+ {
+ ---+ ${conf, Right portion}
+ type = "repeating",
+ direction = "right",
+
+ repeat_amount = function (buffer) --[[@as function]]
+ local utils = require("markview.utils");
+ local window = utils.buf_getwin(buffer)
+
+ local width = vim.api.nvim_win_get_width(window)
+ local textoff = vim.fn.getwininfo(window)[1].textoff;
+
+ return math.ceil((width - textoff - 3) / 2);
+ end,
+
+ text = "โ",
+ hl = {
+ "MarkviewGradient1", "MarkviewGradient1",
+ "MarkviewGradient2", "MarkviewGradient2",
+ "MarkviewGradient3", "MarkviewGradient3",
+ "MarkviewGradient4", "MarkviewGradient4",
+ "MarkviewGradient5", "MarkviewGradient5",
+ "MarkviewGradient6", "MarkviewGradient6",
+ "MarkviewGradient7", "MarkviewGradient7",
+ "MarkviewGradient8", "MarkviewGradient8",
+ "MarkviewGradient9", "MarkviewGradient9"
+ }
+ ---_
+ }
+ }
+ ---_
+ },
+
+ list_items = {
+ ---+${conf, List items}
+ enable = true,
+ wrap = true,
+
+ indent_size = 4,
+ shift_width = 4,
+
+ marker_minus = {
+ add_padding = true,
+ conceal_on_checkboxes = true,
+
+ text = "๎ฉฑ",
+ hl = "MarkviewListItemMinus"
+ },
+
+ marker_plus = {
+ add_padding = true,
+ conceal_on_checkboxes = true,
+
+ text = "๎ชซ",
+ hl = "MarkviewListItemPlus"
+ },
+
+ marker_star = {
+ add_padding = true,
+ conceal_on_checkboxes = true,
+
+ text = "๎ชฉ",
+ hl = "MarkviewListItemStar"
+ },
+
+ marker_dot = {
+ add_padding = true,
+ conceal_on_checkboxes = true
+ },
+
+ marker_parenthesis = {
+ add_padding = true,
+ conceal_on_checkboxes = true
+ }
+ ---_
+ },
+
+ metadata_minus = {
+ ---+${lua}
+
+ enable = true,
+
+ hl = "MarkviewCode",
+ border_hl = "MarkviewCodeFg",
+
+ border_top = "โ",
+ border_bottom = "โ"
+
+ ---_
+ },
+
+ metadata_plus = {
+ ---+${lua}
+
+ enable = true,
+
+ hl = "MarkviewCode",
+ border_hl = "MarkviewCodeFg",
+
+ border_top = "โ",
+ border_bottom = "โ"
+
+ ---_
+ },
+
+ reference_definitions = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๏
",
+ hl = "MarkviewPalette4Fg"
+ },
+
+ ---+${lua, Github sites}
+
+ ["github%.com/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com/
+
+ icon = "๎ช ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com//
+
+ icon = "๓ฐณ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+/tree/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com///tree/
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+/commits/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com///commits/
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/releases$"] = {
+ --- github.com///releases
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/tags$"] = {
+ --- github.com///tags
+
+ icon = "๏ฌ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/issues$"] = {
+ --- github.com///issues
+
+ icon = "๎ฌ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/pulls$"] = {
+ --- github.com///pulls
+
+ icon = "๎ฆ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/wiki$"] = {
+ --- github.com///wiki
+
+ icon = "๏ญ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ---_
+ ---+${lua, Commonly used sites by programmers}
+
+ ["developer%.mozilla%.org"] = {
+ priority = 9999,
+
+ icon = "๓ฐ ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["w3schools%.com"] = {
+ priority = 9999,
+
+ icon = "๎ ",
+ hl = "MarkviewPalette4Fg"
+ },
+
+ ["stackoverflow%.com"] = {
+ priority = 9999,
+
+ icon = "๓ฐ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["reddit%.com"] = {
+ priority = 9999,
+
+ icon = "๏ก ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["github%.com"] = {
+ priority = 9999,
+
+ icon = "๎ช ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["gitlab%.com"] = {
+ priority = 9999,
+
+ icon = "๎ซ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["dev%.to"] = {
+ priority = 9999,
+
+ icon = "๓ฑด ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["codepen%.io"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["replit%.com"] = {
+ priority = 9999,
+
+ icon = "๎ข ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["jsfiddle%.net"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["npmjs%.com"] = {
+ priority = 9999,
+
+ icon = "๎ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["pypi%.org"] = {
+ priority = 9999,
+
+ icon = "๓ฐฆ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["mvnrepository%.com"] = {
+ priority = 9999,
+
+ icon = "๎ด ",
+ hl = "MarkviewPalette1Fg"
+ },
+
+ ["medium%.com"] = {
+ priority = 9999,
+
+ icon = "๏บ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["linkedin%.com"] = {
+ priority = 9999,
+
+ icon = "๓ฐป ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["news%.ycombinator%.com"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ---_
+
+ ---_
+ },
+
+ tables = {
+ ---+ ${class, Tables}
+
+ enable = true,
+
+ col_min_width = 10,
+ block_decorator = true,
+ use_virt_lines = false,
+
+ parts = {
+ top = { "โญ", "โ", "โฎ", "โฌ" },
+ header = { "โ", "โ", "โ" },
+ separator = { "โ", "โ", "โค", "โผ" },
+ row = { "โ", "โ", "โ" },
+ bottom = { "โฐ", "โ", "โฏ", "โด" },
+
+ overlap = { "โ", "โ", "โฅ", "โฟ" },
+
+ align_left = "โผ",
+ align_right = "โพ",
+ align_center = { "โด", "โถ" }
+ },
+
+ hl = {
+ top = { "TableHeader", "TableHeader", "TableHeader", "TableHeader" },
+ header = { "TableHeader", "TableHeader", "TableHeader" },
+ separator = { "TableHeader", "TableHeader", "TableHeader", "TableHeader" },
+ row = { "TableBorder", "TableBorder", "TableBorder" },
+ bottom = { "TableBorder", "TableBorder", "TableBorder", "TableBorder" },
+
+ overlap = { "TableBorder", "TableBorder", "TableBorder", "TableBorder" },
+
+ align_left = "TableAlignLeft",
+ align_right = "TableAlignRight",
+ align_center = { "TableAlignCenter", "TableAlignCenter" }
+ }
+
+ ---_
+ },
+
+ ---_
+ },
+ markdown_inline = {
+ ---+${lua}
+
+ enable = true,
+
+ block_references = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๓ฐฟจ ",
+
+ hl = "MarkviewPalette6Fg",
+ file_hl = "MarkviewPalette0Fg",
+ },
+
+ ---_
+ },
+
+ checkboxes = {
+ ---+ ${conf, Minimal style checkboxes}
+ enable = true,
+
+ checked = { text = "๓ฐ ", hl = "MarkviewCheckboxChecked", scope_hl = "MarkviewCheckboxChecked" },
+ unchecked = { text = "๓ฐฐ", hl = "MarkviewCheckboxUnchecked", scope_hl = "MarkviewCheckboxUnchecked" },
+
+ ["/"] = { text = "๓ฑ", hl = "MarkviewCheckboxPending" },
+ [">"] = { text = "๏", hl = "MarkviewCheckboxCancelled" },
+ ["<"] = { text = "๓ฐ", hl = "MarkviewCheckboxCancelled" },
+ ["-"] = { text = "๓ฐถ", hl = "MarkviewCheckboxCancelled", scope_hl = "MarkviewCheckboxStriked" },
+
+ ["?"] = { text = "๓ฐ", hl = "MarkviewCheckboxPending" },
+ ["!"] = { text = "๓ฐฆ", hl = "MarkviewCheckboxUnchecked" },
+ ["*"] = { text = "๓ฐ", hl = "MarkviewCheckboxPending" },
+ ['"'] = { text = "๓ฐธฅ", hl = "MarkviewCheckboxCancelled" },
+ ["l"] = { text = "๓ฐ", hl = "MarkviewCheckboxProgress" },
+ ["b"] = { text = "๓ฐ", hl = "MarkviewCheckboxProgress" },
+ ["i"] = { text = "๓ฐฐ", hl = "MarkviewCheckboxChecked" },
+ ["S"] = { text = "๎พ", hl = "MarkviewCheckboxChecked" },
+ ["I"] = { text = "๓ฐจ", hl = "MarkviewCheckboxPending" },
+ ["p"] = { text = "๏
ค", hl = "MarkviewCheckboxChecked" },
+ ["c"] = { text = "๏
ฅ", hl = "MarkviewCheckboxUnchecked" },
+ ["f"] = { text = "๓ฑ ", hl = "MarkviewCheckboxUnchecked" },
+ ["k"] = { text = "๏", hl = "MarkviewCheckboxPending" },
+ ["w"] = { text = "๏ฝ", hl = "MarkviewCheckboxProgress" },
+ ["u"] = { text = "๓ฐต", hl = "MarkviewCheckboxChecked" },
+ ["d"] = { text = "๓ฐณ", hl = "MarkviewCheckboxUnchecked" },
+ ---_
+ },
+
+ emails = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๏ ",
+ hl = "MarkviewEmail"
+ },
+
+ ---+${lua, Commonly used email service providers}
+
+ ["%@gmail%.com$"] = {
+ --- user@gmail.com
+
+ icon = "๓ฐซ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["%@outlook%.com$"] = {
+ --- user@outlook.com
+
+ icon = "๓ฐดข ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["%@yahoo%.com$"] = {
+ --- user@yahoo.com
+
+ icon = "๏ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["%@icloud%.com$"] = {
+ --- user@icloud.com
+
+ icon = "๓ฐธ ",
+ hl = "MarkviewPalette6Fg"
+ }
+
+ ---_
+
+ ---_
+ },
+
+ embed_files = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๓ฐ ฎ ",
+ hl = "MarkviewPalette7Fg"
+ }
+
+ ---_
+ },
+
+ entities = {
+ ---+${lua}
+
+ enable = true,
+ hl = "Special"
+
+ ---_
+ },
+
+ emoji_shorthands = {
+ enable = true
+ },
+
+ escapes = {
+ enable = true
+ },
+
+ footnotes = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๓ฐฏ ",
+ hl = "MarkviewHyperlink"
+ },
+
+ ["^%d+$"] = {
+ --- Numbered footnotes.
+
+ icon = "๓ฐฏ ",
+ hl = "MarkviewPalette4Fg"
+ }
+
+ ---_
+ },
+
+ highlights = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ padding_left = " ",
+ padding_right = " ",
+
+ hl = "MarkviewPalette3"
+ }
+
+ ---_
+ },
+
+ hyperlinks = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๓ฐท ",
+ hl = "MarkviewHyperlink",
+ },
+
+ ---+${lua, Github sites}
+
+ ["github%.com/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com/
+
+ icon = "๎ช ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com//
+
+ icon = "๓ฐณ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+/tree/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com///tree/
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+/commits/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com///commits/
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/releases$"] = {
+ --- github.com///releases
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/tags$"] = {
+ --- github.com///tags
+
+ icon = "๏ฌ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/issues$"] = {
+ --- github.com///issues
+
+ icon = "๎ฌ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/pulls$"] = {
+ --- github.com///pulls
+
+ icon = "๎ฆ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/wiki$"] = {
+ --- github.com///wiki
+
+ icon = "๏ญ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ---_
+ ---+${lua, Commonly used sites by programmers}
+
+ ["developer%.mozilla%.org"] = {
+ priority = 9999,
+
+ icon = "๓ฐ ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["w3schools%.com"] = {
+ priority = 9999,
+
+ icon = "๎ ",
+ hl = "MarkviewPalette4Fg"
+ },
+
+ ["stackoverflow%.com"] = {
+ priority = 9999,
+
+ icon = "๓ฐ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["reddit%.com"] = {
+ priority = 9999,
+
+ icon = "๏ก ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["github%.com"] = {
+ priority = 9999,
+
+ icon = "๎ช ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["gitlab%.com"] = {
+ priority = 9999,
+
+ icon = "๎ซ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["dev%.to"] = {
+ priority = 9999,
+
+ icon = "๓ฑด ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["codepen%.io"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["replit%.com"] = {
+ priority = 9999,
+
+ icon = "๎ข ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["jsfiddle%.net"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["npmjs%.com"] = {
+ priority = 9999,
+
+ icon = "๎ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["pypi%.org"] = {
+ priority = 9999,
+
+ icon = "๓ฐฆ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["mvnrepository%.com"] = {
+ priority = 9999,
+
+ icon = "๎ด ",
+ hl = "MarkviewPalette1Fg"
+ },
+
+ ["medium%.com"] = {
+ priority = 9999,
+
+ icon = "๏บ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["linkedin%.com"] = {
+ priority = 9999,
+
+ icon = "๓ฐป ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["news%.ycombinator%.com"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ---_
+
+ ---_
+ },
+
+ images = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๓ฐฅถ ",
+ hl = "MarkviewImage",
+ },
+
+ ["%.svg$"] = { icon = "๓ฐก " },
+ ["%.png$"] = { icon = "๓ฐธญ " },
+ ["%.jpg$"] = { icon = "๓ฐฅ " },
+ ["%.gif$"] = { icon = "๓ฐตธ " },
+ ["%.pdf$"] = { icon = "๎ฝ " }
+
+ ---_
+ },
+
+ inline_codes = {
+ ---+${lua}
+
+ enable = true,
+ hl = "MarkviewInlineCode",
+
+ padding_left = " ",
+ padding_right = " "
+
+ ---_
+ },
+
+ internal_links = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๏ ",
+ hl = "MarkviewPalette7Fg",
+ },
+
+ ---_
+ },
+
+ uri_autolinks = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๎ฌ ",
+ hl = "MarkviewEmail"
+ },
+
+ ---+${lua, Github sites}
+
+ ["github%.com/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com/
+
+ icon = "๎ช ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com//
+
+ icon = "๓ฐณ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+/tree/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com///tree/
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+/commits/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com///commits/
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/releases$"] = {
+ --- github.com///releases
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/tags$"] = {
+ --- github.com///tags
+
+ icon = "๏ฌ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/issues$"] = {
+ --- github.com///issues
+
+ icon = "๎ฌ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/pulls$"] = {
+ --- github.com///pulls
+
+ icon = "๎ฆ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/wiki$"] = {
+ --- github.com///wiki
+
+ icon = "๏ญ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ---_
+ ---+${lua, Commonly used sites by programmers}
+
+ ["developer%.mozilla%.org"] = {
+ priority = 9999,
+
+ icon = "๓ฐ ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["w3schools%.com"] = {
+ priority = 9999,
+
+ icon = "๎ ",
+ hl = "MarkviewPalette4Fg"
+ },
+
+ ["stackoverflow%.com"] = {
+ priority = 9999,
+
+ icon = "๓ฐ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["reddit%.com"] = {
+ priority = 9999,
+
+ icon = "๏ก ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["github%.com"] = {
+ priority = 9999,
+
+ icon = "๎ช ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["gitlab%.com"] = {
+ priority = 9999,
+
+ icon = "๎ซ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["dev%.to"] = {
+ priority = 9999,
+
+ icon = "๓ฑด ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["codepen%.io"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["replit%.com"] = {
+ priority = 9999,
+
+ icon = "๎ข ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["jsfiddle%.net"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["npmjs%.com"] = {
+ priority = 9999,
+
+ icon = "๎ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["pypi%.org"] = {
+ priority = 9999,
+
+ icon = "๓ฐฆ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["mvnrepository%.com"] = {
+ priority = 9999,
+
+ icon = "๎ด ",
+ hl = "MarkviewPalette1Fg"
+ },
+
+ ["medium%.com"] = {
+ priority = 9999,
+
+ icon = "๏บ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["linkedin%.com"] = {
+ priority = 9999,
+
+ icon = "๓ฐป ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["news%.ycombinator%.com"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ---_
+
+ ---_
+ },
+
+ ---_
+ },
+ html = {
+ ---+${lua}
+ enable = true,
+
+ container_elements = {
+ ---+${lua}
+
+ enable = true,
+
+ ---+${lua, Various inline elements used in markdown}
+
+ ["^b$"] = {
+ on_opening_tag = { conceal = "" },
+ on_node = { hl_group = "Bold" },
+ on_closing_tag = { conceal = "" },
+ },
+ ["^code$"] = {
+ on_opening_tag = { conceal = "", hl_mode = "combine", virt_text_pos = "inline", virt_text = { { " ", "MarkviewInlineCode" } } },
+ on_node = { hl_group = "MarkviewInlineCode" },
+ on_closing_tag = { conceal = "", hl_mode = "combine", virt_text_pos = "inline", virt_text = { { " ", "MarkviewInlineCode" } } },
+ },
+ ["^em$"] = {
+ on_opening_tag = { conceal = "" },
+ on_node = { hl_group = "@text.emphasis" },
+ on_closing_tag = { conceal = "" },
+ },
+ ["^i$"] = {
+ on_opening_tag = { conceal = "" },
+ on_node = { hl_group = "Italic" },
+ on_closing_tag = { conceal = "" },
+ },
+ ["^mark$"] = {
+ on_opening_tag = { conceal = "" },
+ on_node = { hl_group = "MarkviewPalette1" },
+ on_closing_tag = { conceal = "" },
+ },
+ ["^strong$"] = {
+ on_opening_tag = { conceal = "" },
+ on_node = { hl_group = "@text.strong" },
+ on_closing_tag = { conceal = "" },
+ },
+ ["^sub$"] = {
+ on_opening_tag = { conceal = "", hl_mode = "combine", virt_text_pos = "inline", virt_text = { { "โ[", "MarkviewSubscript" } } },
+ on_node = { hl_group = "MarkviewSubscript" },
+ on_closing_tag = { conceal = "", hl_mode = "combine", virt_text_pos = "inline", virt_text = { { "]", "MarkviewSubscript" } } },
+ },
+ ["^sup$"] = {
+ on_opening_tag = { conceal = "", hl_mode = "combine", virt_text_pos = "inline", virt_text = { { "โ[", "MarkviewSuperscript" } } },
+ on_node = { hl_group = "MarkviewSuperscript" },
+ on_closing_tag = { conceal = "", hl_mode = "combine", virt_text_pos = "inline", virt_text = { { "]", "MarkviewSuperscript" } } },
+ },
+ ["^u$"] = {
+ on_opening_tag = { conceal = "" },
+ on_node = { hl_group = "Underlined" },
+ on_closing_tag = { conceal = "" },
+ },
+
+ ---_
+ ---_
+ },
+
+ headings = {
+ ---+${lua}
+
+ enable = true,
+
+ heading_1 = {
+ hl_group = "MarkviewPalette1Bg"
+ },
+ heading_2 = {
+ hl_group = "MarkviewPalette2Bg"
+ },
+ heading_3 = {
+ hl_group = "MarkviewPalette3Bg"
+ },
+ heading_4 = {
+ hl_group = "MarkviewPalette4Bg"
+ },
+ heading_5 = {
+ hl_group = "MarkviewPalette5Bg"
+ },
+ heading_6 = {
+ hl_group = "MarkviewPalette6Bg"
+ },
+
+ ---_
+ },
+
+ void_elements = {
+ ---+${lua}
+
+ enable = true,
+
+ ---+${lua, Various void elements used in markdown}
+
+ ["^hr$"] = {
+ on_node = {
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { "โ", "MarkviewGradient2" },
+ { "โ", "MarkviewGradient3" },
+ { "โ", "MarkviewGradient4" },
+ { "โ", "MarkviewGradient5" },
+ { " โ ", "MarkviewGradient9" },
+ { "โ", "MarkviewGradient5" },
+ { "โ", "MarkviewGradient4" },
+ { "โ", "MarkviewGradient3" },
+ { "โ", "MarkviewGradient2" },
+ }
+ }
+ },
+ ["^br$"] = {
+ on_node = {
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { "๓ฑฆ", "Comment" },
+ }
+ }
+ },
+
+ ---_
+
+ ---_
+ }
+
+ ---_
+ },
+ latex = {
+ ---+${lua}
+
+ enable = true,
+
+ blocks = {
+ ---+${lua}
+
+ enable = true,
+
+ hl = "MarkviewCode",
+ pad_char = " ",
+ pad_amount = 3,
+
+ text = " ๎ญค LaTeX ",
+ text_hl = "MarkviewCodeInfo"
+
+ ---_
+ },
+
+ commands = {
+ ---+${lua}
+
+ enable = true,
+
+ ---+${lua, Various commonly used LaTeX math commands}
+
+ ["boxed"] = {
+ condition = function (item)
+ return #item.args == 1;
+ end,
+ on_command = {
+ conceal = ""
+ },
+
+ on_args = {
+ {
+ on_before = function (item)
+ return {
+ end_col = item.range[2] + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { "๏ ", "MarkviewPalette4Fg" },
+ { "[", "@punctuation.bracket.latex" }
+ },
+
+ hl_mode = "combine"
+ }
+ end,
+
+ after_offset = function (range)
+ return { range[1], range[2], range[3], range[4] - 1 };
+ end,
+ on_after = function (item)
+ return {
+ end_col = item.range[4],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { "]", "@punctuation.bracket" }
+ },
+
+ hl_mode = "combine"
+ }
+ end
+ }
+ }
+ },
+ ["frac"] = {
+ condition = function (item)
+ return #item.args == 2;
+ end,
+ on_command = {
+ conceal = ""
+ },
+
+ on_args = {
+ {
+ on_before = function (item)
+ return {
+ end_col = item.range[2] + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { "(", "@punctuation.bracket" }
+ },
+
+ hl_mode = "combine"
+ }
+ end,
+
+ after_offset = function (range)
+ return { range[1], range[2], range[3], range[4] - 1 };
+ end,
+ on_after = function (item)
+ return {
+ end_col = item.range[4],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { ")", "@punctuation.bracket" },
+ { " รท ", "@keyword.function" }
+ },
+
+ hl_mode = "combine"
+ }
+ end
+ },
+ {
+ on_before = function (item)
+ return {
+ end_col = item.range[2] + 1,
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { "(", "@punctuation.bracket" }
+ },
+
+ hl_mode = "combine"
+ }
+ end,
+
+ after_offset = function (range)
+ return { range[1], range[2], range[3], range[4] - 1 };
+ end,
+ on_after = function (item)
+ return {
+ end_col = item.range[4],
+ conceal = "",
+
+ virt_text_pos = "inline",
+ virt_text = {
+ { ")", "@punctuation.bracket" },
+ },
+
+ hl_mode = "combine"
+ }
+ end
+ },
+ }
+ },
+
+ ["sin"] = operator("sin"),
+ ["cos"] = operator("cos"),
+ ["tan"] = operator("tan"),
+
+ ["sinh"] = operator("sinh"),
+ ["cosh"] = operator("cosh"),
+ ["tanh"] = operator("tanh"),
+
+ ["csc"] = operator("csc"),
+ ["sec"] = operator("sec"),
+ ["cot"] = operator("cot"),
+
+ ["csch"] = operator("csch"),
+ ["sech"] = operator("sech"),
+ ["coth"] = operator("coth"),
+
+ ["arcsin"] = operator("arcsin"),
+ ["arccos"] = operator("arccos"),
+ ["arctan"] = operator("arctan"),
+
+ ["arg"] = operator("arg"),
+ ["deg"] = operator("deg"),
+ ["det"] = operator("det"),
+ ["dim"] = operator("dim"),
+ ["exp"] = operator("exp"),
+ ["gcd"] = operator("gcd"),
+ ["hom"] = operator("hom"),
+ ["inf"] = operator("inf"),
+ ["ker"] = operator("ker"),
+ ["lg"] = operator("lg"),
+
+ ["lim"] = operator("lim"),
+ ["liminf"] = operator("lim inf", "inline", 7),
+ ["limsup"] = operator("lim sup", "inline", 7),
+
+ ["ln"] = operator("ln"),
+ ["log"] = operator("log"),
+ ["min"] = operator("min"),
+ ["max"] = operator("max"),
+ ["Pr"] = operator("Pr"),
+ ["sup"] = operator("sup"),
+ ["sqrt"] = operator(symbols.entries.sqrt, "inline", 5),
+ ["lvert"] = operator(symbols.entries.vert, "inline", 6),
+ ["lVert"] = operator(symbols.entries.Vert, "inline", 6),
+
+ ---_
+
+ ---_
+ },
+
+ escapes = {
+ enable = true
+ },
+
+ fonts = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ enable = true,
+ hl = "MarkviewSpecial"
+ },
+ -- ["^mathtt$"] = { hl = "MarkviewPalette1" }
+ ---_
+ },
+
+ inlines = {
+ ---+${lua}
+
+ enable = true,
+
+ padding_left = " ",
+ padding_right = " ",
+
+ hl = "MarkviewInlineCode"
+
+ ---_
+ },
+
+ parenthesis = {
+ ---+${lua}
+
+ enable = true,
+
+ left = "(",
+ right = "(",
+ hl = "@punctuation.bracket"
+
+ ---_
+ },
+
+ subscripts = {
+ enable = true,
+
+ hl = "MarkviewSubscript"
+ },
+
+ superscripts = {
+ enable = true,
+
+ hl = "MarkviewSuperscript"
+ },
+
+ symbols = {
+ enable = true,
+
+ hl = "MarkviewComment"
+ },
+
+ texts = {
+ enable = true
+ },
+
+ ---_
+ },
+ typst = {
+ ---+${lua}
+
+ enable = true,
+
+ code_blocks = {
+ ---+${lua}
+
+ enable = true,
+
+ style = "block",
+ text_direction = "right",
+
+ min_width = 60,
+ pad_amount = 3,
+ pad_char = " ",
+
+ text = "๓ฐฃ Code",
+
+ hl = "MarkviewCode",
+ text_hl = "MarkviewIcon5"
+
+ ---_
+ },
+
+ code_spans = {
+ ---+${lua}
+
+ enable = true,
+
+ padding_left = " ",
+ padding_right = " ",
+
+ hl = "MarkviewCode"
+
+ ---_
+ },
+
+ escapes = {
+ enable = true
+ },
+
+ headings = {
+ ---+ ${class, Headings}
+ enable = true,
+ shift_width = 1,
+
+ heading_1 = {
+ ---+ ${conf, Heading 1}
+ style = "icon",
+ sign = "๓ฐ ", sign_hl = "MarkviewHeading1Sign",
+
+ icon = "๓ฐผ ", hl = "MarkviewHeading1",
+ ---_
+ },
+ heading_2 = {
+ ---+ ${conf, Heading 2}
+ style = "icon",
+ sign = "๓ฐ ", sign_hl = "MarkviewHeading2Sign",
+
+ icon = "๓ฐจ ", hl = "MarkviewHeading2",
+ ---_
+ },
+ heading_3 = {
+ ---+ ${conf, Heading 3}
+ style = "icon",
+
+ icon = "๓ฐผ ", hl = "MarkviewHeading3",
+ ---_
+ },
+ heading_4 = {
+ ---+ ${conf, Heading 4}
+ style = "icon",
+
+ icon = "๓ฐฒ ", hl = "MarkviewHeading4",
+ ---_
+ },
+ heading_5 = {
+ ---+ ${conf, Heading 5}
+ style = "icon",
+
+ icon = "๓ฐผ ", hl = "MarkviewHeading5",
+ ---_
+ },
+ heading_6 = {
+ ---+ ${conf, Heading 6}
+ style = "icon",
+
+ icon = "๓ฐด ", hl = "MarkviewHeading6",
+ ---_
+ }
+ ---_
+ },
+
+ labels = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ hl = "MarkviewInlineCode",
+ padding_left = " ",
+ icon = "๏ซ ",
+ padding_right = " "
+ }
+
+ ---_
+ },
+
+ list_items = {
+ ---+${conf, List items}
+
+ enable = true,
+
+ indent_size = 4,
+ shift_width = 4,
+
+ marker_minus = {
+ add_padding = true,
+
+ text = "๎ฉฑ",
+ hl = "MarkviewListItemMinus"
+ },
+
+ marker_plus = {
+ add_padding = true,
+
+ text = "%d)",
+ hl = "MarkviewListItemPlus"
+ },
+
+ marker_dot = {
+ add_padding = true,
+ }
+
+ ---_
+ },
+
+ math_blocks = {
+ ---+${lua}
+
+ enable = true,
+
+ text = " ๓ฐช Math ",
+ pad_amount = 3,
+ pad_char = " ",
+
+ hl = "MarkviewCode",
+ text_hl = "MarkviewCodeInfo"
+
+ ---_
+ },
+
+ math_spans = {
+ ---+${lua}
+
+ enable = true,
+
+ padding_left = " ",
+ padding_right = " ",
+
+ hl = "MarkviewInlineCode"
+
+ ---_
+ },
+
+ raw_blocks = {
+ ---+${lua}
+
+ enable = true,
+
+ style = "block",
+ label_direction = "right",
+
+ sign = true,
+
+ min_width = 60,
+ pad_amount = 3,
+ pad_char = " ",
+
+ border_hl = "MarkviewCode",
+
+ default = {
+ block_hl = "MarkviewCode",
+ pad_hl = "MarkviewCode"
+ },
+
+ ["diff"] = {
+ block_hl = function (_, line)
+ if line:match("^%+") then
+ return "MarkviewPalette4";
+ elseif line:match("^%-") then
+ return "MarkviewPalette1";
+ else
+ return "MarkviewCode";
+ end
+ end,
+ pad_hl = "MarkviewCode"
+ }
+
+ ---_
+ },
+
+ raw_spans = {
+ ---+${lua}
+
+ enable = true,
+
+ padding_left = " ",
+ padding_right = " ",
+
+ hl = "MarkviewInlineCode"
+
+ ---_
+ },
+
+ reference_links = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๎ฌถ ",
+ hl = "MarkviewHyperlink"
+ },
+
+ ---_
+ },
+
+ subscripts = {
+ enable = true,
+
+ hl = "MarkviewSubscript"
+ },
+
+ superscripts = {
+ enable = true,
+
+ hl = "MarkviewSuperscript"
+ },
+
+ symbols = {
+ enable = true,
+
+ hl = "Special"
+ },
+
+ terms = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ text = "๎ช
",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ---_
+ },
+
+ url_links = {
+ ---+${lua}
+
+ enable = true,
+
+ default = {
+ icon = "๎ฌ ",
+ hl = "MarkviewEmail"
+ },
+
+ ---+${lua, Github sites}
+
+ ["github%.com/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com/
+
+ icon = "๎ช ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com//
+
+ icon = "๓ฐณ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+/tree/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com///tree/
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+/commits/[%a%d%-%_%.]+%/?$"] = {
+ --- github.com///commits/
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/releases$"] = {
+ --- github.com///releases
+
+ icon = "๏ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/tags$"] = {
+ --- github.com///tags
+
+ icon = "๏ฌ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/issues$"] = {
+ --- github.com///issues
+
+ icon = "๎ฌ ",
+ hl = "MarkviewPalette0Fg"
+ },
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/pulls$"] = {
+ --- github.com///pulls
+
+ icon = "๎ฆ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["github%.com/[%a%d%-%_%.]+/[%a%d%-%_%.]+%/wiki$"] = {
+ --- github.com///wiki
+
+ icon = "๏ญ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ---_
+ ---+${lua, Commonly used sites by programmers}
+
+ ["developer%.mozilla%.org"] = {
+ priority = 9999,
+
+ icon = "๓ฐ ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["w3schools%.com"] = {
+ priority = 9999,
+
+ icon = "๎ ",
+ hl = "MarkviewPalette4Fg"
+ },
+
+ ["stackoverflow%.com"] = {
+ priority = 9999,
+
+ icon = "๓ฐ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["reddit%.com"] = {
+ priority = 9999,
+
+ icon = "๏ก ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["github%.com"] = {
+ priority = 9999,
+
+ icon = "๎ช ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["gitlab%.com"] = {
+ priority = 9999,
+
+ icon = "๎ซ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["dev%.to"] = {
+ priority = 9999,
+
+ icon = "๓ฑด ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["codepen%.io"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["replit%.com"] = {
+ priority = 9999,
+
+ icon = "๎ข ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ["jsfiddle%.net"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["npmjs%.com"] = {
+ priority = 9999,
+
+ icon = "๎ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["pypi%.org"] = {
+ priority = 9999,
+
+ icon = "๓ฐฆ ",
+ hl = "MarkviewPalette0Fg"
+ },
+
+ ["mvnrepository%.com"] = {
+ priority = 9999,
+
+ icon = "๎ด ",
+ hl = "MarkviewPalette1Fg"
+ },
+
+ ["medium%.com"] = {
+ priority = 9999,
+
+ icon = "๏บ ",
+ hl = "MarkviewPalette6Fg"
+ },
+
+ ["linkedin%.com"] = {
+ priority = 9999,
+
+ icon = "๓ฐป ",
+ hl = "MarkviewPalette5Fg"
+ },
+
+ ["news%.ycombinator%.com"] = {
+ priority = 9999,
+
+ icon = "๏ ",
+ hl = "MarkviewPalette2Fg"
+ },
+
+ ---_
+
+ ---_
+ }
+
+ ---_
+ },
+ yaml = {
+ ---+${lua}
+
+ enable = true,
+
+ properties = {
+ ---+${lua}
+
+ enable = true,
+
+ data_types = {
+ ["text"] = {
+ text = " ๓ฐ ", hl = "MarkviewIcon4"
+ },
+ ["list"] = {
+ text = " ๓ฐ ", hl = "MarkviewIcon5"
+ },
+ ["number"] = {
+ text = " ๏ท ", hl = "MarkviewIcon6"
+ },
+ ["checkbox"] = {
+ ---@diagnostic disable
+ text = function (_, item)
+ return item.value == "true" and " ๓ฐฒ " or " ๓ฐฑ "
+ end,
+ ---@diagnostic enable
+ hl = "MarkviewIcon6"
+ },
+ ["date"] = {
+ text = " ๓ฐญ ", hl = "MarkviewIcon2"
+ },
+ ["date_&_time"] = {
+ text = " ๓ฐฅ ", hl = "MarkviewIcon3"
+ }
+ },
+
+ default = {
+ use_types = true,
+
+ border_top = " โ ",
+ border_middle = " โ ",
+ border_bottom = " โฐโธ",
+
+ border_hl = "MarkviewComment"
+ },
+
+ ["^tags$"] = {
+ match_string = "^tags$",
+ use_types = false,
+
+ text = " ๓ฐน ",
+ hl = nil
+ },
+ ["^aliases$"] = {
+ match_string = "^aliases$",
+ use_types = false,
+
+ text = " ๓ฑซ ",
+ hl = nil
+ },
+ ["^cssclasses$"] = {
+ match_string = "^cssclasses$",
+ use_types = false,
+
+ text = " ๎ ",
+ hl = nil
+ },
+
+
+ ["^publish$"] = {
+ match_string = "^publish$",
+ use_types = false,
+
+ text = " ๎ผ ",
+ hl = nil
+ },
+ ["^permalink$"] = {
+ match_string = "^permalink$",
+ use_types = false,
+
+ text = " ๏ฅ ",
+ hl = nil
+ },
+ ["^description$"] = {
+ match_string = "^description$",
+ use_types = false,
+
+ text = " ๓ฐผ ",
+ hl = nil
+ },
+ ["^image$"] = {
+ match_string = "^image$",
+ use_types = false,
+
+ text = " ๓ฐซ ",
+ hl = nil
+ },
+ ["^cover$"] = {
+ match_string = "^cover$",
+ use_types = false,
+
+ text = " ๓ฐน ",
+ hl = nil
+ }
+
+ ---_
+ }
+
+ ---_
+ }
+ ---_
+};
+
+spec.config = vim.deepcopy(spec.default);
+
+spec.fixup = {
+ ---+${lua}
+
+ ["buf_ignore"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "buf_ignore",
+ alter = "preview โ ignore_buftypes"
+ });
+
+ if vim.islist(value) == false then
+ return {};
+ end
+
+ return {
+ preview = {
+ ignore_buftypes = value;
+ }
+ };
+ ---_
+ end,
+ ["callbacks"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "callbacks",
+ alter = "preview โ callbacks"
+ });
+
+ if type(value) ~= "table" then
+ return {};
+ end
+
+ return {
+ preview = {
+ callbacks = value;
+ }
+ };
+ ---_
+ end,
+ ["debounce"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "debounce",
+ alter = "preview โ debounce"
+ });
+
+ if type(value) ~= "number" then
+ return {};
+ end
+
+ return {
+ preview = {
+ debounce = value;
+ }
+ };
+ ---_
+ end,
+ ["filetypes"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "filetypes",
+ alter = "preview โ filetypes"
+ });
+
+ if vim.islist(value) == false then
+ return {};
+ end
+
+ return {
+ preview = {
+ filetypes = value;
+ }
+ };
+ ---_
+ end,
+ ["hybrid_modes"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "hybrid_modes",
+ alter = "preview โ hybrid_modes"
+ });
+
+ if vim.islist(value) == false then
+ return {};
+ end
+
+ return {
+ preview = {
+ hybrid_modes = value;
+ }
+ };
+ ---_
+ end,
+ ["ignore_nodes"] = function (_)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "ignore_nodes",
+ alter = "preview โ ignore_previews"
+ });
+
+ return {};
+ ---_
+ end,
+ ["initial_state"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "initial_state",
+ alter = "preview โ enable"
+ });
+
+ if type(value) ~= "boolean" then
+ return {};
+ else
+ return {
+ preview = {
+ enable = value
+ }
+ };
+ end
+ ---_
+ end,
+ ["max_file_length"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "max_file_length",
+ alter = "preview โ max_buf_lines"
+ });
+
+ if type(value) ~= "integer" then
+ return {};
+ else
+ return {
+ preview = {
+ max_buf_lines = value
+ }
+ };
+ end
+ ---_
+ end,
+ ["modes"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "modes",
+ alter = "preview โ modes"
+ });
+
+ if vim.islist(value) == false then
+ return {};
+ end
+
+ return {
+ preview = {
+ modes = value;
+ }
+ };
+ ---_
+ end,
+ ["render_distance"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "render_distance",
+ alter = "preview โ draw_range"
+ });
+
+ if vim.islist(value) == false or #value ~= 2 then
+ return {};
+ elseif type(value) == "number" then
+ health.notify("type", {
+ option = "preview โ draw_range",
+ uses = "[ integer, integer ]",
+ got = type(value)
+ });
+
+ return {
+ preview = {
+ draw_range = { value, value }
+ }
+ };
+ end
+
+ return {};
+ ---_
+ end,
+ ["split_conf"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "split_conf",
+ alter = "preview โ splitview_winopts"
+ });
+
+ if type(value) ~= "table" then
+ health.notify("type", {
+ option = "preview โ splitview_winopts",
+ uses = "table",
+ got = type(value)
+ });
+
+ return {};
+ end
+
+ return {
+ preview = {
+ splitview_winopts = value;
+ }
+ };
+ ---_
+ end,
+
+ ["injections"] = function ()
+ ---+${lua}
+
+ health.notify("deprecation", {
+ option = "injections",
+ tip = {
+ { "See ", "Normal" },
+ { " :h markview-advanced ", "DiagnosticVirtualTextHint" }
+ }
+ });
+
+ return {};
+
+ ---_
+ end,
+
+
+ ["block_quotes"] = function (config)
+ ---+${lua}
+
+ local _o = {
+ markdown = {
+ block_quotes = {};
+ }
+ };
+
+ --- Handles old callout definitions.
+ ---@param callouts table[]
+ local handle_callouts = function (callouts)
+ ---+${lua}
+
+ health.notify("deprecation", {
+ option = "markdown โ block_quotes โ callouts",
+ tip = {
+ { "Create a callout using the " },
+ { " match_string ", "DiagnosticVirtualTextInfo" },
+ { " as the key inside " },
+ { " markdown โ block_quotes ", "DiagnosticVirtualTextHint" },
+ { "." },
+ }
+ });
+
+ for _, callout in ipairs(callouts) do
+ if callout.match_string then
+ _o.markdown.block_quotes[callout.match_string] = {
+ border = callout.border,
+ border_hl = callout.border_hl,
+
+ hl = callout.hl,
+
+ icon = callout.icon,
+ icon_hl = callout.icon_hl,
+
+ preview = callout.preview,
+ preview_hl = callout.preview_hl,
+
+ title = callout.title,
+ };
+ end
+ end
+
+ ---_
+ end
+
+ for key, value in pairs(config) do
+ if key == "callouts" then
+ if vim.islist(value) then
+ handle_callouts(value);
+ end
+ else
+ _o.markdown.block_quotes[key] = value;
+ end
+ end
+
+ return _o;
+
+ ---_
+ end,
+ ["code_blocks"] = function (config)
+ ---+${lua}
+
+ local _o = {
+ preview = {},
+ markdown = {
+ code_blocks = {}
+ }
+ };
+
+ for key, value in pairs(config) do
+ if key == "icon" then
+ health.notify("deprecation", {
+ option = "code_blocks โ icon",
+ alter = "preview โ icon_provider"
+ });
+
+ _o.preview.icon_provider = value;
+ elseif key == "language_names" then
+ health.notify("deprecation", {
+ option = "code_blocks โ language_names"
+ });
+ elseif key == "hl" then
+ health.notify("deprecation", {
+ option = "code_blocks โ hl",
+ alter = "code_blocks โ border_hl"
+ });
+
+ _o.markdown.code_blocks.border_hl = value;
+ elseif key == "style" then
+ if value == "minimal" then
+ health.notify("type", {
+ option = "markdown โ code_blocks โ style",
+ uses = '"simple" | "block"',
+ got = '"minimal"'
+ });
+
+ _o.markdown.code_blocks.style = "block";
+ else
+ _o.markdown.code_blocks.style = value;
+ end
+ else
+ _o.markdown.code_blocks[key] = value;
+ end
+ end
+
+ return _o;
+ ---_
+ end,
+ ["headings"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "headings",
+ alter = "markdown โ headings"
+ });
+
+ return {
+ markdown = {
+ headings = value
+ }
+ };
+ ---_
+ end,
+ ["horizontal_rules"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "horizontal_rules",
+ alter = "markdown โ horizontal_rules"
+ });
+
+ return {
+ markdown = {
+ horizontal_rules = value
+ }
+ };
+ ---_
+ end,
+ ["list_items"] = function (value)
+ ---+${lua}
+ health.notify("deprecation", {
+ option = "list_items",
+ alter = "markdown โ list_items"
+ });
+
+ return {
+ markdown = {
+ list_items = value
+ }
+ };
+ ---_
+ end,
+ ["tables"] = function (config)
+ ---+${lua}
+ local _o = {
+ markdown = {
+ tables = {}
+ }
+ };
+
+ health.notify("deprecation", {
+ option = "tables",
+ alter = "markdown โ tables"
+ });
+
+ for k, v in pairs(config) do
+ if k == "parts" and vim.islist(v) then
+ --- Legacy option spec
+ elseif k == "hl" and vim.islist(v) then
+ --- Legacy option spec
+ elseif k == "col_min_width" then
+ health.notify("deprecation", {
+ option = "markdown โ tables โ col_min_width"
+ });
+ else
+ _o.markdown.tables[k] = v;
+ end
+ end
+
+ return _o;
+ ---_
+ end,
+
+ ["inline_codes"] = function (value)
+ ---+${lua}
+
+ return {
+ markdown_inline = {
+ inline_codes = value
+ }
+ };
+
+ ---_
+ end,
+ ["checkboxes"] = function (config)
+ ---+${lua}
+
+ local _o = {
+ markdown_inline = {
+ checkboxes = {}
+ }
+ };
+
+ for k, v in pairs(config) do
+ if k == "custom" then
+ if vim.islist(v) == false then
+ goto invalid_type;
+ end
+
+ for _, entry in ipairs(v) do
+ if entry.match_string then
+ _o.markdown_inline.checkboxes[entry.match_string] = {
+ text = entry.text,
+ hl = entry.hl,
+
+ scope_hl = entry.scope_hl
+ };
+ end
+ end
+
+ ::invalid_type::
+ else
+ _o.markdown_inline.checkboxes[k] = v;
+ end
+ end
+
+ return _o;
+
+ ---_
+ end,
+ ["links"] = function (config)
+ ---+${lua}
+
+ local _o = {
+ markdown_inline = {}
+ };
+
+ --- Handles link config tables.
+ ---@param opt string
+ ---@param val table
+ local function handle_link (opt, val)
+ ---+${lua}
+
+ local _l = {
+ default = {}
+ };
+
+ for k, v in pairs(val) do
+ if k == "icon" then
+ _l.default[k] = v;
+ elseif k == "hl" then
+ _l.default[k] = v;
+ elseif k == "custom" then
+ if vim.islist(v) == false then
+ goto invalid_type;
+ end
+
+ for _, entry in ipairs(v) do
+ if entry.match_string then
+ _l[entry.match_string] = {
+ text = entry.text,
+ hl = entry.hl
+ };
+ end
+ end
+
+ ::invalid_type::
+ elseif k ~= "__emoji_link_compatability" then
+ _l[k] = v;
+ end
+ end
+
+ _o.markdown_inline[opt] = _l;
+ ---_
+ end
+
+ for k, v in pairs(config) do
+ if vim.list_contains({ "hyperlinks", "images", "emails", "internals" }, k) then
+ if k == "internals" then
+ handle_link("internal_links", v);
+ else
+ handle_link(k, v);
+ end
+ end
+ end
+
+ return _o;
+
+ ---_
+ end,
+ ["footnotes"] = function (config)
+ ---+${lua}
+
+ local _o = {
+ markdown_inline = {
+ footnotes = {}
+ }
+ };
+
+ --- Handles link config tables.
+ ---@param opt string
+ ---@param val table
+ local function handle_link (opt, val)
+ ---+${lua}
+
+ local _l = {
+ default = {}
+ };
+
+ for k, v in pairs(val) do
+ if k == "icon" then
+ _l.default[k] = v;
+ elseif k == "hl" then
+ _l.default[k] = v;
+ elseif k == "custom" then
+ if vim.islist(v) == false then
+ goto invalid_type;
+ end
+
+ for _, entry in ipairs(v) do
+ if entry.match_string then
+ _l[entry.match_string] = {
+ text = entry.text,
+ hl = entry.hl
+ };
+ end
+ end
+
+ ::invalid_type::
+ elseif k ~= "use_unicode" then
+ _l[k] = v;
+ end
+ end
+
+ _o.markdown_inline[opt] = _l;
+ ---_
+ end
+
+ handle_link("footnotes", config);
+ return _o;
+
+ ---_
+ end,
+
+ ["html"] = function (value)
+ ---+${lua}
+
+ if value.entities then
+ health.notify("deprecation", {
+ option = "html โ entities",
+ alter = "markdown_inline โ entities"
+ });
+ end
+
+ return {
+ markdown_inline = {
+ entities = value.entities
+ },
+ html = {
+ container_elements = value.container_elements,
+ headings = value.headings,
+ void_elements = value.void_elements
+ }
+ };
+ ---_
+ end,
+
+ ["latex"] = function (config)
+ ---+${lua}
+
+ local _o = {
+ latex = {}
+ };
+
+ for k, v in pairs(config) do
+ if k == "brackets" then
+ health.notify("deprecation", {
+ option = "latex โ brackets",
+ alter = "latex โ parenthesis"
+ });
+
+ _o.latex.parenthesis = v;
+ elseif k == "block" then
+ health.notify("deprecation", {
+ option = "latex โ block",
+ alter = "latex โ blocks"
+ });
+
+ _o.latex.blocks = v;
+ elseif k == "inline" then
+ health.notify("deprecation", {
+ option = "latex โ inline",
+ alter = "latex โ inlines"
+ });
+
+ _o.latex.inlines = v;
+ elseif k == "operators" then
+ health.notify("deprecation", {
+ option = "latex โ operators",
+ alter = "latex โ commands"
+ });
+
+ local _c = {};
+
+ for _, entry in ipairs(v) do
+ _c[entry.match_string] = {
+ -- TODO, here
+ };
+ end
+
+ _o.latex.commands = _c;
+ elseif k == "symbols" then
+ if v.overwrite then
+ health.notify("deprecation", {
+ option = "latex โ symbols โ overwrite"
+ });
+ end
+
+ if v.groups then
+ health.notify("deprecation", {
+ option = "latex โ symbols โ groups",
+ tip = {
+ { " latex โ symbols โ hl ", "DiagnosticVirtualTextInfo" },
+ { " can be a " },
+ { " fun(buffer, item): string? ", "DiagnosticVirtualTextHint" },
+ { "." },
+ }
+ });
+ end
+
+ _o.latex.symbols = {
+ enable = v.enable,
+ hl = v.hl
+ };
+ elseif k == "subscript" then
+ health.notify("deprecation", {
+ option = "latex โ subscript",
+ alter = "latex โ subscripts"
+ });
+
+ _o.latex.subscripts = v;
+ elseif k == "superscript" then
+ health.notify("deprecation", {
+ option = "latex โ superscript",
+ alter = "latex โ superscripts"
+ });
+
+ _o.latex.superscripts = v;
+ end
+ end
+
+ return _o;
+ ---_
+ end
+ ---_
+};
+
+--- Tries to fix deprecated config spec
+---@param config table?
+---@return table
+spec.fix_config = function (config)
+ ---+${lua}
+
+ if type(config) ~= "table" then
+ return {};
+ end
+
+ --- Table containing valid options.
+ local main = {
+ renderers = config.renderers,
+ highlight_groups = config.highlight_groups,
+
+ preview = config.preview,
+ experimental = config.experimental,
+
+ html = config.html,
+ latex = config.latex,
+ markdown = config.markdown,
+ markdown_inline = config.markdown_inline,
+ typst = config.typst,
+ yaml = config.yaml,
+ };
+
+ --- Table containing the fixed version of
+ --- deprecated options.
+ local fixed = {};
+
+ for k, v in pairs(config) do
+ if spec.fixup[k] then
+ local _f, _r = pcall(spec.fixup[k], v);
+
+ if _f == true then
+ fixed = vim.tbl_deep_extend("force", fixed, _r);
+ end
+ end
+ end
+
+ if vim.tbl_isempty(fixed) == false then
+ health.fixed_config = fixed;
+ end
+
+ return vim.tbl_deep_extend("force", main, fixed);
+ ---_
+end
+
+--- Setup function for markview.
+---@param config mkv.config?
+spec.setup = function (config)
+ config = spec.fix_config(config);
+ spec.config = vim.tbl_deep_extend("force", spec.config, config);
+end
+
+--- Options for the configuration table parser.
+---@class spec.options
+---
+---@field fallback any Fallback value to return.
+---@field eval? string[] Keys that should be evaluated(defaults to `vim.tbl_keys()`).
+---@field eval_ignore? string[] Keys that shouldn't be evaluated.
+---@field ignore_enable? boolean Whether to ignore `enable = false` when parsing config
+---@field source? table Custom source config(defaults to `spec.config` when nil).
+---@field eval_args? any[] Arguments used to evaluate the output value's keys.
+---@field args? { __is_arg_list: boolean?, [integer]: any } Arguments used to parse the configuration table. Use `__is_arg_list = true` if nested configs use different arguments.
+
+--- Function to retrieve configuration options
+--- from a config table.
+---@param keys ( string | integer )[]
+---@param opts spec.options
+---@return any
+spec.get = function (keys, opts)
+ ---+${lua}
+
+ --- In case the values are correctly provided..
+ keys = keys or {};
+ opts = opts or {};
+
+ --- Turns a dynamic value into
+ --- a static value.
+ ---@param val any | fun(...): any
+ ---@param args any[]?
+ ---@return any
+ local function to_static(val, args)
+ ---+${lua}
+
+ if type(val) ~= "function" then
+ return val;
+ end
+
+ args = args or {};
+
+ ---@diagnostic disable
+ if pcall(val, unpack(args)) then
+ return val(unpack(args));
+ end
+ ---@diagnostic enable
+
+ return val;
+ ---_
+ end
+
+ ---@param index integer | string
+ ---@return any
+ local function get_arg(index)
+ ---+${lua}
+ if type(opts.args) ~= "table" then
+ return {};
+ elseif opts.args.__is_arg_list == true then
+ return opts.args[index];
+ else
+ return opts.args;
+ end
+ ---_
+ end
+
+ --- Temporarily store the value.
+ ---
+ --- Use `deepcopy()` as we may need to
+ --- modify this value.
+ ---@type any
+ local val;
+
+ if type(opts.source) == "table" or type(opts.source) == "function" then
+ val = opts.source;
+ elseif spec.config then
+ val = spec.config;
+ else
+ val = {};
+ end
+
+ --- Turn the main value into a static value.
+ --- [ In case a function was provided as the source. ]
+ val = to_static(val, get_arg("init"));
+
+ if type(val) ~= "table" then
+ --- The source isn't a table.
+ return opts.fallback;
+ end
+
+ for k, key in ipairs(keys) do
+ val = to_static(val[key], val.args);
+
+ if k ~= #keys then
+ if type(val) ~= "table" then
+ return opts.fallback;
+ elseif opts.ignore_enable ~= true and val.enable == false then
+ return opts.fallback;
+ end
+ end
+ end
+
+ if vim.islist(opts.eval_args) == true and type(val) == "table" then
+ local _e = {};
+ local eval = opts.eval or vim.tbl_keys(val);
+ local ignore = opts.eval_ignore or {};
+
+ for k, v in pairs(val) do
+ if type(v) ~= "function" then
+ --- A silly attempt at reducing
+ --- wasted time due to extra
+ --- logic.
+ _e[k] = v;
+ elseif vim.list_contains(ignore, k) == false then
+ if vim.list_contains(eval, k) then
+ _e[k] = to_static(v, opts.eval_args);
+ else
+ _e[k] = v;
+ end
+ else
+ _e[k] = v;
+ end
+ end
+
+ val = _e;
+ elseif vim.islist(opts.eval_args) == true and type(val) == "function" then
+ val = to_static(val, opts.eval_args);
+ end
+
+ if val == nil and opts.fallback then
+ return opts.fallback;
+ elseif type(val) == "table" and ( opts.ignore_enable ~= true and val.enable == false ) then
+ return opts.fallback;
+ else
+ return val;
+ end
+
+ ---_
+end
+
+return spec;
diff --git a/lua/markview/symbols.lua b/lua/markview/symbols.lua
new file mode 100644
index 0000000..b2d09ab
--- /dev/null
+++ b/lua/markview/symbols.lua
@@ -0,0 +1,6266 @@
+local symbols = {};
+
+symbols.shorthands = {
+ ---+${lua}
+
+ ["+1"] = "๐",
+ ["-1"] = "๐",
+ ["100"] = "๐ฏ",
+ ["1234"] = "๐ข",
+ ["1st_place_medal"] = "๐ฅ",
+ ["2nd_place_medal"] = "๐ฅ",
+ ["3rd_place_medal"] = "๐ฅ",
+ ["8ball"] = "๐ฑ",
+ ["a"] = "๐
ฐ",
+ ["ab"] = "๐",
+ ["abacus"] = "๐งฎ",
+ ["abc"] = "๐ค",
+ ["abcd"] = "๐ก",
+ ["accept"] = "๐",
+ ["accessibility"] = "โฟ",
+ ["accordion"] = "๐ช",
+ ["adhesive_bandage"] = "๐ฉน",
+ ["adult"] = "๐ง",
+ ["aerial_tramway"] = "๐ก",
+ ["afghanistan"] = "๐ฆ๐ซ",
+ ["airplane"] = "โ",
+ ["aland_islands"] = "๐ฆโ๐ฝ",
+ ["alarm_clock"] = "โฐ",
+ ["albania"] = "๐ฆ",
+ ["alembic"] = "โ",
+ ["algeria"] = "๐ฉ",
+ ["alien"] = "๐ฝ",
+ ["ambulance"] = "๐",
+ ["american_samoa"] = "๐ฆ",
+ ["amphora"] = "๐บ",
+ ["anatomical_heart"] = "๐ซ",
+ ["anchor"] = "โ",
+ ["andorra"] = "๐ฆ",
+ ["angel"] = "๐ผ",
+ ["anger"] = "๐ข",
+ ["angola"] = "๐ฆ",
+ ["angry"] = "๐ ",
+ ["anguilla"] = "๐ฆ",
+ ["anguished"] = "๐ง",
+ ["ant"] = "๐",
+ ["antarctica"] = "๐ฆ",
+ ["antigua_barbuda"] = "๐ฆ",
+ ["apple"] = "๐",
+ ["aquarius"] = "โ",
+ ["argentina"] = "๐ฆ",
+ ["aries"] = "โ",
+ ["armenia"] = "๐ฆ",
+ ["arrow_backward"] = "โ",
+ ["arrow_double_down"] = "โฌ",
+ ["arrow_double_up"] = "โซ",
+ ["arrow_down"] = "โฌ",
+ ["arrow_down_small"] = "๐ฝ",
+ ["arrow_forward"] = "โถ",
+ ["arrow_heading_down"] = "โคต",
+ ["arrow_heading_up"] = "โคด",
+ ["arrow_left"] = "โฌ
",
+ ["arrow_lower_left"] = "โ",
+ ["arrow_lower_right"] = "โ",
+ ["arrow_right"] = "โก",
+ ["arrow_right_hook"] = "โช",
+ ["arrow_up"] = "โฌ",
+ ["arrow_up_down"] = "โ",
+ ["arrow_up_small"] = "๐ผ",
+ ["arrow_upper_left"] = "โ",
+ ["arrow_upper_right"] = "โ",
+ ["arrows_clockwise"] = "๐",
+ ["arrows_counterclockwise"] = "๐",
+ ["art"] = "๐จ",
+ ["articulated_lorry"] = "๐",
+ ["artificial_satellite"] = "๐ฐ",
+ ["artist"] = "๐ง",
+ ["aruba"] = "๐ฆ",
+ ["ascension_island"] = "๐ฆ",
+ ["asterisk"] = "*",
+ ["astonished"] = "๐ฒ",
+ ["astronaut"] = "๐ง",
+ ["athletic_shoe"] = "๐",
+ ["atm"] = "๐ง",
+ ["atom"] = "",
+ ["atom_symbol"] = "โ",
+ ["australia"] = "๐ฆ",
+ ["austria"] = "๐ฆ",
+ ["auto_rickshaw"] = "๐บ",
+ ["avocado"] = "๐ฅ",
+ ["axe"] = "๐ช",
+ ["azerbaijan"] = "๐ฆ",
+ ["b"] = "๐
ฑ",
+ ["baby"] = "๐ถ",
+ ["baby_bottle"] = "๐ผ",
+ ["baby_chick"] = "๐ค",
+ ["baby_symbol"] = "๐ผ",
+ ["back"] = "๐",
+ ["bacon"] = "๐ฅ",
+ ["badger"] = "๐ฆก",
+ ["badminton"] = "๐ธ",
+ ["bagel"] = "๐ฅฏ",
+ ["baggage_claim"] = "๐",
+ ["baguette_bread"] = "๐ฅ",
+ ["bahamas"] = "๐ง",
+ ["bahrain"] = "๐ง",
+ ["balance_scale"] = "โ",
+ ["bald_man"] = "๐จ",
+ ["bald_woman"] = "๐ฉ",
+ ["ballet_shoes"] = "๐ฉฐ",
+ ["balloon"] = "๐",
+ ["ballot_box"] = "๐ณ",
+ ["ballot_box_with_check"] = "โ",
+ ["bamboo"] = "๐",
+ ["banana"] = "๐",
+ ["bangbang"] = "โผ",
+ ["bangladesh"] = "๐ง",
+ ["banjo"] = "๐ช",
+ ["bank"] = "๐ฆ",
+ ["bar_chart"] = "๐",
+ ["barbados"] = "๐ง",
+ ["barber"] = "๐",
+ ["baseball"] = "โพ",
+ ["basket"] = "๐งบ",
+ ["basketball"] = "๐",
+ ["basketball_man"] = "โน",
+ ["basketball_woman"] = "โน",
+ ["bat"] = "๐ฆ",
+ ["bath"] = "๐",
+ ["bathtub"] = "๐",
+ ["battery"] = "๐",
+ ["beach_umbrella"] = "๐",
+ ["beans"] = "๐ซ",
+ ["bear"] = "๐ป",
+ ["bearded_person"] = "๐ง",
+ ["beaver"] = "๐ฆซ",
+ ["bed"] = "๐",
+ ["bee"] = "๐",
+ ["beer"] = "๐บ",
+ ["beers"] = "๐ป",
+ ["beetle"] = "๐ชฒ",
+ ["beginner"] = "๐ฐ",
+ ["belarus"] = "๐ง",
+ ["belgium"] = "๐ง",
+ ["belize"] = "๐ง",
+ ["bell"] = "๐",
+ ["bell_pepper"] = "๐ซ",
+ ["bellhop_bell"] = "๐",
+ ["benin"] = "๐ง",
+ ["bento"] = "๐ฑ",
+ ["bermuda"] = "๐ง",
+ ["beverage_box"] = "๐ง",
+ ["bhutan"] = "๐ง",
+ ["bicyclist"] = "๐ด",
+ ["bike"] = "๐ฒ",
+ ["biking_man"] = "๐ด",
+ ["biking_woman"] = "๐ด",
+ ["bikini"] = "๐",
+ ["billed_cap"] = "๐งข",
+ ["biohazard"] = "โฃ",
+ ["bird"] = "๐ฆ",
+ ["birthday"] = "๐",
+ ["bison"] = "๐ฆฌ",
+ ["biting_lip"] = "๐ซฆ",
+ ["black_bird"] = "๐ฆ",
+ ["black_cat"] = "๐",
+ ["black_circle"] = "โซ",
+ ["black_flag"] = "๐ด",
+ ["black_heart"] = "๐ค",
+ ["black_joker"] = "๐",
+ ["black_large_square"] = "โฌ",
+ ["black_medium_small_square"] = "โพ",
+ ["black_medium_square"] = "โผ",
+ ["black_nib"] = "โ",
+ ["black_small_square"] = "โช",
+ ["black_square_button"] = "๐ฒ",
+ ["blond_haired_man"] = "๐ฑ",
+ ["blond_haired_person"] = "๐ฑ",
+ ["blond_haired_woman"] = "๐ฑ",
+ ["blonde_woman"] = "๐ฑ",
+ ["blossom"] = "๐ผ",
+ ["blowfish"] = "๐ก",
+ ["blue_book"] = "๐",
+ ["blue_car"] = "๐",
+ ["blue_heart"] = "๐",
+ ["blue_square"] = "๐ฆ",
+ ["blueberries"] = "๐ซ",
+ ["blush"] = "๐",
+ ["boar"] = "๐",
+ ["boat"] = "โต",
+ ["bolivia"] = "๐ง",
+ ["bomb"] = "๐ฃ",
+ ["bone"] = "๐ฆด",
+ ["book"] = "๐",
+ ["bookmark"] = "๐",
+ ["bookmark_tabs"] = "๐",
+ ["books"] = "๐",
+ ["boom"] = "๐ฅ",
+ ["boomerang"] = "๐ช",
+ ["boot"] = "๐ข",
+ ["bosnia_herzegovina"] = "๐ง",
+ ["botswana"] = "๐ง",
+ ["bouncing_ball_man"] = "โน",
+ ["bouncing_ball_person"] = "โน",
+ ["bouncing_ball_woman"] = "โน",
+ ["bouquet"] = "๐",
+ ["bouvet_island"] = "๐ง",
+ ["bow"] = "๐",
+ ["bow_and_arrow"] = "๐น",
+ ["bowing_man"] = "๐",
+ ["bowing_woman"] = "๐",
+ ["bowl_with_spoon"] = "๐ฅฃ",
+ ["bowling"] = "๐ณ",
+ ["bowtie"] = "๐",
+ ["boxing_glove"] = "๐ฅ",
+ ["boy"] = "๐ฆ",
+ ["brain"] = "๐ง ",
+ ["brazil"] = "๐ง",
+ ["bread"] = "๐",
+ ["breast_feeding"] = "๐คฑ",
+ ["bricks"] = "๐งฑ",
+ ["bride_with_veil"] = "๐ฐ",
+ ["bridge_at_night"] = "๐",
+ ["briefcase"] = "๐ผ",
+ ["british_indian_ocean_territory"] = "๐ฎ",
+ ["british_virgin_islands"] = "๐ป",
+ ["broccoli"] = "๐ฅฆ",
+ ["broken_heart"] = "๐",
+ ["broom"] = "๐งน",
+ ["brown_circle"] = "๐ค",
+ ["brown_heart"] = "๐ค",
+ ["brown_square"] = "๐ซ",
+ ["brunei"] = "๐ง",
+ ["bubble_tea"] = "๐ง",
+ ["bubbles"] = "๐ซง",
+ ["bucket"] = "๐ชฃ",
+ ["bug"] = "๐",
+ ["building_construction"] = "๐",
+ ["bulb"] = "๐ก",
+ ["bulgaria"] = "๐ง",
+ ["bullettrain_front"] = "๐
",
+ ["bullettrain_side"] = "๐",
+ ["burkina_faso"] = "๐ง",
+ ["burrito"] = "๐ฏ",
+ ["burundi"] = "๐ง",
+ ["bus"] = "๐",
+ ["business_suit_levitating"] = "๐ด",
+ ["busstop"] = "๐",
+ ["bust_in_silhouette"] = "๐ค",
+ ["busts_in_silhouette"] = "๐ฅ",
+ ["butter"] = "๐ง",
+ ["butterfly"] = "๐ฆ",
+ ["cactus"] = "๐ต",
+ ["cake"] = "๐ฐ",
+ ["calendar"] = "๐",
+ ["call_me_hand"] = "๐ค",
+ ["calling"] = "๐ฒ",
+ ["cambodia"] = "๐ฐ",
+ ["camel"] = "๐ซ",
+ ["camera"] = "๐ท",
+ ["camera_flash"] = "๐ธ",
+ ["cameroon"] = "๐จ",
+ ["camping"] = "๐",
+ ["canada"] = "๐จ",
+ ["canary_islands"] = "๐ฎ",
+ ["cancer"] = "โ",
+ ["candle"] = "๐ฏ",
+ ["candy"] = "๐ฌ",
+ ["canned_food"] = "๐ฅซ",
+ ["canoe"] = "๐ถ",
+ ["cape_verde"] = "๐จ",
+ ["capital_abcd"] = "๐ ",
+ ["capricorn"] = "โ",
+ ["car"] = "๐",
+ ["card_file_box"] = "๐",
+ ["card_index"] = "๐",
+ ["card_index_dividers"] = "๐",
+ ["caribbean_netherlands"] = "๐ง",
+ ["carousel_horse"] = "๐ ",
+ ["carpentry_saw"] = "๐ช",
+ ["carrot"] = "๐ฅ",
+ ["cartwheeling"] = "๐คธ",
+ ["cat"] = "๐ฑ",
+ ["cat2"] = "๐",
+ ["cayman_islands"] = "๐ฐ",
+ ["cd"] = "๐ฟ",
+ ["central_african_republic"] = "๐จ",
+ ["ceuta_melilla"] = "๐ช",
+ ["chad"] = "๐น",
+ ["chains"] = "โ",
+ ["chair"] = "๐ช",
+ ["champagne"] = "๐พ",
+ ["chart"] = "๐น",
+ ["chart_with_downwards_trend"] = "๐",
+ ["chart_with_upwards_trend"] = "๐",
+ ["checkered_flag"] = "๐",
+ ["cheese"] = "๐ง",
+ ["cherries"] = "๐",
+ ["cherry_blossom"] = "๐ธ",
+ ["chess_pawn"] = "โ",
+ ["chestnut"] = "๐ฐ",
+ ["chicken"] = "๐",
+ ["child"] = "๐ง",
+ ["children_crossing"] = "๐ธ",
+ ["chile"] = "๐จ",
+ ["chipmunk"] = "๐ฟ",
+ ["chocolate_bar"] = "๐ซ",
+ ["chopsticks"] = "๐ฅข",
+ ["christmas_island"] = "๐จ",
+ ["christmas_tree"] = "๐",
+ ["church"] = "โช",
+ ["cinema"] = "๐ฆ",
+ ["circus_tent"] = "๐ช",
+ ["city_sunrise"] = "๐",
+ ["city_sunset"] = "๐",
+ ["cityscape"] = "๐",
+ ["cl"] = "๐",
+ ["clamp"] = "๐",
+ ["clap"] = "๐",
+ ["clapper"] = "๐ฌ",
+ ["classical_building"] = "๐",
+ ["climbing"] = "๐ง",
+ ["climbing_man"] = "๐ง",
+ ["climbing_woman"] = "๐ง",
+ ["clinking_glasses"] = "๐ฅ",
+ ["clipboard"] = "๐",
+ ["clipperton_island"] = "๐จ",
+ ["clock1"] = "๐",
+ ["clock10"] = "๐",
+ ["clock1030"] = "๐ฅ",
+ ["clock11"] = "๐",
+ ["clock1130"] = "๐ฆ",
+ ["clock12"] = "๐",
+ ["clock1230"] = "๐ง",
+ ["clock130"] = "๐",
+ ["clock2"] = "๐",
+ ["clock230"] = "๐",
+ ["clock3"] = "๐",
+ ["clock330"] = "๐",
+ ["clock4"] = "๐",
+ ["clock430"] = "๐",
+ ["clock5"] = "๐",
+ ["clock530"] = "๐ ",
+ ["clock6"] = "๐",
+ ["clock630"] = "๐ก",
+ ["clock7"] = "๐",
+ ["clock730"] = "๐ข",
+ ["clock8"] = "๐",
+ ["clock830"] = "๐ฃ",
+ ["clock9"] = "๐",
+ ["clock930"] = "๐ค",
+ ["closed_book"] = "๐",
+ ["closed_lock_with_key"] = "๐",
+ ["closed_umbrella"] = "๐",
+ ["cloud"] = "โ",
+ ["cloud_with_lightning"] = "๐ฉ",
+ ["cloud_with_lightning_and_rain"] = "โ",
+ ["cloud_with_rain"] = "๐ง",
+ ["cloud_with_snow"] = "๐จ",
+ ["clown_face"] = "๐คก",
+ ["clubs"] = "โฃ",
+ ["cn"] = "๐จ",
+ ["coat"] = "๐งฅ",
+ ["cockroach"] = "๐ชณ",
+ ["cocktail"] = "๐ธ",
+ ["coconut"] = "๐ฅฅ",
+ ["cocos_islands"] = "๐จ",
+ ["coffee"] = "โ",
+ ["coffin"] = "โฐ",
+ ["coin"] = "๐ช",
+ ["cold_face"] = "๐ฅถ",
+ ["cold_sweat"] = "๐ฐ",
+ ["collision"] = "๐ฅ",
+ ["colombia"] = "๐จ",
+ ["comet"] = "โ",
+ ["comoros"] = "๐ฐ",
+ ["compass"] = "๐งญ",
+ ["computer"] = "๐ป",
+ ["computer_mouse"] = "๐ฑ",
+ ["confetti_ball"] = "๐",
+ ["confounded"] = "๐",
+ ["confused"] = "๐",
+ ["congo_brazzaville"] = "๐จ",
+ ["congo_kinshasa"] = "๐จ",
+ ["congratulations"] = "ใ",
+ ["construction"] = "๐ง",
+ ["construction_worker"] = "๐ท",
+ ["construction_worker_man"] = "๐ท",
+ ["construction_worker_woman"] = "๐ท",
+ ["control_knobs"] = "๐",
+ ["convenience_store"] = "๐ช",
+ ["cook"] = "๐ง",
+ ["cook_islands"] = "๐จ",
+ ["cookie"] = "๐ช",
+ ["cool"] = "๐",
+ ["cop"] = "๐ฎ",
+ ["copyright"] = "ยฉ",
+ ["coral"] = "๐ชธ",
+ ["corn"] = "๐ฝ",
+ ["costa_rica"] = "๐จ",
+ ["cote_divoire"] = "๐จ",
+ ["couch_and_lamp"] = "๐",
+ ["couple"] = "๐ซ",
+ ["couple_with_heart"] = "๐",
+ ["couple_with_heart_man_man"] = "๐จ",
+ ["couple_with_heart_woman_man"] = "๐ฉ",
+ ["couple_with_heart_woman_woman"] = "๐ฉ",
+ ["couplekiss"] = "๐",
+ ["couplekiss_man_man"] = "๐จ",
+ ["couplekiss_man_woman"] = "๐ฉ",
+ ["couplekiss_woman_woman"] = "๐ฉ",
+ ["cow"] = "๐ฎ",
+ ["cow2"] = "๐",
+ ["cowboy_hat_face"] = "๐ค ",
+ ["crab"] = "๐ฆ",
+ ["crayon"] = "๐",
+ ["credit_card"] = "๐ณ",
+ ["crescent_moon"] = "๐",
+ ["cricket"] = "๐ฆ",
+ ["cricket_game"] = "๐",
+ ["croatia"] = "๐ญ",
+ ["crocodile"] = "๐",
+ ["croissant"] = "๐ฅ",
+ ["crossed_fingers"] = "๐ค",
+ ["crossed_flags"] = "๐",
+ ["crossed_swords"] = "โ",
+ ["crown"] = "๐",
+ ["crutch"] = "๐ฉผ",
+ ["cry"] = "๐ข",
+ ["crying_cat_face"] = "๐ฟ",
+ ["crystal_ball"] = "๐ฎ",
+ ["cuba"] = "๐จ",
+ ["cucumber"] = "๐ฅ",
+ ["cup_with_straw"] = "๐ฅค",
+ ["cupcake"] = "๐ง",
+ ["cupid"] = "๐",
+ ["curacao"] = "๐จ",
+ ["curling_stone"] = "๐ฅ",
+ ["curly_haired_man"] = "๐จ",
+ ["curly_haired_woman"] = "๐ฉ",
+ ["curly_loop"] = "โฐ",
+ ["currency_exchange"] = "๐ฑ",
+ ["curry"] = "๐",
+ ["cursing_face"] = "๐คฌ",
+ ["custard"] = "๐ฎ",
+ ["customs"] = "๐",
+ ["cut_of_meat"] = "๐ฅฉ",
+ ["cyclone"] = "๐",
+ ["cyprus"] = "๐จ",
+ ["czech_republic"] = "๐จ",
+ ["dagger"] = "๐ก",
+ ["dancer"] = "๐",
+ ["dancers"] = "๐ฏ",
+ ["dancing_men"] = "๐ฏ",
+ ["dancing_women"] = "๐ฏ",
+ ["dango"] = "๐ก",
+ ["dark_sunglasses"] = "๐ถ",
+ ["dart"] = "๐ฏ",
+ ["dash"] = "๐จ",
+ ["date"] = "๐
",
+ ["de"] = "๐ฉ",
+ ["deaf_man"] = "๐ง",
+ ["deaf_person"] = "๐ง",
+ ["deaf_woman"] = "๐ง",
+ ["deciduous_tree"] = "๐ณ",
+ ["deer"] = "๐ฆ",
+ ["denmark"] = "๐ฉ",
+ ["department_store"] = "๐ฌ",
+ ["dependabot"] = "๏พ ",
+ ["derelict_house"] = "๐",
+ ["desert"] = "๐",
+ ["desert_island"] = "๐",
+ ["desktop_computer"] = "๐ฅ",
+ ["detective"] = "๐ต",
+ ["diamond_shape_with_a_dot_inside"] = "๐ ",
+ ["diamonds"] = "โฆ",
+ ["diego_garcia"] = "๐ฉ",
+ ["disappointed"] = "๐",
+ ["disappointed_relieved"] = "๐ฅ",
+ ["disguised_face"] = "๐ฅธ",
+ ["diving_mask"] = "๐คฟ",
+ ["diya_lamp"] = "๐ช",
+ ["dizzy"] = "๐ซ",
+ ["dizzy_face"] = "๐ต",
+ ["djibouti"] = "๐ฉ",
+ ["dna"] = "๐งฌ",
+ ["do_not_litter"] = "๐ฏ",
+ ["dodo"] = "๐ฆค",
+ ["dog"] = "๐ถ",
+ ["dog2"] = "๐",
+ ["dollar"] = "๐ต",
+ ["dolls"] = "๐",
+ ["dolphin"] = "๐ฌ",
+ ["dominica"] = "๐ฉ",
+ ["dominican_republic"] = "๐ฉ",
+ ["donkey"] = "๐ซ",
+ ["door"] = "๐ช",
+ ["dotted_line_face"] = "๐ซฅ",
+ ["doughnut"] = "๐ฉ",
+ ["dove"] = "๐",
+ ["dragon"] = "๐",
+ ["dragon_face"] = "๐ฒ",
+ ["dress"] = "๐",
+ ["dromedary_camel"] = "๐ช",
+ ["drooling_face"] = "๐คค",
+ ["drop_of_blood"] = "๐ฉธ",
+ ["droplet"] = "๐ง",
+ ["drum"] = "๐ฅ",
+ ["duck"] = "๐ฆ",
+ ["dumpling"] = "๐ฅ",
+ ["dvd"] = "๐",
+ ["e-mail"] = "๐ง",
+ ["eagle"] = "๐ฆ
",
+ ["ear"] = "๐",
+ ["ear_of_rice"] = "๐พ",
+ ["ear_with_hearing_aid"] = "๐ฆป",
+ ["earth_africa"] = "๐",
+ ["earth_americas"] = "๐",
+ ["earth_asia"] = "๐",
+ ["ecuador"] = "๐ช",
+ ["egg"] = "๐ฅ",
+ ["eggplant"] = "๐",
+ ["egypt"] = "๐ช",
+ ["eight"] = "8",
+ ["eight_pointed_black_star"] = "โด",
+ ["eight_spoked_asterisk"] = "โณ",
+ ["eject_button"] = "โ",
+ ["el_salvador"] = "๐ธ",
+ ["electric_plug"] = "๐",
+ ["electron"] = "๎ฎ",
+ ["elephant"] = "๐",
+ ["elevator"] = "๐",
+ ["elf"] = "๐ง",
+ ["elf_man"] = "๐ง",
+ ["elf_woman"] = "๐ง",
+ ["email"] = "๐ง",
+ ["empty_nest"] = "๐ชน",
+ ["end"] = "๐",
+ ["england"] = "๐ด",
+ ["envelope"] = "โ",
+ ["envelope_with_arrow"] = "๐ฉ",
+ ["equatorial_guinea"] = "๐ฌ",
+ ["eritrea"] = "๐ช",
+ ["es"] = "๐ช",
+ ["estonia"] = "๐ช",
+ ["ethiopia"] = "๐ช",
+ ["eu"] = "๐ช",
+ ["euro"] = "๐ถ",
+ ["european_castle"] = "๐ฐ",
+ ["european_post_office"] = "๐ค",
+ ["european_union"] = "๐ช",
+ ["evergreen_tree"] = "๐ฒ",
+ ["exclamation"] = "โ",
+ ["exploding_head"] = "๐คฏ",
+ ["expressionless"] = "๐",
+ ["eye"] = "๐",
+ ["eye_speech_bubble"] = "๐",
+ ["eyeglasses"] = "๐",
+ ["eyes"] = "๐",
+ ["face_exhaling"] = "๐ฎ",
+ ["face_holding_back_tears"] = "๐ฅน",
+ ["face_in_clouds"] = "๐ถ",
+ ["face_with_diagonal_mouth"] = "๐ซค",
+ ["face_with_head_bandage"] = "๐ค",
+ ["face_with_open_eyes_and_hand_over_mouth"] = "๐ซข",
+ ["face_with_peeking_eye"] = "๐ซฃ",
+ ["face_with_spiral_eyes"] = "๐ต",
+ ["face_with_thermometer"] = "๐ค",
+ ["facepalm"] = "๐คฆ",
+ ["facepunch"] = "๐",
+ ["factory"] = "๐ญ",
+ ["factory_worker"] = "๐ง",
+ ["fairy"] = "๐ง",
+ ["fairy_man"] = "๐ง",
+ ["fairy_woman"] = "๐ง",
+ ["falafel"] = "๐ง",
+ ["falkland_islands"] = "๐ซ",
+ ["fallen_leaf"] = "๐",
+ ["family"] = "๐ช",
+ ["family_man_boy"] = "๐จ",
+ ["family_man_boy_boy"] = "๐จ",
+ ["family_man_girl"] = "๐จ",
+ ["family_man_girl_boy"] = "๐จ",
+ ["family_man_girl_girl"] = "๐จ",
+ ["family_man_man_boy"] = "๐จ",
+ ["family_man_man_boy_boy"] = "๐จ",
+ ["family_man_man_girl"] = "๐จ",
+ ["family_man_man_girl_boy"] = "๐จ",
+ ["family_man_man_girl_girl"] = "๐จ",
+ ["family_man_woman_boy"] = "๐จ",
+ ["family_man_woman_boy_boy"] = "๐จ",
+ ["family_man_woman_girl"] = "๐จ",
+ ["family_man_woman_girl_boy"] = "๐จ",
+ ["family_man_woman_girl_girl"] = "๐จ",
+ ["family_woman_boy"] = "๐ฉ",
+ ["family_woman_boy_boy"] = "๐ฉ",
+ ["family_woman_girl"] = "๐ฉ",
+ ["family_woman_girl_boy"] = "๐ฉ",
+ ["family_woman_girl_girl"] = "๐ฉ",
+ ["family_woman_woman_boy"] = "๐ฉ",
+ ["family_woman_woman_boy_boy"] = "๐ฉ",
+ ["family_woman_woman_girl"] = "๐ฉ",
+ ["family_woman_woman_girl_boy"] = "๐ฉ",
+ ["family_woman_woman_girl_girl"] = "๐ฉ",
+ ["farmer"] = "๐ง",
+ ["faroe_islands"] = "๐ซ",
+ ["fast_forward"] = "โฉ",
+ ["fax"] = "๐ ",
+ ["fearful"] = "๐จ",
+ ["feather"] = "๐ชถ",
+ ["feet"] = "๐พ",
+ ["female_detective"] = "๐ต",
+ ["female_sign"] = "โ",
+ ["ferris_wheel"] = "๐ก",
+ ["ferry"] = "โด",
+ ["field_hockey"] = "๐",
+ ["fiji"] = "๐ซ",
+ ["file_cabinet"] = "๐",
+ ["file_folder"] = "๐",
+ ["film_projector"] = "๐ฝ",
+ ["film_strip"] = "๐",
+ ["finland"] = "๐ซ",
+ ["fire"] = "๐ฅ",
+ ["fire_engine"] = "๐",
+ ["fire_extinguisher"] = "๐งฏ",
+ ["firecracker"] = "๐งจ",
+ ["firefighter"] = "๐ง",
+ ["fireworks"] = "๐",
+ ["first_quarter_moon"] = "๐",
+ ["first_quarter_moon_with_face"] = "๐",
+ ["fish"] = "๐",
+ ["fish_cake"] = "๐ฅ",
+ ["fishing_pole_and_fish"] = "๐ฃ",
+ ["fishsticks"] = fishsticks,
+ ["fist"] = "โ",
+ ["fist_left"] = "๐ค",
+ ["fist_oncoming"] = "๐",
+ ["fist_raised"] = "โ",
+ ["fist_right"] = "๐ค",
+ ["five"] = "5",
+ ["flags"] = "๐",
+ ["flamingo"] = "๐ฆฉ",
+ ["flashlight"] = "๐ฆ",
+ ["flat_shoe"] = "๐ฅฟ",
+ ["flatbread"] = "๐ซ",
+ ["fleur_de_lis"] = "โ",
+ ["flight_arrival"] = "๐ฌ",
+ ["flight_departure"] = "๐ซ",
+ ["flipper"] = "๐ฌ",
+ ["floppy_disk"] = "๐พ",
+ ["flower_playing_cards"] = "๐ด",
+ ["flushed"] = "๐ณ",
+ ["flute"] = "๐ช",
+ ["fly"] = "๐ชฐ",
+ ["flying_disc"] = "๐ฅ",
+ ["flying_saucer"] = "๐ธ",
+ ["fog"] = "๐ซ",
+ ["foggy"] = "๐",
+ ["folding_hand_fan"] = "๐ชญ",
+ ["fondue"] = "๐ซ",
+ ["foot"] = "๐ฆถ",
+ ["football"] = "๐",
+ ["footprints"] = "๐ฃ",
+ ["fork_and_knife"] = "๐ด",
+ ["fortune_cookie"] = "๐ฅ ",
+ ["fountain"] = "โฒ",
+ ["fountain_pen"] = "๐",
+ ["four"] = "4",
+ ["four_leaf_clover"] = "๐",
+ ["fox_face"] = "๐ฆ",
+ ["fr"] = "๐ซ",
+ ["framed_picture"] = "๐ผ",
+ ["free"] = "๐",
+ ["french_guiana"] = "๐ฌ",
+ ["french_polynesia"] = "๐ต",
+ ["french_southern_territories"] = "๐น",
+ ["fried_egg"] = "๐ณ",
+ ["fried_shrimp"] = "๐ค",
+ ["fries"] = "๐",
+ ["frog"] = "๐ธ",
+ ["frowning"] = "๐ฆ",
+ ["frowning_face"] = "โน",
+ ["frowning_man"] = "๐",
+ ["frowning_person"] = "๐",
+ ["frowning_woman"] = "๐",
+ ["fu"] = "๐",
+ ["fuelpump"] = "โฝ",
+ ["full_moon"] = "๐",
+ ["full_moon_with_face"] = "๐",
+ ["funeral_urn"] = "โฑ",
+ ["gabon"] = "๐ฌ",
+ ["gambia"] = "๐ฌ",
+ ["game_die"] = "๐ฒ",
+ ["garlic"] = "๐ง",
+ ["gb"] = "๐ฌ",
+ ["gear"] = "โ",
+ ["gem"] = "๐",
+ ["gemini"] = "โ",
+ ["genie"] = "๐ง",
+ ["genie_man"] = "๐ง",
+ ["genie_woman"] = "๐ง",
+ ["georgia"] = "๐ฌ",
+ ["ghana"] = "๐ฌ",
+ ["ghost"] = "๐ป",
+ ["gibraltar"] = "๐ฌ",
+ ["gift"] = "๐",
+ ["gift_heart"] = "๐",
+ ["ginger_root"] = "๐ซ",
+ ["giraffe"] = "๐ฆ",
+ ["girl"] = "๐ง",
+ ["globe_with_meridians"] = "๐",
+ ["gloves"] = "๐งค",
+ ["goal_net"] = "๐ฅ
",
+ ["goat"] = "๐",
+ ["goberserk"] = "",
+ ["godmode"] = "",
+ ["goggles"] = "๐ฅฝ",
+ ["golf"] = "โณ",
+ ["golfing"] = "๐",
+ ["golfing_man"] = "๐",
+ ["golfing_woman"] = "๐",
+ ["goose"] = "๐ชฟ",
+ ["gorilla"] = "๐ฆ",
+ ["grapes"] = "๐",
+ ["greece"] = "๐ฌ",
+ ["green_apple"] = "๐",
+ ["green_book"] = "๐",
+ ["green_circle"] = "๐ข",
+ ["green_heart"] = "๐",
+ ["green_salad"] = "๐ฅ",
+ ["green_square"] = "๐ฉ",
+ ["greenland"] = "๐ฌ",
+ ["grenada"] = "๐ฌ",
+ ["grey_exclamation"] = "โ",
+ ["grey_heart"] = "๐ฉถ",
+ ["grey_question"] = "โ",
+ ["grimacing"] = "๐ฌ",
+ ["grin"] = "๐",
+ ["grinning"] = "๐",
+ ["guadeloupe"] = "๐ฌ",
+ ["guam"] = "๐ฌ",
+ ["guard"] = "๐",
+ ["guardsman"] = "๐",
+ ["guardswoman"] = "๐",
+ ["guatemala"] = "๐ฌ",
+ ["guernsey"] = "๐ฌ",
+ ["guide_dog"] = "๐ฆฎ",
+ ["guinea"] = "๐ฌ",
+ ["guinea_bissau"] = "๐ฌ",
+ ["guitar"] = "๐ธ",
+ ["gun"] = "๐ซ",
+ ["guyana"] = "๐ฌ",
+ ["hair_pick"] = "๐ชฎ",
+ ["haircut"] = "๐",
+ ["haircut_man"] = "๐",
+ ["haircut_woman"] = "๐",
+ ["haiti"] = "๐ญ",
+ ["hamburger"] = "๐",
+ ["hammer"] = "๐จ",
+ ["hammer_and_pick"] = "โ",
+ ["hammer_and_wrench"] = "๐ ",
+ ["hamsa"] = "๐ชฌ",
+ ["hamster"] = "๐น",
+ ["hand"] = "โ",
+ ["hand_over_mouth"] = "๐คญ",
+ ["hand_with_index_finger_and_thumb_crossed"] = "๐ซฐ",
+ ["handbag"] = "๐",
+ ["handball_person"] = "๐คพ",
+ ["handshake"] = "๐ค",
+ ["hankey"] = "๐ฉ",
+ ["hash"] = "#",
+ ["hatched_chick"] = "๐ฅ",
+ ["hatching_chick"] = "๐ฃ",
+ ["headphones"] = "๐ง",
+ ["headstone"] = "๐ชฆ",
+ ["health_worker"] = "๐ง",
+ ["hear_no_evil"] = "๐",
+ ["heard_mcdonald_islands"] = "๐ญ",
+ ["heart"] = "โค",
+ ["heart_decoration"] = "๐",
+ ["heart_eyes"] = "๐",
+ ["heart_eyes_cat"] = "๐ป",
+ ["heart_hands"] = "๐ซถ",
+ ["heart_on_fire"] = "โค",
+ ["heartbeat"] = "๐",
+ ["heartpulse"] = "๐",
+ ["hearts"] = "โฅ",
+ ["heavy_check_mark"] = "โ",
+ ["heavy_division_sign"] = "โ",
+ ["heavy_dollar_sign"] = "๐ฒ",
+ ["heavy_equals_sign"] = "๐ฐ",
+ ["heavy_exclamation_mark"] = "โ",
+ ["heavy_heart_exclamation"] = "โฃ",
+ ["heavy_minus_sign"] = "โ",
+ ["heavy_multiplication_x"] = "โ",
+ ["heavy_plus_sign"] = "โ",
+ ["hedgehog"] = "๐ฆ",
+ ["helicopter"] = "๐",
+ ["herb"] = "๐ฟ",
+ ["hibiscus"] = "๐บ",
+ ["high_brightness"] = "๐",
+ ["high_heel"] = "๐ ",
+ ["hiking_boot"] = "๐ฅพ",
+ ["hindu_temple"] = "๐",
+ ["hippopotamus"] = "๐ฆ",
+ ["hocho"] = "๐ช",
+ ["hole"] = "๐ณ",
+ ["honduras"] = "๐ญ",
+ ["honey_pot"] = "๐ฏ",
+ ["honeybee"] = "๐",
+ ["hong_kong"] = "๐ญ",
+ ["hook"] = "๐ช",
+ ["horse"] = "๐ด",
+ ["horse_racing"] = "๐",
+ ["hospital"] = "๐ฅ",
+ ["hot_face"] = "๐ฅต",
+ ["hot_pepper"] = "๐ถ",
+ ["hotdog"] = "๐ญ",
+ ["hotel"] = "๐จ",
+ ["hotsprings"] = "โจ",
+ ["hourglass"] = "โ",
+ ["hourglass_flowing_sand"] = "โณ",
+ ["house"] = "๐ ",
+ ["house_with_garden"] = "๐ก",
+ ["houses"] = "๐",
+ ["hugs"] = "๐ค",
+ ["hungary"] = "๐ญ",
+ ["hurtrealbad"] = "",
+ ["hushed"] = "๐ฏ",
+ ["hut"] = "๐",
+ ["hyacinth"] = "๐ชป",
+ ["ice_cream"] = "๐จ",
+ ["ice_cube"] = "๐ง",
+ ["ice_hockey"] = "๐",
+ ["ice_skate"] = "โธ",
+ ["icecream"] = "๐ฆ",
+ ["iceland"] = "๐ฎ",
+ ["id"] = "๐",
+ ["identification_card"] = "๐ชช",
+ ["ideograph_advantage"] = "๐",
+ ["imp"] = "๐ฟ",
+ ["inbox_tray"] = "๐ฅ",
+ ["incoming_envelope"] = "๐จ",
+ ["index_pointing_at_the_viewer"] = "๐ซต",
+ ["india"] = "๐ฎ",
+ ["indonesia"] = "๐ฎ",
+ ["infinity"] = "โพ",
+ ["information_desk_person"] = "๐",
+ ["information_source"] = "โน",
+ ["innocent"] = "๐",
+ ["interrobang"] = "โ",
+ ["iphone"] = "๐ฑ",
+ ["iran"] = "๐ฎ",
+ ["iraq"] = "๐ฎ",
+ ["ireland"] = "๐ฎ",
+ ["isle_of_man"] = "๐ฎ",
+ ["israel"] = "๐ฎ",
+ ["it"] = "๐ฎ",
+ ["izakaya_lantern"] = "๐ฎ",
+ ["jack_o_lantern"] = "๐",
+ ["jamaica"] = "๐ฏ",
+ ["japan"] = "๐พ",
+ ["japanese_castle"] = "๐ฏ",
+ ["japanese_goblin"] = "๐บ",
+ ["japanese_ogre"] = "๐น",
+ ["jar"] = "๐ซ",
+ ["jeans"] = "๐",
+ ["jellyfish"] = "๐ชผ",
+ ["jersey"] = "๐ฏ",
+ ["jigsaw"] = "๐งฉ",
+ ["jordan"] = "๐ฏ",
+ ["joy"] = "๐",
+ ["joy_cat"] = "๐น",
+ ["joystick"] = "๐น",
+ ["jp"] = "๐ฏ",
+ ["judge"] = "๐ง",
+ ["juggling_person"] = "๐คน",
+ ["kaaba"] = "๐",
+ ["kangaroo"] = "๐ฆ",
+ ["kazakhstan"] = "๐ฐ",
+ ["kenya"] = "๐ฐ",
+ ["key"] = "๐",
+ ["keyboard"] = "โจ",
+ ["keycap_ten"] = "๐",
+ ["khanda"] = "๐ชฏ",
+ ["kick_scooter"] = "๐ด",
+ ["kimono"] = "๐",
+ ["kiribati"] = "๐ฐ",
+ ["kiss"] = "๐",
+ ["kissing"] = "๐",
+ ["kissing_cat"] = "๐ฝ",
+ ["kissing_closed_eyes"] = "๐",
+ ["kissing_heart"] = "๐",
+ ["kissing_smiling_eyes"] = "๐",
+ ["kite"] = "๐ช",
+ ["kiwi_fruit"] = "๐ฅ",
+ ["kneeling_man"] = "๐ง",
+ ["kneeling_person"] = "๐ง",
+ ["kneeling_woman"] = "๐ง",
+ ["knife"] = "๐ช",
+ ["knot"] = "๐ชข",
+ ["koala"] = "๐จ",
+ ["koko"] = "๐",
+ ["kosovo"] = "๐ฝ",
+ ["kr"] = "๐ฐ",
+ ["kuwait"] = "๐ฐ",
+ ["kyrgyzstan"] = "๐ฐ",
+ ["lab_coat"] = "๐ฅผ",
+ ["label"] = "๐ท",
+ ["lacrosse"] = "๐ฅ",
+ ["ladder"] = "๐ช",
+ ["lady_beetle"] = "๐",
+ ["lantern"] = "๐ฎ",
+ ["laos"] = "๐ฑ",
+ ["large_blue_circle"] = "๐ต",
+ ["large_blue_diamond"] = "๐ท",
+ ["large_orange_diamond"] = "๐ถ",
+ ["last_quarter_moon"] = "๐",
+ ["last_quarter_moon_with_face"] = "๐",
+ ["latin_cross"] = "โ",
+ ["latvia"] = "๐ฑ",
+ ["laughing"] = "๐",
+ ["leafy_green"] = "๐ฅฌ",
+ ["leaves"] = "๐",
+ ["lebanon"] = "๐ฑ",
+ ["ledger"] = "๐",
+ ["left_luggage"] = "๐
",
+ ["left_right_arrow"] = "โ",
+ ["left_speech_bubble"] = "๐จ",
+ ["leftwards_arrow_with_hook"] = "โฉ",
+ ["leftwards_hand"] = "๐ซฒ",
+ ["leftwards_pushing_hand"] = "๐ซท",
+ ["leg"] = "๐ฆต",
+ ["lemon"] = "๐",
+ ["leo"] = "โ",
+ ["leopard"] = "๐",
+ ["lesotho"] = "๐ฑ",
+ ["level_slider"] = "๐",
+ ["liberia"] = "๐ฑ",
+ ["libra"] = "โ",
+ ["libya"] = "๐ฑ",
+ ["liechtenstein"] = "๐ฑ",
+ ["light_blue_heart"] = "๐ฉต",
+ ["light_rail"] = "๐",
+ ["link"] = "๐",
+ ["lion"] = "๐ฆ",
+ ["lips"] = "๐",
+ ["lipstick"] = "๐",
+ ["lithuania"] = "๐ฑ",
+ ["lizard"] = "๐ฆ",
+ ["llama"] = "๐ฆ",
+ ["lobster"] = "๐ฆ",
+ ["lock"] = "๐",
+ ["lock_with_ink_pen"] = "๐",
+ ["lollipop"] = "๐ญ",
+ ["long_drum"] = "๐ช",
+ ["loop"] = "โฟ",
+ ["lotion_bottle"] = "๐งด",
+ ["lotus"] = "๐ชท",
+ ["lotus_position"] = "๐ง",
+ ["lotus_position_man"] = "๐ง",
+ ["lotus_position_woman"] = "๐ง",
+ ["loud_sound"] = "๐",
+ ["loudspeaker"] = "๐ข",
+ ["love_hotel"] = "๐ฉ",
+ ["love_letter"] = "๐",
+ ["love_you_gesture"] = "๐ค",
+ ["low_battery"] = "๐ชซ",
+ ["low_brightness"] = "๐
",
+ ["luggage"] = "๐งณ",
+ ["lungs"] = "๐ซ",
+ ["luxembourg"] = "๐ฑ",
+ ["lying_face"] = "๐คฅ",
+ ["m"] = "โ",
+ ["macau"] = "๐ฒ",
+ ["macedonia"] = "๐ฒ",
+ ["madagascar"] = "๐ฒ",
+ ["mag"] = "๐",
+ ["mag_right"] = "๐",
+ ["mage"] = "๐ง",
+ ["mage_man"] = "๐ง",
+ ["mage_woman"] = "๐ง",
+ ["magic_wand"] = "๐ช",
+ ["magnet"] = "๐งฒ",
+ ["mahjong"] = "๐",
+ ["mailbox"] = "๐ซ",
+ ["mailbox_closed"] = "๐ช",
+ ["mailbox_with_mail"] = "๐ฌ",
+ ["mailbox_with_no_mail"] = "๐ญ",
+ ["malawi"] = "๐ฒ",
+ ["malaysia"] = "๐ฒ",
+ ["maldives"] = "๐ฒ",
+ ["male_detective"] = "๐ต",
+ ["male_sign"] = "โ",
+ ["mali"] = "๐ฒ",
+ ["malta"] = "๐ฒ",
+ ["mammoth"] = "๐ฆฃ",
+ ["man"] = "๐จ",
+ ["man_artist"] = "๐จ",
+ ["man_astronaut"] = "๐จ",
+ ["man_beard"] = "๐ง",
+ ["man_cartwheeling"] = "๐คธ",
+ ["man_cook"] = "๐จ",
+ ["man_dancing"] = "๐บ",
+ ["man_facepalming"] = "๐คฆ",
+ ["man_factory_worker"] = "๐จ",
+ ["man_farmer"] = "๐จ",
+ ["man_feeding_baby"] = "๐จ",
+ ["man_firefighter"] = "๐จ",
+ ["man_health_worker"] = "๐จ",
+ ["man_in_manual_wheelchair"] = "๐จ",
+ ["man_in_motorized_wheelchair"] = "๐จ",
+ ["man_in_tuxedo"] = "๐คต",
+ ["man_judge"] = "๐จ",
+ ["man_juggling"] = "๐คน",
+ ["man_mechanic"] = "๐จ",
+ ["man_office_worker"] = "๐จ",
+ ["man_pilot"] = "๐จ",
+ ["man_playing_handball"] = "๐คพ",
+ ["man_playing_water_polo"] = "๐คฝ",
+ ["man_scientist"] = "๐จ",
+ ["man_shrugging"] = "๐คท",
+ ["man_singer"] = "๐จ",
+ ["man_student"] = "๐จ",
+ ["man_teacher"] = "๐จ",
+ ["man_technologist"] = "๐จ",
+ ["man_with_gua_pi_mao"] = "๐ฒ",
+ ["man_with_probing_cane"] = "๐จ",
+ ["man_with_turban"] = "๐ณ",
+ ["man_with_veil"] = "๐ฐ",
+ ["mandarin"] = "๐",
+ ["mango"] = "๐ฅญ",
+ ["mans_shoe"] = "๐",
+ ["mantelpiece_clock"] = "๐ฐ",
+ ["manual_wheelchair"] = "๐ฆฝ",
+ ["maple_leaf"] = "๐",
+ ["maracas"] = "๐ช",
+ ["marshall_islands"] = "๐ฒ",
+ ["martial_arts_uniform"] = "๐ฅ",
+ ["martinique"] = "๐ฒ",
+ ["mask"] = "๐ท",
+ ["massage"] = "๐",
+ ["massage_man"] = "๐",
+ ["massage_woman"] = "๐",
+ ["mate"] = "๐ง",
+ ["mauritania"] = "๐ฒ",
+ ["mauritius"] = "๐ฒ",
+ ["mayotte"] = "๐พ",
+ ["meat_on_bone"] = "๐",
+ ["mechanic"] = "๐ง",
+ ["mechanical_arm"] = "๐ฆพ",
+ ["mechanical_leg"] = "๐ฆฟ",
+ ["medal_military"] = "๐",
+ ["medal_sports"] = "๐
",
+ ["medical_symbol"] = "โ",
+ ["mega"] = "๐ฃ",
+ ["melon"] = "๐",
+ ["melting_face"] = "๐ซ ",
+ ["memo"] = "๐",
+ ["men_wrestling"] = "๐คผ",
+ ["mending_heart"] = "โค",
+ ["menorah"] = "๐",
+ ["mens"] = "๐น",
+ ["mermaid"] = "๐ง",
+ ["merman"] = "๐ง",
+ ["merperson"] = "๐ง",
+ ["metal"] = "๐ค",
+ ["metro"] = "๐",
+ ["mexico"] = "๐ฒ",
+ ["microbe"] = "๐ฆ ",
+ ["micronesia"] = "๐ซ",
+ ["microphone"] = "๐ค",
+ ["microscope"] = "๐ฌ",
+ ["middle_finger"] = "๐",
+ ["military_helmet"] = "๐ช",
+ ["milk_glass"] = "๐ฅ",
+ ["milky_way"] = "๐",
+ ["minibus"] = "๐",
+ ["minidisc"] = "๐ฝ",
+ ["mirror"] = "๐ช",
+ ["mirror_ball"] = "๐ชฉ",
+ ["mobile_phone_off"] = "๐ด",
+ ["moldova"] = "๐ฒ",
+ ["monaco"] = "๐ฒ",
+ ["money_mouth_face"] = "๐ค",
+ ["money_with_wings"] = "๐ธ",
+ ["moneybag"] = "๐ฐ",
+ ["mongolia"] = "๐ฒ",
+ ["monkey"] = "๐",
+ ["monkey_face"] = "๐ต",
+ ["monocle_face"] = "๐ง",
+ ["monorail"] = "๐",
+ ["montenegro"] = "๐ฒ",
+ ["montserrat"] = "๐ฒ",
+ ["moon"] = "๐",
+ ["moon_cake"] = "๐ฅฎ",
+ ["moose"] = "๐ซ",
+ ["morocco"] = "๐ฒ",
+ ["mortar_board"] = "๐",
+ ["mosque"] = "๐",
+ ["mosquito"] = "๐ฆ",
+ ["motor_boat"] = "๐ฅ",
+ ["motor_scooter"] = "๐ต",
+ ["motorcycle"] = "๐",
+ ["motorized_wheelchair"] = "๐ฆผ",
+ ["motorway"] = "๐ฃ",
+ ["mount_fuji"] = "๐ป",
+ ["mountain"] = "โฐ",
+ ["mountain_bicyclist"] = "๐ต",
+ ["mountain_biking_man"] = "๐ต",
+ ["mountain_biking_woman"] = "๐ต",
+ ["mountain_cableway"] = "๐ ",
+ ["mountain_railway"] = "๐",
+ ["mountain_snow"] = "๐",
+ ["mouse"] = "๐ญ",
+ ["mouse2"] = "๐",
+ ["mouse_trap"] = "๐ชค",
+ ["movie_camera"] = "๐ฅ",
+ ["moyai"] = "๐ฟ",
+ ["mozambique"] = "๐ฒ",
+ ["mrs_claus"] = "๐คถ",
+ ["muscle"] = "๐ช",
+ ["mushroom"] = "๐",
+ ["musical_keyboard"] = "๐น",
+ ["musical_note"] = "๐ต",
+ ["musical_score"] = "๐ผ",
+ ["mute"] = "๐",
+ ["mx_claus"] = "๐ง",
+ ["myanmar"] = "๐ฒ",
+ ["nail_care"] = "๐
",
+ ["name_badge"] = "๐",
+ ["namibia"] = "๐ณ",
+ ["national_park"] = "๐",
+ ["nauru"] = "๐ณ",
+ ["nauseated_face"] = "๐คข",
+ ["nazar_amulet"] = "๐งฟ",
+ ["neckbeard"] = "",
+ ["necktie"] = "๐",
+ ["negative_squared_cross_mark"] = "โ",
+ ["nepal"] = "๐ณ",
+ ["nerd_face"] = "๐ค",
+ ["nest_with_eggs"] = "๐ชบ",
+ ["nesting_dolls"] = "๐ช",
+ ["netherlands"] = "๐ณ",
+ ["neutral_face"] = "๐",
+ ["new"] = "๐",
+ ["new_caledonia"] = "๐ณ",
+ ["new_moon"] = "๐",
+ ["new_moon_with_face"] = "๐",
+ ["new_zealand"] = "๐ณ",
+ ["newspaper"] = "๐ฐ",
+ ["newspaper_roll"] = "๐",
+ ["next_track_button"] = "โญ",
+ ["ng"] = "๐",
+ ["ng_man"] = "๐
",
+ ["ng_woman"] = "๐
",
+ ["nicaragua"] = "๐ณ",
+ ["niger"] = "๐ณ",
+ ["nigeria"] = "๐ณ",
+ ["night_with_stars"] = "๐",
+ ["nine"] = "9",
+ ["ninja"] = "๐ฅท",
+ ["niue"] = "๐ณ",
+ ["no_bell"] = "๐",
+ ["no_bicycles"] = "๐ณ",
+ ["no_entry"] = "โ",
+ ["no_entry_sign"] = "๐ซ",
+ ["no_good"] = "๐
",
+ ["no_good_man"] = "๐
",
+ ["no_good_woman"] = "๐
",
+ ["no_mobile_phones"] = "๐ต",
+ ["no_mouth"] = "๐ถ",
+ ["no_pedestrians"] = "๐ท",
+ ["no_smoking"] = "๐ญ",
+ ["non-potable_water"] = "๐ฑ",
+ ["norfolk_island"] = "๐ณ",
+ ["north_korea"] = "๐ฐ",
+ ["northern_mariana_islands"] = "๐ฒ",
+ ["norway"] = "๐ณ",
+ ["nose"] = "๐",
+ ["notebook"] = "๐",
+ ["notebook_with_decorative_cover"] = "๐",
+ ["notes"] = "๐ถ",
+ ["nut_and_bolt"] = "๐ฉ",
+ ["o"] = "โญ",
+ ["o2"] = "๐
พ",
+ ["ocean"] = "๐",
+ ["octocat"] = "",
+ ["octopus"] = "๐",
+ ["oden"] = "๐ข",
+ ["office"] = "๐ข",
+ ["office_worker"] = "๐ง",
+ ["oil_drum"] = "๐ข",
+ ["ok"] = "๐",
+ ["ok_hand"] = "๐",
+ ["ok_man"] = "๐",
+ ["ok_person"] = "๐",
+ ["ok_woman"] = "๐",
+ ["old_key"] = "๐",
+ ["older_adult"] = "๐ง",
+ ["older_man"] = "๐ด",
+ ["older_woman"] = "๐ต",
+ ["olive"] = "๐ซ",
+ ["om"] = "๐",
+ ["oman"] = "๐ด",
+ ["on"] = "๐",
+ ["oncoming_automobile"] = "๐",
+ ["oncoming_bus"] = "๐",
+ ["oncoming_police_car"] = "๐",
+ ["oncoming_taxi"] = "๐",
+ ["one"] = "1",
+ ["one_piece_swimsuit"] = "๐ฉฑ",
+ ["onion"] = "๐ง
",
+ ["open_book"] = "๐",
+ ["open_file_folder"] = "๐",
+ ["open_hands"] = "๐",
+ ["open_mouth"] = "๐ฎ",
+ ["open_umbrella"] = "โ",
+ ["ophiuchus"] = "โ",
+ ["orange"] = "๐",
+ ["orange_book"] = "๐",
+ ["orange_circle"] = "๐ ",
+ ["orange_heart"] = "๐งก",
+ ["orange_square"] = "๐ง",
+ ["orangutan"] = "๐ฆง",
+ ["orthodox_cross"] = "โฆ",
+ ["otter"] = "๐ฆฆ",
+ ["outbox_tray"] = "๐ค",
+ ["owl"] = "๐ฆ",
+ ["ox"] = "๐",
+ ["oyster"] = "๐ฆช",
+ ["package"] = "๐ฆ",
+ ["page_facing_up"] = "๐",
+ ["page_with_curl"] = "๐",
+ ["pager"] = "๐",
+ ["paintbrush"] = "๐",
+ ["pakistan"] = "๐ต",
+ ["palau"] = "๐ต",
+ ["palestinian_territories"] = "๐ต",
+ ["palm_down_hand"] = "๐ซณ",
+ ["palm_tree"] = "๐ด",
+ ["palm_up_hand"] = "๐ซด",
+ ["palms_up_together"] = "๐คฒ",
+ ["panama"] = "๐ต",
+ ["pancakes"] = "๐ฅ",
+ ["panda_face"] = "๐ผ",
+ ["paperclip"] = "๐",
+ ["paperclips"] = "๐",
+ ["papua_new_guinea"] = "๐ต",
+ ["parachute"] = "๐ช",
+ ["paraguay"] = "๐ต",
+ ["parasol_on_ground"] = "โฑ",
+ ["parking"] = "๐
ฟ",
+ ["parrot"] = "๐ฆ",
+ ["part_alternation_mark"] = "ใฝ",
+ ["partly_sunny"] = "โ
",
+ ["partying_face"] = "๐ฅณ",
+ ["passenger_ship"] = "๐ณ",
+ ["passport_control"] = "๐",
+ ["pause_button"] = "โธ",
+ ["paw_prints"] = "๐พ",
+ ["pea_pod"] = "๐ซ",
+ ["peace_symbol"] = "โฎ",
+ ["peach"] = "๐",
+ ["peacock"] = "๐ฆ",
+ ["peanuts"] = "๐ฅ",
+ ["pear"] = "๐",
+ ["pen"] = "๐",
+ ["pencil"] = "๐",
+ ["pencil2"] = "โ",
+ ["penguin"] = "๐ง",
+ ["pensive"] = "๐",
+ ["people_holding_hands"] = "๐ง",
+ ["people_hugging"] = "๐ซ",
+ ["performing_arts"] = "๐ญ",
+ ["persevere"] = "๐ฃ",
+ ["person_bald"] = "๐ง",
+ ["person_curly_hair"] = "๐ง",
+ ["person_feeding_baby"] = "๐ง",
+ ["person_fencing"] = "๐คบ",
+ ["person_in_manual_wheelchair"] = "๐ง",
+ ["person_in_motorized_wheelchair"] = "๐ง",
+ ["person_in_tuxedo"] = "๐คต",
+ ["person_red_hair"] = "๐ง",
+ ["person_white_hair"] = "๐ง",
+ ["person_with_crown"] = "๐ซ
",
+ ["person_with_probing_cane"] = "๐ง",
+ ["person_with_turban"] = "๐ณ",
+ ["person_with_veil"] = "๐ฐ",
+ ["peru"] = "๐ต",
+ ["petri_dish"] = "๐งซ",
+ ["philippines"] = "๐ต",
+ ["phone"] = "โ",
+ ["pick"] = "โ",
+ ["pickup_truck"] = "๐ป",
+ ["pie"] = "๐ฅง",
+ ["pig"] = "๐ท",
+ ["pig2"] = "๐",
+ ["pig_nose"] = "๐ฝ",
+ ["pill"] = "๐",
+ ["pilot"] = "๐ง",
+ ["pinata"] = "๐ช
",
+ ["pinched_fingers"] = "๐ค",
+ ["pinching_hand"] = "๐ค",
+ ["pineapple"] = "๐",
+ ["ping_pong"] = "๐",
+ ["pink_heart"] = "๐ฉท",
+ ["pirate_flag"] = "๐ด",
+ ["pisces"] = "โ",
+ ["pitcairn_islands"] = "๐ต",
+ ["pizza"] = "๐",
+ ["placard"] = "๐ชง",
+ ["place_of_worship"] = "๐",
+ ["plate_with_cutlery"] = "๐ฝ",
+ ["play_or_pause_button"] = "โฏ",
+ ["playground_slide"] = "๐",
+ ["pleading_face"] = "๐ฅบ",
+ ["plunger"] = "๐ช ",
+ ["point_down"] = "๐",
+ ["point_left"] = "๐",
+ ["point_right"] = "๐",
+ ["point_up"] = "โ",
+ ["point_up_2"] = "๐",
+ ["poland"] = "๐ต",
+ ["polar_bear"] = "๐ป",
+ ["police_car"] = "๐",
+ ["police_officer"] = "๐ฎ",
+ ["policeman"] = "๐ฎ",
+ ["policewoman"] = "๐ฎ",
+ ["poodle"] = "๐ฉ",
+ ["poop"] = "๐ฉ",
+ ["popcorn"] = "๐ฟ",
+ ["portugal"] = "๐ต",
+ ["post_office"] = "๐ฃ",
+ ["postal_horn"] = "๐ฏ",
+ ["postbox"] = "๐ฎ",
+ ["potable_water"] = "๐ฐ",
+ ["potato"] = "๐ฅ",
+ ["potted_plant"] = "๐ชด",
+ ["pouch"] = "๐",
+ ["poultry_leg"] = "๐",
+ ["pound"] = "๐ท",
+ ["pouring_liquid"] = "๐ซ",
+ ["pout"] = "๐ก",
+ ["pouting_cat"] = "๐พ",
+ ["pouting_face"] = "๐",
+ ["pouting_man"] = "๐",
+ ["pouting_woman"] = "๐",
+ ["pray"] = "๐",
+ ["prayer_beads"] = "๐ฟ",
+ ["pregnant_man"] = "๐ซ",
+ ["pregnant_person"] = "๐ซ",
+ ["pregnant_woman"] = "๐คฐ",
+ ["pretzel"] = "๐ฅจ",
+ ["previous_track_button"] = "โฎ",
+ ["prince"] = "๐คด",
+ ["princess"] = "๐ธ",
+ ["printer"] = "๐จ",
+ ["probing_cane"] = "๐ฆฏ",
+ ["puerto_rico"] = "๐ต",
+ ["punch"] = "๐",
+ ["purple_circle"] = "๐ฃ",
+ ["purple_heart"] = "๐",
+ ["purple_square"] = "๐ช",
+ ["purse"] = "๐",
+ ["pushpin"] = "๐",
+ ["put_litter_in_its_place"] = "๐ฎ",
+ ["qatar"] = "๐ถ",
+ ["question"] = "โ",
+ ["rabbit"] = "๐ฐ",
+ ["rabbit2"] = "๐",
+ ["raccoon"] = "๐ฆ",
+ ["racehorse"] = "๐",
+ ["racing_car"] = "๐",
+ ["radio"] = "๐ป",
+ ["radio_button"] = "๐",
+ ["radioactive"] = "โข",
+ ["rage"] = "๐ก",
+ ["railway_car"] = "๐",
+ ["railway_track"] = "๐ค",
+ ["rainbow"] = "๐",
+ ["rainbow_flag"] = "๐ณ",
+ ["raised_back_of_hand"] = "๐ค",
+ ["raised_eyebrow"] = "๐คจ",
+ ["raised_hand"] = "โ",
+ ["raised_hand_with_fingers_splayed"] = "๐",
+ ["raised_hands"] = "๐",
+ ["raising_hand"] = "๐",
+ ["raising_hand_man"] = "๐",
+ ["raising_hand_woman"] = "๐",
+ ["ram"] = "๐",
+ ["ramen"] = "๐",
+ ["rat"] = "๐",
+ ["razor"] = "๐ช",
+ ["receipt"] = "๐งพ",
+ ["record_button"] = "โบ",
+ ["recycle"] = "โป",
+ ["red_car"] = "๐",
+ ["red_circle"] = "๐ด",
+ ["red_envelope"] = "๐งง",
+ ["red_haired_man"] = "๐จ",
+ ["red_haired_woman"] = "๐ฉ",
+ ["red_square"] = "๐ฅ",
+ ["registered"] = "ยฎ",
+ ["relaxed"] = "โบ",
+ ["relieved"] = "๐",
+ ["reminder_ribbon"] = "๐",
+ ["repeat"] = "๐",
+ ["repeat_one"] = "๐",
+ ["rescue_worker_helmet"] = "โ",
+ ["restroom"] = "๐ป",
+ ["reunion"] = "๐ท",
+ ["revolving_hearts"] = "๐",
+ ["rewind"] = "โช",
+ ["rhinoceros"] = "๐ฆ",
+ ["ribbon"] = "๐",
+ ["rice"] = "๐",
+ ["rice_ball"] = "๐",
+ ["rice_cracker"] = "๐",
+ ["rice_scene"] = "๐",
+ ["right_anger_bubble"] = "๐ฏ",
+ ["rightwards_hand"] = "๐ซฑ",
+ ["rightwards_pushing_hand"] = "๐ซธ",
+ ["ring"] = "๐",
+ ["ring_buoy"] = "๐",
+ ["ringed_planet"] = "๐ช",
+ ["robot"] = "๐ค",
+ ["rock"] = "๐ชจ",
+ ["rocket"] = "๐",
+ ["rofl"] = "๐คฃ",
+ ["roll_eyes"] = "๐",
+ ["roll_of_paper"] = "๐งป",
+ ["roller_coaster"] = "๐ข",
+ ["roller_skate"] = "๐ผ",
+ ["romania"] = "๐ท",
+ ["rooster"] = "๐",
+ ["rose"] = "๐น",
+ ["rosette"] = "๐ต",
+ ["rotating_light"] = "๐จ",
+ ["round_pushpin"] = "๐",
+ ["rowboat"] = "๐ฃ",
+ ["rowing_man"] = "๐ฃ",
+ ["rowing_woman"] = "๐ฃ",
+ ["ru"] = "๐ท",
+ ["rugby_football"] = "๐",
+ ["runner"] = "๐",
+ ["running"] = "๐",
+ ["running_man"] = "๐",
+ ["running_shirt_with_sash"] = "๐ฝ",
+ ["running_woman"] = "๐",
+ ["rwanda"] = "๐ท",
+ ["sa"] = "๐",
+ ["safety_pin"] = "๐งท",
+ ["safety_vest"] = "๐ฆบ",
+ ["sagittarius"] = "โ",
+ ["sailboat"] = "โต",
+ ["sake"] = "๐ถ",
+ ["salt"] = "๐ง",
+ ["saluting_face"] = "๐ซก",
+ ["samoa"] = "๐ผ",
+ ["san_marino"] = "๐ธ",
+ ["sandal"] = "๐ก",
+ ["sandwich"] = "๐ฅช",
+ ["santa"] = "๐
",
+ ["sao_tome_principe"] = "๐ธ",
+ ["sari"] = "๐ฅป",
+ ["sassy_man"] = "๐",
+ ["sassy_woman"] = "๐",
+ ["satellite"] = "๐ก",
+ ["satisfied"] = "๐",
+ ["saudi_arabia"] = "๐ธ",
+ ["sauna_man"] = "๐ง",
+ ["sauna_person"] = "๐ง",
+ ["sauna_woman"] = "๐ง",
+ ["sauropod"] = "๐ฆ",
+ ["saxophone"] = "๐ท",
+ ["scarf"] = "๐งฃ",
+ ["school"] = "๐ซ",
+ ["school_satchel"] = "๐",
+ ["scientist"] = "๐ง",
+ ["scissors"] = "โ",
+ ["scorpion"] = "๐ฆ",
+ ["scorpius"] = "โ",
+ ["scotland"] = "๐ด",
+ ["scream"] = "๐ฑ",
+ ["scream_cat"] = "๐",
+ ["screwdriver"] = "๐ช",
+ ["scroll"] = "๐",
+ ["seal"] = "๐ฆญ",
+ ["seat"] = "๐บ",
+ ["secret"] = "ใ",
+ ["see_no_evil"] = "๐",
+ ["seedling"] = "๐ฑ",
+ ["selfie"] = "๐คณ",
+ ["senegal"] = "๐ธ",
+ ["serbia"] = "๐ท",
+ ["service_dog"] = "๐",
+ ["seven"] = "7",
+ ["sewing_needle"] = "๐ชก",
+ ["seychelles"] = "๐ธ",
+ ["shaking_face"] = "๐ซจ",
+ ["shallow_pan_of_food"] = "๐ฅ",
+ ["shamrock"] = "โ",
+ ["shark"] = "๐ฆ",
+ ["shaved_ice"] = "๐ง",
+ ["sheep"] = "๐",
+ ["shell"] = "๐",
+ ["shield"] = "๐ก",
+ ["shinto_shrine"] = "โฉ",
+ ["ship"] = "๐ข",
+ ["shipit"] = "",
+ ["shirt"] = "๐",
+ ["shit"] = "๐ฉ",
+ ["shoe"] = "๐",
+ ["shopping"] = "๐",
+ ["shopping_cart"] = "๐",
+ ["shorts"] = "๐ฉณ",
+ ["shower"] = "๐ฟ",
+ ["shrimp"] = "๐ฆ",
+ ["shrug"] = "๐คท",
+ ["shushing_face"] = "๐คซ",
+ ["sierra_leone"] = "๐ธ",
+ ["signal_strength"] = "๐ถ",
+ ["singapore"] = "๐ธ",
+ ["singer"] = "๐ง",
+ ["sint_maarten"] = "๐ธ",
+ ["six"] = "6",
+ ["six_pointed_star"] = "๐ฏ",
+ ["skateboard"] = "๐น",
+ ["ski"] = "๐ฟ",
+ ["skier"] = "โท",
+ ["skull"] = "๐",
+ ["skull_and_crossbones"] = "โ ",
+ ["skunk"] = "๐ฆจ",
+ ["sled"] = "๐ท",
+ ["sleeping"] = "๐ด",
+ ["sleeping_bed"] = "๐",
+ ["sleepy"] = "๐ช",
+ ["slightly_frowning_face"] = "๐",
+ ["slightly_smiling_face"] = "๐",
+ ["slot_machine"] = "๐ฐ",
+ ["sloth"] = "๐ฆฅ",
+ ["slovakia"] = "๐ธ",
+ ["slovenia"] = "๐ธ",
+ ["small_airplane"] = "๐ฉ",
+ ["small_blue_diamond"] = "๐น",
+ ["small_orange_diamond"] = "๐ธ",
+ ["small_red_triangle"] = "๐บ",
+ ["small_red_triangle_down"] = "๐ป",
+ ["smile"] = "๐",
+ ["smile_cat"] = "๐ธ",
+ ["smiley"] = "๐",
+ ["smiley_cat"] = "๐บ",
+ ["smiling_face_with_tear"] = "๐ฅฒ",
+ ["smiling_face_with_three_hearts"] = "๐ฅฐ",
+ ["smiling_imp"] = "๐",
+ ["smirk"] = "๐",
+ ["smirk_cat"] = "๐ผ",
+ ["smoking"] = "๐ฌ",
+ ["snail"] = "๐",
+ ["snake"] = "๐",
+ ["sneezing_face"] = "๐คง",
+ ["snowboarder"] = "๐",
+ ["snowflake"] = "โ",
+ ["snowman"] = "โ",
+ ["snowman_with_snow"] = "โ",
+ ["soap"] = "๐งผ",
+ ["sob"] = "๐ญ",
+ ["soccer"] = "โฝ",
+ ["socks"] = "๐งฆ",
+ ["softball"] = "๐ฅ",
+ ["solomon_islands"] = "๐ธ",
+ ["somalia"] = "๐ธ",
+ ["soon"] = "๐",
+ ["sos"] = "๐",
+ ["sound"] = "๐",
+ ["south_africa"] = "๐ฟ",
+ ["south_georgia_south_sandwich_islands"] = "๐ฌ",
+ ["south_sudan"] = "๐ธ",
+ ["space_invader"] = "๐พ",
+ ["spades"] = "โ ",
+ ["spaghetti"] = "๐",
+ ["sparkle"] = "โ",
+ ["sparkler"] = "๐",
+ ["sparkles"] = "โจ",
+ ["sparkling_heart"] = "๐",
+ ["speak_no_evil"] = "๐",
+ ["speaker"] = "๐",
+ ["speaking_head"] = "๐ฃ",
+ ["speech_balloon"] = "๐ฌ",
+ ["speedboat"] = "๐ค",
+ ["spider"] = "๐ท",
+ ["spider_web"] = "๐ธ",
+ ["spiral_calendar"] = "๐",
+ ["spiral_notepad"] = "๐",
+ ["sponge"] = "๐งฝ",
+ ["spoon"] = "๐ฅ",
+ ["squid"] = "๐ฆ",
+ ["sri_lanka"] = "๐ฑ",
+ ["st_barthelemy"] = "๐ง",
+ ["st_helena"] = "๐ธ",
+ ["st_kitts_nevis"] = "๐ฐ",
+ ["st_lucia"] = "๐ฑ",
+ ["st_martin"] = "๐ฒ",
+ ["st_pierre_miquelon"] = "๐ต",
+ ["st_vincent_grenadines"] = "๐ป",
+ ["stadium"] = "๐",
+ ["standing_man"] = "๐ง",
+ ["standing_person"] = "๐ง",
+ ["standing_woman"] = "๐ง",
+ ["star"] = "โญ",
+ ["star2"] = "๐",
+ ["star_and_crescent"] = "โช",
+ ["star_of_david"] = "โก",
+ ["star_struck"] = "๐คฉ",
+ ["stars"] = "๐ ",
+ ["station"] = "๐",
+ ["statue_of_liberty"] = "๐ฝ",
+ ["steam_locomotive"] = "๐",
+ ["stethoscope"] = "๐ฉบ",
+ ["stew"] = "๐ฒ",
+ ["stop_button"] = "โน",
+ ["stop_sign"] = "๐",
+ ["stopwatch"] = "โฑ",
+ ["straight_ruler"] = "๐",
+ ["strawberry"] = "๐",
+ ["stuck_out_tongue"] = "๐",
+ ["stuck_out_tongue_closed_eyes"] = "๐",
+ ["stuck_out_tongue_winking_eye"] = "๐",
+ ["student"] = "๐ง",
+ ["studio_microphone"] = "๐",
+ ["stuffed_flatbread"] = "๐ฅ",
+ ["sudan"] = "๐ธ",
+ ["sun_behind_large_cloud"] = "๐ฅ",
+ ["sun_behind_rain_cloud"] = "๐ฆ",
+ ["sun_behind_small_cloud"] = "๐ค",
+ ["sun_with_face"] = "๐",
+ ["sunflower"] = "๐ป",
+ ["sunglasses"] = "๐",
+ ["sunny"] = "โ",
+ ["sunrise"] = "๐
",
+ ["sunrise_over_mountains"] = "๐",
+ ["superhero"] = "๐ฆธ",
+ ["superhero_man"] = "๐ฆธ",
+ ["superhero_woman"] = "๐ฆธ",
+ ["supervillain"] = "๐ฆน",
+ ["supervillain_man"] = "๐ฆน",
+ ["supervillain_woman"] = "๐ฆน",
+ ["surfer"] = "๐",
+ ["surfing_man"] = "๐",
+ ["surfing_woman"] = "๐",
+ ["suriname"] = "๐ธ",
+ ["sushi"] = "๐ฃ",
+ ["suspect"] = "",
+ ["suspension_railway"] = "๐",
+ ["svalbard_jan_mayen"] = "๐ธ",
+ ["swan"] = "๐ฆข",
+ ["swaziland"] = "๐ธ",
+ ["sweat"] = "๐",
+ ["sweat_drops"] = "๐ฆ",
+ ["sweat_smile"] = "๐
",
+ ["sweden"] = "๐ธ",
+ ["sweet_potato"] = "๐ ",
+ ["swim_brief"] = "๐ฉฒ",
+ ["swimmer"] = "๐",
+ ["swimming_man"] = "๐",
+ ["swimming_woman"] = "๐",
+ ["switzerland"] = "๐จ",
+ ["symbols"] = "๐ฃ",
+ ["synagogue"] = "๐",
+ ["syria"] = "๐ธ",
+ ["syringe"] = "๐",
+ ["t-rex"] = "๐ฆ",
+ ["taco"] = "๐ฎ",
+ ["tada"] = "๐",
+ ["taiwan"] = "๐น",
+ ["tajikistan"] = "๐น",
+ ["takeout_box"] = "๐ฅก",
+ ["tamale"] = "๐ซ",
+ ["tanabata_tree"] = "๐",
+ ["tangerine"] = "๐",
+ ["tanzania"] = "๐น",
+ ["taurus"] = "โ",
+ ["taxi"] = "๐",
+ ["tea"] = "๐ต",
+ ["teacher"] = "๐ง",
+ ["teapot"] = "๐ซ",
+ ["technologist"] = "๐ง",
+ ["teddy_bear"] = "๐งธ",
+ ["telephone"] = "โ",
+ ["telephone_receiver"] = "๐",
+ ["telescope"] = "๐ญ",
+ ["tennis"] = "๐พ",
+ ["tent"] = "โบ",
+ ["test_tube"] = "๐งช",
+ ["thailand"] = "๐น",
+ ["thermometer"] = "๐ก",
+ ["thinking"] = "๐ค",
+ ["thong_sandal"] = "๐ฉด",
+ ["thought_balloon"] = "๐ญ",
+ ["thread"] = "๐งต",
+ ["three"] = "3",
+ ["thumbsdown"] = "๐",
+ ["thumbsup"] = "๐",
+ ["ticket"] = "๐ซ",
+ ["tickets"] = "๐",
+ ["tiger"] = "๐ฏ",
+ ["tiger2"] = "๐
",
+ ["timer_clock"] = "โฒ",
+ ["timor_leste"] = "๐น",
+ ["tipping_hand_man"] = "๐",
+ ["tipping_hand_person"] = "๐",
+ ["tipping_hand_woman"] = "๐",
+ ["tired_face"] = "๐ซ",
+ ["tm"] = "โข",
+ ["togo"] = "๐น",
+ ["toilet"] = "๐ฝ",
+ ["tokelau"] = "๐น",
+ ["tokyo_tower"] = "๐ผ",
+ ["tomato"] = "๐
",
+ ["tonga"] = "๐น",
+ ["tongue"] = "๐
",
+ ["toolbox"] = "๐งฐ",
+ ["tooth"] = "๐ฆท",
+ ["toothbrush"] = "๐ชฅ",
+ ["top"] = "๐",
+ ["tophat"] = "๐ฉ",
+ ["tornado"] = "๐ช",
+ ["tr"] = "๐น",
+ ["trackball"] = "๐ฒ",
+ ["tractor"] = "๐",
+ ["traffic_light"] = "๐ฅ",
+ ["train"] = "๐",
+ ["train2"] = "๐",
+ ["tram"] = "๐",
+ ["transgender_flag"] = "๐ณ",
+ ["transgender_symbol"] = "โง",
+ ["triangular_flag_on_post"] = "๐ฉ",
+ ["triangular_ruler"] = "๐",
+ ["trident"] = "๐ฑ",
+ ["trinidad_tobago"] = "๐น",
+ ["tristan_da_cunha"] = "๐น",
+ ["triumph"] = "๐ค",
+ ["troll"] = "๐ง",
+ ["trolleybus"] = "๐",
+ ["trollface"] = "",
+ ["trophy"] = "๐",
+ ["tropical_drink"] = "๐น",
+ ["tropical_fish"] = "๐ ",
+ ["truck"] = "๐",
+ ["trumpet"] = "๐บ",
+ ["tshirt"] = "๐",
+ ["tulip"] = "๐ท",
+ ["tumbler_glass"] = "๐ฅ",
+ ["tunisia"] = "๐น",
+ ["turkey"] = "๐ฆ",
+ ["turkmenistan"] = "๐น",
+ ["turks_caicos_islands"] = "๐น",
+ ["turtle"] = "๐ข",
+ ["tuvalu"] = "๐น",
+ ["tv"] = "๐บ",
+ ["twisted_rightwards_arrows"] = "๐",
+ ["two"] = "2",
+ ["two_hearts"] = "๐",
+ ["two_men_holding_hands"] = "๐ฌ",
+ ["two_women_holding_hands"] = "๐ญ",
+ ["u5272"] = "๐น",
+ ["u5408"] = "๐ด",
+ ["u55b6"] = "๐บ",
+ ["u6307"] = "๐ฏ",
+ ["u6708"] = "๐ท",
+ ["u6709"] = "๐ถ",
+ ["u6e80"] = "๐ต",
+ ["u7121"] = "๐",
+ ["u7533"] = "๐ธ",
+ ["u7981"] = "๐ฒ",
+ ["u7a7a"] = "๐ณ",
+ ["uganda"] = "๐บ",
+ ["uk"] = "๐ฌ",
+ ["ukraine"] = "๐บ",
+ ["umbrella"] = "โ",
+ ["unamused"] = "๐",
+ ["underage"] = "๐",
+ ["unicorn"] = "๐ฆ",
+ ["united_arab_emirates"] = "๐ฆ",
+ ["united_nations"] = "๐บ",
+ ["unlock"] = "๐",
+ ["up"] = "๐",
+ ["upside_down_face"] = "๐",
+ ["uruguay"] = "๐บ",
+ ["us"] = "๐บ",
+ ["us_outlying_islands"] = "๐บ",
+ ["us_virgin_islands"] = "๐ป",
+ ["uzbekistan"] = "๐บ",
+ ["v"] = "โ",
+ ["vampire"] = "๐ง",
+ ["vampire_man"] = "๐ง",
+ ["vampire_woman"] = "๐ง",
+ ["vanuatu"] = "๐ป",
+ ["vatican_city"] = "๐ป",
+ ["venezuela"] = "๐ป",
+ ["vertical_traffic_light"] = "๐ฆ",
+ ["vhs"] = "๐ผ",
+ ["vibration_mode"] = "๐ณ",
+ ["video_camera"] = "๐น",
+ ["video_game"] = "๐ฎ",
+ ["vietnam"] = "๐ป",
+ ["violin"] = "๐ป",
+ ["virgo"] = "โ",
+ ["volcano"] = "๐",
+ ["volleyball"] = "๐",
+ ["vomiting_face"] = "๐คฎ",
+ ["vs"] = "๐",
+ ["vulcan_salute"] = "๐",
+ ["waffle"] = "๐ง",
+ ["wales"] = "๐ด",
+ ["walking"] = "๐ถ",
+ ["walking_man"] = "๐ถ",
+ ["walking_woman"] = "๐ถ",
+ ["wallis_futuna"] = "๐ผ",
+ ["waning_crescent_moon"] = "๐",
+ ["waning_gibbous_moon"] = "๐",
+ ["warning"] = "โ ",
+ ["wastebasket"] = "๐",
+ ["watch"] = "โ",
+ ["water_buffalo"] = "๐",
+ ["water_polo"] = "๐คฝ",
+ ["watermelon"] = "๐",
+ ["wave"] = "๐",
+ ["wavy_dash"] = "ใฐ",
+ ["waxing_crescent_moon"] = "๐",
+ ["waxing_gibbous_moon"] = "๐",
+ ["wc"] = "๐พ",
+ ["weary"] = "๐ฉ",
+ ["wedding"] = "๐",
+ ["weight_lifting"] = "๐",
+ ["weight_lifting_man"] = "๐",
+ ["weight_lifting_woman"] = "๐",
+ ["western_sahara"] = "๐ช",
+ ["whale"] = "๐ณ",
+ ["whale2"] = "๐",
+ ["wheel"] = "๐",
+ ["wheel_of_dharma"] = "โธ",
+ ["wheelchair"] = "โฟ",
+ ["white_check_mark"] = "โ
",
+ ["white_circle"] = "โช",
+ ["white_flag"] = "๐ณ",
+ ["white_flower"] = "๐ฎ",
+ ["white_haired_man"] = "๐จ",
+ ["white_haired_woman"] = "๐ฉ",
+ ["white_heart"] = "๐ค",
+ ["white_large_square"] = "โฌ",
+ ["white_medium_small_square"] = "โฝ",
+ ["white_medium_square"] = "โป",
+ ["white_small_square"] = "โซ",
+ ["white_square_button"] = "๐ณ",
+ ["wilted_flower"] = "๐ฅ",
+ ["wind_chime"] = "๐",
+ ["wind_face"] = "๐ฌ",
+ ["window"] = "๐ช",
+ ["wine_glass"] = "๐ท",
+ ["wing"] = "๐ชฝ",
+ ["wink"] = "๐",
+ ["wireless"] = "๐",
+ ["wolf"] = "๐บ",
+ ["woman"] = "๐ฉ",
+ ["woman_artist"] = "๐ฉ",
+ ["woman_astronaut"] = "๐ฉ",
+ ["woman_beard"] = "๐ง",
+ ["woman_cartwheeling"] = "๐คธ",
+ ["woman_cook"] = "๐ฉ",
+ ["woman_dancing"] = "๐",
+ ["woman_facepalming"] = "๐คฆ",
+ ["woman_factory_worker"] = "๐ฉ",
+ ["woman_farmer"] = "๐ฉ",
+ ["woman_feeding_baby"] = "๐ฉ",
+ ["woman_firefighter"] = "๐ฉ",
+ ["woman_health_worker"] = "๐ฉ",
+ ["woman_in_manual_wheelchair"] = "๐ฉ",
+ ["woman_in_motorized_wheelchair"] = "๐ฉ",
+ ["woman_in_tuxedo"] = "๐คต",
+ ["woman_judge"] = "๐ฉ",
+ ["woman_juggling"] = "๐คน",
+ ["woman_mechanic"] = "๐ฉ",
+ ["woman_office_worker"] = "๐ฉ",
+ ["woman_pilot"] = "๐ฉ",
+ ["woman_playing_handball"] = "๐คพ",
+ ["woman_playing_water_polo"] = "๐คฝ",
+ ["woman_scientist"] = "๐ฉ",
+ ["woman_shrugging"] = "๐คท",
+ ["woman_singer"] = "๐ฉ",
+ ["woman_student"] = "๐ฉ",
+ ["woman_teacher"] = "๐ฉ",
+ ["woman_technologist"] = "๐ฉ",
+ ["woman_with_headscarf"] = "๐ง",
+ ["woman_with_probing_cane"] = "๐ฉ",
+ ["woman_with_turban"] = "๐ณ",
+ ["woman_with_veil"] = "๐ฐ",
+ ["womans_clothes"] = "๐",
+ ["womans_hat"] = "๐",
+ ["women_wrestling"] = "๐คผ",
+ ["womens"] = "๐บ",
+ ["wood"] = "๐ชต",
+ ["woozy_face"] = "๐ฅด",
+ ["world_map"] = "๐บ",
+ ["worm"] = "๐ชฑ",
+ ["worried"] = "๐",
+ ["wrench"] = "๐ง",
+ ["wrestling"] = "๐คผ",
+ ["writing_hand"] = "โ",
+ ["x"] = "โ",
+ ["x_ray"] = "๐ฉป",
+ ["yarn"] = "๐งถ",
+ ["yawning_face"] = "๐ฅฑ",
+ ["yellow_circle"] = "๐ก",
+ ["yellow_heart"] = "๐",
+ ["yellow_square"] = "๐จ",
+ ["yemen"] = "๐พ",
+ ["yen"] = "๐ด",
+ ["yin_yang"] = "โฏ",
+ ["yo_yo"] = "๐ช",
+ ["yum"] = "๐",
+ ["zambia"] = "๐ฟ",
+ ["zany_face"] = "๐คช",
+ ["zap"] = "โก",
+ ["zebra"] = "๐ฆ",
+ ["zero"] = "0",
+ ["zimbabwe"] = "๐ฟ",
+ ["zipper_mouth_face"] = "๐ค",
+ ["zombie"] = "๐ง",
+ ["zombie_man"] = "๐ง",
+ ["zombie_woman"] = "๐ง",
+ ["zzz"] = "๐ค"
+ ---_
+};
+
+symbols.superscripts = {
+ ---+${class}
+ ["0"] = "โฐ",
+ ["1"] = "ยน",
+ ["2"] = "ยฒ",
+ ["3"] = "ยณ",
+ ["4"] = "โด",
+ ["5"] = "โต",
+ ["6"] = "โถ",
+ ["7"] = "โท",
+ ["8"] = "โธ",
+ ["9"] = "โน",
+
+ ["+"] = "โบ",
+ ["-"] = "โป",
+ ["="] = "โผ",
+ ["("] = "โฝ",
+ [")"] = "โพ",
+
+ ["A"] = "แต",
+ ["B"] = "แต",
+ ["C"] = "แถ",
+ ["D"] = "แต",
+ ["E"] = "แต",
+ ["F"] = "แถ ",
+ ["G"] = "แต",
+ ["H"] = "สฐ",
+ ["I"] = "โฑ",
+ ["J"] = "สฒ",
+ ["K"] = "แต",
+ ["L"] = "หก",
+ ["M"] = "แต",
+ ["N"] = "โฟ",
+ ["O"] = "แต",
+ ["P"] = "แต",
+ ["Q"] = "แถฟ",
+ ["R"] = "สณ",
+ ["S"] = "หข",
+ ["T"] = "แต",
+ ["U"] = "แต",
+ ["V"] = "แต",
+ ["W"] = "สท",
+ ["X"] = "หฃ",
+ ["Y"] = "สธ",
+ ["Z"] = "แถป",
+
+ ["a"] = "แต",
+ ["b"] = "แต",
+ ["c"] = "แถ",
+ ["d"] = "แต",
+ ["e"] = "แต",
+ ["f"] = "แถ ",
+ ["g"] = "แต",
+ ["h"] = "สฐ",
+ ["i"] = "โฑ",
+ ["j"] = "สฒ",
+ ["k"] = "แต",
+ ["l"] = "หก",
+ ["m"] = "แต",
+ ["n"] = "โฟ",
+ ["o"] = "แต",
+ ["p"] = "แต",
+ ["q"] = "แถฃ",
+ ["r"] = "สณ",
+ ["s"] = "หข",
+ ["t"] = "แต",
+ ["u"] = "แต",
+ ["v"] = "แต",
+ ["w"] = "สท",
+ ["x"] = "หฃ",
+ ["y"] = "สธ",
+ ["z"] = "แถป",
+
+ ["alpha"] = "แต
",
+ ["beta"] = "แต",
+ ["gamma"] = "แต",
+ ["delta"] = "แต",
+ ["epsilon"] = "แต",
+ ["theta"] = "แถฟ",
+ ["iota"] = "แถฅ",
+ ["Phi"] = "แถฒ",
+ ["varphi"] = "แต ",
+ ["chi"] = "แตก",
+ ---_
+};
+
+symbols.subscripts = {
+ ---+${class}
+ ["0"] = "โ",
+ ["1"] = "โ",
+ ["2"] = "โ",
+ ["3"] = "โ",
+ ["4"] = "โ",
+ ["5"] = "โ
",
+ ["6"] = "โ",
+ ["7"] = "โ",
+ ["8"] = "โ",
+ ["9"] = "โ",
+
+ ["+"] = "โ",
+ ["-"] = "โ",
+ ["="] = "โ",
+ ["("] = "โ",
+ [")"] = "โ",
+
+ ["A"] = "แด",
+ ["B"] = "ส",
+ ["C"] = "แด",
+ ["D"] = "แด
",
+ ["E"] = "แด",
+ ["F"] = "า",
+ ["G"] = "ษข",
+ ["H"] = "ส",
+ ["I"] = "ษช",
+ ["J"] = "แด",
+ ["K"] = "แด",
+ ["L"] = "ส",
+ ["M"] = "แด",
+ ["N"] = "ษด",
+ ["O"] = "ษช",
+ ["P"] = "แด",
+ ["Q"] = "วซ",
+ ["R"] = "ส",
+ ["S"] = "s",
+ ["T"] = "แด",
+ ["U"] = "แด",
+ ["V"] = "แด ",
+ ["W"] = "แดก",
+ ["X"] = "x",
+ ["Y"] = "ส",
+ ["Z"] = "แดข",
+
+ ["a"] = "โ",
+ ["b"] = "แตฆ",
+ ["c"] = "๐ธ",
+ ["d"] = "๐น",
+ ["e"] = "โ",
+ ["f"] = "๐ป",
+ ["g"] = "๐ฐ",
+ ["h"] = "โ",
+ ["i"] = "แตข",
+ ["j"] = "โฑผ",
+ ["k"] = "โ",
+ ["l"] = "โ",
+ ["m"] = "โ",
+ ["n"] = "โ",
+ ["o"] = "โ",
+ ["p"] = "โ",
+ ["q"] = "โด",
+ ["r"] = "แตฃ",
+ ["s"] = "โ",
+ ["t"] = "โ",
+ ["u"] = "แตค",
+ ["v"] = "แตฅ",
+ ["w"] = "๐",
+ ["x"] = "โ",
+ ["y"] = "แตง",
+ ["z"] = "๐",
+
+ ["beta"] = "แตฆ",
+ ["gamma"] = "แตง",
+ ["rho"] = "แตจ",
+ ["epsilon"] = "แตฉ",
+ ["chi"] = "แตช",
+ ---_
+};
+
+--- Uses \ding{val}
+symbols.decorative_punctuation = {
+ ["123"] = "โ",
+ ["125"] = "โ",
+ ["161"] = "โก",
+ ["163"] = "โฃ",
+
+ ["124"] = "โ",
+ ["126"] = "โ",
+ ["162"] = "โข",
+};
+
+symbols.entries = {
+ ---+ ${class, Predefined LaTeX text-mode commands | Page 19}
+ ["textasciicircum"] = "ห",
+ ["textless"] = "<",
+
+ ["textasciitilde"] = "ห",
+ ["textordfeminine"] = "ยช",
+
+ ["textasteriskcentered"] = "โ",
+ ["textordmasculine"] = "ยบ",
+
+ ["textbackslash"] = "\\",
+ ["textparagraph"] = "ยถ",
+
+ ["textbar"] = "|",
+ ["textperiodcentered"] = "ยท",
+
+ ["textbardbl"] = "โ",
+ ["textpertenthousand"] = "โฑ",
+
+ ["textbigcircle"] = "โ",
+ ["textperthousand"] = "โฐ",
+
+ ["textbraceleft"] = "{",
+ ["textquestiondown"] = "ยฟ",
+
+ ["textbraceright"] = "}",
+ ["textquotedblleft"] = "โ",
+
+ ["textbullet"] = "โข",
+ ["textquotedblright"] = "โ",
+
+ ["textcopyrightโ "] = "ยฉ",
+ ["textquoteleft"] = "โ",
+
+ ["textdagger"] = "โ ",
+ ["textquoteright"] = "โ",
+
+ ["textdaggerdbl"] = "โก",
+ ["textregistered"] = "ยฎ",
+
+ ["textdollarโ "] = "$",
+ ["textsectionโ "] = "ยง",
+
+ ["textellipsis"] = "โฆ",
+ ["textsterling"] = "ยฃ",
+
+ ["textemdash"] = "โ",
+ ["texttrademark"] = "โข",
+
+ ["textendash"] = "โ",
+ ["textunderscore"] = "_",
+
+ ["textexclamdown"] = "ยก",
+ ["textvisiblespace"] = "โฃ",
+
+ ["textgreater"] = ">",
+ ---_
+ ---+${class, Commands Defined to Work in Both Mode | Page 19}
+ ["copyright"] = "ยฉ",
+ ["dag"] = "โ ",
+ ["ddag"] = "โก",
+ ["dots"] = "โฆ",
+ ["P"] = "ยถ",
+ ["pounds"] = "ยฃ",
+ ["S"] = "ยง",
+
+ ["checkmark"] = "โ",
+ ["circledR"] = "ยฎ",
+ ["maltese"] = "โ ",
+ ---_
+
+ ---+${class, Non-ASCII letters | Page 20}
+ ["aa"] = "หa",
+ ["DH"] = "ร",
+ ["L"] = "L",
+ ["o"] = "รธ",
+ ["th"] = "รพ",
+
+ ["AA"] = "หA",
+ ["DJ"] = "ร",
+ ["l"] = "l",
+ ["oe"] = "ล",
+ ["TH"] = "ร",
+
+ ["AE"] = "ร",
+ ["dj"] = "ฤ",
+ ["NG"] = "ล",
+ ["OE"] = "ล",
+ ["ae"] = "รฆ",
+
+ ["IJ"] = "IJ",
+ ["ng"] = "ล",
+ ["ss"] = "ร",
+ ["dh"] = "รฐ",
+ ["ij"] = "ij",
+
+ ["O"] = "ร",
+ ["SS"] = "SS",
+ ---_
+ ---+${class, textgreek Upright Greek Letters | Page 20}
+ ["textalpha"] = "ฮฑ",
+ ["texteta"] = "ฮท",
+ ["textnu"] = "ฮฝ",
+ ["texttau"] = "ฯ",
+
+ ["textbeta"] = "ฮฒ",
+ ["texttheta"] = "ฮธ",
+ ["textxi"] = "ฮพ",
+ ["textupsilon"] = "ฯ
",
+
+ ["textgamma"] = "ฮณ",
+ ["textiota"] = "ฮน",
+ ["textomikron"] = "ฮฟ",
+ ["textphi"] = "ฯ",
+
+ ["textdelta"] = "ฮด",
+ ["textkappa"] = "ฮบ",
+ ["textpi"] = "ฯ",
+ ["textchi"] = "ฯ",
+
+ ["textepsilon"] = "ฮต",
+ ["textlambda"] = "ฮป",
+ ["textrho"] = "ฯ",
+ ["textpsi"] = "ฯ",
+
+ ["textzeta"] = "ฮถ",
+ ["textmu"] = "ฮผ",
+ ["textsigma"] = "ฯ",
+ ["textomega"] = "ฯ",
+
+ ["textAlpha"] = "ฮ",
+ ["textEta"] = "ฮ",
+ ["textNu"] = "ฮ",
+ ["textTau"] = "ฮค",
+
+ ["textBeta"] = "ฮ",
+ ["textTheta"] = "ฮ",
+ ["textXi"] = "ฮ",
+ ["textUpsilon"] = "ฮฅ",
+
+ ["textGamma"] = "ฮ",
+ ["textIota"] = "ฮ",
+ ["textOmikron"] = "ฮ",
+ ["textPhi"] = "ฮฆ",
+
+ ["textDelta"] = "ฮ",
+ ["textKappa"] = "ฮ",
+ ["textPi"] = "ฮ ",
+ ["textChi"] = "ฮง",
+
+ ["textEpsilon"] = "ฮ",
+ ["textLambda"] = "ฮ",
+ ["textRho"] = "ฮก",
+ ["textPsi"] = "ฮจ",
+
+ ["textZeta"] = "ฮ",
+ ["textMu"] = "ฮ",
+ ["textSigma"] = "ฮฃ",
+ ["textOmega"] = "ฮฉ",
+ ---_
+
+ ---+${class, Letters Used to Typeset Vietnamese | Page 21}
+ ["OHORN"] = "ฦ ",
+ ["ohorn"] = "ฦก",
+ ["UHORN"] = "ฦฏ",
+ ["uhorn"] = "ฦฐ",
+ ---_
+ ---+${class, Punctuation Marks Not Found in OT1 | Page 21}
+ ["guillemetleft"] = "ยซ",
+ ["guilsinglleft"] = "โน",
+ ["quotedblbase"] = "โ",
+ ["textquotedbl"] = '"',
+ ["guillemetright"] = "ยป",
+ ["guilsinglright"] = "โบ",
+ ["quotesinglbase"] = "โ",
+ ---_
+
+ ---+${class, fontawesome5 Decorative Marks & Symbols | Page 22}
+ ["faAsterisk"] = "*",
+ ["faExclamation"] = ",",
+ ["faQuoteRight"] = "ยฑ",
+
+ ["faAt"] = "@",
+ ["faParagraph"] = "ยถ",
+ ["faSlash"] = "/",
+
+ ["faEllipsisH"] = "!",
+ ["faQuestion"] = "?",
+
+ ["faEllipsisV"] = '"',
+ ["faQuoteLeft"] = "ยฐ",
+ ---_
+
+ ---+${class, Various math symbols}
+ ["mathexclam"] = "!",
+ ["mathoctothorpe"] = "#",
+ ["mathdollar"] = "$",
+ ["mathpercent"] = "%",
+ ["mathampersand"] = "&",
+ ["lparen"] = "(",
+ ["rparen"] = ")",
+ ["mathplus"] = "+",
+ ["mathcomma"] = ",",
+ ["mathperiod"] = ".",
+ ["mathslash"] = "/",
+ ["mathcolon"] = ":",
+ ["mathsemicolon"] = ";",
+ ["less"] = "<",
+ ["equal"] = "=",
+ ["greater"] = ">",
+ ["mathquestion"] = "?",
+ ["mathatsign"] = "@",
+ ["lbrack"] = "[",
+ ["backslash"] = "\\",
+ ["rbrack"] = "]",
+ ["lbrace"] = "{",
+ ["vert"] = "|",
+ ["rbrace"] = "}",
+ ["mathsterling"] = "ยฃ",
+ ["mathyen"] = "ยฅ",
+ ["mathsection"] = "ยง",
+ ["neg"] = "ยฌ",
+ ["pm"] = "ยฑ",
+ ["mathparagraph"] = "ยถ",
+ ["cdotp"] = "ยท",
+ ["times"] = "ร",
+ ["matheth"] = "รฐ",
+ ["div"] = "รท",
+ ["Zbar"] = "ฦต",
+ -- widecheck, Not a symbol
+ -- candra, Not a symbol
+ -- oturnedcomma, Not a symbol
+ -- ocommatopright, Not a symbol
+ -- droang, Not a symbol
+ -- wideutilde, Not a symbol
+ -- mathunderbar, Not a symbol
+ -- notaccent, Not a symbol
+ -- underleftrightarrow, Not a symbol
+ ["mupAlpha"] = "ฮ",
+ ["mupBeta"] = "ฮ",
+ ["mupGamma"] = "ฮ",
+ ["mupDelta"] = "ฮ",
+ ["mupEpsilon"] = "ฮ",
+ ["mupZeta"] = "ฮ",
+ ["mupEta"] = "ฮ",
+ ["mupTheta"] = "ฮ",
+ ["mupIota"] = "ฮ",
+ ["mupKappa"] = "ฮ",
+ ["mupLambda"] = "ฮ",
+ ["mupMu"] = "ฮ",
+ ["mupNu"] = "ฮ",
+ ["mupXi"] = "ฮ",
+ ["mupOmicron"] = "ฮ",
+ ["mupPi"] = "ฮ ",
+ ["mupRho"] = "ฮก",
+ ["mupSigma"] = "ฮฃ",
+ ["mupTau"] = "ฮค",
+ ["mupUpsilon"] = "ฮฅ",
+ ["mupPhi"] = "ฮฆ",
+ ["mupChi"] = "ฮง",
+ ["mupPsi"] = "ฮจ",
+ ["mupOmega"] = "ฮฉ",
+ ["mupalpha"] = "ฮฑ",
+ ["mupbeta"] = "ฮฒ",
+ ["mupgamma"] = "ฮณ",
+ ["mupdelta"] = "ฮด",
+ ["mupvarepsilon"] = "ฮต",
+ ["mupzeta"] = "ฮถ",
+ ["mupeta"] = "ฮท",
+ ["muptheta"] = "ฮธ",
+ ["mupiota"] = "ฮน",
+ ["mupkappa"] = "ฮบ",
+ ["muplambda"] = "ฮป",
+ ["mupmu"] = "ฮผ",
+ ["mupnu"] = "ฮฝ",
+ ["mupxi"] = "ฮพ",
+ ["mupomicron"] = "ฮฟ",
+ ["muppi"] = "ฯ",
+ ["muprho"] = "ฯ",
+ ["mupvarsigma"] = "ฯ",
+ ["mupsigma"] = "ฯ",
+ ["muptau"] = "ฯ",
+ ["mupupsilon"] = "ฯ
",
+ ["mupvarphi"] = "ฯ",
+ ["mupchi"] = "ฯ",
+ ["muppsi"] = "ฯ",
+ ["mupomega"] = "ฯ",
+ ["mupvartheta"] = "ฯ",
+ ["mupphi"] = "ฯ",
+ ["mupvarpi"] = "ฯ",
+ ["upDigamma"] = "ฯ",
+ ["updigamma"] = "ฯ",
+ ["mupvarkappa"] = "ฯฐ",
+ ["mupvarrho"] = "ฯฑ",
+ ["mupvarTheta"] = "ฯด",
+ ["mupepsilon"] = "ฯต",
+ ["upbackepsilon"] = "ฯถ",
+ ["mathhyphen"] = "โ",
+ ["horizbar"] = "โ",
+ ["Vert"] = "โ",
+ ["twolowline"] = "โ",
+ ["dagger"] = "โ ",
+ ["ddagger"] = "โก",
+ ["smblkcircle"] = "โข",
+ ["enleadertwodots"] = "โฅ",
+ ["unicodeellipsis"] = "โฆ",
+ ["prime"] = "โฒ",
+ ["dprime"] = "โณ",
+ ["trprime"] = "โด",
+ ["backprime"] = "โต",
+ ["backdprime"] = "โถ",
+ ["backtrprime"] = "โท",
+ ["caretinsert"] = "โธ",
+ ["Exclam"] = "โผ",
+ ["tieconcat"] = "โ",
+ ["hyphenbullet"] = "โ",
+ ["fracslash"] = "โ",
+ ["Question"] = "โ",
+ ["closure"] = "โ",
+ ["qprime"] = "โ",
+ ["euro"] = "โฌ",
+
+ -- leftharpoonaccent, Not a symbol
+ -- overleftharpoon, Not a symbol
+ -- lightharpoonaccent, Not a symbol
+ -- overrightharpoon, Not a symbol
+ -- vertoverlay, Not a symbol
+ -- overleftarrow Not a symbol,
+ -- overrightarrow Not a symbol,
+ -- vec, Not a symbol
+ -- dddot Not a symbol,
+ -- ddddot, Not a symbol
+ -- enclosecircle, Not a symbol
+ -- enclosesquare, Not a symbol
+ -- enclosediamond, Not a symbol
+ -- overleftrightarrow, Not a symbol
+ -- enclosetriangle, Not a symbol
+ -- annuity, Not a symbol
+ -- threeunderdot, Not a symbol
+ -- widebridgeabove, Not a symbol
+ -- underrightharpoondown, Not a symbol
+ -- underleftharpoondown, Not a symbol
+ -- underleftarrow, Not a symbol
+ -- underrightarrow, Not a symbol
+ -- asteraccent, Not a symbol
+
+ ["Eulerconst"] = "โ",
+ ["Planckconst"] = "โ",
+ ["hslash"] = "โ",
+ ["Im"] = "โ",
+ ["ell"] = "โ",
+ ["wp"] = "โ",
+ ["Re"] = "โ",
+ ["mho"] = "โง",
+ ["turnediota"] = "โฉ",
+ ["Angstrom"] = "โซ",
+ ["Finv"] = "โฒ",
+ ["aleph"] = "โต",
+ ["beth"] = "โถ",
+ ["gimel"] = "โท",
+ ["daleth"] = "โธ",
+ ["Bbbpi"] = "โผ",
+ ["Bbbgamma"] = "โฝ",
+ ["BbbGamma"] = "โพ",
+ ["BbbPi"] = "โฟ",
+ ["Bbbsum"] = "โ
",
+ ["Game"] = "โ
",
+ ["sansLturned"] = "โ
",
+ ["sansLmirrored"] = "โ
",
+ ["Yup"] = "โ
",
+ ["CapitalDifferentialD"] = "โ
",
+ ["DifferentialD"] = "โ
",
+ ["ExponentialE"] = "โ
",
+ ["ComplexI"] = "โ
",
+ ["ComplexJ"] = "โ
",
+ ["PropertyLine"] = "โ
",
+ ["upand"] = "โ
",
+ ["leftarrow"] = "โ",
+ ["uparrow"] = "โ",
+ ["rightarrow"] = "โ",
+ ["downarrow"] = "โ",
+ ["leftrightarrow"] = "โ",
+ ["updownarrow"] = "โ",
+ ["nwarrow"] = "โ",
+ ["nearrow"] = "โ",
+ ["searrow"] = "โ",
+ ["swarrow"] = "โ",
+ ["nleftarrow"] = "โ",
+ ["nrightarrow"] = "โ",
+ ["leftwavearrow"] = "โ",
+ ["rightwavearrow"] = "โ",
+ ["twoheadleftarrow"] = "โ",
+ ["twoheaduparrow"] = "โ",
+ ["twoheadrightarrow"] = "โ ",
+ ["twoheaddownarrow"] = "โก",
+ ["leftarrowtail"] = "โข",
+ ["rightarrowtail"] = "โฃ",
+ ["mapsfrom"] = "โค",
+ ["mapsup"] = "โฅ",
+ ["mapsto"] = "โฆ",
+ ["mapsdown"] = "โง",
+ ["updownarrowbar"] = "โจ",
+ ["hookleftarrow"] = "โฉ",
+ ["hookrightarrow"] = "โช",
+ ["looparrowleft"] = "โซ",
+ ["looparrowright"] = "โฌ",
+ ["leftrightsquigarrow"] = "โญ",
+ ["nleftrightarrow"] = "โฎ",
+ ["downzigzagarrow"] = "โฏ",
+ ["Lsh"] = "โฐ",
+ ["Rsh"] = "โฑ",
+ ["Ldsh"] = "โฒ",
+ ["Rdsh"] = "โณ",
+ ["lin๓ฏปญ"] = "โด",
+ ["carriagereturn"] = "โต",
+ ["curvearrowleft"] = "โถ",
+ ["curvearrowright"] = "โท",
+ ["barovernorthwestarrow"] = "โธ",
+ ["barleftarrowrightarrowbar"] = "โน",
+ ["acwopencirclearrow"] = "โบ",
+ ["cwopencirclearrow"] = "โป",
+ ["leftharpoonup"] = "โผ",
+ ["leftharpoondown"] = "โฝ",
+ ["upharpoonright"] = "โพ",
+ ["upharpoonleft"] = "โฟ",
+ ["rightharpoonup"] = "โ",
+ ["rightharpoondown"] = "โ",
+ ["downharpoonright"] = "โ",
+ ["downharpoonleft"] = "โ",
+ ["rightleftarrows"] = "โ",
+ ["updownarrows"] = "โ
",
+ ["leftrightarrows"] = "โ",
+ ["leftleftarrows"] = "โ",
+ ["upuparrows"] = "โ",
+ ["rightrightarrows"] = "โ",
+ ["downdownarrows"] = "โ",
+ ["leftrightharpoons"] = "โ",
+ ["rightleftharpoons"] = "โ",
+ ["nLeftarrow"] = "โ",
+ ["nLeftrightarrow"] = "โ",
+ ["nRightarrow"] = "โ",
+ ["Leftarrow"] = "โ",
+ ["Uparrow"] = "โ",
+ ["Rightarrow"] = "โ",
+ ["Downarrow"] = "โ",
+ ["Leftrightarrow"] = "โ",
+ ["Updownarrow"] = "โ",
+ ["Nwarrow"] = "โ",
+ ["Nearrow"] = "โ",
+ ["Searrow"] = "โ",
+ ["Swarrow"] = "โ",
+ ["Lleftarrow"] = "โ",
+ ["Rrightarrow"] = "โ",
+ ["leftsquigarrow"] = "โ",
+ ["rightsquigarrow"] = "โ",
+ ["nHuparrow"] = "โ",
+ ["nHdownarrow"] = "โ",
+ ["leftdasharrow"] = "โ ",
+ ["updasharrow"] = "โก",
+ ["rightdasharrow"] = "โข",
+ ["downdasharrow"] = "โฃ",
+ ["barleftarrow"] = "โค",
+ ["rightarrowbar"] = "โฅ",
+ ["leftwhitearrow"] = "โฆ",
+ ["upwhitearrow"] = "โง",
+ ["rightwhitearrow"] = "โจ",
+ ["downwhitearrow"] = "โฉ",
+ ["whitearrowupfrombar"] = "โช",
+ ["circleonrightarrow"] = "โด",
+ ["downuparrows"] = "โต",
+ ["rightthreearrows"] = "โถ",
+ ["nvleftarrow"] = "โท",
+ ["nvrightarrow"] = "โธ",
+ ["nvleftrightarrow"] = "โน",
+ ["nVleftarrow"] = "โบ",
+ ["nVrightarrow"] = "โป",
+ ["nVleftrightarrow"] = "โผ",
+ ["leftarrowtriangle"] = "โฝ",
+ ["rightarrowtriangle"] = "โพ",
+ ["leftrightarrowtriangle"] = "โฟ",
+ ["forall"] = "โ",
+ ["complement"] = "โ",
+ ["partial"] = "โ",
+ ["exists"] = "โ",
+ ["nexists"] = "โ",
+ ["varnothing"] = "โ
",
+ ["increment"] = "โ",
+ ["nabla"] = "โ",
+ ["in"] = "โ",
+ ["notin"] = "โ",
+ ["smallin"] = "โ",
+ ["ni"] = "โ",
+ ["nni"] = "โ",
+ ["smallni"] = "โ",
+ ["QED"] = "โ",
+ ["prod"] = "โ",
+ ["coprod"] = "โ",
+ ["sum"] = "โ",
+ ["minus"] = "โ",
+ ["mp"] = "โ",
+ ["dotplus"] = "โ",
+ ["divslash"] = "โ",
+ ["setminus"] = "โงต",
+ ["ast"] = "โ",
+ ["vysmwhtcircle"] = "โ",
+ ["vysmblkcircle"] = "โ",
+ ["sqrt"] = "โ",
+ ["surd"] = "โ",
+ ["cuberoot"] = "โ",
+ ["fourthroot"] = "โ",
+ ["propto"] = "โ",
+ ["infty"] = "โ",
+ ["rightangle"] = "โ",
+ ["angle"] = "โ ",
+ ["measuredangle"] = "โก",
+ ["sphericalangle"] = "โข",
+ ["mid"] = "โฃ",
+ ["nmid"] = "โค",
+ ["parallel"] = "โฅ",
+ ["nparallel"] = "โฆ",
+ ["wedge"] = "โง",
+ ["vee"] = "โจ",
+ ["cap"] = "โฉ",
+ ["cup"] = "โช",
+ ["int"] = "โซ",
+ ["iint"] = "โฌ",
+ ["iiint"] = "โญ",
+ ["oint"] = "โฎ",
+ ["oiint"] = "โฏ",
+ ["oiiint"] = "โฐ",
+ ["intclockwise"] = "โฑ",
+ ["varointclockwise"] = "โฒ",
+ ["ointctrclockwise"] = "โณ",
+ ["therefore"] = "โด",
+ ["because"] = "โต",
+ ["mathratio"] = "โถ",
+ ["Colon"] = "โท",
+ ["dotminus"] = "โธ",
+ ["dashcolon"] = "โน",
+ ["dotsminusdots"] = "โบ",
+ ["kernelcontraction"] = "โป",
+ ["sim"] = "โผ",
+ ["backsim"] = "โฝ",
+ ["invlazys"] = "โพ",
+ ["sinewave"] = "โฟ",
+ ["wr"] = "โ",
+ ["nsim"] = "โ",
+ ["eqsim"] = "โ",
+ ["simeq"] = "โ",
+ ["nsime"] = "โ",
+ ["sime"] = "โ",
+ ["nsimeq"] = "โ",
+ ["cong"] = "โ
",
+ ["simneqq"] = "โ",
+ ["ncong"] = "โ",
+ ["approx"] = "โ",
+ ["napprox"] = "โ",
+ ["approxeq"] = "โ",
+ ["approxident"] = "โ",
+ ["backcong"] = "โ",
+ ["asymp"] = "โ",
+ ["Bumpeq"] = "โ",
+ ["bumpeq"] = "โ",
+ ["doteq"] = "โ",
+ ["Doteq"] = "โ",
+ ["fallingdotseq"] = "โ",
+ ["risingdotseq"] = "โ",
+ ["coloneq"] = "โ",
+ ["eqcolon"] = "โ",
+ ["eqcirc"] = "โ",
+ ["circeq"] = "โ",
+ ["arceq"] = "โ",
+ ["wedgeq"] = "โ",
+ ["veeeq"] = "โ",
+ ["stareq"] = "โ",
+ ["triangleq"] = "โ",
+ ["eqdef"] = "โ",
+ ["measeq"] = "โ",
+ ["questeq"] = "โ",
+ ["ne"] = "โ ",
+ ["equiv"] = "โก",
+ ["nequiv"] = "โข",
+ ["Equiv"] = "โฃ",
+ ["leq"] = "โค",
+ ["geq"] = "โฅ",
+ ["leqq"] = "โฆ",
+ ["geqq"] = "โง",
+ ["lneqq"] = "โจ",
+ ["gneqq"] = "โฉ",
+ ["ll"] = "โช",
+ ["gg"] = "โซ",
+ ["between"] = "โฌ",
+ ["nasymp"] = "โญ",
+ ["nless"] = "โฎ",
+ ["ngtr"] = "โฏ",
+ ["nleq"] = "โฐ",
+ ["ngeq"] = "โฑ",
+ ["lesssim"] = "โฒ",
+ ["gtrsim"] = "โณ",
+ ["nlesssim"] = "โด",
+ ["ngtrsim"] = "โต",
+ ["lessgtr"] = "โถ",
+ ["gtrless"] = "โท",
+ ["nlessgtr"] = "โธ",
+ ["ngtrless"] = "โน",
+ ["prec"] = "โบ",
+ ["succ"] = "โป",
+ ["preccurlyeq"] = "โผ",
+ ["succcurlyeq"] = "โฝ",
+ ["precsim"] = "โพ",
+ ["succsim"] = "โฟ",
+ ["nprec"] = "โ",
+ ["nsucc"] = "โ",
+ ["subset"] = "โ",
+ ["supset"] = "โ",
+ ["nsubset"] = "โ",
+ ["nsupset"] = "โ
",
+ ["subseteq"] = "โ",
+ ["supseteq"] = "โ",
+ ["nsubseteq"] = "โ",
+ ["nsupseteq"] = "โ",
+ ["subsetneq"] = "โ",
+ ["supsetneq"] = "โ",
+ ["cupleftarrow"] = "โ",
+ ["cupdot"] = "โ",
+ ["uplus"] = "โ",
+ ["sqsubset"] = "โ",
+ ["sqsupset"] = "โ",
+ ["sqsubseteq"] = "โ",
+ ["sqsupseteq"] = "โ",
+ ["sqcap"] = "โ",
+ ["sqcup"] = "โ",
+ ["oplus"] = "โ",
+ ["ominus"] = "โ",
+ ["otimes"] = "โ",
+ ["oslash"] = "โ",
+ ["odot"] = "โ",
+ ["circledcirc"] = "โ",
+ ["circledast"] = "โ",
+ ["circledequal"] = "โ",
+ ["circleddash"] = "โ",
+ ["boxplus"] = "โ",
+ ["boxminus"] = "โ",
+ ["boxtimes"] = "โ ",
+ ["boxdot"] = "โก",
+ ["vdash"] = "โข",
+ ["dashv"] = "โฃ",
+ ["top"] = "โค",
+ ["bot"] = "โฅ",
+ ["assert"] = "โฆ",
+ ["models"] = "โง",
+ ["vDash"] = "โจ",
+ ["Vdash"] = "โฉ",
+ ["Vvdash"] = "โช",
+ ["VDash"] = "โซ",
+ ["nvdash"] = "โฌ",
+ ["nvDash"] = "โญ",
+ ["nVdash"] = "โฎ",
+ ["nVDash"] = "โฏ",
+ ["prurel"] = "โฐ",
+ ["scurel"] = "โฑ",
+ ["vartriangleleft"] = "โฒ",
+ ["vartriangleright"] = "โณ",
+ ["trianglelefteq"] = "โด",
+ ["trianglerighteq"] = "โต",
+ ["origof"] = "โถ",
+ ["imageof"] = "โท",
+ ["multimap"] = "โธ",
+ ["hermitmatrix"] = "โน",
+ ["intercal"] = "โบ",
+ ["veebar"] = "โป",
+ ["barwedge"] = "โผ",
+ ["barvee"] = "โฝ",
+ ["measuredrightangle"] = "โพ",
+ ["varlrtriangle"] = "โฟ",
+ ["bigwedge"] = "โ",
+ ["bigvee"] = "โ",
+ ["bigcap"] = "โ",
+ ["bigcup"] = "โ",
+ ["smwhtdiamond"] = "โ",
+ ["cdot"] = "โ
",
+ ["star"] = "โ",
+ ["divideontimes"] = "โ",
+ ["bowtie"] = "โ",
+ ["ltimes"] = "โ",
+ ["rtimes"] = "โ",
+ ["leftthreetimes"] = "โ",
+ ["rightthreetimes"] = "โ",
+ ["backsimeq"] = "โ",
+ ["curlyvee"] = "โ",
+ ["curlywedge"] = "โ",
+ ["Subset"] = "โ",
+ ["Supset"] = "โ",
+ ["Cap"] = "โ",
+ ["Cup"] = "โ",
+ ["pitchfork"] = "โ",
+ ["equalparallel"] = "โ",
+ ["lessdot"] = "โ",
+ ["gtrdot"] = "โ",
+ ["lll"] = "โ",
+ ["ggg"] = "โ",
+ ["lesseqgtr"] = "โ",
+ ["gtreqless"] = "โ",
+ ["eqless"] = "โ",
+ ["eqgtr"] = "โ",
+ ["curlyeqprec"] = "โ",
+ ["curlyeqsucc"] = "โ",
+ ["npreccurlyeq"] = "โ ",
+ ["nsucccurlyeq"] = "โก",
+ ["nsqsubseteq"] = "โข",
+ ["nsqsupseteq"] = "โฃ",
+ ["sqsubsetneq"] = "โค",
+ ["sqsupsetneq"] = "โฅ",
+ ["lnsim"] = "โฆ",
+ ["gnsim"] = "โง",
+ ["precnsim"] = "โจ",
+ ["succnsim"] = "โฉ",
+ ["nvartriangleleft"] = "โช",
+ ["nvartriangleright"] = "โซ",
+ ["ntrianglelefteq"] = "โฌ",
+ ["ntrianglerighteq"] = "โญ",
+ ["vdots"] = "โฎ",
+ ["unicodecdots"] = "โฏ",
+ ["adots"] = "โฐ",
+ ["ddots"] = "โฑ",
+ ["disin"] = "โฒ",
+ ["varisins"] = "โณ",
+ ["isins"] = "โด",
+ ["isindot"] = "โต",
+ ["varisinobar"] = "โถ",
+ ["isinobar"] = "โท",
+ ["isinvb"] = "โธ",
+ ["isinE"] = "โน",
+ ["nisd"] = "โบ",
+ ["varnis"] = "โป",
+ ["nis"] = "โผ",
+ ["varniobar"] = "โฝ",
+ ["niobar"] = "โพ",
+ ["bagmember"] = "โฟ",
+ ["diameter"] = "โ",
+ ["house"] = "โ",
+ ["varbarwedge"] = "โ
",
+ ["vardoublebarwedge"] = "โ",
+ ["lceil"] = "โ",
+ ["rceil"] = "โ",
+ ["lfloor"] = "โ",
+ ["rfloor"] = "โ",
+ ["invnot"] = "โ",
+ ["sqlozenge"] = "โ",
+ ["profline"] = "โ",
+ ["profsurf"] = "โ",
+ ["viewdata"] = "โ",
+ ["turnednot"] = "โ",
+ ["ulcorner"] = "โ",
+ ["urcorner"] = "โ",
+ ["llcorner"] = "โ",
+ ["lrcorner"] = "โ",
+ ["inttop"] = "โ ",
+ ["intbottom"] = "โก",
+ ["frown"] = "โข",
+ ["smile"] = "โฃ",
+ ["varhexagonlrbonds"] = "โฌ",
+ ["conictaper"] = "โฒ",
+ ["topbot"] = "โถ",
+ ["obar"] = "โฝ",
+ ["APLnotslash"] = "โฟ",
+ ["APLnotbackslash"] = "โ",
+ ["APLboxupcaret"] = "โ",
+ ["APLboxquestion"] = "โฐ",
+ ["rangledownzigzagarrow"] = "โผ",
+ ["hexagon"] = "โ",
+ ["lparenuend"] = "โ",
+ ["lparenextender"] = "โ",
+ ["lparenlend"] = "โ",
+ ["rparenuend"] = "โ",
+ ["rparenextender"] = "โ",
+ ["rparenlend"] = "โ ",
+ ["lbrackuend"] = "โก",
+ ["lbrackextender"] = "โข",
+ ["lbracklend"] = "โฃ",
+ ["rbrackuend"] = "โค",
+ ["rbrackextender"] = "โฅ",
+ ["rbracklend"] = "โฆ",
+ ["lbraceuend"] = "โง",
+ ["lbracemid"] = "โจ",
+ ["lbracelend"] = "โฉ",
+ ["vbraceextender"] = "โช",
+ ["rbraceuend"] = "โซ",
+ ["rbracemid"] = "โฌ",
+ ["rbracelend"] = "โญ",
+ ["intextender"] = "โฎ",
+ ["harrowextender"] = "โฏ",
+ ["lmoustache"] = "โฐ",
+ ["rmoustache"] = "โฑ",
+ ["sumtop"] = "โฒ",
+ ["sumbottom"] = "โณ",
+ ["overbracket"] = "โด",
+ ["underbracket"] = "โต",
+ ["bbrktbrk"] = "โถ",
+ ["sqrtbottom"] = "โท",
+ ["lvboxline"] = "โธ",
+ ["rvboxline"] = "โน",
+ ["varcarriagereturn"] = "โ",
+ ["overparen"] = "โ",
+ ["underparen"] = "โ",
+ ["overbrace"] = "โ",
+ ["underbrace"] = "โ",
+ ["obrbrak"] = "โ ",
+ ["ubrbrak"] = "โก",
+ ["trapezium"] = "โข",
+ ["benzenr"] = "โฃ",
+ ["strns"] = "โค",
+ ["fltns"] = "โฅ",
+ ["accurrent"] = "โฆ",
+ ["elinters"] = "โง",
+ ["blanksymbol"] = "โข",
+ ["mathvisiblespace"] = "โฃ",
+ ["bdtriplevdash"] = "โ",
+ ["blockuphalf"] = "โ",
+ ["blocklowhalf"] = "โ",
+ ["blockfull"] = "โ",
+ ["blocklefthalf"] = "โ",
+ ["blockrighthalf"] = "โ",
+ ["blockqtrshaded"] = "โ",
+ ["blockhalfshaded"] = "โ",
+ ["blockthreeqtrshaded"] = "โ",
+ ["mdlgblksquare"] = "โ ",
+ ["mdlgwhtsquare"] = "โก",
+ ["squoval"] = "โข",
+ ["blackinwhitesquare"] = "โฃ",
+ ["squarehfill"] = "โค",
+ ["squarevfill"] = "โฅ",
+ ["squarehvfill"] = "โฆ",
+ ["squarenwsefill"] = "โง",
+ ["squareneswfill"] = "โจ",
+ ["squarecrossfill"] = "โฉ",
+ ["smblksquare"] = "โช",
+ ["smwhtsquare"] = "โซ",
+ ["hrectangleblack"] = "โฌ",
+ ["hrectangle"] = "โญ",
+ ["vrectangleblack"] = "โฎ",
+ ["vrectangle"] = "โฏ",
+ ["parallelogramblack"] = "โฐ",
+ ["parallelogram"] = "โฑ",
+ ["bigblacktriangleup"] = "โฒ",
+ ["bigtriangleup"] = "โณ",
+ ["blacktriangle"] = "โด",
+ ["vartriangle"] = "โต",
+ ["blacktriangleright"] = "โถ",
+ ["triangleright"] = "โท",
+ ["smallblacktriangleright"] = "โธ",
+ ["smalltriangleright"] = "โน",
+ ["blackpointerright"] = "โบ",
+ ["whitepointerright"] = "โป",
+ ["bigblacktriangledown"] = "โผ",
+ ["bigtriangledown"] = "โฝ",
+ ["blacktriangledown"] = "โพ",
+ ["triangledown"] = "โฟ",
+ ["blacktriangleleft"] = "โ",
+ ["triangleleft"] = "โ",
+ ["smallblacktriangleleft"] = "โ",
+ ["smalltriangleleft"] = "โ",
+ ["blackpointerleft"] = "โ",
+ ["whitepointerleft"] = "โ
",
+ ["mdlgblkdiamond"] = "โ",
+ ["mdlgwhtdiamond"] = "โ",
+ ["blackinwhitediamond"] = "โ",
+ ["fisheye"] = "โ",
+ ["mdlgwhtlozenge"] = "โ",
+ ["mdlgwhtcircle"] = "โ",
+ ["dottedcircle"] = "โ",
+ ["circlevertfill"] = "โ",
+ ["bullseye"] = "โ",
+ ["mdlgblkcircle"] = "โ",
+ ["circlelefthalfblack"] = "โ",
+ ["circlerighthalfblack"] = "โ",
+ ["circlebottomhalfblack"] = "โ",
+ ["circletophalfblack"] = "โ",
+ ["circleurquadblack"] = "โ",
+ ["blackcircleulquadwhite"] = "โ",
+ ["blacklefthalfcircle"] = "โ",
+ ["blackrighthalfcircle"] = "โ",
+ ["inversebullet"] = "โ",
+ ["inversewhitecircle"] = "โ",
+ ["invwhiteupperhalfcircle"] = "โ",
+ ["invwhitelowerhalfcircle"] = "โ",
+ ["ularc"] = "โ",
+ ["urarc"] = "โ",
+ ["lrarc"] = "โ",
+ ["llarc"] = "โ",
+ ["topsemicircle"] = "โ ",
+ ["botsemicircle"] = "โก",
+ ["lrblacktriangle"] = "โข",
+ ["llblacktriangle"] = "โฃ",
+ ["ulblacktriangle"] = "โค",
+ ["urblacktriangle"] = "โฅ",
+ ["smwhtcircle"] = "โฆ",
+ ["squareleftblack"] = "โง",
+ ["squarerightblack"] = "โจ",
+ ["squareulblack"] = "โฉ",
+ ["squarelrblack"] = "โช",
+ ["boxbar"] = "โซ",
+ ["trianglecdot"] = "โฌ",
+ ["triangleleftblack"] = "โญ",
+ ["trianglerightblack"] = "โฎ",
+ ["lgwhtcircle"] = "โฏ",
+ ["squareulquad"] = "โฐ",
+ ["squarellquad"] = "โฑ",
+ ["squarelrquad"] = "โฒ",
+ ["squareurquad"] = "โณ",
+ ["circleulquad"] = "โด",
+ ["circlellquad"] = "โต",
+ ["circlelrquad"] = "โถ",
+ ["circleurquad"] = "โท",
+ ["ultriangle"] = "โธ",
+ ["urtriangle"] = "โน",
+ ["lltriangle"] = "โบ",
+ ["mdwhtsquare"] = "โป",
+ ["mdblksquare"] = "โผ",
+ ["mdsmwhtsquare"] = "โฝ",
+ ["mdsmblksquare"] = "โพ",
+ ["lrtriangle"] = "โฟ",
+ ["bigstar"] = "โ
",
+ ["bigwhitestar"] = "โ",
+ ["astrosun"] = "โ",
+ ["danger"] = "โก",
+ ["blacksmiley"] = "โป",
+ ["sun"] = "โผ",
+ ["rightmoon"] = "โฝ",
+ ["leftmoon"] = "โพ",
+ ["female"] = "โ",
+ ["male"] = "โ",
+ ["spadesuit"] = "โ ",
+ ["heartsuit"] = "โก",
+ ["diamondsuit"] = "โข",
+ ["clubsuit"] = "โฃ",
+ ["varspadesuit"] = "โค",
+ ["varheartsuit"] = "โฅ",
+ ["vardiamondsuit"] = "โฆ",
+ ["varclubsuit"] = "โง",
+ ["quarternote"] = "โฉ",
+ ["eighthnote"] = "โช",
+ ["twonotes"] = "โซ",
+ ["flat"] = "โญ",
+ ["natural"] = "โฎ",
+ ["sharp"] = "โฏ",
+ ["acidfree"] = "โพ",
+ ["dicei"] = "โ",
+ ["diceii"] = "โ",
+ ["diceiii"] = "โ",
+ ["diceiv"] = "โ",
+ ["dicev"] = "โ",
+ ["dicevi"] = "โ
",
+ ["circledrightdot"] = "โ",
+ ["circledtwodots"] = "โ",
+ ["blackcircledrightdot"] = "โ",
+ ["blackcircledtwodots"] = "โ",
+ ["Hermaphrodite"] = "โฅ",
+ ["mdwhtcircle"] = "โช",
+ ["mdblkcircle"] = "โซ",
+ ["mdsmwhtcircle"] = "โฌ",
+ ["neuter"] = "โฒ",
+ ["circledstar"] = "โช",
+ ["varstar"] = "โถ",
+ ["dingasterisk"] = "โฝ",
+ ["lbrbrak"] = "โฒ",
+ ["rbrbrak"] = "โณ",
+ ["draftingarrow"] = "โ",
+ ["threedangle"] = "โ",
+ ["whiteinwhitetriangle"] = "โ",
+ ["perp"] = "โ",
+ ["subsetcirc"] = "โ",
+ ["supsetcirc"] = "โ",
+ ["lbag"] = "โ
",
+ ["rbag"] = "โ",
+ ["veedot"] = "โ",
+ ["bsolhsub"] = "โ",
+ ["suphsol"] = "โ",
+ ["diagup"] = "โ",
+ ["longdivision"] = "โ",
+ ["diagdown"] = "โ",
+ ["diamondcdot"] = "โ",
+ ["wedgedot"] = "โ",
+ ["upin"] = "โ",
+ ["pullback"] = "โ",
+ ["pushout"] = "โ",
+ ["leftouterjoin"] = "โ",
+ ["rightouterjoin"] = "โ",
+ ["fullouterjoin"] = "โ",
+ ["bigbot"] = "โ",
+ ["bigtop"] = "โ",
+ ["DashVDash"] = "โ",
+ ["dashVdash"] = "โ",
+ ["multimapinv"] = "โ",
+ ["vlongdash"] = "โ",
+ ["longdashv"] = "โ",
+ ["cirbot"] = "โ",
+ ["lozengeminus"] = "โ ",
+ ["concavediamond"] = "โก",
+ ["concavediamondtickleft"] = "โข",
+ ["concavediamondtickright"] = "โฃ",
+ ["whitesquaretickleft"] = "โค",
+ ["whitesquaretickright"] = "โฅ",
+ ["lBrack"] = "โฆ",
+ ["rBrack"] = "โง",
+ ["langle"] = "โจ",
+ ["rangle"] = "โฉ",
+ ["lAngle"] = "โช",
+ ["rAngle"] = "โซ",
+ ["Lbrbrak"] = "โฌ",
+ ["Rbrbrak"] = "โญ",
+ ["lgroup"] = "โฎ",
+ ["rgroup"] = "โฏ",
+ ["UUparrow"] = "โฐ",
+ ["DDownarrow"] = "โฑ",
+ ["acwgapcirclearrow"] = "โฒ",
+ ["cwgapcirclearrow"] = "โณ",
+ ["rightarrowonoplus"] = "โด",
+ ["longleftarrow"] = "โต",
+ ["longrightarrow"] = "โถ",
+ ["longleftrightarrow"] = "โท",
+ ["Longleftarrow"] = "โ=",
+ ["Longrightarrow"] = "=โ",
+ ["Longleftrightarrow"] = "โโ",
+ ["longmapsfrom"] = "โป",
+ ["longmapsto"] = "โผ",
+ ["Longmapsfrom"] = "โฝ",
+ ["Longmapsto"] = "โพ",
+ ["longrightsquigarrow"] = "โฟ",
+ ["nvtwoheadrightarrow"] = "โค",
+ ["nVtwoheadrightarrow"] = "โค",
+ ["nvLeftarrow"] = "โค",
+ ["nvRightarrow"] = "โค",
+ ["nvLeftrightarrow"] = "โค",
+ ["twoheadmapsto"] = "โค
",
+ ["Mapsfrom"] = "โค",
+ ["Mapsto"] = "โค",
+ ["downarrowbarred"] = "โค",
+ ["uparrowbarred"] = "โค",
+ ["Uuparrow"] = "โค",
+ ["Ddownarrow"] = "โค",
+ ["leftbkarrow"] = "โค",
+ ["rightbkarrow"] = "โค",
+ ["leftdbkarrow"] = "โค",
+ ["dbkarrow"] = "โค",
+ ["drbkarrow"] = "โค",
+ ["rightdotarrow"] = "โค",
+ ["baruparrow"] = "โค",
+ ["downarrowbar"] = "โค",
+ ["nvrightarrowtail"] = "โค",
+ ["nVrightarrowtail"] = "โค",
+ ["twoheadrightarrowtail"] = "โค",
+ ["nvtwoheadrightarrowtail"] = "โค",
+ ["nVtwoheadrightarrowtail"] = "โค",
+ ["lefttail"] = "โค",
+ ["righttail"] = "โค",
+ ["leftdbltail"] = "โค",
+ ["rightdbltail"] = "โค",
+ ["diamondleftarrow"] = "โค",
+ ["rightarrowdiamond"] = "โค",
+ ["diamondleftarrowbar"] = "โค",
+ ["barrightarrowdiamond"] = "โค ",
+ ["nwsearrow"] = "โคก",
+ ["neswarrow"] = "โคข",
+ ["hknwarrow"] = "โคฃ",
+ ["hknearrow"] = "โคค",
+ ["hksearrow"] = "โคฅ",
+ ["hkswarrow"] = "โคฆ",
+ ["tona"] = "โคง",
+ ["toea"] = "โคจ",
+ ["tosa"] = "โคฉ",
+ ["towa"] = "โคช",
+ ["rdiagovfdiag"] = "โคซ",
+ ["fdiagovrdiag"] = "โคฌ",
+ ["seovnearrow"] = "โคญ",
+ ["neovsearrow"] = "โคฎ",
+ ["fdiagovnearrow"] = "โคฏ",
+ ["rdiagovsearrow"] = "โคฐ",
+ ["neovnwarrow"] = "โคฑ",
+ ["nwovnearrow"] = "โคฒ",
+ ["rightcurvedarrow"] = "โคณ",
+ ["uprightcurvearrow"] = "โคด",
+ ["downrightcurvedarrow"] = "โคต",
+ ["leftdowncurvedarrow"] = "โคถ",
+ ["rightdowncurvedarrow"] = "โคท",
+ ["cwrightarcarrow"] = "โคธ",
+ ["acwleftarcarrow"] = "โคน",
+ ["acwoverarcarrow"] = "โคบ",
+ ["acwunderarcarrow"] = "โคป",
+ ["curvearrowrightminus"] = "โคผ",
+ ["curvearrowleftplus"] = "โคฝ",
+ ["cwundercurvearrow"] = "โคพ",
+ ["ccwundercurvearrow"] = "โคฟ",
+ ["acwcirclearrow"] = "โฅ",
+ ["cwcirclearrow"] = "โฅ",
+ ["rightarrowshortleftarrow"] = "โฅ",
+ ["leftarrowshortrightarrow"] = "โฅ",
+ ["shortrightarrowleftarrow"] = "โฅ",
+ ["rightarrowplus"] = "โฅ
",
+ ["leftarrowplus"] = "โฅ",
+ ["rightarrowx"] = "โฅ",
+ ["leftrightarrowcircle"] = "โฅ",
+ ["twoheaduparrowcircle"] = "โฅ",
+ ["leftrightharpoonupdown"] = "โฅ",
+ ["leftrightharpoondownup"] = "โฅ",
+ ["updownharpoonrightleft"] = "โฅ",
+ ["updownharpoonleftright"] = "โฅ",
+ ["leftrightharpoonupup"] = "โฅ",
+ ["updownharpoonrightright"] = "โฅ",
+ ["leftrightharpoondowndown"] = "โฅ",
+ ["updownharpoonleftleft"] = "โฅ",
+ ["barleftharpoonup"] = "โฅ",
+ ["rightharpoonupbar"] = "โฅ",
+ ["barupharpoonright"] = "โฅ",
+ ["downharpoonrightbar"] = "โฅ",
+ ["barleftharpoondown"] = "โฅ",
+ ["rightharpoondownbar"] = "โฅ",
+ ["barupharpoonleft"] = "โฅ",
+ ["downharpoonleftbar"] = "โฅ",
+ ["leftharpoonupbar"] = "โฅ",
+ ["barrightharpoonup"] = "โฅ",
+ ["upharpoonrightbar"] = "โฅ",
+ ["bardownharpoonright"] = "โฅ",
+ ["leftharpoondownbar"] = "โฅ",
+ ["barrightharpoondown"] = "โฅ",
+ ["upharpoonleftbar"] = "โฅ ",
+ ["bardownharpoonleft"] = "โฅก",
+ ["leftharpoonsupdown"] = "โฅข",
+ ["upharpoonsleftright"] = "โฅฃ",
+ ["rightharpoonsupdown"] = "โฅค",
+ ["downharpoonsleftright"] = "โฅฅ",
+ ["leftrightharpoonsup"] = "โฅฆ",
+ ["leftrightharpoonsdown"] = "โฅง",
+ ["rightleftharpoonsup"] = "โฅจ",
+ ["rightleftharpoonsdown"] = "โฅฉ",
+ ["leftharpoonupdash"] = "โฅช",
+ ["dashleftharpoondown"] = "โฅซ",
+ ["rightharpoonupdash"] = "โฅฌ",
+ ["dashrightharpoondown"] = "โฅญ",
+ ["updownharpoonsleftright"] = "โฅฎ",
+ ["downupharpoonsleftright"] = "โฅฏ",
+ ["rightimply"] = "โฅฐ",
+ ["equalrightarrow"] = "โฅฑ",
+ ["similarrightarrow"] = "โฅฒ",
+ ["leftarrowsimilar"] = "โฅณ",
+ ["rightarrowsimilar"] = "โฅด",
+ ["rightarrowapprox"] = "โฅต",
+ ["ltlarr"] = "โฅถ",
+ ["leftarrowless"] = "โฅท",
+ ["gtrarr"] = "โฅธ",
+ ["subrarr"] = "โฅน",
+ ["leftarrowsubset"] = "โฅบ",
+ ["suplarr"] = "โฅป",
+ ["leftfishtail"] = "โฅผ",
+ ["rightfishtail"] = "โฅฝ",
+ ["upfishtail"] = "โฅพ",
+ ["downfishtail"] = "โฅฟ",
+ ["Vvert"] = "โฆ",
+ ["mdsmblkcircle"] = "โฆ",
+ ["typecolon"] = "โฆ",
+ ["lBrace"] = "โฆ",
+ ["rBrace"] = "โฆ",
+ ["lParen"] = "โฆ
",
+ ["rParen"] = "โฆ",
+ ["llparenthesis"] = "โฆ",
+ ["rrparenthesis"] = "โฆ",
+ ["llangle"] = "โฆ",
+ ["rrangle"] = "โฆ",
+ ["lbrackubar"] = "โฆ",
+ ["rbrackubar"] = "โฆ",
+ ["lbrackultick"] = "โฆ",
+ ["rbracklrtick"] = "โฆ",
+ ["lbracklltick"] = "โฆ",
+ ["rbrackurtick"] = "โฆ",
+ ["langledot"] = "โฆ",
+ ["rangledot"] = "โฆ",
+ ["lparenless"] = "โฆ",
+ ["rparengtr"] = "โฆ",
+ ["Lparengtr"] = "โฆ",
+ ["Rparenless"] = "โฆ",
+ ["lblkbrbrak"] = "โฆ",
+ ["rblkbrbrak"] = "โฆ",
+ ["fourvdots"] = "โฆ",
+ ["vzigzag"] = "โฆ",
+ ["measuredangleleft"] = "โฆ",
+ ["rightanglesqr"] = "โฆ",
+ ["rightanglemdot"] = "โฆ",
+ ["angles"] = "โฆ",
+ ["angdnr"] = "โฆ",
+ ["gtlpar"] = "โฆ ",
+ ["sphericalangleup"] = "โฆก",
+ ["turnangle"] = "โฆข",
+ ["revangle"] = "โฆฃ",
+ ["angleubar"] = "โฆค",
+ ["revangleubar"] = "โฆฅ",
+ ["wideangledown"] = "โฆฆ",
+ ["wideangleup"] = "โฆง",
+ ["measanglerutone"] = "โฆจ",
+ ["measanglelutonw"] = "โฆฉ",
+ ["measanglerdtose"] = "โฆช",
+ ["measangleldtosw"] = "โฆซ",
+ ["measangleurtone"] = "โฆฌ",
+ ["measangleultonw"] = "โฆญ",
+ ["measangledrtose"] = "โฆฎ",
+ ["measangledltosw"] = "โฆฏ",
+ ["revemptyset"] = "โฆฐ",
+ ["emptysetobar"] = "โฆฑ",
+ ["emptysetocirc"] = "โฆฒ",
+ ["emptysetoarr"] = "โฆณ",
+ ["emptysetoarrl"] = "โฆด",
+ ["circlehbar"] = "โฆต",
+ ["circledvert"] = "โฆถ",
+ ["circledparallel"] = "โฆท",
+ ["obslash"] = "โฆธ",
+ ["operp"] = "โฆน",
+ ["obot"] = "โฆบ",
+ ["olcross"] = "โฆป",
+ ["odotslashdot"] = "โฆผ",
+ ["uparrowoncircle"] = "โฆฝ",
+ ["circledwhitebullet"] = "โฆพ",
+ ["circledbullet"] = "โฆฟ",
+ ["olessthan"] = "โง",
+ ["ogreaterthan"] = "โง",
+ ["cirscir"] = "โง",
+ ["cirE"] = "โง",
+ ["boxdiag"] = "โง",
+ ["boxbslash"] = "โง
",
+ ["boxast"] = "โง",
+ ["boxcircle"] = "โง",
+ ["boxbox"] = "โง",
+ ["boxonbox"] = "โง",
+ ["triangleodot"] = "โง",
+ ["triangleubar"] = "โง",
+ ["triangles"] = "โง",
+ ["triangleserifs"] = "โง",
+ ["rtriltri"] = "โง",
+ ["ltrivb"] = "โง",
+ ["vbrtri"] = "โง",
+ ["lfbowtie"] = "โง",
+ ["rfbowtie"] = "โง",
+ ["fbowtie"] = "โง",
+ ["lftimes"] = "โง",
+ ["rftimes"] = "โง",
+ ["hourglass"] = "โง",
+ ["blackhourglass"] = "โง",
+ ["lvzigzag"] = "โง",
+ ["rvzigzag"] = "โง",
+ ["Lvzigzag"] = "โง",
+ ["Rvzigzag"] = "โง",
+ ["iinfin"] = "โง",
+ ["tieinfty"] = "โง",
+ ["nvinfty"] = "โง",
+ ["dualmap"] = "โง",
+ ["laplac"] = "โง ",
+ ["lrtriangleeq"] = "โงก",
+ ["shuffle"] = "โงข",
+ ["eparsl"] = "โงฃ",
+ ["smeparsl"] = "โงค",
+ ["eqvparsl"] = "โงฅ",
+ ["gleichstark"] = "โงฆ",
+ ["thermod"] = "โงง",
+ ["downtriangleleftblack"] = "โงจ",
+ ["downtrianglerightblack"] = "โงฉ",
+ ["blackdiamonddownarrow"] = "โงช",
+ ["mdlgblklozenge"] = "โงซ",
+ ["circledownarrow"] = "โงฌ",
+ ["blackcircledownarrow"] = "โงญ",
+ ["errbarsquare"] = "โงฎ",
+ ["errbarblacksquare"] = "โงฏ",
+ ["errbardiamond"] = "โงฐ",
+ ["errbarblackdiamond"] = "โงฑ",
+ ["errbarcircle"] = "โงฒ",
+ ["errbarblackcircle"] = "โงณ",
+ ["ruledelayed"] = "โงด",
+ ["reversesolidus"] = "โงต",
+ ["dsol"] = "โงถ",
+ ["rsolbar"] = "โงท",
+ ["xsol"] = "โงธ",
+ ["xbsol"] = "โงน",
+ ["doubleplus"] = "โงบ",
+ ["tripleplus"] = "โงป",
+ ["lcurvyangle"] = "โงผ",
+ ["rcurvyangle"] = "โงฝ",
+ ["tplus"] = "โงพ",
+ ["tminus"] = "โงฟ",
+ ["bigodot"] = "โจ",
+ ["bigoplus"] = "โจ",
+ ["bigotimes"] = "โจ",
+ ["bigcupdot"] = "โจ",
+ ["biguplus"] = "โจ",
+ ["bigsqcap"] = "โจ
",
+ ["bigsqcup"] = "โจ",
+ ["conjquant"] = "โจ",
+ ["disjquant"] = "โจ",
+ ["bigtimes"] = "โจ",
+ ["modtwosum"] = "โจ",
+ ["sumint"] = "โจ",
+ ["iiiint"] = "โจ",
+ ["intbar"] = "โจ",
+ ["intBar"] = "โจ",
+ ["fint"] = "โจ",
+ ["cirfnint"] = "โจ",
+ ["awint"] = "โจ",
+ ["rppolint"] = "โจ",
+ ["scpolint"] = "โจ",
+ ["npolint"] = "โจ",
+ ["pointint"] = "โจ",
+ ["sqint"] = "โจ",
+ ["intlarhk"] = "โจ",
+ ["intx"] = "โจ",
+ ["intcap"] = "โจ",
+ ["intcup"] = "โจ",
+ ["upint"] = "โจ",
+ ["lowint"] = "โจ",
+ ["Join"] = "โจ",
+ ["bigtriangleleft"] = "โจ",
+ ["zcmp"] = "โจ",
+ ["zpipe"] = "โจ ",
+ ["zproject"] = "โจก",
+ ["ringplus"] = "โจข",
+ ["plushat"] = "โจฃ",
+ ["simplus"] = "โจค",
+ ["plusdot"] = "โจฅ",
+ ["plussim"] = "โจฆ",
+ ["plussubtwo"] = "โจง",
+ ["plustrif"] = "โจจ",
+ ["commaminus"] = "โจฉ",
+ ["minusdot"] = "โจช",
+ ["minusfdots"] = "โจซ",
+ ["minusrdots"] = "โจฌ",
+ ["opluslhrim"] = "โจญ",
+ ["oplusrhrim"] = "โจฎ",
+ ["vectimes"] = "โจฏ",
+ ["dottimes"] = "โจฐ",
+ ["timesbar"] = "โจฑ",
+ ["btimes"] = "โจฒ",
+ ["smashtimes"] = "โจณ",
+ ["otimeslhrim"] = "โจด",
+ ["otimesrhrim"] = "โจต",
+ ["otimeshat"] = "โจถ",
+ ["Otimes"] = "โจท",
+ ["odiv"] = "โจธ",
+ ["triangleplus"] = "โจน",
+ ["triangleminus"] = "โจบ",
+ ["triangletimes"] = "โจป",
+ ["intprod"] = "โจผ",
+ ["intprodr"] = "โจฝ",
+ ["fcmp"] = "โจพ",
+ ["amalg"] = "โจฟ",
+ ["capdot"] = "โฉ",
+ ["uminus"] = "โฉ",
+ ["barcup"] = "โฉ",
+ ["barcap"] = "โฉ",
+ ["capwedge"] = "โฉ",
+ ["cupvee"] = "โฉ
",
+ ["cupovercap"] = "โฉ",
+ ["capovercup"] = "โฉ",
+ ["cupbarcap"] = "โฉ",
+ ["capbarcup"] = "โฉ",
+ ["twocups"] = "โฉ",
+ ["twocaps"] = "โฉ",
+ ["closedvarcup"] = "โฉ",
+ ["closedvarcap"] = "โฉ",
+ ["Sqcap"] = "โฉ",
+ ["Sqcup"] = "โฉ",
+ ["closedvarcupsmashprod"] = "โฉ",
+ ["wedgeodot"] = "โฉ",
+ ["veeodot"] = "โฉ",
+ ["Wedge"] = "โฉ",
+ ["Vee"] = "โฉ",
+ ["wedgeonwedge"] = "โฉ",
+ ["veeonvee"] = "โฉ",
+ ["bigslopedvee"] = "โฉ",
+ ["bigslopedwedge"] = "โฉ",
+ ["veeonwedge"] = "โฉ",
+ ["wedgemidvert"] = "โฉ",
+ ["veemidvert"] = "โฉ",
+ ["midbarwedge"] = "โฉ",
+ ["midbarvee"] = "โฉ",
+ ["doublebarwedge"] = "โฉ",
+ ["wedgebar"] = "โฉ",
+ ["wedgedoublebar"] = "โฉ ",
+ ["varveebar"] = "โฉก",
+ ["doublebarvee"] = "โฉข",
+ ["veedoublebar"] = "โฉฃ",
+ ["dsub"] = "โฉค",
+ ["rsub"] = "โฉฅ",
+ ["eqdot"] = "โฉฆ",
+ ["dotequiv"] = "โฉง",
+ ["equivVert"] = "โฉจ",
+ ["equivVvert"] = "โฉฉ",
+ ["dotsim"] = "โฉช",
+ ["simrdots"] = "โฉซ",
+ ["simminussim"] = "โฉฌ",
+ ["congdot"] = "โฉญ",
+ ["asteq"] = "โฉฎ",
+ ["hatapprox"] = "โฉฏ",
+ ["approxeqq"] = "โฉฐ",
+ ["eqqplus"] = "โฉฑ",
+ ["pluseqq"] = "โฉฒ",
+ ["eqqsim"] = "โฉณ",
+ ["Coloneq"] = "โฉด",
+ ["eqeq"] = "โฉต",
+ ["eqeqeq"] = "โฉถ",
+ ["ddotseq"] = "โฉท",
+ ["equivDD"] = "โฉธ",
+ ["ltcir"] = "โฉน",
+ ["gtcir"] = "โฉบ",
+ ["ltquest"] = "โฉป",
+ ["gtquest"] = "โฉผ",
+ ["leqslant"] = "โฉฝ",
+ ["geqslant"] = "โฉพ",
+ ["lesdot"] = "โฉฟ",
+ ["gesdot"] = "โช",
+ ["lesdoto"] = "โช",
+ ["gesdoto"] = "โช",
+ ["lesdotor"] = "โช",
+ ["gesdotol"] = "โช",
+ ["lessapprox"] = "โช
",
+ ["gtrapprox"] = "โช",
+ ["lneq"] = "โช",
+ ["gneq"] = "โช",
+ ["lnapprox"] = "โช",
+ ["gnapprox"] = "โช",
+ ["lesseqqgtr"] = "โช",
+ ["gtreqqless"] = "โช",
+ ["lsime"] = "โช",
+ ["gsime"] = "โช",
+ ["lsimg"] = "โช",
+ ["gsiml"] = "โช",
+ ["lgE"] = "โช",
+ ["glE"] = "โช",
+ ["lesges"] = "โช",
+ ["gesles"] = "โช",
+ ["eqslantless"] = "โช",
+ ["eqslantgtr"] = "โช",
+ ["elsdot"] = "โช",
+ ["egsdot"] = "โช",
+ ["eqqless"] = "โช",
+ ["eqqgtr"] = "โช",
+ ["eqqslantless"] = "โช",
+ ["eqqslantgtr"] = "โช",
+ ["simless"] = "โช",
+ ["simgtr"] = "โช",
+ ["simlE"] = "โช",
+ ["simgE"] = "โช ",
+ ["Lt"] = "โชก",
+ ["Gt"] = "โชข",
+ ["partialmeetcontraction"] = "โชฃ",
+ ["glj"] = "โชค",
+ ["gla"] = "โชฅ",
+ ["ltcc"] = "โชฆ",
+ ["gtcc"] = "โชง",
+ ["lescc"] = "โชจ",
+ ["gescc"] = "โชฉ",
+ ["smt"] = "โชช",
+ ["lat"] = "โชซ",
+ ["smte"] = "โชฌ",
+ ["late"] = "โชญ",
+ ["bumpeqq"] = "โชฎ",
+ ["preceq"] = "โชฏ",
+ ["succeq"] = "โชฐ",
+ ["precneq"] = "โชฑ",
+ ["succneq"] = "โชฒ",
+ ["preceqq"] = "โชณ",
+ ["succeqq"] = "โชด",
+ ["precneqq"] = "โชต",
+ ["succneqq"] = "โชถ",
+ ["precapprox"] = "โชท",
+ ["succapprox"] = "โชธ",
+ ["precnapprox"] = "โชน",
+ ["succnapprox"] = "โชบ",
+ ["Prec"] = "โชป",
+ ["Succ"] = "โชผ",
+ ["subsetdot"] = "โชฝ",
+ ["supsetdot"] = "โชพ",
+ ["subsetplus"] = "โชฟ",
+ ["supsetplus"] = "โซ",
+ ["submult"] = "โซ",
+ ["supmult"] = "โซ",
+ ["subedot"] = "โซ",
+ ["supedot"] = "โซ",
+ ["subseteqq"] = "โซ
",
+ ["supseteqq"] = "โซ",
+ ["subsim"] = "โซ",
+ ["supsim"] = "โซ",
+ ["subsetapprox"] = "โซ",
+ ["supsetapprox"] = "โซ",
+ ["subsetneqq"] = "โซ",
+ ["supsetneqq"] = "โซ",
+ ["lsqhook"] = "โซ",
+ ["rsqhook"] = "โซ",
+ ["csub"] = "โซ",
+ ["csup"] = "โซ",
+ ["csube"] = "โซ",
+ ["csupe"] = "โซ",
+ ["subsup"] = "โซ",
+ ["supsub"] = "โซ",
+ ["subsub"] = "โซ",
+ ["supsup"] = "โซ",
+ ["suphsub"] = "โซ",
+ ["supdsub"] = "โซ",
+ ["forkv"] = "โซ",
+ ["topfork"] = "โซ",
+ ["mlcp"] = "โซ",
+ ["forks"] = "โซ",
+ ["forksnot"] = "โซ",
+ ["shortlefttack"] = "โซ",
+ ["shortdowntack"] = "โซ",
+ ["shortuptack"] = "โซ ",
+ ["perps"] = "โซก",
+ ["vDdash"] = "โซข",
+ ["dashV"] = "โซฃ",
+ ["Dashv"] = "โซค",
+ ["DashV"] = "โซฅ",
+ ["varVdash"] = "โซฆ",
+ ["Barv"] = "โซง",
+ ["vBar"] = "โซจ",
+ ["vBarv"] = "โซฉ",
+ ["barV"] = "โซช",
+ ["Vbar"] = "โซซ",
+ ["Not"] = "โซฌ",
+ ["bNot"] = "โซญ",
+ ["revnmid"] = "โซฎ",
+ ["cirmid"] = "โซฏ",
+ ["midcir"] = "โซฐ",
+ ["topcir"] = "โซฑ",
+ ["nhpar"] = "โซฒ",
+ ["parsim"] = "โซณ",
+ ["interleave"] = "โซด",
+ ["nhVvert"] = "โซต",
+ ["threedotcolon"] = "โซถ",
+ ["lllnest"] = "โซท",
+ ["gggnest"] = "โซธ",
+ ["leqqslant"] = "โซน",
+ ["geqqslant"] = "โซบ",
+ ["trslash"] = "โซป",
+ ["biginterleave"] = "โซผ",
+ ["sslash"] = "โซฝ",
+ ["talloblong"] = "โซพ",
+ ["bigtalloblong"] = "โซฟ",
+ ["squaretopblack"] = "โฌ",
+ ["squarebotblack"] = "โฌ",
+ ["squareurblack"] = "โฌ",
+ ["squarellblack"] = "โฌ",
+ ["diamondleftblack"] = "โฌ",
+ ["diamondrightblack"] = "โฌ",
+ ["diamondtopblack"] = "โฌ",
+ ["diamondbotblack"] = "โฌ",
+ ["dottedsquare"] = "โฌ",
+ ["lgblksquare"] = "โฌ",
+ ["lgwhtsquare"] = "โฌ",
+ ["vysmblksquare"] = "โฌ",
+ ["vysmwhtsquare"] = "โฌ",
+ ["pentagonblack"] = "โฌ",
+ ["pentagon"] = "โฌ ",
+ ["varhexagon"] = "โฌก",
+ ["varhexagonblack"] = "โฌข",
+ ["hexagonblack"] = "โฌฃ",
+ ["lgblkcircle"] = "โฌค",
+ ["mdblkdiamond"] = "โฌฅ",
+ ["mdwhtdiamond"] = "โฌฆ",
+ ["mdblklozenge"] = "โฌง",
+ ["mdwhtlozenge"] = "โฌจ",
+ ["smblkdiamond"] = "โฌฉ",
+ ["smblklozenge"] = "โฌช",
+ ["smwhtlozenge"] = "โฌซ",
+ ["blkhorzoval"] = "โฌฌ",
+ ["whthorzoval"] = "โฌญ",
+ ["blkvertoval"] = "โฌฎ",
+ ["whtvertoval"] = "โฌฏ",
+ ["circleonleftarrow"] = "โฌฐ",
+ ["leftthreearrows"] = "โฌฑ",
+ ["leftarrowonoplus"] = "โฌฒ",
+ ["longleftsquigarrow"] = "โฌณ",
+ ["nvtwoheadleftarrow"] = "โฌด",
+ ["nVtwoheadleftarrow"] = "โฌต",
+ ["twoheadmapsfrom"] = "โฌถ",
+ ["twoheadleftdbkarrow"] = "โฌท",
+ ["leftdotarrow"] = "โฌธ",
+ ["nvleftarrowtail"] = "โฌน",
+ ["nVleftarrowtail"] = "โฌบ",
+ ["twoheadleftarrowtail"] = "โฌป",
+ ["nvtwoheadleftarrowtail"] = "โฌผ",
+ ["nVtwoheadleftarrowtail"] = "โฌฝ",
+ ["leftarrowx"] = "โฌพ",
+ ["leftcurvedarrow"] = "โฌฟ",
+ ["equalleftarrow"] = "โญ",
+ ["bsimilarleftarrow"] = "โญ",
+ ["leftarrowbackapprox"] = "โญ",
+ ["rightarrowgtr"] = "โญ",
+ ["rightarrowsupset"] = "โญ",
+ ["LLeftarrow"] = "โญ
",
+ ["RRightarrow"] = "โญ",
+ ["bsimilarrightarrow"] = "โญ",
+ ["rightarrowbackapprox"] = "โญ",
+ ["similarleftarrow"] = "โญ",
+ ["leftarrowapprox"] = "โญ",
+ ["leftarrowbsimilar"] = "โญ",
+ ["rightarrowbsimilar"] = "โญ",
+ ["medwhitestar"] = "โญ",
+ ["medblackstar"] = "โญ",
+ ["smwhitestar"] = "โญ",
+ ["rightpentagonblack"] = "โญ",
+ ["rightpentagon"] = "โญ",
+ ["postalmark"] = "ใ",
+ ["hzigzag"] = "ใฐ",
+ ["imath"] = "๐ค",
+ ["jmath"] = "๐ฅ",
+ ["mbfAlpha"] = "๐จ",
+ ["mbfBeta"] = "๐ฉ",
+ ["mbfGamma"] = "๐ช",
+ ["mbfDelta"] = "๐ซ",
+ ["mbfEpsilon"] = "๐ฌ",
+ ["mbfZeta"] = "๐ญ",
+ ["mbfEta"] = "๐ฎ",
+ ["mbfTheta"] = "๐ฏ",
+ ["mbfIota"] = "๐ฐ",
+ ["mbfKappa"] = "๐ฑ",
+ ["mbfLambda"] = "๐ฒ",
+ ["mbfMu"] = "๐ณ",
+ ["mbfNu"] = "๐ด",
+ ["mbfXi"] = "๐ต",
+ ["mbfOmicron"] = "๐ถ",
+ ["mbfPi"] = "๐ท",
+ ["mbfRho"] = "๐ธ",
+ ["mbfvarTheta"] = "๐น",
+ ["mbfSigma"] = "๐บ",
+ ["mbfTau"] = "๐ป",
+ ["mbfUpsilon"] = "๐ผ",
+ ["mbfPhi"] = "๐ฝ",
+ ["mbfChi"] = "๐พ",
+ ["mbfPsi"] = "๐ฟ",
+ ["mbfOmega"] = "๐",
+ ["mbfnabla"] = "๐",
+ ["mbfalpha"] = "๐",
+ ["mbfbeta"] = "๐",
+ ["mbfgamma"] = "๐",
+ ["mbfdelta"] = "๐
",
+ ["mbfvarepsilon"] = "๐",
+ ["mbfzeta"] = "๐",
+ ["mbfeta"] = "๐",
+ ["mbftheta"] = "๐",
+ ["mbfiota"] = "๐",
+ ["mbfkappa"] = "๐",
+ ["mbflambda"] = "๐",
+ ["mbfmu"] = "๐",
+ ["mbfnu"] = "๐",
+ ["mbfxi"] = "๐",
+ ["mbfomicron"] = "๐",
+ ["mbfpi"] = "๐",
+ ["mbfrho"] = "๐",
+ ["mbfvarsigma"] = "๐",
+ ["mbfsigma"] = "๐",
+ ["mbftau"] = "๐",
+ ["mbfupsilon"] = "๐",
+ ["mbfvarphi"] = "๐",
+ ["mbfchi"] = "๐",
+ ["mbfpsi"] = "๐",
+ ["mbfomega"] = "๐",
+ ["mbfpartial"] = "๐",
+ ["mbfepsilon"] = "๐",
+ ["mbfvartheta"] = "๐",
+ ["mbfvarkappa"] = "๐",
+ ["mbfphi"] = "๐",
+ ["mbfvarrho"] = "๐ ",
+ ["mbfvarpi"] = "๐ก",
+ ["mitAlpha"] = "๐ข",
+ ["mitBeta"] = "๐ฃ",
+ ["mitGamma"] = "๐ค",
+ ["mitDelta"] = "๐ฅ",
+ ["mitEpsilon"] = "๐ฆ",
+ ["mitZeta"] = "๐ง",
+ ["mitEta"] = "๐จ",
+ ["mitTheta"] = "๐ฉ",
+ ["mitIota"] = "๐ช",
+ ["mitKappa"] = "๐ซ",
+ ["mitLambda"] = "๐ฌ",
+ ["mitMu"] = "๐ญ",
+ ["mitNu"] = "๐ฎ",
+ ["mitXi"] = "๐ฏ",
+ ["mitOmicron"] = "๐ฐ",
+ ["mitPi"] = "๐ฑ",
+ ["mitRho"] = "๐ฒ",
+ ["mitvarTheta"] = "๐ณ",
+ ["mitSigma"] = "๐ด",
+ ["mitTau"] = "๐ต",
+ ["mitUpsilon"] = "๐ถ",
+ ["mitPhi"] = "๐ท",
+ ["mitChi"] = "๐ธ",
+ ["mitPsi"] = "๐น",
+ ["mitOmega"] = "๐บ",
+ ["mitnabla"] = "๐ป",
+ ["mitalpha"] = "๐ผ",
+ ["mitbeta"] = "๐ฝ",
+ ["mitgamma"] = "๐พ",
+ ["mitdelta"] = "๐ฟ",
+ ["mitvarepsilon"] = "๐",
+ ["mitzeta"] = "๐",
+ ["miteta"] = "๐",
+ ["mittheta"] = "๐",
+ ["mitiota"] = "๐",
+ ["mitkappa"] = "๐
",
+ ["mitlambda"] = "๐",
+ ["mitmu"] = "๐",
+ ["mitnu"] = "๐",
+ ["mitxi"] = "๐",
+ ["mitomicron"] = "๐",
+ ["mitpi"] = "๐",
+ ["mitrho"] = "๐",
+ ["mitvarsigma"] = "๐",
+ ["mitsigma"] = "๐",
+ ["mittau"] = "๐",
+ ["mitupsilon"] = "๐",
+ ["mitvarphi"] = "๐",
+ ["mitchi"] = "๐",
+ ["mitpsi"] = "๐",
+ ["mitomega"] = "๐",
+ ["mitpartial"] = "๐",
+ ["mitepsilon"] = "๐",
+ ["mitvartheta"] = "๐",
+ ["mitvarkappa"] = "๐",
+ ["mitphi"] = "๐",
+ ["mitvarrho"] = "๐",
+ ["mitvarpi"] = "๐",
+ ["mbfitAlpha"] = "๐",
+ ["mbfitBeta"] = "๐",
+ ["mbfitGamma"] = "๐",
+ ["mbfitDelta"] = "๐",
+ ["mbfitEpsilon"] = "๐ ",
+ ["mbfitZeta"] = "๐ก",
+ ["mbfitEta"] = "๐ข",
+ ["mbfitTheta"] = "๐ฃ",
+ ["mbfitIota"] = "๐ค",
+ ["mbfitKappa"] = "๐ฅ",
+ ["mbfitLambda"] = "๐ฆ",
+ ["mbfitMu"] = "๐ง",
+ ["mbfitNu"] = "๐จ",
+ ["mbfitXi"] = "๐ฉ",
+ ["mbfitOmicron"] = "๐ช",
+ ["mbfitPi"] = "๐ซ",
+ ["mbfitRho"] = "๐ฌ",
+ ["mbfitvarTheta"] = "๐ญ",
+ ["mbfitSigma"] = "๐ฎ",
+ ["mbfitTau"] = "๐ฏ",
+ ["mbfitUpsilon"] = "๐ฐ",
+ ["mbfitPhi"] = "๐ฑ",
+ ["mbfitChi"] = "๐ฒ",
+ ["mbfitPsi"] = "๐ณ",
+ ["mbfitOmega"] = "๐ด",
+ ["mbfitnabla"] = "๐ต",
+ ["mbfitalpha"] = "๐ถ",
+ ["mbfitbeta"] = "๐ท",
+ ["mbfitgamma"] = "๐ธ",
+ ["mbfitdelta"] = "๐น",
+ ["mbfitvarepsilon"] = "๐บ",
+ ["mbfitzeta"] = "๐ป",
+ ["mbfiteta"] = "๐ผ",
+ ["mbfittheta"] = "๐ฝ",
+ ["mbfitiota"] = "๐พ",
+ ["mbfitkappa"] = "๐ฟ",
+ ["mbfitlambda"] = "๐",
+ ["mbfitmu"] = "๐",
+ ["mbfitnu"] = "๐",
+ ["mbfitxi"] = "๐",
+ ["mbfitomicron"] = "๐",
+ ["mbfitpi"] = "๐
",
+ ["mbfitrho"] = "๐",
+ ["mbfitvarsigma"] = "๐",
+ ["mbfitsigma"] = "๐",
+ ["mbfittau"] = "๐",
+ ["mbfitupsilon"] = "๐",
+ ["mbfitvarphi"] = "๐",
+ ["mbfitchi"] = "๐",
+ ["mbfitpsi"] = "๐",
+ ["mbfitomega"] = "๐",
+ ["mbfitpartial"] = "๐",
+ ["mbfitepsilon"] = "๐",
+ ["mbfitvartheta"] = "๐",
+ ["mbfitvarkappa"] = "๐",
+ ["mbfitphi"] = "๐",
+ ["mbfitvarrho"] = "๐",
+ ["mbfitvarpi"] = "๐",
+ ["mbfsansAlpha"] = "๐",
+ ["mbfsansBeta"] = "๐",
+ ["mbfsansGamma"] = "๐",
+ ["mbfsansDelta"] = "๐",
+ ["mbfsansEpsilon"] = "๐",
+ ["mbfsansZeta"] = "๐",
+ ["mbfsansEta"] = "๐",
+ ["mbfsansTheta"] = "๐",
+ ["mbfsansIota"] = "๐",
+ ["mbfsansKappa"] = "๐",
+ ["mbfsansLambda"] = "๐ ",
+ ["mbfsansMu"] = "๐ก",
+ ["mbfsansNu"] = "๐ข",
+ ["mbfsansXi"] = "๐ฃ",
+ ["mbfsansOmicron"] = "๐ค",
+ ["mbfsansPi"] = "๐ฅ",
+ ["mbfsansRho"] = "๐ฆ",
+ ["mbfsansvarTheta"] = "๐ง",
+ ["mbfsansSigma"] = "๐จ",
+ ["mbfsansTau"] = "๐ฉ",
+ ["mbfsansUpsilon"] = "๐ช",
+ ["mbfsansPhi"] = "๐ซ",
+ ["mbfsansChi"] = "๐ฌ",
+ ["mbfsansPsi"] = "๐ญ",
+ ["mbfsansOmega"] = "๐ฎ",
+ ["mbfsansnabla"] = "๐ฏ",
+ ["mbfsansalpha"] = "๐ฐ",
+ ["mbfsansbeta"] = "๐ฑ",
+ ["mbfsansgamma"] = "๐ฒ",
+ ["mbfsansdelta"] = "๐ณ",
+ ["mbfsansvarepsilon"] = "๐ด",
+ ["mbfsanszeta"] = "๐ต",
+ ["mbfsanseta"] = "๐ถ",
+ ["mbfsanstheta"] = "๐ท",
+ ["mbfsansiota"] = "๐ธ",
+ ["mbfsanskappa"] = "๐น",
+ ["mbfsanslambda"] = "๐บ",
+ ["mbfsansmu"] = "๐ป",
+ ["mbfsansnu"] = "๐ผ",
+ ["mbfsansxi"] = "๐ฝ",
+ ["mbfsansomicron"] = "๐พ",
+ ["mbfsanspi"] = "๐ฟ",
+ ["mbfsansrho"] = "๐",
+ ["mbfsansvarsigma"] = "๐",
+ ["mbfsanssigma"] = "๐",
+ ["mbfsanstau"] = "๐",
+ ["mbfsansupsilon"] = "๐",
+ ["mbfsansvarphi"] = "๐
",
+ ["mbfsanschi"] = "๐",
+ ["mbfsanspsi"] = "๐",
+ ["mbfsansomega"] = "๐",
+ ["mbfsanspartial"] = "๐",
+ ["mbfsansepsilon"] = "๐",
+ ["mbfsansvartheta"] = "๐",
+ ["mbfsansvarkappa"] = "๐",
+ ["mbfsansphi"] = "๐",
+ ["mbfsansvarrho"] = "๐",
+ ["mbfsansvarpi"] = "๐",
+ ["mbfitsansAlpha"] = "๐",
+ ["mbfitsansBeta"] = "๐",
+ ["mbfitsansGamma"] = "๐",
+ ["mbfitsansDelta"] = "๐",
+ ["mbfitsansEpsilon"] = "๐",
+ ["mbfitsansZeta"] = "๐",
+ ["mbfitsansEta"] = "๐",
+ ["mbfitsansTheta"] = "๐",
+ ["mbfitsansIota"] = "๐",
+ ["mbfitsansKappa"] = "๐",
+ ["mbfitsansLambda"] = "๐",
+ ["mbfitsansMu"] = "๐",
+ ["mbfitsansNu"] = "๐",
+ ["mbfitsansXi"] = "๐",
+ ["mbfitsansOmicron"] = "๐",
+ ["mbfitsansPi"] = "๐",
+ ["mbfitsansRho"] = "๐ ",
+ ["mbfitsansvarTheta"] = "๐ก",
+ ["mbfitsansSigma"] = "๐ข",
+ ["mbfitsansTau"] = "๐ฃ",
+ ["mbfitsansUpsilon"] = "๐ค",
+ ["mbfitsansPhi"] = "๐ฅ",
+ ["mbfitsansChi"] = "๐ฆ",
+ ["mbfitsansPsi"] = "๐ง",
+ ["mbfitsansOmega"] = "๐จ",
+ ["mbfitsansnabla"] = "๐ฉ",
+ ["mbfitsansalpha"] = "๐ช",
+ ["mbfitsansbeta"] = "๐ซ",
+ ["mbfitsansgamma"] = "๐ฌ",
+ ["mbfitsansdelta"] = "๐ญ",
+ ["mbfitsansvarepsilon"] = "๐ฎ",
+ ["mbfitsanszeta"] = "๐ฏ",
+ ["mbfitsanseta"] = "๐ฐ",
+ ["mbfitsanstheta"] = "๐ฑ",
+ ["mbfitsansiota"] = "๐ฒ",
+ ["mbfitsanskappa"] = "๐ณ",
+ ["mbfitsanslambda"] = "๐ด",
+ ["mbfitsansmu"] = "๐ต",
+ ["mbfitsansnu"] = "๐ถ",
+ ["mbfitsansxi"] = "๐ท",
+ ["mbfitsansomicron"] = "๐ธ",
+ ["mbfitsanspi"] = "๐น",
+ ["mbfitsansrho"] = "๐บ",
+ ["mbfitsansvarsigma"] = "๐ป",
+ ["mbfitsanssigma"] = "๐ผ",
+ ["mbfitsanstau"] = "๐ฝ",
+ ["mbfitsansupsilon"] = "๐พ",
+ ["mbfitsansvarphi"] = "๐ฟ",
+ ["mbfitsanschi"] = "๐",
+ ["mbfitsanspsi"] = "๐",
+ ["mbfitsansomega"] = "๐",
+ ["mbfitsanspartial"] = "๐",
+ ["mbfitsansepsilon"] = "๐",
+ ["mbfitsansvartheta"] = "๐
",
+ ["mbfitsansvarkappa"] = "๐",
+ ["mbfitsansphi"] = "๐",
+ ["mbfitsansvarrho"] = "๐",
+ ["mbfitsansvarpi"] = "๐",
+ ["mbfDigamma"] = "๐",
+ ["mbfdigamma"] = "๐",
+ ---_
+
+ ---+${class, Greek letters}
+ ["Alpha"] = "A",
+ ["alpha"] = "ฮฑ",
+
+ ["Nu"] = "N",
+ ["nu"] = "ฮฝ",
+
+ ["Beta"] = "B",
+ ["beta"] = "ฮฒ",
+
+ ["Gamma"] = "ฮ",
+ ["gamma"] = "ฮณ",
+
+ ["Omicron"] = "O",
+ ["omicron"] = "o",
+
+ ["Delta"] = "ฮ",
+ ["delta"] = "ฮด",
+
+ ["Pi"] = "ฮ ",
+ ["pi"] = "ฯ",
+ ["varpi"] = "ฯ",
+
+ ["Epsilon"] = "ฦ",
+ ["epsilon"] = "ฯต",
+ ["varepsilon"] = "ฮต",
+
+ ["Rho"] = "P",
+ ["rho"] = "ฯ",
+ ["varrho"] = "ฯฑ",
+
+ ["Zeta"] = "Z",
+ ["zeta"] = "ฮถ",
+
+ ["Sigma"] = "ฮฃ",
+ ["sigma"] = "ฯ",
+ ["varsigma"] = "ฯ",
+
+ ["Eta"] = "H",
+ ["eta"] = "ฮท",
+
+ ["Tau"] = "T",
+ ["tau"] = "ฯ",
+
+ ["Theta"] = "ฮ",
+ ["theta"] = "ฮธ",
+ ["vartheta"] = "ฯ",
+
+ ["Upsilon"] = "ฮฅ",
+ ["upsilon"] = "ฯ
",
+
+ ["Iota"] = "I",
+ ["iota"] = "ฮน",
+
+ ["Phi"] = "ฮฆ",
+ ["phi"] = "ฯ",
+ ["varphi"] = "ฯ",
+
+ ["Kappa"] = "K",
+ ["kappa"] = "ฮบ",
+ ["varkappa"] = "ฯฐ",
+
+ ["Chi"] = "X",
+ ["chi"] = "ฯ",
+
+ ["Lambda"] = "ฮ",
+ ["lambda"] = "ฮป",
+
+ ["Psi"] = "ฮจ",
+ ["psi"] = "ฯ",
+
+ ["Mu"] = "M",
+ ["mu"] = "ฮผ",
+
+ ["Omega"] = "ฮฉ",
+ ["omega"] = "ฯ",
+ ---_
+
+ ["Digmma"] = "ฯ",
+ ["digmma"] = "ฯ",
+
+ ["ngeqslant"] = "โช",
+ ["nsucceq"] = "โก",
+
+ ---+${class, Symbols from unimathsymbols}
+ ["sphat"] = "^",
+ ["cent"] = "ยข",
+ ["yen"] = "ยฅ",
+ ["spddot"] = "ยจ",
+ ["Micro"] = "ยต",
+ ["eth"] = "รฐ",
+ ["not"] = "/",
+ ["Xi"] = "ฮ",
+ ["xi"] = "ฮพ",
+ ["varbeta"] = "ฯ",
+ ["Qoppa"] = "ฯ",
+ ["qoppa"] = "ฯ",
+ ["Stigma"] = "ฯ",
+ ["stigma"] = "ฯ",
+ ["Digamma"] = "ฯ",
+ ["digamma"] = "ฯ",
+ ["Koppa"] = "ฯ",
+ ["koppa"] = "ฯ",
+ ["Sampi"] = "ฯ ",
+ ["sampi"] = "ฯก",
+ ["varTheta"] = "ฯด",
+ ["backepsilon"] = "ฯถ",
+ ["tcohm"] = "โฆ",
+ ["invamp"] = "โ
",
+ ["dashleftarrow"] = "โ ",
+ ["dashrightarrow"] = "โข",
+ ["LeftArrowBar"] = "โค",
+ ["RightArrowBar"] = "โฅ",
+ ["pfun"] = "โธ",
+ ["ffun"] = "โป",
+ ["blacksquare"] = "โ ",
+ ["slash"] = "/",
+ ["smallsetminus"] = "โ",
+ ["circ"] = "โ",
+ ["bullet"] = "โ",
+ ["Proportion"] = "โท",
+ ["AC"] = "โฟ",
+ ["corresponds"] = "โ",
+ ["neq"] = "โ ",
+ ["notasymp"] = "โญ",
+ ["NotLessTilde"] = "โด",
+ ["NotGreaterTilde"] = "โต",
+ ["NotGreaterLess"] = "โน",
+ ["multimapdotbothA"] = "โถ",
+ ["multimapdotbothB"] = "โท",
+ ["diamond"] = "โ",
+ ["hash"] = "โ",
+ ["npreceq"] = "โ ",
+ ["ntriangleleft"] = "โช",
+ ["ntriangleright"] = "โซ",
+ ["cdots"] = "โฏ",
+ ["iddots"] = "โฐ",
+ ["barin"] = "โถ",
+ ["invneg"] = "โ",
+ ["wasylozenge"] = "โ",
+ ["APLinv"] = "โน",
+ ["notslash"] = "โฟ",
+ ["notbackslash"] = "โ",
+ ["APLleftarrowbox"] = "โ",
+ ["APLrightarrowbox"] = "โ",
+ ["invdiameter"] = "โ",
+ ["APLuparrowbox"] = "โ",
+ ["APLdownarrowbox"] = "โ",
+ ["APLcomment"] = "โ",
+ ["APLinput"] = "โ",
+ ["APLlog"] = "โ",
+ ["blacktriangleup"] = "โด",
+ ["smalltriangleup"] = "โต",
+ ["RHD"] = "โถ",
+ ["rhd"] = "โท",
+ ["smalltriangledown"] = "โฟ",
+ ["LHD"] = "โ",
+ ["lhd"] = "โ",
+ ["Diamondblack"] = "โ",
+ ["Diamond"] = "โ",
+ ["lozenge"] = "โ",
+ ["Circle"] = "โ",
+ ["CIRCLE"] = "โ",
+ ["LEFTcircle"] = "โ",
+ ["RIGHTcircle"] = "โ",
+ ["LEFTCIRCLE"] = "โ",
+ ["RIGHTCIRCLE"] = "โ",
+ ["square"] = "โป",
+ ["Sun"] = "โ",
+ ["Square"] = "โ",
+ ["CheckedBox"] = "โ",
+ ["XBox"] = "โ",
+ ["frownie"] = "โน",
+ ["smiley"] = "โบ",
+ ["mercury"] = "โฟ",
+ ["earth"] = "โ",
+ ["jupiter"] = "โ",
+ ["saturn"] = "โ",
+ ["uranus"] = "โ
",
+ ["neptune"] = "โ",
+ ["pluto"] = "โ",
+ ["aries"] = "โ",
+ ["taurus"] = "โ",
+ ["gemini"] = "โ",
+ ["cancer"] = "โ",
+ ["leo"] = "โ",
+ ["virgo"] = "โ",
+ ["libra"] = "โ",
+ ["scorpio"] = "โ",
+ ["sagittarius"] = "โ",
+ ["capricornus"] = "โ",
+ ["aquarius"] = "โ",
+ ["pisces"] = "โ",
+ ["warning m"] = "โ ",
+ ["medcirc"] = "โช",
+ ["medbullet"] = "โซ",
+ ["Lbag"] = "โ
",
+ ["Rbag"] = "โ",
+ ["Diamonddot"] = "โ",
+ ["llbracket"] = "โฆ",
+ ["rrbracket"] = "โง",
+ ["lang"] = "โช",
+ ["rang"] = "โซ",
+ ["psur"] = "โค",
+ ["UpArrowBar"] = "โค",
+ ["DownArrowBar"] = "โค",
+ ["pinj"] = "โค",
+ ["finj"] = "โค",
+ ["bij"] = "โค",
+ ["leadsto"] = "โคณ",
+ ["leftrightharpoon"] = "โฅ",
+ ["rightleftharpoon"] = "โฅ",
+ ["leftrightharpoonup"] = "โฅ",
+ ["rightupdownharpoon"] = "rightupdownharpoon",
+ ["leftrightharpoondown"] = "โฅ",
+ ["leftupdownharpoon"] = "โฅ",
+ ["LeftVectorBar"] = "โฅ",
+ ["RightVectorBar"] = "โฅ",
+ ["RightUpVectorBar"] = "โฅ",
+ ["RightDownVectorBar"] = "โฅ",
+ ["DownLeftVectorBar"] = "โฅ",
+ ["DownRightVectorBar"] = "โฅ",
+ ["LeftUpVectorBar m"] = "โฅ",
+ ["LeftDownVectorBar"] = "โฅ",
+ ["LeftTeeVector"] = "โฅ",
+ ["RightTeeVector"] = "โฅ",
+ ["RightUpTeeVector"] = "โฅ",
+ ["RightDownTeeVector"] = "โฅ",
+ ["DownLeftTeeVector"] = "โฅ",
+ ["DownRightTeeVector"] = "โฅ",
+ ["LeftUpTeeVector"] = "โฅ ",
+ ["LeftDownTeeVector"] = "โฅก",
+ ["leftleftharpoons"] = "โฅข",
+ ["upupharpoons"] = "โฅฃ",
+ ["rightrightharpoons m"] = "โฅค",
+ ["downdownharpoons"] = "โฅฅ",
+ ["leftbarharpoon m"] = "โฅช",
+ ["barleftharpoon"] = "โฅซ",
+ ["rightbarharpoon"] = "โฅฌ",
+ ["barrightharpoon"] = "โฅญ",
+ ["updownharpoons"] = "โฅฎ",
+ ["downupharpoons"] = "โฅฏ",
+ ["strictfi"] = "โฅผ",
+ ["strictif"] = "โฅฝ",
+ ["VERT"] = "โฆ",
+ ["spot"] = "โฆ",
+ ["Lparen"] = "โฆ
",
+ ["Rparen"] = "โฆ",
+ ["limg"] = "โฆ",
+ ["rimg"] = "โฆ",
+ ["lblot"] = "โฆ",
+ ["rblot"] = "โฆ",
+ ["circledbslash"] = "โฆธ",
+ ["circledless"] = "โง",
+ ["circledgtr"] = "โง",
+ ["boxslash"] = "โง",
+ ["LeftTriangleBar"] = "โง",
+ ["RightTriangleBar"] = "โง",
+ ["multimapboth"] = "โง",
+ ["blacklozenge"] = "โงซ",
+ ["zhide"] = "โงน",
+ ["varprod"] = "โจ",
+ ["Coloneqq"] = "โฉด",
+ ["Equal"] = "โฉต",
+ ["Same"] = "โฉถ",
+ ["NestedLessLess"] = "โชก",
+ ["NestedGreaterGreater"] = "โชข",
+ ["leftslice"] = "โชฆ",
+ ["rightslice"] = "โชง",
+ ["llcurly"] = "โชป",
+ ["ggcurly"] = "โชผ",
+ ["Top"] = "โซช",
+ ["Bot"] = "โซซ",
+ ---_
+};
+
+symbols.typst_entries = {
+ ---+${class}
+ ["wj"] = "๐ ๐๐๐๐",
+ ["zwj"] = "๐ฃ๐ ๐",
+ ["zwnj"] = "๐ฃ๐ ๐๐",
+ ["zws"] = "๐ฃ๐ ๐๐",
+ ["lrm"] = "",
+ ["space"] = " ",
+ ["sp.nork"] = "ย ",
+ ["sp.nork.nrrow"] = "โฏ",
+ ["space.en"] = "โ",
+ ["space.quad"] = "โ",
+ ["space.third"] = "โ",
+ ["space.quarter"] = "โ
",
+ ["space.sixth"] = "โ",
+ ["space.med"] = "โ",
+ ["space.fig"] = "โ",
+ ["space.punct"] = "โ",
+ ["space.thin"] = "โ",
+ ["space.hair"] = "โ",
+ ["paren.l"] = "(",
+ ["paren.l.double"] = "โฆ
",
+ ["paren.r"] = ")",
+ ["paren.r.double"] = "โฆ",
+ ["paren.t"] = "โ",
+ ["paren.b"] = "โ",
+ ["brace.l"] = "{",
+ ["brace.l.double"] = "โฆ",
+ ["brace.r"] = "}",
+ ["brace.r.double"] = "โฆ",
+ ["brace.t"] = "โ",
+ ["brace.b"] = "โ",
+ ["bracket.l"] = "[",
+ ["bracket.l.double"] = "โฆ",
+ ["bracket.r"] = "]",
+ ["bracket.r.double"] = "โง",
+ ["bracket.t"] = "โด",
+ ["bracket.b"] = "โต",
+ ["shell.l"] = "โฒ",
+ ["shell.l.double"] = "โฌ",
+ ["shell.r"] = "โณ",
+ ["shell.r.double"] = "โญ",
+ ["shell.t"] = "โ ",
+ ["shell.b"] = "โก",
+ ["bar.v"] = "|",
+ ["bar.v.double"] = "โ",
+ ["bar.v.triple"] = "โฆ",
+ ["bar.v.broken"] = "ยฆ",
+ ["bar.h"] = "โ",
+ ["fence.l"] = "โง",
+ ["fence.l.double"] = "โง",
+ ["fence.r"] = "โง",
+ ["fence.r.double"] = "โง",
+ ["fence.dotted"] = "โฆ",
+ ["angle"] = "โ ",
+ ["angle.l"] = "โจ",
+ ["angle.l.curly"] = "โงผ",
+ ["angle.l.dot"] = "โฆ",
+ ["angle.l.double"] = "ใ",
+ ["angle.r"] = "โฉ",
+ ["angle.r.curly"] = "โงฝ",
+ ["angle.r.dot"] = "โฆ",
+ ["angle.r.double"] = "ใ",
+ ["angle.acute"] = "โฆ",
+ ["angle.arc"] = "โก",
+ ["angle.arc.rev"] = "โฆ",
+ ["angle.oblique"] = "โฆฆ",
+ ["angle.rev"] = "โฆฃ",
+ ["angle.right"] = "โ",
+ ["angle.right.rev"] = "โฏพ",
+ ["angle.right.arc"] = "โพ",
+ ["angle.right.dot"] = "โฆ",
+ ["angle.right.sq"] = "โฆ",
+ ["angle.s"] = "โฆ",
+ ["angle.spatial"] = "โ",
+ ["angle.spheric"] = "โข",
+ ["angle.spheric.rev"] = "โฆ ",
+ ["angle.spheric.top"] = "โฆก",
+ ["ceil.l"] = "โ",
+ ["ceil.r"] = "โ",
+ ["floor.l"] = "โ",
+ ["floor.r"] = "โ",
+ ["amp"] = "&",
+ ["amp.inv"] = "โ
",
+ ["ast.op"] = "โ",
+ ["ast.basic"] = "*",
+ ["ast.low"] = "โ",
+ ["ast.double"] = "โ",
+ ["ast.triple"] = "โ",
+ ["ast.small"] = "๏นก",
+ ["ast.circle"] = "โ",
+ ["ast.square"] = "โง",
+ ["at"] = "@",
+ ["backslash"] = "\\",
+ ["backslash.circle"] = "โฆธ",
+ ["backslash.not"] = "โงท",
+ ["co"] = "โ
",
+ ["colon"] = ":",
+ ["colon.double"] = "โท",
+ ["colon.eq"] = "โ",
+ ["colon.double.eq"] = "โฉด",
+ ["comma"] = ",",
+ ["dagger"] = "โ ",
+ ["dagger.double"] = "โก",
+ ["dash.en"] = "โ",
+ ["dash.em"] = "โ",
+ ["dash.em.two"] = "โธบ",
+ ["dash.em.three"] = "โธป",
+ ["dash.fig"] = "โ",
+ ["dash.wave"] = "ใ",
+ ["dash.colon"] = "โน",
+ ["dash.circle"] = "โ",
+ ["dash.wave.double"] = "ใฐ",
+ ["dot.op"] = "โ
",
+ ["dot.basic"] = ".",
+ ["dot.c"] = "ยท",
+ ["dot.circle"] = "โ",
+ ["dot.circle.big"] = "โจ",
+ ["dot.square"] = "โก",
+ ["dot.double"] = "ยจ",
+ ["dot.triple"] = "โด",
+ ["dot.quad"] = "โ",
+ ["excl"] = "!",
+ ["excl.double"] = "โผ",
+ ["excl.inv"] = "ยก",
+ ["excl.quest"] = "โ",
+ ["quest"] = "?",
+ ["quest.double"] = "โ",
+ ["quest.excl"] = "โ",
+ ["quest.inv"] = "ยฟ",
+ ["interrobang"] = "โฝ",
+ ["hash"] = "#",
+ ["hyph"] = "โ",
+ ["hyph.minus"] = "-",
+ ["hyph.nobreak"] = "โ",
+ ["hyph.point"] = "โง",
+ ["hyph.soft"] = "ยญ",
+ ["percent"] = "%",
+ ["permille"] = "โฐ",
+ ["pilcrow"] = "ยถ",
+ ["pilcrow.rev"] = "โ",
+ ["section"] = "ยง",
+ ["semi"] = ";",
+ ["semi.rev"] = "โ",
+ ["slash"] = "/",
+ ["slash.double"] = "โซฝ",
+ ["slash.triple"] = "โซป",
+ ["slash.big"] = "โงธ",
+ ["dots.h.c"] = "โฏ",
+ ["dots.h"] = "โฆ",
+ ["dots.v"] = "โฎ",
+ ["dots.down"] = "โฑ",
+ ["dots.up"] = "โฐ",
+ ["tilde.op"] = "โผ",
+ ["tilde.basic"] = "~",
+ ["tilde.dot"] = "โฉช",
+ ["tilde.eq"] = "โ",
+ ["tilde.eq.not"] = "โ",
+ ["tilde.eq.rev"] = "โ",
+ ["tilde.equiv"] = "โ
",
+ ["tilde.equiv.not"] = "โ",
+ ["tilde.nequiv"] = "โ",
+ ["tilde.not"] = "โ",
+ ["tilde.rev"] = "โฝ",
+ ["tilde.rev.equiv"] = "โ",
+ ["tilde.triple"] = "โ",
+ ["acute"] = "ยด",
+ ["acute.double"] = "ห",
+ ["breve"] = "ห",
+ ["caret"] = "โธ",
+ ["caron"] = "ห",
+ ["hat"] = "^",
+ ["diaer"] = "ยจ",
+ ["grave"] = "`",
+ ["macron"] = "ยฏ",
+ ["quote.double"] = '"',
+ ["quote.single"] = "'",
+ ["quote.l.double"] = "โ",
+ ["quote.l.single"] = "โ",
+ ["quote.r.double"] = "โ",
+ ["quote.r.single"] = "โ",
+ ["quote.angle.l.double"] = "ยซ",
+ ["quote.angle.l.single"] = "โน",
+ ["quote.angle.r.double"] = "ยป",
+ ["quote.angle.r.single"] = "โบ",
+ ["quote.high.double"] = "โ",
+ ["quote.high.single"] = "โ",
+ ["quote.low.double"] = "โ",
+ ["quote.low.single"] = "โ",
+ ["prime"] = "โฒ",
+ ["prime.rev"] = "โต",
+ ["prime.double"] = "โณ",
+ ["prime.double.rev"] = "โถ",
+ ["prime.triple"] = "โด",
+ ["prime.triple.rev"] = "โท",
+ ["prime.quad"] = "โ",
+ ["plus"] = "+",
+ ["plus.circle"] = "โ",
+ ["plus.circle.arrow"] = "โด",
+ ["plus.circle.big"] = "โจ",
+ ["plus.dot"] = "โ",
+ ["plus.double"] = "โงบ",
+ ["plus.minus"] = "ยฑ",
+ ["plus.small"] = "๏นข",
+ ["plus.square"] = "โ",
+ ["plus.triangle"] = "โจน",
+ ["plus.triple"] = "โงป",
+ ["minus"] = "โ",
+ ["minus.circle"] = "โ",
+ ["minus.dot"] = "โธ",
+ ["minus.plus"] = "โ",
+ ["minus.square"] = "โ",
+ ["minus.tilde"] = "โ",
+ ["minus.triangle"] = "โจบ",
+ ["div"] = "รท",
+ ["div.circle"] = "โจธ",
+ ["times"] = "ร",
+ ["times.big"] = "โจ",
+ ["times.circle"] = "โ",
+ ["times.circle.big"] = "โจ",
+ ["times.div"] = "โ",
+ ["times.three.l"] = "โ",
+ ["times.three.r"] = "โ",
+ ["times.l"] = "โ",
+ ["times.r"] = "โ",
+ ["times.square"] = "โ ",
+ ["times.triangle"] = "โจป",
+ ["ratio"] = "โถ",
+ ["eq"] = "=",
+ ["eq.star"] = "โ",
+ ["eq.circle"] = "โ",
+ ["eq.colon"] = "โ",
+ ["eq.def"] = "โ",
+ ["eq.delta"] = "โ",
+ ["eq.equi"] = "โ",
+ ["eq.est"] = "โ",
+ ["eq.gt"] = "โ",
+ ["eq.lt"] = "โ",
+ ["eq.m"] = "โ",
+ ["eq.not"] = "โ ",
+ ["eq.prec"] = "โ",
+ ["eq.quest"] = "โ",
+ ["eq.small"] = "๏นฆ",
+ ["eq.succ"] = "โ",
+ ["eq.triple"] = "โก",
+ ["eq.quad"] = "โฃ",
+ ["gt"] = ">",
+ ["gt.circle"] = "โง",
+ ["gt.dot"] = "โ",
+ ["gt.approx"] = "โช",
+ ["gt.double"] = "โซ",
+ ["gt.eq"] = "โฅ",
+ ["gt.eq.slant"] = "โฉพ",
+ ["gt.eq.lt"] = "โ",
+ ["gt.eq.not"] = "โฑ",
+ ["gt.equiv"] = "โง",
+ ["gt.lt"] = "โท",
+ ["gt.lt.not"] = "โน",
+ ["gt.neq"] = "โช",
+ ["gt.napprox"] = "โช",
+ ["gt.nequiv"] = "โฉ",
+ ["gt.not"] = "โฏ",
+ ["gt.ntilde"] = "โง",
+ ["gt.small"] = "๏นฅ",
+ ["gt.tilde"] = "โณ",
+ ["gt.tilde.not"] = "โต",
+ ["gt.tri"] = "โณ",
+ ["gt.tri.eq"] = "โต",
+ ["gt.tri.eq.not"] = "โญ",
+ ["gt.tri.not"] = "โซ",
+ ["gt.triple"] = "โ",
+ ["gt.triple.nested"] = "โซธ",
+ ["lt"] = "<",
+ ["lt.circle"] = "โง",
+ ["lt.dot"] = "โ",
+ ["lt.approx"] = "โช
",
+ ["lt.double"] = "โช",
+ ["lt.eq"] = "โค",
+ ["lt.eq.slant"] = "โฉฝ",
+ ["lt.eq.gt"] = "โ",
+ ["lt.eq.not"] = "โฐ",
+ ["lt.equiv"] = "โฆ",
+ ["lt.gt"] = "โถ",
+ ["lt.gt.not"] = "โธ",
+ ["lt.neq"] = "โช",
+ ["lt.napprox"] = "โช",
+ ["lt.nequiv"] = "โจ",
+ ["lt.not"] = "โฎ",
+ ["lt.ntilde"] = "โฆ",
+ ["lt.small"] = "๏นค",
+ ["lt.tilde"] = "โฒ",
+ ["lt.tilde.not"] = "โด",
+ ["lt.tri"] = "โฒ",
+ ["lt.tri.eq"] = "โด",
+ ["lt.tri.eq.not"] = "โฌ",
+ ["lt.tri.not"] = "โช",
+ ["lt.triple"] = "โ",
+ ["lt.triple.nested"] = "โซท",
+ ["approx"] = "โ",
+ ["approx.eq"] = "โ",
+ ["approx.not"] = "โ",
+ ["prec"] = "โบ",
+ ["prec.approx"] = "โชท",
+ ["prec.curly.eq"] = "โผ",
+ ["prec.curly.eq.not"] = "โ ",
+ ["prec.double"] = "โชป",
+ ["prec.eq"] = "โชฏ",
+ ["prec.equiv"] = "โชณ",
+ ["prec.napprox"] = "โชน",
+ ["prec.neq"] = "โชฑ",
+ ["prec.nequiv"] = "โชต",
+ ["prec.not"] = "โ",
+ ["prec.ntilde"] = "โจ",
+ ["prec.tilde"] = "โพ",
+ ["succ"] = "โป",
+ ["succ.approx"] = "โชธ",
+ ["succ.curly.eq"] = "โฝ",
+ ["succ.curly.eq.not"] = "โก",
+ ["succ.double"] = "โชผ",
+ ["succ.eq"] = "โชฐ",
+ ["succ.equiv"] = "โชด",
+ ["succ.napprox"] = "โชบ",
+ ["succ.neq"] = "โชฒ",
+ ["succ.nequiv"] = "โชถ",
+ ["succ.not"] = "โ",
+ ["succ.ntilde"] = "โฉ",
+ ["succ.tilde"] = "โฟ",
+ ["equiv"] = "โก",
+ ["equiv.not"] = "โข",
+ ["prop"] = "โ",
+ ["original"] = "โถ",
+ ["image"] = "โท",
+ ["emptyset"] = "โ
",
+ ["emptyset.arrow.r"] = "โฆณ",
+ ["emptyset.arrow.l"] = "โฆด",
+ ["emptyset.bar"] = "โฆฑ",
+ ["emptyset.circle"] = "โฆฒ",
+ ["emptyset.rev"] = "โฆฐ",
+ ["nothing"] = "โ
",
+ ["nothing.arrow.r"] = "โฆณ",
+ ["nothing.arrow.l"] = "โฆด",
+ ["nothing.bar"] = "โฆฑ",
+ ["nothing.circle"] = "โฆฒ",
+ ["nothing.rev"] = "โฆฐ",
+ ["without"] = "โ",
+ ["complement"] = "โ",
+ ["in"] = "โ",
+ ["in.not"] = "โ",
+ ["in.rev"] = "โ",
+ ["in.rev.not"] = "โ",
+ ["in.rev.small"] = "โ",
+ ["in.small"] = "โ",
+ ["subset"] = "โ",
+ ["subset.dot"] = "โชฝ",
+ ["subset.double"] = "โ",
+ ["subset.eq"] = "โ",
+ ["subset.eq.not"] = "โ",
+ ["subset.eq.sq"] = "โ",
+ ["subset.eq.sq.not"] = "โข",
+ ["subset.neq"] = "โ",
+ ["subset.not"] = "โ",
+ ["subset.sq"] = "โ",
+ ["subset.sq.neq"] = "โค",
+ ["supset"] = "โ",
+ ["supset.dot"] = "โชพ",
+ ["supset.double"] = "โ",
+ ["supset.eq"] = "โ",
+ ["supset.eq.not"] = "โ",
+ ["supset.eq.sq"] = "โ",
+ ["supset.eq.sq.not"] = "โฃ",
+ ["supset.neq"] = "โ",
+ ["supset.not"] = "โ
",
+ ["supset.sq"] = "โ",
+ ["supset.sq.neq"] = "โฅ",
+ ["union"] = "โช",
+ ["union.arrow"] = "โ",
+ ["union.big"] = "โ",
+ ["union.dot"] = "โ",
+ ["union.dot.big"] = "โจ",
+ ["union.double"] = "โ",
+ ["union.minus"] = "โฉ",
+ ["union.or"] = "โฉ
",
+ ["union.plus"] = "โ",
+ ["union.plus.big"] = "โจ",
+ ["union.sq"] = "โ",
+ ["union.sq.big"] = "โจ",
+ ["union.sq.double"] = "โฉ",
+ ["sect"] = "โฉ",
+ ["sect.and"] = "โฉ",
+ ["sect.big"] = "โ",
+ ["sect.dot"] = "โฉ",
+ ["sect.double"] = "โ",
+ ["sect.sq"] = "โ",
+ ["sect.sq.big"] = "โจ
",
+ ["sect.sq.double"] = "โฉ",
+ ["infinity"] = "โ",
+ ["infinity.bar"] = "โง",
+ ["infinity.incomplete"] = "โง",
+ ["infinity.tie"] = "โง",
+ ["oo"] = "โ",
+ ["diff"] = "โ",
+ ["partial"] = "โ",
+ ["gradient"] = "โ",
+ ["nabla"] = "โ",
+ ["sum"] = "โ",
+ ["sum.integral"] = "โจ",
+ ["product"] = "โ",
+ ["product.co"] = "โ",
+ ["integral"] = "โซ",
+ ["integral.arrow.hook"] = "โจ",
+ ["integral.ccw"] = "โจ",
+ ["integral.cont"] = "โฎ",
+ ["integral.cont.ccw"] = "โณ",
+ ["integral.cont.cw"] = "โฒ",
+ ["integral.cw"] = "โฑ",
+ ["integral.dash"] = "โจ",
+ ["integral.dash.double"] = "โจ",
+ ["integral.double"] = "โฌ",
+ ["integral.quad"] = "โจ",
+ ["integral.sect"] = "โจ",
+ ["integral.slash"] = "โจ",
+ ["integral.square"] = "โจ",
+ ["integral.surf"] = "โฏ",
+ ["integral.times"] = "โจ",
+ ["integral.triple"] = "โญ",
+ ["integral.union"] = "โจ",
+ ["integral.vol"] = "โฐ",
+ ["laplace"] = "โ",
+ ["forall"] = "โ",
+ ["exists"] = "โ",
+ ["exists.not"] = "โ",
+ ["top"] = "โค",
+ ["bot"] = "โฅ",
+ ["not"] = "ยฌ",
+ ["and"] = "โง",
+ ["and.big"] = "โ",
+ ["and.curly"] = "โ",
+ ["and.dot"] = "โ",
+ ["and.double"] = "โฉ",
+ ["or"] = "โจ",
+ ["or.big"] = "โ",
+ ["or.curly"] = "โ",
+ ["or.dot"] = "โ",
+ ["or.double"] = "โฉ",
+ ["xor"] = "โ",
+ ["xor.big"] = "โจ",
+ ["models"] = "โง",
+ ["forces"] = "โฉ",
+ ["forces.not"] = "โฎ",
+ ["therefore"] = "โด",
+ ["because"] = "โต",
+ ["qed"] = "โ",
+ ["compose"] = "โ",
+ ["convolve"] = "โ",
+ ["multimap"] = "โธ",
+ ["multimap.double"] = "โง",
+ ["tiny"] = "โงพ",
+ ["miny"] = "โงฟ",
+ ["divides"] = "โฃ",
+ ["divides.not"] = "โค",
+ ["wreath"] = "โ",
+ ["parallel"] = "โฅ",
+ ["parallel.struck"] = "โซฒ",
+ ["parallel.circle"] = "โฆท",
+ ["parallel.eq"] = "โ",
+ ["parallel.equiv"] = "โฉจ",
+ ["parallel.not"] = "โฆ",
+ ["parallel.slanted.eq"] = "โงฃ",
+ ["parallel.slanted.eq.tilde"] = "โงค",
+ ["parallel.slanted.equiv"] = "โงฅ",
+ ["parallel.tilde"] = "โซณ",
+ ["perp"] = "โ",
+ ["perp.circle"] = "โฆน",
+ ["diameter"] = "โ",
+ ["join"] = "โจ",
+ ["join.r"] = "โ",
+ ["join.l"] = "โ",
+ ["join.l.r"] = "โ",
+ ["degree"] = "ยฐ",
+ ["degree.c"] = "โ",
+ ["degree.f"] = "โ",
+ ["smash"] = "โจณ",
+ ["bitcoin"] = "โฟ",
+ ["dollar"] = "$",
+ ["euro"] = "โฌ",
+ ["franc"] = "โฃ",
+ ["lira"] = "โบ",
+ ["peso"] = "โฑ",
+ ["pound"] = "ยฃ",
+ ["ruble"] = "โฝ",
+ ["rupee"] = "โน",
+ ["won"] = "โฉ",
+ ["yen"] = "ยฅ",
+ ["ballot"] = "โ",
+ ["ballot.cross"] = "โ",
+ ["ballot.check"] = "โ",
+ ["ballot.check.heavy"] = "๐น",
+ ["checkmark"] = "โ",
+ ["checkmark.light"] = "๐ธ",
+ ["checkmark.heavy"] = "โ",
+ ["crossmark"] = "โ",
+ ["crossmark.heavy"] = "โ",
+ ["floral"] = "โฆ",
+ ["floral.l"] = "โ",
+ ["floral.r"] = "โง",
+ ["refmark"] = "โป",
+ ["copyright"] = "ยฉ",
+ ["copyright.sound"] = "โ",
+ ["copyleft"] = "๐ฏ",
+ ["trademark"] = "โข",
+ ["trademark.registered"] = "ยฎ",
+ ["trademark.service"] = "โ ",
+ ["maltese"] = "โ ",
+ ["suit.club.filled"] = "โฃ",
+ ["suit.club.stroked"] = "โง",
+ ["suit.diamond.filled"] = "โฆ",
+ ["suit.diamond.stroked"] = "โข",
+ ["suit.heart.filled"] = "โฅ",
+ ["suit.heart.stroked"] = "โก",
+ ["suit.spade.filled"] = "โ ",
+ ["suit.spade.stroked"] = "โค",
+ ["note.up"] = "๐",
+ ["note.down"] = "๐",
+ ["note.whole"] = "๐
",
+ ["note.half"] = "๐
",
+ ["note.quarter"] = "๐
",
+ ["note.quarter.alt"] = "โฉ",
+ ["note.eighth"] = "๐
",
+ ["note.eighth.alt"] = "โช",
+ ["note.eighth.beamed"] = "โซ",
+ ["note.sixteenth"] = "๐
ก",
+ ["note.sixteenth.beamed"] = "โฌ",
+ ["note.grace"] = "๐",
+ ["note.grace.slash"] = "๐",
+ ["rest.whole"] = "๐ป",
+ ["rest.multiple"] = "๐บ",
+ ["rest.multiple.measure"] = "๐ฉ",
+ ["rest.half"] = "๐ผ",
+ ["rest.quarter"] = "๐ฝ",
+ ["rest.eighth"] = "๐พ",
+ ["rest.sixteenth"] = "๐ฟ",
+ ["natural"] = "โฎ",
+ ["natural.t"] = "๐ฎ",
+ ["natural.b"] = "๐ฏ",
+ ["flat"] = "โญ",
+ ["flat.t"] = "๐ฌ",
+ ["flat.b"] = "๐ญ",
+ ["flat.double"] = "๐ซ",
+ ["flat.quarter"] = "๐ณ",
+ ["sharp"] = "โฏ",
+ ["sharp.t"] = "๐ฐ",
+ ["sharp.b"] = "๐ฑ",
+ ["sharp.double"] = "๐ช",
+ ["sharp.quarter"] = "๐ฒ",
+ ["bullet"] = "โข",
+ ["circle.stroked"] = "โ",
+ ["circle.stroked.tiny"] = "โ",
+ ["circle.stroked.small"] = "โฌ",
+ ["circle.stroked.big"] = "โฏ",
+ ["circle.filled"] = "โ",
+ ["circle.filled.tiny"] = "โฆ",
+ ["circle.filled.small"] = "โ",
+ ["circle.filled.big"] = "โฌค",
+ ["circle.dotted"] = "โ",
+ ["circle.nested"] = "โ",
+ ["ellipse.stroked.h"] = "โฌญ",
+ ["ellipse.stroked.v"] = "โฌฏ",
+ ["ellipse.filled.h"] = "โฌฌ",
+ ["ellipse.filled.v"] = "โฌฎ",
+ ["triangle.stroked.t"] = "โณ",
+ ["triangle.stroked.b"] = "โฝ",
+ ["triangle.stroked.r"] = "โท",
+ ["triangle.stroked.l"] = "โ",
+ ["triangle.stroked.bl"] = "โบ",
+ ["triangle.stroked.br"] = "โฟ",
+ ["triangle.stroked.tl"] = "โธ",
+ ["triangle.stroked.tr"] = "โน",
+ ["triangle.stroked.small.t"] = "โต",
+ ["triangle.stroked.small.b"] = "โฟ",
+ ["triangle.stroked.small.r"] = "โน",
+ ["triangle.stroked.small.l"] = "โ",
+ ["triangle.stroked.rounded"] = "๐",
+ ["triangle.stroked.nested"] = "โ",
+ ["triangle.stroked.dot"] = "โฌ",
+ ["triangle.filled.t"] = "โฒ",
+ ["triangle.filled.b"] = "โผ",
+ ["triangle.filled.r"] = "โถ",
+ ["triangle.filled.l"] = "โ",
+ ["triangle.filled.bl"] = "โฃ",
+ ["triangle.filled.br"] = "โข",
+ ["triangle.filled.tl"] = "โค",
+ ["triangle.filled.tr"] = "โฅ",
+ ["triangle.filled.small.t"] = "โด",
+ ["triangle.filled.small.b"] = "โพ",
+ ["triangle.filled.small.r"] = "โธ",
+ ["triangle.filled.small.l"] = "โ",
+ ["square.stroked"] = "โก",
+ ["square.stroked.tiny"] = "โซ",
+ ["square.stroked.small"] = "โฝ",
+ ["square.stroked.medium"] = "โป",
+ ["square.stroked.big"] = "โฌ",
+ ["square.stroked.dotted"] = "โฌ",
+ ["square.stroked.rounded"] = "โข",
+ ["square.filled"] = "โ ",
+ ["square.filled.tiny"] = "โช",
+ ["square.filled.small"] = "โพ",
+ ["square.filled.medium"] = "โผ",
+ ["square.filled.big"] = "โฌ",
+ ["rect.stroked.h"] = "โญ",
+ ["rect.stroked.v"] = "โฏ",
+ ["rect.filled.h"] = "โฌ",
+ ["rect.filled.v"] = "โฎ",
+ ["penta.stroked"] = "โฌ ",
+ ["penta.filled"] = "โฌ",
+ ["hexa.stroked"] = "โฌก",
+ ["hexa.filled"] = "โฌข",
+ ["diamond.stroked"] = "โ",
+ ["diamond.stroked.small"] = "โ",
+ ["diamond.stroked.medium"] = "โฌฆ",
+ ["diamond.stroked.dot"] = "โ",
+ ["diamond.filled"] = "โ",
+ ["diamond.filled.medium"] = "โฌฅ",
+ ["diamond.filled.small"] = "โฌฉ",
+ ["lozenge.stroked"] = "โ",
+ ["lozenge.stroked.small"] = "โฌซ",
+ ["lozenge.stroked.medium"] = "โฌจ",
+ ["lozenge.filled"] = "โงซ",
+ ["lozenge.filled.small"] = "โฌช",
+ ["lozenge.filled.medium"] = "โฌง",
+ ["parallelogram.stroked"] = "โฑ",
+ ["parallelogram.filled"] = "โฐ",
+ ["star.op"] = "โ",
+ ["star.stroked"] = "โ",
+ ["star.filled"] = "โ
",
+ ["arrow.r"] = "โ",
+ ["arrow.r.long.bar"] = "โผ",
+ ["arrow.r.bar"] = "โฆ",
+ ["arrow.r.curve"] = "โคท",
+ ["arrow.r.turn"] = "โฎ",
+ ["arrow.r.dashed"] = "โข",
+ ["arrow.r.dotted"] = "โค",
+ ["arrow.r.double"] = "โ",
+ ["arrow.r.double.bar"] = "โค",
+ ["arrow.r.double.long"] = "โน",
+ ["arrow.r.double.long.bar"] = "โพ",
+ ["arrow.r.double.not"] = "โ",
+ ["arrow.r.filled"] = "โก",
+ ["arrow.r.hook"] = "โช",
+ ["arrow.r.long"] = "โถ",
+ ["arrow.r.long.squiggly"] = "โฟ",
+ ["arrow.r.loop"] = "โฌ",
+ ["arrow.r.not"] = "โ",
+ ["arrow.r.quad"] = "โญ",
+ ["arrow.r.squiggly"] = "โ",
+ ["arrow.r.stop"] = "โฅ",
+ ["arrow.r.stroked"] = "โจ",
+ ["arrow.r.tail"] = "โฃ",
+ ["arrow.r.tilde"] = "โฅฒ",
+ ["arrow.r.triple"] = "โ",
+ ["arrow.r.twohead.bar"] = "โค
",
+ ["arrow.r.twohead"] = "โ ",
+ ["arrow.r.wave"] = "โ",
+ ["arrow.l"] = "โ",
+ ["arrow.l.bar"] = "โค",
+ ["arrow.l.curve"] = "โคถ",
+ ["arrow.l.turn"] = "โฎ",
+ ["arrow.l.dashed"] = "โ ",
+ ["arrow.l.dotted"] = "โฌธ",
+ ["arrow.l.double"] = "โ",
+ ["arrow.l.double.bar"] = "โค",
+ ["arrow.l.double.long"] = "โธ",
+ ["arrow.l.double.long.bar"] = "โฝ",
+ ["arrow.l.double.not"] = "โ",
+ ["arrow.l.filled"] = "โฌ
",
+ ["arrow.l.hook"] = "โฉ",
+ ["arrow.l.long"] = "โต",
+ ["arrow.l.long.bar"] = "โป",
+ ["arrow.l.long.squiggly"] = "โฌณ",
+ ["arrow.l.loop"] = "โซ",
+ ["arrow.l.not"] = "โ",
+ ["arrow.l.quad"] = "โญ
",
+ ["arrow.l.squiggly"] = "โ",
+ ["arrow.l.stop"] = "โค",
+ ["arrow.l.stroked"] = "โฆ",
+ ["arrow.l.tail"] = "โข",
+ ["arrow.l.tilde"] = "โญ",
+ ["arrow.l.triple"] = "โ",
+ ["arrow.l.twohead.bar"] = "โฌถ",
+ ["arrow.l.twohead"] = "โ",
+ ["arrow.l.wave"] = "โ",
+ ["arrow.t"] = "โ",
+ ["arrow.t.bar"] = "โฅ",
+ ["arrow.t.curve"] = "โคด",
+ ["arrow.t.turn"] = "โฎ",
+ ["arrow.t.dashed"] = "โก",
+ ["arrow.t.double"] = "โ",
+ ["arrow.t.filled"] = "โฌ",
+ ["arrow.t.quad"] = "โฐ",
+ ["arrow.t.stop"] = "โค",
+ ["arrow.t.stroked"] = "โง",
+ ["arrow.t.triple"] = "โค",
+ ["arrow.t.twohead"] = "โ",
+ ["arrow.b"] = "โ",
+ ["arrow.b.bar"] = "โง",
+ ["arrow.b.curve"] = "โคต",
+ ["arrow.b.turn"] = "โฎ",
+ ["arrow.b.dashed"] = "โฃ",
+ ["arrow.b.double"] = "โ",
+ ["arrow.b.filled"] = "โฌ",
+ ["arrow.b.quad"] = "โฑ",
+ ["arrow.b.stop"] = "โค",
+ ["arrow.b.stroked"] = "โฉ",
+ ["arrow.b.triple"] = "โค",
+ ["arrow.b.twohead"] = "โก",
+ ["arrow.l.r"] = "โ",
+ ["arrow.l.r.double"] = "โ",
+ ["arrow.l.r.double.long"] = "โบ",
+ ["arrow.l.r.double.not"] = "โ",
+ ["arrow.l.r.filled"] = "โฌ",
+ ["arrow.l.r.long"] = "โท",
+ ["arrow.l.r.not"] = "โฎ",
+ ["arrow.l.r.stroked"] = "โฌ",
+ ["arrow.l.r.wave"] = "โญ",
+ ["arrow.t.b"] = "โ",
+ ["arrow.t.b.double"] = "โ",
+ ["arrow.t.b.filled"] = "โฌ",
+ ["arrow.t.b.stroked"] = "โณ",
+ ["arrow.tr"] = "โ",
+ ["arrow.tr.double"] = "โ",
+ ["arrow.tr.filled"] = "โฌ",
+ ["arrow.tr.hook"] = "โคค",
+ ["arrow.tr.stroked"] = "โฌ",
+ ["arrow.br"] = "โ",
+ ["arrow.br.double"] = "โ",
+ ["arrow.br.filled"] = "โฌ",
+ ["arrow.br.hook"] = "โคฅ",
+ ["arrow.br.stroked"] = "โฌ",
+ ["arrow.tl"] = "โ",
+ ["arrow.tl.double"] = "โ",
+ ["arrow.tl.filled"] = "โฌ",
+ ["arrow.tl.hook"] = "โคฃ",
+ ["arrow.tl.stroked"] = "โฌ",
+ ["arrow.bl"] = "โ",
+ ["arrow.bl.double"] = "โ",
+ ["arrow.bl.filled"] = "โฌ",
+ ["arrow.bl.hook"] = "โคฆ",
+ ["arrow.bl.stroked"] = "โฌ",
+ ["arrow.tl.br"] = "โคก",
+ ["arrow.tr.bl"] = "โคข",
+ ["arrow.ccw"] = "โบ",
+ ["arrow.ccw.half"] = "โถ",
+ ["arrow.cw"] = "โป",
+ ["arrow.cw.half"] = "โท",
+ ["arrow.zigzag"] = "โฏ",
+ ["arrows.rr"] = "โ",
+ ["arrows.ll"] = "โ",
+ ["arrows.tt"] = "โ",
+ ["arrows.bb"] = "โ",
+ ["arrows.lr"] = "โ",
+ ["arrows.lr.stop"] = "โน",
+ ["arrows.rl"] = "โ",
+ ["arrows.tb"] = "โ
",
+ ["arrows.bt"] = "โต",
+ ["arrows.rrr"] = "โถ",
+ ["arrows.lll"] = "โฌฑ",
+ ["arrowhead.t"] = "โ",
+ ["arrowhead.b"] = "โ",
+ ["harpoon.rt"] = "โ",
+ ["harpoon.rt.bar"] = "โฅ",
+ ["harpoon.rt.stop"] = "โฅ",
+ ["harpoon.rb"] = "โ",
+ ["harpoon.rb.bar"] = "โฅ",
+ ["harpoon.rb.stop"] = "โฅ",
+ ["harpoon.lt"] = "โผ",
+ ["harpoon.lt.bar"] = "โฅ",
+ ["harpoon.lt.stop"] = "โฅ",
+ ["harpoon.lb"] = "โฝ",
+ ["harpoon.lb.bar"] = "โฅ",
+ ["harpoon.lb.stop"] = "โฅ",
+ ["harpoon.tl"] = "โฟ",
+ ["harpoon.tl.bar"] = "โฅ ",
+ ["harpoon.tl.stop"] = "โฅ",
+ ["harpoon.tr"] = "โพ",
+ ["harpoon.tr.bar"] = "โฅ",
+ ["harpoon.tr.stop"] = "โฅ",
+ ["harpoon.bl"] = "โ",
+ ["harpoon.bl.bar"] = "โฅก",
+ ["harpoon.bl.stop"] = "โฅ",
+ ["harpoon.br"] = "โ",
+ ["harpoon.br.bar"] = "โฅ",
+ ["harpoon.br.stop"] = "โฅ",
+ ["harpoon.lt.rt"] = "โฅ",
+ ["harpoon.lb.rb"] = "โฅ",
+ ["harpoon.lb.rt"] = "โฅ",
+ ["harpoon.lt.rb"] = "โฅ",
+ ["harpoon.tl.bl"] = "โฅ",
+ ["harpoon.tr.br"] = "โฅ",
+ ["harpoon.tl.br"] = "โฅ",
+ ["harpoon.tr.bl"] = "โฅ",
+ ["harpoons.rtrb"] = "โฅค",
+ ["harpoons.blbr"] = "โฅฅ",
+ ["harpoons.bltr"] = "โฅฏ",
+ ["harpoons.lbrb"] = "โฅง",
+ ["harpoons.ltlb"] = "โฅข",
+ ["harpoons.ltrb"] = "โ",
+ ["harpoons.ltrt"] = "โฅฆ",
+ ["harpoons.rblb"] = "โฅฉ",
+ ["harpoons.rtlb"] = "โ",
+ ["harpoons.rtlt"] = "โฅจ",
+ ["harpoons.tlbr"] = "โฅฎ",
+ ["harpoons.tltr"] = "โฅฃ",
+ ["tack.r"] = "โข",
+ ["tack.r.not"] = "โฌ",
+ ["tack.r.long"] = "โ",
+ ["tack.r.short"] = "โฆ",
+ ["tack.r.double"] = "โจ",
+ ["tack.r.double.not"] = "โญ",
+ ["tack.l"] = "โฃ",
+ ["tack.l.long"] = "โ",
+ ["tack.l.short"] = "โซ",
+ ["tack.l.double"] = "โซค",
+ ["tack.t"] = "โฅ",
+ ["tack.t.big"] = "โ",
+ ["tack.t.double"] = "โซซ",
+ ["tack.t.short"] = "โซ ",
+ ["tack.b"] = "โค",
+ ["tack.b.big"] = "โ",
+ ["tack.b.double"] = "โซช",
+ ["tack.b.short"] = "โซ",
+ ["tack.l.r"] = "โ",
+ ["alpha"] = "ฮฑ",
+ ["beta"] = "ฮฒ",
+ ["beta.alt"] = "ฯ",
+ ["chi"] = "ฯ",
+ ["delta"] = "ฮด",
+ ["epsilon"] = "ฮต",
+ ["epsilon.alt"] = "ฯต",
+ ["eta"] = "ฮท",
+ ["gamma"] = "ฮณ",
+ ["iota"] = "ฮน",
+ ["kai"] = "ฯ",
+ ["kappa"] = "ฮบ",
+ ["kappa.alt"] = "ฯฐ",
+ ["lambda"] = "ฮป",
+ ["mu"] = "ฮผ",
+ ["nu"] = "ฮฝ",
+ ["ohm"] = "โฆ",
+ ["ohm.inv"] = "โง",
+ ["omega"] = "ฯ",
+ ["omicron"] = "ฮฟ",
+ ["phi"] = "ฯ",
+ ["phi.alt"] = "ฯ",
+ ["pi"] = "ฯ",
+ ["pi.alt"] = "ฯ",
+ ["psi"] = "ฯ",
+ ["rho"] = "ฯ",
+ ["rho.alt"] = "ฯฑ",
+ ["sigma"] = "ฯ",
+ ["sigma.alt"] = "ฯ",
+ ["tau"] = "ฯ",
+ ["theta"] = "ฮธ",
+ ["theta.alt"] = "ฯ",
+ ["upsilon"] = "ฯ
",
+ ["xi"] = "ฮพ",
+ ["zeta"] = "ฮถ",
+ ["Alpha"] = "ฮ",
+ ["Beta"] = "ฮ",
+ ["Chi"] = "ฮง",
+ ["Delta"] = "ฮ",
+ ["Epsilon"] = "ฮ",
+ ["Eta"] = "ฮ",
+ ["Gamma"] = "ฮ",
+ ["Iota"] = "ฮ",
+ ["Kai"] = "ฯ",
+ ["Kappa"] = "ฮ",
+ ["Lambda"] = "ฮ",
+ ["Mu"] = "ฮ",
+ ["Nu"] = "ฮ",
+ ["Omega"] = "ฮฉ",
+ ["Omicron"] = "ฮ",
+ ["Phi"] = "ฮฆ",
+ ["Pi"] = "ฮ ",
+ ["Psi"] = "ฮจ",
+ ["Rho"] = "ฮก",
+ ["Sigma"] = "ฮฃ",
+ ["Tau"] = "ฮค",
+ ["Theta"] = "ฮ",
+ ["Upsilon"] = "ฮฅ",
+ ["Xi"] = "ฮ",
+ ["Zeta"] = "ฮ",
+ ["aleph"] = "ื",
+ ["alef"] = "ื",
+ ["beth"] = "ื",
+ ["bet"] = "ื",
+ ["gimmel"] = "ื",
+ ["gimel"] = "ื",
+ ["daleth"] = "ื",
+ ["dalet"] = "ื",
+ ["shin"] = "ืฉ",
+ ["AA"] = "๐ธ",
+ ["BB"] = "๐น",
+ ["CC"] = "โ",
+ ["DD"] = "๐ป",
+ ["EE"] = "๐ผ",
+ ["FF"] = "๐ฝ",
+ ["GG"] = "๐พ",
+ ["HH"] = "โ",
+ ["II"] = "๐",
+ ["JJ"] = "๐",
+ ["KK"] = "๐",
+ ["LL"] = "๐",
+ ["MM"] = "๐",
+ ["NN"] = "โ",
+ ["OO"] = "๐",
+ ["PP"] = "โ",
+ ["QQ"] = "โ",
+ ["RR"] = "โ",
+ ["SS"] = "๐",
+ ["TT"] = "๐",
+ ["UU"] = "๐",
+ ["VV"] = "๐",
+ ["WW"] = "๐",
+ ["XX"] = "๐",
+ ["YY"] = "๐",
+ ["ZZ"] = "โค",
+ ["ell"] = "โ",
+ ["planck"] = "โ",
+ ["planck.reduce"] = "โ",
+ ["angstrom"] = "โซ",
+ ["kelvin"] = "โช",
+ ["Re"] = "โ",
+ ["Im"] = "โ",
+ ["dotless.i"] = "๐ค",
+ ["dotless.j"] = "๐ฅ",
+ ---_
+};
+
+symbols.typst_shorthands = {
+ ---+${class}
+ ["bracket.l.double"] = "[|",
+ ["bracket.r.double"] = "|]",
+ ["bar.v.double"] = "||",
+ ["ast.op"] = "*",
+ ["colon.eq"] = ":=",
+ ["colon.double.eq"] = "::=",
+ ["dots.h"] = "...",
+ ["tilde.op"] = "~",
+ ["prime"] = "'",
+ ["minus"] = "-",
+ ["eq.colon"] = "=:",
+ ["eq.not"] = "!=",
+ ["gt.double"] = ">>",
+ ["gt.eq"] = ">=",
+ ["gt.triple"] = ">>>",
+ ["lt.double"] = "<<",
+ ["lt.eq"] = "<=",
+ ["lt.triple"] = "<<<",
+ ["convolve"] = "*",
+ ["arrow.r"] = "->",
+ ["arrow.r.bar"] = "|->",
+ ["arrow.r.double"] = "=>",
+ ["arrow.r.double.bar"] = "|=>",
+ ["arrow.r.double.long"] = "==>",
+ ["arrow.r.long"] = "-->",
+ ["arrow.r.long.squiggly"] = "~~>",
+ ["arrow.r.squiggly"] = "~>",
+ ["arrow.r.tail"] = ">->",
+ ["arrow.r.twohead"] = "->>",
+ ["arrow.l"] = "<-",
+ ["arrow.l.double.long"] = "<==",
+ ["arrow.l.long"] = "<--",
+ ["arrow.l.long.squiggly"] = "<~~",
+ ["arrow.l.squiggly"] = "<~",
+ ["arrow.l.tail"] = "<-<",
+ ["arrow.l.twohead"] = "<<-",
+ ["arrow.l.r"] = "<->",
+ ["arrow.l.r.double"] = "<=>",
+ ["arrow.l.r.double.long"] = "<==>",
+ ["arrow.l.r.long"] = "<->",
+ ---_
+};
+
+symbols.fonts = {
+ ---+${clqss}
+ default = {
+ ["A"] = "๐ด",
+ ["B"] = "๐ต",
+ ["C"] = "๐ถ",
+ ["D"] = "๐ท",
+ ["E"] = "๐ธ",
+ ["F"] = "๐น",
+ ["G"] = "๐บ",
+ ["H"] = "๐ป",
+ ["I"] = "๐ผ",
+ ["J"] = "๐ฝ",
+ ["K"] = "๐พ",
+ ["L"] = "๐ฟ",
+ ["M"] = "๐",
+ ["N"] = "๐",
+ ["O"] = "๐",
+ ["P"] = "๐",
+ ["Q"] = "๐",
+ ["R"] = "๐
",
+ ["S"] = "๐",
+ ["T"] = "๐",
+ ["U"] = "๐",
+ ["V"] = "๐",
+ ["W"] = "๐",
+ ["X"] = "๐",
+ ["Y"] = "๐",
+ ["Z"] = "๐",
+
+ ["a"] = "๐",
+ ["b"] = "๐",
+ ["c"] = "๐",
+ ["d"] = "๐",
+ ["e"] = "๐",
+ ["f"] = "๐",
+ ["g"] = "๐",
+ ["h"] = "๐",
+ ["i"] = "๐",
+ ["j"] = "๐",
+ ["k"] = "๐",
+ ["l"] = "๐",
+ ["m"] = "๐",
+ ["n"] = "๐",
+ ["o"] = "๐",
+ ["p"] = "๐",
+ ["q"] = "๐",
+ ["r"] = "๐",
+ ["s"] = "๐ ",
+ ["t"] = "๐ก",
+ ["u"] = "๐ข",
+ ["v"] = "๐ฃ",
+ ["w"] = "๐ค",
+ ["x"] = "๐ฅ",
+ ["y"] = "๐ฆ",
+ ["z"] = "๐ง",
+ },
+
+ ["mathbf"] = {
+ ["Gamma"] = "๐ช",
+ ["Delta"] = "๐ซ",
+ ["Theta"] = "๐ฏ",
+ ["Lambda"] = "๐ฒ",
+ ["Xi"] = "๐ต",
+ ["Pi"] = "๐ท",
+ ["Sigma"] = "๐บ",
+ ["Upsilon"] = "๐ผ",
+ ["Phi"] = "๐ฝ",
+ ["Psi"] = "๐ฟ",
+ ["Omega"] = "๐",
+
+ ["alpha"] = "๐",
+ ["beta"] = "๐",
+ ["gamma"] = "๐",
+ ["delta"] = "๐
",
+ ["varepsilon"] = "๐",
+ ["zeta"] = "๐",
+ ["eta"] = "๐",
+ ["theta"] = "๐",
+ ["iota"] = "๐",
+ ["kappa"] = "๐",
+ ["lambda"] = "๐",
+ ["mu"] = "๐",
+ ["nu"] = "๐",
+ ["xi"] = "๐",
+ ["pi"] = "๐",
+ ["rho"] = "๐",
+ ["varsigma"] = "๐",
+ ["sigma"] = "๐",
+ ["tau"] = "๐",
+ ["upsilon"] = "๐",
+ ["varphi"] = "๐",
+ ["chi"] = "๐",
+ ["psi"] = "๐",
+ ["omega"] = "๐",
+ ["epsilon"] = "๐",
+ ["vartheta"] = "๐",
+ ["phi"] = "๐",
+ ["varrho"] = "๐ ",
+ ["varpi"] = "๐ก",
+
+ ["A"] = "๐",
+ ["B"] = "๐",
+ ["C"] = "๐",
+ ["D"] = "๐",
+ ["E"] = "๐",
+ ["F"] = "๐
",
+ ["G"] = "๐",
+ ["H"] = "๐",
+ ["I"] = "๐",
+ ["J"] = "๐",
+ ["K"] = "๐",
+ ["L"] = "๐",
+ ["M"] = "๐",
+ ["N"] = "๐",
+ ["O"] = "๐",
+ ["P"] = "๐",
+ ["Q"] = "๐",
+ ["R"] = "๐",
+ ["S"] = "๐",
+ ["T"] = "๐",
+ ["U"] = "๐",
+ ["V"] = "๐",
+ ["W"] = "๐",
+ ["X"] = "๐",
+ ["Y"] = "๐",
+ ["Z"] = "๐",
+
+ ["a"] = "๐",
+ ["b"] = "๐",
+ ["c"] = "๐",
+ ["d"] = "๐",
+ ["e"] = "๐",
+ ["f"] = "๐",
+ ["g"] = "๐ ",
+ ["h"] = "๐ก",
+ ["i"] = "๐ข",
+ ["j"] = "๐ฃ",
+ ["k"] = "๐ค",
+ ["l"] = "๐ฅ",
+ ["m"] = "๐ฆ",
+ ["n"] = "๐ง",
+ ["o"] = "๐จ",
+ ["p"] = "๐ฉ",
+ ["q"] = "๐ช",
+ ["r"] = "๐ซ",
+ ["s"] = "๐ฌ",
+ ["t"] = "๐ญ",
+ ["u"] = "๐ฎ",
+ ["v"] = "๐ฏ",
+ ["w"] = "๐ฐ",
+ ["x"] = "๐ฑ",
+ ["y"] = "๐ฒ",
+ ["z"] = "๐ณ",
+
+ ["0"] = "๐",
+ ["1"] = "๐",
+ ["2"] = "๐",
+ ["3"] = "๐",
+ ["4"] = "๐",
+ ["5"] = "๐",
+ ["6"] = "๐",
+ ["7"] = "๐",
+ ["8"] = "๐",
+ ["9"] = "๐",
+ },
+
+ ["mathbfit"] = {
+ ["Gamma"] = "๐",
+ ["Delta"] = "๐",
+ ["Theta"] = "๐ฃ",
+ ["Lambda"] = "๐ฆ",
+ ["Xi"] = "๐ฉ",
+ ["Pi"] = "๐ซ",
+ ["Sigma"] = "๐ฎ",
+ ["Upsilon"] = "๐ฐ",
+ ["Phi"] = "๐ฑ",
+ ["Psi"] = "๐ณ",
+ ["alpha"] = "๐ถ",
+ ["Omega"] = "๐ด",
+
+ ["beta"] = "๐ท",
+ ["gamma"] = "๐ธ",
+ ["delta"] = "๐น",
+ ["varepsilon"] = "๐บ",
+ ["zeta"] = "๐ป",
+ ["eta"] = "๐ผ",
+ ["theta"] = "๐ฝ",
+ ["iota"] = "๐พ",
+ ["kappa"] = "๐ฟ",
+ ["lambda"] = "๐",
+ ["mu"] = "๐",
+ ["nu"] = "๐",
+ ["xi"] = "๐",
+ ["pi"] = "๐
",
+ ["rho"] = "๐",
+ ["varsigma"] = "๐",
+ ["sigma"] = "๐",
+ ["tau"] = "๐",
+ ["upsilon"] = "๐",
+ ["varphi"] = "๐",
+ ["chi"] = "๐",
+ ["psi"] = "๐",
+ ["omega"] = "๐",
+ ["epsilon"] = "๐",
+ ["vartheta"] = "๐",
+ ["phi"] = "๐",
+ ["varrho"] = "๐",
+ ["varpi"] = "๐",
+
+ ["A"] = "๐จ",
+ ["B"] = "๐ฉ",
+ ["C"] = "๐ช",
+ ["D"] = "๐ซ",
+ ["E"] = "๐ฌ",
+ ["F"] = "๐ญ",
+ ["G"] = "๐ฎ",
+ ["H"] = "๐ฏ",
+ ["I"] = "๐ฐ",
+ ["J"] = "๐ฑ",
+ ["K"] = "๐ฒ",
+ ["L"] = "๐ณ",
+ ["M"] = "๐ด",
+ ["N"] = "๐ต",
+ ["O"] = "๐ถ",
+ ["P"] = "๐ท",
+ ["Q"] = "๐ธ",
+ ["R"] = "๐น",
+ ["S"] = "๐บ",
+ ["T"] = "๐ป",
+ ["U"] = "๐ผ",
+ ["V"] = "๐ฝ",
+ ["W"] = "๐พ",
+ ["X"] = "๐ฟ",
+ ["Y"] = "๐",
+ ["Z"] = "๐",
+
+ ["a"] = "๐",
+ ["b"] = "๐",
+ ["c"] = "๐",
+ ["d"] = "๐
",
+ ["e"] = "๐",
+ ["f"] = "๐",
+ ["g"] = "๐",
+ ["h"] = "๐",
+ ["i"] = "๐",
+ ["j"] = "๐",
+ ["k"] = "๐",
+ ["l"] = "๐",
+ ["m"] = "๐",
+ ["n"] = "๐",
+ ["o"] = "๐",
+ ["p"] = "๐",
+ ["q"] = "๐",
+ ["r"] = "๐",
+ ["s"] = "๐",
+ ["t"] = "๐",
+ ["u"] = "๐",
+ ["v"] = "๐",
+ ["w"] = "๐",
+ ["x"] = "๐",
+ ["y"] = "๐",
+ ["z"] = "๐",
+ },
+
+ ["mathcal"] = {
+ ["A"] = "๐",
+ ["B"] = "โฌ",
+ ["C"] = "๐",
+ ["D"] = "๐",
+ ["E"] = "โฐ",
+ ["F"] = "โฑ",
+ ["G"] = "๐ข",
+ ["H"] = "โ",
+ ["I"] = "โ",
+ ["J"] = "๐ฅ",
+ ["K"] = "๐ฆ",
+ ["L"] = "โ",
+ ["M"] = "โณ",
+ ["N"] = "๐ฉ",
+ ["O"] = "๐ช",
+ ["P"] = "๐ซ",
+ ["Q"] = "๐ฌ",
+ ["R"] = "โ",
+ ["S"] = "๐ฎ",
+ ["T"] = "๐ฏ",
+ ["U"] = "๐ฐ",
+ ["V"] = "๐ฑ",
+ ["W"] = "๐ฒ",
+ ["X"] = "๐ณ",
+ ["Y"] = "๐ด",
+ ["Z"] = "๐ต",
+
+ ["a"] = "๐ถ",
+ ["b"] = "๐ท",
+ ["c"] = "๐ธ",
+ ["d"] = "๐น",
+ ["e"] = "โฏ",
+ ["f"] = "๐ป",
+ ["g"] = "โ",
+ ["h"] = "๐ฝ",
+ ["i"] = "๐พ",
+ ["j"] = "๐ฟ",
+ ["k"] = "๐",
+ ["l"] = "๐",
+ ["m"] = "๐",
+ ["n"] = "๐",
+ ["o"] = "โด",
+ ["p"] = "๐
",
+ ["q"] = "๐",
+ ["r"] = "๐",
+ ["s"] = "๐",
+ ["t"] = "๐",
+ ["u"] = "๐",
+ ["v"] = "๐",
+ ["w"] = "๐",
+ ["x"] = "๐",
+ ["y"] = "๐",
+ ["z"] = "๐",
+ },
+
+ ["mathbfscr"] = {
+ ["A"] = "๐",
+ ["B"] = "๐",
+ ["C"] = "๐",
+ ["D"] = "๐",
+ ["E"] = "๐",
+ ["F"] = "๐",
+ ["G"] = "๐",
+ ["H"] = "๐",
+ ["I"] = "๐",
+ ["J"] = "๐",
+ ["K"] = "๐",
+ ["L"] = "๐",
+ ["M"] = "๐",
+ ["N"] = "๐",
+ ["O"] = "๐",
+ ["P"] = "๐",
+ ["Q"] = "๐ ",
+ ["R"] = "๐ก",
+ ["S"] = "๐ข",
+ ["T"] = "๐ฃ",
+ ["U"] = "๐ค",
+ ["V"] = "๐ฅ",
+ ["W"] = "๐ฆ",
+ ["X"] = "๐ง",
+ ["Y"] = "๐จ",
+ ["Z"] = "๐ฉ",
+
+ ["a"] = "๐ช",
+ ["b"] = "๐ซ",
+ ["c"] = "๐ฌ",
+ ["d"] = "๐ญ",
+ ["e"] = "๐ฎ",
+ ["f"] = "๐ฏ",
+ ["g"] = "๐ฐ",
+ ["h"] = "๐ฑ",
+ ["i"] = "๐ฒ",
+ ["j"] = "๐ณ",
+ ["k"] = "๐ด",
+ ["l"] = "๐ต",
+ ["m"] = "๐ถ",
+ ["n"] = "๐ท",
+ ["o"] = "๐ธ",
+ ["p"] = "๐น",
+ ["q"] = "๐บ",
+ ["r"] = "๐ป",
+ ["s"] = "๐ผ",
+ ["t"] = "๐ฝ",
+ ["u"] = "๐พ",
+ ["v"] = "๐ฟ",
+ ["w"] = "๐",
+ ["x"] = "๐",
+ ["y"] = "๐",
+ ["z"] = "๐",
+ },
+
+ ["mathfrak"] = {
+ ["A"] = "๐",
+ ["B"] = "๐
",
+ ["C"] = "โญ",
+ ["D"] = "๐",
+ ["E"] = "๐",
+ ["F"] = "๐",
+ ["G"] = "๐",
+ ["H"] = "โ",
+ ["I"] = "๐ด",
+ ["J"] = "๐",
+ ["K"] = "๐",
+ ["L"] = "๐",
+ ["M"] = "๐",
+ ["N"] = "๐",
+ ["O"] = "๐",
+ ["P"] = "๐",
+ ["Q"] = "๐",
+ ["S"] = "๐",
+ ["T"] = "๐",
+ ["U"] = "๐",
+ ["V"] = "๐",
+ ["W"] = "๐",
+ ["X"] = "๐",
+ ["Y"] = "๐",
+ ["Z"] = "โจ",
+
+ ["a"] = "๐",
+ ["b"] = "๐",
+ ["c"] = "๐ ",
+ ["d"] = "๐ก",
+ ["e"] = "๐ข",
+ ["f"] = "๐ฃ",
+ ["g"] = "๐ค",
+ ["h"] = "๐ฅ",
+ ["i"] = "๐ฆ",
+ ["j"] = "๐ง",
+ ["k"] = "๐จ",
+ ["l"] = "๐ฉ",
+ ["m"] = "๐ช",
+ ["n"] = "๐ซ",
+ ["o"] = "๐ฌ",
+ ["p"] = "๐ญ",
+ ["q"] = "๐ฎ",
+ ["r"] = "๐ฏ",
+ ["s"] = "๐ฐ",
+ ["t"] = "๐ฑ",
+ ["u"] = "๐ฒ",
+ ["v"] = "๐ณ",
+ ["w"] = "๐ด",
+ ["x"] = "๐ต",
+ ["y"] = "๐ถ",
+ ["z"] = "๐ท",
+ },
+
+ ["mathbb"] = {
+ ["A"] = "๐ธ",
+ ["B"] = "๐น",
+ ["C"] = "โ",
+ ["D"] = "๐ป",
+ ["E"] = "๐ผ",
+ ["F"] = "๐ฝ",
+ ["G"] = "๐พ",
+ ["H"] = "โ",
+ ["I"] = "๐",
+ ["J"] = "๐",
+ ["K"] = "๐",
+ ["L"] = "๐",
+ ["M"] = "๐",
+ ["N"] = "โ",
+ ["O"] = "๐",
+ ["P"] = "โ",
+ ["Q"] = "โ",
+ ["R"] = "โ",
+ ["S"] = "๐",
+ ["T"] = "๐",
+ ["U"] = "๐",
+ ["V"] = "๐",
+ ["W"] = "๐",
+ ["X"] = "๐",
+ ["Y"] = "๐",
+ ["Z"] = "โค",
+
+ ["a"] = "๐",
+ ["b"] = "๐",
+ ["c"] = "๐",
+ ["d"] = "๐",
+ ["e"] = "๐",
+ ["f"] = "๐",
+ ["g"] = "๐",
+ ["h"] = "๐",
+ ["i"] = "๐",
+ ["j"] = "๐",
+ ["k"] = "๐",
+ ["l"] = "๐",
+ ["m"] = "๐",
+ ["n"] = "๐",
+ ["o"] = "๐ ",
+ ["p"] = "๐ก",
+ ["q"] = "๐ข",
+ ["r"] = "๐ฃ",
+ ["s"] = "๐ค",
+ ["t"] = "๐ฅ",
+ ["u"] = "๐ฆ",
+ ["v"] = "๐ง",
+ ["w"] = "๐จ",
+ ["x"] = "๐ฉ",
+ ["y"] = "๐ช",
+ ["z"] = "๐ซ",
+
+ ["0"] = "๐",
+ ["1"] = "๐",
+ ["2"] = "๐",
+ ["3"] = "๐",
+ ["4"] = "๐",
+ ["5"] = "๐",
+ ["6"] = "๐",
+ ["7"] = "๐",
+ ["8"] = "๐ ",
+ ["9"] = "๐ก",
+ },
+
+ ["mathbffrak"] = {
+ ["A"] = "๐ฌ",
+ ["B"] = "๐ญ",
+ ["C"] = "๐ฎ",
+ ["D"] = "๐ฏ",
+ ["E"] = "๐ฐ",
+ ["F"] = "๐ฑ",
+ ["G"] = "๐ฒ",
+ ["H"] = "๐ณ",
+ ["I"] = "๐ด",
+ ["J"] = "๐ต",
+ ["K"] = "๐ถ",
+ ["L"] = "๐ท",
+ ["M"] = "๐ธ",
+ ["N"] = "๐น",
+ ["O"] = "๐บ",
+ ["P"] = "๐ป",
+ ["Q"] = "๐ผ",
+ ["R"] = "๐ฝ",
+ ["S"] = "๐พ",
+ ["T"] = "๐ฟ",
+ ["U"] = "๐",
+ ["V"] = "๐",
+ ["W"] = "๐",
+ ["X"] = "๐",
+ ["Y"] = "๐",
+ ["Z"] = "๐
",
+
+ ["a"] = "๐",
+ ["b"] = "๐",
+ ["c"] = "๐",
+ ["d"] = "๐",
+ ["e"] = "๐",
+ ["f"] = "๐",
+ ["g"] = "๐",
+ ["h"] = "๐",
+ ["i"] = "๐",
+ ["j"] = "๐",
+ ["k"] = "๐",
+ ["l"] = "๐",
+ ["m"] = "๐",
+ ["n"] = "๐",
+ ["o"] = "๐",
+ ["p"] = "๐",
+ ["q"] = "๐",
+ ["r"] = "๐",
+ ["s"] = "๐",
+ ["t"] = "๐",
+ ["u"] = "๐",
+ ["v"] = "๐",
+ ["w"] = "๐",
+ ["x"] = "๐",
+ ["y"] = "๐",
+ ["z"] = "๐",
+
+ ["0"] = "๐",
+ ["1"] = "๐",
+ ["2"] = "๐",
+ ["3"] = "๐",
+ ["4"] = "๐",
+ ["5"] = "๐",
+ ["6"] = "๐",
+ ["7"] = "๐",
+ ["8"] = "๐",
+ ["9"] = "๐",
+ },
+
+ ["mathsf"] = {
+ ["A"] = "๐ ",
+ ["B"] = "๐ก",
+ ["C"] = "๐ข",
+ ["D"] = "๐ฃ",
+ ["E"] = "๐ค",
+ ["F"] = "๐ฅ",
+ ["G"] = "๐ฆ",
+ ["H"] = "๐ง",
+ ["I"] = "๐จ",
+ ["J"] = "๐ฉ",
+ ["K"] = "๐ช",
+ ["L"] = "๐ซ",
+ ["M"] = "๐ฌ",
+ ["N"] = "๐ญ",
+ ["O"] = "๐ฎ",
+ ["P"] = "๐ฏ",
+ ["Q"] = "๐ฐ",
+ ["R"] = "๐ฑ",
+ ["S"] = "๐ฒ",
+ ["T"] = "๐ณ",
+ ["U"] = "๐ด",
+ ["V"] = "๐ต",
+ ["W"] = "๐ถ",
+ ["X"] = "๐ท",
+ ["Y"] = "๐ธ",
+ ["Z"] = "๐น",
+
+ ["a"] = "๐บ",
+ ["b"] = "๐ป",
+ ["c"] = "๐ผ",
+ ["d"] = "๐ฝ",
+ ["e"] = "๐พ",
+ ["f"] = "๐ฟ",
+ ["g"] = "๐",
+ ["h"] = "๐",
+ ["i"] = "๐",
+ ["j"] = "๐",
+ ["k"] = "๐",
+ ["l"] = "๐
",
+ ["m"] = "๐",
+ ["n"] = "๐",
+ ["o"] = "๐",
+ ["p"] = "๐",
+ ["q"] = "๐",
+ ["r"] = "๐",
+ ["s"] = "๐",
+ ["t"] = "๐",
+ ["u"] = "๐",
+ ["v"] = "๐",
+ ["w"] = "๐",
+ ["x"] = "๐",
+ ["y"] = "๐",
+ ["z"] = "๐",
+
+ ["0"] = "๐ข",
+ ["1"] = "๐ฃ",
+ ["2"] = "๐ค",
+ ["3"] = "๐ฅ",
+ ["4"] = "๐ฆ",
+ ["5"] = "๐ง",
+ ["6"] = "๐จ",
+ ["7"] = "๐ฉ",
+ ["8"] = "๐ช",
+ ["9"] = "๐ซ",
+ },
+
+ ["mathsfbf"] = {
+ ["Gamma"] = "๐",
+ ["Delta"] = "๐",
+ ["Theta"] = "๐",
+ ["Lambda"] = "๐ ",
+ ["Xi"] = "๐ฃ",
+ ["Pi"] = "๐ฅ",
+ ["Sigma"] = "๐จ",
+ ["Upsilon"] = "๐ช",
+ ["Phi"] = "๐ซ",
+ ["Psi"] = "๐ญ",
+ ["Omega"] = "๐ฎ",
+
+ ["alpha"] = "๐ฐ",
+ ["beta"] = "๐ฑ",
+ ["gamma"] = "๐ฒ",
+ ["delta"] = "๐ณ",
+ ["varepsilon"] = "๐ด",
+ ["zeta"] = "๐ต",
+ ["eta"] = "๐ถ",
+ ["theta"] = "๐ท",
+ ["iota"] = "๐ธ",
+ ["kappa"] = "๐น",
+ ["lambda"] = "๐บ",
+ ["mu"] = "๐ป",
+ ["nu"] = "๐ผ",
+ ["xi"] = "๐ฝ",
+ ["pi"] = "๐ฟ",
+ ["rho"] = "๐",
+ ["varsigma"] = "๐",
+ ["sigma"] = "๐",
+ ["tau"] = "๐",
+ ["upsilon"] = "๐",
+ ["varphi"] = "๐
",
+ ["chi"] = "๐",
+ ["psi"] = "๐",
+ ["omega"] = "๐",
+ ["epsilon"] = "๐",
+ ["vartheta"] = "๐",
+ ["phi"] = "๐",
+ ["varrho"] = "๐",
+ ["varpi"] = "๐",
+
+ ["A"] = "๐",
+ ["B"] = "๐",
+ ["C"] = "๐",
+ ["D"] = "๐",
+ ["E"] = "๐",
+ ["F"] = "๐",
+ ["G"] = "๐",
+ ["H"] = "๐",
+ ["I"] = "๐",
+ ["J"] = "๐",
+ ["K"] = "๐",
+ ["L"] = "๐",
+ ["M"] = "๐ ",
+ ["N"] = "๐ก",
+ ["O"] = "๐ข",
+ ["P"] = "๐ฃ",
+ ["Q"] = "๐ค",
+ ["R"] = "๐ฅ",
+ ["S"] = "๐ฆ",
+ ["T"] = "๐ง",
+ ["U"] = "๐จ",
+ ["V"] = "๐ฉ",
+ ["W"] = "๐ช",
+ ["X"] = "๐ซ",
+ ["Y"] = "๐ฌ",
+ ["Z"] = "๐ญ",
+
+ ["a"] = "๐ฎ",
+ ["b"] = "๐ฏ",
+ ["c"] = "๐ฐ",
+ ["d"] = "๐ฑ",
+ ["e"] = "๐ฒ",
+ ["f"] = "๐ณ",
+ ["g"] = "๐ด",
+ ["h"] = "๐ต",
+ ["i"] = "๐ถ",
+ ["j"] = "๐ท",
+ ["k"] = "๐ธ",
+ ["l"] = "๐น",
+ ["m"] = "๐บ",
+ ["n"] = "๐ป",
+ ["o"] = "๐ผ",
+ ["p"] = "๐ฝ",
+ ["q"] = "๐พ",
+ ["r"] = "๐ฟ",
+ ["s"] = "๐",
+ ["t"] = "๐",
+ ["u"] = "๐",
+ ["v"] = "๐",
+ ["w"] = "๐",
+ ["x"] = "๐
",
+ ["y"] = "๐",
+ ["z"] = "๐",
+
+ ["0"] = "๐ฌ",
+ ["1"] = "๐ญ",
+ ["2"] = "๐ฎ",
+ ["3"] = "๐ฏ",
+ ["4"] = "๐ฐ",
+ ["5"] = "๐ฑ",
+ ["6"] = "๐ฒ",
+ ["7"] = "๐ณ",
+ ["8"] = "๐ด",
+ ["9"] = "๐ต",
+ },
+
+ ["mathsfit"] = {
+ ["A"] = "๐",
+ ["B"] = "๐",
+ ["C"] = "๐",
+ ["D"] = "๐",
+ ["E"] = "๐",
+ ["F"] = "๐",
+ ["G"] = "๐",
+ ["H"] = "๐",
+ ["I"] = "๐",
+ ["J"] = "๐",
+ ["K"] = "๐",
+ ["L"] = "๐",
+ ["M"] = "๐",
+ ["N"] = "๐",
+ ["O"] = "๐",
+ ["P"] = "๐",
+ ["Q"] = "๐",
+ ["R"] = "๐",
+ ["S"] = "๐",
+ ["T"] = "๐",
+ ["U"] = "๐",
+ ["V"] = "๐",
+ ["W"] = "๐",
+ ["X"] = "๐",
+ ["Y"] = "๐ ",
+ ["Z"] = "๐ก",
+
+ ["a"] = "๐ข",
+ ["b"] = "๐ฃ",
+ ["c"] = "๐ค",
+ ["d"] = "๐ฅ",
+ ["e"] = "๐ฆ",
+ ["f"] = "๐ง",
+ ["g"] = "๐จ",
+ ["h"] = "๐ฉ",
+ ["i"] = "๐ช",
+ ["j"] = "๐ซ",
+ ["k"] = "๐ฌ",
+ ["l"] = "๐ญ",
+ ["m"] = "๐ฎ",
+ ["n"] = "๐ฏ",
+ ["o"] = "๐ฐ",
+ ["p"] = "๐ฑ",
+ ["q"] = "๐ฒ",
+ ["r"] = "๐ณ",
+ ["s"] = "๐ด",
+ ["t"] = "๐ต",
+ ["u"] = "๐ถ",
+ ["v"] = "๐ท",
+ ["w"] = "๐ธ",
+ ["x"] = "๐น",
+ ["y"] = "๐บ",
+ ["z"] = "๐ป",
+ },
+
+ ["mathsfbfit"] = {
+ ["Gamma"] = "๐",
+ ["Delta"] = "๐",
+ ["Pi"] = "๐",
+ ["Sigma"] = "๐ข",
+ ["Upsilon"] = "๐ค",
+ ["Phi"] = "๐ฅ",
+ ["Psi"] = "๐ง",
+ ["Omega"] = "๐จ",
+
+ ["alpha"] = "๐ช",
+ ["beta"] = "๐ซ",
+ ["gamma"] = "๐ฌ",
+ ["delta"] = "๐ญ",
+ ["varepsilon"] = "๐ฎ",
+ ["zeta"] = "๐ฏ",
+ ["eta"] = "๐ฐ",
+ ["theta"] = "๐ฑ",
+ ["iota"] = "๐ฒ",
+ ["kappa"] = "๐ณ",
+ ["lambda"] = "๐ด",
+ ["mu"] = "๐ต",
+ ["nu"] = "๐ถ",
+ ["xi"] = "๐ท",
+ ["pi"] = "๐น",
+ ["rho"] = "๐บ",
+ ["varsigma"] = "๐ป",
+ ["sigma"] = "๐ผ",
+ ["tau"] = "๐ฝ",
+ ["upsilon"] = "๐พ",
+ ["varphi"] = "๐ฟ",
+ ["chi"] = "๐",
+ ["psi"] = "๐",
+ ["omega"] = "๐",
+ ["epsilon"] = "๐",
+ ["vartheta"] = "๐
",
+ ["phi"] = "๐",
+ ["varrho"] = "๐",
+ ["varpi"] = "๐",
+
+ ["A"] = "๐ผ",
+ ["B"] = "๐ฝ",
+ ["C"] = "๐พ",
+ ["D"] = "๐ฟ",
+ ["E"] = "๐",
+ ["F"] = "๐",
+ ["G"] = "๐",
+ ["H"] = "๐",
+ ["I"] = "๐",
+ ["J"] = "๐
",
+ ["K"] = "๐",
+ ["L"] = "๐",
+ ["M"] = "๐",
+ ["N"] = "๐",
+ ["O"] = "๐",
+ ["P"] = "๐",
+ ["Q"] = "๐",
+ ["R"] = "๐",
+ ["S"] = "๐",
+ ["T"] = "๐",
+ ["U"] = "๐",
+ ["V"] = "๐",
+ ["W"] = "๐",
+ ["X"] = "๐",
+ ["Y"] = "๐",
+ ["Z"] = "๐",
+
+ ["a"] = "๐",
+ ["b"] = "๐",
+ ["c"] = "๐",
+ ["d"] = "๐",
+ ["e"] = "๐",
+ ["f"] = "๐",
+ ["g"] = "๐",
+ ["h"] = "๐",
+ ["i"] = "๐",
+ ["j"] = "๐",
+ ["k"] = "๐ ",
+ ["l"] = "๐ก",
+ ["m"] = "๐ข",
+ ["n"] = "๐ฃ",
+ ["o"] = "๐ค",
+ ["p"] = "๐ฅ",
+ ["q"] = "๐ฆ",
+ ["r"] = "๐ง",
+ ["s"] = "๐จ",
+ ["t"] = "๐ฉ",
+ ["u"] = "๐ช",
+ ["v"] = "๐ซ",
+ ["w"] = "๐ฌ",
+ ["x"] = "๐ญ",
+ ["y"] = "๐ฎ",
+ ["z"] = "๐ฏ",
+
+ ["0"] = "๐ข",
+ ["1"] = "๐ฃ",
+ ["2"] = "๐ค",
+ ["3"] = "๐ฅ",
+ ["4"] = "๐ฆ",
+ ["5"] = "๐ง",
+ ["6"] = "๐จ",
+ ["7"] = "๐ฉ",
+ ["8"] = "๐ช",
+ ["9"] = "๐ซ",
+ },
+
+ ["mathtt"] = {
+ ["A"] = "๐ฐ",
+ ["B"] = "๐ฑ",
+ ["C"] = "๐ฒ",
+ ["D"] = "๐ณ",
+ ["E"] = "๐ด",
+ ["F"] = "๐ต",
+ ["G"] = "๐ถ",
+ ["H"] = "๐ท",
+ ["I"] = "๐ธ",
+ ["J"] = "๐น",
+ ["K"] = "๐บ",
+ ["L"] = "๐ป",
+ ["M"] = "๐ผ",
+ ["N"] = "๐ฝ",
+ ["O"] = "๐พ",
+ ["P"] = "๐ฟ",
+ ["Q"] = "๐",
+ ["R"] = "๐",
+ ["S"] = "๐",
+ ["T"] = "๐",
+ ["U"] = "๐",
+ ["V"] = "๐
",
+ ["W"] = "๐",
+ ["X"] = "๐",
+ ["Y"] = "๐",
+ ["Z"] = "๐",
+
+ ["a"] = "๐",
+ ["b"] = "๐",
+ ["c"] = "๐",
+ ["d"] = "๐",
+ ["e"] = "๐",
+ ["f"] = "๐",
+ ["g"] = "๐",
+ ["h"] = "๐",
+ ["i"] = "๐",
+ ["j"] = "๐",
+ ["k"] = "๐",
+ ["l"] = "๐",
+ ["m"] = "๐",
+ ["n"] = "๐",
+ ["o"] = "๐",
+ ["p"] = "๐",
+ ["q"] = "๐",
+ ["r"] = "๐",
+ ["s"] = "๐",
+ ["t"] = "๐",
+ ["u"] = "๐",
+ ["v"] = "๐",
+ ["w"] = "๐ ",
+ ["x"] = "๐ก",
+ ["y"] = "๐ข",
+ ["z"] = "๐ฃ",
+
+ ["0"] = "๐ถ",
+ ["1"] = "๐ท",
+ ["2"] = "๐ธ",
+ ["3"] = "๐น",
+ ["4"] = "๐บ",
+ ["5"] = "๐ป",
+ ["6"] = "๐ผ",
+ ["7"] = "๐ฝ",
+ ["8"] = "๐พ",
+ ["9"] = "๐ฟ",
+ }
+ ---_
+}
+
+symbols.tostring = function (font, text)
+ local _o = "";
+
+ for letter in string.gmatch(text, ".") do
+ if symbols.fonts and symbols.fonts[font] and symbols.fonts[font][letter] then
+ _o = _o .. symbols.fonts[font][letter];
+ elseif type(symbols[font]) == "table" and symbols[font][letter] then
+ _o = _o .. symbols[font][letter];
+ else
+ _o = _o .. letter;
+ end
+ end
+
+ return _o;
+end
+
+return symbols;
diff --git a/lua/markview/treesitter.lua b/lua/markview/treesitter.lua
deleted file mode 100644
index 4b00687..0000000
--- a/lua/markview/treesitter.lua
+++ /dev/null
@@ -1,82 +0,0 @@
-local ts = {};
-
---- Fixes indentation of the provided text
----
---- ```query
---- (section
---- (atx_heading)) @fold
---- (#set! @fold)
---- ```
----
---- Will become,
----
---- ```query
---- (section
---- (atx_heading)) @fold
---- (#set! @fold)
---- ```
----@param text string
----@return string
-local fix_indent = function (text)
- local _l = "";
- local leading_spaces;
-
- if text:sub(-1) ~= "\n" then text = text .. "\n" end
-
- for line in text:gmatch("(.-)\n") do
- if not leading_spaces then
- leading_spaces = line:match("^%s+");
- end
-
- line = line:gsub("^" .. leading_spaces, "");
- _l = _l .. line .. "\n";
- end
-
- _l = _l:gsub("(\n)$", "");
-
- return _l;
-end
-
----@param opts markview.conf.injections
-ts.inject = function (opts)
- if not opts or opts.enable == false or not vim.islist(opts.languages) then
- return;
- end
-
- --- Iterate over all the languages
- for lang, conf in pairs(opts.languages) do
- if conf.enable == false then
- goto continue;
- end
-
- if conf.overwrite == true then
- pcall(vim.treesitter.query.set, lang, conf.query);
- return;
- end
-
- local _q = "";
-
- --- Get the default injections file
- local _f = vim.treesitter.query.get_files(lang, "injections");
-
- for _, file in ipairs(_f) do
- local _r = io.open(file, "r");
-
- --- Read all the contents from the file and close it
- --- If nil, then no injections exist for this language
- if _r then
- _q = _q .. _r:read("*all") .. "\n";
- _r:close();
- end
- end
-
- --- Append the new query
- --- TODO, Fix indentation
- _q = _q .. fix_indent(conf.query);
- pcall(vim.treesitter.query.set, lang, _q);
-
- ::continue::
- end
-end
-
-return ts;
diff --git a/lua/markview/typst_renderer.lua b/lua/markview/typst_renderer.lua
deleted file mode 100644
index e69de29..0000000
diff --git a/lua/markview/utils.lua b/lua/markview/utils.lua
index 143069b..56ef101 100644
--- a/lua/markview/utils.lua
+++ b/lua/markview/utils.lua
@@ -1,5 +1,63 @@
local utils = {};
+--- Checks if a parser is available or not
+---@param parser_name string
+---@return boolean
+utils.parser_installed = function (parser_name)
+ local has_ts, parsers = pcall(require, "nvim-treesitter.parsers");
+
+ if has_ts == false then
+ --- `nvim-treesitter` not available.
+ return false;
+ elseif parsers.has_parser(parser_name) == true then
+ --- Parser installed via `nvim-treesitter`.
+ return true;
+ elseif pcall(vim.treesitter.query.get, parser_name, "highlights") ~= nil then
+ --- Parser installed manually.
+ return true;
+ end
+
+ return false;
+end
+
+utils.within_range = function (range, pos)
+ if pos.row_start < range.row_start then
+ return false;
+ elseif pos.row_end > range.row_end then
+ return false;
+ elseif
+ (pos.row_start == range.row_start and pos.row_end == range.row_end) and
+ (pos.col_start < range.col_start or pos.col_end > range.col_end)
+ then
+ return false;
+ end
+
+ return true;
+end
+
+--- Escapes magic characters from a string
+---@param input string
+---@return string
+utils.escape_string = function (input)
+ input = input:gsub("%%", "%%%%");
+
+ input = input:gsub("%(", "%%(");
+ input = input:gsub("%)", "%%)");
+
+ input = input:gsub("%.", "%%.");
+ input = input:gsub("%+", "%%+");
+ input = input:gsub("%-", "%%-");
+ input = input:gsub("%*", "%%*");
+ input = input:gsub("%?", "%%?");
+ input = input:gsub("%^", "%%^");
+ input = input:gsub("%$", "%%$");
+
+ input = input:gsub("%[", "%%[");
+ input = input:gsub("%]", "%%]");
+
+ return input;
+end
+
--- Clamps a value between a range
---@param val number
---@param min number
@@ -31,6 +89,23 @@ utils.hl_exists = function (hl)
return false;
end
+--- Checks if a highlight group exists or not
+---@param hl string?
+---@return string?
+utils.set_hl = function (hl)
+ if type(hl) ~= "string" then
+ return;
+ end
+
+ if vim.fn.hlexists("Markview" .. hl) == 1 then
+ return "Markview" .. hl;
+ elseif vim.fn.hlexists("Markview_" .. hl) == 1 then
+ return "Markview_" .. hl;
+ else
+ return hl;
+ end
+end
+
--- Gets attached windows from a buffer ID
---@param buf integer
---@return integer[]
@@ -46,6 +121,16 @@ utils.find_attached_wins = function (buf)
return attached_wins;
end
+utils.buf_getwin = function (buffer)
+ local wins = vim.fn.win_findbuf(buffer);
+
+ if vim.list_contains(wins, vim.api.nvim_get_current_win()) then
+ return vim.api.nvim_get_current_win();
+ end
+
+ return wins[1];
+end
+
--- Gets the start & stop line for a range from the cursor
---@param buffer integer
---@param window integer
@@ -58,4 +143,266 @@ utils.get_cursor_range = function (buffer, window)
return math.max(0, cursor[1] - 1), math.min(lines, cursor[1]);
end
+utils.virt_len = function (virt_texts)
+ if not virt_texts then
+ return 0;
+ end
+
+ local _l = 0;
+
+ for _, text in ipairs(virt_texts) do
+ _l = _l + vim.fn.strdisplaywidth(text[1]);
+ end
+
+ return _l;
+end
+
+utils.tostatic = function (tbl, opts)
+ if not opts then opts = {}; end
+ local _o = {};
+
+ for k, v in pairs(tbl or {}) do
+ ---@diagnostic disable
+ if
+ pcall(v, unpack(opts.args or {}))
+ then
+ _o[k] = v(unpack(opts.args or {}));
+ ---@diagnostic enable
+ elseif type(v) ~= "function" then
+ _o[k] = v;
+ end
+ end
+
+ return _o;
+end
+
+utils.pattern = function (main_config, txt, opts)
+ --- Checks if we can do pattern matching
+ ---@return boolean
+ local has_pattern = function ()
+ if type(main_config) ~= "table" then
+ return false;
+ elseif vim.islist(main_config.patterns) == false then
+ return false;
+ elseif type(txt) ~= "string" then
+ return false;
+ end
+
+ return true;
+ end
+
+ local spec = require("markview.spec");
+
+ local default = spec.get({ "default" }, { source = main_config, fallback = {}, eval_args = opts.eval_args });
+ --- NOTE, Pattern items can also be dynamic.
+ local patterns = spec.get({ "patterns" }, { source = main_config, fallback = {}, eval_args = opts.eval_args });
+ local custom = {};
+
+ if has_pattern() == false then
+ return default;
+ end
+
+ --- Iterate over the items
+ for _, entry in ipairs(patterns) do
+ if entry.match_string and txt:match(entry.match_string) then
+ --- FIXME, Do we remove the `match_string` entry?
+ custom = entry;
+ break;
+ end
+ end
+
+ --- Oh yeah, the entry can also be dynamic.
+ custom = spec.get({}, { source = custom, eval_args = opts.eval_args });
+ return vim.tbl_deep_extend("force", default, custom);
+end
+
+utils.create_user_command_class = function (config)
+ local class = {};
+
+ class.config = config;
+
+ function class.exec (self, params)
+ local sub = params.fargs[1];
+
+ local function exec_subcommand ()
+ if config.sub_commands == nil then
+ return false;
+ elseif config.sub_commands[sub] == nil then
+ return false;
+ elseif config.sub_commands[sub].action == nil then
+ return false;
+ end
+
+ return true;
+ end
+
+ if sub == nil and self.config.default and self.config.default.action then
+ self.config.default.action(params);
+ elseif exec_subcommand() == true then
+ self.config.sub_commands[sub].action(params);
+ end
+ end
+
+ function class.comp (self, arg_lead, cmdline, cursor_pos)
+ ---+${lua}
+
+ local is_subcommand = function (text)
+ local cmds = vim.tbl_keys(self.config.sub_commands or {});
+ return vim.list_contains(cmds, text);
+ end
+
+ local matches_subcommand = function (text)
+ if is_subcommand(text) then
+ return false;
+ end
+
+ for key, _ in pairs(self.config.sub_commands or {}) do
+ if key:match(text) then
+ return true;
+ end
+ end
+
+ return false;
+ end
+
+ local nargs = 0;
+ local args = {};
+
+ local text = cmdline:sub(0, cursor_pos);
+
+ for arg in text:gmatch("(%S+)") do
+ nargs = nargs + 1;
+ table.insert(args, arg);
+ end
+
+ table.remove(args, 1);
+ nargs = nargs - 1;
+
+ local item;
+
+ if nargs == 0 or (nargs == 1 and matches_subcommand(args[1])) then
+ item = self.config.default;
+ elseif is_subcommand(args[1]) and self.config.sub_commands and self.config.sub_commands[args[1]] then
+ item = self.config.sub_commands[args[1]];
+ else
+ return {};
+ end
+
+ if vim.islist(item.completion) then
+ return item.completion --[[ @as string[] ]];
+ elseif pcall(item.completion, arg_lead, cmdline, cursor_pos) then
+ ---@type string[]
+ return item.completion(arg_lead, cmdline, cursor_pos);
+ end
+ ---_
+ end
+
+ return class;
+end
+
+--- Gets a config from a list of config tables.
+--- NOTE, {name} will be used to index the config.
+---@param config table
+---@param name string
+---@param opts { default: boolean, def_fallback: any?, eval_args: any[], ignore_keys?: any[] }
+---@return any
+utils.match = function (config, name, opts)
+ config = config or {};
+ name = name or "";
+ opts = opts or {};
+
+ local spec = require("markview.spec");
+
+ --- Default configuration
+ local default = {};
+
+ if opts.default ~= false then
+ default = spec.get({ "default" }, vim.tbl_extend("keep", {
+ source = config,
+ fallback = opts.def_fallback
+ }, opts));
+ end
+
+ local match = {};
+
+ local sort_keys = function (values)
+ local w_priority = {};
+ local n_priority = {};
+
+ for k, v in pairs(values or {}) do
+ if type(v) == "table" and type(v.priority) == "number" then
+ table.insert(w_priority, {
+ key = k,
+ priority = v.priority
+ });
+ elseif k ~= "default" and vim.list_contains(opts.ignore_keys or {}, k) == false then
+ table.insert(n_priority, k);
+ end
+ end
+
+ table.sort(w_priority, function (a, b)
+ return a.priority > b.priority;
+ end)
+
+ local keys = {};
+
+ for _, item in ipairs(w_priority) do
+ table.insert(keys, item.key);
+ end
+
+ keys = vim.list_extend(n_priority, keys);
+
+ return keys;
+ end
+
+ local function is_valid (value, pattern)
+ local ignore = opts.ignore_keys or {};
+
+ if vim.list_contains(ignore, pattern) then
+ return false;
+ elseif string.match(value, pattern) then
+ return true;
+ else
+ return false;
+ end
+ end
+
+ --- NOTE, We should sort the keys so that we
+ --- don't get different results every time
+ --- when multiple patterns can be matched.
+ ---
+ ---@type string[]
+ local keys = sort_keys(config or {});
+
+ for _, key in ipairs(keys) do
+ if is_valid(name, key) == true then
+ match = spec.get(
+ { key },
+ vim.tbl_extend("force", opts, { source = config })
+ );
+ break
+ end
+ end
+
+ return vim.tbl_deep_extend("force", default, match);
+end
+
+--- Checks if a string only contains {chars}
+---@param str string
+---@param chars string[]
+---@return boolean
+utils.str_contains = function (str, chars)
+ if type(str) ~= "string" or str == "" then
+ return false;
+ end
+
+ local tmp = str;
+
+ for _, char in ipairs(chars or {}) do
+ tmp = string.gsub(tmp, utils.escape_string(char), "");
+ end
+
+ return string.match(tmp, "^%s*$") ~= nil;
+end
+
return utils;
diff --git a/markview.nvim.wiki b/markview.nvim.wiki
index 9da72aa..b9482e8 160000
--- a/markview.nvim.wiki
+++ b/markview.nvim.wiki
@@ -1 +1 @@
-Subproject commit 9da72aac8da99747cf66129ec470af50686274a8
+Subproject commit b9482e8c3e6ada753934228741b06f3bbb54c87b
diff --git a/plugin/markview.lua b/plugin/markview.lua
index 1e1b6dc..9527ed1 100644
--- a/plugin/markview.lua
+++ b/plugin/markview.lua
@@ -1,329 +1,919 @@
+--- Functionality provider for `markview.nvim`.
+--- Functionalities that are implementated,
+---
+--- + Buffer registration.
+--- + Command.
+--- + Dynamic highlight groups.
+---
+--- **Author**: MD. Mouinul Hossain Shawon (OXY2DEV)
+
local markview = require("markview");
-local utils = require("markview.utils");
-local hls = require("markview.highlights");
-local ts = require("markview.treesitter");
+local spec = require("markview.spec");
+local health = require("markview.health");
-if vim.fn.has("nvim-0.10.0") == 0 then
- vim.notify("[ markview.nvim ]: Neovim version >=0.10 required!", vim.diagnostic.severity.ERROR)
- return;
-end
+health.notify("trace", {
+ level = 1,
+ message = "Start"
+});
----@diagnostic disable
-ts.inject(markview.configuration.injections)
-hls.create(markview.configuration.highlight_groups)
----@diagnostic enable
+--- Was the completion source loaded?
+if vim.g.markview_cmp_loaded == nil then
+ vim.g.markview_cmp_loaded = false;
+end
-local buf_render = function (buffer)
- local lines = vim.api.nvim_buf_line_count(buffer);
- local parsed_content;
+ ------------------------------------------------------------------------------------------
- local mode = vim.api.nvim_get_mode().mode;
+--- Sets up the highlight groups.
+--- Should be called AFTER loading
+--- colorschemes.
+require("markview.highlights").setup();
- if lines < (markview.configuration.max_file_length or 1000) then
- -- Buffer isn't too big. Render everything
- parsed_content = markview.parser.init(buffer, markview.configuration);
+health.notify("trace", {
+ level = 5,
+ message = "Created highlight groups"
+});
- markview.renderer.render(buffer, parsed_content, markview.configuration)
- else
- -- Buffer is too big, render only parts of it
- local cursor = vim.api.nvim_win_get_cursor(0);
- local start = math.max(0, cursor[1] - markview.configuration.render_distance);
- local stop = math.min(lines, cursor[1] + markview.configuration.render_distance);
+--- FIX, Patch for the broken (fenced_code_block) concealment.
+--- Doesn't hide leading spaces before ```.
+vim.treesitter.query.add_directive("conceal-patch!", function (match, _, bufnr, predicate, metadata)
+ ---+${lua}
+ local id = predicate[2];
+ local node = match[id];
- parsed_content = markview.parser.init(buffer, markview.configuration, start, stop);
+ local r_s, c_s, r_e, c_e = node:range();
+ local line = vim.api.nvim_buf_get_lines(bufnr, r_s, r_s + 1, true)[1];
- markview.renderer.render(buffer, parsed_content, markview.configuration)
+ if not line then
+ return;
+ elseif not metadata[id] then
+ metadata[id] = { range = {} };
end
- markview.keymaps.init(buffer, parsed_content, markview.configuration);
+ line = line:sub(c_s + 1, #line);
+ local spaces = line:match("^(%s*)%S"):len();
+
+ metadata[id].range[1] = r_s;
+ metadata[id].range[2] = c_s + spaces;
+ metadata[id].range[3] = r_e;
+ metadata[id].range[4] = c_e;
+
+ metadata[id].conceal = "";
+ ---_
+end);
+
+health.notify("trace", {
+ level = 5,
+ message = {
+ { "Added tree-sitter directive ", "Special" },
+ { " conceal-patch! ", "DiagnosticVirtualTextInfo" }
+ }
+});
+
+ ------------------------------------------------------------------------------------------
- -- Don't do hybrid mode stuff unless needed
- if not markview.configuration.hybrid_modes or not vim.list_contains(markview.configuration.hybrid_modes, mode) then
+--- Registers completion sources for `markview.nvim`.
+local function register_source()
+ ---+${lua}
+
+ ---@type boolean, table
+ local has_cmp, cmp = pcall(require, "cmp");
+
+ if has_cmp == false then
return;
- elseif markview.state.hybrid_mode == false then
+ elseif vim.g.markview_cmp_loaded == false then
+ --- Completion source for `markview.nvim`.
+ local mkv_src = require("cmp-markview");
+ cmp.register_source("cmp-markview", mkv_src);
+
+ vim.g.markview_cmp_loaded = true;
+ end
+
+ local old_src = cmp.get_config().sources or {};
+
+ if vim.list_contains(old_src, "cmp-markview") then
return;
end
- local win = utils.find_attached_wins(buffer)[1];
+ cmp.setup.buffer({
+ sources = vim.list_extend(old_src, {
+ {
+ name = "cmp-markview",
+ keyword_length = 1,
+ options = {}
+ }
+ })
+ });
+
+ health.notify("trace", {
+ level = 5,
+ message = "Registered source for nvim-cmp."
+ });
+ ---_
+end
+
+--- Registers buffers.
+vim.api.nvim_create_autocmd({ "BufAdd", "BufEnter" }, {
+ group = markview.augroup,
+ callback = function (event)
+ ---+${lua}
+ local buffer = event.buf;
+
+ if markview.state.enable == false then
+ --- New buffers shouldn't be registered.
+ return;
+ elseif markview.actions.__is_attached(buffer) == true then
+ --- Already attached to this buffer!
+ return;
+ end
- -- Get the cursor
- local cursor = vim.api.nvim_win_get_cursor(win or 0);
- local node = vim.treesitter.get_node({ bufnr = buffer, pos = { cursor[1] - 1, cursor[2]} });
+ ---@type string, string
+ local bt, ft = vim.bo[buffer].buftype, vim.bo[buffer].filetype;
+ local attach_ft = spec.get({ "preview", "filetypes" }, { fallback = {}, ignore_enable = true });
+ local ignore_bt = spec.get({ "preview", "ignore_buftypes" }, { fallback = {}, ignore_enable = true });
- --- Don't hide stuff on specific nodes
- while node:parent() do
- if vim.list_contains(markview.configuration.ignore_nodes or {}, node:type()) then
+ if vim.list_contains(ignore_bt, bt) == true then
+ --- Ignored buffer type.
+ return;
+ elseif vim.list_contains(attach_ft, ft) == false then
+ --- Ignored file type.
return;
end
- node = node:parent();
+ markview.actions.attach(buffer);
+ register_source();
+ ---_
end
+});
- -- Range to start & stop parsing
- local start = math.max(0, cursor[1] - 1);
- local stop = math.min(lines, cursor[1]);
+local o_timer = vim.uv.new_timer();
- -- Get the contents range to clear
- local under_cursor = markview.parser.init(buffer, markview.configuration, start, stop);
- local clear_range = markview.renderer.get_content_range(under_cursor);
+--- Option changes(e.g. wrap, linebreak)
+vim.api.nvim_create_autocmd({ "OptionSet" }, {
+ group = markview.augroup,
+ callback = function ()
+ ---+${lua}
+ local buffer = vim.api.nvim_get_current_buf();
+ local option = vim.fn.expand("");
- -- Content range was invalid, nothing to clear
- if not clear_range or not clear_range[1] or not clear_range[2] then
- return;
+ local valid_options = { "wrap", "linebreak" };
+
+ ---@type string[] List of modes where preview is shown.
+ local preview_modes = spec.get({ "preview", "modes" }, { fallback = {}, ignore_enable = true });
+ local mode = vim.api.nvim_get_mode().mode;
+
+ if markview.actions.__is_attached(buffer) == false then
+ --- Not attached to a buffer
+ return;
+ elseif markview.actions.__is_enabled(buffer) == false then
+ --- Disabled on this buffer.
+ return;
+ elseif vim.list_contains(preview_modes, mode) == false then
+ --- Wrong mode.
+ return;
+ elseif vim.list_contains(valid_options, option) == false then
+ --- This option shouldn't cause a redraw.
+ return;
+ elseif vim.v.option_old == vim.v.option_new then
+ --- Option value wasn't changed.
+ return;
+ end
+
+ o_timer:stop()
+ o_timer:start(5, 0, vim.schedule_wrap(function ()
+ markview.render(buffer);
+ end));
+ ---_
end
+});
- markview.renderer.clear(buffer, clear_range[1], clear_range[2])
-end
+--- Mode changes.
+vim.api.nvim_create_autocmd({ "ModeChanged" }, {
+ group = markview.augroup,
+ callback = function (event)
+ ---+${lua}
+ local buffer = event.buf;
+ local mode = vim.api.nvim_get_mode().mode;
+ ---@type string[] List of modes where preview is shown.
+ local preview_modes = spec.get({ "preview", "modes" }, { fallback = {}, ignore_enable = true });
+ ---@type string[] List of modes where preview is shown.
+ local hybrid_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {}, ignore_enable = true });
+ local old_mode = vim.v.event.old_mode;
-local redraw_autocmd = function (augroup, buffer, validate)
- local update_events = { "BufEnter", "ModeChanged", "TextChanged" };
+ if markview.actions.__is_attached(buffer) == false then
+ --- Buffer isn't attached!
+ return;
+ elseif markview.actions.__is_enabled(buffer) == false then
+ --- Markview disabled on this buffer.
+ markview.clear(buffer);
+ return;
+ elseif buffer == markview.state.splitview_source then
+ --- Splitview should only update from
+ --- cursor movements or content changes.
+ return;
+ end
- if vim.list_contains(markview.configuration.modes, "n") or vim.list_contains(markview.configuration.modes, "v") then
- table.insert(update_events, "CursorMoved");
- end
+ if vim.list_contains(hybrid_modes, mode) then
+ health.notify("trace", {
+ level = 1,
+ message = string.format("Mode(%s): %d", mode, buffer);
+ });
+ health.__child_indent_in();
+
+ if vim.list_contains(hybrid_modes, old_mode) then
+ --- Switching between 2 hybrid modes.
+ goto callback;
+ else
+ vim.defer_fn(function ()
+ markview.render(buffer);
+ end, 0);
+ end
+ elseif vim.list_contains(preview_modes, mode) then
+ health.notify("trace", {
+ level = 1,
+ message = string.format("Mode(%s): %d", mode, buffer);
+ });
+ health.__child_indent_in();
+
+ --- Preview
+ if vim.list_contains(hybrid_modes, old_mode) then
+ vim.defer_fn(function ()
+ markview.render(buffer);
+ end, 0);
+ elseif vim.list_contains(preview_modes, old_mode) then
+ --- Previous mode was a preview
+ --- mode.
+ --- Most likely the text hasn't
+ --- changed.
+ goto callback;
+ else
+ markview.render(buffer);
+ end
+ else
+ health.notify("trace", {
+ level = 2,
+ message = string.format("Mode(%s): %d", mode, buffer);
+ });
+ health.__child_indent_in();
+
+ --- Clear
+ if vim.list_contains(preview_modes, old_mode) == false then
+ --- Previous mode was not a preview
+ --- mode.
+ --- Most likely a preview shouldn't
+ --- have occurred.
+ goto callback;
+ else
+ markview.clear(buffer);
+ end
+ end
- if vim.list_contains(markview.configuration.modes, "i") then
- table.insert(update_events, "CursorMovedI");
- table.insert(update_events, "TextChangedI"); -- For smoother experience when writing, potentially can cause bugs
+ ::callback::
+ markview.actions.__exec_callback("on_mode_change", buffer, vim.fn.win_findbuf(buffer), mode)
+ health.__child_indent_de();
+ ---_
end
+});
+
+local timer = vim.uv.new_timer();
- -- Mode
- local cached_mode = vim.api.nvim_get_mode().mode;
- local timer = vim.uv.new_timer();
+--- Preview updates.
+vim.api.nvim_create_autocmd({
+ "CursorMoved", "TextChanged",
+ "CursorMovedI", "TextChangedI"
+}, {
+ group = markview.augroup,
+ callback = function (event)
+ ---+${lua}
+ timer:stop();
- -- This is just a cache
- local r_autocmd;
+ local buffer = event.buf;
+ local name = event.event;
+ local mode = vim.api.nvim_get_mode().mode;
- local tmp = vim.api.nvim_create_autocmd(update_events, {
- buffer = buffer,
- group = augroup,
- callback = function (event)
- local windows = utils.find_attached_wins(buffer);
- local debounce = markview.configuration.debounce;
+ ---@type string[] List of modes where preview is shown.
+ local modes = spec.get({ "preview", "modes" }, { fallback = {}, ignore_enable = true });
+ ---@type string[] List of modes where preview is shown.
+ local hybrid_modes = spec.get({ "preview", "hybrid_modes" }, { fallback = {}, ignore_enable = true });
+ local delay = spec.get({ "preview", "debounce" }, { fallback = 25, ignore_enable = true });
+
+ --- Checks if we need to immediately render
+ --- previews or not.
+ ---@return boolean
+ local function immediate_render ()
+ ---+${lua}
+ if vim.list_contains({ "TextChanged", "TextChangedI" }, name) then
+ --- Changes to the buffer content MUST
+ --- always be debounced to ensure that
+ --- this doesn't hamper typing.
+ return false;
+ end
- -- Current mode
- local mode = vim.api.nvim_get_mode().mode;
+ local utils = require("markview.utils");
+ local win = utils.buf_getwin(buffer);
- if event.event == "ModeChanged" and cached_mode == mode then
- debounce = 0;
+ if type(win) ~= "number" or markview.win_is_safe(win) == false then
+ --- Window isn't safe.
+ --- This shouldn't occur normally.
+ return false;
end
- timer:stop();
- timer:start(debounce, 0, vim.schedule_wrap(function ()
- if markview.autocmds[buffer] and markview.autocmds[buffer].was_detached == true then
- return;
- end
+ local distance_threshold = math.floor(vim.o.lines * 0.75);
+ local pos_y = vim.api.nvim_win_get_cursor(win)[1];
- if markview.state.enable == false or markview.state.buf_states[buffer] == false then
- return;
- end
+ local old = markview.state.buffer_states[buffer].y or 0;
+ local diff = math.abs(pos_y - old);
- if validate == false then
- goto noValidation;
- end
+ --- Update the cached cursor position.
+ if not markview.state.buffer_states[buffer].y then
+ markview.state.buffer_states[buffer].y = pos_y;
+ elseif diff >= distance_threshold then
+ markview.state.buffer_states[buffer].y = pos_y;
+ end
- --- Incorrect file type
- if not vim.list_contains(markview.configuration.filetypes or { "markdown" }, vim.bo[buffer].filetype) then
- markview.unload();
- vim.api.nvim_del_autocmd(r_autocmd);
+ if diff >= distance_threshold then
+ --- User has covered a significant
+ --- distance since the last redraw.
+ ---
+ --- We probably should redraw.
+ return true;
+ else
+ --- User still hasn't covered a large
+ --- distance.
+ ---
+ --- We shouldn't redraw.
+ return false;
+ end
+ ---_
+ end
+ --- Handles the renderer for a buffer.
+ local handle_renderer = function ()
+ ---+${lua}
+
+ ---@type integer
+ local lines = vim.api.nvim_buf_line_count(buffer);
+ ---@type integer
+ local max_l = spec.get({ "preview", "max_buf_lines" }, { fallback = 1000, ignore_enable = true });
+
+ if lines >= max_l then
+ if immediate_render() == true then
+ --- Use a small delay to prevent input
+ --- lags when doing `gg` or `G`.
+ -- markview.render(buffer);
+ vim.defer_fn(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
+ end
+
+ markview.render(buffer);
+ end, 0);
+ else
+ timer:start(delay, 0, vim.schedule_wrap(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
+ end
+
+ markview.render(buffer);
+ end));
+ end
+ elseif vim.list_contains(hybrid_modes, mode) then
+ if not markview.state.buffer_states[buffer] then
+ return;
+ elseif markview.state.buffer_states[buffer].hybrid_mode == false then
return;
end
- -- Incorrect buffer type
- if vim.islist(markview.configuration.buf_ignore) and vim.list_contains(markview.configuration.buf_ignore, vim.bo[buffer].buftype) then
- markview.unload();
- vim.api.nvim_del_autocmd(r_autocmd);
+ --- Hybrid mode movements MUST be
+ --- handled through debounce.
+ timer:start(delay, 0, vim.schedule_wrap(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
+ end
- return
- end
+ markview.render(buffer);
+ end));
+ elseif vim.list_contains({ "TextChanged", "TextChangedI" }, name) then
+ --- Buffer content changes MUST be
+ --- handle via debounce.
+ timer:start(delay, 0, vim.schedule_wrap(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
+ end
- ::noValidation::
+ markview.render(buffer);
+ end));
+ end
+ ---_
+ end
- -- Only on mode change or if the mode changed due to text changed
- if mode ~= cached_mode or event.event == "ModeChanged" then
- -- Call the on_mode_change callback before exiting
- if not markview.configuration.callbacks or not markview.configuration.callbacks.on_mode_change then
- goto noCallbacks;
+ --- Handles the splitview renderer.
+ local function handle_splitview ()
+ ---+${lua}
+
+ ---@type integer
+ local lines = vim.api.nvim_buf_line_count(buffer);
+ ---@type integer
+ local max_l = spec.get({ "preview", "max_buf_lines" }, { fallback = 1000, ignore_enable = true });
+
+ if lines >= max_l then
+ if immediate_render() == true then
+ --- Use a small delay to prevent input
+ --- lags when doing `gg` or `G`.
+ -- markview.render(buffer);
+ vim.defer_fn(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
+ end
+
+ markview.splitview_render();
+ end, 0);
+ elseif vim.list_contains({ "CursorMoved", "CursorMovedI" }, name) then
+ --- BUG, on Android changing cursor
+ --- position outside of `defer_fn`
+ --- results in high input lags.
+ vim.defer_fn(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
+ end
+
+ markview.update_splitview_cursor();
+ end, 0);
+ else
+ --- Buffer content change(use debounce).
+ timer:start(delay, 0, vim.schedule_wrap(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
+ end
+
+ markview.splitview_render();
+ end));
+ end
+ elseif vim.list_contains({ "TextChanged", "TextChangedI" }, name) then
+ timer:start(delay, 0, vim.schedule_wrap(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
end
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_mode_change, buffer, window, mode);
+ markview.splitview_render();
+ end));
+ else
+ vim.defer_fn(function ()
+ if vim.v.exiting ~= vim.NIL then
+ return;
end
- end
- ::noCallbacks::
+ markview.update_splitview_cursor();
+ end, 0);
+ end
- cached_mode = mode; -- Still gotta update the cache
+ ---_
+ end
- if vim.list_contains(markview.configuration.modes, mode) then
- markview.renderer.clear(buffer);
- buf_render(buffer);
- elseif vim.tbl_isempty(markview.configuration.modes) then
- markview.renderer.clear(buffer);
- buf_render(buffer);
- else
- markview.renderer.clear(buffer);
- vim.cmd("redraw!");
- end
- end));
+ if markview.actions.__is_attached(buffer) == false then
+ return;
+ elseif markview.actions.__is_enabled(buffer) == false then
+ return;
+ elseif vim.list_contains(modes, mode) == false then
+ if buffer == markview.state.splitview_source then
+ handle_splitview();
+ end
+
+ return;
end
- });
- r_autocmd = tmp;
- markview.autocmds[buffer] = {
- was_detached = false,
- id = tmp
- }
-end
+ if buffer == markview.state.splitview_source then
+ handle_splitview();
+ else
+ handle_renderer();
+ end
+ ---_
+ end
+});
-vim.api.nvim_create_autocmd({ "BufWinEnter" }, {
- desc = "Attaches markview to the buffers",
- callback = function (event)
- local buffer = event.buf;
+--- Updates the highlight groups.
+vim.api.nvim_create_autocmd("ColorScheme", {
+ callback = function ()
+ local hls = require("markview.highlights");
+ hls.create(hls.groups)
- local ft = vim.bo[buffer].filetype;
- local bt = vim.bo[buffer].buftype;
+ health.notify("trace", {
+ level = 5,
+ message = "Updated highlight groups"
+ });
+ end
+});
- --- Incorrect file type
- if not vim.list_contains(markview.configuration.filetypes or { "markdown" }, ft) then
- return;
+ ------------------------------------------------------------------------------------------
+
+---@type mkv.cmd_completion
+local get_complete_items = {
+ default = function (str)
+ ---+${lua}
+ if str == nil then
+ local _o = vim.tbl_keys(markview.commands);
+ table.sort(_o);
+
+ return _o;
+ end
+
+ local _o = {};
+
+ for _, key in ipairs(vim.tbl_keys(markview.commands)) do
+ if string.match(key, "^" .. str) then
+ table.insert(_o, key);
+ end
end
- -- Incorrect buffer type
- if vim.islist(markview.configuration.buf_ignore) and vim.list_contains(markview.configuration.buf_ignore, bt) then
- return
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+
+ attach = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
end
- local windows = utils.find_attached_wins(buffer);
- local mode = vim.api.nvim_get_mode().mode;
+ local buf = args[3];
+ local _o = {};
+
+ for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
+ if markview.buf_is_safe(buffer) == false then
+ goto continue;
+ end
- -- If not attached then attach
- if not vim.list_contains(markview.attached_buffers, buffer) then
- table.insert(markview.attached_buffers, buffer);
- markview.attached_windows = vim.list_extend(markview.attached_windows, windows);
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
+ end
+
+ ::continue::
+ end
+
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+ detach = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
end
- -- Plugin is disabled
- if markview.state.enable == false or markview.state.buf_states[buffer] == false then
- -- Call the on_disable callback before exiting
- if not markview.configuration.callbacks or not markview.configuration.callbacks.on_disable then
- return;
+ local buf = args[3];
+ local _o = {};
+
+ for _, buffer in ipairs(markview.state.attached_buffers) do
+ if markview.buf_is_safe(buffer) == false then
+ goto continue;
end
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_disable, buffer, window);
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
end
- goto addAutocmd;
+ ::continue::
+ end
+
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+
+ enable = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
end
- -- Set state to true and call the callback
- markview.state.buf_states[buffer] = markview.configuration.initial_state;
+ local buf = args[3];
+ local _o = {};
- if markview.state.buf_states[buffer] == false or not vim.list_contains(markview.configuration.modes, mode) then
- for _, window in ipairs(windows) do
- if markview.configuration.callbacks and markview.configuration.callbacks.on_disable then
- pcall(markview.configuration.callbacks.on_disable, buffer, window);
- end
+ for _, buffer in ipairs(markview.state.attached_buffers) do
+ if markview.buf_is_safe(buffer) == false or markview.actions.__is_enabled(buffer) == true then
+ goto continue;
end
- else
- for _, window in ipairs(windows) do
- if markview.configuration.callbacks and markview.configuration.callbacks.on_enable then
- pcall(markview.configuration.callbacks.on_enable, buffer, window);
- end
+
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
end
- -- Clear the buffer before rendering things
- markview.renderer.clear(buffer);
- buf_render(buffer);
+ ::continue::
end
- ::addAutocmd::
- -- Augroup for the special autocmds
- local markview_augroup = vim.api.nvim_create_augroup("markview_buf_" .. buffer, { clear = true });
- redraw_autocmd(markview_augroup, buffer);
- end
-})
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+ disable = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
+ end
-vim.api.nvim_create_autocmd({ "User" }, {
- desc = "Attaches markview to the buffers",
- pattern = "MarkviewEnter",
- callback = function (event)
- local buffer = event.buf;
+ local buf = args[3];
+ local _o = {};
- if vim.list_contains(markview.attached_buffers, buffer) then
- return;
+ for _, buffer in ipairs(markview.state.attached_buffers) do
+ if markview.buf_is_safe(buffer) == false or markview.actions.__is_enabled(buffer) == false then
+ goto continue;
+ end
+
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
+ end
+
+ ::continue::
end
- local windows = utils.find_attached_wins(buffer);
- local mode = vim.api.nvim_get_mode().mode;
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+
+ hybridToggle = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
+ end
+
+ local buf = args[3];
+ local _o = {};
+
+ for _, buffer in ipairs(markview.state.attached_buffers) do
+ if markview.buf_is_safe(buffer) == false or markview.actions.__is_enabled(buffer) == false then
+ goto continue;
+ end
+
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
+ end
- -- If not attached then attach
- if not vim.list_contains(markview.attached_buffers, buffer) then
- table.insert(markview.attached_buffers, buffer);
- markview.attached_windows = vim.list_extend(markview.attached_windows, windows);
+ ::continue::
end
- -- Plugin is disabled
- if markview.state.enable == false or markview.state.buf_states[buffer] == false then
- -- Call the on_disable callback before exiting
- if not markview.configuration.callbacks or not markview.configuration.callbacks.on_disable then
- return;
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+ hybridDisable = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
+ end
+
+ local buf = args[3];
+ local _o = {};
+
+ for _, buffer in ipairs(markview.state.attached_buffers) do
+ if markview.buf_is_safe(buffer) == false or markview.actions.__is_enabled(buffer) == false then
+ goto continue;
end
- for _, window in ipairs(windows) do
- pcall(markview.configuration.callbacks.on_disable, buffer, window);
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
end
- return;
+ ::continue::
end
- -- Set state to true and call the callback
- markview.state.buf_states[buffer] = markview.configuration.initial_state;
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+ hybridEnable = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
+ end
- if markview.state.buf_states[buffer] == false or not vim.list_contains(markview.configuration.modes, mode) then
- for _, window in ipairs(windows) do
- if markview.configuration.callbacks and markview.configuration.callbacks.on_disable then
- pcall(markview.configuration.callbacks.on_disable, buffer, window);
- end
+ local buf = args[3];
+ local _o = {};
+
+ for _, buffer in ipairs(markview.state.attached_buffers) do
+ if markview.buf_is_safe(buffer) == false or markview.actions.__is_enabled(buffer) == false then
+ goto continue;
end
- else
- for _, window in ipairs(windows) do
- if markview.configuration.callbacks and markview.configuration.callbacks.on_enable then
- pcall(markview.configuration.callbacks.on_enable, buffer, window);
- end
+
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
+ end
+
+ ::continue::
+ end
+
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+
+ splitOpen = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
+ end
+
+ local buf = args[3];
+ local _o = {};
+
+ for _, buffer in ipairs(markview.state.attached_buffers) do
+ if markview.buf_is_safe(buffer) == false then
+ goto continue;
+ end
+
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
end
- -- Clear the buffer before rendering things
- markview.renderer.clear(buffer);
- buf_render(buffer);
+ ::continue::
+ end
+
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+
+ render = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
end
- -- Augroup for the special autocmds
- local markview_augroup = vim.api.nvim_create_augroup("markview_buf_" .. buffer, { clear = true });
- redraw_autocmd(markview_augroup, buffer, false);
+ local buf = args[3];
+ local _o = {};
+
+ for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
+ if markview.buf_is_safe(buffer) == false then
+ goto continue;
+ end
+
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
+ end
+
+ ::continue::
+ end
+
+ table.sort(_o);
+ return _o;
+ ---_
+ end,
+ clear = function (args, cmd)
+ ---+${lua}
+ if #args > 3 then
+ --- Too many arguments!
+ return {};
+ elseif #args >= 3 and string.match(cmd, "%s$") then
+ --- Attempting to get completion beyond
+ --- the argument count.
+ return {};
+ end
+
+ local buf = args[3];
+ local _o = {};
+
+ for _, buffer in ipairs(vim.api.nvim_list_bufs()) do
+ if markview.buf_is_safe(buffer) == false then
+ goto continue;
+ end
+
+ if buf == nil then
+ table.insert(_o, tostring(buffer));
+ elseif string.match(tostring(buffer), "^" .. buf) then
+ table.insert(_o, tostring(buffer));
+ end
+
+ ::continue::
+ end
+
+ table.sort(_o);
+ return _o;
+ ---_
end
-})
+};
+
+--- User command.
+vim.api.nvim_create_user_command("Markview", function (cmd)
+ ---+${lua}
+
+ local function exec(fun, args)
+ args = args or {};
+ local fargs = {};
+
+ for _, arg in ipairs(args) do
+ if tonumber(arg) then
+ table.insert(fargs, tonumber(arg));
+ elseif arg == "true" or arg == "false" then
+ table.insert(fargs, arg == "true");
+ else
+ --- BUG, is this used by any functions?
+ -- table.insert(fargs, arg);
+ end
+ end
-vim.api.nvim_create_autocmd("User", {
- pattern = "MarkviewLeave",
- callback = function (event)
- if not markview.autocmds[event.buf] then
- return;
- elseif markview.autocmds[event.buf].was_detached == true then
- return;
+ ---@diagnostic disable-next-line
+ pcall(fun, unpack(fargs));
+ end
+
+ ---@type string[] Command arguments.
+ local args = cmd.fargs;
+
+ if #args == 0 then
+ markview.commands.Toggle();
+ elseif type(markview.commands[args[1]]) == "function" then
+ --- FIXME, Change this if `vim.list_slice` becomes deprecated.
+ exec(markview.commands[args[1]], vim.list_slice(args, 2))
+ end
+ ---_
+end, {
+ ---+${lua}
+ nargs = "*",
+ desc = "User command for `markview.nvim`",
+ complete = function (_, cmd, cursorpos)
+ local function is_subcommand(str)
+ return markview.commands[str] ~= nil;
end
- local data = markview.autocmds[event.buf];
- markview.renderer.clear(event.buf);
- data.was_detached = true;
+ local before = string.sub(cmd, 0, cursorpos);
+ local parts = {};
+
+ for part in string.gmatch(before, "%S+") do
+ table.insert(parts, part);
+ end
- vim.api.nvim_del_autocmd(data.id);
- markview.unload(event.buf);
+ if #parts == 1 then
+ return get_complete_items.default(parts[2]);
+ elseif #parts == 2 and is_subcommand(parts[2]) == false then
+ return get_complete_items.default(parts[2]);
+ elseif is_subcommand(parts[2]) == true and get_complete_items[parts[2]] ~= nil then
+ return get_complete_items[parts[2]](parts, before);
+ end
end
+ ---_
});
-
diff --git a/queries/markdown/highlights.scm b/queries/markdown/highlights.scm
new file mode 100644
index 0000000..03b448b
--- /dev/null
+++ b/queries/markdown/highlights.scm
@@ -0,0 +1,121 @@
+;From MDeiml/tree-sitter-markdown & Helix
+(setext_heading
+ (paragraph) @markup.heading.1
+ (setext_h1_underline) @markup.heading.1)
+
+(setext_heading
+ (paragraph) @markup.heading.2
+ (setext_h2_underline) @markup.heading.2)
+
+(atx_heading
+ (atx_h1_marker)) @markup.heading.1
+
+(atx_heading
+ (atx_h2_marker)) @markup.heading.2
+
+(atx_heading
+ (atx_h3_marker)) @markup.heading.3
+
+(atx_heading
+ (atx_h4_marker)) @markup.heading.4
+
+(atx_heading
+ (atx_h5_marker)) @markup.heading.5
+
+(atx_heading
+ (atx_h6_marker)) @markup.heading.6
+
+(info_string) @label
+
+(pipe_table_header
+ (pipe_table_cell) @markup.heading)
+
+(pipe_table_header
+ "|" @punctuation.special)
+
+(pipe_table_row
+ "|" @punctuation.special)
+
+(pipe_table_delimiter_row
+ "|" @punctuation.special)
+
+(pipe_table_delimiter_cell) @punctuation.special
+
+; Code blocks (conceal backticks and language annotation)
+(indented_code_block) @markup.raw.block
+
+((fenced_code_block) @markup.raw.block
+ (#set! priority 90))
+
+(fenced_code_block
+ (fenced_code_block_delimiter) @markup.raw.block
+ (#conceal-patch! @markup.raw.block))
+
+(fenced_code_block
+ (info_string
+ (language) @label
+ (#set! conceal "")))
+
+(link_destination) @markup.link.url
+
+[
+ (link_title)
+ (link_label)
+] @markup.link.label
+
+((link_label)
+ .
+ ":" @punctuation.delimiter)
+
+[
+ (list_marker_plus)
+ (list_marker_minus)
+ (list_marker_star)
+ (list_marker_dot)
+ (list_marker_parenthesis)
+] @markup.list
+
+; NOTE: The following has been commented out due to issues with spaces in the
+; list marker nodes generated by the parser. If those spaces ever get captured
+; by a different node (e.g. block_continuation) we can safely re-add these
+; conceals.
+; ;; Conceal bullet points
+; ([(list_marker_plus) (list_marker_star)]
+; @punctuation.special
+; (#offset! @punctuation.special 0 0 0 -1)
+; (#set! conceal "โข"))
+; ([(list_marker_plus) (list_marker_star)]
+; @punctuation.special
+; (#any-of? @punctuation.special "+" "*")
+; (#set! conceal "โข"))
+; ((list_marker_minus)
+; @punctuation.special
+; (#offset! @punctuation.special 0 0 0 -1)
+; (#set! conceal "โ"))
+; ((list_marker_minus)
+; @punctuation.special
+; (#eq? @punctuation.special "-")
+; (#set! conceal "โ"))
+(thematic_break) @punctuation.special
+
+(task_list_marker_unchecked) @markup.list.unchecked
+
+(task_list_marker_checked) @markup.list.checked
+
+((block_quote) @markup.quote
+ (#set! priority 90))
+
+([
+ (plus_metadata)
+ (minus_metadata)
+] @keyword.directive
+ (#set! priority 90))
+
+[
+ (block_continuation)
+ (block_quote_marker)
+] @punctuation.special
+
+(backslash_escape) @string.escape
+
+(inline) @spell
diff --git a/queries/markdown_inline/highlights.scm b/queries/markdown_inline/highlights.scm
new file mode 100644
index 0000000..825177b
--- /dev/null
+++ b/queries/markdown_inline/highlights.scm
@@ -0,0 +1,98 @@
+; From MDeiml/tree-sitter-markdown
+(code_span) @markup.raw @nospell
+
+(emphasis) @markup.italic
+
+(strong_emphasis) @markup.strong
+
+(strikethrough) @markup.strikethrough
+
+(shortcut_link
+ (link_text) @nospell)
+
+[
+ (backslash_escape)
+ (hard_line_break)
+] @string.escape
+
+; Conceal codeblock and text style markers
+([
+ (code_span_delimiter)
+ (emphasis_delimiter)
+] @conceal
+ (#set! conceal ""))
+
+; Conceal inline links
+(inline_link
+ [
+ "["
+ "]"
+ "("
+ (link_destination)
+ ")"
+ ] @markup.link
+ (#set! conceal ""))
+
+[
+ (link_label)
+ (link_text)
+ (link_title)
+ (image_description)
+] @markup.link.label
+
+(inline_link
+ (link_text) @_label
+ (link_destination) @_url
+ (#set! @_label url @_url))
+
+; Conceal image links
+(image
+ [
+ "!"
+ "["
+ "]"
+ "("
+ (link_destination)
+ ")"
+ ] @markup.link
+ (#set! conceal ""))
+
+; Conceal full reference links
+(full_reference_link
+ [
+ "["
+ "]"
+ (link_label)
+ ] @markup.link
+ (#set! conceal ""))
+
+; Conceal collapsed reference links
+(collapsed_reference_link
+ [
+ "["
+ "]"
+ ] @markup.link
+ (#set! conceal ""))
+
+; Conceal shortcut links
+(shortcut_link
+ [
+ "["
+ "]"
+ ] @markup.link
+ (#set! conceal ""))
+
+[
+ (link_destination)
+ (uri_autolink)
+ (email_autolink)
+] @markup.link.url @nospell
+
+((link_destination) @_url
+ (#set! @_url url @_url))
+
+((uri_autolink) @_url
+ (#offset! @_url 0 1 0 -1)
+ (#set! @_url url @_url))
+
+(entity_reference) @nospell
diff --git a/showcases/Blocks.md b/showcases/Blocks.md
deleted file mode 100644
index 4660b7e..0000000
--- a/showcases/Blocks.md
+++ /dev/null
@@ -1,25 +0,0 @@
-markview.nvim
-
-> A regular Block quote
->
-> >[!NOTE]
-> > Some note!
->
-> >[!Success] Some random title
-> > Looks pretty *cool*!
->
-> ```lua
-> -- Supports nesting too!
-> vim.print("Hello, vim!");
-> ```
->
-> + Tasks to do,
-> - [~] Fix bugs
-> - [ ] Release new version
-
-$$
-\lim_{x \to \infty} \ln 2x - 1 - \ln x + 5
-$$
-
diff --git a/showcases/Headings.md b/showcases/Headings.md
deleted file mode 100644
index 649529a..0000000
--- a/showcases/Headings.md
+++ /dev/null
@@ -1,26 +0,0 @@
-markview.nvim
-
-# Heading 1
-
-## Heading 2
-
-### Heading 3
-
-#### Heading 4
-
-##### Heading 5
-
-###### Heading 6
-
-Heading 1:
-A heading with some description
-=======
-
-Heading 2:
-Another heading with some description
--------
-
-
-
diff --git a/showcases/Inline.md b/showcases/Inline.md
deleted file mode 100644
index 6c1964e..0000000
--- a/showcases/Inline.md
+++ /dev/null
@@ -1,29 +0,0 @@
-markview.nvim
-
-*Italic*, **Bold**, ***Italic bold***
-[Some text]
-
-From this plugin:
-`inline code`
-
-[OXY2DEV/markview.nvim](github.com)
-[www.neovim.org](https://www.neovim.org)
-[r/neovim](reddit.com)
-[[Internal links]]
-
-
-A [^footnote]
-
-
-
-${a + b}^{2} = a^{2} + 2ab + b^{2}$
-$\frac{tan^{2} a + tan^{2} b}{1 + 2tan a \times tan b}$
-$\sum_{1}^{2} 5$
-$\alpha \times \Psi$
-
-Inline math: $\oint_{5}^{6} x^3dx$
-
-
-
diff --git a/showcases/LaTeX.latex b/showcases/LaTeX.latex
deleted file mode 100644
index c8f1768..0000000
--- a/showcases/LaTeX.latex
+++ /dev/null
@@ -1,54 +0,0 @@
-markview.nvim
-
-Displayed math:
-\[
-E = mc^2
-\prod_{5}^{6}
-\]
-
-Fractions:
-\[
-\frac{a + 1}{b + 5} = \frac{c}{d}
-\]
-
-Square root:
-\[
-\sqrt{a^2 + b^2}
-\]
-
-Summation with limits:
-\[
-\sum_{i=1}^{n} i = \frac{n(n+1)}{2}
-\]
-
-Integral:
-\[
-\int_{0}^{\infty} e^{-x^2} \, dx = \frac{\sqrt{\pi}}{2}
-\]
-
-Calligraphic:
-\[
-\mathcal{A}, \mathcal{B}, \mathcal{C}
-\]
-
-Bold:
-\[
-\mathsfit{F} = m \mathbfit{a}
-\]
-
-Italic:
-\[
-\mathsfit{l} = l_1 + l_2 + \ldots + l_n
-\]
-
-Greek letters:
-\[
-\alpha, \beta, \gamma, \delta, \epsilon, \zeta, \eta, \theta, \iota, \kappa, \lambda, \mu, \nu, \xi, \pi, \rho, \sigma, \tau, \upsilon, \phi, \chi, \psi, \omega
-\]
-
-Partial derivative:
-\[
-\frac{\partial f}{\partial x}
-\]
-
-% vim:nospell
diff --git a/showcases/Tables.md b/showcases/Tables.md
deleted file mode 100644
index 5eb7c6f..0000000
--- a/showcases/Tables.md
+++ /dev/null
@@ -1,21 +0,0 @@
-markview.nvim
-
-
-| Left alignmemt | Center alignment | Right alignment |
-|:---------------|:----------------:|----------------:|
-| 1 | 2 | 3 |
-| 4 | 5 | 6 |
-| 7 | 8 | 9 |
-
-
-| Left alignmemt | Center alignment | Right alignment |
-|:---------------|:----------------:|----------------:|
-| *ialic*| **bold** |***bold italic*** |
-| italic | bold |Underlined |
-| `inline code`| [link](reddit.com) | |
-| [^footnote]|[[Internal link]]|β |
-
-
-
diff --git a/test/html.md b/test/html.md
new file mode 100644
index 0000000..84540c3
--- /dev/null
+++ b/test/html.md
@@ -0,0 +1,27 @@
+; Container elements
+
+Bold
+Code span
+Emphasis
+Italic
+Marked
+Strong
+Subscript
+Superscript
+Underlined
+
+; Headings
+
+Heading 1
+Heading 2
+Heading 3
+Heading 4
+Heading 5
+Heading 6
+
+; Void elements
+
+
+
+A line. Another line.
+
diff --git a/test/latex.md b/test/latex.md
new file mode 100644
index 0000000..9ae4a06
--- /dev/null
+++ b/test/latex.md
@@ -0,0 +1,67 @@
+; Math blocks
+
+$$
+1 + 2 = 3
+$$
+
+; LaTeX commands
+
+$$
+\sin{45ยฐ} = \frac{1}{2}
+$$
+
+; Escapes
+
+$$
+\& \. \\
+$$
+
+; Fonts
+
+$$
+Hello LaTeX!
+\mathbf{Hello LaTeX!}
+\mathsfit{Hello LaTeX!}
+\mathtt{Hello LaTeX! \alpha}
+\mathsf{Hello LaTeX!}
+\mathsfbfit{Hello LaTeX!}
+\mathsfbf{Hello LaTeX!}
+\mathfrak{Hello LaTeX!}
+\mathbfit{Hello LaTeX!}
+\mathbffrak{Hello LaTeX!}
+\mathbb{Hello LaTeX!}
+\mathbfscr{Hello LaTeX!}
+$$
+
+; Inline maths
+
+Some math in a line, $1+2=3$.
+
+; Subscripts
+
+$$
+a_s
+b_{some text + \gamma}
+$$
+
+; Superscripts
+
+$$
+c^5
+d^{Some other text + \alpha}
+$$
+
+; Symbols
+
+$$
+\alpha \beta \gamma \delta \eta \theta \xi \pi
+\Alpha \Beta \Gamma \Delta \Eta \Theta \Xi \Pi
+$$
+
+; Text mode
+
+$$
+\text{a^2 + 2ab + b^2}
+a^2 + 2ab + b^2
+$$
+
diff --git a/test/markdown.md b/test/markdown.md
new file mode 100644
index 0000000..81f4aa1
--- /dev/null
+++ b/test/markdown.md
@@ -0,0 +1,173 @@
+---
+author: "OXY2DEV"
+---
+
+
+; Block quotes
+
+
+> A regular block quote.
+> It spans across multiple lines.
+>
+> It also contains an empty line.
+
+>[!ABSTRACT]
+
+>[!SUMMARY]
+
+>[!TLDR]
+
+>[!TODO]
+
+>[!INFO]
+
+>[!SUCCESS]
+
+>[!CHECK]
+
+>[!DONE]
+
+>[!QUESTION]
+
+>[!HELP]
+
+>[!FAQ]
+
+>[!FAILURE]
+
+>[!FAIL]
+
+>[!MISSING]
+
+>[!DANGER]
+
+>[!ERROR]
+
+>[!BUG]
+
+>[!EXAMPLE]
+
+>[!QUOTE]
+
+>[!CITE]
+
+>[!HINT]
+
+>[!ATTENTION]
+
+
+>[!NOTE]
+
+>[!TIP]
+
+>[!IMPORTANT]
+
+>[!WARNING]
+
+>[!CAUTION]
+
+
+>[!ABSTRACT]
+>
+> >[!SUCCESS] Custom title
+> >
+> > >[!QUESTION]
+> > >
+> > > >[!FAILURE] Custom title
+> > > >
+
+
+; Code block
+
+
+```c Info string
+printf("Hello world!")
+```
+
+```html A very long info string that wil not fit here! And to be absolutely sure I will add a few more words.
+Hello world!
+```
+
+```js
+console.log("Hello world!");
+```
+
+```lua
+vim.print("Hello world!");
+```
+
+```md
+Hello *world!*
+```
+
+```py
+print("Hello world!");
+```
+
+```ts
+console.log("Hello world!");
+```
+
+```typ
+Hello _world!_
+```
+
+
+; Headings
+
+
+# Heading 1
+
+## Heading 2
+
+### Heading 3
+
+#### Heading 4
+
+##### Heading 5
+
+###### Heading 6
+
+
+Setext 1
+========
+
+Setext 2
+--------
+
+
+; Horizontal rules
+
+
+---
+
+; Reference definitions
+
+[Test]: www.neovim.org
+
+; List items
+
+
+- Item 1
++ Item 2
+* Item 3
+ - Nest 1
+ + Nest 2
+ * Nest 3
+ 1. Nest 4
+ 2. Nest 5
+ * [X] Nest 6
+ + [-] Nest 7
+ - [/] Nest 8
+
+
+; Tables
+
+
+| Normal | Left | Center | Right
+|--------|:-----|:------:| --: |
+| 1 | 2 | 3 | 4 |
+| **Bold** | *italic* | ***Bold italic*** | `Inline code` |
+| [Shortcut] | [Link](reddit.com) |  | [[Internal]] |
+
+
diff --git a/test/markdown_inline.md b/test/markdown_inline.md
new file mode 100644
index 0000000..86410bb
--- /dev/null
+++ b/test/markdown_inline.md
@@ -0,0 +1,85 @@
+; Block reference
+
+[[#^Block]]
+![[Some_file.md#^Block]]
+
+; Checkboxes
+
+- [X] Checked
+- [ ] Unchecked
+- [/] Incomplete
+- [>] Forwarded
+- [<] Scheduling
+- [-] Cancelled
+
+- [?] Question
+- [!] Important
+- [*] Star
+- ["] Quote
+- [l] Location
+- [b] Bookmark
+- [i] Information
+- [S] Savings
+- [I] Idea
+- [p] Pros
+- [c] Cons
+- [f] Fire
+- [k] Key
+- [w] Win
+- [u] Up
+- [d] Down
+
+- [u] Item 1
+ + [d] Nest 1
+
+; Emails
+
+Mail to .
+
+; Embed files
+
+An ![[Embed file.md]]
+
+; Entities
+
+⇓ ∬ α Β γ
+
+; Escaped characters
+
+\& \= \\ \| \.
+
+; Footnotes
+
+Work in progress. [^1]
+
+[^1]:Footnote
+
+; Highlights
+
+Some ==Special text==.
+
+; Hyperlinks
+
+[Neovim](www.neovim.org)
+[Reddit][example]
+
+[example]:www.reddit.com
+
+; Images
+
+
+
+
+; Inline codes
+
+A line of `text`.
+
+; Internal links
+
+This is an [[internal link]].
+They also support [[internal link|aliases]].
+
+; URI autolinks
+
+
+
diff --git a/test/typst.typ b/test/typst.typ
new file mode 100644
index 0000000..dc1c113
--- /dev/null
+++ b/test/typst.typ
@@ -0,0 +1,118 @@
+; Codes
+
+#{
+ let a = [from]
+ let b = [*world*]
+ [hello ]
+ a + [ the ] + b
+}
+
+Inline: #{ a + [ the ] +
+b }
+
+; Escaped characters
+
+\$ \# \& \. \|
+
+; Headings
+
+= Heading 1
+
+== Heading 1
+
+=== Heading 1
+
+==== Heading 1
+
+===== Heading 1
+
+====== Heading 1
+
+; Labels
+
+This text has a
+
+; List items
+
+- Item 1
++ Item 2
+1. Item 3
+ + Nest 1
+ + Nest 2
+ + Nest 3
+
+; Math blocks
+
+$
+1 + 2 = 3
+$
+
+; Math spans
+
+Some math inside a line, $1 + 2 = 3$.
+
+; Raw blocks
+
+```c
+printf("Hello world!")
+```
+
+```html
+Hello world!
+```
+
+```js
+console.log("Hello world!");
+```
+
+```lua
+vim.print("Hello world!");
+```
+
+```md
+Hello *world!*
+```
+
+```py
+print("Hello world!");
+```
+
+```ts
+console.log("Hello world!");
+```
+
+```typ
+Hello _world!_
+```
+
+; Reference links
+
+@label
+
+; Subscripts
+
+$
+a_{2+3}
+$
+
+; Superscripts
+
+$
+b^{4+5}
+$
+
+; Symbols
+
+$
+paren.l.double bracket.t shell.b fence.l
+arrow.l.r.long
+$
+
+; Term
+
+/ Term: Some term
+
+; Urls
+
+https://www.neovim.org
+
diff --git a/test/yaml.md b/test/yaml.md
new file mode 100644
index 0000000..ae9024a
--- /dev/null
+++ b/test/yaml.md
@@ -0,0 +1,13 @@
+---
+tags:
+ - tg 1
+ - tg 2
+aliases:
+ - tags:
+ - hi
+ - al 2
+author: OXY2DEV
+checkbox: false
+date: 2025-01-02
+---
+