Skip to content

Commit 006806e

Browse files
fix: support indentation for latex blocks
## Details Issue: #421 This was a known issue since computing the indentation level requires us to be in the `markdown` language tree, which `latex` is separated from by 2 levels, `markdown` -> `markdown-inline` -> `latex`. Going between language trees is not possible directly from the node. To get around this we get the closest markdown node to the latex node's position via: ```lua vim.treesitter.get_node({ bufnr = buf, pos = { node.start_row, node.start_col }, lang = 'markdown', }) ``` Then using this node we can compute the indent using the `Indent` module. This became a lot easier after separating this logic from the `Base` render parent class, so we don't need to do any weird extension for `latex` rendering. Also modified the latex handler to create a class instance similar to the other builtin handlers. Renamed all handler implementations to use `run` for the main method name instead of `parse`.
1 parent ff577b4 commit 006806e

File tree

7 files changed

+99
-44
lines changed

7 files changed

+99
-44
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- use selene to prevent accidental print statements [7f81e9d](https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/7f81e9dcc15504c044f20df39d28a590cd5c6ca5)
2121
- configurable indent for first line of paragraph [#417](https://github.com/MeanderingProgrammer/render-markdown.nvim/issues/417)
2222
[57c7f33](https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/57c7f33f276876c994898683680da9e3a3590d0d)
23+
- use physical lines for table border if possible [ff577b4](https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/ff577b44bd3ab642acec0f134a7bf26b7278d137)
2324

2425
### Bug Fixes
2526

@@ -29,6 +30,7 @@
2930
[080104e](https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/080104e4dce26819efb4f4c83d1b7b2d82b96f7c)
3031
- handle spaces before atx headings [bd56575](https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/bd5657594bf1a96b04f900c87e8d74226a54d832)
3132
- remove accidental vim.print [bff12b4](https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/bff12b4655d1537cf0f10859fcd63ef2cec65010)
33+
- ignore callouts outside of quotes and checkboxes outside of lists [b4016e8](https://github.com/MeanderingProgrammer/render-markdown.nvim/commit/b4016e812c9a18784d8c1c6b4f0b2858a4cf502d)
3234

3335
### Collaborator Shoutouts
3436

doc/render-markdown.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*render-markdown.txt* For NVIM v0.11.1 Last change: 2025 May 06
1+
*render-markdown.txt* For NVIM v0.11.1 Last change: 2025 May 08
22

33
==============================================================================
44
Table of Contents *render-markdown-table-of-contents*

lua/render-markdown/handler/html.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ end
3030

3131
---@param root TSNode
3232
---@return render.md.Mark[]
33-
function Handler:parse(root)
33+
function Handler:run(root)
3434
if self.context:skip(self.context.config.html) then
3535
return {}
3636
end
@@ -49,7 +49,7 @@ local M = {}
4949
---@param ctx render.md.handler.Context
5050
---@return render.md.Mark[]
5151
function M.parse(ctx)
52-
return Handler.new(ctx.buf):parse(ctx.root)
52+
return Handler.new(ctx.buf):run(ctx.root)
5353
end
5454

5555
return M

lua/render-markdown/handler/latex.lua

+89-36
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,120 @@
11
local Context = require('render-markdown.request.context')
2+
local Indent = require('render-markdown.lib.indent')
23
local Iter = require('render-markdown.lib.iter')
34
local Marks = require('render-markdown.lib.marks')
45
local Node = require('render-markdown.lib.node')
56
local Str = require('render-markdown.lib.str')
67
local log = require('render-markdown.core.log')
78

8-
---@class render.md.handler.Latex: render.md.Handler
9-
local M = {}
9+
---@class render.md.handler.buf.Latex
10+
---@field private context render.md.request.Context
11+
---@field private config render.md.latex.Config
12+
local Handler = {}
13+
Handler.__index = Handler
1014

1115
---@private
1216
---@type table<string, string>
13-
M.cache = {}
17+
Handler.cache = {}
1418

15-
---@param ctx render.md.handler.Context
19+
---@param buf integer
20+
---@return render.md.handler.buf.Latex
21+
function Handler.new(buf)
22+
local self = setmetatable({}, Handler)
23+
self.context = Context.get(buf)
24+
self.config = self.context.config.latex
25+
return self
26+
end
27+
28+
---@param root TSNode
1629
---@return render.md.Mark[]
17-
function M.parse(ctx)
18-
local context = Context.get(ctx.buf)
19-
local config = context.config.latex
20-
if context:skip(config) then
30+
function Handler:run(root)
31+
if self.context:skip(self.config) then
2132
return {}
2233
end
23-
if vim.fn.executable(config.converter) ~= 1 then
24-
log.add('debug', 'executable not found', config.converter)
34+
if vim.fn.executable(self.config.converter) ~= 1 then
35+
log.add('debug', 'executable not found', self.config.converter)
2536
return {}
2637
end
2738

28-
local node = Node.new(ctx.buf, ctx.root)
39+
local node = Node.new(self.context.buf, root)
2940
log.node('latex', node)
3041

31-
local raw_expression = M.cache[node.text]
32-
if not raw_expression then
33-
raw_expression = vim.fn.system(config.converter, node.text)
34-
if vim.v.shell_error == 1 then
35-
log.add('error', config.converter, raw_expression)
36-
raw_expression = 'error'
37-
end
38-
M.cache[node.text] = raw_expression
39-
end
40-
41-
local expressions = {} ---@type string[]
42-
for _ = 1, config.top_pad do
43-
expressions[#expressions + 1] = ''
44-
end
45-
for _, expression in ipairs(Str.split(raw_expression, '\n', true)) do
46-
expressions[#expressions + 1] = Str.pad(node.start_col) .. expression
47-
end
48-
for _ = 1, config.bottom_pad do
49-
expressions[#expressions + 1] = ''
50-
end
51-
52-
local lines = Iter.list.map(expressions, function(expression)
53-
return { { expression, config.highlight } }
42+
local indent = self:indent(node.start_row, node.start_col)
43+
local lines = Iter.list.map(self:expressions(node), function(expression)
44+
local line = vim.list_extend({}, indent)
45+
line[#line + 1] = { expression, self.config.highlight }
46+
return line
5447
end)
5548

56-
local above = config.position == 'above'
49+
local above = self.config.position == 'above'
5750
local row = above and node.start_row or node.end_row
5851

59-
local marks = Marks.new(context, true)
52+
local marks = Marks.new(self.context, true)
6053
marks:add(false, row, 0, {
6154
virt_lines = lines,
6255
virt_lines_above = above,
6356
})
6457
return marks:get()
6558
end
6659

60+
---@private
61+
---@param node render.md.Node
62+
---@return string[]
63+
function Handler:expressions(node)
64+
local result = {} ---@type string[]
65+
for _ = 1, self.config.top_pad do
66+
result[#result + 1] = ''
67+
end
68+
for _, line in ipairs(self:convert(node.text)) do
69+
result[#result + 1] = Str.pad(node.start_col) .. line
70+
end
71+
for _ = 1, self.config.bottom_pad do
72+
result[#result + 1] = ''
73+
end
74+
return result
75+
end
76+
77+
---@private
78+
---@param text string
79+
---@return string[]
80+
function Handler:convert(text)
81+
local result = Handler.cache[text]
82+
if not result then
83+
local converter = self.config.converter
84+
result = vim.fn.system(converter, text)
85+
if vim.v.shell_error == 1 then
86+
log.add('error', converter, result)
87+
result = 'error'
88+
end
89+
Handler.cache[text] = result
90+
end
91+
return Str.split(result, '\n', true)
92+
end
93+
94+
---@private
95+
---@param row integer
96+
---@param col integer
97+
---@return render.md.mark.Line
98+
function Handler:indent(row, col)
99+
local buf = self.context.buf
100+
local node = vim.treesitter.get_node({
101+
bufnr = buf,
102+
pos = { row, col },
103+
lang = 'markdown',
104+
})
105+
if not node then
106+
return {}
107+
end
108+
return Indent.new(self.context, Node.new(buf, node)):line(true):get()
109+
end
110+
111+
---@class render.md.handler.Latex: render.md.Handler
112+
local M = {}
113+
114+
---@param ctx render.md.handler.Context
115+
---@return render.md.Mark[]
116+
function M.parse(ctx)
117+
return Handler.new(ctx.buf):run(ctx.root)
118+
end
119+
67120
return M

lua/render-markdown/handler/markdown.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ end
5959

6060
---@param root TSNode
6161
---@return render.md.Mark[]
62-
function Handler:parse(root)
62+
function Handler:run(root)
6363
local marks = Marks.new(self.context, false)
6464
self.context.view:nodes(root, self.query, function(capture, node)
6565
local render = self.renders[capture]
@@ -75,7 +75,7 @@ local M = {}
7575
---@param ctx render.md.handler.Context
7676
---@return render.md.Mark[]
7777
function M.parse(ctx)
78-
return Handler.new(ctx.buf):parse(ctx.root)
78+
return Handler.new(ctx.buf):run(ctx.root)
7979
end
8080

8181
return M

lua/render-markdown/handler/markdown_inline.lua

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ end
4444

4545
---@param root TSNode
4646
---@return render.md.Mark[]
47-
function Handler:parse(root)
47+
function Handler:run(root)
4848
local marks = Marks.new(self.context, true)
4949
self.context.view:nodes(root, self.query, function(capture, node)
5050
local render = self.renders[capture]
@@ -60,7 +60,7 @@ local M = {}
6060
---@param ctx render.md.handler.Context
6161
---@return render.md.Mark[]
6262
function M.parse(ctx)
63-
return Handler.new(ctx.buf):parse(ctx.root)
63+
return Handler.new(ctx.buf):run(ctx.root)
6464
end
6565

6666
return M

lua/render-markdown/health.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ local state = require('render-markdown.state')
55
local M = {}
66

77
---@private
8-
M.version = '8.3.29'
8+
M.version = '8.3.30'
99

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

0 commit comments

Comments
 (0)