From 45eac53ecb9c19077df8e0d2bdd8beac56bc83b9 Mon Sep 17 00:00:00 2001 From: Rene Schallner Date: Thu, 9 Dec 2021 05:40:53 +0100 Subject: [PATCH] We can now follow tags --- .luacheckrc | 1 - data/plenary/filetypes/telekasten.lua | 4 +- lua/taglinks/taglinks.lua | 196 ++++++++++++++++++++++++++ lua/telekasten.lua | 83 ++++++++--- 4 files changed, 258 insertions(+), 26 deletions(-) create mode 100644 lua/taglinks/taglinks.lua diff --git a/.luacheckrc b/.luacheckrc index 426fb6c..b035079 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -14,7 +14,6 @@ ignore = { globals = { "_", - "vim", "TelescopeGlobalState", "_TelescopeConfigurationValues", "_TelescopeConfigurationPickers", diff --git a/data/plenary/filetypes/telekasten.lua b/data/plenary/filetypes/telekasten.lua index 81faeb4..ee38fee 100644 --- a/data/plenary/filetypes/telekasten.lua +++ b/data/plenary/filetypes/telekasten.lua @@ -1,5 +1,5 @@ return { extension = { - ['md'] = 'telekasten' - } + ["md"] = "telekasten", + }, } diff --git a/lua/taglinks/taglinks.lua b/lua/taglinks/taglinks.lua new file mode 100644 index 0000000..abea668 --- /dev/null +++ b/lua/taglinks/taglinks.lua @@ -0,0 +1,196 @@ +local M = {} + +M.is_tag_or_link_at = function(line, col, opts) + opts = opts or {} + local initial_col = col + + local char + local is_tagline = opts.tag_notation == "yaml-bare" + and line:sub(1, 4) == "tags" + + local seen_bracket = false + while col >= 1 do + char = line:sub(col, col) + + if seen_bracket then + if char == "[" then + return "link", col + 2 + end + end + + if char == "[" then + seen_bracket = true + end + + if is_tagline == true then + if char == " " or char == "\t" or char == "," or char == ":" then + if col ~= initial_col then + return "tag", col + 1 + end + end + else + if char == "#" and opts.tag_notation == "#tag" then + return "tag", col + end + + if char == ":" and opts.tag_notation == ":tag:" then + return "tag", col + end + end + + if char == " " or char == "\t" then + return nil, nil + end + col = col - 1 + end + return nil, nil +end + +M.get_tag_at = function(line, col, opts) + -- we ignore the rule: no tags begin with a numeric digit + local endcol = col + 1 + local pattern = "[%w-_/]" + local char + while endcol <= #line do + char = line:sub(endcol, endcol) + if char:match(pattern) == nil then + if opts.tag_notation == ":tag:" then + if char == ":" then + local tag = line:sub(col, endcol) + return tag + end + else + return line:sub(col, endcol - 1) + end + end + endcol = endcol + 1 + end + -- we exhausted the line + return line:sub(col, endcol) +end + +------------- +-- testing -- +------------- + +local function _eval(line, col, opts) + local kind, newcol = M.is_tag_or_link_at(line, col, opts) + return { kind = kind, col = newcol, line = line } +end + +local function _print_debug(x, prefix) + prefix = prefix or "" + for k, v in pairs(x) do + print(prefix .. k .. ": " .. tostring(v)) + end +end + +local function _expect(x, y) + for k, v in pairs(y) do + if x[k] ~= v then + print("expected:") + _print_debug(y, " ") + print("got:") + _print_debug(x, " ") + assert(false) + end + end +end + +M._testme = function() + local line = "" + local col = 10 + local opts = {} + local tag + local ret + assert(_eval(line, col, opts).kind == nil) + + -- #tags + opts.tag_notation = "#tag" + + line = "this is a #tag in a line" + + -- lets find it + col = 13 + _expect(_eval(line, col, opts), { col = 11, kind = "tag" }) + ret = _eval(line, col, opts) + tag = M.get_tag_at(line, ret.col, opts) + -- print('tag .. `' .. tag .. '`') + assert(tag == "#tag") + + -- lets be in the space after + col = 15 + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + -- lets be in the next word + col = 16 + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + -- lets be in the prev word + col = 9 + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + -- lets change the tag notation but hit the tag col + col = 13 + opts.tag_notation = ":tag:" + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + -- :tags: + opts.tag_notation = ":tag:" + + line = "this is a :tag: in a line" + + -- lets find it + col = 13 + _expect(_eval(line, col, opts), { col = 11, kind = "tag" }) + ret = _eval(line, col, opts) + tag = M.get_tag_at(line, ret.col, opts) + assert(tag == ":tag:") + + -- lets be in the space after + col = 16 + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + -- lets be in the next word + col = 17 + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + -- lets be in the prev word + col = 9 + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + -- lets change the tag notation but hit the tag col + col = 13 + opts.tag_notation = "#tag" + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + -- tagline + line = "tags: [ first, second, third]" + opts.tag_notation = "yaml-bare" + + col = 13 + _expect(_eval(line, col, opts), { col = 9, kind = "tag" }) + ret = _eval(line, col, opts) + tag = M.get_tag_at(line, ret.col, opts) + assert(tag == "first") + + col = 9 + _expect(_eval(line, col, opts), { col = 9, kind = "tag" }) + + col = 14 + _expect(_eval(line, col, opts), { col = nil, kind = nil }) + + col = 18 + _expect(_eval(line, col, opts), { col = 16, kind = "tag" }) + + -- + line = "this is a [[link]] line" + col = 13 + _expect(_eval(line, col, opts), { col = 13, kind = "link" }) + + line = "this is a [[link]] line" + col = 15 + _expect(_eval(line, col, opts), { col = 13, kind = "link" }) +end + +return M diff --git a/lua/telekasten.lua b/lua/telekasten.lua index e309d14..cd18ab0 100644 --- a/lua/telekasten.lua +++ b/lua/telekasten.lua @@ -10,6 +10,7 @@ local previewers = require("telescope.previewers") local make_entry = require("telescope.make_entry") local debug_utils = require("plenary.debug_utils") local filetype = require("plenary.filetype") +local taglinks = require("taglinks/taglinks") -- declare locals for the nvim api stuff to avoid more lsp warnings local vim = vim @@ -61,7 +62,11 @@ M.Cfg = { }, close_after_yanking = false, insert_after_inserting = true, + install_syntax = true, + + -- tag notation: '#tag', ':tag:', 'yaml-bare' + tag_notation = "#tag", } local function file_exists(fname) @@ -659,6 +664,13 @@ local function resolve_link(title) return fexists, filename end +-- local function check_for_link_or_tag() +local function check_for_link_or_tag() + local line = vim.api.nvim_get_current_line() + local col = vim.fn.col(".") + return taglinks.is_tag_or_link_at(line, col, M.Cfg) +end + -- -- FollowLink: -- ----------- @@ -672,33 +684,47 @@ local function FollowLink(opts) opts.close_after_yanking = opts.close_after_yanking or M.Cfg.close_after_yanking - vim.cmd("normal yi]") - local title = vim.fn.getreg('"0') - title = title:gsub("^(%[)(.+)(%])$", "%2") local search_mode = "files" - - local parts = vim.split(title, "#") + local title local filename = "" - - -- if there is a # - if #parts ~= 1 then - search_mode = "heading" - title = parts[2] - filename = parts[1] - parts = vim.split(title, "%^") - if #parts ~= 1 then - search_mode = "para" - title = parts[2] - end - end - local fexists - if #filename > 0 then - fexists, filename = resolve_link(filename) - if fexists == false then - -- print("error") - filename = "" + -- first: check if we're in a tag or a link + local kind, atcol = check_for_link_or_tag() + + if kind == "tag" then + local tag = taglinks.get_tag_at( + vim.api.nvim_get_current_line(), + atcol, + M.Cfg + ) + search_mode = "tag" + title = tag + else + -- we are in a link + vim.cmd("normal yi]") + title = vim.fn.getreg('"0') + title = title:gsub("^(%[)(.+)(%])$", "%2") + + local parts = vim.split(title, "#") + + -- if there is a # + if #parts ~= 1 then + search_mode = "heading" + title = parts[2] + filename = parts[1] + parts = vim.split(title, "%^") + if #parts ~= 1 then + search_mode = "para" + title = parts[2] + end + end + if #filename > 0 then + fexists, filename = resolve_link(filename) + if fexists == false then + -- print("error") + filename = "" + end end end @@ -766,6 +792,16 @@ local function FollowLink(opts) } end + if search_mode == "tag" then + search_command = { + "rg", + "--vimgrep", + "-e", + prompt, + "--", + } + end + if #filename > 0 then table.insert(search_command, filename) else @@ -1521,5 +1557,6 @@ M.find_friends = FindFriends M.insert_img_link = InsertImgLink M.preview_img = PreviewImg M.browse_media = BrowseImg +M.taglinks = taglinks return M