Skip to content

Commit 25bfaf0

Browse files
chore: refactor various node computations into the context that stores needed information
1 parent 420058b commit 25bfaf0

File tree

7 files changed

+76
-87
lines changed

7 files changed

+76
-87
lines changed

lua/render-markdown/context.lua

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local str = require('render-markdown.str')
12
local util = require('render-markdown.util')
23

34
---@class render.md.Context
@@ -38,10 +39,16 @@ function Context:add_link(info, icon)
3839
table.insert(self.links[row], { info.start_col, info.end_col, icon })
3940
end
4041

41-
---@param row integer
42-
---@return [integer, integer, string][]
43-
function Context:get_links(row)
44-
return self.links[row] or {}
42+
---@param info render.md.NodeInfo
43+
---@return integer
44+
function Context:link_width(info)
45+
local result = 0
46+
for _, icon_range in ipairs(self.links[info.start_row] or {}) do
47+
if info.start_col < icon_range[2] and info.end_col > icon_range[1] then
48+
result = result + str.width(icon_range[3])
49+
end
50+
end
51+
return result
4552
end
4653

4754
---@return integer
@@ -64,7 +71,7 @@ end
6471
---@return boolean
6572
function Context:contains_node(node)
6673
local top, _, bottom, _ = node:range()
67-
return top <= self.bottom and bottom >= self.top
74+
return top < self.bottom and bottom >= self.top
6875
end
6976

7077
---@param root TSNode
@@ -77,6 +84,38 @@ function Context:query(root, query, callback)
7784
end
7885
end
7986

87+
---@param info? render.md.NodeInfo
88+
---@return boolean
89+
function Context:hidden(info)
90+
if info == nil then
91+
return true
92+
end
93+
return str.width(info.text) == self:concealed(info)
94+
end
95+
96+
---@param info render.md.NodeInfo
97+
---@return integer
98+
function Context:concealed(info)
99+
local ranges = self:get_conceal(info.start_row)
100+
if #ranges == 0 then
101+
return 0
102+
end
103+
local result = 0
104+
local col = info.start_col
105+
for _, index in ipairs(vim.fn.str2list(info.text)) do
106+
local ch = vim.fn.nr2char(index)
107+
for _, range in ipairs(ranges) do
108+
-- Essentially vim.treesitter.is_in_node_range but only care about column
109+
if col >= range[1] and col + 1 <= range[2] then
110+
result = result + str.width(ch)
111+
end
112+
end
113+
col = col + #ch
114+
end
115+
return result
116+
end
117+
118+
---@private
80119
---@param row integer
81120
---@return [integer, integer][]
82121
function Context:get_conceal(row)

lua/render-markdown/handler/markdown.lua

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
local Context = require('render-markdown.context')
12
local NodeInfo = require('render-markdown.node_info')
23
local code_block_parser = require('render-markdown.parser.code_block')
34
local colors = require('render-markdown.colors')
45
local component = require('render-markdown.component')
5-
local context = require('render-markdown.context')
66
local icons = require('render-markdown.icons')
77
local list = require('render-markdown.list')
88
local logger = require('render-markdown.logger')
@@ -13,6 +13,7 @@ local str = require('render-markdown.str')
1313
---@class render.md.handler.buf.Markdown
1414
---@field private buf integer
1515
---@field private config render.md.BufferConfig
16+
---@field private context render.md.Context
1617
---@field private last_heading_border integer
1718
---@field private marks render.md.Mark[]
1819
local Handler = {}
@@ -24,6 +25,7 @@ function Handler.new(buf)
2425
local self = setmetatable({}, Handler)
2526
self.buf = buf
2627
self.config = state.get_config(buf)
28+
self.context = Context.get(buf)
2729
self.last_heading_border = -1
2830
self.marks = {}
2931
return self
@@ -32,7 +34,7 @@ end
3234
---@param root TSNode
3335
---@return render.md.Mark[]
3436
function Handler:parse(root)
35-
context.get(self.buf):query(root, state.markdown_query, function(capture, node)
37+
self.context:query(root, state.markdown_query, function(capture, node)
3638
local info = NodeInfo.new(self.buf, node)
3739
logger.debug_node_info(capture, info)
3840
if capture == 'heading' then
@@ -48,7 +50,7 @@ function Handler:parse(root)
4850
elseif capture == 'checkbox_checked' then
4951
self:checkbox(info, self.config.checkbox.checked)
5052
elseif capture == 'quote' then
51-
context.get(self.buf):query(node, state.markdown_quote_query, function(nested_capture, nested_node)
53+
self.context:query(node, state.markdown_quote_query, function(nested_capture, nested_node)
5254
local nested_info = NodeInfo.new(self.buf, nested_node)
5355
logger.debug_node_info(nested_capture, nested_info)
5456
if nested_capture == 'quote_marker' then
@@ -135,7 +137,7 @@ function Handler:heading_icon(info, level, foreground, background)
135137
-- Available width is level + 1 - concealed, where level = number of `#` characters, one
136138
-- is added to account for the space after the last `#` but before the heading title,
137139
-- and concealed text is subtracted since that space is not usable
138-
local width = level + 1 - info:concealed()
140+
local width = level + 1 - self.context:concealed(info)
139141
if icon == nil then
140142
return width
141143
end
@@ -171,11 +173,11 @@ function Handler:heading_width(info, icon_width)
171173
local width = heading.left_pad + icon_width + heading.right_pad
172174
local content = info:sibling('inline')
173175
if content ~= nil then
174-
width = width + str.width(content.text) + self:added_width(content) - content:concealed()
176+
width = width + str.width(content.text) + self.context:link_width(content) - self.context:concealed(content)
175177
end
176178
return math.max(width, heading.min_width)
177179
else
178-
return context.get(self.buf):get_width()
180+
return self.context:get_width()
179181
end
180182
end
181183

@@ -234,7 +236,7 @@ function Handler:dash(info)
234236

235237
local width
236238
if dash.width == 'full' then
237-
width = context.get(self.buf):get_width()
239+
width = self.context:get_width()
238240
else
239241
---@type integer
240242
width = dash.width
@@ -253,7 +255,7 @@ function Handler:code(info)
253255
if not code.enabled or code.style == 'none' then
254256
return
255257
end
256-
local code_block = code_block_parser.parse(code, self.buf, info)
258+
local code_block = code_block_parser.parse(code, self.context, info)
257259
if code_block == nil then
258260
return
259261
end
@@ -294,7 +296,7 @@ function Handler:language(code_block, add_background)
294296
end
295297
if code.position == 'left' then
296298
local icon_text = icon .. ' '
297-
if info:hidden() then
299+
if self.context:hidden(info) then
298300
-- Code blocks will pick up varying amounts of leading white space depending on the
299301
-- context they are in. This gets lumped into the delimiter node and as a result,
300302
-- after concealing, the extmark will be left shifted. Logic below accounts for this.
@@ -657,21 +659,7 @@ end
657659
---@param info render.md.NodeInfo
658660
---@return integer
659661
function Handler:table_visual_offset(info)
660-
return info:concealed() - self:added_width(info)
661-
end
662-
663-
---@private
664-
---@param info render.md.NodeInfo
665-
---@return integer
666-
function Handler:added_width(info)
667-
local result = 0
668-
local icon_ranges = context.get(self.buf):get_links(info.start_row)
669-
for _, icon_range in ipairs(icon_ranges) do
670-
if info.start_col < icon_range[2] and info.end_col > icon_range[1] then
671-
result = result + str.width(icon_range[3])
672-
end
673-
end
674-
return result
662+
return self.context:concealed(info) - self.context:link_width(info)
675663
end
676664

677665
---@class render.md.handler.Markdown: render.md.Handler

lua/render-markdown/handler/markdown_inline.lua

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
local Context = require('render-markdown.context')
12
local NodeInfo = require('render-markdown.node_info')
23
local component = require('render-markdown.component')
3-
local context = require('render-markdown.context')
44
local list = require('render-markdown.list')
55
local logger = require('render-markdown.logger')
66
local state = require('render-markdown.state')
@@ -9,6 +9,7 @@ local str = require('render-markdown.str')
99
---@class render.md.handler.buf.MarkdownInline
1010
---@field private buf integer
1111
---@field private config render.md.BufferConfig
12+
---@field private context render.md.Context
1213
---@field private marks render.md.Mark[]
1314
local Handler = {}
1415
Handler.__index = Handler
@@ -19,14 +20,15 @@ function Handler.new(buf)
1920
local self = setmetatable({}, Handler)
2021
self.buf = buf
2122
self.config = state.get_config(buf)
23+
self.context = Context.get(buf)
2224
self.marks = {}
2325
return self
2426
end
2527

2628
---@param root TSNode
2729
---@return render.md.Mark[]
2830
function Handler:parse(root)
29-
context.get(self.buf):query(root, state.inline_query, function(capture, node)
31+
self.context:query(root, state.inline_query, function(capture, node)
3032
local info = NodeInfo.new(self.buf, node)
3133
logger.debug_node_info(capture, info)
3234
if capture == 'code' then
@@ -167,7 +169,7 @@ function Handler:link(info)
167169
virt_text_pos = 'inline',
168170
})
169171
if added then
170-
context.get(self.buf):add_link(info, icon)
172+
self.context:add_link(info, icon)
171173
end
172174
end
173175

lua/render-markdown/health.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ local M = {}
55

66
---@private
77
---@type string
8-
M.version = '6.0.9'
8+
M.version = '6.0.10'
99

1010
function M.check()
1111
vim.health.start('render-markdown.nvim [version]')

lua/render-markdown/node_info.lua

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
local context = require('render-markdown.context')
2-
local str = require('render-markdown.str')
3-
41
---@param node TSNode
52
---@return boolean
63
local function in_section(node)
@@ -129,30 +126,4 @@ function NodeInfo:lines()
129126
return vim.api.nvim_buf_get_lines(self.buf, self.start_row, self.end_row, false)
130127
end
131128

132-
---@return boolean
133-
function NodeInfo:hidden()
134-
return str.width(self.text) == self:concealed()
135-
end
136-
137-
---@return integer
138-
function NodeInfo:concealed()
139-
local ranges = context.get(self.buf):get_conceal(self.start_row)
140-
if #ranges == 0 then
141-
return 0
142-
end
143-
local result = 0
144-
local col = self.start_col
145-
for _, index in ipairs(vim.fn.str2list(self.text)) do
146-
local ch = vim.fn.nr2char(index)
147-
for _, range in ipairs(ranges) do
148-
-- Essentially vim.treesitter.is_in_node_range but only care about column
149-
if col >= range[1] and col + 1 <= range[2] then
150-
result = result + str.width(ch)
151-
end
152-
end
153-
col = col + #ch
154-
end
155-
return result
156-
end
157-
158129
return NodeInfo
Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
local context = require('render-markdown.context')
21
local str = require('render-markdown.str')
32

43
---@class render.md.parser.CodeBlock
@@ -18,10 +17,10 @@ local M = {}
1817
---@field end_delim_hidden boolean
1918

2019
---@param config render.md.Code
21-
---@param buf integer
20+
---@param context render.md.Context
2221
---@param info render.md.NodeInfo
2322
---@return render.md.parsed.CodeBlock?
24-
function M.parse(config, buf, info)
23+
function M.parse(config, context, info)
2524
-- Do not attempt to render single line code block
2625
if info.end_row - info.start_row <= 1 then
2726
return nil
@@ -31,7 +30,7 @@ function M.parse(config, buf, info)
3130
if code_info ~= nil then
3231
language_info = code_info:child('language', info.start_row)
3332
end
34-
local longest_line, width = M.get_width(config, buf, info)
33+
local longest_line, width = M.get_width(config, context, info)
3534
---@type render.md.parsed.CodeBlock
3635
return {
3736
col = info.start_col,
@@ -40,39 +39,29 @@ function M.parse(config, buf, info)
4039
leading_spaces = str.leading_spaces(info.text),
4140
longest_line = longest_line,
4241
width = width,
43-
code_info_hidden = M.hidden(code_info),
42+
code_info_hidden = context:hidden(code_info),
4443
language_info = language_info,
4544
language = (language_info or {}).text,
46-
start_delim_hidden = M.hidden(info:child('fenced_code_block_delimiter', info.start_row)),
47-
end_delim_hidden = M.hidden(info:child('fenced_code_block_delimiter', info.end_row - 1)),
45+
start_delim_hidden = context:hidden(info:child('fenced_code_block_delimiter', info.start_row)),
46+
end_delim_hidden = context:hidden(info:child('fenced_code_block_delimiter', info.end_row - 1)),
4847
}
4948
end
5049

5150
---@private
5251
---@param config render.md.Code
53-
---@param buf integer
52+
---@param context render.md.Context
5453
---@param info render.md.NodeInfo
5554
---@return integer, integer
56-
function M.get_width(config, buf, info)
55+
function M.get_width(config, context, info)
5756
local lines = info:lines()
5857
local code_width = vim.fn.max(vim.tbl_map(str.width, lines))
5958
local longest_line = config.left_pad + code_width + config.right_pad
6059
local width = math.max(longest_line, config.min_width)
6160
if config.width == 'block' then
6261
return width, width
6362
else
64-
return width, context.get(buf):get_width()
63+
return width, context:get_width()
6564
end
6665
end
6766

68-
---@private
69-
---@param info? render.md.NodeInfo
70-
---@return boolean
71-
function M.hidden(info)
72-
if info == nil then
73-
return true
74-
end
75-
return info:hidden()
76-
end
77-
7867
return M

lua/render-markdown/ui.lua

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
local BufferState = require('render-markdown.buffer_state')
2+
local Context = require('render-markdown.context')
23
local Extmark = require('render-markdown.extmark')
3-
local context = require('render-markdown.context')
44
local logger = require('render-markdown.logger')
55
local state = require('render-markdown.state')
66
local util = require('render-markdown.util')
@@ -48,7 +48,7 @@ function M.debounce_update(buf, win, change)
4848
local buffer_state = cache[buf] or BufferState.new(buf)
4949
cache[buf] = buffer_state
5050

51-
if not change and context.contains_range(buf, win) then
51+
if not change and Context.contains_range(buf, win) then
5252
vim.schedule(function()
5353
M.update(buf, win, false)
5454
end)
@@ -122,9 +122,9 @@ function M.parse_buffer(buf, win)
122122
return {}
123123
end
124124
-- Reset buffer context
125-
context.reset(buf, win)
125+
Context.reset(buf, win)
126126
-- Make sure injections are processed
127-
parser:parse(context.get(buf):range())
127+
parser:parse(Context.get(buf):range())
128128
-- Parse marks
129129
local marks = {}
130130
-- Parse markdown after all other nodes to take advantage of state
@@ -154,7 +154,7 @@ end
154154
---@return render.md.Mark[]
155155
function M.parse_tree(buf, language, root)
156156
logger.debug('language', language)
157-
if not context.get(buf):contains_node(root) then
157+
if not Context.get(buf):contains_node(root) then
158158
return {}
159159
end
160160

0 commit comments

Comments
 (0)