Skip to content

Instantly share code, notes, and snippets.

@mskorzhinskiy
Created April 22, 2020 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mskorzhinskiy/7e7d8c39f7b7e4dc73a3c8eb6b2422e1 to your computer and use it in GitHub Desktop.
Save mskorzhinskiy/7e7d8c39f7b7e4dc73a3c8eb6b2422e1 to your computer and use it in GitHub Desktop.
Customized navigation for org-mode
;; New navigation/edition
(defmacro org-user/save-state (&rest body)
"Helper for executing BODY with macroses."
(declare (debug (body)))
`(save-excursion
(save-restriction
(org-save-outline-visibility nil
,@body))))
(defun org-user/current-headline-level ()
"Get current headline level."
(let ((element (org-element-at-point)))
(when element
(getf (getf element 'headline) :level))))
(defun org-user/narrow-to-content ()
"Narrow to content."
(interactive)
(let ((end))
(save-excursion
(save-restriction
(org-narrow-to-element)
(outline-next-heading)
(setq end (point))))
(narrow-to-region (point) end)))
(defun org-user/fold-all-items ()
"Fold all items in item list."
(interactive)
(let ((eos (save-excursion (org-end-of-subtree t t)
(when (bolp) (backward-char)) (point))))
(save-excursion
(org-back-to-heading)
(while (org-list-search-forward (org-item-beginning-re) eos t)
(beginning-of-line 1)
(let* ((struct (org-list-struct))
(prevs (org-list-prevs-alist struct))
(end (org-list-get-bottom-point struct)))
(dolist (e (org-list-get-all-items (point) struct prevs))
(org-list-set-item-visibility e struct 'folded))
(goto-char (if (< end eos) end eos)))))))
(defun org-user/item-list-find-in-content ()
"Goto down to next item list."
(catch 'found
(org-user/save-state
(org-user/narrow-to-content)
(org-show-all)
(while (not (eobp))
(when (org-at-item-p)
(throw 'found (point)))
(forward-line)
(beginning-of-line)))))
(defun org-user/jump-to-item-list ()
"Jump to nearest item list."
(let ((found (org-user/item-list-find-in-content)))
(when found
(goto-char found)
(org-show-set-visibility 'minimal)
(org-user/fold-all-items))
found))
(defun org-user/jump-to-child ()
"Jump to nearest child item."
(let ((level (org-user/current-headline-level))
should-go)
(save-excursion
(outline-next-heading)
(setq should-go (< level (org-user/current-headline-level))))
(when should-go
(org-show-children)
(outline-next-heading))))
(defun org-user/show-item ()
"Default function for showing item."
(outline-hide-subtree)
(outline-show-entry)
(outline-show-children)
(org-user/fold-all-items)
(when (org-at-item-p)
(org-list-set-item-visibility
(point-at-bol) (org-list-struct) 'children)))
(defun org-user/up ()
"Goto to upper item."
(interactive)
(cond
((org-at-item-p) (org-previous-visible-heading 1))
((org-at-heading-p) (org-up-heading-safe))
(t (outline-previous-heading)))
(org-user/show-item))
(defun org-user/down ()
"Goto down hierarhy."
(interactive)
(cond ((org-at-heading-p)
(unless (org-user/jump-to-item-list)
(unless (org-user/jump-to-child)
(org-forward-paragraph)
(org-indent-line)))
(org-user/show-item))))
(defun org-user/next ()
"Go to next thing."
(interactive)
(cond
;; Item
((org-at-item-p)
(let ((struct (org-list-struct)))
(org-list-set-item-visibility
(point-at-bol) struct 'folded)
(org-next-item)
(org-list-set-item-visibility
(point-at-bol) struct 'children)))
;; Heading
((org-at-heading-p)
(outline-hide-subtree)
(outline-forward-same-level 1)
(org-user/show-item))
;; Content \ out of hierarchy
(t (forward-line 1))))
(defun org-user/prev ()
"Go to next thing."
(interactive)
(cond
;; Item
((org-at-item-p)
(let ((struct (org-list-struct)))
(org-list-set-item-visibility
(point-at-bol) struct 'folded)
(org-previous-item)
(org-list-set-item-visibility
(point-at-bol) struct 'children)))
;; Heading
((org-at-heading-p)
(outline-hide-subtree)
(outline-backward-same-level 1)
(org-user/show-item))
;; Content \ out of hierarhy
(t (forward-line -1))))
;; Each keybinding folds item under the point and unfolds next item, but only
;; 1-level deep. Item can be anything: headline or item list.
(define-key org-mode-map (kbd "C-c C-n") #'org-user/next)
(define-key org-mode-map (kbd "C-c C-p") #'org-user/prev)
;; Up acts as universal "up". With headline or item under the point will jump to
;; the parent. But will jump to the current headline if pointer is on the
;; headline contents.
(define-key org-mode-map (kbd "C-c C-b") #'org-user/up)
;; Down will jump to the nearest "child" thing. In that order:
;; 1. If there are item lists in current headline, it will jump to the head of the item list;
;; 2. If there are children headlines, it will jump to the first child headline;
;; 3. If there are nothing, it will jump to the contents;
(define-key org-mode-map (kbd "C-c C-f") #'org-user/down)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment