Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/meanderingprogrammer/render-markdown.nvim

Plugin to improve viewing Markdown files in Neovim
https://github.com/meanderingprogrammer/render-markdown.nvim

lua markdown neovim neovim-plugin nvim nvim-plugin

Last synced: about 13 hours ago
JSON representation

Plugin to improve viewing Markdown files in Neovim

Awesome Lists containing this project

README

        

# render-markdown.nvim

Plugin to improve viewing Markdown files in Neovim

| | |
| --------- | ------- |
| ![Heading](https://github.com/user-attachments/assets/663a34c5-0438-4688-8204-332065f65835) | ![Table](https://github.com/user-attachments/assets/162986e1-91f0-4e13-a83f-6183d58b0fcb) |
| ![Quote](https://github.com/user-attachments/assets/5343ca45-d5e1-4de0-9065-46499e1ed919) | ![LaTeX](https://github.com/user-attachments/assets/9e8909e4-7256-45fc-b481-4aba8850ebc3) |
| ![Callout](https://github.com/user-attachments/assets/4324ea72-a017-4175-9f9d-363da5e5f6ba) | |

# Features

- Contained: runs entirely inside Neovim with no external windows
- Configurable: all components, padding, icons, and colors can be modified
- File type agnostic: can render `markdown` injected into any file
- Injections: can directly manipulate treesitter to add logical `markdown` sections
- Mode based rendering: changes between `rendered` and `raw` view based on mode
- Anti-conceal: hides virtual text added by this plugin on cursor line
- Window options: changes option values between `rendered` and `raw` view
- Large files: only renders visisble range, can be entirely disabled based on size
- Custom rendering: provides extension point where user can add anything
- Renders the following `markdown` components out of the box:
- Headings: icon, color, border, padding [^1], width
- Code blocks: background, language icon [^1] [^2], border, padding [^1], width
- Code inline: background
- Horizontal breaks: icon, color, width
- List bullets: icon, color, padding [^1]
- Checkboxes: icon, color, user defined states [^1]
- Block quotes: icon, color, line breaks [^1]
- Callouts: icon, color, user defined values, Github & Obsidian defaults
- Tables: border, color, alignment indicator, auto align cells always to left [^1]
- Links [^1]: icon, color, user defined destinations
- `LaTeX` blocks [^3]: renders formulas
- Org indent mode [^1]: per level padding

[^1]: Requires neovim >= `0.10.0`
[^2]: Requires icon provider, `mini.icons` or `nvim-web-devicons`
[^3]: Requires `latex` parser and `pylatexenc`

# Requirements

- neovim `>= 0.9.0` (minimum) `>= 0.10.0` (recommended)
- [treesitter](https://github.com/nvim-treesitter/nvim-treesitter) parsers:
- [markdown & markdown_inline](https://github.com/tree-sitter-grammars/tree-sitter-markdown):
Used to parse `markdown` files
- [latex](https://github.com/latex-lsp/tree-sitter-latex) (Optional):
Used to get `LaTeX` blocks from `markdown` files
- Icon provider plugin (Optional): Used for icon above code blocks
- [mini.icons](https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-icons.md)
- [nvim-web-devicons](https://github.com/nvim-tree/nvim-web-devicons)
- System dependencies:
- [pylatexenc](https://pypi.org/project/pylatexenc/) (Optional):
Used to transform `LaTeX` strings to appropriate unicode using `latex2text`

# Install

## lazy.nvim

```lua
{
'MeanderingProgrammer/render-markdown.nvim',
opts = {},
dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.nvim' }, -- if you use the mini.nvim suite
-- dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.icons' }, -- if you use standalone mini plugins
-- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons
}
```

## rocks.nvim

This plugin is available on [LuaRocks](https://luarocks.org/modules/MeanderingProgrammer/render-markdown.nvim)

```vim
:Rocks install render-markdown.nvim
```

## packer.nvim

```lua
use({
'MeanderingProgrammer/render-markdown.nvim',
after = { 'nvim-treesitter' },
requires = { 'echasnovski/mini.nvim', opt = true }, -- if you use the mini.nvim suite
-- requires = { 'echasnovski/mini.icons', opt = true }, -- if you use standalone mini plugins
-- requires = { 'nvim-tree/nvim-web-devicons', opt = true }, -- if you prefer nvim-web-devicons
config = function()
require('render-markdown').setup({})
end,
})
```

# Commands

| Command | Lua Function | Description |
| -------------------------- | --------------------------------------- | ------------------------------------------------- |
| `:RenderMarkdown` | `require('render-markdown').enable()` | Enable this plugin |
| `:RenderMarkdown enable` | `require('render-markdown').enable()` | Enable this plugin |
| `:RenderMarkdown disable` | `require('render-markdown').disable()` | Disable this plugin |
| `:RenderMarkdown toggle` | `require('render-markdown').toggle()` | Switch between enabling & disabling this plugin |
| `:RenderMarkdown log` | `require('render-markdown').log()` | Opens the log file for this plugin |
| `:RenderMarkdown expand` | `require('render-markdown').expand()` | Increase anti-conceal margin above and below by 1 |
| `:RenderMarkdown contract` | `require('render-markdown').contract()` | Decrease anti-conceal margin above and below by 1 |
| `:RenderMarkdown debug` | `require('render-markdown').debug()` | Prints information about marks on current line |

# Setup

Checkout the [Wiki](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki)
for examples and images associated with different configuration options.

The full default configuration is provided below for reference.

Any part of it can be modified however for many fields this does not make much sense.

Some of the more useful fields are discussed further down.

Full Default Configuration

```lua
require('render-markdown').setup({
-- Whether Markdown should be rendered by default or not
enabled = true,
-- Maximum file size (in MB) that this plugin will attempt to render
-- Any file larger than this will effectively be ignored
max_file_size = 10.0,
-- Milliseconds that must pass before updating marks, updates occur
-- within the context of the visible window, not the entire buffer
debounce = 100,
-- Pre configured settings that will attempt to mimic various target
-- user experiences. Any user provided settings will take precedence.
-- obsidian: mimic Obsidian UI
-- lazy: will attempt to stay up to date with LazyVim configuration
-- none: does nothing
preset = 'none',
-- Capture groups that get pulled from markdown
markdown_query = [[
(section) @section

(atx_heading [
(atx_h1_marker)
(atx_h2_marker)
(atx_h3_marker)
(atx_h4_marker)
(atx_h5_marker)
(atx_h6_marker)
] @heading)
(setext_heading) @heading

(thematic_break) @dash

(fenced_code_block) @code

[
(list_marker_plus)
(list_marker_minus)
(list_marker_star)
] @list_marker

(task_list_marker_unchecked) @checkbox_unchecked
(task_list_marker_checked) @checkbox_checked

(block_quote) @quote

(pipe_table) @table
]],
-- Capture groups that get pulled from quote nodes
markdown_quote_query = [[
[
(block_quote_marker)
(block_continuation)
] @quote_marker
]],
-- Capture groups that get pulled from inline markdown
inline_query = [[
(code_span) @code

(shortcut_link) @shortcut

[
(image)
(email_autolink)
(inline_link)
(full_reference_link)
] @link
]],
-- The level of logs to write to file: vim.fn.stdpath('state') .. '/render-markdown.log'
-- Only intended to be used for plugin development / debugging
log_level = 'error',
-- Filetypes this plugin will run on
file_types = { 'markdown' },
-- Out of the box language injections for known filetypes that allow markdown to be
-- interpreted in specified locations, see :h treesitter-language-injections
-- Set enabled to false in order to disable
injections = {
gitcommit = {
enabled = true,
query = [[
((message) @injection.content
(#set! injection.combined)
(#set! injection.include-children)
(#set! injection.language "markdown"))
]],
},
},
-- Vim modes that will show a rendered view of the markdown file
-- All other modes will be uneffected by this plugin
render_modes = { 'n', 'c' },
anti_conceal = {
-- This enables hiding any added text on the line the cursor is on
enabled = true,
-- Number of lines above cursor to show
above = 0,
-- Number of lines below cursor to show
below = 0,
},
padding = {
-- Highlight to use when adding whitespace, should match background
highlight = 'Normal',
},
latex = {
-- Whether LaTeX should be rendered, mainly used for health check
enabled = true,
-- Executable used to convert latex formula to rendered unicode
converter = 'latex2text',
-- Highlight for LaTeX blocks
highlight = 'RenderMarkdownMath',
-- Amount of empty lines above LaTeX blocks
top_pad = 0,
-- Amount of empty lines below LaTeX blocks
bottom_pad = 0,
},
heading = {
-- Turn on / off heading icon & background rendering
enabled = true,
-- Turn on / off any sign column related rendering
sign = true,
-- Determines how icons fill the available space:
-- inline: underlying '#'s are concealed resulting in a left aligned icon
-- overlay: result is left padded with spaces to hide any additional '#'
position = 'overlay',
-- Replaces '#+' of 'atx_h._marker'
-- The number of '#' in the heading determines the 'level'
-- The 'level' is used to index into the array using a cycle
icons = { '󰲡 ', '󰲣 ', '󰲥 ', '󰲧 ', '󰲩 ', '󰲫 ' },
-- Added to the sign column if enabled
-- The 'level' is used to index into the array using a cycle
signs = { '󰫎 ' },
-- Width of the heading background:
-- block: width of the heading text
-- full: full width of the window
-- Can also be an array of the above values in which case the 'level' is used
-- to index into the array using a clamp
width = 'full',
-- Amount of padding to add to the left of headings
left_pad = 0,
-- Amount of padding to add to the right of headings when width is 'block'
right_pad = 0,
-- Minimum width to use for headings when width is 'block'
min_width = 0,
-- Determins if a border is added above and below headings
border = false,
-- Highlight the start of the border using the foreground highlight
border_prefix = false,
-- Used above heading for border
above = '▄',
-- Used below heading for border
below = '▀',
-- The 'level' is used to index into the array using a clamp
-- Highlight for the heading icon and extends through the entire line
backgrounds = {
'RenderMarkdownH1Bg',
'RenderMarkdownH2Bg',
'RenderMarkdownH3Bg',
'RenderMarkdownH4Bg',
'RenderMarkdownH5Bg',
'RenderMarkdownH6Bg',
},
-- The 'level' is used to index into the array using a clamp
-- Highlight for the heading and sign icons
foregrounds = {
'RenderMarkdownH1',
'RenderMarkdownH2',
'RenderMarkdownH3',
'RenderMarkdownH4',
'RenderMarkdownH5',
'RenderMarkdownH6',
},
},
code = {
-- Turn on / off code block & inline code rendering
enabled = true,
-- Turn on / off any sign column related rendering
sign = true,
-- Determines how code blocks & inline code are rendered:
-- none: disables all rendering
-- normal: adds highlight group to code blocks & inline code, adds padding to code blocks
-- language: adds language icon to sign column if enabled and icon + name above code blocks
-- full: normal + language
style = 'full',
-- Determines where language icon is rendered:
-- right: right side of code block
-- left: left side of code block
position = 'left',
-- Amount of padding to add around the language
language_pad = 0,
-- An array of language names for which background highlighting will be disabled
-- Likely because that language has background highlights itself
disable_background = { 'diff' },
-- Width of the code block background:
-- block: width of the code block
-- full: full width of the window
width = 'full',
-- Amount of padding to add to the left of code blocks
left_pad = 0,
-- Amount of padding to add to the right of code blocks when width is 'block'
right_pad = 0,
-- Minimum width to use for code blocks when width is 'block'
min_width = 0,
-- Determins how the top / bottom of code block are rendered:
-- thick: use the same highlight as the code body
-- thin: when lines are empty overlay the above & below icons
border = 'thin',
-- Used above code blocks for thin border
above = '▄',
-- Used below code blocks for thin border
below = '▀',
-- Highlight for code blocks
highlight = 'RenderMarkdownCode',
-- Highlight for inline code
highlight_inline = 'RenderMarkdownCodeInline',
},
dash = {
-- Turn on / off thematic break rendering
enabled = true,
-- Replaces '---'|'***'|'___'|'* * *' of 'thematic_break'
-- The icon gets repeated across the window's width
icon = '─',
-- Width of the generated line:
-- : a hard coded width value
-- full: full width of the window
width = 'full',
-- Highlight for the whole line generated from the icon
highlight = 'RenderMarkdownDash',
},
bullet = {
-- Turn on / off list bullet rendering
enabled = true,
-- Replaces '-'|'+'|'*' of 'list_item'
-- How deeply nested the list is determines the 'level'
-- The 'level' is used to index into the array using a cycle
-- If the item is a 'checkbox' a conceal is used to hide the bullet instead
icons = { '●', '○', '◆', '◇' },
-- Padding to add to the left of bullet point
left_pad = 0,
-- Padding to add to the right of bullet point
right_pad = 0,
-- Highlight for the bullet icon
highlight = 'RenderMarkdownBullet',
},
-- Checkboxes are a special instance of a 'list_item' that start with a 'shortcut_link'
-- There are two special states for unchecked & checked defined in the markdown grammar
checkbox = {
-- Turn on / off checkbox state rendering
enabled = true,
-- Determines how icons fill the available space:
-- inline: underlying text is concealed resulting in a left aligned icon
-- overlay: result is left padded with spaces to hide any additional text
position = 'inline',
unchecked = {
-- Replaces '[ ]' of 'task_list_marker_unchecked'
icon = '󰄱 ',
-- Highlight for the unchecked icon
highlight = 'RenderMarkdownUnchecked',
},
checked = {
-- Replaces '[x]' of 'task_list_marker_checked'
icon = '󰱒 ',
-- Highligh for the checked icon
highlight = 'RenderMarkdownChecked',
},
-- Define custom checkbox states, more involved as they are not part of the markdown grammar
-- As a result this requires neovim >= 0.10.0 since it relies on 'inline' extmarks
-- Can specify as many additional states as you like following the 'todo' pattern below
-- The key in this case 'todo' is for healthcheck and to allow users to change its values
-- 'raw': Matched against the raw text of a 'shortcut_link'
-- 'rendered': Replaces the 'raw' value when rendering
-- 'highlight': Highlight for the 'rendered' icon
custom = {
todo = { raw = '[-]', rendered = '󰥔 ', highlight = 'RenderMarkdownTodo' },
},
},
quote = {
-- Turn on / off block quote & callout rendering
enabled = true,
-- Replaces '>' of 'block_quote'
icon = '▋',
-- Whether to repeat icon on wrapped lines. Requires neovim >= 0.10. This will obscure text if
-- not configured correctly with :h 'showbreak', :h 'breakindent' and :h 'breakindentopt'. A
-- combination of these that is likely to work is showbreak = ' ' (2 spaces), breakindent = true,
-- breakindentopt = '' (empty string). These values are not validated by this plugin. If you want
-- to avoid adding these to your main configuration then set them in win_options for this plugin.
repeat_linebreak = false,
-- Highlight for the quote icon
highlight = 'RenderMarkdownQuote',
},
pipe_table = {
-- Turn on / off pipe table rendering
enabled = true,
-- Pre configured settings largely for setting table border easier
-- heavy: use thicker border characters
-- double: use double line border characters
-- round: use round border corners
-- none: does nothing
preset = 'none',
-- Determines how the table as a whole is rendered:
-- none: disables all rendering
-- normal: applies the 'cell' style rendering to each row of the table
-- full: normal + a top & bottom line that fill out the table when lengths match
style = 'full',
-- Determines how individual cells of a table are rendered:
-- overlay: writes completely over the table, removing conceal behavior and highlights
-- raw: replaces only the '|' characters in each row, leaving the cells unmodified
-- padded: raw + cells are padded to maximum visual width for each column
-- trimmed: padded except empty space is subtracted from visual width calculation
cell = 'padded',
-- Minimum column width to use for padded or trimmed cell
min_width = 0,
-- Characters used to replace table border
-- Correspond to top(3), delimiter(3), bottom(3), vertical, & horizontal
-- stylua: ignore
border = {
'┌', '┬', '┐',
'├', '┼', '┤',
'└', '┴', '┘',
'│', '─',
},
-- Gets placed in delimiter row for each column, position is based on alignmnet
alignment_indicator = '━',
-- Highlight for table heading, delimiter, and the line above
head = 'RenderMarkdownTableHead',
-- Highlight for everything else, main table rows and the line below
row = 'RenderMarkdownTableRow',
-- Highlight for inline padding used to add back concealed space
filler = 'RenderMarkdownTableFill',
},
-- Callouts are a special instance of a 'block_quote' that start with a 'shortcut_link'
-- Can specify as many additional values as you like following the pattern from any below, such as 'note'
-- The key in this case 'note' is for healthcheck and to allow users to change its values
-- 'raw': Matched against the raw text of a 'shortcut_link', case insensitive
-- 'rendered': Replaces the 'raw' value when rendering
-- 'highlight': Highlight for the 'rendered' text and quote markers
callout = {
note = { raw = '[!NOTE]', rendered = '󰋽 Note', highlight = 'RenderMarkdownInfo' },
tip = { raw = '[!TIP]', rendered = '󰌶 Tip', highlight = 'RenderMarkdownSuccess' },
important = { raw = '[!IMPORTANT]', rendered = '󰅾 Important', highlight = 'RenderMarkdownHint' },
warning = { raw = '[!WARNING]', rendered = '󰀪 Warning', highlight = 'RenderMarkdownWarn' },
caution = { raw = '[!CAUTION]', rendered = '󰳦 Caution', highlight = 'RenderMarkdownError' },
-- Obsidian: https://help.obsidian.md/Editing+and+formatting/Callouts
abstract = { raw = '[!ABSTRACT]', rendered = '󰨸 Abstract', highlight = 'RenderMarkdownInfo' },
summary = { raw = '[!SUMMARY]', rendered = '󰨸 Summary', highlight = 'RenderMarkdownInfo' },
tldr = { raw = '[!TLDR]', rendered = '󰨸 Tldr', highlight = 'RenderMarkdownInfo' },
info = { raw = '[!INFO]', rendered = '󰋽 Info', highlight = 'RenderMarkdownInfo' },
todo = { raw = '[!TODO]', rendered = '󰗡 Todo', highlight = 'RenderMarkdownInfo' },
hint = { raw = '[!HINT]', rendered = '󰌶 Hint', highlight = 'RenderMarkdownSuccess' },
success = { raw = '[!SUCCESS]', rendered = '󰄬 Success', highlight = 'RenderMarkdownSuccess' },
check = { raw = '[!CHECK]', rendered = '󰄬 Check', highlight = 'RenderMarkdownSuccess' },
done = { raw = '[!DONE]', rendered = '󰄬 Done', highlight = 'RenderMarkdownSuccess' },
question = { raw = '[!QUESTION]', rendered = '󰘥 Question', highlight = 'RenderMarkdownWarn' },
help = { raw = '[!HELP]', rendered = '󰘥 Help', highlight = 'RenderMarkdownWarn' },
faq = { raw = '[!FAQ]', rendered = '󰘥 Faq', highlight = 'RenderMarkdownWarn' },
attention = { raw = '[!ATTENTION]', rendered = '󰀪 Attention', highlight = 'RenderMarkdownWarn' },
failure = { raw = '[!FAILURE]', rendered = '󰅖 Failure', highlight = 'RenderMarkdownError' },
fail = { raw = '[!FAIL]', rendered = '󰅖 Fail', highlight = 'RenderMarkdownError' },
missing = { raw = '[!MISSING]', rendered = '󰅖 Missing', highlight = 'RenderMarkdownError' },
danger = { raw = '[!DANGER]', rendered = '󱐌 Danger', highlight = 'RenderMarkdownError' },
error = { raw = '[!ERROR]', rendered = '󱐌 Error', highlight = 'RenderMarkdownError' },
bug = { raw = '[!BUG]', rendered = '󰨰 Bug', highlight = 'RenderMarkdownError' },
example = { raw = '[!EXAMPLE]', rendered = '󰉹 Example', highlight = 'RenderMarkdownHint' },
quote = { raw = '[!QUOTE]', rendered = '󱆨 Quote', highlight = 'RenderMarkdownQuote' },
cite = { raw = '[!CITE]', rendered = '󱆨 Cite', highlight = 'RenderMarkdownQuote' },
},
link = {
-- Turn on / off inline link icon rendering
enabled = true,
-- Inlined with 'image' elements
image = '󰥶 ',
-- Inlined with 'email_autolink' elements
email = '󰀓 ',
-- Fallback icon for 'inline_link' elements
hyperlink = '󰌹 ',
-- Applies to the fallback inlined icon
highlight = 'RenderMarkdownLink',
-- Define custom destination patterns so icons can quickly inform you of what a link
-- contains. Applies to 'inline_link' and wikilink nodes.
-- Can specify as many additional values as you like following the 'web' pattern below
-- The key in this case 'web' is for healthcheck and to allow users to change its values
-- 'pattern': Matched against the destination text see :h lua-pattern
-- 'icon': Gets inlined before the link text
-- 'highlight': Highlight for the 'icon'
custom = {
web = { pattern = '^http[s]?://', icon = '󰖟 ', highlight = 'RenderMarkdownLink' },
},
},
sign = {
-- Turn on / off sign rendering
enabled = true,
-- Applies to background of sign text
highlight = 'RenderMarkdownSign',
},
-- Mimic org-indent-mode behavior by indenting everything under a heading based on the
-- level of the heading. Indenting starts from level 2 headings onward.
indent = {
-- Turn on / off org-indent-mode
enabled = false,
-- Amount of additional padding added for each heading level
per_level = 2,
-- Heading levels <= this value will not be indented
-- Use 0 to begin indenting from the very first level
skip_level = 1,
-- Do not indent heading titles, only the body
skip_heading = false,
},
-- Window options to use that change between rendered and raw view
win_options = {
-- See :h 'conceallevel'
conceallevel = {
-- Used when not being rendered, get user setting
default = vim.api.nvim_get_option_value('conceallevel', {}),
-- Used when being rendered, concealed text is completely hidden
rendered = 3,
},
-- See :h 'concealcursor'
concealcursor = {
-- Used when not being rendered, get user setting
default = vim.api.nvim_get_option_value('concealcursor', {}),
-- Used when being rendered, disable concealing text in all modes
rendered = '',
},
},
-- More granular configuration mechanism, allows different aspects of buffers
-- to have their own behavior. Values default to the top level configuration
-- if no override is provided. Supports the following fields:
-- enabled, max_file_size, debounce, render_modes, anti_conceal, padding, heading, code,
-- dash, bullet, checkbox, quote, pipe_table, callout, link, sign, indent, win_options
overrides = {
-- Overrides for different buftypes, see :h 'buftype'
buftype = {
nofile = {
padding = { highlight = 'NormalFloat' },
sign = { enabled = false },
},
},
-- Overrides for different filetypes, see :h 'filetype'
filetype = {},
},
-- Mapping from treesitter language to user defined handlers
-- See 'Custom Handlers' document for more info
custom_handlers = {},
})
```

We use the following definitions when discussing indexing into arrays:

1. Cycle: Indexed `mod` the length.
Example: `{ 1, 2, 3 }` @ 4 = 1.
2. Clamp: Indexed normally but larger values use the last value in the array.
Example: `{ 1, 2, 3 }` @ 4 = 3.

## Headings

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/Headings)

```lua
require('render-markdown').setup({
heading = {
-- Turn on / off heading icon & background rendering
enabled = true,
-- Turn on / off any sign column related rendering
sign = true,
-- Determines how icons fill the available space:
-- inline: underlying '#'s are concealed resulting in a left aligned icon
-- overlay: result is left padded with spaces to hide any additional '#'
position = 'overlay',
-- Replaces '#+' of 'atx_h._marker'
-- The number of '#' in the heading determines the 'level'
-- The 'level' is used to index into the array using a cycle
icons = { '󰲡 ', '󰲣 ', '󰲥 ', '󰲧 ', '󰲩 ', '󰲫 ' },
-- Added to the sign column if enabled
-- The 'level' is used to index into the array using a cycle
signs = { '󰫎 ' },
-- Width of the heading background:
-- block: width of the heading text
-- full: full width of the window
-- Can also be an array of the above values in which case the 'level' is used
-- to index into the array using a clamp
width = 'full',
-- Amount of padding to add to the left of headings
left_pad = 0,
-- Amount of padding to add to the right of headings when width is 'block'
right_pad = 0,
-- Minimum width to use for headings when width is 'block'
min_width = 0,
-- Determins if a border is added above and below headings
border = false,
-- Highlight the start of the border using the foreground highlight
border_prefix = false,
-- Used above heading for border
above = '▄',
-- Used below heading for border
below = '▀',
-- The 'level' is used to index into the array using a clamp
-- Highlight for the heading icon and extends through the entire line
backgrounds = {
'RenderMarkdownH1Bg',
'RenderMarkdownH2Bg',
'RenderMarkdownH3Bg',
'RenderMarkdownH4Bg',
'RenderMarkdownH5Bg',
'RenderMarkdownH6Bg',
},
-- The 'level' is used to index into the array using a clamp
-- Highlight for the heading and sign icons
foregrounds = {
'RenderMarkdownH1',
'RenderMarkdownH2',
'RenderMarkdownH3',
'RenderMarkdownH4',
'RenderMarkdownH5',
'RenderMarkdownH6',
},
},
})
```

## Code Blocks

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/CodeBlocks)

```lua
require('render-markdown').setup({
code = {
-- Turn on / off code block & inline code rendering
enabled = true,
-- Turn on / off any sign column related rendering
sign = true,
-- Determines how code blocks & inline code are rendered:
-- none: disables all rendering
-- normal: adds highlight group to code blocks & inline code, adds padding to code blocks
-- language: adds language icon to sign column if enabled and icon + name above code blocks
-- full: normal + language
style = 'full',
-- Determines where language icon is rendered:
-- right: right side of code block
-- left: left side of code block
position = 'left',
-- Amount of padding to add around the language
language_pad = 0,
-- An array of language names for which background highlighting will be disabled
-- Likely because that language has background highlights itself
disable_background = { 'diff' },
-- Width of the code block background:
-- block: width of the code block
-- full: full width of the window
width = 'full',
-- Amount of padding to add to the left of code blocks
left_pad = 0,
-- Amount of padding to add to the right of code blocks when width is 'block'
right_pad = 0,
-- Minimum width to use for code blocks when width is 'block'
min_width = 0,
-- Determins how the top / bottom of code block are rendered:
-- thick: use the same highlight as the code body
-- thin: when lines are empty overlay the above & below icons
border = 'thin',
-- Used above code blocks for thin border
above = '▄',
-- Used below code blocks for thin border
below = '▀',
-- Highlight for code blocks
highlight = 'RenderMarkdownCode',
-- Highlight for inline code
highlight_inline = 'RenderMarkdownCodeInline',
},
})
```

## Dashed Line

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/DashedLine)

```lua
require('render-markdown').setup({
dash = {
-- Turn on / off thematic break rendering
enabled = true,
-- Replaces '---'|'***'|'___'|'* * *' of 'thematic_break'
-- The icon gets repeated across the window's width
icon = '─',
-- Width of the generated line:
-- : a hard coded width value
-- full: full width of the window
width = 'full',
-- Highlight for the whole line generated from the icon
highlight = 'RenderMarkdownDash',
},
})
```

## List Bullets

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/ListBullets)

```lua
require('render-markdown').setup({
bullet = {
-- Turn on / off list bullet rendering
enabled = true,
-- Replaces '-'|'+'|'*' of 'list_item'
-- How deeply nested the list is determines the 'level'
-- The 'level' is used to index into the array using a cycle
-- If the item is a 'checkbox' a conceal is used to hide the bullet instead
icons = { '●', '○', '◆', '◇' },
-- Padding to add to the left of bullet point
left_pad = 0,
-- Padding to add to the right of bullet point
right_pad = 0,
-- Highlight for the bullet icon
highlight = 'RenderMarkdownBullet',
},
})
```

## Checkboxes

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/Checkboxes)

```lua
require('render-markdown').setup({
-- Checkboxes are a special instance of a 'list_item' that start with a 'shortcut_link'
-- There are two special states for unchecked & checked defined in the markdown grammar
checkbox = {
-- Turn on / off checkbox state rendering
enabled = true,
-- Determines how icons fill the available space:
-- inline: underlying text is concealed resulting in a left aligned icon
-- overlay: result is left padded with spaces to hide any additional text
position = 'inline',
unchecked = {
-- Replaces '[ ]' of 'task_list_marker_unchecked'
icon = '󰄱 ',
-- Highlight for the unchecked icon
highlight = 'RenderMarkdownUnchecked',
},
checked = {
-- Replaces '[x]' of 'task_list_marker_checked'
icon = '󰱒 ',
-- Highligh for the checked icon
highlight = 'RenderMarkdownChecked',
},
-- Define custom checkbox states, more involved as they are not part of the markdown grammar
-- As a result this requires neovim >= 0.10.0 since it relies on 'inline' extmarks
-- Can specify as many additional states as you like following the 'todo' pattern below
-- The key in this case 'todo' is for healthcheck and to allow users to change its values
-- 'raw': Matched against the raw text of a 'shortcut_link'
-- 'rendered': Replaces the 'raw' value when rendering
-- 'highlight': Highlight for the 'rendered' icon
custom = {
todo = { raw = '[-]', rendered = '󰥔 ', highlight = 'RenderMarkdownTodo' },
},
},
})
```

## Block Quotes

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/BlockQuotes)

```lua
require('render-markdown').setup({
quote = {
-- Turn on / off block quote & callout rendering
enabled = true,
-- Replaces '>' of 'block_quote'
icon = '▋',
-- Whether to repeat icon on wrapped lines. Requires neovim >= 0.10. This will obscure text if
-- not configured correctly with :h 'showbreak', :h 'breakindent' and :h 'breakindentopt'. A
-- combination of these that is likely to work is showbreak = ' ' (2 spaces), breakindent = true,
-- breakindentopt = '' (empty string). These values are not validated by this plugin. If you want
-- to avoid adding these to your main configuration then set them in win_options for this plugin.
repeat_linebreak = false,
-- Highlight for the quote icon
highlight = 'RenderMarkdownQuote',
},
})
```

## Tables

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/Tables)

```lua
require('render-markdown').setup({
pipe_table = {
-- Turn on / off pipe table rendering
enabled = true,
-- Pre configured settings largely for setting table border easier
-- heavy: use thicker border characters
-- double: use double line border characters
-- round: use round border corners
-- none: does nothing
preset = 'none',
-- Determines how the table as a whole is rendered:
-- none: disables all rendering
-- normal: applies the 'cell' style rendering to each row of the table
-- full: normal + a top & bottom line that fill out the table when lengths match
style = 'full',
-- Determines how individual cells of a table are rendered:
-- overlay: writes completely over the table, removing conceal behavior and highlights
-- raw: replaces only the '|' characters in each row, leaving the cells unmodified
-- padded: raw + cells are padded to maximum visual width for each column
-- trimmed: padded except empty space is subtracted from visual width calculation
cell = 'padded',
-- Minimum column width to use for padded or trimmed cell
min_width = 0,
-- Characters used to replace table border
-- Correspond to top(3), delimiter(3), bottom(3), vertical, & horizontal
-- stylua: ignore
border = {
'┌', '┬', '┐',
'├', '┼', '┤',
'└', '┴', '┘',
'│', '─',
},
-- Gets placed in delimiter row for each column, position is based on alignmnet
alignment_indicator = '━',
-- Highlight for table heading, delimiter, and the line above
head = 'RenderMarkdownTableHead',
-- Highlight for everything else, main table rows and the line below
row = 'RenderMarkdownTableRow',
-- Highlight for inline padding used to add back concealed space
filler = 'RenderMarkdownTableFill',
},
})
```

## Callouts

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/Callouts)

```lua
require('render-markdown').setup({
-- Callouts are a special instance of a 'block_quote' that start with a 'shortcut_link'
-- Can specify as many additional values as you like following the pattern from any below, such as 'note'
-- The key in this case 'note' is for healthcheck and to allow users to change its values
-- 'raw': Matched against the raw text of a 'shortcut_link', case insensitive
-- 'rendered': Replaces the 'raw' value when rendering
-- 'highlight': Highlight for the 'rendered' text and quote markers
callout = {
note = { raw = '[!NOTE]', rendered = '󰋽 Note', highlight = 'RenderMarkdownInfo' },
tip = { raw = '[!TIP]', rendered = '󰌶 Tip', highlight = 'RenderMarkdownSuccess' },
important = { raw = '[!IMPORTANT]', rendered = '󰅾 Important', highlight = 'RenderMarkdownHint' },
warning = { raw = '[!WARNING]', rendered = '󰀪 Warning', highlight = 'RenderMarkdownWarn' },
caution = { raw = '[!CAUTION]', rendered = '󰳦 Caution', highlight = 'RenderMarkdownError' },
-- Obsidian: https://help.obsidian.md/Editing+and+formatting/Callouts
abstract = { raw = '[!ABSTRACT]', rendered = '󰨸 Abstract', highlight = 'RenderMarkdownInfo' },
summary = { raw = '[!SUMMARY]', rendered = '󰨸 Summary', highlight = 'RenderMarkdownInfo' },
tldr = { raw = '[!TLDR]', rendered = '󰨸 Tldr', highlight = 'RenderMarkdownInfo' },
info = { raw = '[!INFO]', rendered = '󰋽 Info', highlight = 'RenderMarkdownInfo' },
todo = { raw = '[!TODO]', rendered = '󰗡 Todo', highlight = 'RenderMarkdownInfo' },
hint = { raw = '[!HINT]', rendered = '󰌶 Hint', highlight = 'RenderMarkdownSuccess' },
success = { raw = '[!SUCCESS]', rendered = '󰄬 Success', highlight = 'RenderMarkdownSuccess' },
check = { raw = '[!CHECK]', rendered = '󰄬 Check', highlight = 'RenderMarkdownSuccess' },
done = { raw = '[!DONE]', rendered = '󰄬 Done', highlight = 'RenderMarkdownSuccess' },
question = { raw = '[!QUESTION]', rendered = '󰘥 Question', highlight = 'RenderMarkdownWarn' },
help = { raw = '[!HELP]', rendered = '󰘥 Help', highlight = 'RenderMarkdownWarn' },
faq = { raw = '[!FAQ]', rendered = '󰘥 Faq', highlight = 'RenderMarkdownWarn' },
attention = { raw = '[!ATTENTION]', rendered = '󰀪 Attention', highlight = 'RenderMarkdownWarn' },
failure = { raw = '[!FAILURE]', rendered = '󰅖 Failure', highlight = 'RenderMarkdownError' },
fail = { raw = '[!FAIL]', rendered = '󰅖 Fail', highlight = 'RenderMarkdownError' },
missing = { raw = '[!MISSING]', rendered = '󰅖 Missing', highlight = 'RenderMarkdownError' },
danger = { raw = '[!DANGER]', rendered = '󱐌 Danger', highlight = 'RenderMarkdownError' },
error = { raw = '[!ERROR]', rendered = '󱐌 Error', highlight = 'RenderMarkdownError' },
bug = { raw = '[!BUG]', rendered = '󰨰 Bug', highlight = 'RenderMarkdownError' },
example = { raw = '[!EXAMPLE]', rendered = '󰉹 Example', highlight = 'RenderMarkdownHint' },
quote = { raw = '[!QUOTE]', rendered = '󱆨 Quote', highlight = 'RenderMarkdownQuote' },
cite = { raw = '[!CITE]', rendered = '󱆨 Cite', highlight = 'RenderMarkdownQuote' },
},
})
```

## Links

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/Links)

```lua
require('render-markdown').setup({
link = {
-- Turn on / off inline link icon rendering
enabled = true,
-- Inlined with 'image' elements
image = '󰥶 ',
-- Inlined with 'email_autolink' elements
email = '󰀓 ',
-- Fallback icon for 'inline_link' elements
hyperlink = '󰌹 ',
-- Applies to the fallback inlined icon
highlight = 'RenderMarkdownLink',
-- Define custom destination patterns so icons can quickly inform you of what a link
-- contains. Applies to 'inline_link' and wikilink nodes.
-- Can specify as many additional values as you like following the 'web' pattern below
-- The key in this case 'web' is for healthcheck and to allow users to change its values
-- 'pattern': Matched against the destination text see :h lua-pattern
-- 'icon': Gets inlined before the link text
-- 'highlight': Highlight for the 'icon'
custom = {
web = { pattern = '^http[s]?://', icon = '󰖟 ', highlight = 'RenderMarkdownLink' },
},
},
})
```

## Signs

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/Signs)

```lua
require('render-markdown').setup({
sign = {
-- Turn on / off sign rendering
enabled = true,
-- Applies to background of sign text
highlight = 'RenderMarkdownSign',
},
})
```

## Indent

[Wiki Page](https://github.com/MeanderingProgrammer/render-markdown.nvim/wiki/Indent)

```lua
require('render-markdown').setup({
-- Mimic org-indent-mode behavior by indenting everything under a heading based on the
-- level of the heading. Indenting starts from level 2 headings onward.
indent = {
-- Turn on / off org-indent-mode
enabled = false,
-- Amount of additional padding added for each heading level
per_level = 2,
-- Heading levels <= this value will not be indented
-- Use 0 to begin indenting from the very first level
skip_level = 1,
-- Do not indent heading titles, only the body
skip_heading = false,
},
})
```

# Colors

The table below shows all the highlight groups with their default link

| Highlight Group | Default Group | Description |
| ------------------------ | ---------------------------------- | ------------------------- |
| RenderMarkdownH1 | @markup.heading.1.markdown | H1 icons |
| RenderMarkdownH2 | @markup.heading.2.markdown | H2 icons |
| RenderMarkdownH3 | @markup.heading.3.markdown | H3 icons |
| RenderMarkdownH4 | @markup.heading.4.markdown | H4 icons |
| RenderMarkdownH5 | @markup.heading.5.markdown | H5 icons |
| RenderMarkdownH6 | @markup.heading.6.markdown | H6 icons |
| RenderMarkdownH1Bg | DiffAdd | H1 background line |
| RenderMarkdownH2Bg | DiffChange | H2 background line |
| RenderMarkdownH3Bg | DiffDelete | H3 background line |
| RenderMarkdownH4Bg | DiffDelete | H4 background line |
| RenderMarkdownH5Bg | DiffDelete | H5 background line |
| RenderMarkdownH6Bg | DiffDelete | H6 background line |
| RenderMarkdownCode | ColorColumn | Code block background |
| RenderMarkdownCodeInline | RenderMarkdownCode | Inline code background |
| RenderMarkdownBullet | Normal | List item bullet points |
| RenderMarkdownQuote | @markup.quote | Block quote marker |
| RenderMarkdownDash | LineNr | Thematic break line |
| RenderMarkdownLink | @markup.link.label.markdown_inline | Image & hyperlink icons |
| RenderMarkdownSign | SignColumn | Sign column background |
| RenderMarkdownMath | @markup.math | LaTeX lines |
| RenderMarkdownUnchecked | @markup.list.unchecked | Unchecked checkbox |
| RenderMarkdownChecked | @markup.list.checked | Checked checkbox |
| RenderMarkdownTodo | @markup.raw | Todo custom checkbox |
| RenderMarkdownTableHead | @markup.heading | Pipe table heading rows |
| RenderMarkdownTableRow | Normal | Pipe table body rows |
| RenderMarkdownTableFill | Conceal | Pipe table inline padding |
| RenderMarkdownSuccess | DiagnosticOk | Success related callouts |
| RenderMarkdownInfo | DiagnosticInfo | Info related callouts |
| RenderMarkdownHint | DiagnosticHint | Hint related callouts |
| RenderMarkdownWarn | DiagnosticWarn | Warning related callouts |
| RenderMarkdownError | DiagnosticError | Error related callouts |

# Info

## vimwiki

> [!NOTE]
>
> [vimwiki](https://github.com/vimwiki/vimwiki) overrides the `filetype` of
> `markdown` files, as such there are additional setup steps.
>
> - Add `vimwiki` to the `file_types` configuration of this plugin
>
> ```lua
> require('render-markdown').setup({
> file_types = { 'markdown', 'vimwiki' },
> })
> ```
>
> - Register `markdown` as the parser for `vimwiki` files
>
> ```lua
> vim.treesitter.language.register('markdown', 'vimwiki')
> ```

## obsidian.nvim

> [!NOTE]
>
> [obsidian.nvim](https://github.com/epwalsh/obsidian.nvim) provides UI functionality
> that is enabled by default. While there may be a way to have the 2 work together,
> for the foreseeable future only one of these plugins should be used for the UI.
> If you choose this plugin disable the `obsidian.nvim` UI with:
>
> ```lua
> require('obsidian').setup({
> ui = { enable = false },
> })
> ```
>
> You can also do something more custom like lazy loading this plugin via a command
> and adding logic to the config method to disable `obsidian.nvim` as suggested in
> [#116](https://github.com/MeanderingProgrammer/render-markdown.nvim/issues/116),
> though things like this can break at any time given the reliance on internal logic:
>
> ```lua
> return {
> 'MeanderingProgrammer/render-markdown.nvim',
> cmd = { 'RenderMarkdown' },
> dependencies = { 'nvim-treesitter/nvim-treesitter', 'echasnovski/mini.nvim' },
> config = function()
> require('obsidian').get_client().opts.ui.enable = false
> vim.api.nvim_buf_clear_namespace(0, vim.api.nvim_get_namespaces()['ObsidianUI'], 0, -1)
> require('render-markdown').setup({})
> end,
> }
> ```

## Images

> [!NOTE]
>
> Images are only supported so far as this plugin will not interfere with others
> like [image.nvim](https://github.com/3rd/image.nvim), however nothing is done
> natively by this plugin.
> It is recommended to enable the `only_render_image_at_cursor` option.

## Additional

- [Limitations](doc/limitations.md): Known limitations of this plugin
- [Custom Handlers](doc/custom-handlers.md): Allow users to integrate custom rendering
for either unsupported languages or to override / extend builtin implementations
- [Troubleshooting Guide](doc/troubleshooting.md)
- [Purpose](doc/purpose.md): Why this plugin exists
- [Markdown Ecosystem](doc/markdown-ecosystem.md): Information about other `markdown`
related plugins and how they co-exist

# Donate

I enjoy working on these projects and will continue to do so with the time I can
find. Any support is appreciated including starring the repo and reporting issues.
Money is also nice: [Donate via Stripe](https://donate.stripe.com/4gw2bSbwA5gw5s48ww).