4

(current as of org 8.2.10)

I have a thing (shameless plug) that outputs a simple snippet of org-headings in a single file that look like this:

* little boys
  - snakes
  - snails
  - puppy dog tails
* little girls
  - sugar
  - spice
  - everything nice
** addendum
  - etc.

These are meant to go into another file through org-insert functions, specifically, a subheading of that other file.

In order to do that I have to demote all of the headings so that they slide nicely into place. How can I do that?

I tried:

  • C-x r t to prepend asterisks; this adds asterisks to every line
  • C-x h M-S-<right> to try demoting the whole selection; this only demoted the first line

Further issue: org-metaright does not demote subtrees

Commenters were correct that C-x h M-<right> (org-metaright) promotes or demotes visible selections. However, this ignores their subtrees, resulting in reordering of their substructure. The same behavior occurs with org-do-demote called on a selection.

  • 3
    What command does M-S-<right> run? For me (Emacs 24.3.1, Org 8.2.10), M-<right> runs org-metaright, and that does the proper behavior (that is, adds a single asterisk to the "little boys" and "little girls" lines). Similarly, C-x h M-x org-do-demote also works properly. – zck Dec 25 '14 at 2:51
  • 2
    I might not be understanding the question, but doesn't org-metaright operate on a selected region? – Dan Dec 25 '14 at 2:51
  • 2
    Demoting and promoting works with selected regions, if that might be of use in this situation. – lawlist Dec 25 '14 at 7:19
  • I cannot find org-insert-file as a standard orgmode command. – Juancho Dec 26 '14 at 15:19
  • 1
    @TrevorAlexander Can't you just call show-all before org-do-demote? – Malabarba Dec 30 '14 at 22:20
2

Org healines are simply lines starting with a *. So you can cycle through all of them and manually insert an * on each one to get the effect you want.

(defun endless/demote-everything (number beg end)
  "Add a NUMBER of * to all headlines between BEG and END.
Interactively, NUMBER is the prefix argument and BEG and END are
the region boundaries."
  (interactive "p\nr")
  (save-excursion
    (save-restriction
      (save-match-data
        (widen)
        (narrow-to-region beg end)
        (goto-char (point-min))
        (let ((string (make-string number ?*)))
          (while (search-forward-regexp "^\\*" nil t)
            (insert string)))))))

At first you might be worried this would catch undesired edge cases, such as a #+SRC_BLOCK where one of the lines starts with a *. But org-mode itself uses this method to identify headlines, so no org buffer should ever contain a * as the first char of a line unless it's a headline.

  • I think it is more usual for functions to act on the (possibly narrowed) buffer when there is no region. Also why use of save-match-data in this specific function ? Most other functions/commands do not preserve the match data anyway. Lastly, in fact org uses "^\*+ " (aka org-outline-regexp-bol), i.e. there must be a space after the stars. – YoungFrog Feb 20 '15 at 16:23
  • It's not necessary to manually search for the org-mode headlines. There is an API for this and you can use the function org-map-tree like in this example from the Emacs wiki: orgmode.org/worg/org-hacks.html#orgheadline9 – Uwe Koloska Nov 18 '15 at 23:56
5

If I understand it correctly, you have a list of subtrees

* A
** A1
*** A1a
* B
** B1

and want to insert them into another subtree

* First
** First Sub
* Second

at the right level:

* First
** First Sub
*** A
**** A1
***** A1a
*** B
**** B1
* Second

As this is Emacs (and org-mode of course), there is a function for this ;-)

Just use org-paste-subtree like so:

  1. save your new list in the kill ring (select and M-w)
  2. enter *** after First Sub
  3. call org-paste-subtree

The function is described as

Paste the clipboard as a subtree, with modification of headline level.

and will work for demoting and promoting the subtree in the kill ring.

org-mode can even be configured to use this style of yank every time a subtree is yanked into a subtree. Customize the variable org-yank-adjusted-subtrees and you can use C-y instead of org-paste-subtree in the example above.

For me this was especially useful when I wanted to promote all subtrees under one toplevel.

1

The problem you described can also be solved with the functions outline-promote and outline-demote.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.