Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 79 additions & 1 deletion lua/diagram/hover.lua
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ end
local get_diagram_at_cursor = function(bufnr, integrations)
local cursor = vim.api.nvim_win_get_cursor(0)
local row = cursor[1] - 1 -- 0-indexed
local col = cursor[2]

-- Find matching integration for current filetype
local ft = vim.bo[bufnr].filetype
Expand All @@ -78,6 +77,84 @@ local get_diagram_at_cursor = function(bufnr, integrations)
return nil
end

--- Render diagram at cursor and open the image with the OS default app (|vim.ui.open()|).
--- New entry point: same render path as hover, but skips the tab/image.nvim preview.
---@param integrations Integration[]
---@param renderer_options table<string, any>
M.open_diagram_externally_at_cursor = function(integrations, renderer_options)
local bufnr = vim.api.nvim_get_current_buf()
local diagram = get_diagram_at_cursor(bufnr, integrations)
if not diagram then
vim.notify("No diagram found at cursor", vim.log.levels.INFO)
return
end

local ft = vim.bo[bufnr].filetype
local integration = nil
for _, integ in ipairs(integrations) do
if vim.tbl_contains(integ.filetypes, ft) then
integration = integ
break
end
end
if not integration then
return
end

local renderer = nil
for _, r in ipairs(integration.renderers) do
if r.id == diagram.renderer_id then
renderer = r
break
end
end
if not renderer then
vim.notify("No renderer found for " .. diagram.renderer_id, vim.log.levels.ERROR)
return
end

local options = renderer_options[renderer.id] or {}
local renderer_result = renderer.render(diagram.source, options)
-- Abort if render failed (e.g. mmdc not installed); same idea as render_buffer in init.lua.
if not renderer_result then
return
end

local function open_file()
if vim.fn.filereadable(renderer_result.file_path) == 0 then
vim.notify("Diagram file not found: " .. renderer_result.file_path, vim.log.levels.ERROR)
return
end
vim.ui.open(renderer_result.file_path)
end

-- Async render (e.g. mermaid): poll until job finishes, then open (same pattern as show_diagram_hover).
if renderer_result.job_id then
local timer = vim.loop.new_timer()
if not timer then
return
end
timer:start(
0,
100,
vim.schedule_wrap(function()
local result = vim.fn.jobwait({ renderer_result.job_id }, 0)
if result[1] ~= -1 then
if timer:is_active() then
timer:stop()
end
if not timer:is_closing() then
timer:close()
end
open_file()
end
end)
)
else
open_file()
end
end

---@param diagram Diagram
---@param integrations Integration[]
---@param renderer_options table<string, any>
Expand Down Expand Up @@ -140,6 +217,7 @@ M.show_diagram_hover = function(diagram, integrations, renderer_options)
"Press 'q' to close this tab",
"Press 'o' to open image with system viewer",
"",
"",
})

-- Try to render the image
Expand Down
12 changes: 9 additions & 3 deletions lua/diagram/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ local render_buffer = function(bufnr, winnr, integration)

local renderer_options = state.renderer_options[renderer.id] or {}
local renderer_result = renderer.render(diagram.source, renderer_options)

-- Skip rendering if the renderer returned nil (e.g., executable not found)
if not renderer_result then
goto continue
Expand Down Expand Up @@ -120,15 +120,15 @@ local render_buffer = function(bufnr, winnr, integration)
else
render_image()
end

::continue::
end
end

---@param opts PluginOptions
local setup = function(opts)
local ok = pcall(require, "image")
if not ok then
if not ok then
vim.notify("Missing dependency: 3rd/image.nvim\nPlease install image.nvim to use diagram.nvim", vim.log.levels.ERROR, { title = "Diagram.nvim" })
return
end
Expand Down Expand Up @@ -200,6 +200,11 @@ local show_diagram_hover = function()
hover.hover_at_cursor(state.integrations, state.renderer_options)
end

-- Public API: render diagram at cursor and open PNG with OS default app (vim.ui.open). See hover.lua.
local open_diagram_externally = function()
hover.open_diagram_externally_at_cursor(state.integrations, state.renderer_options)
end

local render = function()
local bufnr = vim.api.nvim_get_current_buf()
local winnr = vim.api.nvim_get_current_win()
Expand All @@ -220,6 +225,7 @@ return {
setup = setup,
get_cache_dir = get_cache_dir,
show_diagram_hover = show_diagram_hover,
open_diagram_externally = open_diagram_externally,
render = render,
clear = clear,
}