How to use org-tree-to-indirect-buffer and turn off org-indent-mode in the new indirect buffer, with a toggle to go back, all in a single key binding?

I like using org-mode as a distraction free text editor.

I also like using org-indent-mode when navigating my entire file.

I also like using org-tree-to-indirect-buffer to focus on a desired section of text. Doing this makes org-indent-mode rather unnecessary however, as I'm usually working at the lowest level and thus the indent is just empty space where I could have more text on the screen.

After turning off org-indent-mode manually for a while I tried to come up with a single shortcut to toggle both commands at once.

I tried:

;; custom org to indirect buffer, toggling off indent-mode for the new indirect buffer
(defun my-org-to-indirect-buffer ()
"Run some-command' and some-other-command' in sequence."
(interactive)
(org-tree-to-indirect-buffer)
(org-indent-mode)
)

(global-set-key (kbd "C-f") 'my-org-to-indirect-buffer)


Not only does this fail to toggle off org-indent-mode in the indirect buffer, it also messes with the original buffer, so I have to manually toggle org-indent-mode off and on before it works again. I get this happens because the second command triggers after killing the indirect buffer, yet it doesn't behave as I'd expect and just turn off the mode, as my mode-line still displays it running. Clearly there's something going on I'm missing.

How would I open an indirect buffer and toggle off org-indent-mode in a single keypress, with a second keypress undoing the changes, reverting back to my main buffer with org-indent-mode on?

Two problems:

• org-indent-mode is a minor mode and like all minor modes is enabled by calling with a positive argument and disabled by calling it with a negative argument - see its doc string with C-h f org-indent-mode. So you have to call it like this: (org-indent-mode -1) to disable it.

• org-to-tree-indirect-buffer leaves the current buffer unchanged, i.e. that of the original Org mode file. However, you need to turn off org-indent-mode not in the original buffer but in the generated indirect buffer. Fortunately, it saves that indirect buffer in the global variable org-last-indirect-buffer, so you can use with-current-buffer to temporarily switch to the indirect buffer and disable org-indent-mode there.

The final form of the function would then look like this (EDIT: the fontification of the buffer was lost when executing the original form of the following function, so I added an explicit call to font-lock-fontify-buffer to restore it, although this is probably a workaround, not the real solution. However, I still cannot reproduce the OP's problem where he loses org-indent-mode in the original buffer) /EDIT):

(defun my-org-to-indirect-buffer ()
"Run some-command' and some-other-command' in sequence."
(interactive)
(org-tree-to-indirect-buffer)
;; turn off org-indent-mode in the indirect buffer
(with-current-buffer org-last-indirect-buffer (org-indent-mode -1))
;; the original buffer loses fontification for some reason, so we restore it explicitly
(font-lock-fontify-buffer))


One more problem might be the key binding: why do you bind it in the global map? Presumably you only need it in an Org mode buffer, so why not restrict it to the mode-specific keymap? Something like this:

(define-key org-mode-map (kbd "C-c f") #'my-org-to-indirect-buffer)

• This does seem much closer to a solution, yet after using it to make and close an indirect buffer I still have to manually toggle org-indent-mode off and on for everything to return to normal on the original buffer. As for the keybindings, I just use global bindings because I literally only use emacs for org-mode, but you raise a good point. Jul 11 at 6:53
• I cannot reproduce the problem. The original buffer is not touched, so org-indent-mode is never turned off in it. I would suggest you restart emacs if you did not that already: there may be something curdled from your previous experimentation in the original session. Also make sure to clean up your init file if you had added your modification to it, before adding the above. If you still have a problem, please edit your question and add a step-by-step process of what you are doing, so I can try to reproduce it. Jul 11 at 13:04
• I was afraid of that, thanks. I'll see if I can find the problem by commenting out the various tweaks I've implemented. Don't really want to start fresh for this one small issue, even if I probably could create a cleaner setup now. I'll open a new question if needed, focused on what might be interacting with indent mode like that. Jul 11 at 14:21
• No doubt: tinkering with the init.el file is a lifelong pursuit :-) But I meant just cleaning up the stuff you might have added for this problem only. BTW, one good way to find out if your init file has a problem is to run emacs -q which starts emacs without any of your customizations. A common general recommendation is that if that resolves whatever problem you are having, you can bisect your init file to figure out which part of it causes the problem. Jul 11 at 17:51
• Well, in an absolutely blank init.el file, just your code, I still see the same odd behavior. The original buffer looses indent mode, as well as fontify/emphasis on all text, yet the fontify/emphasis will appear on any new text as expected. Disabling the not-functioning indent mode will re-enable fontify/emphasis on all text, then enabling indent mode obviously re-enables indent mode. Not really sure what to make of that. Jul 11 at 17:56

Big thanks to NickD for setting me on the right path.

Indeed, the error message "Not enabling jit-lock: it does not work in indirect buffer" is key to this problem.

When looking up that error message in jit-lock.el, we find this comment:

    ;; We're in an indirect buffer, and we're turning the mode on.
;; This doesn't work because jit-lock relies on the fontified'
;; text-property which is shared with the base buffer.


In essence, we can't alter the fontified state of the indirect buffer, just the main buffer. The same seems to hold true for org-indent-mode, or at least it does in my setup for whatever reason.

Thus, to create a toggle we need to turn off and on org-indent-mode via the original buffer, not the indirect copy.

;; custom org to indirect buffer
(defun my-org-to-indirect-buffer ()
(interactive)
(if (buffer-live-p org-last-indirect-buffer)
; if the org indirect buffer is active
(with-current-buffer (buffer-base-buffer) (org-indent-mode 1)
(message "Enabled org-indent-mode"))
; then turn back on indent mode, because we're closing the indirect buffer
(org-indent-mode -1) (message "Disabled org-indent-mode"))
; else turn indent mode off, because we're opening the indirect buffer
(org-tree-to-indirect-buffer)
)

(define-key org-mode-map (kbd "C-f") #'my-org-to-indirect-buffer)
; org-mode specific key binding for an org-mode specific function


Still, this isn't perfect, as it only allows for one indirect buffer at a time. Trying to use the command on any other buffer while the first indirect buffer is open doesn't work and gives the error save-current-buffer: Wrong type argument: stringp, nil` which I don't really know what to do with. Yet it does what I set out to do, so I'll consider it a win. If someone feels like making a more universal function though I'll happily mark their answer as the best instead.