-- -- 50-goto.lua -- local follow = require("dotfiles.goto") -- Add `'` to the list of characters included in `` because `'` is a valid URI character vim.opt.isfname:append("'") vim.keymap.set({ "n", "x" }, "gg", function() follow.follow("edit") end, { desc = "Edit URL/file in current window" }) vim.keymap.set({ "n", "x" }, "gs", function() follow.follow("split") end, { desc = "Edit URL/file in split window" }) vim.keymap.set({ "n", "x" }, "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://` resolves to `` 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://` — open Neovim help for 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, })