From 5228a3b49efffa7bf248c5735fc2c1ecdde018e6 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Fri, 30 Apr 2021 15:07:36 +0200 Subject: [PATCH] Refactor file listing and zettel picking --- README.md | 2 + lua/zettelkasten/list.lua | 42 ++++++++++++++++----- lua/zettelkasten/list_spec.lua | 67 +++++++++++++++++++--------------- 3 files changed, 72 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 38a8ef5..31eef6b 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ next up: * [ ] recognize duplicate anchors (in directory, when listing, etc) * [ ] provide option to rename and automatically change backlinks * [ ] zettel 'lens' (preview first headline + content of linked zettel through floating window etc, on keypress) +* [ ] support *both* md-style and wiki-style links at the same time +* [ ] file/directory exception list for gathering files, which will be ignored ## TODO: maintenance diff --git a/lua/zettelkasten/list.lua b/lua/zettelkasten/list.lua index d7d3aa0..c8c7ec6 100644 --- a/lua/zettelkasten/list.lua +++ b/lua/zettelkasten/list.lua @@ -1,4 +1,5 @@ local ls = {} +-- TODO rename to files.lua? since it's the only module interacting solely w/ the file system local o = require 'zettelkasten.options' @@ -7,19 +8,40 @@ local function isDirectory(ftype) return false end +local function isFile(ftype) + if ftype == 'file' then return true end + return false +end + local function cleanPath(path) if path:match("^~") then path = os.getenv("HOME") .. path:sub(2) end return path end +-- Returns a set of valid zettels in the form +-- { anchor = fullpathname }. +-- Takes a (flat) set of files to iterate over in the form that +-- get_all_files produces. -- TODO transform paths: -- * to ensure / at the end (or no /) gets taken into account -function ls.get_anchors_and_paths(path, recursive) +function ls.get_anchors_and_paths(fileset) -- TODO check for duplicates and warn user local zettel = {} local anchorreg = '^.*/?(' .. o.anchor().regex .. ')[^/]*%' .. o.zettel().extension .. '$' + for full_path, name in pairs(fileset) do + local anchor = string.match(name, anchorreg) + if anchor then zettel[tostring(anchor)] = full_path end + end + return zettel +end + +-- Returns a set of all files at the target directory, as well +-- as subdirectories if the recursive argument is set to true. +-- Set has the form { "full/path/name.md" = "name.md" } +function ls.get_all_files(path, recursive) + local f = {} path = cleanPath(path) local handle = vim.loop.fs_scandir(path) @@ -28,24 +50,26 @@ function ls.get_anchors_and_paths(path, recursive) if not name then break end if isDirectory(ftype) and recursive then - local subdir = ls.get_anchors_and_paths(path .. "/" .. name, true) - for k, v in pairs(subdir) do zettel[tostring(k)] = v end + local subdir = ls.get_all_files(path .. "/" .. name, true) + for k, v in pairs(subdir) do f[tostring(k)] = v end end - local anchor = string.match(name, anchorreg) - if anchor then zettel[tostring(anchor)] = path .. "/" .. name end + if isFile(ftype) then f[tostring(path .. "/" .. name)] = name end end - return zettel + + return f end -- Returns the path to the zettel defined by the anchor argument. -- Take a list of zettel as an optional variable, without which -- it will use the (recursive) results of the zettel_root directory. function ls.get_zettel(anchor, all) - all = all or ls.get_anchors_and_paths(o.zettel().rootdir, true) - if not all then return end + local zettels = all or + ls.get_anchors_and_paths( + ls.get_all_files(o.zettel().rootdir, true)) + if not zettels then return end - return all[anchor] + return zettels[anchor] end return ls diff --git a/lua/zettelkasten/list_spec.lua b/lua/zettelkasten/list_spec.lua index 6289d28..a132d77 100644 --- a/lua/zettelkasten/list_spec.lua +++ b/lua/zettelkasten/list_spec.lua @@ -24,20 +24,24 @@ describe("get_anchors_and_paths", function() it("should return anchor-keyed table pointing to filename of zettel", function() - local file_list = {"1910291645 this-is-a-testfile.md"} + local file_list = {} + file_list["someDir/1910291645 this-is-a-testfile.md"] = + "1910291645 this-is-a-testfile.md" _G.vim = get_api_mock(file_list) local expected = { ["1910291645"] = "someDir/1910291645 this-is-a-testfile.md" } - assert.same(expected, ls.get_anchors_and_paths("someDir")) + assert.same(expected, ls.get_anchors_and_paths(file_list)) end) it("should ignore any malformed files", function() local file_list = { - "2010261208 this-should-be-picked-up.md", - "1910291645 this-is-a-testfile.md", "this-is-not-a-testfile.md", - "1910271456 this-is-wrong-extension.txt", "1812 this-is-ignored.md" + ["someDir/2010261208 this-should-be-picked-up.md"] = "2010261208 this-should-be-picked-up.md", + ["someDir/1910291645 this-is-a-testfile.md"] = "1910291645 this-is-a-testfile.md", + ["someDir/this-is-not-a-testfile.md"] = "this-is-not-a-testfile.md", + ["1910271456 this-is-wrong-extension.txt"] = "1910271456 this-is-wrong-extension.txt", + ["1812 this-is-ignored.md"] = "1812 this-is-ignored.md" } _G.vim = get_api_mock(file_list) @@ -45,9 +49,28 @@ describe("get_anchors_and_paths", function() ["1910291645"] = "someDir/1910291645 this-is-a-testfile.md", ["2010261208"] = "someDir/2010261208 this-should-be-picked-up.md" } - assert.same(expected, ls.get_anchors_and_paths("someDir")) + assert.same(expected, ls.get_anchors_and_paths(file_list)) end) + it("should adhere to the zettel extension defined in options", function() + local file_list = { + ["mydirectory/1910291645 myfile.wiki"] = "1910291645 myfile.wiki", + ["mydirectory/2345678901 another.wiki"] = "2345678901 another.wiki" + } + _G.vim = get_api_mock(file_list) + vim.g['zettel_extension'] = '.wiki' + + local expected = { + ["1910291645"] = "mydirectory/1910291645 myfile.wiki", + ["2345678901"] = "mydirectory/2345678901 another.wiki" + } + + assert.same(expected, ls.get_anchors_and_paths(file_list, false, vim.g)) + + end) +end) + +describe("get_all_files", function() it("should recurse into directories if recursive argument passed in ", function() local files = { @@ -75,15 +98,14 @@ describe("get_anchors_and_paths", function() } _G.vim = vim_api_mock - ls.get_anchors_and_paths("path/to/startingdir", true) + ls.get_all_files("path/to/startingdir", true) assert.spy(vim_api_mock.loop.fs_scandir).was_called(2) assert.spy(vim_api_mock.loop.fs_scandir).was_called_with( "path/to/startingdir/more-notes-here") end) - it("should append all notes found in subdirectories when recursing", - function() + it("should add all files found in subdirectories when recursing", function() local outer_files = { "subdir", "1234567890 myfile.md", "2345678901 another.md" } @@ -114,27 +136,12 @@ describe("get_anchors_and_paths", function() } _G.vim = vim_api_mock local expected = { - ["1234567890"] = "mydirectory/1234567890 myfile.md", - ["2345678901"] = "mydirectory/2345678901 another.md", - ["2222222222"] = "mydirectory/subdir/2222222222 should-be-present.md", - ["3333333333"] = "mydirectory/subdir/3333333333 should-also-be-present.md" + ["mydirectory/1234567890 myfile.md"] = "1234567890 myfile.md", + ["mydirectory/2345678901 another.md"] = "2345678901 another.md", + ["mydirectory/subdir/2222222222 should-be-present.md"] = "2222222222 should-be-present.md", + ["mydirectory/subdir/3333333333 should-also-be-present.md"] = "3333333333 should-also-be-present.md" } - assert.same(expected, ls.get_anchors_and_paths('mydirectory', true)) - end) - - it("should adhere to the zettel extension defined in options", function() - local file_list = {"1910291645 myfile.wiki", "2345678901 another.wiki"} - _G.vim = get_api_mock(file_list) - vim.g['zettel_extension'] = '.wiki' - - local expected = { - ["1910291645"] = "mydirectory/1910291645 myfile.wiki", - ["2345678901"] = "mydirectory/2345678901 another.wiki" - } - - assert.same(expected, - ls.get_anchors_and_paths('mydirectory', false, vim.g)) - + assert.same(expected, ls.get_all_files('mydirectory', true)) end) end) @@ -154,7 +161,7 @@ describe("get_zettel", function() assert.is_not_error(function() ls.get_zettel("myanchor") end) end) it("should default to the zettel root dir if no list passed in", function() - local fc = stub(ls, "get_anchors_and_paths") + local fc = stub(ls, "get_all_files") local expected = require'zettelkasten.options'.zettel().rootdir ls.get_zettel(expected)