Skip to content

Commit 5192575

Browse files
committed
ref!(math-renderer): modularize image generation to make way for typst
1 parent c5844ca commit 5192575

File tree

3 files changed

+256
-175
lines changed

3 files changed

+256
-175
lines changed

lua/neorg/modules/core/highlights/module.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,10 @@ module.config.public = {
368368
escape = "+@type",
369369
},
370370

371-
-- Rendered Latex, this will dictate the foreground color of latex images rendered via
372-
-- core.latex.renderer
371+
-- Rendered Latex, this will dictate the foreground color of math images rendered via
372+
-- core.math.renderer
373373
rendered = {
374-
latex = "+Normal",
374+
math = "+Normal",
375375
},
376376
},
377377

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
--[[
2+
file: Core-Math-Renderer-LaTeX
3+
title: Convert LaTeX snippets into image files
4+
summary: A module that provides images of LaTeX for `core.math.renderer`
5+
---
6+
7+
The module is used by `core.math.renderer` to render math blocks as LaTeX.
8+
9+
Requires:
10+
- `latex` executable in path with the following packages:
11+
- standalone
12+
- amsmath
13+
- amssymb
14+
- graphicx
15+
- `dvipng` executable in path (normally comes with LaTeX)
16+
17+
A highlight group that controls the foreground color of the rendered math: `@norg.rendered.latex`,
18+
configurable in `core.highlights`. It links to `Normal` by default
19+
20+
Note, when `'concealcursor'` contains `"n"` This plugin will fail for the time being.
21+
--]]
22+
local nio
23+
local neorg = require("neorg.core")
24+
local module = neorg.modules.create("core.math.renderer.latex")
25+
26+
assert(vim.re ~= nil, "Neovim 0.10.0+ is required for the `core.math.renderer.latex` module!")
27+
28+
module.load = function()
29+
nio = require("nio")
30+
end
31+
32+
module.config.public = {
33+
-- "Dots Per Inch" increasing this value will result in crisper images at the expense of
34+
-- performance
35+
dpi = 350,
36+
}
37+
38+
module.private = {}
39+
40+
---@type MathImageGenerator
41+
module.public = {
42+
---Returns a filepath where the rendered image sits
43+
---@async
44+
---@param snippet string the full latex snippet to convert to an image
45+
---@param foreground_color { r: number, g: number, b: number }
46+
---@return string | nil
47+
async_generate_image = function(snippet, foreground_color)
48+
local document_name = module.private.async_create_latex_document(snippet)
49+
50+
if not document_name then
51+
return
52+
end
53+
54+
local cwd = nio.fn.fnamemodify(document_name, ":h")
55+
local create_dvi = nio.process.run({
56+
cmd = "latex",
57+
args = {
58+
"--interaction=nonstopmode",
59+
"--output-format=dvi",
60+
document_name,
61+
},
62+
cwd = cwd,
63+
})
64+
if not create_dvi or type(create_dvi) == "string" then
65+
return
66+
end
67+
local res = create_dvi.result()
68+
if res ~= 0 then
69+
return
70+
end
71+
72+
local png_result = nio.fn.tempname()
73+
png_result = ("%s.png"):format(png_result)
74+
75+
local fg = module.private.format_color(foreground_color)
76+
local dvipng = nio.process.run({
77+
cmd = "dvipng",
78+
args = {
79+
"-D",
80+
module.config.public.dpi,
81+
"-T",
82+
"tight",
83+
"-bg",
84+
"Transparent",
85+
"-fg",
86+
fg,
87+
"-o",
88+
png_result,
89+
document_name .. ".dvi",
90+
},
91+
})
92+
93+
if not dvipng or type(dvipng) == "string" then
94+
return
95+
end
96+
res = dvipng.result()
97+
if res ~= 0 then
98+
return
99+
end
100+
101+
return png_result
102+
end,
103+
}
104+
105+
---Writes a latex snippet to a file and wraps it with latex headers so it will render nicely
106+
---@async
107+
---@param snippet string latex snippet (if it's math it should include the surrounding $$)
108+
---@return string temp file path
109+
module.private.async_create_latex_document = function(snippet)
110+
local tempname = nio.fn.tempname()
111+
local tempfile = nio.file.open(tempname, "w")
112+
113+
local content = table.concat({
114+
"\\documentclass[6pt]{standalone}",
115+
"\\usepackage{amsmath}",
116+
"\\usepackage{amssymb}",
117+
"\\usepackage{graphicx}",
118+
"\\begin{document}",
119+
snippet,
120+
"\\end{document}",
121+
}, "\n")
122+
123+
tempfile.write(content)
124+
tempfile.close()
125+
126+
return tempname
127+
end
128+
129+
---Format the foreground color information into something that can be passed to the dvipng command
130+
---@param foreground_color {r: number, g: number, b: number}
131+
module.private.format_color = function(foreground_color)
132+
return ("rgb %s %s %s"):format(foreground_color.r, foreground_color.g, foreground_color.b)
133+
end
134+
135+
return module

0 commit comments

Comments
 (0)