Skip to content

Commit bab2fca

Browse files
refactor: use treesitter for promote and demote
1 parent a4adf7e commit bab2fca

File tree

4 files changed

+85
-35
lines changed

4 files changed

+85
-35
lines changed

lua/orgmode/config/init.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,11 @@ end
366366
---@param amount number
367367
function Config:apply_indent(content, amount)
368368
local indent = self:get_indent(amount)
369+
370+
if indent == '' then
371+
return content
372+
end
373+
369374
if type(content) ~= 'table' then
370375
return indent .. content
371376
end
@@ -376,5 +381,6 @@ function Config:apply_indent(content, amount)
376381
return content
377382
end
378383

384+
---@type Config
379385
instance = Config:new()
380386
return instance

lua/orgmode/org/mappings.lua

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -465,21 +465,21 @@ function OrgMappings:_todo_change_state(direction)
465465
end
466466

467467
function OrgMappings:do_promote(whole_subtree)
468-
local item = Files.get_closest_headline()
469-
local old_level = item.level
468+
local headline = ts_org.closest_headline()
469+
local old_level = headline:level()
470470
local foldclosed = vim.fn.foldclosed('.')
471-
item:promote(1, whole_subtree)
471+
headline:promote(1, whole_subtree)
472472
if foldclosed > -1 and vim.fn.foldclosed('.') == -1 then
473473
vim.cmd([[norm!zc]])
474474
end
475475
EventManager.dispatch(events.HeadlinePromoted:new(Files.get_closest_headline(), ts_org.closest_headline(), old_level))
476476
end
477477

478478
function OrgMappings:do_demote(whole_subtree)
479-
local item = Files.get_closest_headline()
480-
local old_level = item.level
479+
local headline = ts_org.closest_headline()
480+
local old_level = headline:level()
481481
local foldclosed = vim.fn.foldclosed('.')
482-
item:demote(1, whole_subtree)
482+
headline:demote(1, whole_subtree)
483483
if foldclosed > -1 and vim.fn.foldclosed('.') == -1 then
484484
vim.cmd([[norm!zc]])
485485
end

lua/orgmode/parser/section.lua

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -404,35 +404,6 @@ function Section:demote(amount, demote_child_sections, dryRun)
404404
return lines
405405
end
406406

407-
---@param amount number
408-
---@param promote_child_sections boolean
409-
function Section:promote(amount, promote_child_sections)
410-
amount = amount or 1
411-
promote_child_sections = promote_child_sections or false
412-
if self.level == 1 then
413-
return utils.echo_warning('Cannot demote top level heading.')
414-
end
415-
vim.api.nvim_call_function('setline', { self.range.start_line, self.line:sub(1 + amount) })
416-
if config.org_indent_mode == 'indent' then
417-
local contents = self.root:get_node_text_list(self.node)
418-
for i, content in ipairs(contents) do
419-
if i > 1 then
420-
if content:match('^%*+') then
421-
break
422-
end
423-
if vim.trim(content:sub(1, amount)) == '' then
424-
vim.api.nvim_call_function('setline', { self.range.start_line + i - 1, content:sub(1 + amount) })
425-
end
426-
end
427-
end
428-
end
429-
if promote_child_sections then
430-
for _, section in ipairs(self.sections) do
431-
section:promote(amount, true)
432-
end
433-
end
434-
end
435-
436407
---@return boolean
437408
function Section:has_planning()
438409
for _, date in ipairs(self.dates) do

lua/orgmode/treesitter/headline.lua

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
local utils = require('orgmode.utils')
12
local ts_utils = require('nvim-treesitter.ts_utils')
23
local tree_utils = require('orgmode.utils.treesitter')
34
local Date = require('orgmode.objects.date')
@@ -52,6 +53,78 @@ function Headline:priority()
5253
return self:parse('%[#(%w+)%]')
5354
end
5455

56+
---@param amount number
57+
---@param recursive? boolean
58+
function Headline:promote(amount, recursive)
59+
amount = amount or 1
60+
recursive = recursive or false
61+
if self:level() == 1 then
62+
return utils.echo_warning('Cannot demote top level heading.')
63+
end
64+
65+
return self:_handle_promote_demote(recursive, function(lines)
66+
for i, line in ipairs(lines) do
67+
if line:sub(1, 1) == '*' then
68+
lines[i] = line:sub(1 + amount)
69+
elseif vim.trim(line:sub(1, amount)) == '' then
70+
lines[i] = line:sub(1 + amount)
71+
end
72+
end
73+
return lines
74+
end)
75+
end
76+
77+
78+
---@param amount number
79+
---@param recursive? boolean
80+
function Headline:demote(amount, recursive)
81+
amount = amount or 1
82+
recursive = recursive or false
83+
84+
return self:_handle_promote_demote(recursive, function(lines)
85+
for i, line in ipairs(lines) do
86+
if line:sub(1, 1) == '*' then
87+
lines[i] = '*' .. line
88+
else
89+
lines[i] = config:apply_indent(line, amount)
90+
end
91+
end
92+
return lines
93+
end)
94+
end
95+
96+
function Headline:_handle_promote_demote(recursive, modifier)
97+
local whole_subtree = function()
98+
local text = query.get_node_text(self.headline:parent(), 0)
99+
local lines = modifier(vim.split(text, '\n', true))
100+
local start_line, _, end_line, _ = self.headline:parent():range()
101+
vim.api.nvim_buf_set_lines(0, start_line, end_line, false, lines)
102+
return self:refresh()
103+
end
104+
105+
if recursive then
106+
return whole_subtree()
107+
end
108+
109+
local first_child_section = nil
110+
for _, node in ipairs(ts_utils.get_named_children(self.headline:parent())) do
111+
if node:type() == 'section' then
112+
first_child_section = node
113+
break
114+
end
115+
end
116+
117+
if not first_child_section then
118+
return whole_subtree()
119+
end
120+
121+
local start = self.headline:start()
122+
local end_line = first_child_section:start()
123+
local lines = modifier(vim.api.nvim_buf_get_lines(0, start, end_line, false))
124+
vim.api.nvim_buf_set_lines(0, start, end_line, false, lines)
125+
return self:refresh()
126+
end
127+
55128
---@return userdata, string
56129
function Headline:tags()
57130
local node = self.headline:field('tags')[1]

0 commit comments

Comments
 (0)