initial support for #36 : pickers can now show the number of links and

backlinks if opts.show_link_counts is set. Which it is for the 'link
search' following the tag selection.
This commit is contained in:
Rene Schallner
2021-12-13 07:38:51 +01:00
parent 0803d54f62
commit 89191a1c84
3 changed files with 468 additions and 40 deletions

135
lua/taglinks/linkutils.lua Normal file
View File

@@ -0,0 +1,135 @@
-- local async = require("plenary.async")
local scan = require("plenary.scandir")
local M = {}
local function file_exists(fn, file_list)
return file_list[fn] ~= nil
end
local function resolve_link(title, file_list, subdir_list, opts)
local fexists = false
local filename = title .. opts.extension
filename = filename:gsub("^%./", "") -- strip potential leading ./
if
opts.weeklies
and file_exists(opts.weeklies .. "/" .. filename, file_list)
then
filename = opts.weeklies .. "/" .. filename
fexists = true
end
if
opts.dailies and file_exists(opts.dailies .. "/" .. filename, file_list)
then
filename = opts.dailies .. "/" .. filename
fexists = true
end
if file_exists(opts.home .. "/" .. filename, file_list) then
filename = opts.home .. "/" .. filename
fexists = true
end
if fexists == false then
-- now search for it in all subdirs
local tempfn
for _, folder in pairs(subdir_list) do
tempfn = folder .. "/" .. filename
-- [[testnote]]
if file_exists(tempfn, file_list) then
filename = tempfn
fexists = true
-- print("Found: " .. filename)
break
end
end
end
if fexists == false then
-- default fn for creation
filename = opts.home .. "/" .. filename
end
return fexists, filename
end
-- TODO: cache mtimes and only update if changed
-- The reason we go over all notes in one go, is: backlinks
-- We generate 2 maps: one containing the number of links within a note
-- and a second one containing the number of backlinks to a note
-- Since we're parsing all notes anyway, we can mark linked notes as backlinked from the currently parsed note
M.generate_backlink_map = function(opts)
assert(opts ~= nil, "opts must not be nil")
-- TODO: check for code blocks
-- local in_fenced_code_block = false
-- also watch out for \t tabbed code blocks or ones with leading spaces that don't end up in a - or * list
-- first, find all notes
assert(opts.extension ~= nil, "Error: need extension in opts!")
assert(opts.home ~= nil, "Error: need home dir in opts!")
-- async seems to have lost await and we don't want to enter callback hell, hence we go sync here
local subdir_list = scan.scan_dir(opts.home, { only_dirs = true })
local file_list = {}
-- transform the file list
local _x = scan.scan_dir(opts.home, {
search_pattern = function(entry)
return entry:sub(-#opts.extension) == opts.extension
end,
})
for _, v in pairs(_x) do
file_list[v] = true
end
-- now process all the notes
local link_counts = {}
local backlink_counts = {}
for note_fn, _ in pairs(file_list) do
-- print("processing " .. note_fn .. "...")
-- go over file line by line
for line in io.lines(note_fn) do
for linktitle in line:gmatch("%[%[(.-)%]%]") do
-- strip # from title
linktitle = linktitle:gsub("#.*$", "")
-- now: inc our link count
link_counts[note_fn] = link_counts[note_fn] or 0
link_counts[note_fn] = link_counts[note_fn] + 1
-- and: inc the backlinks of the linked note
local fexists, backlinked_file = resolve_link(
linktitle,
file_list,
subdir_list,
opts
)
-- print(
-- "note for link `"
-- .. linktitle
-- .. "` = "
-- .. backlinked_file
-- .. " (exists: "
-- .. tostring(fexists)
-- .. ')'
-- )
if fexists and (note_fn ~= backlinked_file) then
backlink_counts[backlinked_file] = backlink_counts[backlinked_file]
or 0
backlink_counts[backlinked_file] = backlink_counts[backlinked_file]
+ 1
end
end
end
-- check if in comments block
-- find all links in the note and count them
-- add 1 (this note) as back-link to linked note
end
local ret = {
link_counts = link_counts,
backlink_counts = backlink_counts,
}
return ret
end
return M

View File

@@ -21,6 +21,7 @@ local function command_find_all_tags(opts)
return "rg", { "--vimgrep", "-o", re, "--", opts.cwd }
end
-- strips away leading ' or " , then trims whitespace
local function trim(s)
if s:sub(1, 1) == '"' or s:sub(1, 1) == "'" then
s = s:sub(2)