Skip to content

Commit

Permalink
feature: Set custom highlight groups with default links to better sup…
Browse files Browse the repository at this point in the history
…port colorschemes

## Details

Request: #70

The current approach of using standard highlight groups works well,
however if color scheme maintainers wish to support this plugin specifically
it will impact everywhere else the highlight groups are used.

To improve this add a level of indirection. Create custom highlights
that link to all the same defaults as currently used. That way changing
the underlying links still has the same impact as well as being backwards
compatible. Users setting custom values also remain unaffected.

However color scheme maintainers can override the highlights used by
this plugin giving them the ability to apply their theme better to this
plugin specifically.

I do not think this will be a very common trend, but I am more than
happy to support it. Add a table to the README with all the highlghts
and default links.
  • Loading branch information
MeanderingProgrammer committed Jul 18, 2024
1 parent 3c36a25 commit 0f32655
Show file tree
Hide file tree
Showing 13 changed files with 398 additions and 226 deletions.
168 changes: 101 additions & 67 deletions README.md

Large diffs are not rendered by default.

Binary file modified demo/box_dash_quote.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/callout.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/heading_code.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/latex.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified demo/list_table.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
210 changes: 141 additions & 69 deletions doc/render-markdown.txt

Large diffs are not rendered by default.

52 changes: 50 additions & 2 deletions lua/render-markdown/colors.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,59 @@ local cache = {
---@class render.md.Colors
local M = {}

---@private
---@type string
M.prefix = 'RenderMarkdown'

-- stylua: ignore
---@private
---@type table<string, string>
M.colors = {
-- Headings
H1 = '@markup.heading.1.markdown',
H2 = '@markup.heading.2.markdown',
H3 = '@markup.heading.3.markdown',
H4 = '@markup.heading.4.markdown',
H5 = '@markup.heading.5.markdown',
H6 = '@markup.heading.6.markdown',
H1Bg = 'DiffAdd',
H2Bg = 'DiffChange',
H3Bg = 'DiffDelete',
-- General
Code = 'ColorColumn',
Bullet = 'Normal',
Quote = '@markup.quote',
Dash = 'LineNr',
Link = '@markup.link.label.markdown_inline',
Sign = 'SignColumn',
Math = '@markup.math',
-- Checkboxes
Unchecked = '@markup.list.unchecked',
Checked = '@markup.list.checked',
Todo = '@markup.raw',
-- Pipe tables
TableHead = '@markup.heading',
TableRow = 'Normal',
TableFill = 'Conceal',
-- Callouts
Success = 'DiagnosticOk',
Info = 'DiagnosticInfo',
Hint = 'DiagnosticHint',
Warn = 'DiagnosticWarn',
Error = 'DiagnosticError',
}

function M.setup()
for name, link in pairs(M.colors) do
vim.api.nvim_set_hl(0, M.prefix .. name, { link = link, default = true })
end
end

---@param foreground string
---@param background string
---@return string
M.combine = function(foreground, background)
local name = string.format('RenderMd_%s_%s', foreground, background)
local name = string.format('%s_%s_%s', M.prefix, foreground, background)
if not vim.tbl_contains(cache.highlights, name) then
local fg = M.get_hl(foreground).fg
local bg = M.get_hl(background).bg
Expand All @@ -26,7 +74,7 @@ end
---@param highlight string
---@return string
M.inverse = function(highlight)
local name = string.format('RenderMd_Inverse_%s', highlight)
local name = string.format('%s_Inverse_%s', M.prefix, highlight)
if not vim.tbl_contains(cache.highlights, name) then
local hl = M.get_hl(highlight)
vim.api.nvim_set_hl(0, name, { fg = hl.bg, bg = hl.fg })
Expand Down
70 changes: 36 additions & 34 deletions lua/render-markdown/init.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local colors = require('render-markdown.colors')
local manager = require('render-markdown.manager')
local state = require('render-markdown.state')

Expand Down Expand Up @@ -193,7 +194,7 @@ M.default_config = {
-- Executable used to convert latex formula to rendered unicode
converter = 'latex2text',
-- Highlight for LaTeX blocks
highlight = '@markup.math',
highlight = 'RenderMarkdownMath',
},
heading = {
-- Turn on / off heading icon & background rendering
Expand All @@ -210,16 +211,16 @@ M.default_config = {
signs = { '󰫎 ' },
-- The 'level' is used to index into the array using a clamp
-- Highlight for the heading icon and extends through the entire line
backgrounds = { 'DiffAdd', 'DiffChange', 'DiffDelete' },
backgrounds = { 'RenderMarkdownH1Bg', 'RenderMarkdownH2Bg', 'RenderMarkdownH3Bg' },
-- The 'level' is used to index into the array using a clamp
-- Highlight for the heading and sign icons
foregrounds = {
'@markup.heading.1.markdown',
'@markup.heading.2.markdown',
'@markup.heading.3.markdown',
'@markup.heading.4.markdown',
'@markup.heading.5.markdown',
'@markup.heading.6.markdown',
'RenderMarkdownH1',
'RenderMarkdownH2',
'RenderMarkdownH3',
'RenderMarkdownH4',
'RenderMarkdownH5',
'RenderMarkdownH6',
},
},
code = {
Expand All @@ -244,7 +245,7 @@ M.default_config = {
-- Used below code blocks for thin border
below = '',
-- Highlight for code blocks & inline code
highlight = 'ColorColumn',
highlight = 'RenderMarkdownCode',
},
dash = {
-- Turn on / off thematic break rendering
Expand All @@ -253,7 +254,7 @@ M.default_config = {
-- The icon gets repeated across the window's width
icon = '',
-- Highlight for the whole line generated from the icon
highlight = 'LineNr',
highlight = 'RenderMarkdownDash',
},
bullet = {
-- Turn on / off list bullet rendering
Expand All @@ -264,7 +265,7 @@ M.default_config = {
-- If the item is a 'checkbox' a conceal is used to hide the bullet instead
icons = { '', '', '', '' },
-- Highlight for the bullet icon
highlight = 'Normal',
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
Expand All @@ -275,13 +276,13 @@ M.default_config = {
-- Replaces '[ ]' of 'task_list_marker_unchecked'
icon = '󰄱 ',
-- Highlight for the unchecked icon
highlight = '@markup.list.unchecked',
highlight = 'RenderMarkdownUnchecked',
},
checked = {
-- Replaces '[x]' of 'task_list_marker_checked'
icon = '󰱒 ',
-- Highligh for the checked icon
highlight = '@markup.heading',
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
Expand All @@ -291,7 +292,7 @@ M.default_config = {
-- 'rendered': Replaces the 'raw' value when rendering
-- 'highlight': Highlight for the 'rendered' icon
custom = {
todo = { raw = '[-]', rendered = '󰥔 ', highlight = '@markup.raw' },
todo = { raw = '[-]', rendered = '󰥔 ', highlight = 'RenderMarkdownTodo' },
},
},
quote = {
Expand All @@ -300,7 +301,7 @@ M.default_config = {
-- Replaces '>' of 'block_quote'
icon = '',
-- Highlight for the quote icon
highlight = '@markup.quote',
highlight = 'RenderMarkdownQuote',
},
pipe_table = {
-- Turn on / off pipe table rendering
Expand All @@ -325,11 +326,11 @@ M.default_config = {
'', '',
},
-- Highlight for table heading, delimiter, and the line above
head = '@markup.heading',
head = 'RenderMarkdownTableHead',
-- Highlight for everything else, main table rows and the line below
row = 'Normal',
row = 'RenderMarkdownTableRow',
-- Highlight for inline padding used to add back concealed space
filler = 'Conceal',
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'
Expand All @@ -338,21 +339,21 @@ M.default_config = {
-- 'rendered': Replaces the 'raw' value when rendering
-- 'highlight': Highlight for the 'rendered' text and quote markers
callout = {
note = { raw = '[!NOTE]', rendered = '󰋽 Note', highlight = 'DiagnosticInfo' },
tip = { raw = '[!TIP]', rendered = '󰌶 Tip', highlight = 'DiagnosticOk' },
important = { raw = '[!IMPORTANT]', rendered = '󰅾 Important', highlight = 'DiagnosticHint' },
warning = { raw = '[!WARNING]', rendered = '󰀪 Warning', highlight = 'DiagnosticWarn' },
caution = { raw = '[!CAUTION]', rendered = '󰳦 Caution', highlight = 'DiagnosticError' },
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.a.md/Editing+and+formatting/Callouts
abstract = { raw = '[!ABSTRACT]', rendered = '󰨸 Abstract', highlight = 'DiagnosticInfo' },
todo = { raw = '[!TODO]', rendered = '󰗡 Todo', highlight = 'DiagnosticInfo' },
success = { raw = '[!SUCCESS]', rendered = '󰄬 Success', highlight = 'DiagnosticOk' },
question = { raw = '[!QUESTION]', rendered = '󰘥 Question', highlight = 'DiagnosticWarn' },
failure = { raw = '[!FAILURE]', rendered = '󰅖 Failure', highlight = 'DiagnosticError' },
danger = { raw = '[!DANGER]', rendered = '󱐌 Danger', highlight = 'DiagnosticError' },
bug = { raw = '[!BUG]', rendered = '󰨰 Bug', highlight = 'DiagnosticError' },
example = { raw = '[!EXAMPLE]', rendered = '󰉹 Example', highlight = 'DiagnosticHint' },
quote = { raw = '[!QUOTE]', rendered = '󱆨 Quote', highlight = '@markup.quote' },
abstract = { raw = '[!ABSTRACT]', rendered = '󰨸 Abstract', highlight = 'RenderMarkdownInfo' },
todo = { raw = '[!TODO]', rendered = '󰗡 Todo', highlight = 'RenderMarkdownInfo' },
success = { raw = '[!SUCCESS]', rendered = '󰄬 Success', highlight = 'RenderMarkdownSuccess' },
question = { raw = '[!QUESTION]', rendered = '󰘥 Question', highlight = 'RenderMarkdownWarn' },
failure = { raw = '[!FAILURE]', rendered = '󰅖 Failure', highlight = 'RenderMarkdownError' },
danger = { raw = '[!DANGER]', rendered = '󱐌 Danger', highlight = 'RenderMarkdownError' },
bug = { raw = '[!BUG]', rendered = '󰨰 Bug', highlight = 'RenderMarkdownError' },
example = { raw = '[!EXAMPLE]', rendered = '󰉹 Example', highlight = 'RenderMarkdownHint' },
quote = { raw = '[!QUOTE]', rendered = '󱆨 Quote', highlight = 'RenderMarkdownQuote' },
},
link = {
-- Turn on / off inline link icon rendering
Expand All @@ -362,7 +363,7 @@ M.default_config = {
-- Inlined with 'inline_link' elements
hyperlink = '󰌹 ',
-- Applies to the inlined icon
highlight = '@markup.link.label.markdown_inline',
highlight = 'RenderMarkdownLink',
},
sign = {
-- Turn on / off sign rendering
Expand All @@ -372,7 +373,7 @@ M.default_config = {
buftypes = { 'nofile' },
},
-- Applies to background of sign text
highlight = 'SignColumn',
highlight = 'RenderMarkdownSign',
},
-- Window options to use that change between rendered and raw view
win_options = {
Expand Down Expand Up @@ -407,6 +408,7 @@ function M.setup(opts)
state.inline_link_query = vim.treesitter.query.parse('markdown_inline', state.config.inline_link_query)
end)

colors.setup()
manager.setup()

vim.api.nvim_create_user_command('RenderMarkdown', M.command, {
Expand Down
12 changes: 6 additions & 6 deletions tests/box_dash_quote_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@ async_tests.describe('box_dash_quote.md', function()
vim.list_extend(expected, util.heading(0, 1))

-- Checkboxes
vim.list_extend(expected, util.checkbox(2, ' 󰄱 ', '@markup.list.unchecked', false))
vim.list_extend(expected, util.checkbox(3, ' 󰱒 ', '@markup.heading', false))
vim.list_extend(expected, util.checkbox(4, ' 󰥔 ', '@markup.raw', true))
vim.list_extend(expected, util.checkbox(2, ' 󰄱 ', 'RenderMarkdownUnchecked', false))
vim.list_extend(expected, util.checkbox(3, ' 󰱒 ', 'RenderMarkdownChecked', false))
vim.list_extend(expected, util.checkbox(4, ' 󰥔 ', 'RenderMarkdownTodo', true))

-- Line break
vim.list_extend(expected, {
{
row = { 6 },
col = { 0 },
virt_text = { { string.rep('', vim.opt.columns:get()), 'LineNr' } },
virt_text = { { string.rep('', vim.opt.columns:get()), 'RenderMarkdownDash' } },
virt_text_pos = 'overlay',
},
})

-- Quote lines
vim.list_extend(expected, {
util.quote(8, ' %s ', '@markup.quote'),
util.quote(9, ' %s ', '@markup.quote'),
util.quote(8, ' %s ', 'Quote'),
util.quote(9, ' %s ', 'Quote'),
})

local actual = util.get_actual_marks()
Expand Down
12 changes: 6 additions & 6 deletions tests/callout_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ local function callout(row, start_col, end_col, text, highlight)
return {
row = { row, row },
col = { start_col, end_col },
virt_text = { { text, highlight } },
virt_text = { { text, 'RenderMarkdown' .. highlight } },
virt_text_pos = 'overlay',
}
end
Expand All @@ -20,11 +20,11 @@ async_tests.describe('callout.md', function()
async_tests.it('default', function()
util.setup('demo/callout.md')

local info = 'DiagnosticInfo'
local ok = 'DiagnosticOk'
local hint = 'DiagnosticHint'
local warn = 'DiagnosticWarn'
local error = 'DiagnosticError'
local info = 'Info'
local ok = 'Success'
local hint = 'Hint'
local warn = 'Warn'
local error = 'Error'

local expected = {}

Expand Down
37 changes: 20 additions & 17 deletions tests/latex_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ local util = require('tests.util')

local eq = assert.are.same

---@param start_row integer
---@param end_row integer
---@param start_col integer
---@param end_col integer
---@param lines string[]
---@return render.md.MarkInfo
local function latex(start_row, end_row, start_col, end_col, lines)
local virt_lines = vim.tbl_map(function(line)
return { { line, 'RenderMarkdownMath' } }
end, lines)
return {
row = { start_row, end_row },
col = { start_col, end_col },
virt_lines = virt_lines,
virt_lines_above = true,
}
end

async_tests.describe('latex.md', function()
async_tests.it('default', function()
stub.new(vim.fn, 'executable', function(expr)
Expand All @@ -23,27 +41,12 @@ async_tests.describe('latex.md', function()

local expected = {}

-- Heading
vim.list_extend(expected, util.heading(0, 1))

vim.list_extend(expected, {
-- Inline
{
row = { 2, 2 },
col = { 0, 21 },
virt_lines = { { { '√(3x-1)+(1+x)^2', '@markup.math' } } },
virt_lines_above = true,
},
latex(2, 2, 0, 21, { '√(3x-1)+(1+x)^2' }),
-- Block
{
row = { 4, 7 },
col = { 0, 2 },
virt_lines = {
{ { 'f(x,y) = x + √(y)', '@markup.math' } },
{ { 'f(x,y) = √(y) + x^2/4y', '@markup.math' } },
},
virt_lines_above = true,
},
latex(4, 7, 0, 2, { 'f(x,y) = x + √(y)', 'f(x,y) = √(y) + x^2/4y' }),
})

local actual = util.get_actual_marks()
Expand Down
Loading

0 comments on commit 0f32655

Please sign in to comment.