generated from eblume/project-template
feat(nvim): conceal wiki-link ids to styled name hyperlinks (§8.4)
`conceal.lua` hides the `[[id|` prefix and `]]` suffix with conceal extmarks (refreshed on edit), leaving the label as a styled `HephLink`; `conceallevel=2` + empty `concealcursor` reveal the raw `[[id|Name]]` on the cursor's line so it stays editable. The `[[` picker now inserts the labelled `[[id|Name]]` form (readable + conceal-ready; collapses to bare on save). e2e asserts the conceal extmarks + conceallevel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ef2081fd8b
commit
fd010a7066
6 changed files with 103 additions and 6 deletions
66
heph.nvim/lua/heph/conceal.lua
Normal file
66
heph.nvim/lua/heph/conceal.lua
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
--- Conceal `[[NODEID|Name]]` links down to a styled "Name" hyperlink in node
|
||||
--- buffers (tech-spec §8.4). The node id is structural noise to a reader, so we
|
||||
--- hide the `[[id|` prefix and the `]]` suffix with conceal extmarks, leaving
|
||||
--- the label visible and highlighted. `conceallevel=2` + an empty
|
||||
--- `concealcursor` reveal the raw `[[id|Name]]` on the line the cursor is on, so
|
||||
--- it stays directly editable. A bare `[[id]]` (briefly, before save→reload
|
||||
--- canonicalises it) just hides its brackets.
|
||||
|
||||
local M = {}
|
||||
|
||||
local ns = vim.api.nvim_create_namespace("heph_link_conceal")
|
||||
|
||||
--- Recompute conceal extmarks for every `[[…]]` span in `buf`.
|
||||
function M.refresh(buf)
|
||||
if not vim.api.nvim_buf_is_valid(buf) then
|
||||
return
|
||||
end
|
||||
vim.api.nvim_buf_clear_namespace(buf, ns, 0, -1)
|
||||
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
|
||||
for lnum, line in ipairs(lines) do
|
||||
local row = lnum - 1
|
||||
local from = 1
|
||||
while true do
|
||||
local s = line:find("[[", from, true) -- 1-based byte of first `[`
|
||||
if not s then
|
||||
break
|
||||
end
|
||||
local e = line:find("]]", s + 2, true) -- 1-based byte of `]]`
|
||||
if not e then
|
||||
break
|
||||
end
|
||||
local inner = line:sub(s + 2, e - 1)
|
||||
local pipe = inner:find("|", 1, true)
|
||||
-- Byte columns are 0-based for extmarks; end_col is exclusive.
|
||||
local open_end -- exclusive end of the hidden prefix (`[[` or `[[id|`)
|
||||
if pipe then
|
||||
open_end = (s + 1 + pipe) -- 0-based col just past the `|`
|
||||
else
|
||||
open_end = s + 1 -- 0-based col just past `[[`
|
||||
end
|
||||
-- Hide the prefix, highlight the visible label, hide the closing `]]`.
|
||||
vim.api.nvim_buf_set_extmark(buf, ns, row, s - 1, { end_col = open_end, conceal = "" })
|
||||
vim.api.nvim_buf_set_extmark(buf, ns, row, open_end, { end_col = e - 1, hl_group = "HephLink" })
|
||||
vim.api.nvim_buf_set_extmark(buf, ns, row, e - 1, { end_col = e + 1, conceal = "" })
|
||||
from = e + 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Enable link conceal for the current window + `buf`: define the highlight,
|
||||
--- set the window conceal options, refresh now, and refresh on edits.
|
||||
function M.attach(buf)
|
||||
vim.api.nvim_set_hl(0, "HephLink", { link = "Underlined", default = true })
|
||||
vim.wo.conceallevel = 2
|
||||
vim.wo.concealcursor = "" -- reveal the raw link on the cursor's line
|
||||
M.refresh(buf)
|
||||
vim.api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
|
||||
buffer = buf,
|
||||
callback = function()
|
||||
M.refresh(buf)
|
||||
end,
|
||||
desc = "heph: refresh [[link]] conceal",
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
|
|
@ -94,8 +94,16 @@ function M.insert()
|
|||
if not choice then
|
||||
return
|
||||
end
|
||||
local id = choice.__create and rpc.call("node.create", { kind = "doc", title = choice.title }).id or choice.id
|
||||
vim.api.nvim_put({ "[[" .. id .. "]]" }, "c", true, true)
|
||||
local id, title
|
||||
if choice.__create then
|
||||
local node = rpc.call("node.create", { kind = "doc", title = choice.title })
|
||||
id, title = node.id, node.title
|
||||
else
|
||||
id, title = choice.id, choice.title
|
||||
end
|
||||
-- Insert the labelled form `[[id|Name]]` (readable + conceal-ready); it
|
||||
-- collapses to the canonical bare `[[id]]` on save (§8.4).
|
||||
vim.api.nvim_put({ "[[" .. id .. "|" .. title .. "]]" }, "c", true, true)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ function M.read(buf, uri)
|
|||
vim.bo[buf].fileformat = "unix"
|
||||
vim.bo[buf].modified = false
|
||||
require("heph.link").attach(buf)
|
||||
require("heph.conceal").attach(buf)
|
||||
end
|
||||
|
||||
--- `BufWriteCmd` handler: route frontmatter edits to RPCs, then save the body.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue