Skip to content

Commit 6c45397

Browse files
committed
feat: enhance orgfile search
- remove empty column - show titles instead of filenames when available - replace prompt title on mode switch
1 parent 933cc0f commit 6c45397

File tree

4 files changed

+120
-35
lines changed

4 files changed

+120
-35
lines changed

lua/telescope-orgmode/insert_link.lua

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,30 @@ end
4141

4242
return function(opts)
4343
opts = vim.tbl_extend('force', config.opts, opts or {})
44+
opts.state = {
45+
current = nil,
46+
next = nil,
47+
headlines = {
48+
max_depth = opts.max_depth,
49+
prompt_title = 'Insert link to headline',
50+
},
51+
orgfiles = {
52+
max_depth = 0,
53+
prompt_title = 'Insert link to org file',
54+
},
55+
}
4456

4557
pickers
4658
.new(opts, {
47-
prompt_title = 'Link Target',
59+
prompt_title = opts.state.headlines.prompt_title,
4860
finder = finders.new_table({
4961
results = utils.get_entries(opts),
5062
entry_maker = opts.entry_maker or utils.make_entry(opts),
5163
}),
5264
sorter = conf.generic_sorter(opts),
5365
previewer = conf.grep_previewer(opts),
5466
attach_mappings = function(_, map)
55-
map('i', '<C-Space>', utils.gen_depth_toggle(opts), { desc = 'Toggle headline/file jump' })
67+
map('i', '<C-Space>', utils.gen_depth_toggle(opts), { desc = 'Toggle headline/orgfile' })
5668
for mode, mappings in pairs(opts.mappings or {}) do
5769
for key, action in pairs(mappings) do
5870
map(mode, key, action)

lua/telescope-orgmode/refile_heading.lua

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,26 @@ M.closest_headline = nil
3434

3535
return function(opts)
3636
opts = vim.tbl_extend('force', config.opts, opts or {})
37+
opts.state = {
38+
current = nil,
39+
next = nil,
40+
headlines = {
41+
max_depth = opts.max_depth,
42+
prompt_title = 'Refile to headline',
43+
},
44+
orgfiles = {
45+
max_depth = 0,
46+
prompt_title = 'Refile to org files',
47+
},
48+
}
3749

3850
M.closest_headline = OrgApi.current():get_closest_headline()
3951

4052
pickers
4153
.new(opts, {
4254
-- TODO: alter prompt title when depth is 0: Refile under file, Refile
4355
-- under Headline
44-
prompt_title = 'Refile Destination',
56+
prompt_title = opts.state.headlines.prompt_title,
4557
finder = finders.new_table({
4658
results = utils.get_entries(opts),
4759
entry_maker = opts.entry_maker or utils.make_entry(opts),

lua/telescope-orgmode/search_headings.lua

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,22 @@ local config = require('telescope-orgmode.config')
77

88
return function(opts)
99
opts = vim.tbl_extend('force', config.opts, opts or {})
10+
opts.state = {
11+
current = nil,
12+
next = nil,
13+
headlines = {
14+
max_depth = opts.max_depth,
15+
prompt_title = 'Search headlines',
16+
},
17+
orgfiles = {
18+
max_depth = 0,
19+
prompt_title = 'Search org files',
20+
},
21+
}
1022

1123
pickers
1224
.new(opts, {
13-
prompt_title = 'Search Headings',
25+
prompt_title = opts.state.headlines.prompt_title,
1426
finder = finders.new_table({
1527
results = utils.get_entries(opts),
1628
entry_maker = opts.entry_maker or utils.make_entry(opts),

lua/telescope-orgmode/utils.lua

Lines changed: 80 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,11 @@ local utils = {}
1313
---@field file OrgApiFile
1414
---@field filename string
1515
---@field headline? OrgApiHeadline
16+
---@field title? string
1617

17-
---Fetches entrys from OrgApi and extracts the relevant information
18-
---@param opts any
18+
---@param file_results { file: OrgApiFile, filename: string }[]
1919
---@return OrgEntry[]
20-
utils.get_entries = function(opts)
21-
---@type { file: OrgApiFile, filename: string }[]
22-
local file_results = vim.tbl_map(function(file)
23-
return { file = file, filename = file.filename }
24-
end, orgmode.load())
25-
26-
if not opts.archived then
27-
file_results = vim.tbl_filter(function(entry)
28-
return not entry.file.is_archive_file
29-
end, file_results)
30-
end
31-
32-
if opts.max_depth == 0 then
33-
return file_results
34-
end
35-
20+
local function index_headlines(file_results, opts)
3621
local results = {}
3722
for _, file_entry in ipairs(file_results) do
3823
for _, headline in ipairs(file_entry.file.headlines) do
@@ -43,6 +28,7 @@ utils.get_entries = function(opts)
4328
file = file_entry.file,
4429
filename = file_entry.filename,
4530
headline = headline,
31+
title = nil,
4632
}
4733
table.insert(results, entry)
4834
end
@@ -52,11 +38,58 @@ utils.get_entries = function(opts)
5238
return results
5339
end
5440

41+
---@param file_results { file: OrgApiFile, filename: string }[]
42+
---@return OrgEntry[]
43+
local function index_orgfiles(file_results, opts)
44+
local results = {}
45+
for _, file_entry in ipairs(file_results) do
46+
local entry = {
47+
file = file_entry.file,
48+
filename = file_entry.filename,
49+
-- not beautiful to access a private property, but this is the only way to get the title
50+
---@diagnostic disable-next-line: invisible, undefined-field
51+
title = file_entry.file._file:get_directive('TITLE') or nil,
52+
headline = nil,
53+
}
54+
table.insert(results, entry)
55+
end
56+
return results
57+
end
58+
59+
---Fetches entrys from OrgApi and extracts the relevant information
60+
---@param opts any
61+
---@return OrgEntry[]
62+
utils.get_entries = function(opts)
63+
---@type { file: OrgApiFile, filename: string, last_used: number }[]
64+
local file_results = vim.tbl_map(function(file)
65+
return { file = file, filename = file.filename }
66+
end, orgmode.load())
67+
68+
if not opts.archived then
69+
file_results = vim.tbl_filter(function(entry)
70+
return not entry.file.is_archive_file
71+
end, file_results)
72+
end
73+
74+
if opts.state and opts.state.current and opts.state.current.max_depth == 0 then
75+
return index_orgfiles(file_results, opts)
76+
end
77+
78+
return index_headlines(file_results, opts)
79+
end
80+
5581
---Entry-Maker for Telescope
5682
---@param opts any
5783
---@return fun(entry: OrgEntry):MatchEntry
5884
utils.make_entry = function(opts)
59-
local displayer = entry_display.create({
85+
local orgfile_displayer = entry_display.create({
86+
separator = ' ',
87+
items = {
88+
{ remaining = true },
89+
},
90+
})
91+
92+
local headline_displayer = entry_display.create({
6093
separator = ' ',
6194
items = {
6295
{ width = vim.F.if_nil(opts.location_width, 20) },
@@ -67,27 +100,32 @@ utils.make_entry = function(opts)
67100

68101
---@param entry MatchEntry
69102
local function make_display(entry)
70-
return displayer({ entry.location, entry.tags .. ' ' .. entry.line })
103+
if opts.state and opts.state.current and opts.state.current.max_depth == 0 then
104+
return orgfile_displayer({ entry.line })
105+
else
106+
return headline_displayer({ entry.location, entry.tags .. ' ' .. entry.line })
107+
end
71108
end
72109

73110
return function(entry)
74-
local headline = entry.headline
75-
76111
local lnum = nil
77112
local location = vim.fn.fnamemodify(entry.filename, ':t')
78-
local line = ''
113+
local line = entry.title or location
79114
local tags = ''
115+
local ordinal = line
80116

117+
local headline = entry.headline
81118
if headline then
82119
lnum = headline.position.start_line
83120
location = string.format('%s:%i', location, lnum)
84121
line = string.format('%s %s', string.rep('*', headline.level), headline.title)
122+
ordinal = tags .. ' ' .. line .. ' ' .. location
85123
tags = table.concat(headline.all_tags, ':')
86124
end
87125

88126
return {
89127
value = entry,
90-
ordinal = location .. ' ' .. tags .. ' ' .. line,
128+
ordinal = ordinal,
91129
filename = entry.filename,
92130
lnum = lnum,
93131
display = make_display,
@@ -103,20 +141,31 @@ utils.gen_depth_toggle = function(opts)
103141
local current_picker = action_state.get_current_picker(prompt_bufnr)
104142
local status = state.get_status(prompt_bufnr)
105143

106-
if status._ot_current_depth == nil and status._ot_next_depth == nil then
107-
-- uninitialized state - initialize with "show files only"
144+
-- FIXME: the state get's sometimes nil when the initalization has already been run
145+
-- In this case, a toggle is "dropped" (keypress does not change the state).
146+
-- Can we avoid that by initializing the state in the higher order function?
147+
-- Idea: We can try to do it as before, but pass the prompt_bufnr with the opts.
148+
if status._ot_state == nil then
149+
-- uninitialized state - initialize with orgfiles
108150
-- Because when this function is called the first time, it is triggered
109-
-- by the users and we search over headings by default, we set the state
151+
-- by the users and we search over headlines by default, we set the state
110152
-- for the first toggle already here.
111-
status._ot_current_depth = 0
112-
status._ot_next_depth = opts.max_depth
153+
-- _ot_ is used as our plugin-specific namespace in the action status
154+
-- (ot - orgmode telescope)
155+
status._ot_state = { current = opts.state.orgfiles, next = opts.state.headlines }
113156
else
114157
-- initalized state - swap to next state
115-
status._ot_current_depth, status._ot_next_depth = status._ot_next_depth, status._ot_current_depth
158+
status._ot_state.current, status._ot_state.next = status._ot_state.next, status._ot_state.current
116159
end
117160

118161
-- opts is used as a channel to communicate the depth state to the get_entries function
119-
opts.max_depth = status._ot_current_depth
162+
opts.state.current = status._ot_state.current
163+
164+
-- the caller may not have defined a prompt title - then we don't adjust it
165+
if opts.state.current.prompt_title then
166+
current_picker.layout.prompt.border:change_title(status._ot_state.current.prompt_title)
167+
end
168+
120169
local new_finder = finders.new_table({
121170
results = utils.get_entries(opts),
122171
entry_maker = opts.entry_maker or utils.make_entry(opts),

0 commit comments

Comments
 (0)