c4b4eb9
dotfiles.git > main > c4b4eb9 > files / ghostty
Dim wikilinks for pages that don't exist
Commit: c4b4eb9552d28b688f1d8b43c8fc85e5f5660fc9
Parent: ff90f9b
4 changed files:
nvim/after/queries/markdown_inline/highlights.scm view file
@@ -11,3 +11,15 @@ . "]" @markup.link.wiki.bracket (#set! @markup.link.wiki.bracket conceal ""))++; Dim links to notes that don't exist yet, like Obsidian does+(inline+ "[" @_bracket+ .+ (shortcut_link+ "["+ (link_text) @markup.link.wiki.missing+ "]")+ .+ "]" @_bracket+ (#not-wikilink-exists? @markup.link.wiki.missing))nvim/ftplugin/markdown.lua view file
@@ -5,6 +5,8 @@ ol.columns = 80 ol.showbreak = " " +--- Registers the predicate the wikilink highlights use+require("wikilink") vim.treesitter.start() local follow = function(fallback) return function() require("wikilink").follow(fallback) end endnvim/lua/colors.lua view file
@@ -161,6 +161,7 @@ hl(0, "@markup.link.label", {fg = blue, underline = true}) hl(0, "@markup.link.url", {link = "Gray"}) hl(0, "@markup.link.wiki", {fg = blue, underline = true})+hl(0, "@markup.link.wiki.missing", {fg = "#466b99", underline = true}) hl(0, "@markup.link.wiki.bracket", {link = "Punctuation"}) hl(0, "OilDir", {link = "Blue"})nvim/lua/wikilink.lua view file
@@ -21,8 +21,9 @@ end --- The vault is the nearest dir with .obsidian (or .git), falling back to the file's own dir-local function vault_root()- return vim.fs.root(0, {".obsidian", ".git"}) or fn.expand("%:p:h")+local function vault_root(buf)+ buf = buf or 0+ return vim.fs.root(buf, {".obsidian", ".git"}) or vim.fs.dirname(vim.api.nvim_buf_get_name(buf)) end --- Obsidian matches by note name anywhere in the vault, or by path if one is given@@ -74,13 +75,22 @@ local skipped_dirs = {[".git"] = true, [".obsidian"] = true, [".trash"] = true, node_modules = true} +--- Every file in the vault, relative to its root+local function vault_files(root)+ local found = {}+ for path, type in vim.fs.dir(root, {depth = math.huge, skip = function(dir)+ return not skipped_dirs[vim.fs.basename(dir)]+ end}) do+ if type == "file" then found[#found + 1] = path end+ end+ return found+end+ --- Every note in the vault as {name = "Note", path = "dir/Note"}, name is what Obsidian links by local function notes() local found = {}- for path, type in vim.fs.dir(vault_root(), {depth = math.huge, skip = function(dir)- return not skipped_dirs[vim.fs.basename(dir)]- end}) do- if type == "file" and path:match("%.md$") then+ for _, path in ipairs(vault_files(vault_root())) do+ if path:match("%.md$") then local rel = path:sub(1, -4) found[#found + 1] = {name = vim.fs.basename(rel), path = rel} end@@ -88,4 +98,49 @@ return found end +--- Linkable names and paths per vault, notes without their .md like links write them+local indexes = {}++local function vault_index(root)+ if indexes[root] then return indexes[root] end+ local index = {names = {}, paths = {}}+ for _, path in ipairs(vault_files(root)) do+ path = path:gsub("%.md$", "")+ index.names[vim.fs.basename(path)] = true+ index.paths[#index.paths + 1] = "/" .. path+ end+ indexes[root] = index+ return index+end++--- Whether following the link would land on a note that already exists+local function exists(name, buf)+ if name == "" then return true end+ name = name:gsub("%.md$", "")+ local index = vault_index(vault_root(buf))+ if not name:find("/") then return index.names[name] == true end++ local here = vim.fs.dirname(vim.api.nvim_buf_get_name(buf))+ if fn.filereadable(vim.fs.joinpath(here, name .. ".md")) == 1 then return true end+ for _, path in ipairs(index.paths) do+ if path:sub(-#name - 1) == "/" .. name then return true end+ end+ return false+end++--- Notes come and go, so rescan the next time a link gets highlighted+vim.api.nvim_create_autocmd({"BufEnter", "BufWritePost", "BufFilePost", "FocusGained"}, {+ group = vim.api.nvim_create_augroup("wikilink", {}),+ callback = function() indexes = {} end,+})++--- (#wikilink-exists? @capture) for highlighting links to missing notes differently+vim.treesitter.query.add_predicate("wikilink-exists?", function(match, _, source, pred)+ for _, node in ipairs(match[pred[2]] or {}) do+ local target = vim.treesitter.get_node_text(node, source):gsub("|.*", ""):gsub("#.*", "")+ if not exists(target, source) then return false end+ end+ return true+end, {force = true})+ return {follow = follow, notes = notes}