org-paste-subtree: With single/double prefix, force inserting sibling/child

* lisp/org.el (org-paste-subtree): When called with single or double
universal argument, force inserting sibling heading or child heading
accordingly.
* testing/lisp/test-org.el (test-org/paste-subtree): Add tests for the
new behavior.
* doc/org-manual.org (Structure Editing): Update the command description.
* etc/ORG-NEWS (~org-paste-subtree~ now handles =C-u= and =C-u C-u=
prefix arguments specially): Announce the change.

Link: https://orgmode.org/list/878rhxtszb.fsf@localhost
This commit is contained in:
Ihor Radchenko 2024-04-21 14:59:37 +03:00
parent 36d0928043
commit 5b0b7f2924
No known key found for this signature in database
GPG Key ID: 6470762A7DA11D8B
4 changed files with 46 additions and 6 deletions

View File

@ -921,7 +921,9 @@ The following commands jump to other headlines in the buffer.
Yank subtree from kill ring. This does modify the level of the
subtree to make sure the tree fits in nicely at the yank position.
The yank level can also be specified with a numeric prefix argument,
or by yanking after a headline marker like =****=.
or by yanking after a headline marker like =****=. With
{{{kbd(C-u)}}} prefix, force inserting as a sibling. With
{{{kbd(C-u C-u)}}} prefix argument, force inserting as a child.
- {{{kbd(C-y)}}} (~org-yank~) ::

View File

@ -1000,6 +1000,11 @@ properties, links to headlines in the file can also be made more
robust by using the file id instead of the file path.
** New features
*** ~org-paste-subtree~ now handles =C-u= and =C-u C-u= prefix arguments specially
With =C-u= prefix argument, force inserting a sibling heading below.
With =C-u C-u= prefix argument, force inserting a child heading.
*** =colview= dynamic block now writes column width specifications
When column format contains width specifications, =colview= dynamic

View File

@ -7294,7 +7294,13 @@ The entire subtree is promoted or demoted in order to match a new headline
level.
If the cursor is at the beginning of a headline, the same level as
that headline is used to paste the tree.
that headline is used to paste the tree before current headline.
With `\\[universal-argument]' prefix, force inserting at the same level
as current headline, after subtree at point.
With `\\[universal-argument]' `\\[universal-argument]' prefix, force
inserting as a child headline, as the first child.
If not, the new level is derived from the *visible* headings
before and after the insertion point, and taken to be the inferior headline
@ -7330,12 +7336,15 @@ When REMOVE is non-nil, remove the subtree from the clipboard."
level-indicator?
(force-level
(cond
(level (prefix-numeric-value level))
;; When point is after the stars in an otherwise empty
;; headline, use the number of stars as the forced level.
((and (org-match-line "^\\*+[ \t]*$")
((and (or (not level) (member level '((4) (16))))
(org-match-line "^\\*+[ \t]*$")
(not (eq ?* (char-after))))
(setq level-indicator? (org-outline-level)))
((equal level '(4)) (org-outline-level))
((equal level '(16)) nil) ; handle later
(level (prefix-numeric-value level))
((looking-at-p org-outline-regexp-bol) (org-outline-level))))
(previous-level
(save-excursion
@ -7345,7 +7354,12 @@ When REMOVE is non-nil, remove the subtree from the clipboard."
(save-excursion
(org-next-visible-heading 1)
(if (org-at-heading-p) (org-outline-level) 1)))
(new-level (or force-level (max previous-level next-level)))
(new-level (or force-level
(max
;; C-u C-u forces child.
(if (equal level '(16)) (1+ previous-level) 0)
previous-level
next-level)))
(shift (if (or (= old-level -1)
(= new-level -1)
(= old-level new-level))
@ -7360,7 +7374,8 @@ When REMOVE is non-nil, remove the subtree from the clipboard."
(delete-region (line-beginning-position) (line-beginning-position 2)))
;; Paste before the next visible heading or at end of buffer,
;; unless point is at the beginning of a headline.
(unless (and (bolp) (org-at-heading-p))
(unless (and (bolp) (org-at-heading-p) (not (member level '((4) (16)))))
(when (equal level '(4)) (org-end-of-subtree t))
(org-next-visible-heading 1)
(unless (bolp) (insert "\n")))
(setq beg (point))

View File

@ -9356,6 +9356,18 @@ CLOSED: %s
(org-test-with-temp-text "* H1\n<point>Paragraph\n* H2"
(org-paste-subtree nil "* Text")
(buffer-string))))
;; With prefix argument, move to the end of subtree.
(should
(equal "* H1\nParagraph\n** H1.1\n* Text\n* H2"
(org-test-with-temp-text "* H1\n<point>Paragraph\n** H1.1\n* H2"
(org-paste-subtree '(4) "* Text")
(buffer-string))))
;; With double prefix argument, move to first sibling
(should
(equal "* H1\nParagraph\n** Text\n** H1.1\n* H2"
(org-test-with-temp-text "* H1\n<point>Paragraph\n** H1.1\n* H2"
(org-paste-subtree '(16) "* Text")
(buffer-string))))
;; If point is between two headings, use the deepest level.
(should
(equal "* H1\n\n* Text\n* H2"
@ -9378,6 +9390,12 @@ CLOSED: %s
(org-test-with-temp-text "<point>* H1\n** H2"
(org-paste-subtree nil "*** Text")
(buffer-string))))
;; With prefix argument, ignore that we are at bol
(should
(equal "* H1\n** H2\n* Text\n"
(org-test-with-temp-text "<point>* H1\n** H2"
(org-paste-subtree '(4) "*** Text")
(buffer-string))))
;; When point is on heading but not at bol, use smallest level among
;; current heading and next, inserting before the next heading.
(should