Skip to content

Commit 5351b85

Browse files
Search headlines from end when archiving to avoid issues with duplicates
1 parent 8be9a4b commit 5351b85

File tree

2 files changed

+32
-11
lines changed

2 files changed

+32
-11
lines changed

lua/orgmode/org/mappings.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function OrgMappings:archive()
5050
archive_location,
5151
vim.schedule_wrap(function()
5252
Files.update_file(archive_location, function()
53-
local archived_headline = ts_org.find_headline_by_title(item.title, true)
53+
local archived_headline = ts_org.find_headline_by_title(item.title, { exact = true, from_end = true })
5454
if archived_headline then
5555
archived_headline:set_property('ARCHIVE_TIME', Date.now():to_string())
5656
archived_headline:set_property('ARCHIVE_FILE', file.filename)

lua/orgmode/treesitter/init.lua

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,43 @@ local Headline = require('orgmode.treesitter.headline')
33
local Listitem = require('orgmode.treesitter.listitem')
44
local M = {}
55

6-
---@param matcher function
6+
---@param matcher function(headline: Headline, index: number): boolean
7+
---@param from_end? boolean
78
---@return Headline|nil
8-
local function query_headlines(matcher)
9+
local function query_headlines(matcher, from_end)
910
local trees = vim.treesitter.get_parser(0, 'org', {}):parse()
1011
if #trees == 0 then
1112
return {}
1213
end
1314
local root = trees[1]:root()
1415
local ts_query = tree_utils.parse_query('(section (headline) @headline)')
15-
local index = 1
16+
local headlines = {}
1617
for _, match, _ in ts_query:iter_matches(root) do
17-
-- local items = {}
1818
for _, matched_node in pairs(match) do
1919
local headline = Headline:new(matched_node)
20-
local valid = matcher(headline, index)
20+
table.insert(headlines, headline)
21+
end
22+
end
23+
24+
if from_end then
25+
for i = #headlines, 1, -1 do
26+
local headline = headlines[i]
27+
local valid = matcher(headline, i)
2128
if valid then
2229
return headline
2330
end
24-
index = index + 1
31+
end
32+
return nil
33+
end
34+
35+
for i, headline in ipairs(headlines) do
36+
local valid = matcher(headline, i)
37+
if valid then
38+
return headline
2539
end
2640
end
41+
42+
return nil
2743
end
2844

2945
---@param cursor? Table Cursor position tuple {row, col}
@@ -53,18 +69,23 @@ M.headline_at = function(index)
5369
end)
5470
end
5571

72+
---@class FindHeadlineOpts
73+
---@field from_end? boolean
74+
---@field exact? boolean
75+
5676
---@param title string
57-
---@param exact? boolean
77+
---@param opts? FindHeadlineOpts
5878
---@return Headline|nil
59-
M.find_headline_by_title = function(title, exact)
79+
M.find_headline_by_title = function(title, opts)
80+
opts = opts or {}
6081
return query_headlines(function(headline, _)
6182
local pattern = '^' .. vim.pesc(title:lower())
62-
if exact then
83+
if opts.exact then
6384
pattern = pattern .. '$'
6485
end
6586

6687
return headline:title():lower():match(pattern)
67-
end)
88+
end, opts.from_end)
6889
end
6990

7091
return M

0 commit comments

Comments
 (0)