Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add finder option for choosing a preferred finder backend (#129) #130

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Removed annoying "skipped updating frontmatter" message on file write.

### Added

- Added `finder` option for choosing a preferred finder backend.

## [v1.9.0](https://github.com/epwalsh/obsidian.nvim/releases/tag/v1.9.0) - 2023-04-22

### Added
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ return {

-- Optional, set to true to force ':ObsidianOpen' to bring the app to the foreground.
open_app_foreground = false,

-- Optional, by default commands like `:ObsidianSearch` will attempt -
-- in that order - telescope.nvim, fzf-lua, and fzf.nvim, and use the
-- first one they find. By setting this option to your preferred
-- finder, you can attempt it first. Note that if the specified finder
-- is not installed, or if it the command does not support it, the
-- remaining finders will be attempted in the original order.
finder = "fzf-lua",
},
config = function(_, opts)
require("obsidian").setup(opts)
Expand Down
280 changes: 150 additions & 130 deletions lua/obsidian/command.lua
Original file line number Diff line number Diff line change
Expand Up @@ -192,50 +192,60 @@ end
command.search = function(client, data)
local base_cmd = vim.tbl_flatten { util.SEARCH_CMD, { "--smart-case", "--column", "--line-number", "--no-heading" } }

local has_telescope, telescope = pcall(require, "telescope.builtin")
client:_run_with_finder_backend(":ObsidianSearch", {
["telescope.nvim"] = function()
local has_telescope, telescope = pcall(require, "telescope.builtin")

if has_telescope then
-- Search with telescope.nvim
local vimgrep_arguments = vim.tbl_flatten { base_cmd, {
"--with-filename",
"--color=never",
} }

if data.args:len() > 0 then
telescope.grep_string { cwd = tostring(client.dir), search = data.args, vimgrep_arguments = vimgrep_arguments }
else
telescope.live_grep { cwd = tostring(client.dir), vimgrep_arguments = vimgrep_arguments }
end
return
end

local has_fzf_lua, fzf_lua = pcall(require, "fzf-lua")

if has_fzf_lua then
if data.args:len() > 0 then
fzf_lua.grep { cwd = tostring(client.dir), search = data.args }
else
fzf_lua.live_grep { cwd = tostring(client.dir), exec_empty_query = true }
end
return
end

-- Fall back to trying with fzf.vim
local has_fzf, _ = pcall(function()
local grep_cmd =
vim.tbl_flatten { base_cmd, { "--color=always", "--", vim.fn.shellescape(data.args), tostring(client.dir) } }

vim.api.nvim_call_function("fzf#vim#grep", {
table.concat(grep_cmd, " "),
true,
vim.api.nvim_call_function("fzf#vim#with_preview", {}),
false,
})
end)
if not has_telescope then
util.implementation_unavailable()
end
-- Search with telescope.nvim
local vimgrep_arguments =
vim.tbl_flatten { base_cmd, {
"--with-filename",
"--color=never",
} }

if data.args:len() > 0 then
telescope.grep_string {
cwd = tostring(client.dir),
search = data.args,
vimgrep_arguments = vimgrep_arguments,
}
else
telescope.live_grep { cwd = tostring(client.dir), vimgrep_arguments = vimgrep_arguments }
end
end,
["fzf-lua"] = function()
local has_fzf_lua, fzf_lua = pcall(require, "fzf-lua")

if not has_fzf then
echo.err "Either telescope.nvim, fzf-lua or fzf.vim is required for :ObsidianSearch command"
end
if not has_fzf_lua then
util.implementation_unavailable()
end
if data.args:len() > 0 then
fzf_lua.grep { cwd = tostring(client.dir), search = data.args }
else
fzf_lua.live_grep { cwd = tostring(client.dir), exec_empty_query = true }
end
end,
["fzf.vim"] = function()
-- Fall back to trying with fzf.vim
local has_fzf, _ = pcall(function()
local grep_cmd =
vim.tbl_flatten { base_cmd, { "--color=always", "--", vim.fn.shellescape(data.args), tostring(client.dir) } }

vim.api.nvim_call_function("fzf#vim#grep", {
table.concat(grep_cmd, " "),
true,
vim.api.nvim_call_function("fzf#vim#with_preview", {}),
false,
})
end)
if not has_fzf then
util.implementation_unavailable()
end
end,
})
end

--- Insert a template
Expand Down Expand Up @@ -287,70 +297,74 @@ command.insert_template = function(client, data)
vim.api.nvim_win_set_cursor(0, { new_row, 0 })
end

-- try with telescope.nvim
local has_telescope, _ = pcall(require, "telescope.builtin")
if has_telescope then
local choose_template = function()
local opts = {
client:_run_with_finder_backend(":ObsidianTemplate", {
["telescope.nvim"] = function()
-- try with telescope.nvim
local has_telescope, _ = pcall(require, "telescope.builtin")
if not has_telescope then
util.implementation_unavailable()
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should explicitly return false if has_telescope is false, and same for the others below. Just for clarity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I also verify in run_first_supported that the returned value is boolean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to throw a magic value from skipped implementations. That way run_first_supported can return the value of the implementation that succeeded.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to throw a magic value from skipped implementations. That way run_first_supported can return the value of the implementation that succeeded.

I like that idea 👍

local choose_template = function()
local opts = {
cwd = tostring(templates_dir),
attach_mappings = function(_, map)
map({ "i", "n" }, "<CR>", function(prompt_bufnr)
local template = require("telescope.actions.state").get_selected_entry()
require("telescope.actions").close(prompt_bufnr)
apply_template(template[1])
end)
end,
}
require("telescope.builtin").find_files(opts)
end
choose_template()
end,
["fzf-lua"] = function()
-- try with fzf-lua
local has_fzf_lua, fzf_lua = pcall(require, "fzf-lua")
if not has_fzf_lua then
util.implementation_unavailable()
end
local cmd = vim.tbl_flatten { util.FIND_CMD, { ".", "-name", "'*.md'" } }
cmd = util.table_params_to_str(cmd)
fzf_lua.files {
cmd = cmd,
cwd = tostring(templates_dir),
attach_mappings = function(_, map)
map({ "i", "n" }, "<CR>", function(prompt_bufnr)
local template = require("telescope.actions.state").get_selected_entry()
require("telescope.actions").close(prompt_bufnr)
apply_template(template[1])
end)
return true
end,
file_icons = false,
actions = {
["default"] = function(entry)
-- for some reason fzf-lua passes the filename with 6 characters
-- at the start that appear on screen as 2 whitespace characters
-- so we need to start on the 7th character
local template = entry[1]:sub(7)
apply_template(template)
end,
},
}
require("telescope.builtin").find_files(opts)
end
choose_template()
return
end

-- try with fzf-lua
local has_fzf_lua, fzf_lua = pcall(require, "fzf-lua")
if has_fzf_lua then
local cmd = vim.tbl_flatten { util.FIND_CMD, { ".", "-name", "'*.md'" } }
cmd = util.table_params_to_str(cmd)
fzf_lua.files {
cmd = cmd,
cwd = tostring(templates_dir),
file_icons = false,
actions = {
["default"] = function(entry)
-- for some reason fzf-lua passes the filename with 6 characters
-- at the start that appear on screen as 2 whitespace characters
-- so we need to start on the 7th character
local template = entry[1]:sub(7)
end,
["fzf.vim"] = function()
-- try with fzf
local has_fzf, _ = pcall(function()
vim.api.nvim_create_user_command("ApplyTemplate", function(path)
-- remove escaped whitespace and extract the file name
local file_path = string.gsub(path.args, "\\ ", " ")
local template = vim.fs.basename(file_path)
apply_template(template)
end,
},
}
return
end

-- try with fzf
local has_fzf, _ = pcall(function()
vim.api.nvim_create_user_command("ApplyTemplate", function(path)
-- remove escaped whitespace and extract the file name
local file_path = string.gsub(path.args, "\\ ", " ")
local template = vim.fs.basename(file_path)
apply_template(template)
vim.api.nvim_del_user_command "ApplyTemplate"
end, { nargs = 1, bang = true })

local base_cmd = vim.tbl_flatten { util.FIND_CMD, { tostring(templates_dir), "-name", "'*.md'" } }
base_cmd = util.table_params_to_str(base_cmd)
local fzf_options = { source = base_cmd, sink = "ApplyTemplate" }
vim.api.nvim_call_function("fzf#run", {
vim.api.nvim_call_function("fzf#wrap", { fzf_options }),
})
end)

if not has_fzf then
echo.err "Either telescope.nvim or fzf.vim is required for :ObsidianTemplate command"
end
vim.api.nvim_del_user_command "ApplyTemplate"
end, { nargs = 1, bang = true })

local base_cmd = vim.tbl_flatten { util.FIND_CMD, { tostring(templates_dir), "-name", "'*.md'" } }
base_cmd = util.table_params_to_str(base_cmd)
local fzf_options = { source = base_cmd, sink = "ApplyTemplate" }
vim.api.nvim_call_function("fzf#run", {
vim.api.nvim_call_function("fzf#wrap", { fzf_options }),
})
end)
if not has_fzf then
util.implementation_unavailable()
end
end,
})
end

---Quick switch to an obsidian note
Expand All @@ -359,36 +373,42 @@ end
---@param data table
command.quick_switch = function(client, data)
local dir = tostring(client.dir)
local has_telescope, telescope = pcall(require, "telescope.builtin")

if has_telescope then
-- Search with telescope.nvim
telescope.find_files { cwd = dir, search_file = "*.md" }
return
end

local has_fzf_lua, fzf_lua = pcall(require, "fzf-lua")
client:_run_with_finder_backend(":ObsidianQuickSwitch", {
["telescope.nvim"] = function()
local has_telescope, telescope = pcall(require, "telescope.builtin")

if has_fzf_lua then
local cmd = vim.tbl_flatten { util.FIND_CMD, { ".", "-name", "'*.md'" } }
cmd = util.table_params_to_str(cmd)
fzf_lua.files { cmd = cmd, cwd = tostring(client.dir) }
return
end

-- Fall back to trying with fzf.vim
local has_fzf, _ = pcall(function()
local base_cmd = vim.tbl_flatten { util.FIND_CMD, { dir, "-name", "'*.md'" } }
base_cmd = util.table_params_to_str(base_cmd)
local fzf_options = { source = base_cmd, sink = "e" }
vim.api.nvim_call_function("fzf#run", {
vim.api.nvim_call_function("fzf#wrap", { fzf_options }),
})
end)
if not has_telescope then
util.implementation_unavailable()
end
-- Search with telescope.nvim
telescope.find_files { cwd = dir, search_file = "*.md" }
end,
["fzf-lua"] = function()
local has_fzf_lua, fzf_lua = pcall(require, "fzf-lua")

if not has_fzf then
echo.err "Either telescope.nvim or fzf.vim is required for :ObsidianQuickSwitch command"
end
if not has_fzf_lua then
util.implementation_unavailable()
end
local cmd = vim.tbl_flatten { util.FIND_CMD, { ".", "-name", "'*.md'" } }
cmd = util.table_params_to_str(cmd)
fzf_lua.files { cmd = cmd, cwd = tostring(client.dir) }
end,
["fzf.vim"] = function()
-- Fall back to trying with fzf.vim
local has_fzf, _ = pcall(function()
local base_cmd = vim.tbl_flatten { util.FIND_CMD, { dir, "-name", "'*.md'" } }
base_cmd = util.table_params_to_str(base_cmd)
local fzf_options = { source = base_cmd, sink = "e" }
vim.api.nvim_call_function("fzf#run", {
vim.api.nvim_call_function("fzf#wrap", { fzf_options }),
})
end)
if not has_fzf then
util.implementation_unavailable()
end
end,
})
end

command.link_new = function(client, data)
Expand Down
2 changes: 2 additions & 0 deletions lua/obsidian/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ local config = {}
---@field daily_notes obsidian.config.DailyNotesOpts
---@field use_advanced_uri boolean|?
---@field open_app_foreground boolean|?
---@field finder string|?
config.ClientOpts = {}

---Get defaults.
Expand All @@ -34,6 +35,7 @@ config.ClientOpts.default = function()
daily_notes = config.DailyNotesOpts.default(),
use_advanced_uri = nil,
open_app_foreground = false,
finder = nil,
}
end

Expand Down
21 changes: 21 additions & 0 deletions lua/obsidian/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,25 @@ client.resolve_note = function(self, query)
return nil
end

client._run_with_finder_backend = function(self, command_name, implementations)
local finders_order = { "telescope.nvim", "fzf-lua", "fzf.vim" }
if self.opts.finder then
for idx, finder in ipairs(finders_order) do
if finder == self.opts.finder then
table.remove(finders_order, idx)
break
end
end
table.insert(finders_order, 1, self.opts.finder)
end
local success, err = pcall(obsidian.util.run_first_supported, command_name, finders_order, implementations)
if not success then
if type(err) == "string" then
echo.err(err)
else
error(err)
end
end
end

return obsidian
Loading