mirror of
https://github.com/folke/snacks.nvim
synced 2025-07-07 13:15:08 +00:00
feat(image): refactor of treesitter queries to support inline image data
This commit is contained in:
parent
48a3fed3c5
commit
0bf0c6223d
22 changed files with 393 additions and 68 deletions
161
lua/snacks/image/convert.lua
Normal file
161
lua/snacks/image/convert.lua
Normal file
|
@ -0,0 +1,161 @@
|
|||
---@class snacks.image.convert
|
||||
local M = {}
|
||||
-- vim.list_extend(args, {
|
||||
-- -- "-density",
|
||||
-- -- "4000",
|
||||
-- -- "-background",
|
||||
-- -- "transparent",
|
||||
-- -- "-flatten",
|
||||
-- -- "+repage",
|
||||
-- -- -- "-adaptive-resize",
|
||||
-- -- -- "800",
|
||||
-- -- "-quality",
|
||||
-- -- "100",
|
||||
-- -- "-trim",
|
||||
-- })
|
||||
|
||||
---@alias snacks.image.generate.on_done fun(code: number)
|
||||
|
||||
---@class snacks.image.generate
|
||||
---@field cwd? string
|
||||
---@field cmd string
|
||||
---@field args string[]
|
||||
---@field on_done? snacks.image.generate.on_done
|
||||
|
||||
local uv = vim.uv or vim.loop
|
||||
|
||||
local have_magick ---@type boolean
|
||||
|
||||
---@param src string
|
||||
function M.is_url(src)
|
||||
return src:find("^https?://") == 1
|
||||
end
|
||||
|
||||
---@param src string
|
||||
function M.is_uri(src)
|
||||
return src:find("^%w%w+://") == 1
|
||||
end
|
||||
|
||||
---@param src string
|
||||
function M.norm(src)
|
||||
if src:find("^file://") then
|
||||
return vim.fs.normalize(vim.uri_to_fname(src))
|
||||
end
|
||||
return src
|
||||
end
|
||||
|
||||
---@param src string
|
||||
---@param ext string
|
||||
function M.tmpfile(src, ext)
|
||||
local root = Snacks.image.config.cache
|
||||
local base = vim.fn.fnamemodify(src, ":t:r")
|
||||
if M.is_uri(src) then
|
||||
base = src:gsub("%?.*", ""):match("^%w%w+://(.*)$") or base
|
||||
end
|
||||
base = base:gsub("[^%w%.]+", "-")
|
||||
vim.fn.mkdir(root, "p")
|
||||
return root .. "/" .. vim.fn.sha256(src):sub(1, 8) .. "-" .. base .. "." .. ext
|
||||
end
|
||||
|
||||
---@param file string
|
||||
---@param opts snacks.image.generate
|
||||
---@return (fun(): boolean) is_ready
|
||||
function M.generate(file, opts)
|
||||
local on_done = function(code)
|
||||
if opts.on_done then
|
||||
opts.on_done(code)
|
||||
end
|
||||
end
|
||||
if vim.fn.filereadable(file) == 1 then
|
||||
on_done(0)
|
||||
return function()
|
||||
return true
|
||||
end
|
||||
end
|
||||
if Snacks.image.config.debug.convert then
|
||||
Snacks.debug.cmd(opts)
|
||||
end
|
||||
local handle ---@type uv.uv_process_t
|
||||
handle = uv.spawn(opts.cmd, opts, function(code)
|
||||
handle:close()
|
||||
on_done(code)
|
||||
end)
|
||||
return function()
|
||||
return (not handle or handle:is_closing() or false) and vim.fn.filereadable(file) == 1
|
||||
end
|
||||
end
|
||||
|
||||
---@param src string
|
||||
---@param dest string
|
||||
---@param opts? {args?: (string|number)[], on_done?: snacks.image.generate.on_done}
|
||||
---@return (fun(): boolean) is_ready
|
||||
function M.magick(src, dest, opts)
|
||||
opts = opts or {}
|
||||
local args = opts.args or { src .. "[0]" } ---@type string[]
|
||||
args[#args + 1] = dest
|
||||
have_magick = have_magick == nil and vim.fn.executable("magick") == 1 or have_magick
|
||||
return M.generate(dest, {
|
||||
cmd = have_magick and "magick" or "convert",
|
||||
args = args,
|
||||
on_done = opts.on_done,
|
||||
})
|
||||
end
|
||||
|
||||
---@param src string
|
||||
---@param dest string
|
||||
---@param opts? {on_done?: snacks.image.generate.on_done}
|
||||
---@return (fun(): boolean) is_ready
|
||||
function M.tex2pdf(src, dest, opts)
|
||||
return M.generate(dest, {
|
||||
cmd = "pdflatex",
|
||||
args = { "-output-directory=" .. vim.fn.fnamemodify(dest, ":h"), src },
|
||||
on_done = opts and opts.on_done,
|
||||
})
|
||||
end
|
||||
|
||||
---@param src string
|
||||
---@param opts? {on_done?: snacks.image.generate.on_done}
|
||||
---@return string png, (fun(): boolean) is_ready
|
||||
function M.convert(src, opts)
|
||||
local png = M.tmpfile(src, "png")
|
||||
src = M.norm(src)
|
||||
if not M.is_uri(src) then
|
||||
src = vim.fs.normalize(src)
|
||||
png = M.tmpfile(src, "png")
|
||||
local ext = vim.fn.fnamemodify(src, ":e"):lower()
|
||||
if ext == "png" then
|
||||
if opts and opts.on_done then
|
||||
opts.on_done(0)
|
||||
end
|
||||
return src, function()
|
||||
return true
|
||||
end
|
||||
elseif ext == "tex" then
|
||||
local pdf = src:gsub("%.tex$", ".pdf")
|
||||
local is_ready = function()
|
||||
return false
|
||||
end
|
||||
M.tex2pdf(src, pdf, {
|
||||
on_done = function(code)
|
||||
if code == 0 then
|
||||
opts.args = { "-density", 300, pdf, "-trim" }
|
||||
is_ready = M.magick(pdf, png, opts)
|
||||
end
|
||||
end,
|
||||
})
|
||||
return png, function()
|
||||
return is_ready()
|
||||
end
|
||||
end
|
||||
end
|
||||
opts.args = {
|
||||
-- "-density",
|
||||
-- 128,
|
||||
src,
|
||||
"-scale",
|
||||
"200%",
|
||||
}
|
||||
return png, M.magick(src, png, opts)
|
||||
end
|
||||
|
||||
return M
|
|
@ -5,7 +5,8 @@
|
|||
---@field sent? boolean image data is sent
|
||||
---@field placements table<number, snacks.image.Placement> image placements
|
||||
---@field augroup number
|
||||
---@field _convert uv.uv_process_t?
|
||||
---@field _ready fun(): boolean
|
||||
---@field closed? boolean
|
||||
local M = {}
|
||||
M.__index = M
|
||||
|
||||
|
@ -16,7 +17,6 @@ local _pid = 0
|
|||
local nvim_id = 0
|
||||
local uv = vim.uv or vim.loop
|
||||
local images = {} ---@type table<string, snacks.Image>
|
||||
local have_magick ---@type boolean?
|
||||
local terminal = Snacks.image.terminal
|
||||
|
||||
---@param src string
|
||||
|
@ -25,6 +25,7 @@ function M.new(src)
|
|||
self.src = src
|
||||
self.file = self:convert()
|
||||
if images[self.file] then
|
||||
self.closed = true
|
||||
return images[self.file]
|
||||
end
|
||||
images[self.file] = self
|
||||
|
@ -38,18 +39,15 @@ function M.new(src)
|
|||
-- interleave the nvim id and the image id
|
||||
self.id = bit.bor(bit.lshift(nvim_id, 24 - NVIM_ID_BITS), _id)
|
||||
self.placements = {}
|
||||
if self:ready() then
|
||||
vim.schedule(function()
|
||||
self:on_ready()
|
||||
end)
|
||||
end
|
||||
self.augroup = vim.api.nvim_create_augroup("snacks.image." .. self.id, { clear = true })
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function M:on_ready()
|
||||
self:send()
|
||||
if not self.sent and not self.closed then
|
||||
self:send()
|
||||
end
|
||||
end
|
||||
|
||||
function M:on_send()
|
||||
|
@ -59,39 +57,23 @@ function M:on_send()
|
|||
end
|
||||
|
||||
function M:ready()
|
||||
return (not self._convert or self._convert:is_closing()) and self.file and vim.fn.filereadable(self.file) == 1
|
||||
return self._ready() and self.file and vim.fn.filereadable(self.file) == 1
|
||||
end
|
||||
|
||||
function M:convert()
|
||||
local src = self.src
|
||||
if src:find("^file://") then
|
||||
src = vim.uri_to_fname(src)
|
||||
end
|
||||
-- convert urls and non-png files to png
|
||||
if not src:find("^https?://") and src:lower():find("%.png$") then
|
||||
return src
|
||||
end
|
||||
if not src:find("^%w%w+://") then
|
||||
src = vim.fs.normalize(src)
|
||||
end
|
||||
local fin = src .. "[0]"
|
||||
local root = Snacks.image.config.cache
|
||||
vim.fn.mkdir(root, "p")
|
||||
src = root .. "/" .. Snacks.util.file_encode(fin) .. ".png"
|
||||
if vim.fn.filereadable(src) == 1 then
|
||||
return src
|
||||
end
|
||||
local opts = { args = { fin, src } }
|
||||
have_magick = have_magick == nil and vim.fn.executable("magick") == 1 or have_magick
|
||||
self._convert = uv.spawn(have_magick and "magick" or "convert", opts, function(code)
|
||||
self._convert:close()
|
||||
if code == 0 then
|
||||
vim.schedule(function()
|
||||
self:on_ready()
|
||||
end)
|
||||
end
|
||||
end)
|
||||
return src
|
||||
local png, ready = Snacks.image.convert.convert(self.src, {
|
||||
on_done = function(code)
|
||||
if code == 0 then
|
||||
vim.schedule(function()
|
||||
self:on_ready()
|
||||
end)
|
||||
else
|
||||
Snacks.notify.error("Failed to convert image to " .. self.file)
|
||||
end
|
||||
end,
|
||||
})
|
||||
self._ready = ready
|
||||
return png
|
||||
end
|
||||
|
||||
-- create the image
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
---@field util snacks.image.util
|
||||
---@field buf snacks.image.buf
|
||||
---@field doc snacks.image.doc
|
||||
---@field convert snacks.image.convert
|
||||
local M = setmetatable({}, {
|
||||
---@param M snacks.image
|
||||
__index = function(M, k)
|
||||
if vim.tbl_contains({ "terminal", "image", "placement", "util", "doc", "buf" }, k) then
|
||||
if vim.tbl_contains({ "terminal", "image", "placement", "util", "doc", "buf", "convert" }, k) then
|
||||
M[k] = require("snacks.image." .. k)
|
||||
end
|
||||
return rawget(M, k)
|
||||
|
@ -75,7 +76,11 @@ local defaults = {
|
|||
statuscolumn = "",
|
||||
},
|
||||
cache = vim.fn.stdpath("cache") .. "/snacks/image",
|
||||
debug = false,
|
||||
debug = {
|
||||
request = false,
|
||||
convert = false,
|
||||
placement = false,
|
||||
},
|
||||
env = {},
|
||||
}
|
||||
M.config = Snacks.config.get("image", defaults)
|
||||
|
@ -225,6 +230,12 @@ function M.health()
|
|||
end
|
||||
end
|
||||
|
||||
if Snacks.health.have_tool({ "pdflatex" }) then
|
||||
Snacks.health.ok("`pdflatex` is available to render math expressions in `latex` and `markdown` documents")
|
||||
else
|
||||
Snacks.health.warn("`pdflatex` is required to render LaTeX math equations")
|
||||
end
|
||||
|
||||
if env.supported then
|
||||
Snacks.health.ok("your terminal supports the kitty graphics protocol")
|
||||
elseif M.config.force then
|
||||
|
|
|
@ -114,7 +114,7 @@ function M:render_grid(loc)
|
|||
vim.api.nvim_set_hl(0, hl, {
|
||||
fg = self.img.id,
|
||||
sp = self.id,
|
||||
bg = Snacks.image.config.debug and "#FF007C" or nil,
|
||||
bg = Snacks.image.config.debug.placement and "#FF007C" or nil,
|
||||
})
|
||||
local lines = {} ---@type string[]
|
||||
for r = 1, loc.height do
|
||||
|
@ -180,7 +180,7 @@ function M:render_fallback(state)
|
|||
end
|
||||
|
||||
function M:debug(...)
|
||||
if not Snacks.image.config.debug then
|
||||
if true or not Snacks.image.config.debug then
|
||||
return
|
||||
end
|
||||
Snacks.debug.inspect({ ... }, self.img.src, self.img.id, self.id)
|
||||
|
|
|
@ -169,7 +169,7 @@ function M.request(opts)
|
|||
if env.transform then
|
||||
data = env.transform(data)
|
||||
end
|
||||
if Snacks.image.config.debug and opts.m ~= 1 then
|
||||
if Snacks.image.config.debug.request and opts.m ~= 1 then
|
||||
Snacks.debug.inspect(opts)
|
||||
end
|
||||
io.stdout:write(data)
|
||||
|
|
|
@ -30,8 +30,8 @@ end
|
|||
function M.pixels_to_cells(size)
|
||||
local terminal = Snacks.image.terminal.size()
|
||||
return M.norm({
|
||||
width = size.width / terminal.cell_width * terminal.scale,
|
||||
height = size.height / terminal.cell_height * terminal.scale,
|
||||
width = size.width / terminal.cell_width,
|
||||
height = size.height / terminal.cell_height,
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
(declaration
|
||||
(call_expression
|
||||
(function_name) @fn (#eq? @fn "url")
|
||||
(arguments [(plain_value) @image (string_value (string_content) @image)]))
|
||||
) @anchor
|
||||
(arguments [(plain_value) @image.src (string_value (string_content) @image.src)]))
|
||||
) @image
|
||||
|
|
|
@ -4,14 +4,20 @@
|
|||
(tag_name) @tag (#eq? @tag "img")
|
||||
(attribute
|
||||
(attribute_name) @attr_name (#eq? @attr_name "src")
|
||||
(quoted_attribute_value (attribute_value) @image)
|
||||
(quoted_attribute_value (attribute_value) @image.src)
|
||||
)
|
||||
)
|
||||
) @anchor
|
||||
) @image
|
||||
|
||||
(self_closing_tag
|
||||
(tag_name) @tag (#eq? @tag "img")
|
||||
(attribute
|
||||
(attribute_name) @attr_name (#eq? @attr_name "src")
|
||||
(quoted_attribute_value (attribute_value) @image)
|
||||
(quoted_attribute_value (attribute_value) @image.src)
|
||||
)
|
||||
) @anchor
|
||||
) @image
|
||||
|
||||
(element
|
||||
(start_tag (tag_name) @tag (#eq? @tag "svg"))
|
||||
(#set! ext "svg")
|
||||
) @image @image.content
|
||||
|
|
|
@ -4,15 +4,15 @@
|
|||
(identifier) @tag (#any-of? @tag "img" "Image")
|
||||
(jsx_attribute
|
||||
(property_identifier) @attr_name (#eq? @attr_name "src")
|
||||
(string (string_fragment) @image)
|
||||
(string (string_fragment) @image.src)
|
||||
)
|
||||
)
|
||||
) @anchor
|
||||
) @image
|
||||
|
||||
(jsx_self_closing_element
|
||||
(identifier) @tag (#any-of? @tag "img" "Image")
|
||||
(jsx_attribute
|
||||
(property_identifier) @attr_name (#eq? @attr_name "src")
|
||||
(string (string_fragment) @image)
|
||||
(string (string_fragment) @image.src)
|
||||
)
|
||||
) @anchor
|
||||
) @image
|
||||
|
|
9
queries/latex/images.scm
Normal file
9
queries/latex/images.scm
Normal file
|
@ -0,0 +1,9 @@
|
|||
(inline_formula) @image.content @image
|
||||
|
||||
(displayed_equation) @image.content @image
|
||||
(math_environment) @image.content @image
|
||||
|
||||
(graphics_include
|
||||
(_ (path) @image.src)
|
||||
) @image
|
||||
|
|
@ -1 +1,9 @@
|
|||
; extends
|
||||
|
||||
(fenced_code_block
|
||||
(info_string (language) @lang)
|
||||
(#eq? @lang "math")
|
||||
(code_fence_content) @image.content
|
||||
(#set! injection.language "latex")
|
||||
(#set! image.ext "tex")
|
||||
) @image
|
||||
|
|
8
queries/markdown/injections.scm
Normal file
8
queries/markdown/injections.scm
Normal file
|
@ -0,0 +1,8 @@
|
|||
; extends
|
||||
|
||||
(fenced_code_block
|
||||
(info_string (language) @lang)
|
||||
(#eq? @lang "math")
|
||||
(code_fence_content) @injection.content
|
||||
(#set! injection.language "latex")
|
||||
)
|
|
@ -1,9 +1,9 @@
|
|||
|
||||
(image
|
||||
[
|
||||
(link_destination) @image
|
||||
(image_description (shortcut_link (link_text) @image))
|
||||
(#gsub! @image "|.*" "") ; remove wikilink image options
|
||||
(#gsub! @image "^<" "") ; remove bracket link
|
||||
(#gsub! @image "^>" "")
|
||||
]) @anchor
|
||||
(link_destination) @image.src
|
||||
(image_description (shortcut_link (link_text) @image.src))
|
||||
(#gsub! @image.src "|.*" "") ; remove wikilink image options
|
||||
(#gsub! @image.src "^<" "") ; remove bracket link
|
||||
(#gsub! @image.src "^>" "")
|
||||
]) @image
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
(infirm_tag
|
||||
(tag_name) @tag (#eq? @tag "image")
|
||||
(tag_parameters (tag_param) @image)
|
||||
) @anchor
|
||||
(tag_parameters (tag_param) @image.src)
|
||||
) @image
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
(call_expression
|
||||
(function_name) @fn (#eq? @fn "url")
|
||||
(arguments [
|
||||
(plain_value) @image
|
||||
(string_value) @image
|
||||
(plain_value) @image.src
|
||||
(string_value) @image.src
|
||||
; Remove quotes from the image URL
|
||||
(#gsub! @image "^['\"]" "")
|
||||
(#gsub! @image "['\"]$" "")
|
||||
(#gsub! @image.src "^['\"]" "")
|
||||
(#gsub! @image.src "['\"]$" "")
|
||||
]))
|
||||
) @anchor
|
||||
) @image
|
||||
|
|
12
tests/image/math.md
Normal file
12
tests/image/math.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
This sentence uses `$` delimiters to show math inline: $\sqrt{3x-1}+(1+x)^2$
|
||||
|
||||
This sentence uses delimiters to show math inline: $`\sqrt{3x-1}+(1+x)^2`$
|
||||
|
||||
**The Cauchy-Schwarz Inequality**\
|
||||
$$\left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)$$
|
||||
|
||||
**The Cauchy-Schwarz Inequality**
|
||||
|
||||
```math
|
||||
\left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)
|
||||
```
|
BIN
tests/image/math.png
Normal file
BIN
tests/image/math.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
2
tests/image/test.aux
Normal file
2
tests/image/test.aux
Normal file
|
@ -0,0 +1,2 @@
|
|||
\relax
|
||||
\gdef \@abspage@last{1}
|
|
@ -1,4 +1,63 @@
|
|||
<body>
|
||||
<a href="/" class="navbar-brand" aria-label="logo">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
role="img"
|
||||
width="173"
|
||||
height="50"
|
||||
viewBox="0 0 742 214"
|
||||
aria-label="Neovim"
|
||||
>
|
||||
<title>Neovim</title>
|
||||
<defs>
|
||||
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="a">
|
||||
<stop stop-color="#16B0ED" stop-opacity=".8" offset="0%"></stop>
|
||||
<stop stop-color="#0F59B2" stop-opacity=".837" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="b">
|
||||
<stop stop-color="#7DB643" offset="0%"></stop>
|
||||
<stop stop-color="#367533" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="c">
|
||||
<stop stop-color="#88C649" stop-opacity=".8" offset="0%"></stop>
|
||||
<stop stop-color="#439240" stop-opacity=".84" offset="100%"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path
|
||||
d="M.027 45.459L45.224-.173v212.171L.027 166.894V45.459z"
|
||||
fill="url(#a)"
|
||||
transform="translate(1 1)"
|
||||
></path>
|
||||
<path
|
||||
d="M129.337 45.89L175.152-.149l-.928 212.146-45.197-45.104.31-121.005z"
|
||||
fill="url(#b)"
|
||||
transform="matrix(-1 0 0 1 305 1)"
|
||||
></path>
|
||||
<path
|
||||
d="M45.194-.137L162.7 179.173l-32.882 32.881L12.25 33.141 45.194-.137z"
|
||||
fill="url(#c)"
|
||||
transform="translate(1 1)"
|
||||
></path>
|
||||
<path
|
||||
d="M46.234 84.032l-.063 7.063-36.28-53.563 3.36-3.422 32.983 49.922z"
|
||||
fill-opacity=".13"
|
||||
fill="#000"
|
||||
></path>
|
||||
<g fill="#444">
|
||||
<path
|
||||
d="M227 154V64.44h4.655c1.55 0 2.445.75 2.685 2.25l.806 13.502c4.058-5.16 8.786-9.316 14.188-12.466 5.4-3.15 11.413-4.726 18.037-4.726 4.893 0 9.205.781 12.935 2.34 3.729 1.561 6.817 3.811 9.264 6.751 2.448 2.942 4.297 6.48 5.55 10.621 1.253 4.14 1.88 8.821 1.88 14.042V154h-8.504V96.754c0-8.402-1.91-14.987-5.729-19.757-3.82-4.771-9.667-7.156-17.544-7.156-5.851 0-11.28 1.516-16.292 4.545-5.013 3.032-9.489 7.187-13.427 12.467V154H227zM350.624 63c5.066 0 9.755.868 14.069 2.605 4.312 1.738 8.052 4.268 11.219 7.592s5.638 7.412 7.419 12.264C385.11 90.313 386 95.883 386 102.17c0 1.318-.195 2.216-.588 2.696-.393.48-1.01.719-1.851.719h-64.966v1.70c0 6.708.784 12.609 2.353 17.7 1.567 5.09 3.8 9.357 6.695 12.802 2.895 3.445 6.393 6.034 10.495 7.771 4.1 1.738 8.686 2.606 13.752 2.606 4.524 0 8.446-.494 11.762-1.483 3.317-.988 6.108-2.097 8.37-3.324 2.261-1.227 4.056-2.336 5.383-3.324 1.326-.988 2.292-1.482 2.895-1.482.784 0 1.388.3 1.81.898l2.352 2.875c-1.448 1.797-3.362 3.475-5.745 5.031-2.383 1.558-5.038 2.891-7.962 3.998-2.926 1.109-6.062 1.991-9.41 2.65a52.21 52.21 0 01-10.088.989c-6.152 0-11.762-1.064-16.828-3.19-5.067-2.125-9.415-5.225-13.043-9.298-3.63-4.074-6.435-9.06-8.415-14.96C310.99 121.655 310 114.9 310 107.294c0-6.408.92-12.323 2.76-17.744 1.84-5.421 4.493-10.093 7.961-14.016 3.467-3.922 7.72-6.991 12.758-9.209C338.513 64.11 344.229 63 350.624 63zm.573 6c-4.696 0-8.904.702-12.623 2.105-3.721 1.404-6.936 3.421-9.65 6.053-2.713 2.631-4.908 5.79-6.586 9.474S319.55 94.439 319 99h60c0-4.679-.672-8.874-2.013-12.588-1.343-3.712-3.232-6.856-5.67-9.43-2.44-2.571-5.367-4.545-8.782-5.92-3.413-1.374-7.192-2.062-11.338-2.062zM435.546 63c6.526 0 12.368 1.093 17.524 3.28 5.154 2.186 9.5 5.286 13.04 9.298 3.538 4.013 6.238 8.85 8.099 14.51 1.861 5.66 2.791 11.994 2.791 19.002 0 7.008-.932 13.327-2.791 18.957-1.861 5.631-4.561 10.452-8.099 14.465-3.54 4.012-7.886 7.097-13.04 9.254-5.156 2.156-10.998 3.234-17.524 3.234-6.529 0-12.369-1.078-17.525-3.234-5.155-2.157-9.517-5.242-13.085-9.254-3.57-4.013-6.285-8.836-8.145-14.465-1.861-5.63-2.791-11.95-2.791-18.957 0-7.008.93-13.342 2.791-19.002 1.861-5.66 4.576-10.496 8.145-14.51 3.568-4.012 7.93-7.112 13.085-9.299C423.177 64.094 429.017 63 435.546 63zm-.501 86c5.341 0 10.006-.918 13.997-2.757 3.99-1.838 7.32-4.474 9.992-7.909 2.67-3.435 4.664-7.576 5.986-12.428 1.317-4.85 1.98-10.288 1.98-16.316 0-5.965-.66-11.389-1.98-16.27-1.322-4.88-3.316-9.053-5.986-12.519-2.67-3.463-6-6.13-9.992-7.999-3.991-1.867-8.657-2.802-13.997-2.802s-10.008.935-13.997 2.802c-3.991 1.87-7.322 4.536-9.992 8-2.671 3.465-4.68 7.637-6.03 12.518-1.35 4.881-2.026 10.305-2.026 16.27 0 6.026.675 11.465 2.025 16.316 1.35 4.852 3.36 8.993 6.031 12.428 2.67 3.435 6 6.07 9.992 7.91 3.99 1.838 8.656 2.756 13.997 2.756z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
<path
|
||||
d="M530.57 152h-20.05L474 60h18.35c1.61 0 2.967.39 4.072 1.166 1.103.778 1.865 1.763 2.283 2.959l17.722 49.138a92.762 92.762 0 012.551 8.429c.686 2.751 1.298 5.5 1.835 8.25.537-2.75 1.148-5.499 1.835-8.25a77.713 77.713 0 012.64-8.429l18.171-49.138c.417-1.196 1.164-2.181 2.238-2.96 1.074-.776 2.356-1.165 3.849-1.165H567l-36.43 92zM572 61h23v92h-23zM610 153V60.443h13.624c2.887 0 4.78 1.354 5.682 4.06l1.443 6.856a52.7 52.7 0 015.097-4.962 32.732 32.732 0 015.683-3.879 30.731 30.731 0 016.496-2.57c2.314-.632 4.855-.948 7.624-.948 5.832 0 10.63 1.579 14.39 4.736 3.758 3.157 6.57 7.352 8.434 12.585 1.444-3.068 3.248-5.698 5.413-7.894 2.165-2.194 4.541-3.984 7.127-5.367a32.848 32.848 0 018.254-3.068 39.597 39.597 0 018.796-.992c5.111 0 9.653.783 13.622 2.345 3.97 1.565 7.307 3.849 10.014 6.857 2.706 3.007 4.766 6.675 6.18 11.005C739.29 83.537 740 88.5 740 94.092V153h-22.284V94.092c0-5.894-1.294-10.329-3.878-13.306-2.587-2.977-6.376-4.465-11.368-4.465-2.286 0-4.404.391-6.358 1.172a15.189 15.189 0 00-5.144 3.383c-1.473 1.474-2.631 3.324-3.474 5.548-.842 2.225-1.263 4.781-1.263 7.668V153h-22.37V94.092c0-6.194-1.249-10.704-3.744-13.532-2.497-2.825-6.18-4.24-11.051-4.24-3.19 0-6.18.798-8.976 2.391-2.799 1.593-5.399 3.775-7.804 6.54V153H610zM572 30h23v19h-23z"
|
||||
fill="currentColor"
|
||||
fill-opacity=".8"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://github.com/folke/lazy.nvim/releases/latest">
|
||||
<img
|
||||
alt="Latest release"
|
||||
|
|
BIN
tests/image/test.pdf
Normal file
BIN
tests/image/test.pdf
Normal file
Binary file not shown.
62
tests/image/test.tex
Normal file
62
tests/image/test.tex
Normal file
|
@ -0,0 +1,62 @@
|
|||
\documentclass{article}
|
||||
\usepackage{graphicx} % For images
|
||||
\usepackage{amsmath} % For math symbols
|
||||
\usepackage{amssymb} % For extra math symbols
|
||||
|
||||
\begin{document}
|
||||
|
||||
\section{Image Tests}
|
||||
|
||||
Inline image:
|
||||
|
||||
\includegraphics[width=0.5\textwidth]{test.png}
|
||||
|
||||
\begin{figure}[h]
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{test.png}
|
||||
\caption{Test image centered in a figure environment.}
|
||||
\label{fig:test_image}
|
||||
\end{figure}
|
||||
|
||||
\newpage
|
||||
|
||||
\section{Math Tests}
|
||||
|
||||
Inline math: $E=mc^2$ and $\int_0^1 x^2 \,dx$
|
||||
|
||||
Displayed equation:
|
||||
|
||||
\[
|
||||
f(x) = \sum_{n=0}^{\infty} \frac{x^n}{n!}
|
||||
\]
|
||||
|
||||
Equation environment:
|
||||
|
||||
\begin{equation}
|
||||
a^2 + b^2 = c^2
|
||||
\label{eq:pythagoras}
|
||||
\end{equation}
|
||||
|
||||
Aligned equations:
|
||||
|
||||
\begin{align}
|
||||
x^2 + y^2 &= r^2 \\
|
||||
\nabla \cdot \mathbf{E} &= \frac{\rho}{\varepsilon_0}
|
||||
\end{align}
|
||||
|
||||
Multiline equations:
|
||||
|
||||
\begin{multline}
|
||||
a + b + c + d + e + f + g + h + i + j + k = \\
|
||||
l + m + n + o + p + q + r + s + t + u + v
|
||||
\end{multline}
|
||||
|
||||
\newpage
|
||||
|
||||
\section{Testing Referencing}
|
||||
|
||||
Referencing an equation: See Eq.~\ref{eq:pythagoras}.
|
||||
|
||||
Referencing an image: See Fig.~\ref{fig:test_image}.
|
||||
|
||||
\end{document}
|
5
tests/image/test2.md
Normal file
5
tests/image/test2.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# test
|
||||
|
||||
## Wikilinks
|
||||
|
||||
!![[test.jpg]]
|
Loading…
Add table
Add a link
Reference in a new issue