Skip to content

Commit

Permalink
feat: handle extmark scroll, allow editing and preview in markdown at…
Browse files Browse the repository at this point in the history
… the same time, fix kitty clear
  • Loading branch information
3rd committed Jun 28, 2023
1 parent 3ca9bf5 commit 31d12e0
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 87 deletions.
6 changes: 3 additions & 3 deletions lua/image/backends/kitty/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,17 @@ end

backend.clear = function(image_id)
if image_id then
utils.log("kitty: clear", image_id)
local image = backend.state.images[image_id]
if not image then return end
helpers.write_graphics({
action = codes.control.action.delete,
display_delete = "i",
image_id = 1,
image_id = image.internal_id,
quiet = 2,
})
backend.state.images[image_id] = nil
return
end
utils.log("kitty: clear all")
helpers.write_graphics({
action = codes.control.action.delete,
display_delete = "a",
Expand Down
17 changes: 3 additions & 14 deletions lua/image/image.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,28 +50,17 @@ local create_image = function(path, options, state)

-- virtual padding
if ok and instance.buffer and instance.with_virtual_padding then
local row = instance.geometry.y - 1
local row = instance.geometry.y
local width = instance.rendered_geometry.width or 1
local height = instance.rendered_geometry.height or 1

-- remove same-row extmarks
-- local extmarks =
-- vim.api.nvim_buf_get_extmarks(instance.buffer, state.extmarks_namespace, 0, -1, { details = true })
-- for _, extmark in ipairs(extmarks) do
-- local mark_id, mark_row, mark_col, mark_opts = unpack(extmark)
-- local virt_height = #(mark_opts.virt_lines or {})
-- if mark_row == row then
-- if virt_height == height then return end
-- vim.api.nvim_buf_del_extmark(instance.buffer, state.extmarks_namespace, mark_id)
-- end
-- end

local text = string.rep(" ", width)
local filler = {}
for _ = 0, height - 1 do
filler[#filler + 1] = { { text, "" } }
end
vim.api.nvim_buf_set_extmark(instance.buffer, state.extmarks_namespace, row, 0, {
utils.debug("extmark create", { id = numerical_id, buf = instance.buffer })
vim.api.nvim_buf_set_extmark(instance.buffer, state.extmarks_namespace, row - 1, 0, {
id = numerical_id,
virt_lines = filler,
})
Expand Down
7 changes: 0 additions & 7 deletions lua/image/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,6 @@ api.setup = function(options)

-- setup namespaces
state.extmarks_namespace = vim.api.nvim_create_namespace("image.nvim")
vim.api.nvim_set_decoration_provider(state.extmarks_namespace, {
-- on_win = function(_, _, buf, top, bot)
-- vim.schedule(function()
-- hologram.buf_render_images(buf, top, bot)
-- end)
-- end,
})

-- setup autocommands
local group = vim.api.nvim_create_augroup("image.nvim", { clear = true })
Expand Down
48 changes: 25 additions & 23 deletions lua/image/integrations/markdown.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ local render = function(ctx)
local new_image_ids = {}

for _, match in ipairs(matches) do
if vim.loop.fs_stat(match.url) then
local ok = pcall(utils.png.get_dimensions, match.url)
if ok then
local id = string.format("%d:%d:%d", window.id, window.buffer, match.range.start_row)
local height = nil

Expand Down Expand Up @@ -76,42 +77,43 @@ local render = function(ctx)

table.insert(new_image_ids, id)
end
end

for _, image in ipairs(previous_images) do
if not vim.tbl_contains(new_image_ids, image.id) then
-- utils.debug("md clear", image.id)
image.clear()
end
end
for _, image in ipairs(previous_images) do
if not vim.tbl_contains(new_image_ids, image.id) then image.clear() end
end
end
end
end

---@type fun(ctx: IntegrationContext)
local setup_autocommands = function(ctx)
local events = {
local group = vim.api.nvim_create_augroup("image.nvim:markdown", { clear = true })

vim.api.nvim_create_autocmd({
"WinNew",
"BufWinEnter",
"TextChanged",
"WinScrolled",
"WinResized",
"InsertEnter",
"InsertLeave",
}
local group = vim.api.nvim_create_augroup("image.nvim:markdown", { clear = true })
vim.api.nvim_create_autocmd(events, {
}, {
group = group,
callback = function(args)
if args.event == "InsertEnter" then
local current_window = vim.api.nvim_get_current_win()
local images = ctx.api.get_images({ window = current_window })
for _, image in ipairs(images) do
image.clear()
end
else
render(ctx)
callback = function()
render(ctx)
end,
})

vim.api.nvim_create_autocmd({
"TextChanged",
"TextChangedI",
}, {
group = group,
callback = function()
local current_window = vim.api.nvim_get_current_win()
local images = ctx.api.get_images({ window = current_window })
for _, image in ipairs(images) do
image.clear()
end
render(ctx)
end,
})
end
Expand Down
91 changes: 51 additions & 40 deletions lua/image/renderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@ local adjust_to_aspect_ratio = function(term_size, dimensions, width, height)
local pixel_height = height * term_size.cell_height
if width > height then
local new_height = math.ceil(pixel_width / aspect_ratio / term_size.cell_height)
utils.debug("adjust_to_aspect_ratio() landscape", { new_height = new_height })
return width, new_height
else
local new_width = math.ceil(pixel_height * aspect_ratio / term_size.cell_width)
utils.debug("adjust_to_aspect_ratio() portrait", { new_width = new_width })
return new_width, height
end
end
Expand Down Expand Up @@ -57,10 +55,6 @@ local render = function(image, state)
height = image_rows
end

utils.debug(
("render(1): x=%d y=%d w=%d h=%d x_offset=%d y_offset=%d"):format(x, y, width, height, x_offset, y_offset)
)

-- rendered size cannot be larger than the image itself
width = math.min(width, image_columns)
height = math.min(height, image_rows)
Expand All @@ -69,10 +63,6 @@ local render = function(image, state)
width = math.min(width, term_size.screen_cols)
height = math.min(width, term_size.screen_rows)

utils.debug(
("render(2): x=%d y=%d w=%d h=%d x_offset=%d y_offset=%d"):format(x, y, width, height, x_offset, y_offset)
)

if image.window ~= nil then
-- window is valid
local window = utils.window.get_window(image.window)
Expand All @@ -88,33 +78,14 @@ local render = function(image, state)
local global_offsets = get_global_offsets()
x_offset = global_offsets.x - window.scroll_x
y_offset = global_offsets.y + 1 - window.scroll_y
utils.debug("scroll_y", { window.scroll_y, y_offset })

-- window offsets
window_offset_x = window.x
window_offset_y = window.y

-- extmark offsets
if image.buffer then
-- local win_info = vim.fn.getwininfo(image.window)[1]
local extmark_offset_y = 0
local extmarks = vim.api.nvim_buf_get_extmarks(image.buffer, -1, 0, -1, { details = true })
for _, extmark in ipairs(extmarks) do
local mark_id, mark_row, mark_col, mark_opts = unpack(extmark)
local virt_height = #(mark_opts.virt_lines or {})
utils.debug(("render() mark_id=%d mark_row=%d virt_height=%d"):format(mark_id, mark_row, virt_height))
if mark_row + 1 >= y then break end
y_offset = y_offset - virt_height
utils.debug(("render() extmark_offset_y=%d"):format(extmark_offset_y))
end
end

-- w/h can take at most 100% of the window
width = math.min(width, window.width - x - x_offset)
height = math.min(height, window.height - y - y_offset)
utils.debug(
("render(3): x=%d y=%d w=%d h=%d x_offset=%d y_offset=%d"):format(x, y, width, height, x_offset, y_offset)
)

-- global max window width/height percentage
if type(state.options.max_width_window_percentage) == "number" then
Expand All @@ -123,33 +94,73 @@ local render = function(image, state)
if type(state.options.max_height_window_percentage) == "number" then
height = math.min(height, math.floor(window.height * state.options.max_height_window_percentage / 100))
end

utils.debug(
("render(4): x=%d y=%d w=%d h=%d x_offset=%d y_offset=%d"):format(x, y, width, height, x_offset, y_offset)
)
end

-- global max width/height
if type(state.options.max_width) == "number" then width = math.min(width, state.options.max_width) end
if type(state.options.max_height) == "number" then height = math.min(height, state.options.max_height) end
utils.debug(
("render(5): x=%d y=%d w=%d h=%d x_offset=%d y_offset=%d"):format(x, y, width, height, x_offset, y_offset)
)

width, height = adjust_to_aspect_ratio(term_size, image_dimensions, width, height)
utils.debug(
("render(6): x=%d y=%d w=%d h=%d x_offset=%d y_offset=%d"):format(x, y, width, height, x_offset, y_offset)
)

if width <= 0 or height <= 0 then return false end

local absolute_x = x + x_offset + window_offset_x
local absolute_y = y + y_offset + window_offset_y
local prevent_rendering = false

-- extmark offsets
if image.with_virtual_padding and image.window then
local win_info = vim.fn.getwininfo(image.window)[1]
local topline = win_info.topline
local botline = win_info.botline
local topfill = vim.fn.winsaveview().topfill

-- bail if the image is above the top of the window and there's no topfill
if topfill == 0 and image.geometry.y < topline then prevent_rendering = true end

-- bail if the image + its height is above the top of the window + topfill
if image.geometry.y + height + 1 < topline + topfill then prevent_rendering = true end

-- bail if the image is below the bottom of the window
if image.geometry.y > botline then prevent_rendering = true end

-- offset by topfill if the image started above the top of the window
if not prevent_rendering then
if topfill > 0 and image.geometry.y < topline then
--
absolute_y = absolute_y - (height - topfill)
elseif image.buffer then
-- offset by any pre-y virtual lines
local extmarks = vim.tbl_map(
function(mark)
local mark_id, mark_row, mark_col, mark_opts = unpack(mark)
local virt_height = #(mark_opts.virt_lines or {})
return { id = mark_id, row = mark_row + 1, col = mark_col, height = virt_height }
end,
vim.api.nvim_buf_get_extmarks(
image.buffer,
-1,
{ topline - 1, 0 },
{ image.geometry.y, 0 },
{ details = true }
)
)

local offset = topfill
for _, mark in ipairs(extmarks) do
if mark.row ~= image.geometry.y then offset = offset + mark.height end
end

absolute_y = absolute_y + offset
end
end
end

if prevent_rendering then absolute_y = -999999 end

state.backend.render(image, absolute_x, absolute_y, width, height)
image.rendered_geometry = { x = absolute_x, y = absolute_y, width = width, height = height }

-- utils.debug(state.images)
return true
end

Expand Down
1 change: 1 addition & 0 deletions lua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
---@field path string
---@field window? number
---@field buffer? number
---@field with_virtual_padding? boolean
---@field geometry ImageGeometry
---@field rendered_geometry ImageGeometry
---@field get_dimensions fun(): { width: number, height: number }
Expand Down

0 comments on commit 31d12e0

Please sign in to comment.