changelog shortlog graph tags branches changeset files revisions annotate raw help

Mercurial > org > blog / draft/outlines.org

changeset 21: 1204cefcfd28
parent: 889759cafcc2
child: 6d54ccb29de4
author: Richard Westhaver <ellis@rwest.io>
date: Sat, 08 Jun 2024 00:21:48 -0400
permissions: -rw-r--r--
description: style updates
1 #+title: outlines
2 #+setupfile: ../../clean.theme
3 * Overview
4 Source code files are hard to manage. They can get unwieldly quickly and making the
5 wrong assumption about your whereabouts in the code tree can have unintended
6 consequences.
7 
8 There are many ways to solve this problem to different degrees. We'll be talking about
9 one strategy in particular which I use and recommend for any software project.
10 
11 Looking through the source code in the NAS-T repository you'll find some common
12 commenting patterns:
13 
14 - every file start with at least one comment line for example:
15 #+begin_src lisp
16 ;;; file-name.lisp --- file description
17 #+end_src
18 
19 - Before you see any code in a file, you'll likely encounter this line:
20 #+begin_src lisp
21 ;;; Code:
22 #+end_src
23 
24 - etc
25 
26 What's the deal here? To be clear, I'm of the mind that comments should be
27 significant. They should express to the reader something that is of a non-trivial nature
28 and 'where the code starts' doesn't quite qualify. Indeed, these comments don't fit that
29 model at all.
30 
31 The deal is that these comments aren't for the reader, they're for the developer. More
32 specifically, for the developer to treat as a special meta-language to describe the
33 structure of a source code file.
34 
35 * Outlines
36 Like all my good ideas, this one is credited entirely to Emacs. In this case, the
37 excellent [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Outline-Mode.html][Outline mode]]. If you are an Emacs user you've probably already used it without
38 knowing -- Org mode, for example, is [[https://git.savannah.gnu.org/cgit/emacs/org-mode.git/tree/lisp/org.el?h=release_9.6.9#n4789][derived from outline-mode]].
39 
40 I've grown quite fond of it. Here's the summary:
41 
42 #+begin_quote
43 Outline mode is a major mode derived from Text mode, which is specialized for editing
44 outlines. It provides commands to navigate between entries in the outline structure, and
45 commands to make parts of a buffer temporarily invisible, so that the outline structure
46 may be more easily viewed.
47 #+end_quote
48 -- [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Outline-Mode.html][GNU]]
49 
50 ** Quickstart
51 If you want to jump in right away, I recommend using these keybinds in Emacs:
52 
53 #+tblname: outline-keys
54 | <backtab> | outline-cycle-buffer |
55 | M-TAB | outline-cycle |
56 | M-n | outline-next-visible-heading |
57 | M-p | outline-previous-visible-heading |
58 
59 Here's a snippet which will enable the keybinds I use:
60 
61 #+name: enable-outline-keys
62 #+begin_src emacs-lisp
63 (let ((keys
64  '(("<backtab>" #'outline-cycle-buffer)
65  ("M-TAB" #'outline-cycle)
66  ("M-n" #'outline-next-visible-heading)
67  ("M-p" #'outline-previous-visible-heading))))
68  (cl-loop for (k fn) in keys
69  do (keymap-set outline-minor-mode-map k fn)))
70 #+end_src
71 
72 Now open a file in the [[../../src/][src]] directory, like [[../../src/fs/btrfs/btrfs.lisp][this]] one, enable =outline-minor-mode= and
73 move around the file with the new keybinds above.
74 
75 ** Outlines4All
76 Not all programming modes have outline support built-in. The good news is that it's easy
77 to enable it.
78 
79 You only need to modify one variable: =outline-regexp= and enable a minor-mode:
80 =outline-minor-mode=.
81 
82 *** Using dir-locals
83 The way it's done in the NAS-T codebase is with a [[../../.dir-locals.el][.dir-locals.el]] file.
84 
85 You just need to add this form for the mode of your choice, replacing the string
86 with a regular expression which matches on a /heading/. In this case we treat lines
87 starting with three comment chars or more as a new heading.
88 #+begin_src lisp-data
89 (makefile-mode . ((outline-regexp . "###+")))
90 #+end_src
91 
92 =outline-regexp= is declared as a safe local var, so no prompts will appear asking if
93 you trust these values. You will need to configure your keybinds and enable the
94 minor-mode separately though. For project-level support, that's all there is to it.
95 
96 *** Using init.el
97 You may also modify your config to enable =outline-minor-mode= for select major-modes at
98 startup. Here's a quick example from my config:
99 
100 #+begin_src emacs-lisp
101 ;;; Code:
102 (require 'default 'rw/fu)
103 
104 (defun outline-hook (rx)
105  "Enable `outline-minor-mode' and set `outline-regexp'."
106  (setq-local outline-regexp rx)
107  (outline-minor-mode t))
108 
109 (defun add-outline-hook (mode rx)
110  (let ((sym (symb mode "-hook")))
111  (add-hook sym (lambda () (outline-hook rx)))))
112 
113 (defmacro outline-hooks (&rest pairs)
114  `(mapc (lambda (x) (add-outline-hook (car x) (cadr x))) ',pairs))
115 
116 (outline-hooks (asm-mode ";;;+")
117  (nasm-mode ";;;+")
118  (rust-mode "\\(//!\\|////+\\)")
119  (sh-mode "###+")
120  (sh-script-mode "###+")
121  (makefile-mode "###+"))
122 
123 (provide 'outline-cfg)
124 ;;; outline-cfg.el ends here
125 #+end_src
126 ** Default Sections
127 Our default sections should look familiar - they're just Emacs Lisp defaults, with a few
128 choice extensions.
129 *** Source Header
130 First line of every source code file.
131 
132 Here is the prototype in lisp:
133 #+begin_src lisp
134 ;;; filename --- description -*- vars -*-
135 #+end_src
136 
137 In Rust we use:
138 #+begin_src rust
139 //! filename --- description -*- vars -*-
140 #+end_src
141 
142 etc.
143 **** Metadata :optional:
144 Some files may insert a blank line and start the =Code= heading, while others will
145 include some additional information about the file such as a long-description, version,
146 list of exports, etc.
147 *** Commentary :optional:
148 An optional programmer commentary included in source code files after the =Source
149 Header= but before the =Code=. The contents are unpredictable but may include notes,
150 todos, diagrams, stack notations, test results, links, tips, etc.
151 *** Code
152 The =Code= heading should be the final toplevel heading of any source code file. You
153 may see a number of sub-headings, starting with four or more comment chars.