Skip to content

Commit

Permalink
Fix subtree move (fixes #752) (#753)
Browse files Browse the repository at this point in the history
* tests: improve test cases for subtree move

- repeated move
- evaluate cursor position after move

* fix: cursor position after moving subtree

To allow for repetition of moving a subtree, the cursor must stay on the
headline.

* fix: preserve folding when moving subtree

To be consistent with promotion and demotion commands, we preserve the
folding state also when moving a subtree.

---------

Co-authored-by: Sebastian Flügge <seflue@users.noreply.github.com>
  • Loading branch information
seflue and seflue authored Jun 13, 2024
1 parent c5a3446 commit cf261f7
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 15 deletions.
18 changes: 16 additions & 2 deletions lua/orgmode/org/mappings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,14 @@ function OrgMappings:move_subtree_up()
return utils.echo_warning('Cannot move past superior level.')
end
local range = item:get_range()
vim.cmd(string.format(':%d,%dmove %d', range.start_line, range.end_line, prev_headline:get_range().start_line - 1))
local target_line = prev_headline:get_range().start_line - 1
local foldclosed = vim.fn.foldclosed('.')
vim.cmd(string.format(':%d,%dmove %d', range.start_line, range.end_line, target_line))
local pos = vim.fn.getcurpos()
vim.fn.cursor(target_line + 1, pos[2])
if foldclosed > -1 and vim.fn.foldclosed('.') == -1 then
vim.cmd([[norm!zc]])
end
end

function OrgMappings:move_subtree_down()
Expand All @@ -772,7 +779,14 @@ function OrgMappings:move_subtree_down()
return utils.echo_warning('Cannot move past superior level.')
end
local range = item:get_range()
vim.cmd(string.format(':%d,%dmove %d', range.start_line, range.end_line, next_headline:get_range().end_line))
local target_line = next_headline:get_range().end_line
local foldclosed = vim.fn.foldclosed('.')
vim.cmd(string.format(':%d,%dmove %d', range.start_line, range.end_line, target_line))
local pos = vim.fn.getcurpos()
vim.fn.cursor(target_line + range.start_line - range.end_line, pos[2])
if foldclosed > -1 and vim.fn.foldclosed('.') == -1 then
vim.cmd([[norm!zc]])
end
end

function OrgMappings:show_help(type)
Expand Down
98 changes: 85 additions & 13 deletions tests/plenary/ui/mappings/headline_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ describe('Heading mappings', function()
}, vim.api.nvim_buf_get_lines(0, 0, 2, false))
end)

it('should move subtree up (org_move_subtree_up)', function()
it('should move subtree up once (org_move_subtree_up)', function()
helpers.create_file({
'#TITLE: Test',
'',
Expand All @@ -311,9 +311,11 @@ describe('Heading mappings', function()
'Some content for level 2',
'*** NEXT [#1] Level 3',
'Content Level 3',
'* TODO top level todo with multiple tags :OFFICE:PROJECT:',
'* DONE top level todo :WORK:',
'content for top level todo',
'* TODO top level todo with multiple tags :OFFICE:PROJECT:',
'** Subtree level 2',
' Content of subtree level 2',
})

assert.are.same({
Expand All @@ -323,23 +325,85 @@ describe('Heading mappings', function()
'Some content for level 2',
'*** NEXT [#1] Level 3',
'Content Level 3',
'* TODO top level todo with multiple tags :OFFICE:PROJECT:',
'* DONE top level todo :WORK:',
'content for top level todo',
'** Subtree level 2',
' Content of subtree level 2',
}, vim.api.nvim_buf_get_lines(0, 2, 13, false))
vim.fn.cursor(10, 1)
vim.cmd([[norm ,oK]])
assert.are.same({
'* TODO Test orgmode',
' DEADLINE: <2021-07-21 Wed 22:02>',
'** TODO [#A] Test orgmode level 2 :PRIVATE:',
'Some content for level 2',
'*** NEXT [#1] Level 3',
'Content Level 3',
'* DONE top level todo :WORK:',
'content for top level todo',
'** Subtree level 2',
' Content of subtree level 2',
'* TODO top level todo with multiple tags :OFFICE:PROJECT:',
}, vim.api.nvim_buf_get_lines(0, 2, 13, false))
end)

it('should move subtree up twice (org_move_subtree_up)', function()
helpers.create_file({
'#TITLE: Test',
'',
'* TODO Test orgmode',
' DEADLINE: <2021-07-21 Wed 22:02>',
'** TODO [#A] Test orgmode level 2 :PRIVATE:',
'Some content for level 2',
'*** NEXT [#1] Level 3',
'Content Level 3',
'* TODO top level todo with multiple tags :OFFICE:PROJECT:',
'* DONE top level todo :WORK:',
'content for top level todo',
'** Subtree level 2',
' Content of subtree level 2',
})

assert.are.same({
'* TODO Test orgmode',
' DEADLINE: <2021-07-21 Wed 22:02>',
'** TODO [#A] Test orgmode level 2 :PRIVATE:',
'Some content for level 2',
'*** NEXT [#1] Level 3',
'Content Level 3',
'* TODO top level todo with multiple tags :OFFICE:PROJECT:',
}, vim.api.nvim_buf_get_lines(0, 2, 11, false))
vim.fn.cursor(9, 1)
'* DONE top level todo :WORK:',
'content for top level todo',
'** Subtree level 2',
' Content of subtree level 2',
}, vim.api.nvim_buf_get_lines(0, 2, 13, false))
vim.fn.cursor(10, 1)
assert.are_same({
'* DONE top level todo :WORK:',
}, vim.api.nvim_buf_get_lines(0, 9, 10, false))
vim.cmd([[norm ,oK]])
local cursor_line = vim.fn.getcurpos()[2]
assert.are.same(9, cursor_line)
assert.are_same({
'* DONE top level todo :WORK:',
}, vim.api.nvim_buf_get_lines(0, 8, 9, false))
vim.cmd([[norm ,oK]])
cursor_line = vim.fn.getcurpos()[2]
assert.are.same(3, cursor_line)
assert.are.same({
'* DONE top level todo :WORK:',
'content for top level todo',
'** Subtree level 2',
' Content of subtree level 2',
'* TODO Test orgmode',
' DEADLINE: <2021-07-21 Wed 22:02>',
'** TODO [#A] Test orgmode level 2 :PRIVATE:',
'Some content for level 2',
'*** NEXT [#1] Level 3',
'Content Level 3',
'* TODO top level todo with multiple tags :OFFICE:PROJECT:',
}, vim.api.nvim_buf_get_lines(0, 2, 11, false))
}, vim.api.nvim_buf_get_lines(0, 2, 13, false))
end)

it('should move subtree down (org_move_subtree_down)', function()
Expand Down Expand Up @@ -382,15 +446,19 @@ describe('Heading mappings', function()
' 1. First item',
' 2. Second item',
}, vim.api.nvim_buf_get_lines(0, 2, 18, false))
vim.fn.cursor(9, 1)
vim.fn.cursor(3, 1)
vim.cmd([[norm ,oJ]])
local cursor_line = vim.fn.getcurpos()[2]
assert.are.same(5, cursor_line)
assert.are.same({
'* TODO Test orgmode',
' DEADLINE: <2021-07-21 Wed 22:02>',
'** TODO [#A] Test orgmode level 2 :PRIVATE:',
'Some content for level 2',
'*** NEXT [#1] Level 3',
'Content Level 3',
}, vim.api.nvim_buf_get_lines(0, 4, 5, false))
vim.cmd([[norm ,oJ]])
cursor_line = vim.fn.getcurpos()[2]
assert.are.same(13, cursor_line)
assert.are.same({
'* DONE top level todo :WORK:',
'content for top level todo',
'* TODO top level todo with multiple tags :OFFICE:PROJECT:',
' - [ ] The checkbox',
' - [X] The checkbox 2',
Expand All @@ -399,8 +467,12 @@ describe('Heading mappings', function()
'** NEXT Working on this now :OFFICE:NESTED:',
' 1. First item',
' 2. Second item',
'* DONE top level todo :WORK:',
'content for top level todo',
'* TODO Test orgmode',
' DEADLINE: <2021-07-21 Wed 22:02>',
'** TODO [#A] Test orgmode level 2 :PRIVATE:',
'Some content for level 2',
'*** NEXT [#1] Level 3',
'Content Level 3',
}, vim.api.nvim_buf_get_lines(0, 2, 18, false))
end)

Expand Down

0 comments on commit cf261f7

Please sign in to comment.