Fold and Focus — Focused navigation in Org, Markdown, and Elisp (Emacs package)
Below you find the latest version of (1) the package's README and (2) its main source file.
You may also want to read:
For the git repository and issues tracker, see the project's page on sr.ht.
For more packages, see Software.
README.org
(Note: if you're seeing this as a local README.org
instead of online as HTML, the animated gifs may not be rendered properly, and the images may be altogether missing.)
Overview
Fold and Focus helps you navigate Org, Markdown, and Emacs Lisp files with focused attention: one thing at a time.
Regular

Whenever you move forward or backward, it:
- Folds everything.
- Expands only the body of the heading you’re currently in.
- (Optionally narrow to this subtree.)
- Keeps the heading always at a fixed distance from the top of the window.
(default: 2 lines when not narrowed, but you can change that).
Narrowing
In all modes, you can optionally also narrow to the subtree you’re currently in.

This can be done with:
- regular narrowing, which will actually try recursive-narrowing, if you have it; or
- fancy-narrowing
Neither of these external packages is required if you are satisfied with regular narrowing or non-narrowing.
Installation
See my page Software for the most up-to-date instructions on how to download and install any of my Emacs packages.
Having downloaded and installed the package and its dependencies, adapt the configurations below to your init.el
file.
fold-and-focus
Previous recommendation
In previous versions, you had to map keys yourself — like this:
(use-package fold-and-focus :demand t :after org :bind (;; Add fold-and-focus keys to this keymap :map org-mode-map ("M-[" . fold-and-focus-previous) ("M-]" . fold-and-focus-next) ("s-{" . fold-and-focus-previous-reg) ("s-}" . fold-and-focus-next-reg) ("s-[" . fold-and-focus-previous-fancy) ("s-]" . fold-and-focus-next-fancy)))
The minor modes simplify that, and keys come pre-defined in fold-and-focus
keymaps. See below.
Current recommendation
You can now simply enable minor modes.
To enable the three globalized minor modes, add this fold-and-focus
declaration to your init.el
:
(use-package fold-and-focus :demand t :config (global-fold-and-focus-org-mode) (global-fold-and-focus-md-mode) (global-fold-and-focus-el-mode))
They'll autodetect the mode you're in, and default navigation keys will be available.
org
You may want to add these to the customizable variable org-speed-commands
:
("[" fold-and-focus-previous) ("]" fold-and-focus-next) ("{" fold-and-focus-previous-reg) ("}" fold-and-focus-next-reg) (";" fold-and-focus-previous-fancy) ("'" fold-and-focus-next-fancy)
These keys only work when you are at the beginning of a heading:
- asterisks when in Org
- 3+ semicolons when in Emacs Lisp with Outshine.
outshine
The Outshine package is no longer needed to fold-and-focus
in Emacs Lisp.
But if you use it, its use-package
declaration needs to have something like this:
(use-package outshine :demand t :after (:or outline org-mode) :hook ((emacs-lisp-mode lisp-mode) . outshine-mode))
And then you can add commands to outshine-speed-commands-user
:
("[" . fold-and-focus-previous) ("]" . fold-and-focus-next) ("{" . fold-and-focus-previous-reg) ("}" . fold-and-focus-next-reg)
The non-speed versions of these commands are already provided by fold-and-focus-el-mode
, and should therefore be automatically available.
Notes about fancy-narrow
Possible bug when saving
Do you use fancy-narrow
? Then you may see a bug when saving buffers while fancy-narrowed.
In this case, you may want to try the following command and advice:
(defun fold-and-focus-save-buffer-detecting-fancy-narrow (orig-fun &optional args) "Detect if you're fancy-narrowed before saving. If so, then fancy-widen, save, and fancy-narrow again." (interactive) (if (not (and (fboundp 'fancy-narrow-active-p) (fancy-narrow-active-p))) (apply orig-fun args) (save-excursion (let ((b fancy-narrow--beginning) (e fancy-narrow--end)) (prog2 (fancy-widen) (apply orig-fun args) (fancy-narrow-to-region b e)))))) (advice-add 'save-buffer :around #'fold-and-focus-save-buffer-detecting-fancy-narrow)
If that works for you, add it to your init.el
.
Lack of support
You should know that fancy-narrow
is an unsupported package that hasn't been updated by Artur Malabarba since 2017.
Yet it works well for me. I like it and still use it.
This is why I include it in fold-and-focus
as an option.
That said, non-narrowing and regular-narrowing don't require fancy-narrow
, and are more stable options for fold-and-focus
navigation.
Contributing
See my page Software for information about how to contribute to any of my Emacs packages.
News
1.3.0
Fold and Focus News
This release brings smoothier navigation at document boundaries.
Moreover, Emacs Lisp comments subtrees navigation no longer depends on the Outshine package.
New features
Removed dependencies
Until now, to fold-and-focus
Emacs Lisp comments subtrees you needed the minor mode provided by outshine
. This is no longer the case.
Yet note that you'll need a proper outline-regexp
for the navigation to work. Read Navigating elisp comment headings for some options.
Fixes
Smooth navigation at document boundaries (#1) (#2)
Now when you fold-and-focus
all the way to the beginning or end of a document, the response is more predictable, and you can smoothly stop or go back to where you came from. And if you were navigating narrowed, the buffer will widen if you try to go beyond the first or last subtree.
With these improvements, two open bugs got fixed.
1.2.0
This release brings three minor modes and their globalized versions.
They autodetect if you are in Org, Markdown, or Emacs Lisp (with Outshine).
If so, default keybindings are enabled for focused navigation.
New features
New minor modes
This release brings these new minor modes:
(&optional arg)
Enable subtree navigation keys when in markdown-mode
or derived.
1.1.0
Fold and Focus News
This release adds Markdown support.
It also adds support for derived modes.
So you can now enjoy focused navigation when in:
org-mode
and derivedmarkdown-mode
and derived (includinggfm-mode
)emacs-lisp-mode
and derived (ifoutshine-mode
is on)
1.0.0
Fold and Focus Breaking News
To help preserve separation of namespaces, the prefixes of Fold and Focus's functions and variables have all changed from fnf-
to fold-and-focus-
.
There's nothing to do if:
- this is your first install of Fold and Focus or
- you haven't customized any variables, nor bound keys
If, however, you have added anywhere (for example, in your init.el) settings that use the old prefix, simply update them to use the new prefix. Just replace fnf-
with fold-and-focus-
.
You may also want to have a look at customizations you may have made in Fold and Focus group. Use either of:
- M-x
customize-group
RETfold-and-focus
RET (customize-group "fold-and-focus") ;<--C-x C-e
Note: The old symbols have for now been marked as obsolete and aliased to the new ones to avoid any sudden breakage. However, these aliases may be removed without further notice. So if any of the adjustments above apply to you, better do them already, before new releases.
License
This project follows the REUSE Specification (FAQ), which in turn is built upon SPDX.
Therefore, license and copyright information can be found in:
- each file's comment header, or
- an adjacent file of the same name with the additional extension
.license
, or - the
.reuse/dep5
file
The full text of the licenses can be found in the LICENSES
subdirectory.
fold-and-focus.el
Structure
;;; fold-and-focus.el --- Focused navigation in Org, Markdown, and Elisp -*- lexical-binding: t -*- ;;; Commentary: ;;;; For all the details, please do see the README ;;; Acknowledgments: ;;; Code: ;;;; Libraries ;;;; Obsolete symbols ;;;; Symbols from other packages ;;;; Package metadata ;;;; Customizable variables ;;;; Functions ;;;;; Auxiliary ;;;;;; Maybe widen ;;;;;; Check whether valid mode ;;;;;; Check if first or last subtrees ;;;;; Core ;;;;;; Specific to Org ;;;;;; Specific to Markdown ;;;;;; Specific to Emacs Lisp ;;;;;; For all modes ;;;;; Navigation commands ;;;;;; by subtree: Emacs Lisp, Org, or Markdown ;;;;;; by defun: Emacs Lisp ;;;;; Minor modes ;;;;;; Auxiliary ;;;;;;; Parent keymaps ;;;;;; Org ;;;;;; Markdown ;;;;;; Emacs Lisp ;;;;; See README ;;;;; See News ;;;; Wrapping up ;;; fold-and-focus.el ends here
Contents
;;; fold-and-focus.el --- Focused navigation in Org, Markdown, and Elisp -*- lexical-binding: t -*- ;; SPDX-FileCopyrightText: © flandrew <https://flandrew.srht.site/listful> ;;--------------------------------------------------------------------------- ;; Author: flandrew ;; Created: 2021-06-11 ;; Updated: 2025-06-15 ;; Keywords: outlines, convenience ;; Homepage: <https://flandrew.srht.site/listful/software.html> ;;--------------------------------------------------------------------------- ;; Package-Version: 1.3.0 ;; Package-Requires: ((emacs "25.1")) ;;--------------------------------------------------------------------------- ;; SPDX-License-Identifier: GPL-3.0-or-later ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published ;; by the Free Software Foundation, either version 3 of the License, ;; or (at your option) any later version. ;; ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; ;; You should have received a copy of the GNU General Public License ;; along with this file. If not, see <https://www.gnu.org/licenses/>. ;;; Commentary: ;; ;; Fold and Focus helps you navigate Org, Markdown and Emacs Lisp files with ;; focused attention: one thing at a time. You can navigate by heading or ;; by defun, optionally narrowing to it as you go. ;; ;; As you navigate, the heading you move to will be recentered, so you'll ;; always have it at a fixed position. Its contents will be shown. ;; ;; The heading you came from will be folded and won't distract you. ;; ;;;; For all the details, please do see the README ;; ;; Open it easily with: ;; (find-file-read-only "README.org") <--- C-x C-e here¹ ;; ;; or from any buffer: ;; M-x fold-and-focus-see-readme ;; ;; or read it online: ;; <https://flandrew.srht.site/listful/sw-emacs-fold-and-focus.html> ;; ;; ¹ or the key that ‘eval-last-sexp’ is bound to, if not C-x C-e. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Acknowledgments: ;; ;; Outshine's ‘outshine-narrow-to-subtree’ was borrowed and simplified to ;; create the functions ‘fold-and-focus-fancy-narrow-to-el-subtree’ and ;; ‘fold-and-focus-narrow-to-el-subtree’. ;; ;; outshine ;; SPDX-FileCopyrightText: © Thorsten Jolitz and contributors ;; SPDX-License-Identifier: GPL-2.0-or-later ;; Author: Thorsten Jolitz ;; Homepage: <https://github.com/alphapapa/outshine> ;; ;; ------------------------------------------------------------------------ ;; ;; An older version of ‘org-narrow-to-subtree’ has been adapted to create the ;; function ‘fold-and-focus-fancy-narrow-to-org-subtree’, which in turn was ;; used for ‘fold-and-focus-fancy-narrow-to-md-subtree’, which adapts it to ;; markdown. (The org function is a bit different from the one used by the ;; fancy-narrow package, which copied it from ‘org-narrow-to-subtree’.) ;; ;; org ;; SPDX-FileCopyrightText: © Free Software Foundation, Inc. ;; SPDX-License-Identifier: GPL-3.0-or-later ;; Author: Carsten Dominik ;; Homepage: <https://orgmode.org> ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Code: ;;;; Libraries (require 'outline) (require 'lisp-mnt) ; ‘lm-summary’, ‘lm-homepage’, ‘lm-version’, ‘lm-header’ ;;;; Obsolete symbols (define-obsolete-function-alias 'fold-and-focus-fancy-narrow-to-subtree 'fold-and-focus-fancy-narrow-to-el-subtree "1.1.0") (define-obsolete-function-alias 'fold-and-focus-fold-and-show-children 'fold-and-focus-widen-maybe-and-hide "1.3.0") (define-obsolete-function-alias 'fold-and-focus-fold-and-read-previous-entry 'fold-and-focus-go-read-previous-entry "1.3.0") (define-obsolete-function-alias 'fold-and-focus-fold-and-read-next-entry 'fold-and-focus-go-read-next-entry "1.3.0") ;;;; Symbols from other packages ;; Silence "not known to be defined" compiler warnings (declare-function fancy-narrow-to-region "ext:fancy-narrow" (start end)) (declare-function fancy-widen "ext:fancy-narrow" ()) (declare-function markdown-back-to-heading "ext:markdown") (declare-function markdown-end-of-subtree "ext:markdown") (declare-function markdown-heading-at-point "ext:markdown") (declare-function org-at-heading-p "ext:org") (declare-function org-back-to-heading "ext:org") (declare-function org-end-of-subtree "ext:org") ;;;; Package metadata (defvar fold-and-focus--name "Fold and Focus") (defvar fold-and-focus--dot-el (format "%s.el" (file-name-sans-extension (eval-and-compile (or load-file-name buffer-file-name))))) (defvar fold-and-focus--readme-org (expand-file-name "README.org" (file-name-directory fold-and-focus--dot-el))) (defvar fold-and-focus--summary (lm-summary fold-and-focus--dot-el)) (defvar fold-and-focus--homepage (lm-homepage fold-and-focus--dot-el)) (defvar fold-and-focus--version (lm-with-file fold-and-focus--dot-el (or (lm-header "package-version") (lm-version)))) ;;;; Customizable variables (defgroup fold-and-focus nil (format "%s." fold-and-focus--summary) :group 'convenience :link '(emacs-library-link :tag "Lisp file" "fold-and-focus.el") :link `(file-link :tag "README.org" ,fold-and-focus--readme-org) :link `(url-link :tag "Homepage" ,fold-and-focus--homepage)) (defcustom fold-and-focus-recenter-position 2 "Number of lines from the top of the window where focused headings will be. It uses ‘recenter-top-bottom’, so a negative number will be interpreted as number of lines from the bottom of the window." :package-version '(fold-and-focus "1.0.0") :type 'integer) ;;;; Functions ;;;;; Auxiliary ;;;;;; Maybe widen (defun fold-and-focus-reg-widen-maybe () "Decide whether to widen." (when (buffer-narrowed-p) (if (fboundp 'recursive-widen) (recursive-widen) (widen)))) (defun fold-and-focus-fancy-widen-maybe () "Decide whether to ‘fancy-widen’." (and (fboundp 'fancy-narrow-active-p) (fancy-narrow-active-p) (fancy-widen))) ;;;;;; Check whether valid mode (defun fold-and-focus-check-my-mode (&optional function-name) "Check whether fold-and-focus will work in this mode. Optionally, give a FUNCTION-NAME in the error message." (or (derived-mode-p 'org-mode) (derived-mode-p 'markdown-mode) (derived-mode-p 'emacs-lisp-mode) (user-error (concat "To use %s, your mode must be " "org, markdown, emacs-lisp, or " "derived from them") (or function-name "this command")))) ;;;;;; Check if first or last subtrees (defun fold-and-focus--find-heading (count) "Search COUNT headings forwards, or return nil." (re-search-forward (format "^\\(?:%s\\)" outline-regexp) nil t count)) (defun fold-and-focus--before-1st-p () "Is this before the first heading?" (save-excursion (goto-char (line-end-position)) (null (fold-and-focus--find-heading -1)))) (defun fold-and-focus--1st-p () "Is this the first subtree?" (save-excursion (goto-char (line-end-position)) (when (fold-and-focus--find-heading -1) (null (fold-and-focus--find-heading -1))))) (defun fold-and-focus--last-p () "Is this the last subtree?" (save-excursion (goto-char (line-end-position)) (null (fold-and-focus--find-heading 1)))) ;;;;; Core ;;;;;; Specific to Org (defun fold-and-focus-fancy-narrow-to-org-subtree () "Fancy-narrow to the current org subtree. Use the command `\\[fancy-widen]' to see the whole buffer again." (interactive) (save-excursion (save-match-data (fancy-narrow-to-region (progn (org-back-to-heading t) (point)) (progn (org-end-of-subtree t t) (and (org-at-heading-p) (not (eobp)) (backward-char 1)) (point)))))) (defun fold-and-focus--read-entry-org (&optional narrow-option) "Focus on Org entry to read it. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (pcase narrow-option (:reg (when (fboundp 'org-narrow-to-subtree) (if (fboundp 'recursive-narrow-or-widen-dwim) (recursive-narrow-or-widen-dwim) (org-narrow-to-subtree)))) (:fancy (when (fboundp 'fancy-narrow-to-region) (fold-and-focus-fancy-narrow-to-org-subtree)))) (unless (bound-and-true-p org-sticky-header-mode) (when (fboundp 'org-display-outline-path) (org-display-outline-path)))) ;;;;;; Specific to Markdown (defun fold-and-focus-fancy-narrow-to-md-subtree () "Fancy-narrow to the current markdown subtree. Use the command `\\[fancy-widen]' to see the whole buffer again." (interactive) (save-excursion (save-match-data (fancy-narrow-to-region (progn (markdown-back-to-heading t) (point)) (progn (markdown-end-of-subtree t) (and (markdown-heading-at-point) (not (eobp)) (backward-char 1)) (point)))))) (defun fold-and-focus--read-entry-md (&optional narrow-option) "Focus on Markdown entry to read it. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (pcase narrow-option (:reg (when (fboundp 'markdown-narrow-to-subtree) (if (fboundp 'recursive-narrow-save-position) (recursive-narrow-save-position (markdown-narrow-to-subtree)) (markdown-narrow-to-subtree)))) (:fancy (when (fboundp 'fancy-narrow-to-region) (fold-and-focus-fancy-narrow-to-md-subtree))))) ;;;;;; Specific to Emacs Lisp (defun fold-and-focus-narrow-to-el-subtree () "Narrow to the current elisp comments subtree. Use the command ‘\\[widen]’ to see the whole buffer again." (interactive) (outline-mark-subtree) (when (use-region-p) (narrow-to-region (region-beginning) (region-end))) (deactivate-mark)) (defun fold-and-focus-fancy-narrow-to-el-subtree () "Fancy-narrow to the current elisp comments subtree. Use the command ‘\\[fancy-widen]’ to see the whole buffer again." (interactive) (outline-mark-subtree) (when (use-region-p) (fancy-narrow-to-region (region-beginning) (region-end))) (deactivate-mark)) (defun fold-and-focus--read-entry-el (&optional narrow-option) "Focus on Emacs Lisp entry to read it. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (pcase narrow-option (:reg (fold-and-focus-narrow-to-el-subtree)) (:fancy (when (fboundp 'fancy-narrow-to-region) (fold-and-focus-fancy-narrow-to-el-subtree))))) (defun fold-and-focus-read-defun (&optional narrow-option) "In Emacs Lisp mode, focus on defun to read it. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (recenter-top-bottom fold-and-focus-recenter-position) (pcase narrow-option (:reg (if (fboundp 'recursive-narrow-to-defun) (recursive-narrow-to-defun) (narrow-to-defun))) (:fancy (when (fboundp 'fancy-narrow-to-defun) (fancy-narrow-to-defun))))) (defun fold-and-focus-read--goto-defun (e b &optional narrow-option) "Go to defun ending in E and beginning in B. If NARROW-OPTION is :reg, try to widen first." (fold-and-focus-fancy-widen-maybe) (pcase narrow-option (:reg (fold-and-focus-reg-widen-maybe))) (end-of-defun e) (beginning-of-defun b) (when (outline-invisible-p) (outline-show-entry) (end-of-defun e) (beginning-of-defun b)) (fold-and-focus-read-defun narrow-option)) ;;;;;; For all modes (defun fold-and-focus-widen-maybe-and-hide (&optional narrow-option) "Fold and show children. If NARROW-OPTION is :reg, try to widen first." (fold-and-focus-fancy-widen-maybe) (pcase narrow-option (:reg (fold-and-focus-reg-widen-maybe))) (outline-back-to-heading) (outline-hide-subtree)) (defun fold-and-focus-read-entry (&optional narrow-option) "Focus on entry to read it. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (outline-hide-subtree) (outline-show-children) (outline-show-entry) (recenter-top-bottom fold-and-focus-recenter-position) (cond ((derived-mode-p 'org-mode) (fold-and-focus--read-entry-org narrow-option)) ((derived-mode-p 'markdown-mode) (fold-and-focus--read-entry-md narrow-option)) ((derived-mode-p 'emacs-lisp-mode) (fold-and-focus--read-entry-el narrow-option)))) (defun fold-and-focus-go-read-previous-entry (&optional narrow-option) "Go read previous entry. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (if (fold-and-focus--before-1st-p) (message "Before first heading") (fold-and-focus-widen-maybe-and-hide narrow-option) (if (fold-and-focus--1st-p) (message "No previous subtree") (outline-previous-visible-heading 1) (fold-and-focus-read-entry narrow-option)))) (defun fold-and-focus-go-read-next-entry (&optional narrow-option) "Go read next entry. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (if (fold-and-focus--before-1st-p) (progn (outline-next-visible-heading 1) (fold-and-focus-read-entry narrow-option)) (fold-and-focus-widen-maybe-and-hide narrow-option) (if (fold-and-focus--last-p) (message "No next subtree") (outline-show-children) (outline-next-visible-heading 1) (fold-and-focus-read-entry narrow-option)))) ;;;;; Navigation commands ;;;;;; by subtree: Emacs Lisp, Org, or Markdown ;;;###autoload (defun fold-and-focus-previous () "Fold all, read previous entry. No further narrowing." (interactive) (fold-and-focus-check-my-mode this-command) (fold-and-focus-go-read-previous-entry)) ;;;###autoload (defun fold-and-focus-next () "Fold all, read next entry. No further narrowing." (interactive) (fold-and-focus-check-my-mode this-command) (fold-and-focus-go-read-next-entry)) ;;;###autoload (defun fold-and-focus-previous-reg () "Fold all, read previous entry. Narrow to it (recursively, if possible)." (interactive) (fold-and-focus-check-my-mode this-command) (fold-and-focus-go-read-previous-entry :reg)) ;;;###autoload (defun fold-and-focus-next-reg () "Fold all, read next entry. Narrow to it (recursively, if possible)." (interactive) (fold-and-focus-check-my-mode this-command) (fold-and-focus-go-read-next-entry :reg)) ;;;###autoload (defun fold-and-focus-previous-fancy () "Fold all, read previous entry. Fancy-narrow to it." (interactive) (fold-and-focus-check-my-mode this-command) (fold-and-focus-go-read-previous-entry :fancy)) ;;;###autoload (defun fold-and-focus-next-fancy () "Fold all, read next entry. Fancy-narrow to it." (interactive) (fold-and-focus-check-my-mode this-command) (fold-and-focus-go-read-next-entry :fancy)) ;;;;;; by defun: Emacs Lisp ;;;###autoload (defun fold-and-focus-read-previous-defun (&optional narrow-option) "In Emacs Lisp mode, move to the beginning of the previous defun. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (interactive) (fold-and-focus-read--goto-defun 1 2 narrow-option)) ;;;###autoload (defun fold-and-focus-read-next-defun (&optional narrow-option) "In Emacs Lisp mode, move to the beginning of the next defun. If NARROW-OPTION is :reg or :fancy, narrow accordingly." (interactive) (fold-and-focus-read--goto-defun 2 1 narrow-option)) ;;;###autoload (defun fold-and-focus-read-previous-defun-reg () "In Emacs Lisp mode, narrow to the beginning of the previous defun." (interactive) (fold-and-focus-read--goto-defun 1 2 :reg)) ;;;###autoload (defun fold-and-focus-read-next-defun-reg () "In Emacs Lisp mode, narrow to the beginning of the next defun." (interactive) (fold-and-focus-read--goto-defun 2 1 :reg)) ;;;###autoload (defun fold-and-focus-read-previous-defun-fancy () "In Emacs Lisp mode, fancy-narrow to the beginning of the previous defun." (interactive) (fold-and-focus-read--goto-defun 1 2 :fancy)) ;;;###autoload (defun fold-and-focus-read-next-defun-fancy () "In Emacs Lisp mode, fancy-narrow to the beginning of the next defun." (interactive) (fold-and-focus-read--goto-defun 2 1 :fancy)) ;;;;; Minor modes ;;;;;; Auxiliary ;;;;;;; Parent keymaps (defvar fold-and-focus-subtree-nav-map (let ((map (make-sparse-keymap))) (define-key map (kbd "M-[") #'fold-and-focus-previous) (define-key map (kbd "M-]") #'fold-and-focus-next) (define-key map (kbd "s-{") #'fold-and-focus-previous-reg) (define-key map (kbd "s-}") #'fold-and-focus-next-reg) (define-key map (kbd "s-[") #'fold-and-focus-previous-fancy) (define-key map (kbd "s-]") #'fold-and-focus-next-fancy) map) "Keymap for subtree navigation.") (defvar fold-and-focus-defun-nav-map (let ((map (make-sparse-keymap))) (define-key map (kbd "s-.") #'fold-and-focus-read-previous-defun) (define-key map (kbd "s-/") #'fold-and-focus-read-next-defun) (define-key map (kbd "s-:") #'fold-and-focus-read-previous-defun-reg) (define-key map (kbd "s-\"") #'fold-and-focus-read-next-defun-reg) (define-key map (kbd "s-;") #'fold-and-focus-read-previous-defun-fancy) (define-key map (kbd "s-'") #'fold-and-focus-read-next-defun-fancy) map) "Keymap for defun navigation.") ;;;;;; Org (defvar fold-and-focus-org-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map fold-and-focus-subtree-nav-map) map) "Keymap for Org mode navigation.") (defcustom fold-and-focus-org-mode-lighter " ⏿o" "Mode line lighter for ‘fold-and-focus-org-mode’. Either a string to display in the mode line when ‘fold-and-focus-org-mode’ is on, or nil to display nothing." :package-version '(fold-and-focus "1.2.0") :type '(choice (string :tag "Lighter" :value " ⏿o") (const :tag "Nothing" nil))) ;;;###autoload (define-minor-mode fold-and-focus-org-mode "Enable keys for ‘fold-and-focus’ in ‘org-mode’ or derived. See also ‘fold-and-focus-org-mode-lighter’ and ‘global-fold-and-focus-org-mode’." :init-value nil :lighter fold-and-focus-org-mode-lighter :keymap fold-and-focus-org-mode-map) (defun fold-and-focus--turn-on-org-mode () "Enable ‘fold-and-focus-org-mode’ globally." (when (derived-mode-p 'org-mode) (fold-and-focus-org-mode))) ;;;###autoload (define-globalized-minor-mode global-fold-and-focus-org-mode fold-and-focus-org-mode fold-and-focus--turn-on-org-mode) ;;;;;; Markdown (defvar fold-and-focus-md-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map fold-and-focus-subtree-nav-map) map) "Keymap for Markdown mode navigation.") (defcustom fold-and-focus-md-mode-lighter " ⏿m" "Mode line lighter for ‘fold-and-focus-md-mode’. Either a string to display in the mode line when ‘fold-and-focus-md-mode’ is on, or nil to display nothing." :package-version '(fold-and-focus "1.2.0") :type '(choice (string :tag "Lighter" :value " ⏿m") (const :tag "Nothing" nil))) ;;;###autoload (define-minor-mode fold-and-focus-md-mode "Enable keys for ‘fold-and-focus’ in ‘markdown-mode’ or derived. See also ‘fold-and-focus-md-mode-lighter’ and ‘global-fold-and-focus-md-mode’." :init-value nil :lighter fold-and-focus-md-mode-lighter :keymap fold-and-focus-md-mode-map) (defun fold-and-focus--turn-on-md-mode () "Enable ‘fold-and-focus-md-mode’ globally." (when (derived-mode-p 'markdown-mode) (fold-and-focus-md-mode))) ;;;###autoload (define-globalized-minor-mode global-fold-and-focus-md-mode fold-and-focus-md-mode fold-and-focus--turn-on-md-mode) ;;;;;; Emacs Lisp (defvar fold-and-focus-el-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map (make-composed-keymap fold-and-focus-defun-nav-map fold-and-focus-subtree-nav-map)) map) "Keymap for Emacs Lisp mode navigation.") (defcustom fold-and-focus-el-mode-lighter " ⏿e" "Mode line lighter for ‘fold-and-focus-el-mode’. Either a string to display in the mode line when ‘fold-and-focus-el-mode’ is on, or nil to display nothing." :package-version '(fold-and-focus "1.2.0") :type '(choice (string :tag "Lighter" :value " ⏿e") (const :tag "Nothing" nil))) ;;;###autoload (define-minor-mode fold-and-focus-el-mode "Enable keys for ‘fold-and-focus’ in ‘emacs-lisp-mode’ or derived. See also ‘fold-and-focus-el-mode-lighter’ and ‘global-fold-and-focus-el-mode’." :init-value nil :lighter fold-and-focus-el-mode-lighter :keymap fold-and-focus-el-mode-map) (defun fold-and-focus--turn-on-el-mode () "Enable ‘fold-and-focus-el-mode’ globally." (when (derived-mode-p 'emacs-lisp-mode) (fold-and-focus-el-mode))) ;;;###autoload (define-globalized-minor-mode global-fold-and-focus-el-mode fold-and-focus-el-mode fold-and-focus--turn-on-el-mode) ;;;;; See README ;;;###autoload (defun fold-and-focus-see-readme (&optional heading narrow) "Open fold-and-focus's README.org file. Search for the file in fold-and-focus.el's directory. If found, open it read-only. If optional argument HEADING is passed, try to navigate to the heading after opening it. HEADING should be a string. If optional argument NARROW is non-nil, narrow to that heading. This argument has no effect if HEADING is nil or not found." (interactive) (let ((readme fold-and-focus--readme-org)) (if (file-exists-p readme) (let ((pr (make-progress-reporter (format "Opening %s ... " (abbreviate-file-name readme))))) (find-file-read-only readme) (when heading (fold-and-focus--goto-org-heading heading narrow)) (progress-reporter-done pr)) (message "Couldn't find %s's README.org" fold-and-focus--name)))) (defun fold-and-focus--goto-org-heading (heading &optional narrow) "Navigate to org HEADING and optionally NARROW to it." (let* ((hrx (format "^[*]+ %s" heading)) (pos (save-match-data (save-excursion (save-restriction (widen) (goto-char (point-max)) (re-search-backward hrx nil t 1)))))) (when pos (widen) (goto-char pos) (if (and narrow (fboundp 'org-narrow-to-subtree)) (org-narrow-to-subtree) (recenter-top-bottom 1)) (when (fboundp 'outline-show-subtree) (outline-show-subtree)) (when (fboundp 'org-flag-drawer) (save-excursion (forward-line 1) (org-flag-drawer t)))))) ;;;;; See News ;;;###autoload (defun fold-and-focus-see-news () "See the News in fold-and-focus's README.org file." (interactive) (fold-and-focus-see-readme "News" 'narrow) (fold-and-focus--display-org-subtree)) (defun fold-and-focus--display-org-subtree () "Selectively display org subtree." (let ((cmds '(outline-hide-subtree outline-show-children outline-next-heading outline-show-branches))) (and (fboundp (nth 0 cmds)) (fboundp (nth 1 cmds)) (fboundp (nth 2 cmds)) (fboundp (nth 3 cmds)) (mapc #'funcall cmds)))) ;;;; Wrapping up (provide 'fold-and-focus) ;; Local Variables: ;; coding: utf-8 ;; indent-tabs-mode: nil ;; sentence-end-double-space: nil ;; outline-regexp: ";;;;* " ;; End: ;;; fold-and-focus.el ends here