From a9e7fdecf092b06d9058917cfe36c30886e52ece Mon Sep 17 00:00:00 2001 From: Pete Date: Fri, 9 Feb 2024 12:35:42 -0800 Subject: [PATCH] Fix bugs with new note creation (#384) --- CHANGELOG.md | 4 ++ lua/cmp_obsidian_new.lua | 23 +------ lua/obsidian/client.lua | 94 ++++++++++++++++++++------- lua/obsidian/commands/follow_link.lua | 12 +++- test/obsidian/client_spec.lua | 10 ++- 5 files changed, 95 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21acb6867..6e918cfe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed configuration option `detect_cwd`. This wasn't well-defined before and is no longer relevant with the new workspace detection behavior. See [PR #366](https://github.com/epwalsh/obsidian.nvim/pull/366). +### Fixed + +- Fixed two bugs with creating new notes through `:ObsidianFollowLink` (and `gf`) where it wouldn't respect the `completion.new_notes_location` settings, and wouldn't respect paths in certain formats. + ## [v2.10.0](https://github.com/epwalsh/obsidian.nvim/releases/tag/v2.10.0) - 2024-02-05 ### Added diff --git a/lua/cmp_obsidian_new.lua b/lua/cmp_obsidian_new.lua index b60f7c9be..26d8a3d40 100644 --- a/lua/cmp_obsidian_new.lua +++ b/lua/cmp_obsidian_new.lua @@ -1,8 +1,6 @@ local abc = require "obsidian.abc" local completion = require "obsidian.completion.refs" local obsidian = require "obsidian" -local log = require "obsidian.log" -local NewNotesLocation = require("obsidian.config").CompletionNewNotesLocation local LinkStyle = require("obsidian.config").LinkStyle ---@class cmp_obsidian_new.Source : obsidian.ABC @@ -20,26 +18,10 @@ source.complete = function(_, request, callback) local client = assert(obsidian.get_client()) local can_complete, search, insert_start, insert_end, ref_type = completion.can_complete(request) - ---@type string|Path|? - local dir - if client.opts.completion.new_notes_location == nil then - dir = nil -- let the client decide - elseif client.opts.completion.new_notes_location == NewNotesLocation.notes_subdir then - dir = client.dir - if client.opts.notes_subdir ~= nil then - dir = dir / client.opts.notes_subdir - end - elseif client.opts.completion.new_notes_location == NewNotesLocation.current_dir then - dir = vim.fn.expand "%:p:h" - else - log.err "Bad option value for 'completion.new_notes_location'. Skipping creating new note." - return - end - if can_complete and search ~= nil and #search >= client.opts.completion.min_chars then local new_title, new_id, path new_id = client:new_note_id(search) - new_title, new_id, path = client:parse_title_id_path(search, new_id, dir) + new_title, new_id, path = client:parse_title_id_path(search, new_id) if not new_title or string.len(new_title) == 0 then return @@ -81,7 +63,6 @@ source.complete = function(_, request, callback) data = { id = new_id, title = search, - dir = dir, }, }, } @@ -98,7 +79,7 @@ end source.execute = function(_, item, callback) local client = assert(obsidian.get_client()) local data = item.data - client:new_note(data.title, data.id, data.dir) + client:new_note(data.title, data.id) return callback {} end diff --git a/lua/obsidian/client.lua b/lua/obsidian/client.lua index 424266db3..64f55850b 100644 --- a/lua/obsidian/client.lua +++ b/lua/obsidian/client.lua @@ -931,48 +931,94 @@ end --- ---@return string|?,string,Path Client.parse_title_id_path = function(self, title, id, dir) - ---@type Path - local base_dir = dir == nil and self.dir or Path:new(dir) - local title_is_path = false + if title then + title = util.strip_whitespace(title) + if title == "" then + title = nil + end + end + + if id then + id = util.strip_whitespace(id) + if id == "" then + id = nil + end + end - -- Clean up title and guess the right base_dir. - if title ~= nil then - -- Trim whitespace. - title = title:match "^%s*(.-)%s*$" + ---@param s string + ---@param strict_paths_only boolean + ---@return string|?, boolean, string|? + local parse_as_path = function(s, strict_paths_only) + local is_path = false + ---@type string|? + local parent - if title:match "%.md" then + if s:match "%.md" then -- Remove suffix. - title = title:sub(1, title:len() - 3) - title_is_path = true + s = s:sub(1, s:len() - 3) + is_path = true end -- Pull out any parent dirs from title. - local parts = vim.split(title, Path.path.sep) + local parts = vim.split(s, Path.path.sep) if #parts > 1 then - -- 'title' will just be the final part of the path. - title = parts[#parts] - -- Add the other parts to the base_dir. - base_dir = base_dir / table.concat(parts, Path.path.sep, 1, #parts - 1) - elseif dir == nil and self.opts.notes_subdir ~= nil then - base_dir = base_dir / self.opts.notes_subdir + s = parts[#parts] + if not strict_paths_only then + is_path = true + end + parent = table.concat(parts, Path.path.sep, 1, #parts - 1) + end + + if s == "" then + return nil, is_path, parent + else + return s, is_path, parent end - elseif dir == nil and self.opts.notes_subdir ~= nil then - base_dir = base_dir / self.opts.notes_subdir end - if title == "" then - title = nil + local parent, _, title_is_path + if id then + id, _, parent = parse_as_path(id, false) + elseif title then + title, title_is_path, parent = parse_as_path(title, true) + if title_is_path then + id = title + end + end + + ---@type Path + local base_dir + if parent then + base_dir = self.dir / parent + else + local new_notes_location = self.opts.completion.new_notes_location + if not dir and new_notes_location then + if new_notes_location == config.CompletionNewNotesLocation.notes_subdir then + base_dir = self.dir + if self.opts.notes_subdir then + base_dir = base_dir / self.opts.notes_subdir + end + elseif new_notes_location == config.CompletionNewNotesLocation.current_dir then + base_dir = self.buf_dir and self.buf_dir or Path:new(vim.fs.dirname(vim.api.nvim_buf_get_name(0))) + else + error "Bad option value for 'completion.new_notes_location'. Skipping creating new note." + end + else + base_dir = Path:new(dir) + end end -- Generate new ID if needed. - local new_id = id and id or (title_is_path and title or self:new_note_id(title)) + if not id then + id = self:new_note_id(title) + end -- Get path. ---@type Path ---@diagnostic disable-next-line: assign-type-mismatch - local path = base_dir / (new_id .. ".md") + local path = base_dir / (id .. ".md") - return title, new_id, path + return title, id, path end --- Create and save a new note. diff --git a/lua/obsidian/commands/follow_link.lua b/lua/obsidian/commands/follow_link.lua index d4abc7672..7b5bb1e5c 100644 --- a/lua/obsidian/commands/follow_link.lua +++ b/lua/obsidian/commands/follow_link.lua @@ -48,8 +48,16 @@ return function(client, data) }) if confirmation == "" or confirmation == "y" or confirmation == "yes" then -- Create a new note. - local aliases = name == location and {} or { name } - note = client:new_note(location, nil, client.buf_dir, aliases) + ---@type string|?, string[] + local id, aliases + if name == location then + aliases = {} + else + aliases = { name } + id = location + end + + note = client:new_note(name, id, nil, aliases) vim.api.nvim_command(open_cmd .. tostring(note.path)) else log.warn "Aborting" diff --git a/test/obsidian/client_spec.lua b/test/obsidian/client_spec.lua index 79bce9492..3075bc670 100644 --- a/test/obsidian/client_spec.lua +++ b/test/obsidian/client_spec.lua @@ -56,7 +56,7 @@ describe("Client", function() assert.is_false(saved_note.has_frontmatter) end) - it("should parse a title that's a partial path", function() + it("should parse a title that's a partial path and generate new ID", function() local client = tmp_client() local title, id, path = client:parse_title_id_path "notes/Foo" assert.equals(title, "Foo") @@ -64,6 +64,14 @@ describe("Client", function() assert.equals(tostring(path), tostring(Path:new(client.dir) / "notes" / "foo.md")) end) + it("should parse an ID that's a path", function() + local client = tmp_client() + local title, id, path = client:parse_title_id_path("Foo", "notes/1234-foo") + assert.equals(title, "Foo") + assert.equals(id, "1234-foo") + assert.equals(tostring(path), tostring(Path:new(client.dir) / "notes" / "1234-foo.md")) + end) + it("should parse a title that's an exact path", function() local client = tmp_client() local title, id, path = client:parse_title_id_path "notes/foo.md"