Skip to content

Commit

Permalink
feat: add remote image support and integrate it with markdown
Browse files Browse the repository at this point in the history
  • Loading branch information
3rd committed Jun 30, 2023
1 parent 7344637 commit 7023c7d
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 14 deletions.
45 changes: 45 additions & 0 deletions lua/image/image.lua
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,51 @@ local from_file = function(path, options, state)
return create_image(path, options, state)
end

---@param url string
---@param options? ImageOptions
---@param callback fun(image: Image|nil)
---@param state State
local from_url = function(url, options, callback, state)
if state.remote_cache[url] then
callback(state.remote_cache[url])
return
end

local tmp_path = os.tmpname() .. ".png"
local stdout = vim.loop.new_pipe()

vim.loop.spawn("curl", {
args = { "-s", "-o", tmp_path, url },
stdio = { nil, stdout, nil },
hide = true,
}, function(code, signal)
if code ~= 0 then
utils.throw("image: curl errored while downloading " .. url, {
code = code,
signal = signal,
})
end
end)

vim.loop.read_start(stdout, function(err, data)
assert(not err, err)
if not data then utils.debug("image: downloaded " .. url .. " to " .. tmp_path) end
local ok = pcall(utils.png.get_dimensions, tmp_path)
if not ok then
utils.debug("image: invalid png file", tmp_path)
callback(nil)
return
end

vim.defer_fn(function()
local image = create_image(tmp_path, options, state)
state.remote_cache[url] = image
callback(image)
end, 0)
end)
end

return {
from_file = from_file,
from_url = from_url,
}
10 changes: 9 additions & 1 deletion lua/image/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ local state = {
options = default_options,
images = {},
extmarks_namespace = nil,
remote_cache = {},
}

---@type API
Expand Down Expand Up @@ -61,7 +62,7 @@ api.setup = function(options)
local window_history = {}
vim.api.nvim_set_decoration_provider(state.extmarks_namespace, {
on_win = function(_, winid, bufnr, topline, botline)
-- utils.debug("on_win", { winid = winid })
utils.debug("on_win", { winid = winid })

local prev = window_history[winid]
if not prev then
Expand Down Expand Up @@ -174,6 +175,13 @@ api.from_file = function(path, options)
return image.from_file(path, options, state)
end

---@param url string
---@param options? ImageOptions
---@param callback fun(image: Image|nil)
api.from_url = function(url, options, callback)
image.from_url(url, options, callback, state)
end

---@param id? string
api.clear = function(id)
local target = state.images[id]
Expand Down
46 changes: 33 additions & 13 deletions lua/image/integrations/markdown.lua
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
local utils = require("image/utils")

local resolve = function(markdown_file_path, image_path)
local resolve_absolute_path = function(markdown_file_path, image_path)
if string.sub(image_path, 1, 1) == "/" then return image_path end
local markdown_dir = vim.fn.fnamemodify(markdown_file_path, ":h")
local absolute_image_path = markdown_dir .. "/" .. image_path
absolute_image_path = vim.fn.fnamemodify(absolute_image_path, ":p")
return absolute_image_path
end

local is_remote_url = function(url)
return string.sub(url, 1, 7) == "http://" or string.sub(url, 1, 8) == "https://"
end

---@return { node: any, range: { start_row: number, start_col: number, end_row: number, end_col: number }, url: string }[]
local query_buffer_images = function(buffer)
local buf = buffer or vim.api.nvim_get_current_buf()
Expand Down Expand Up @@ -57,13 +61,11 @@ local render = function(ctx)
local file_path = vim.api.nvim_buf_get_name(window.buffer)

for _, match in ipairs(matches) do
local url = resolve(file_path, match.url)

local ok = pcall(utils.png.get_dimensions, url)
if ok then
local id = string.format("%d:%d:%d", window.id, window.buffer, match.range.start_row)
local height = nil
local id = string.format("%d:%d:%d", window.id, window.buffer, match.range.start_row)
local height = nil

---@param image Image
local render_image = function(image)
if ctx.options.sizing_strategy == "height-from-empty-lines" then
local empty_line_count = -1
for i = match.range.end_row + 2, #lines do
Expand All @@ -75,19 +77,37 @@ local render = function(ctx)
end
height = math.max(1, empty_line_count)
end

local image = ctx.api.from_file(url, {
id = id,
image.render({
height = height,
x = match.range.start_col,
y = match.range.start_row + 1,
})
table.insert(new_image_ids, id)
end

-- remote
if is_remote_url(match.url) then
ctx.api.from_url(
match.url,
{ id = id, window = window.id, buffer = window.buffer, with_virtual_padding = true },
function(image)
if not image then return end
render_image(image)
end
)
else
-- local
local url = resolve_absolute_path(file_path, match.url)

local ok = pcall(utils.png.get_dimensions, url)
if not ok then return end
local image = ctx.api.from_file(url, {
id = id,
window = window.id,
buffer = window.buffer,
with_virtual_padding = true,
})
image.render()

table.insert(new_image_ids, id)
render_image(image)
end
end

Expand Down
2 changes: 2 additions & 0 deletions lua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
---@class API
---@field setup fun(options?: Options)
---@field from_file fun(path: string, options?: ImageOptions): Image
---@field from_url fun(url: string, options?: ImageOptions, callback: fun(image: Image| nil))
---@field clear fun(id?: string)
---@field get_images fun(opts?: { window?: number, buffer?: number }): Image[]

Expand All @@ -11,6 +12,7 @@
---@field options Options
---@field images { [string]: Image }
---@field extmarks_namespace any
---@field remote_cache { [string]: Image }

---@class MarkdownIntegrationOptions
---@field enabled boolean
Expand Down

0 comments on commit 7023c7d

Please sign in to comment.