Skip to content

Commit f492596

Browse files
committed
feat: better interact with pickers
1 parent 8ddaa58 commit f492596

File tree

5 files changed

+98
-127
lines changed

5 files changed

+98
-127
lines changed

lua/obsidian/commands/__toc.lua

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
-- TODO: all pickers should do on_list callbacks
2+
3+
local telescope_on_list = function(data)
4+
local pickers = require "telescope.pickers"
5+
local finders = require "telescope.finders"
6+
pickers
7+
.new({}, {
8+
prompt_title = "Table of Contents",
9+
finder = finders.new_table {
10+
results = data.items,
11+
entry_maker = function(value)
12+
return {
13+
value = value,
14+
display = value.text,
15+
path = value.filename,
16+
ordinal = value.text,
17+
}
18+
end,
19+
},
20+
})
21+
:find()
22+
end
23+
24+
local function mini_pick_on_list(data)
25+
local ok, pick = pcall(require, "mini.pick")
26+
if not ok then
27+
vim.notify("no mini.pick found", 3)
28+
return
29+
end
30+
31+
local items = data.items
32+
for _, item in ipairs(data.items) do
33+
item.path = item.filename
34+
end
35+
36+
pick.start {
37+
source = { items = items },
38+
name = "Table of Contents",
39+
show = pick.default_show,
40+
choose = pick.default_choose,
41+
}
42+
end
43+
44+
---@param client obsidian.Client
45+
---@param _ CommandArgs
46+
return function(client, _)
47+
local picker_name = tostring(client:picker())
48+
if picker_name == "TelescopePicker()" then
49+
vim.lsp.buf.document_symbol { on_list = telescope_on_list }
50+
elseif picker_name == "SnacksPicker()" then
51+
require("snacks.picker").lsp_symbols()
52+
elseif picker_name == "FzfPicker()" then
53+
require("fzf-lua").lsp_document_symbols()
54+
elseif picker_name == "MiniPicker()" then
55+
vim.lsp.buf.document_symbol { on_list = mini_pick_on_list }
56+
else
57+
vim.lsp.buf.document_symbol { loclist = false }
58+
end
59+
end

lua/obsidian/commands/backlinks.lua

Lines changed: 32 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,25 @@
1-
local util = require "obsidian.util"
21
local log = require "obsidian.log"
3-
local RefTypes = require("obsidian.search").RefTypes
42

5-
---@param client obsidian.Client
6-
---@param picker obsidian.Picker
7-
---@param note obsidian.Note
8-
---@param opts { anchor: string|?, block: string|? }|?
9-
local function collect_backlinks(client, picker, note, opts)
10-
opts = opts or {}
11-
12-
client:find_backlinks_async(note, function(backlinks)
13-
if vim.tbl_isempty(backlinks) then
14-
if opts.anchor then
15-
log.info("No backlinks found for anchor '%s' in note '%s'", opts.anchor, note.id)
16-
elseif opts.block then
17-
log.info("No backlinks found for block '%s' in note '%s'", opts.block, note.id)
18-
else
19-
log.info("No backlinks found for note '%s'", note.id)
20-
end
21-
return
22-
end
23-
24-
local entries = {}
25-
for _, matches in ipairs(backlinks) do
26-
for _, match in ipairs(matches.matches) do
27-
entries[#entries + 1] = {
28-
value = { path = matches.path, line = match.line },
29-
filename = tostring(matches.path),
30-
lnum = match.line,
31-
}
32-
end
33-
end
34-
35-
---@type string
36-
local prompt_title
37-
if opts.anchor then
38-
prompt_title = string.format("Backlinks to '%s%s'", note.id, opts.anchor)
39-
elseif opts.block then
40-
prompt_title = string.format("Backlinks to '%s#%s'", note.id, util.standardize_block(opts.block))
41-
else
42-
prompt_title = string.format("Backlinks to '%s'", note.id)
43-
end
44-
45-
vim.schedule(function()
46-
picker:pick(entries, {
47-
prompt_title = prompt_title,
48-
callback = function(value)
49-
util.open_buffer(value.path, { line = value.line })
3+
local telescope_on_list = function(data)
4+
local pickers = require "telescope.pickers"
5+
local finders = require "telescope.finders"
6+
pickers
7+
.new({}, {
8+
prompt_title = "References",
9+
finder = finders.new_table {
10+
results = data.items,
11+
entry_maker = function(value)
12+
return {
13+
value = value,
14+
display = value.text,
15+
path = value.filename,
16+
ordinal = value.text,
17+
lnum = value.lnum,
18+
}
5019
end,
51-
})
52-
end)
53-
end, { search = { sort = true }, anchor = opts.anchor, block = opts.block })
20+
},
21+
})
22+
:find()
5423
end
5524

5625
---@param client obsidian.Client
@@ -60,77 +29,19 @@ return function(client)
6029
log.err "No picker configured"
6130
return
6231
end
63-
64-
local location, _, ref_type = util.parse_cursor_link { include_block_ids = true }
65-
66-
if
67-
location ~= nil
68-
and ref_type ~= RefTypes.NakedUrl
69-
and ref_type ~= RefTypes.FileUrl
70-
and ref_type ~= RefTypes.BlockID
71-
then
72-
-- Remove block links from the end if there are any.
73-
-- TODO: handle block links.
74-
---@type string|?
75-
local block_link
76-
location, block_link = util.strip_block_links(location)
77-
78-
-- Remove anchor links from the end if there are any.
79-
---@type string|?
80-
local anchor_link
81-
location, anchor_link = util.strip_anchor_links(location)
82-
83-
-- Assume 'location' is current buffer path if empty, like for TOCs.
84-
if string.len(location) == 0 then
85-
location = vim.api.nvim_buf_get_name(0)
86-
end
87-
88-
local opts = { anchor = anchor_link, block = block_link }
89-
90-
client:resolve_note_async(location, function(...)
91-
---@type obsidian.Note[]
92-
local notes = { ... }
93-
94-
if #notes == 0 then
95-
log.err("No notes matching '%s'", location)
96-
return
97-
elseif #notes == 1 then
98-
return collect_backlinks(client, picker, notes[1], opts)
99-
else
100-
return vim.schedule(function()
101-
picker:pick_note(notes, {
102-
prompt_title = "Select note",
103-
callback = function(note)
104-
collect_backlinks(client, picker, note, opts)
105-
end,
106-
})
107-
end)
108-
end
109-
end)
32+
local picker_name = tostring(picker)
33+
34+
if picker_name == "TelescopePicker()" then
35+
vim.lsp.buf.references({
36+
includeDeclaration = false,
37+
}, { on_list = telescope_on_list })
38+
elseif picker_name == "SnacksPicker()" then
39+
require("snacks.picker").lsp_symbols()
40+
elseif picker_name == "FzfPicker()" then
41+
require("fzf-lua").lsp_document_symbols()
42+
elseif picker_name == "MiniPicker()" then
43+
-- vim.lsp.buf.document_symbol { on_list = mini_pick_on_list }
11044
else
111-
---@type { anchor: string|?, block: string|? }
112-
local opts = {}
113-
---@type obsidian.note.LoadOpts
114-
local load_opts = {}
115-
116-
if ref_type == RefTypes.BlockID then
117-
opts.block = location
118-
else
119-
load_opts.collect_anchor_links = true
120-
end
121-
122-
local note = client:current_note(0, load_opts)
123-
124-
-- Check if cursor is on a header, if so, use that anchor.
125-
local header_match = util.parse_header(vim.api.nvim_get_current_line())
126-
if header_match then
127-
opts.anchor = header_match.anchor
128-
end
129-
130-
if note == nil then
131-
log.err "Current buffer does not appear to be a note inside the vault"
132-
else
133-
collect_backlinks(client, picker, note, opts)
134-
end
45+
vim.lsp.buf.document_symbol { loclist = false }
13546
end
13647
end

lua/obsidian/lsp/handlers/document_symbol.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ local util = require "obsidian.lsp.util"
55
---@param handler function
66
return function(client, params, handler)
77
local bufnr = vim.uri_to_bufnr(params.textDocument.uri)
8-
handler(nil, util.get_headings(client, bufnr))
8+
local symbols = util.get_headings(bufnr)
9+
handler(nil, symbols)
910
end

lua/obsidian/lsp/handlers/references.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ return function(obsidian_client, _, handler, _)
5252
-- return
5353
-- end
5454
--
55+
5556
local entries = {}
5657
for _, matches in ipairs(backlinks) do
5758
for _, match in ipairs(matches.matches) do

lua/obsidian/lsp/util.lua

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,9 @@ local link_query = [[
7070
]]
7171

7272
---Extract headings from buffer
73-
---@param client obsidian.Client
7473
---@param bufnr integer
75-
---@return table TODO:
76-
M.get_headings = function(client, bufnr)
74+
---@return lsp.DocumentSymbol[]
75+
M.get_headings = function(bufnr)
7776
local lang = ts.language.get_lang(vim.bo[bufnr].filetype)
7877
if not lang then
7978
return {}
@@ -85,7 +84,7 @@ M.get_headings = function(client, bufnr)
8584
for id, node, _, _ in query:iter_captures(root, bufnr) do
8685
local text = string.rep("#", id) .. " " .. ts.get_node_text(node, bufnr)
8786
local row, _ = node:start()
88-
table.insert(headings, {
87+
headings[#headings + 1] = {
8988
kind = 15,
9089
range = {
9190
start = { line = row, character = 1 },
@@ -96,7 +95,7 @@ M.get_headings = function(client, bufnr)
9695
["end"] = { line = row, character = 1 },
9796
},
9897
name = text,
99-
})
98+
}
10099
end
101100
return headings
102101
end

0 commit comments

Comments
 (0)