3.7 KiB
Emacs IETF
Prologue
Some years ago I discovered ietf-cli in OpenBSD ports. It creates a local mirror of IETF drafts, RFCs and other files and makes them accessible from the command line. I have it configured to use Emacs for the pager[fn::Like normal people… I uses emacsclient for performance reasons.].
I was never too happy about the cli interface though. While it is open
source I never got around to hack on it or to send feature
requests. These are the things I do not like. Most of them are a
question of work flow more than limitations of the ietf
tool:
- I never figured out how to configure tab-completion in my shell for it.
- I am not yet running a shell inside of Emacs, so it breaks my work flow when reading a draft and I want to quickly open an RFC for reference.
- The tool is pretty opinionated. You need to call just so for it do
what you ask. To open an RFC you need to type
ietf rfc 1925
. It will not acceptietf RFC1925
orietf rfc1925
. That means that copy & paste does not work most of the time.
More recently I discovered the vertico completion extension combined with orderless completion. Those two extensions provide the kind of completion I want for RFCs and even more so for drafts:
[Orderless] divides the pattern into space-separated components, and matches candidates that match all of the components in any order.
Emacs-lisp
The ietf
tool provides the mirror
command that rsyncs the IETF
documents to a configurable folder. Reading an RFC or draft then
comes down to opening the correct file. So we can copy the code of
find-file
, change default-directory
and we are good to go:
;; were ietf mirror stores the local mirror
(setq ietf-mirror "~/ietf-mirror/")
;; look for drafts in the 'short-id/' sub-directory and make sure the
;; buffer is a read-only text buffer.
(defun ietf-draft (filename &optional wildcards)
(interactive
(let
((default-directory (concat ietf-mirror "short-id/")))
(find-file-read-args "Find file: "
(confirm-nonexistent-file-or-buffer))))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
(mapcar 'pop-to-buffer-same-window (nreverse value))
(pop-to-buffer-same-window value))
(read-only-mode)
(text-mode)))
;; RFCs are stored in 'in-notes/'
(defun ietf-rfc (filename &optional wildcards)
(interactive
(let
((default-directory (concat ietf-mirror "in-notes/"))
(completion-ignored-extensions
'("/" ".html" ".json" ".pdf" ".ps" ".tar" ".xml" ".xsd")))
(find-file-read-args "Find file: "
(confirm-nonexistent-file-or-buffer))))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
(mapcar 'pop-to-buffer-same-window (nreverse value))
(pop-to-buffer-same-window value))
(read-only-mode)
(text-mode)))
Setting a global key binding lets us open RFCs and drafts from anywhere within Emacs:
(global-set-key (kbd "C-c i d") 'ietf-draft)
(global-set-key (kbd "C-c i r") 'ietf-rfc)
Epilogue
The ietf
tool has many more options that I have not explored or used
yet. rfc
and draft
are the two main commands I am using and on
occasion I am using the diff tool.
I will keep the tool around to keep the mirror up2date and for the
occasional use of diff
. Having moved the functionality I use most
often into Emacs and making it behave like I want it is a huge
improvement.