numbex
is a minor mode for GNU Emacs that helps you manage numbered
examples and reference to them in your buffer. It is primarily aimed
at linguists, whose practice very often involves having example
sentences, formulas, or other objects given with a number that
uniquely identifies them in the text:
Consider these two examples: (1) One example. (2) Another example. If you look at (1)...
Now, this very good practice starts to get annoying when taking notes
in plain text. Say for instance that you want to switch the two
examples above, or that you want to add another example before them.
To keep things tidy and unambiguous you’d have to change the number of
every other example, and also the number of every reference! If you
make a mistake or you forget anything, you will end up with a mess and
there is no way to know what refers to what from the numbers alone.
numbex-mode
takes care of all this for you.
numbex
should work in any major mode, and in particular it should not
conflict with the default behavior of org-mode
. The fundamental idea
behind numbex
is that the buffer text proper doesn’t contain any
numbering itself, but only numbex items (that is, portions of buffer
content a certain form): the numbering is added to the buffer as text
properties. The command numbex-toggle-visibility
switches the buffer
back and forth from a state with and without the numbering.
There are no preset default keybindings, but it is a good idea to
define some for the two most common interactive commands: numbex-dwim
(aka “do what I mean”) and numbex-toggle-visibility
. The other
interactive commands, explained below, are numbex-list
,
numbex-refresh
, numbex-toggle-numbering-reset
,
numbex-convert-to-latex
, numbex-convert-from-latex
and
numbex-write-out-numbers
.
This use-package declaration illustrates all possible customizations:
(use-package numbex
:config
;; Set "M-n" as the prefix key for numbex commands
(define-key global-map (kbd "M-n") numbex-command-map)
:custom
(numbex-highlight-unlabeled t)
(numbex-highlight-duplicates t)
(numbex-numbering-reset t)
;; Enclose numbers between parentheses
(numbex-delimiters '("(" . ")"))
;; Restart numbering from "(1)" at each page break and at each top level
;; org-mode heading
(numbex-numbering-reset-regexps '("" "^\\* "))
:bind
(:map numbex-command-map
("RET" . numbex-dwim) ; new item or edit one at point
("s" . numbex-list) ; search items throuh 'occur'
("r" . numbex-toggle-numbering-reset)
("M-SPC" . numbex-toggle-visibility) ; show/hide underlying raw items
("M-p" . numbex-backward-example) ; jump to previous example
("M-n" . numbex-forward-example) ; jump to next example
("w" . numbex-write-out-numbers) ; replace items with their number
("g" . numbex-refresh)))
You can install numbex
via Melpa.
A “numbex item” is a buffer substring whose delimiters are {[
and
]}
, and whose body consist of a prefix and a label. The prefix
determines the kind of item:
Prefix | Type of item |
---|---|
ex: | Example (introduces a new label) |
rex: | Reference to an example |
pex: | Reference to immediately preceding example |
nex: | Reference to immediately following example |
The label is the substring after the prefix in the item. So for
instance {[ex:first]}
is an example item whose label is first
. Items
can be unlabeled: {[ex:]}
. There cannot be whitespace characters
inside an item: if you add any, they will be automatically removed.
(This is to make sure that an item never ends up broken in different
lines, which would cause numbex not to recognize the item anymore.)
numbex-previous-item
and numbex-next-item
are two commands that let
you jump quickly between example items.
While you can manipulate numbex items yourself (either manually or
programmatically), it is much more convenient to use the command
numbex-dwim
(more on this below).
The main command provided by numbex-mode is numbex-dwim
. How this
command behaves depends on whether it is invoked while point is on an
already existing item or not: in the former case, it will let you edit
the item, in the latter, you will be guided in creating a new one.
If point is not already on an item, numbex-dwim
will prompt the choice
of which item to create:
If you choose to create a reference, you will be offered completion with the labels that are already being used in the buffer, annotated with the context around the examples (the buffer content between the item and the end of the line where the item is).
{[ex:]} Odd example {[ex:second-example]} One example. {[ex:first-example]} Another example. {[ex:third]} Last example If you look at {[rex:second-example]} you will see that {[pex:]} and {[rex:]} resemble this sentence:
There is a caveat here: if there are two example items labeled with
xyz
in the buffer, only the first one will show up in the completion
selection involved in creating or editing a reference item.
If creating an example, if you choose a label that is already being used you will be asked to confirm your choice:
Evaluating numbex-dwim
while point is on an item (regardless of whether
labels are currently displayed or not) lets you change the label of
the item. Again, if it’s a reference, you will be able to use
completion on the existing labels (with annotation, showing you the
content of the examples). If you are editing pex:
or nex:
items, they
will be automatically converted in regular references. Finally, if
you edit an example by providing a novel label, you will be asked
whether you want to update the label of all the items that reference
that example automatically.
numbex
really tries its best to make sure you use unique labels. If,
in editing or creating a new example, you try to give it a label that
is not unique, you will be warned and asked whether you want to enter
a different one, stick with the non unique one (although that would be
a bad idea) or let numbex
make the label you wish unique by
automatically adding a numerical suffix.
The numbering of references depends on several factors. Labeled
reference items (like {[rex:first-example]}
) inherit the same number
as the corresponding example item (in this case,
{[ex:first-example]}
). Unlabeled ones (like {[rex:]}
) receive the
same number as the example item immediately preceding them.
The special reference items pex:
and nex:
, automatically receive an
uninformative label corresponding to the number they are assigned.
This is because numbex automatically assigns to them the same number
as the example that immediately precedes or follows them
(respectively). If the state of the buffer changes as to which
example precedes or follows them, their label will change accordingly.
This is why it would make no sense (and in a way it would be
confusing) them to have a label: if any label is found, numbex
will
remove it. However, if you edit a pex:
or nex:
item with numbex-dwim
,
it will be automatically converted in a regular reference item with
the new label you selected. So point is on {[pex:]}
, selecting
example as a label with numbex-dwim
will replace the item with
{[rex:example]}
.
Assuming that this is the whole buffer:
{[ex:]} Odd example {[ex:second-example]} One example. {[ex:first-example]} Another example. If you look at {[rex:second-example]} you will see that {[pex:]}...
this is how numbex
will number the items:
(1) Odd example. (2) One example. (3) Another example. If you look at (2) you will see that (3)...
All the interactive commands are listed below. The user can choose a
prefix for numbex-command-map
and then bind commands to keys in that
map.
numbex-dwim
numbex-list
numbex-refresh
numbex-forward-example
numbex-backward-example
numbex-toggle-visibility
numbex-toggle-numbering-reset
numbex-write-out-numbers
numbex-edit
numbex-new-item
numbex-new-example
numbex-new-reference
numbex-new-reference-to-previous
numbex-new-reference-to-next
How examples are numbered when numbex-mode
is first activated depends
on the value of the variable numbex-numbering-reset
(by default t
)
and by numbex-numbering-reset-regexps
(by default ("")
).
If numbex-numbering-reset
is nil
, examples, whether labeled or not,
are just numbered sequentially, starting with (1)
on the very first
example in the buffer. The counter never restarts from (1)
. The
value of numbex-numbering-reset
(a buffer-local variable) can be
switched interactively with the command
numbex-toggle-numbering-reset
.
The buffer-local variable numbex-numbering-reset-regexps
is a list of
regexps, each of which determines where the numbering should restart.
Its default value of ("")
means that the numbering only restarts at
page breaks. You can add to the list whatever regexp you want, and
you can assign a value as a file local variable. So for instance
having this magic comment at the bottom of the buffer will cause the
numbering to restart at each page break and at each 1st and 2nd level
org-mode heading:
;; Local Variables: ;; numbex-numbering-reset-regexps: ("" "^\\*\\*+ ") ;; End:
It is important to note that only the numbering is affected by
numbex-numbering-reset
. This means that labels have to be unique
across the buffer no matter how this variable is set, and that you can
always reference examples outside of the page or the narrowed
buffered, if you have the label, and that the number on such reference
will be the one that the example you are referencing has—and this
could cause local ambiguities (with relative numbering, there can be
several distinct examples in the buffer that are numbered with, say,
(1)
). Furthermore, since the information about the buffer is always
retrievable, you will always get the context of an example you are
referencing, even with relative numbering and when referencing an
example that is outside of the accessible portion of the buffer.
The variable numbex-delimiters
is a cons cell of strings determining
the appearance of the items. The default value is ("(" . ")")
, which
means that the numbers appear between parentheses. This value can be
set file locally. For example, if I want numbers to be between
brackets like [1]
, I can add:
;; Local Variables: ;; numbex-delimiters: ("[" . "]") ;; End:
When point is on an item, the underlying label is displayed in the echo area. If the item is a reference item, the echo area will also display the context of the corresponding example item (its line). This way, you will always have a clue as to what is referred to by the item at point:
Right after any invocation of numbex-dwim
you will be reminded of the
existence of duplicate labels (non-empty labels that are being used by
more than one example item) in the echo area:
These two features work even if the buffer is currently narrowed and the example item you are referring to or the duplicate label are outside of the narrowed portion of the buffer (that is, they are currently inaccessible). This way, the chances of you ending up with a mess once you widen the buffer again are minimized.
By default, numbex color-codes numbers corresponding to unlabeled items or to items with a non-unique label when the buffer is displaying the labels. This is done with whatever text property the current theme uses to mark comments and warnings (respectively).
{[ex:]} Odd example {[ex:second-example]} One example. {[ex:first-example]} Another example. If you look at {[rex:second-example]} you will see that {[pex:]} and {[rex:]} resemble this sentence: {[ex:second-example]} An example.
If you want to change this default behavior, set the variables
numbex-highlight-unlabeled
and/or numbex-highlight-duplicates
to
nil
.
You might want to export the notes you have maintained with numbex in
another plain text file where the numbers are actual text content
instead of text properties (for instance, you want to send a plain
text email with numbered examples). This is a destructive operation:
it will necessarily remove information that cannot be restored
(namely, the labels). Therefore, numbex-write-out-numbers
will save
the content of the buffer in a file (whose name is the name of the
current buffer prefixed by nb-
), where all the numbex items are
actually replaced by the numbers.
Finally, numbex-list
is a convenient wrapper around occur
that
lets you examine the items in the buffer: use it to have, in other
window, a grep-like overview of the lines that contain any item, any
example, any reference, any item with a non-unique label, any
unlabeled item, or, when evaluated when point is on an item, any item
with the same label as the item at point.
The numbering of items and the collection of information about labels
(duplicates etc.) is performed by numbex-refresh
. By default, this
operation is performed automatically if the current buffer is in
numbex-mode
at these moments:
- when
numbex-mode
is activated - every time Emacs is idle for 0.3 seconds (enough time not to be in the way of your typing), if the buffer has changed;
- when the buffer is saved or auto-saved;
- right after any time one of these functions is evaluated:
numbex-dwim
numbex-toggle-visibility
If you have less than a thousand numbex items in your buffer, you
shouldn’t notice any significant lag. If you have 500,
numbex-refresh
should take approximately 0.05 seconds, which makes
the process just about imperceptible.
However, if when you activate numbex-mode
more than 1000 numbex
items are found, you will be asked whether you want to disable
automatic refresh. If you disable it, numbex-refresh
will only be
evaluated when you save the buffer (or when it is auto-saved) and of
course when you interactively call it as a command. Regardless of
what you answer to that question, any time that there are more than
1000 numbex items in the buffer, numbex-refresh
won’t be evaluated
on the idle-timer every 0.3 seconds. It is unlikely, however, that
you will ever have this many examples and references in a single
buffer. If you plan to keep notes with more than ten thousand
items… it’s better if you don’t use numbex-mode
at all.