diff options
| -rw-r--r-- | .config/nvim/lua/dotfiles/goto.lua (renamed from .config/nvim/lua/dotfiles/follow.lua) | 7 | ||||
| -rw-r--r-- | .config/nvim/plugin/50-follow.lua | 19 | ||||
| -rw-r--r-- | .config/nvim/plugin/50-fzf.lua (renamed from .config/nvim/plugin/50-fzf-lua.lua) | 0 | ||||
| -rw-r--r-- | .config/nvim/plugin/50-goto.lua | 112 | ||||
| -rw-r--r-- | .config/nvim/plugin/50-notes.lua | 72 | ||||
| -rw-r--r-- | .config/nvim/plugin/50-nvim-help.lua | 23 |
6 files changed, 116 insertions, 117 deletions
diff --git a/.config/nvim/lua/dotfiles/follow.lua b/.config/nvim/lua/dotfiles/goto.lua index e1cf109..55c076b 100644 --- a/.config/nvim/lua/dotfiles/follow.lua +++ b/.config/nvim/lua/dotfiles/goto.lua @@ -1,6 +1,7 @@ --- Generic "follow the thing under the cursor" engine: extracts a target (a markdown link, `<cfile>`, or the visual --- selection), parses an optional `scheme://uri`, and opens it. Features register per-scheme resolvers and pre-target --- follow handlers (e.g. wiki-links) so this file stays scheme-agnostic — see 50-notes.lua and 50-nvim-help.lua. +-- Generic "follow the thing under the cursor" engine: extracts a target (a markdown link, +-- `<cfile>`, or the visual selection), parses an optional `scheme://uri`, and opens it. Features +-- register per-scheme resolvers and pre-target follow handlers (e.g. wiki-links) so this file stays +-- scheme-agnostic — see 50-notes.lua and 50-nvim-help.lua. local M = {} diff --git a/.config/nvim/plugin/50-follow.lua b/.config/nvim/plugin/50-follow.lua deleted file mode 100644 index 1e48cd5..0000000 --- a/.config/nvim/plugin/50-follow.lua +++ /dev/null @@ -1,19 +0,0 @@ --- Following file names and URLs inside Neovim. The engine lives in --- `lua/dotfiles/follow.lua`; per-scheme behavior is registered by the feature --- that owns it — see 50-notes.lua (`notes://` and `[[wiki-links]]`) and --- 50-nvim-help.lua (`nvim-help://`). - -local follow = require("dotfiles.follow") - --- Add `'` to the list of characters included in `<cfile>` because `'` is a valid URI character -vim.opt.isfname:append("'") - -vim.keymap.set({ "n", "x" }, "<Leader>gg", function() - follow.follow("edit") -end, { desc = "Edit URL/file in current window" }) -vim.keymap.set({ "n", "x" }, "<Leader>gs", function() - follow.follow("split") -end, { desc = "Edit URL/file in split window" }) -vim.keymap.set({ "n", "x" }, "<Leader>gv", function() - follow.follow("vsplit") -end, { desc = "Edit URL/file in vertically split window" }) diff --git a/.config/nvim/plugin/50-fzf-lua.lua b/.config/nvim/plugin/50-fzf.lua index e0c4ce3..e0c4ce3 100644 --- a/.config/nvim/plugin/50-fzf-lua.lua +++ b/.config/nvim/plugin/50-fzf.lua diff --git a/.config/nvim/plugin/50-goto.lua b/.config/nvim/plugin/50-goto.lua new file mode 100644 index 0000000..8c72c15 --- /dev/null +++ b/.config/nvim/plugin/50-goto.lua @@ -0,0 +1,112 @@ +-- +-- 50-goto.lua +-- + +local follow = require("dotfiles.goto") + +-- Add `'` to the list of characters included in `<cfile>` because `'` is a valid URI character +vim.opt.isfname:append("'") + +vim.keymap.set({ "n", "x" }, "<Leader>gg", function() + follow.follow("edit") +end, { desc = "Edit URL/file in current window" }) +vim.keymap.set({ "n", "x" }, "<Leader>gs", function() + follow.follow("split") +end, { desc = "Edit URL/file in split window" }) +vim.keymap.set({ "n", "x" }, "<Leader>gv", function() + follow.follow("vsplit") +end, { desc = "Edit URL/file in vertically split window" }) + +------------------------------------------------------------------------------------------------------------------------ +-- Following notes (`notes://` scheme and `[[wiki-links]]`), wired into the follow engine +------------------------------------------------------------------------------------------------------------------------ + +-- `notes://<path>` resolves to `<path>` relative to the notes dir. +follow.register_scheme("notes", { + resolve = function(uri) + return notes_dir .. "/" .. uri + end, +}) + +-- Returns the inner text of a `[[wiki-link]]` under the cursor, or `nil`. +local function get_wikilink_target() + local line = vim.api.nvim_get_current_line() + local col = vim.api.nvim_win_get_cursor(0)[2] + 1 + local init = 1 + while true do + local s, e, inner = line:find("%[%[(.-)%]%]", init) + if s == nil then + return nil + end + if col >= s and col <= e then + return inner + end + init = e + 1 + end +end + +-- Follow a `[[note]]` / `[[note#Heading]]` / `[[dir/]]` wiki-link relative to the +-- notes dir, creating parent directories (and the note itself on save) as needed. +local function follow_wikilink(inner, edit_cmd) + local name, heading = inner:match("^(.-)#(.*)$") + if name == nil then + name = inner + end + local target = notes_dir .. "/" .. name + if name:sub(-1) == "/" then -- directory link: create and open it + vim.fn.mkdir(target, "p") + vim.cmd(edit_cmd .. " " .. vim.fn.fnameescape(target)) + return + end + if not name:match("%.%w+$") then -- default to a Markdown note + target = target .. ".md" + end + vim.fn.mkdir(vim.fs.dirname(target), "p") + vim.cmd(edit_cmd .. " " .. vim.fn.fnameescape(target)) + if heading ~= nil and heading ~= "" then + vim.fn.cursor(1, 1) + -- `\V` matches the heading literally; `\v` brackets the heading markers. + local pat = [[\v^#+\s+\V]] .. vim.fn.escape(heading, [[\]]) .. [[\v\s*$]] + if vim.fn.search(pat, "cW") == 0 then + vim.notify("No heading '" .. heading .. "' in " .. name, vim.log.levels.WARN) + end + end +end + +-- Wiki-links take precedence over generic URL/file following, but only on a +-- `[[...]]` under the cursor in a markdown buffer in normal mode. +follow.register_handler(function(edit_cmd) + if vim.fn.mode() ~= "n" or vim.bo.filetype ~= "markdown" then + return false + end + local inner = get_wikilink_target() + if inner == nil then + return false + end + follow_wikilink(inner, edit_cmd) + return true +end) + +-- `nvim-help://<tag>` — open Neovim help for <tag> in a scratch, read-only +-- buffer. Registered with the follow engine (see 50-follow.lua). + +require("dotfiles.goto").register_scheme("nvim-help", { + resolve = function(uri) + local tagfiles = {} + for _, path in pairs(vim.opt.runtimepath:get()) do + tagfiles[#tagfiles + 1] = path .. "/doc/tags" + end + vim.opt_local.tags = tagfiles + local matches = vim.fn.taglist(uri) + if #matches == 0 then + return nil, "No help page found for nvim-help://" .. uri + end + return matches[1].filename + end, + after = function() + vim.opt_local.bufhidden = "wipe" + vim.opt_local.buftype = "nofile" + vim.opt_local.swapfile = false + vim.opt_local.readonly = true + end, +}) diff --git a/.config/nvim/plugin/50-notes.lua b/.config/nvim/plugin/50-notes.lua index 4dda9f4..af8e8de 100644 --- a/.config/nvim/plugin/50-notes.lua +++ b/.config/nvim/plugin/50-notes.lua @@ -369,75 +369,3 @@ vim.api.nvim_create_user_command("NotesRenameSection", function(opts) ) end end, { nargs = "*", desc = "Rename the heading at the cursor and update wiki-links" }) - ------------------------------------------------------------------------------------------------------------------------- --- Following notes (`notes://` scheme and `[[wiki-links]]`), wired into the follow engine ------------------------------------------------------------------------------------------------------------------------- - -local follow = require("dotfiles.follow") - --- `notes://<path>` resolves to `<path>` relative to the notes dir. -follow.register_scheme("notes", { - resolve = function(uri) - return notes_dir .. "/" .. uri - end, -}) - --- Returns the inner text of a `[[wiki-link]]` under the cursor, or `nil`. -local function get_wikilink_target() - local line = vim.api.nvim_get_current_line() - local col = vim.api.nvim_win_get_cursor(0)[2] + 1 - local init = 1 - while true do - local s, e, inner = line:find("%[%[(.-)%]%]", init) - if s == nil then - return nil - end - if col >= s and col <= e then - return inner - end - init = e + 1 - end -end - --- Follow a `[[note]]` / `[[note#Heading]]` / `[[dir/]]` wiki-link relative to the --- notes dir, creating parent directories (and the note itself on save) as needed. -local function follow_wikilink(inner, edit_cmd) - local name, heading = inner:match("^(.-)#(.*)$") - if name == nil then - name = inner - end - local target = notes_dir .. "/" .. name - if name:sub(-1) == "/" then -- directory link: create and open it - vim.fn.mkdir(target, "p") - vim.cmd(edit_cmd .. " " .. vim.fn.fnameescape(target)) - return - end - if not name:match("%.%w+$") then -- default to a Markdown note - target = target .. ".md" - end - vim.fn.mkdir(vim.fs.dirname(target), "p") - vim.cmd(edit_cmd .. " " .. vim.fn.fnameescape(target)) - if heading ~= nil and heading ~= "" then - vim.fn.cursor(1, 1) - -- `\V` matches the heading literally; `\v` brackets the heading markers. - local pat = [[\v^#+\s+\V]] .. vim.fn.escape(heading, [[\]]) .. [[\v\s*$]] - if vim.fn.search(pat, "cW") == 0 then - vim.notify("No heading '" .. heading .. "' in " .. name, vim.log.levels.WARN) - end - end -end - --- Wiki-links take precedence over generic URL/file following, but only on a --- `[[...]]` under the cursor in a markdown buffer in normal mode. -follow.register_handler(function(edit_cmd) - if vim.fn.mode() ~= "n" or vim.bo.filetype ~= "markdown" then - return false - end - local inner = get_wikilink_target() - if inner == nil then - return false - end - follow_wikilink(inner, edit_cmd) - return true -end) diff --git a/.config/nvim/plugin/50-nvim-help.lua b/.config/nvim/plugin/50-nvim-help.lua deleted file mode 100644 index 926bb68..0000000 --- a/.config/nvim/plugin/50-nvim-help.lua +++ /dev/null @@ -1,23 +0,0 @@ --- `nvim-help://<tag>` — open Neovim help for <tag> in a scratch, read-only --- buffer. Registered with the follow engine (see 50-follow.lua). - -require("dotfiles.follow").register_scheme("nvim-help", { - resolve = function(uri) - local tagfiles = {} - for _, path in pairs(vim.opt.runtimepath:get()) do - tagfiles[#tagfiles + 1] = path .. "/doc/tags" - end - vim.opt_local.tags = tagfiles - local matches = vim.fn.taglist(uri) - if #matches == 0 then - return nil, "No help page found for nvim-help://" .. uri - end - return matches[1].filename - end, - after = function() - vim.opt_local.bufhidden = "wipe" - vim.opt_local.buftype = "nofile" - vim.opt_local.swapfile = false - vim.opt_local.readonly = true - end, -}) |
