1

The Problem

Jump down to Update 1 below for my thoughts as to the chosen answer to this question.

I'm using Emacs version 26.3 with Org Mode version 9.3.6 installed from Melpa.

In the Org manual for Structure Editing, I read this:

   When there is an active region - i.e., when Transient Mark mode is
active - promotion and demotion work on all headlines in the region.  To
select a region of headlines, it is best to place both point and mark at
the beginning of a line, mark at the beginning of the first headline,
and point at the line just after the last headline to change.  Note that
when point is inside a table (see *note Tables::), the Meta-Cursor keys
have different functionality.

But when I make the transient Mark active and set both mark and point around more than one heading, type (org-shiftmetaleft), it only promotes the first or last heading, depending upon which one mark and point are on at the time. I want it to do what I think the above implies, and promote all headings in the region. Ditto for demoting headings.

Either this is a defect, or user error. Which is it? See MCVE below for details.

MCVE

Store the following setup.el file into an experiment directory, say, /tmp/org.mode.promote.demote.multiple.headings

(defun my-use-package-setup ()


  ;; Derived from
  ;; https://github.com/chrispoole643/etc/blob/master/emacs/.emacs.d/init.el
  ;; referenced by
  ;; https://www.reddit.com/r/emacs/comments/5sx7j0/how_do_i_get_usepackage_to_ignore_the_bundled/
  ;;
  ;; Define org and melpa as package sources, and install `use-package' if it's not
  ;; already there. Always ensure packages being loaded are there (or else it'll
  ;; automatically download from melpa)
  ;;
  ;; I don't want to do it this way, as it is org-mode specific. This ordering and
  ;; prioritization has to happen before all use of use-package. Without this,
  ;; we run the risk of some other package we require pulling in the stock
  ;; version of Org mode shipped with Emacs, when we only want the latest
  ;; version.
  ;;
  (require 'package)

  ;; For this MCVE, I _have_ to set package-user-dir below in order to keep my
  ;; installation separate from the normal one, so as to prove that I am only
  ;; installing the minimum set of packages to reproduce the issue for the MCVE:
  (setq package-user-dir (expand-file-name "/tmp/.emacs.d.tmp.99712ad4-61f4-4464-b003-d6d4eea9b98f"))

  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
  (add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)
  ;; Ensure that "org" and "melpa" are found first in this order (higher numbers are higher priority):
  (setq package-archive-priorities '(("org" . 3)
                                     ("melpa" . 2)
                                     ("gnu" . 1)))
  ;; This is the key!! -->  " The symbol ‘all’ says to load the latest installed
  ;; versions of all packages not specified by other elements." and for org-mode, this means always get that latest version.
  (setq package-load-list '(all))
  (package-initialize)

  ;; Not sure why we need this:
  (setq package-enable-at-startup nil)

  ;;
  ;; Install use-package unconditionally. For some reason the existing
  ;; use-package version failed so we have to waste initialization time doing it
  ;; every time, and cannot use this:
  ;;
  ;;   ;; Install use-package:
  ;;   (unless (package-installed-p 'use-package)
  ;;     (message "Installing use-package")
  ;;     (package-refresh-contents)
  ;;     (package-install 'use-package))
  ;;
  ;; Reason is unknown.
  ;;
  (package-refresh-contents)
  (package-install 'use-package)

  ;; Require use-package:
  (require 'use-package)

  ;; Load org mode early to ensure that the latest org mode version gets picked up, not the
  ;; shipped version.
  ;;
  ;;   Reference https://github.com/jwiegley/use-package#package-installation
  ;;
  (require 'use-package-ensure)
  (setq use-package-always-ensure t))

;;
;; Get the package ordering and priority for using use-package:
;;
;;   Unfortunately, order does matter here: We have to do this setup _before_
;;   any and all use of use-package.
;;
(my-use-package-setup)

;;
;; Get the org package:
;;
(use-package org
  ;; Install both org and "contrib"-uted org-related packages:
  ;;
  ;;    See https://tinyurl.com/y2gt69kj that indicates that org-plus-contrib
  ;;    seems to be some sort of "mashup" package, that includes both org itself
  ;;    and the so-called "contrib" packages. I'm not sure which ones of those
  ;;    contrib packages I actually use so just grab them all.
  ;;
  :ensure org-plus-contrib
  :pin org)

Launch emacs and load the above Elisp file under -Q conditions like this:

#!/bin/bash

exec 2>&1
set -x
experiment_dir='/tmp/org.mode.promote.demote.multiple.headings'
emacs -Q \
       --debug-init \
       --load $experiment_dir/setup.el \
       $experiment_dir/test.org

This will download the minimal amount of packages to retrieve the latest version of Org mode into a scratch directory at /tmp/.emacs.d.tmp.99712ad4-61f4-4464-b003-d6d4eea9b98f so you may choose remove that directory later.

Add the following lines into a small Org mode file:

* Level 1 heading
** Level 2 heading1
** Level 2 heading2
** Level 2 heading3

Move point in front of the first asterisk in the "Level 2 heading" line. Then use M-h (org-mark-element) three times to mark the next three headings. Then type (org-shiftmetaleft) and then only the first one, "Level 2 heading1", is promoted:

* Level 1 heading
* Level 2 heading1
** Level 2 heading2
** Level 2 heading3

I tried moving point right after the last "g" in "level 4 heading" and it promoted only the last one, ignoring the region completely:

* Level 1 heading
** Level 2 heading1
** Level 2 heading2
* Level 2 heading3

I've tried all sorts of things and never achieved the goal in this case which is to promote all three Level 2 headings into level 1:

* Level 1 heading
* Level 2 heading1
* Level 2 heading2
* Level 2 heading3

https://emacs.stackexchange.com/a/54301/15483 seems to imply that it should work and I have something broken in my org mode or something.

Update 1

If you look inside Structure Editing only see this:

‘M-<LEFT>’ (‘org-do-promote’)
     Promote current heading by one level.

‘M-<RIGHT>’ (‘org-do-demote’)
     Demote current heading by one level.

‘M-S-<LEFT>’ (‘org-promote-subtree’)
     Promote the current subtree by one level.

‘M-S-<RIGHT>’ (‘org-demote-subtree’)
     Demote the current subtree by one level.

The last paragraph I quoted at the top of this question does not indicate the scope of commands that respect the marked region. That led me to conclude the region applies to them all, which is not the case. Thus, the answer at https://emacs.stackexchange.com/a/56157/15483 is the correct answer.

I consider this to be a defect in the Org Manual, not in the behavior: This question will be out of date with new manuals if/when this defect is fixed.

1

Try M-right and M-left instead of M-S-right and M-S-left. The commands they run are as follows:

  • M-right: org-do-demote (deals with active region).
  • M-left: org-do-promote (deals with active region).
  • M-S-left: org-promote-subtree (just the subtree of the current heading - does not extend it to the active region).
  • M-S-right: org-demote-subtree (just the subtree of the current heading - does not extend it to the active region).

I think I got it wrong in the linked answer.

| improve this answer | |
  • Thanks NickD! I've added Update 1 to the end of my OP to clarify my further thoughts as to the defect. – bgoodr Mar 15 at 17:16

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.