Skip to content

Commit

Permalink
feat: add Neorg integration
Browse files Browse the repository at this point in the history
  • Loading branch information
3rd committed Jul 4, 2023
1 parent 4fbc195 commit 069eb23
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 11 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ require("image").setup({
download_remote_images = true,
clear_in_insert_mode = false,
},
neorg = {
enabled = true,
download_remote_images = true,
clear_in_insert_mode = false,
},
},
max_width = nil,
max_height = nil,
Expand Down Expand Up @@ -75,11 +80,8 @@ nvim --clean -c ":luafile minimal-setup.lua"

### Integrations

Currently, there's a single integration for Markdown files, which is enabled by default.
\
Will add more soon and document them here.

- Markdown
- Neorg (pending https://github.com/nvim-neorg/neorg/issues/971)

## API

Expand Down
7 changes: 6 additions & 1 deletion lua/image/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ local default_options = {
enabled = true,
sizing_strategy = "auto",
download_remote_images = true,
clear_in_insert_mode = true,
clear_in_insert_mode = false,
},
neorg = {
enabled = true,
download_remote_images = true,
clear_in_insert_mode = false,
},
},
max_width = nil,
Expand Down
8 changes: 4 additions & 4 deletions lua/image/integrations/markdown.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
local utils = require("image/utils")

local resolve_absolute_path = function(markdown_file_path, image_path)
local resolve_absolute_path = function(document_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
local document_dir = vim.fn.fnamemodify(document_file_path, ":h")
local absolute_image_path = document_dir .. "/" .. image_path
absolute_image_path = vim.fn.fnamemodify(absolute_image_path, ":p")
return absolute_image_path
end
Expand Down Expand Up @@ -50,7 +50,6 @@ local render = function(ctx)
for _, window in ipairs(windows) do
if vim.bo[window.buffer].filetype == "markdown" then
local matches = query_buffer_images(window.buffer)
local lines = vim.api.nvim_buf_get_lines(window.buffer, 0, -1, false)

local previous_images = ctx.api.get_images({
window = window.id,
Expand All @@ -68,6 +67,7 @@ local render = function(ctx)
local render_image = function(image)
if ctx.options.sizing_strategy == "height-from-empty-lines" then
local empty_line_count = -1
local lines = vim.api.nvim_buf_get_lines(window.buffer, 0, -1, false)
for i = match.range.end_row + 2, #lines do
if lines[i] == "" then
empty_line_count = empty_line_count + 1
Expand Down
180 changes: 180 additions & 0 deletions lua/image/integrations/neorg.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
local utils = require("image/utils")

local resolve_absolute_path = function(document_file_path, image_path)
if string.sub(image_path, 1, 1) == "/" then return image_path end
local document_dir = vim.fn.fnamemodify(document_file_path, ":h")
local absolute_image_path = document_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()

local parser = vim.treesitter.get_parser(buf, "norg")
local root = parser:parse()[1]:root()
local query =
vim.treesitter.query.parse("norg", '(infirm_tag (tag_name) @name (tag_parameters) @path (#eq? name "image"))')

local images = {}

for id, node in query:iter_captures(root, 0) do
local capture = query.captures[id]
if capture == "path" then
local path = vim.treesitter.get_node_text(node, buffer)
if path then
local start_row, start_col, end_row, end_col = node:range()
table.insert(images, {
node = node,
range = { start_row = start_row, start_col = start_col, end_row = end_row, end_col = end_col },
url = resolve_absolute_path(vim.api.nvim_buf_get_name(buffer), path),
})
end
end
end

return images
end

---@type fun(ctx: IntegrationContext)
local render = function(ctx)
local windows = utils.window.get_visible_windows()

for _, window in ipairs(windows) do
if vim.bo[window.buffer].filetype == "norg" then
local matches = query_buffer_images(window.buffer)

local previous_images = ctx.api.get_images({
window = window.id,
buffer = window.buffer,
})
local new_image_ids = {}

local file_path = vim.api.nvim_buf_get_name(window.buffer)

for _, match in ipairs(matches) do
local id = string.format("%d:%d:%d:%s", window.id, window.buffer, match.range.start_row, match.url)
local height = nil

---@param image Image
local render_image = function(image)
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
if not ctx.options.download_remote_images then return end

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 path = resolve_absolute_path(file_path, match.url)
local ok, image = pcall(ctx.api.from_file, path, {
id = id,
window = window.id,
buffer = window.buffer,
with_virtual_padding = true,
})
if ok then render_image(image) end
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 group = vim.api.nvim_create_augroup("image.nvim:neorg", { clear = true })

vim.api.nvim_create_autocmd({
"WinNew",
"BufWinEnter",
"WinResized",
}, {
group = group,
callback = function(args)
if vim.bo[args.buf].filetype ~= "norg" then return end
render(ctx)
end,
})

vim.api.nvim_create_autocmd({
"TextChanged",
"TextChangedI",
}, {
group = group,
callback = function(args)
if vim.bo[args.buf].filetype ~= "norg" then return end
if args.event == "TextChangedI" and ctx.options.clear_in_insert_mode then return end
render(ctx)
end,
})

if ctx.options.clear_in_insert_mode then
vim.api.nvim_create_autocmd({
"InsertEnter",
}, {
group = group,
callback = function(args)
if vim.bo[args.buf].filetype ~= "norg" then return end
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
end,
})

vim.api.nvim_create_autocmd({
"InsertLeave",
}, {
group = group,
callback = function(args)
if vim.bo[args.buf].filetype ~= "norg" then return end
render(ctx)
end,
})
end
end

---@type fun(api: API, options: NeorgIntegrationOptions)
local setup = function(api, options)
local opts = options or {} --[[@as NeorgIntegrationOptions]]
local context = {
api = api,
options = opts,
}

vim.defer_fn(function()
setup_autocommands(context)
render(context)
end, 0)
end

---@class NeorgIntegration: Integration
local integration = {
setup = setup,
}

return integration
9 changes: 7 additions & 2 deletions lua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@
---@field download_remote_images boolean
---@field clear_in_insert_mode boolean

---@alias IntegrationOptions MarkdownIntegrationOptions
---@class NeorgIntegrationOptions
---@field enabled boolean
---@field download_remote_images boolean
---@field clear_in_insert_mode boolean

---@alias IntegrationOptions MarkdownIntegrationOptions|NeorgIntegrationOptions

---@class Options
---@field backend "kitty"|"ueberzug"
---@field integrations { markdown: IntegrationOptions }
---@field integrations { markdown: MarkdownIntegrationOptions, neorg: NeorgIntegrationOptions }
---@field max_width? number
---@field max_height? number
---@field max_width_window_percentage? number
Expand Down

0 comments on commit 069eb23

Please sign in to comment.