tagref can now be used with org-mode files

I recently contributed a patch to tagref that makes it play nicely with Emacs org-mode files. The PR has already been merged and the feature is available since version 1.12.0.
In this post I want to explain what the PR improves and show how tagref can be used in a project where internal/developer documentation in written in org-mode. But first, let me briefly introduce tagref.
What is tagref?
tagref is a command-line tool that helps manage "tags" and "references" in a project. The idea is based on cross-referencing code and documentation, inspired by the GHC notes system described in the Glasgow Haskell Compiler (ยง5.6) chapter of the AOSA book.
In short, you can annotate code (or text in any file) with a tag inside a comment:
1 2 3 4 5 | |
The tag can then be referenced elsewhere in the repository, such as a doc that explains why the particular edge case might happen or what the developer specifically needs to consider before changing that code.
1 2 3 | |
The same tag can be referenced in other files too. This way, different parts of code and docs become interconnected. When a developer comes across a ref they can quickly look up the tag, the associated notes as well as other references to get a holistic understanding of the code they are about to touch.
The tags and refs can be managed through a command-line interface provided by tagref to,
- list all tags and refs
- check that the referenced tags actually exist and that there are no duplicate tags
- list all unused tags
The check command can be run in a pre-commit hook or CI
pipeline. This helps catch drift between code and docs, which is quite
likely when internal documentation (architectural decision records,
how-to guides, troubleshooting guides, checklists etc.) lives
separately from the code.
Inside a monorepo (such as captrice's codebase), this kind of documentation and note-taking convention, along with the tagref tool, provides a decent system for annotating a source of truth (usually code, but sometimes a doc), and pointing back to it from other places in the repo. Markdown is probably the more popular format for such docs but I prefer to use org-mode, at least in my personal projects.
What did my PR solve?
Besides user defined tags, tagref also supports refs pointing to files and directories in the repository.
1 2 3 4 5 6 7 | |
The above example is taken from captrice's codebase. The
dev-docs/weekly-stats.org file documents optimizations and other
decisions about calculating and displaying weekly stats on the home
page.
The default sigil for file references is file: which happens to be
exactly the same as the bracket-link syntax that org-mode uses for
internal links. In org-mode, an internal link to another document can
be added as,
1 2 | |
However, org-mode expects the file path to be relative to the current
file, whereas tagref (prior to version 1.12.0) considers all paths to
be relative to the working directory. I'd been working around this by
specifying doc: as the custom file sigil, but there were
limitations:
-
The
--file-sigiloption had to be explicitly specified every time tagref was run, otherwise thecheckwould fail. -
Despite having cross referencing between org files, tagref's check command couldn't be leveraged to catch broken links.
PR #273 addresses
this by adding optional support for relative paths in file and
directory references. If the path is prefixed with special path
components such as ./, ../ and so on, it's considered relative to
the file that contains the reference. Otherwise it's considered
relative to the working directory (same as the original behavior,
which makes the change fully backward compatible).
For example,
-
[file:./weekly-stats.org]will be considered relative to the file in which it exists -
[file:weekly-stats.org]will be considered relative to the working directory
Preventing Emacs from normalizing relative paths
When editing org-mode files in Emacs, one almost never types out
bracket links by hand. Instead, C-c C-l or M-x org-insert-link is
used to insert a link interactively. But then the file path gets
normalized i.e. even if ./doc.org is explicitly specified, it gets
replaced with doc.org which is shorter and simpler representation of
the same path.
This would cause tagref to treat it relative to the working
directory. To prevent this, we can tell emacs to skip normalization of
relative file paths. However, the solution feels inelegant as
we're effectively patching a natively compiled core function
file-relative-name in emacs, and not just an org-mode specific
function. Considering this, we can conservatively define the
advice
such that it affects only those org buffers where the
org-link-file-path-type variable is set to 'relative as a local
binding.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
To opt into this behavior, you need to override
org-link-file-path-type locally for all files in the project. This
can be conveniently done through a .dir-locals.el file at the
repository root.
1 2 3 | |
With these two pieces in place, tagref works seamlessly with org-mode files.
- Tagged
- tagref
- org-mode
- opensource
Please reach out to me at