Skip to content

Commit 6f87257

Browse files
feat(dev): add debug API that prints marks on current line
## Details Adds `:RenderMarkdown debug` command which gets marks that interact with current line and prints a more concise view of the extmark details. Mostly intended for development purposes but could be useful for debugging certain kinds of user problems.
1 parent f84eeae commit 6f87257

File tree

8 files changed

+225
-30
lines changed

8 files changed

+225
-30
lines changed

README.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,16 @@ use({
9595

9696
# Commands
9797

98-
- `:RenderMarkdown` | `:RenderMarkdown enable` - Enable this plugin
99-
- Can also be accessed directly through `require('render-markdown').enable()`
100-
- `:RenderMarkdown disable` - Disable this plugin
101-
- Can also be accessed directly through `require('render-markdown').disable()`
102-
- `:RenderMarkdown toggle` - Switch between enabling & disabling this plugin
103-
- Can also be accessed directly through `require('render-markdown').toggle()`
104-
- `:RenderMarkdown log` - Opens the log file for this plugin
105-
- Can also be accessed directly through `require('render-markdown').log()`
106-
- `:RenderMarkdown expand` - Increase anti-conceal margin above and below by 1
107-
- Can also be accessed directly through `require('render-markdown').expand()`
108-
- `:RenderMarkdown contract` - Decrease anti-conceal margin above and below by 1
109-
- Can also be accessed directly through `require('render-markdown').contract()`
98+
| Command | Lua Function | Description |
99+
| -------------------------- | --------------------------------------- | ------------------------------------------------- |
100+
| `:RenderMarkdown` | `require('render-markdown').enable()` | Enable this plugin |
101+
| `:RenderMarkdown enable` | `require('render-markdown').enable()` | Enable this plugin |
102+
| `:RenderMarkdown disable` | `require('render-markdown').disable()` | Disable this plugin |
103+
| `:RenderMarkdown toggle` | `require('render-markdown').toggle()` | Switch between enabling & disabling this plugin |
104+
| `:RenderMarkdown log` | `require('render-markdown').log()` | Opens the log file for this plugin |
105+
| `:RenderMarkdown expand` | `require('render-markdown').expand()` | Increase anti-conceal margin above and below by 1 |
106+
| `:RenderMarkdown contract` | `require('render-markdown').contract()` | Decrease anti-conceal margin above and below by 1 |
107+
| `:RenderMarkdown debug` | `require('render-markdown').debug()` | Prints information about marks on current line |
110108

111109
# Setup
112110

doc/render-markdown.txt

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*render-markdown.txt* For 0.10.0 Last change: 2024 September 15
1+
*render-markdown.txt* For 0.10.0 Last change: 2024 September 16
22

33
==============================================================================
44
Table of Contents *render-markdown-table-of-contents*
@@ -126,19 +126,30 @@ PACKER.NVIM *render-markdown-install-packer.nvim*
126126
==============================================================================
127127
5. Commands *render-markdown-commands*
128128

129-
- `:RenderMarkdown` | `:RenderMarkdown enable` - Enable this plugin
130-
- Can also be accessed directly through `require('render-markdown').enable()`
131-
- `:RenderMarkdown disable` - Disable this plugin
132-
- Can also be accessed directly through `require('render-markdown').disable()`
133-
- `:RenderMarkdown toggle` - Switch between enabling & disabling this plugin
134-
- Can also be accessed directly through `require('render-markdown').toggle()`
135-
- `:RenderMarkdown log` - Opens the log file for this plugin
136-
- Can also be accessed directly through `require('render-markdown').log()`
137-
- `:RenderMarkdown expand` - Increase anti-conceal margin above and below by 1
138-
- Can also be accessed directly through `require('render-markdown').expand()`
139-
- `:RenderMarkdown contract` - Decrease anti-conceal margin above and below by 1
140-
- Can also be accessed directly through `require('render-markdown').contract()`
129+
-------------------------------------------------------------------------------------------------
130+
Command Lua Function Description
131+
-------------------------- --------------------------------------- ------------------------------
132+
:RenderMarkdown require('render-markdown').enable() Enable this plugin
141133

134+
:RenderMarkdown enable require('render-markdown').enable() Enable this plugin
135+
136+
:RenderMarkdown disable require('render-markdown').disable() Disable this plugin
137+
138+
:RenderMarkdown toggle require('render-markdown').toggle() Switch between enabling &
139+
disabling this plugin
140+
141+
:RenderMarkdown log require('render-markdown').log() Opens the log file for this
142+
plugin
143+
144+
:RenderMarkdown expand require('render-markdown').expand() Increase anti-conceal margin
145+
above and below by 1
146+
147+
:RenderMarkdown contract require('render-markdown').contract() Decrease anti-conceal margin
148+
above and below by 1
149+
150+
:RenderMarkdown debug require('render-markdown').debug() Prints information about marks
151+
on current line
152+
-------------------------------------------------------------------------------------------------
142153

143154
==============================================================================
144155
6. Setup *render-markdown-setup*

lua/render-markdown/api.lua

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
local log = require('render-markdown.core.log')
21
local manager = require('render-markdown.manager')
32
local state = require('render-markdown.state')
43

@@ -18,6 +17,7 @@ function M.toggle()
1817
end
1918

2019
function M.log()
20+
local log = require('render-markdown.core.log')
2121
log.flush()
2222
vim.cmd.tabnew(log.file)
2323
end
@@ -32,4 +32,10 @@ function M.contract()
3232
M.enable()
3333
end
3434

35+
function M.debug()
36+
local buf = vim.api.nvim_get_current_buf()
37+
local row, marks = require('render-markdown.core.ui').get_row_marks(buf)
38+
require('render-markdown.core.debug_marks').debug(row, marks)
39+
end
40+
3541
return M
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---@class render.md.DebugMark
2+
---@field conceal boolean
3+
---@field opts vim.api.keyset.set_extmark
4+
---@field row { [1]: integer, [2]: integer }
5+
---@field col { [1]: integer, [2]: integer }
6+
local DebugMark = {}
7+
DebugMark.__index = DebugMark
8+
9+
---@param mark render.md.Mark
10+
---@return render.md.DebugMark
11+
function DebugMark.new(mark)
12+
local self = setmetatable({}, DebugMark)
13+
self.conceal, self.opts = mark.conceal, mark.opts
14+
self.row = { mark.start_row, mark.opts.end_row or mark.start_row }
15+
self.col = { mark.start_col, mark.opts.end_col or mark.start_col }
16+
return self
17+
end
18+
19+
---@return integer[]
20+
function DebugMark:priorities()
21+
local row_offset = 0
22+
if self.opts.virt_lines ~= nil then
23+
row_offset = self.opts.virt_lines_above and -0.5 or 0.5
24+
end
25+
local col = self.opts.virt_text_win_col or 0
26+
local result = { self.row[1] + row_offset, self.row[2] + row_offset }
27+
return vim.list_extend(result, { math.max(self.col[1], col), math.max(self.col[2], col) })
28+
end
29+
30+
---@return string
31+
function DebugMark:__tostring()
32+
---@param text string
33+
---@return string
34+
local function serialize_text(text)
35+
local chars = vim.fn.str2list(text)
36+
if #chars <= 1 then
37+
return string.format('"%s"', text)
38+
end
39+
local first = chars[1]
40+
for _, char in ipairs(chars) do
41+
if first ~= char then
42+
return string.format('"%s"', text)
43+
end
44+
end
45+
return string.format('rep(%s, %d)', vim.fn.nr2char(first), #chars)
46+
end
47+
48+
---@param highlight number|string|string[]
49+
---@return string
50+
local function serialize_highlight(highlight)
51+
if type(highlight) == 'table' then
52+
highlight = table.concat(highlight, '+')
53+
end
54+
local result, _ = highlight:gsub('RenderMarkdown_?', '')
55+
result, _ = result:gsub('Inverse', 'I')
56+
return string.format('(%s)', result)
57+
end
58+
59+
---@param line { [1]?: string, [2]?: number|string|string[] }[]
60+
---@return string[]?
61+
local function virt_line(line)
62+
local result = {}
63+
for _, part in ipairs(line) do
64+
local serialized, text, highlight = {}, part[1], part[2]
65+
if text ~= nil then
66+
table.insert(serialized, serialize_text(text))
67+
end
68+
if highlight ~= nil then
69+
table.insert(serialized, serialize_highlight(highlight))
70+
end
71+
if #serialized > 0 then
72+
table.insert(result, table.concat(serialized, '::'))
73+
end
74+
end
75+
return #result > 0 and result or nil
76+
end
77+
78+
---@param vals { [1]: integer, [2]: integer }
79+
---@return string|integer
80+
local function collapse(vals)
81+
return vals[1] == vals[2] and vals[1] or string.format('%d -> %d', vals[1], vals[2])
82+
end
83+
84+
local lines = {
85+
string.rep('=', vim.o.columns - 10),
86+
string.format('row: %s', collapse(self.row)),
87+
string.format('column: %s', collapse(self.col)),
88+
string.format('hide: %s', self.conceal),
89+
}
90+
91+
---@param name string
92+
---@param value any
93+
local function append(name, value)
94+
if type(value) == 'table' then
95+
value = virt_line(value)
96+
end
97+
if value ~= nil then
98+
if type(value) == 'table' then
99+
value = table.concat(value, ' + ')
100+
end
101+
if type(value) == 'string' and #value == 0 then
102+
value = vim.inspect(value)
103+
end
104+
table.insert(lines, string.format(' %s: %s', name, value))
105+
end
106+
end
107+
108+
append('conceal', self.opts.conceal)
109+
append('sign', { { self.opts.sign_text, self.opts.sign_hl_group } })
110+
append('virt_text', self.opts.virt_text)
111+
append('virt_text_pos', self.opts.virt_text_pos)
112+
append('virt_text_win_col', self.opts.virt_text_win_col)
113+
append('virt_text_repeat_linebreak', self.opts.virt_text_repeat_linebreak)
114+
append('virt_line', (self.opts.virt_lines or {})[1])
115+
append('virt_line_above', self.opts.virt_lines_above)
116+
append('hl_group', { { nil, self.opts.hl_group } })
117+
append('hl_eol', self.opts.hl_eol)
118+
append('hl_mode', self.opts.hl_mode)
119+
return table.concat(lines, '\n')
120+
end
121+
122+
---@param a render.md.DebugMark
123+
---@param b render.md.DebugMark
124+
---@return boolean
125+
function DebugMark.__lt(a, b)
126+
local as, bs = a:priorities(), b:priorities()
127+
for i = 1, math.max(#as, #bs) do
128+
if as[i] ~= bs[i] then
129+
return as[i] < bs[i]
130+
end
131+
end
132+
return false
133+
end
134+
135+
---@class render.md.DebugMarks
136+
local M = {}
137+
138+
---@param row integer
139+
---@param marks render.md.Mark[]
140+
function M.debug(row, marks)
141+
print('Decorations on row: ' .. row)
142+
if #marks == 0 then
143+
print('No decorations found')
144+
end
145+
local debug_marks = vim.tbl_map(DebugMark.new, marks)
146+
table.sort(debug_marks)
147+
for _, mark in ipairs(debug_marks) do
148+
print(mark)
149+
end
150+
end
151+
152+
return M

lua/render-markdown/core/extmark.lua

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
---@class render.md.Extmark
22
---@field private namespace integer
33
---@field private buf integer
4-
---@field private mark render.md.Mark
54
---@field private id? integer
5+
---@field mark render.md.Mark
66
local Extmark = {}
77
Extmark.__index = Extmark
88

@@ -14,11 +14,22 @@ function Extmark.new(namespace, buf, mark)
1414
local self = setmetatable({}, Extmark)
1515
self.namespace = namespace
1616
self.buf = buf
17-
self.mark = mark
1817
self.id = nil
18+
self.mark = mark
1919
return self
2020
end
2121

22+
---@param row integer
23+
---@return boolean
24+
function Extmark:overlaps(row)
25+
local start_row = self.mark.start_row
26+
local end_row = self.mark.opts.end_row or start_row
27+
if start_row == end_row then
28+
end_row = end_row + 1
29+
end
30+
return not (start_row > row or end_row <= row)
31+
end
32+
2233
---@param config render.md.buffer.Config
2334
---@param row? integer
2435
function Extmark:render(config, row)

lua/render-markdown/core/ui.lua

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ function M.invalidate_cache()
2727
cache = {}
2828
end
2929

30+
---@param buf integer
31+
---@return integer, render.md.Mark[]
32+
function M.get_row_marks(buf)
33+
local buffer_state, row = cache[buf], util.cursor_row(buf)
34+
if buffer_state == nil or row == nil then
35+
return 0, {}
36+
end
37+
local marks = {}
38+
for _, extmark in ipairs(buffer_state.marks or {}) do
39+
if extmark:overlaps(row) then
40+
table.insert(marks, extmark.mark)
41+
end
42+
end
43+
return row, marks
44+
end
45+
3046
---@private
3147
---@param buf integer
3248
---@param buffer_state render.md.BufferState

lua/render-markdown/core/util.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ function M.valid(buf, win)
1111
end
1212

1313
---@param buf integer
14-
---@param win integer
14+
---@param win? integer
1515
---@return integer?
1616
function M.cursor_row(buf, win)
1717
if vim.api.nvim_get_current_buf() ~= buf then
1818
return nil
1919
end
20+
win = win or vim.api.nvim_get_current_win()
2021
return vim.api.nvim_win_get_cursor(win)[1] - 1
2122
end
2223

lua/render-markdown/health.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ local state = require('render-markdown.state')
44
local M = {}
55

66
---@private
7-
M.version = '7.0.3'
7+
M.version = '7.0.4'
88

99
function M.check()
1010
M.start('version')

0 commit comments

Comments
 (0)