Skip to content

Commit 4ee4502

Browse files
author
Sebastian Flügge
committed
perf: improve headline loading speed
Using the internal file API of nvim orgmode increases initial loading speed drastically with larger Orgfile collections from multiple seconds of delay to nearly instand loading.
1 parent 6a53595 commit 4ee4502

File tree

4 files changed

+115
-19
lines changed

4 files changed

+115
-19
lines changed

lua/telescope-orgmode/entry_maker/headlines.lua

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,16 @@ require('telescope-orgmode.entry_maker.types')
22
local org = require('telescope-orgmode.org')
33
local entry_display = require('telescope.pickers.entry_display')
44

5-
---@param file_results { file: OrgApiFile, filename: string }[]
5+
---@param headline_results { filename: string, title: string, level: number, line_number: number, all_tags: string[], is_archived: boolean }[]
66
---@return OrgHeadlineEntry[]
7-
local function index_headlines(file_results, opts)
7+
local function index_headlines(headline_results, opts)
88
local results = {}
9-
for _, file_entry in ipairs(file_results) do
10-
for _, headline in ipairs(file_entry.file.headlines) do
11-
local allowed_depth = opts.max_depth == nil or headline.level <= opts.max_depth
12-
local allowed_archive = opts.archived or not headline.is_archived
13-
if allowed_depth and allowed_archive then
14-
local entry = {
15-
file = file_entry.file,
16-
filename = file_entry.filename,
17-
headline = headline,
18-
}
19-
table.insert(results, entry)
20-
end
21-
end
9+
for _, headline in ipairs(headline_results) do
10+
local entry = {
11+
filename = headline.filename,
12+
headline = headline,
13+
}
14+
table.insert(results, entry)
2215
end
2316

2417
return results
@@ -29,7 +22,7 @@ local M = {}
2922
---@param opts any
3023
---@return OrgHeadlineEntry[]
3124
M.get_entries = function(opts)
32-
return index_headlines(org.load_files(opts), opts)
25+
return index_headlines(org.load_headlines(opts), opts)
3326
end
3427

3528
---Entry-Maker for Telescope
@@ -39,8 +32,8 @@ M.make_entry = function(opts)
3932
local displayer = entry_display.create({
4033
separator = ' ',
4134
items = {
42-
{ width = vim.F.if_nil(opts.location_width, 16) },
4335
{ width = vim.F.if_nil(opts.location_width, 24) },
36+
{ width = vim.F.if_nil(opts.tags_width, 20) },
4437
{ remaining = true },
4538
},
4639
})
@@ -56,7 +49,7 @@ M.make_entry = function(opts)
5649

5750
return function(entry)
5851
local headline = entry.headline
59-
local lnum = headline.position.start_line
52+
local lnum = headline.line_number
6053
local location = string.format('%s:%i', vim.fn.fnamemodify(entry.filename, ':t'), lnum)
6154
local line = string.format('%s %s', string.rep('*', headline.level), headline.title)
6255
local tags = table.concat(headline.all_tags, ':')

lua/telescope-orgmode/mappings.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ local M = {}
44

55
function M.attach_mappings(map, opts)
66
map('i', '<c-space>', to_actions.toggle_headlines_orgfiles(opts), { desc = 'Toggle headline/orgfile' })
7+
map('n', '<c-space>', to_actions.toggle_headlines_orgfiles(opts), { desc = 'Toggle headline/orgfile' })
78
M.attach_custom(map, opts)
89
end
910

lua/telescope-orgmode/org.lua

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ local M = {}
55
function M.load_files(opts)
66
---@type { filename: string, last_used: number, title: string }[]
77
local file_results = vim.tbl_map(function(file)
8-
return { filename = file.filename, last_used = file.metadata.mtime, title = file:get_title() }
8+
return { filename = file.filename, last_used = file.metadata.mtime, title = file:get_title() }
99
end, require('orgmode').files:all())
1010

1111
if not opts.archived then
@@ -21,6 +21,44 @@ function M.load_files(opts)
2121
return file_results
2222
end
2323

24+
function M.load_headlines(opts)
25+
---@type { filename: string, title: string, level: number, line_number: number, all_tags: string[], is_archived: boolean }[]
26+
local results = {}
27+
28+
-- Get files sorted by modification time (most recent first)
29+
local files = require('orgmode').files:all()
30+
if not opts.archived then
31+
files = vim.tbl_filter(function(file)
32+
return not (vim.fn.fnamemodify(file.filename, ':e') == 'org_archive')
33+
end, files)
34+
end
35+
36+
table.sort(files, function(a, b)
37+
return a.metadata.mtime < b.metadata.mtime
38+
end)
39+
40+
for _, file in ipairs(files) do
41+
-- Skip archive files unless explicitly requested
42+
local headlines = opts.archived and file:get_headlines_including_archived() or file:get_headlines()
43+
for _, headline in ipairs(headlines) do
44+
if
45+
(not opts.max_depth or headline:get_level() <= opts.max_depth) and (opts.archived or not headline:is_archived())
46+
then
47+
table.insert(results, {
48+
filename = file.filename,
49+
title = headline:get_title(),
50+
level = headline:get_level(),
51+
line_number = headline:get_range().start_line,
52+
all_tags = headline:get_tags(),
53+
is_archived = headline:is_archived(),
54+
})
55+
end
56+
end
57+
end
58+
59+
return results
60+
end
61+
2462
function M.refile(opts)
2563
return OrgApi.refile(opts)
2664
end
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
local OrgFile = require('orgmode.files.file')
2+
local org = require('telescope-orgmode.org')
3+
4+
describe('Telescope Orgmode Integration', function()
5+
---@return OrgFile
6+
local load_file_sync = function(content, filename)
7+
content = content or {}
8+
filename = filename or vim.fn.tempname() .. '.org'
9+
vim.fn.writefile(content, filename)
10+
return OrgFile.load(filename):wait()
11+
end
12+
13+
describe('org.load_headlines integration', function()
14+
it('should return headlines from multiple files', function()
15+
-- Create test files
16+
local file1 = load_file_sync({ '* File1 Headline' })
17+
local file2 = load_file_sync({ '* File2 Headline' })
18+
19+
-- Mock orgmode.files:all() to return our test files
20+
local original_require = require
21+
package.loaded['orgmode'] = {
22+
files = {
23+
all = function()
24+
return { file1, file2 }
25+
end,
26+
},
27+
}
28+
29+
local headlines = org.load_headlines({})
30+
31+
-- Restore original require
32+
require = original_require
33+
34+
assert.are.same(2, #headlines)
35+
assert.are.same('File1 Headline', headlines[1].title)
36+
assert.are.same('File2 Headline', headlines[2].title)
37+
end)
38+
39+
it('should respect archive filtering across files', function()
40+
local regular_file = load_file_sync({ '* Regular Headline' })
41+
local archive_filename = vim.fn.tempname() .. '.org_archive'
42+
local archive_file = load_file_sync({ '* Archive Headline' }, archive_filename)
43+
44+
-- Mock orgmode.files:all()
45+
local original_require = require
46+
package.loaded['orgmode'] = {
47+
files = {
48+
all = function()
49+
return { regular_file, archive_file }
50+
end,
51+
},
52+
}
53+
54+
local headlines_no_archive = org.load_headlines({})
55+
local headlines_with_archive = org.load_headlines({ archived = true })
56+
57+
-- Restore
58+
require = original_require
59+
60+
assert.are.same(1, #headlines_no_archive) -- only regular file
61+
assert.are.same(2, #headlines_with_archive) -- both files
62+
end)
63+
end)
64+
end)

0 commit comments

Comments
 (0)