A Beginner's Guide to Extending Emacs Date: 4 February, 2025 Length: 3,983 words (~17 minutes read) --- Overview This post explains how to extend Emacs to add auto-completion support for reStructuredText (reST) references, bridging the gap for users unfamiliar with Emacs Lisp. Rather than debating editor preferences, it focuses on Emacs' extensibility and introspectability using a practical example. --- Context: reStructuredText in Documentation The author writes user documentation in reST format with lots of cross-references. reST references look like this: Problem: cumbersome to remember all references while editing. Solution: create an Emacs completion function that auto-suggests references. --- Prelude: Understanding Emacs and Lisp Emacs wants you to extend it Emacs encourages deep customization, providing powerful functions (e.g., advice-add) to override any functionality. Geriatric software with modern features Emacs has ~40 years of evolution but still receives significant updates (e.g., Language Server Protocol support in v29). Lisp for the un-Lisped Everything wrapped in parentheses, e.g., (print "Hello") Macros like let for scoping variables Quoting lists to treat them as data: '(list of strings) --- Emacs Completion System The shortcut M-. (Meta + period) runs completion-at-point. The variable completion-at-point-functions is a hook list of completion functions tried in order. Each function returns either: nil (not applicable), another function (discouraged), or a 3+ element list: (START END COLLECTION . PROPS) where: START and END mark the region in the buffer to replace, COLLECTION is a list of completion candidates. --- Defining a "thing" for Completion Use (bounds-of-thing-at-point 'thing) to get bounds of a syntactic element. Define custom thing rst-ref for reST references with allowed characters: Test with: --- Gathering Completion Candidates We need all reST references in the buffer defined as: Use re-search-forward with a regex to find all matches. Use match-string-no-properties to extract the reference name from the match. Develop and test regex with Emacs re-builder and the rx macro, e.g.: Use cl-loop macro to search throughout the buffer and collect all references: --- Implementing the Completion Backend Define a completion function my/rst-internal-reference-capf: Short-circuit: only active inside a :ref: expression. Use bounds-of-thing-at-point to find region to complete. Collect all candidates from buffer using the regex search. Return list (START END CANDIDATES). Add the function to Emacs’ completion-at-point-functions hook: This enables invoking completion with M-. inside reST reference points. --- Enhancements and Integration Mode Hooks Automation To avoid manual hook adding, leverage rst-mode-hook: Adds completion only for buffers in rst-mode automatically. Cross-File Completions Current example works for references within the same