Add new section to intro (Literate Programming)

This commit is contained in:
Kiana Sheibani 2024-03-20 02:31:30 -04:00
parent 2df7c9afe5
commit 4279cac87c
Signed by: toki
GPG key ID: 6CB106C25E86A9F7

View file

@ -41,22 +41,59 @@ It was at this point that I started thinking about Emacs again. By chance, I hap
As I became more comfortable with configuration via scripting, I immersed myself into the many utilities that make up the Emacs ecosystem: =org-mode=, =calfw=, =calc=, =mu4e=. I started putting more and more time into tweaking these applications to fit my needs, my files kept getting longer and longer, and eventually I fully fell off the deep end and now we're here. As I became more comfortable with configuration via scripting, I immersed myself into the many utilities that make up the Emacs ecosystem: =org-mode=, =calfw=, =calc=, =mu4e=. I started putting more and more time into tweaking these applications to fit my needs, my files kept getting longer and longer, and eventually I fully fell off the deep end and now we're here.
*** TODO Literate Programming *** Literate Programming
My first Doom Emacs config was hacked together directly from the generated example config: no comments, no organization, nothing. ~after!~ and ~use-package!~ blocks were scattered about the file without rhyme or reason, making it very difficult to remember what any particular line of code was actually doing. I was able to mitigate some of this issue by categorizing my config into multiple files, but at the end of the day it was a losing battle. The config directory was at 1200 lines of code before I decided that something needed to be done. My first Doom Emacs config was hacked together directly from the generated example config: no comments, no organization, nothing. ~after!~ and ~use-package!~ blocks were scattered about the file without rhyme or reason, making it very difficult to remember what any particular line of code was actually doing. I was able to mitigate some of this issue by categorizing my config into multiple files, but at the end of the day it was a losing battle. The config directory was at around 1200 lines of code before I decided that something needed to be done.
I was considering what to do about this problem of organizational decay when I came across [[https://tecosaur.github.io/emacs-config/config.html][Tecosaur's config]] and learned about =org-mode='s literate programming support. I had been using =org-mode= for several months at this point and was very comfortable with it, so utilizing it to better organize my code seemed like a good idea. I was considering what to do about this problem of organizational decay when I came across [[https://tecosaur.github.io/emacs-config/config.html][Tecosaur's config]] and learned about =org-mode='s literate programming support. I had been using =org-mode= for several months at this point and was very comfortable with it, so utilizing it to better organize my Emacs code seemed like a good idea.
**** Org and Source Code
This file is written in Org, a plain-text markup language similar to Markdown in basic structure. Like Markdown, it has support for embedding blocks of source code in between paragraphs.
Unlike a standard markup language, however, Org mode has built-in capabilities for executing code and inserting the output into the document, somewhat similar to a Jupyter notebook.
#+begin_src emacs-lisp :eval yes :exports both :results replace
;; This is Emacs Lisp code in a src block!
(format "Result: %s" (+ 1 2))
#+end_src
#+RESULTS:
: Result: 3
The second block above was automatically generated by =org-mode=.
(This feature does not exclusively work with Emacs Lisp, but other languages require a compiler or interpreter to be installed.)
**** Tangle, Weave, Export, Publish
Since Org's ability to execute and code process its output is so robust, it's only natural that one might consider using Org to annotate existing code. This could be done by maintaining both the Org document and an actual source file separately, but that would require duplicating edits in both files, which is not ideal.
The solution is [[https://en.wikipedia.org/wiki/Literate_programming][literate programming]], the practice of embedding an active codebase into a document. Literate programming can be done in a few different ways; some languages support directly processing literate programs, including Julia and Agda. However, the way Org implements it is closer to the traditional method, which involves two processing systems:
1. /Tangling/, converting the file into source code that can be executed. Tangling must be performed before the code is used, and in Org is typically done into a separate generated file.
2. /Weaving/, formatting the file into a human-readable document. Org conceptually divides this further into "exporting" and "publishing," where the latter is intended specifically for converting into web-ready HTML.
You are currently reading the published version of this literate program[fn:1]. If you were to download this repository and use it as your config, Emacs would be running the tangled version. These versions are generated in separate processes, but both of them require running code, since as demonstrated above, the exported documentation can contain program execution results.
[fn:1] Unless you're reading the raw file on Github, in which case you are probably already decently familiar with =org-mode= to be able to read its markup.
**** From Code into Comprehension
The simultaneous handling of documentation and code inherent to literate programming is reminiscent of documentation generation (doc comments) in traditional programming. Both systems involve superimposing code and documentation into one file, but the literate style takes the concept one step further; the document isn't embedded in the code, the code is embedded in the document.
Instead of documentation having to be bent around the restrictions of source code, the source code can be written and organized with all the freedoms of prose. If written well, the literate program can be structured in a manner closer to how the human mind understands code, rather than how a computer processes it. This is assisted by features such as literate macros and tangling configuration, features intended to break one's code out of the restrictions of standard programming.
*** =confpkg= *** =confpkg=
As part of their literate config, Tecosaur implemented =confpkg=, an embedded Emacs Lisp library that manages multiple aspects of config tangling: As part of their literate config, Tecosaur implemented =confpkg=, an embedded Emacs Lisp library that manages multiple aspects of config tangling:
- Controlling what files each code block is tangled to - Controlling what generated files each code block is tangled to
- Generating package files from templates - Creating package files from templates
- Automatically detecting cross-section dependencies - Automatically detecting cross-section dependencies
- Reporting profiling information on config load times - Reporting profiling information on config load times
It's an incredibly impressive utility, and I highly recommend reading [[https://tecosaur.github.io/emacs-config/config.html#rudimentary-configuration-confpkg][the section in their config]] on its design. I tried to read through it myself, but I don't understand half of it; it's a bizarre mixture of exploits to hook into =org-mode='s tangling process, self-modifying buffer shenanigans, and abuse of various features of =org-babel=. It's an incredibly impressive utility, and I highly recommend reading [[https://tecosaur.github.io/emacs-config/config.html#rudimentary-configuration-confpkg][the section in their config]] on its design. I tried to read through it myself, but I don't understand half of it; it's a bizarre mixture of exploits to hook into =org-mode='s tangling process, self-modifying buffer shenanigans, and abuse of various features of the source block mechanism.
Luckily, I don't need to be able to understand code in order to do what I do best: press =Ctrl+C= and =Ctrl+V= in that order. Programming! Luckily, I don't need to be able to understand code in order to do what I do best: press =Ctrl+C= and =Ctrl+V= in that order. Programming!
@ -2835,7 +2872,7 @@ The command ~+org/dwim-at-point~ will toggle all overlays in a subtree even if t
When an explicit category is not specified, Org mode typically defaults to the filename (sans extension). This ... sort of makes sense? I guess? It doesn't really, because filename conventions don't make for good category names. This is especially bad for Org-roam, where filenames are automatically generated and can be very large and hard to read. When an explicit category is not specified, Org mode typically defaults to the filename (sans extension). This ... sort of makes sense? I guess? It doesn't really, because filename conventions don't make for good category names. This is especially bad for Org-roam, where filenames are automatically generated and can be very large and hard to read.
To fix this issue, it is thankfully rather simple to patch Org-mode's category system to use a different system for default categories[fn:1]. The following code sets it up so that the file's =#+title= metadata is used as the default category, falling back on the filename if a title is not given. To fix this issue, it is thankfully rather simple to patch Org-mode's category system[fn:2]. The following code sets things up so that the file's =#+title= metadata is used as the default category, falling back on the default behavior if a title is not given.
#+begin_src emacs-lisp #+begin_src emacs-lisp
(defadvice! ~/org-default-category (old-fn) (defadvice! ~/org-default-category (old-fn)
@ -2846,7 +2883,7 @@ To fix this issue, it is thankfully rather simple to patch Org-mode's category s
(funcall old-fn))) (funcall old-fn)))
#+end_src #+end_src
[fn:1] Where by "simple" I mean that it took me multiple hours of combing through Org's source code in order to find the multiple places(???) where this behavior was implemented and to figure out how to modify it. At least the final code is short! [fn:2] Where by "simple" I mean that it took me multiple hours of combing through Org's source code in order to find the multiple places(???) where this behavior was implemented and to figure out how to modify it. At least the final code is short!
** Tags ** Tags