epwalsh / obsidian.nvim

Obsidian 🤝 Neovim
Apache License 2.0
4.18k stars 188 forks source link

Create note with search term as title if no match #45

Closed mikepqr closed 10 months ago

mikepqr commented 2 years ago

🚀 The feature, motivation and pitch

It would be great if the fuzzy finder launched by :ObsidianSearch could be a unified UI to search and create notes, such that, if there is no match for the search term in the picker when the user hits enter, obsidian.nvim invokes :ObsidianNew with the search string as the argument.

This reduces cognitive overhead when creating a note, and is how the "Open Quickly" UI in Obsidian itself works.

I'm not sure if this is possible with fzf or telescope, however!

Alternatives

You could take this further and allow the user to invoke :ObsidianNew from the picker even if there are matches, e.g. if the user selects the match with something other than enter, or the search term ends in !, then create a new note.

Additional context

This is also how Corpus works (the :Corpus command provides a unified way to search and create).

epwalsh commented 2 years ago

This would be great to have. At the moment implementing this is over my head but I'll keep it mind as a larger goal to work towards.

mikepqr commented 2 years ago

For reference for anyone looking into implementing this (including maybe me!), fzf can echo the search term if there is no match with this invocation (ref):

fzf --bind=enter:replace-query+print-query
gplusplus314 commented 1 year ago

Let's talk about the desired UX before writing code. 😉

I think the idea of an explicit keybind within the fuzzy finder chooser is the way to go. I like this because it eliminates a lot of edge cases with the fuzzy matching by avoiding complex logic around partial matches. Creating a new note, rather than matching and selecting an existing note, would be totally deterministic this way.

As a practical example, the Telescope Project plugin binds <C-a> to "add cwd as a project" and it ignores your search query. In our case, we would instead use the search query as a parameter to make a new note.

But a tradeoff would be inconsistent behavior with the official Obsidian app. This is a bit weird because the user could have different fuzzy finders configured, so even if we matched the "Open Quickly" workflow, the actual search results may be different between NeoVim and Obsidian. I think this should be configurable so that the user can decide on the tradeoff in their workflow.

What are your thoughts here, @mikepqr and @epwalsh ?

mikepqr commented 1 year ago

I don't have a strong opinion on exactly how the user would indicate a particular "search" is actually a request for a new file with that name.

Telescope's <C-a> sounds good, modulo the fact that is a standard readline binding, which many users expect to work (it works in fzf, and works in vim command mode with cnoremap <C-A> <Home>). How does Telescope handle that?

Corpus doesn't clobber a readline binding, but ends up with a system that has several options that are a bit of a mouthful to explain, and presumably has more edge cases in its implementation (tldr: :Corpus! or append .md to the search, but see the docs for details).

One other data point is Notational Velocity. AFAIK, this is where the idea of unified search/create in a notes app comes from. In nvALT your input is presumed to be the title of a new note, even if it matches search results. If you hit enter, you get a new note. But the search results are shown, and you can use C-J or C-K to page into them and then select them. I'm not sure if fzf (or telescope) could be used to reproduce this UX, and given "search for existing" is probably a more common task than "create new", I think I prefer the approaches above, which select search results by default.

I would not try to emulate the keyboard interface (or wider UX) of the Obsidian app. The goals/expectations there are very different.

metalelf0 commented 1 year ago

@mikepqr how about the :ObsidianQuickSwitch command? Shouldn't such binding belong to this command, rather than to :ObsidianSearch? The first one is actually searching note names, so maybe it should be its responsibility to eventually create notes.

sotte commented 10 months ago

For my note taking system I have a command OrgNote which

This is implemented using custom telescope actions. Not too complex.

But obsidian.nvim would require implementations for the different fuzzy finders if I'm not mistaken.

image

sotte commented 10 months ago

Just as reference, my implementation looks something like this.

function Orgnote.search_or_link_or_create()
  -- FIXME: prep_link_selected_entry is messy; refactor this.
  local link_info_tb = prep_link_selected_entry()

  require("telescope.builtin").find_files({
    prompt_title = "ORGNOTE | CR open | C-x create | C-l link",
    default_text = link_info_tb.selection or "",
    cwd = root,
    search_file = "*.org",
    attach_mappings = function(_, map)
      map("i", "<C-x>", create_note_from_query)
      map("i", "<C-l>", function(prompt_bufnr)
        link_selected_entry(prompt_bufnr, link_info_tb)
      end)
      return true
    end,
  })
end
epwalsh commented 10 months ago

@sotte even if we can't implement that for other finders it would be great to have for our telescope integration. In general I recommend people use telescope as it has the best Lua API, so it's the easiest for us to work with. Are you interested in making a PR with that?

sotte commented 10 months ago

I actually wanted to say that I don't have the time. But then I looked at the code and drafted an implementation.

Here is the MR: https://github.com/epwalsh/obsidian.nvim/pull/296

There are still some things to address (see MR).

If somebody else wants to bring this over the finish line I'm more than happy to hand this over.

sotte commented 10 months ago

I think with #296 merged, we can close this issue.