{"author":{"name":"Kaushal Modi","type":"card","url":"https://scripter.co/"},"children":[{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#installing-delta\"\u003eInstalling \u003ccode\u003edelta\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#installing-magit-delta\"\u003eInstalling \u003ccode\u003emagit-delta\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#configuring-delta\"\u003eConfiguring \u003ccode\u003edelta\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/dandavison/delta\"\u003eDelta\u003c/a\u003e is a highly configurable\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nI am not kidding. Check out the output of \u003ca href=\"https://dandavison.github.io/delta/full---help-output.html\"\u003e\u003ccode\u003edelta --help\u003c/code\u003e\u003c/a\u003e.\n\u003c/small\u003e\u003c/span\u003e\ncommand line utility that makes the git diffs look better, while also\nsyntax-highlighting\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\n\u003ca href=\"https://github.com/Wilfred/difftastic/\"\u003eDifftastic\u003c/a\u003e is another popular diff tool which compares files based on\ntheir syntax. I like reviewing \u003cem\u003egit diffs\u003c/em\u003e from within Emacs\n(Magit). But \u003cem\u003edifftastic\u003c/em\u003e \u003ca href=\"https://github.com/Wilfred/difftastic/issues/251\"\u003edoes not support Magit\u003c/a\u003e.\n\u003c/small\u003e\u003c/span\u003e\nthe code in the diffs.\u003c/p\u003e\n\u003cp\u003eWhen I first heard of \u0026ldquo;syntax highlighted diffs\u0026rdquo;, I wasn\u0026rsquo;t sure what\nthat meant. If you are in the same boat, here\u0026rsquo;s a screenshot that\nshows that.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--git-delta-example\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"delta-example.png\"\u003e\n        \u003cimg src=\"https://scripter.co/using-git-delta-with-magit/delta-example.png\" alt=\"Figure 1: Example of how delta renders a git diff for an ox-hugo commit\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eExample of how \u003ccode\u003edelta\u003c/code\u003e renders a \u003cem\u003egit diff\u003c/em\u003e for an \u003ccode\u003eox-hugo\u003c/code\u003e commit\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eBut I do most of my git operations including viewing of diffs from\nwithin Emacs, using \u003ca href=\"https://magit.vc\"\u003eMagit\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e        .. and thankfully \u003cem\u003edelta\u003c/em\u003e \u003ca href=\"https://dandavison.github.io/delta/using-delta-with-magit.html\"\u003eworks with Magit\u003c/a\u003e!\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eBelow screenshot shows how the same diff looks like in Magit.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--git-magit-delta-example\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"magit-delta-example.png\"\u003e\n        \u003cimg src=\"https://scripter.co/using-git-delta-with-magit/magit-delta-example.png\" alt=\"Figure 2: Example of how magit-delta renders a git diff for an ox-hugo commit\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 2: \u003c/span\u003eExample of how \u003ccode\u003emagit-delta\u003c/code\u003e renders a \u003cem\u003egit diff\u003c/em\u003e for an \u003ccode\u003eox-hugo\u003c/code\u003e commit\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eThe \u003ca href=\"https://github.com/dandavison/magit-delta\"\u003e\u003ccode\u003emagit-delta\u003c/code\u003e\u003c/a\u003e Emacs package makes this possible, which is also\ndeveloped by the \u003ccode\u003edelta\u003c/code\u003e author Dan Davison.\u003c/p\u003e\n\u003cdl\u003e\n\u003cdt\u003eCaveat\u003c/dt\u003e\n\u003cdd\u003eIf the line numbers are enabled in \u003ccode\u003edelta\u003c/code\u003e, they mess up\nthe interactive expanding and collapsing of diffs in Magit. See\n\u003ca href=\"https://github.com/dandavison/magit-delta/issues/13#issuecomment-949820122\"\u003eMagit Delta Issue # 13\u003c/a\u003e for more details.\u003c/dd\u003e\n\u003c/dl\u003e\n\u003cp\u003eNow, I am alright with not seeing the line numbers in Magit. But I\nreally liked to see the line numbers in the side-by-side view in the\nterminal. Luckily, if disabled the \u003ccode\u003eline-numbers\u003c/code\u003e feature but enabled\nthe \u003ccode\u003eside-by-side\u003c/code\u003e view, I got what I wanted!\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eLine numbers are disabled in Magit and expanding/collapsing of\ndiffs works correctly. \u003cem\u003eI am also really glad that I don\u0026rsquo;t see the\nside-by-side view in Magit diffs even when I enable that feature in\n\u003ccode\u003edelta\u003c/code\u003e, because I like to have my Emacs buffers only about 90\ncharacters wide.\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eLine numbers \u003cstrong\u003eand\u003c/strong\u003e side-by-side view are enabled in the terminal.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eI\u0026rsquo;ll end this post with pointers to installing \u003ccode\u003edelta\u003c/code\u003e and\n\u003ccode\u003emagit-delta\u003c/code\u003e and how to configure them.\u003c/p\u003e\n\n\u003ch2 id=\"installing-delta\"\u003eInstalling \u003ccode\u003edelta\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#installing-delta\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eYou can install \u003ccode\u003edelta\u003c/code\u003e (it\u0026rsquo;s called \u003ccode\u003egit-delta\u003c/code\u003e in some package\nmanagers) using one of the methods listed \u003ca href=\"https://dandavison.github.io/delta/installation.html\"\u003ein its manual\u003c/a\u003e, or you can\ndownload → extract its statically compiled binary for your OS from its\n\u003ca href=\"https://github.com/dandavison/delta/releases\"\u003eGitHub Releases\u003c/a\u003e page.\u003c/p\u003e\n\n\u003ch2 id=\"installing-magit-delta\"\u003eInstalling \u003ccode\u003emagit-delta\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#installing-magit-delta\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eOnce you put this snippet in your Emacs config and evaluate it, it\nwill install this package and enable the \u003ccode\u003emagit-delta-mode\u003c/code\u003e in the\nMagit buffers.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--enabling-magit-delta\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003euse-package\u003c/span\u003e \u003cspan class=\"nv\"\u003emagit-delta\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nb\"\u003e:ensure\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nb\"\u003e:hook\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emagit-mode\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"nv\"\u003emagit-delta-mode\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--enabling-magit-delta\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Installing and enabling \u003ccode\u003emagit-delta\u003c/code\u003e using \u003ccode\u003euse-package\u003c/code\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"configuring-delta\"\u003eConfiguring \u003ccode\u003edelta\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#configuring-delta\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eHere\u0026rsquo;s a snippet for \u003ccode\u003edelta\u003c/code\u003e configuration from my \u003ccode\u003e.gitconfig\u003c/code\u003e. It\u0026rsquo;s\nmostly the same as the one in \u003cem\u003edelta\u003c/em\u003e\u0026rsquo;s the \u003ca href=\"https://github.com/dandavison/delta#get-started\"\u003eGetting Started\u003c/a\u003e guide. The\nmain difference in my workaround for the \u003ccode\u003emagit-delta\u003c/code\u003e issue.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--delta-gitconfig\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sh\" data-lang=\"sh\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003ecore\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003epager\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e delta\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003einteractive\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003ediffFilter\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e delta --color-only\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003eadd.interactive\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003euseBuiltin\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003efalse\u003c/span\u003e \u003cspan class=\"c1\"\u003e# required for git 2.37.0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003ediff\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003ecolorMoved\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e default\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e[\u003c/span\u003edelta\u003cspan class=\"o\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e# https://github.com/dandavison/magit-delta/issues/13\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e# line-numbers = true    # Don\u0026#39;t do this.. messes up diffs in magit\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e#\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    side-by-side \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e      \u003cspan class=\"c1\"\u003e# Display a side-by-side diff view instead of the traditional view\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e# navigate = true          # Activate diff navigation: use n to jump forwards and N to jump backwards\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    relative-paths \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003etrue\u003c/span\u003e    \u003cspan class=\"c1\"\u003e# Output all file paths relative to the current directory\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    file-style \u003cspan class=\"o\"\u003e=\u003c/span\u003e yellow\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    hunk-header-style \u003cspan class=\"o\"\u003e=\u003c/span\u003e line-number syntax\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--delta-gitconfig\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  My configuration for \u003ccode\u003edelta\u003c/code\u003e in \u003ccode\u003e.gitconfig\u003c/code\u003e\n\u003c/div\u003e\n","text":" Table of Contents Installing delta Installing magit-delta Configuring delta Delta is a highly configurable I am not kidding. Check out the output of delta --help. command line utility that makes the git diffs look better, while also syntax-highlighting Difftastic is another popular diff tool which compares files based on their syntax. I like reviewing git diffs from within Emacs (Magit). But difftastic does not support Magit. the code in the diffs.\nWhen I first heard of \u0026ldquo;syntax highlighted diffs\u0026rdquo;, I wasn\u0026rsquo;t sure what that meant. If you are in the same boat, here\u0026rsquo;s a screenshot that shows that.\nFigure 1: Example of how delta renders a git diff for an ox-hugo commit But I do most of my git operations including viewing of diffs from within Emacs, using Magit.\n.. and thankfully delta works with Magit!\nBelow screenshot shows how the same diff looks like in Magit.\nFigure 2: Example of how magit-delta renders a git diff for an ox-hugo commit The magit-delta Emacs package makes this possible, which is also developed by the delta author Dan Davison.\nCaveat If the line numbers are enabled in delta, they mess up the interactive expanding and collapsing of diffs in Magit. See Magit Delta Issue # 13 for more details. Now, I am alright with not seeing the line numbers in Magit. But I really liked to see the line numbers in the side-by-side view in the terminal. Luckily, if disabled the line-numbers feature but enabled the side-by-side view, I got what I wanted!\nLine numbers are disabled in Magit and expanding/collapsing of diffs works correctly. I am also really glad that I don\u0026rsquo;t see the side-by-side view in Magit diffs even when I enable that feature in delta, because I like to have my Emacs buffers only about 90 characters wide. Line numbers and side-by-side view are enabled in the terminal. I\u0026rsquo;ll end this post with pointers to installing delta and magit-delta and how to configure them.\nInstalling delta\u0026nbsp;# You can install delta (it\u0026rsquo;s called git-delta in some package managers) using one of the methods listed in its manual, or you can download → extract its statically compiled binary for your OS from its GitHub Releases page.\nInstalling magit-delta\u0026nbsp;# Once you put this snippet in your Emacs config and evaluate it, it will install this package and enable the magit-delta-mode in the Magit buffers.\n(use-package magit-delta :ensure t :hook (magit-mode . magit-delta-mode)) Code Snippet 1: Installing and enabling magit-delta using use-package Configuring delta\u0026nbsp;# Here\u0026rsquo;s a snippet for delta configuration from my .gitconfig. It\u0026rsquo;s mostly the same as the one in delta\u0026rsquo;s the Getting Started guide. The main difference in my workaround for the magit-delta issue.\n[core] pager = delta [interactive] diffFilter = delta --color-only [add.interactive] useBuiltin = false # required for git 2.37.0 [diff] colorMoved = default [delta] # https://github.com/dandavison/magit-delta/issues/13 # line-numbers = true # Don\u0026#39;t do this.. messes up diffs in magit # side-by-side = true # Display a side-by-side diff view instead of the traditional view # navigate = true # Activate diff navigation: use n to jump forwards and N to jump backwards relative-paths = true # Output all file paths relative to the current directory file-style = yellow hunk-header-style = line-number syntax Code Snippet 2: My configuration for delta in .gitconfig "},"name":"Using Git Delta with Magit","published":"2022-07-06T22:04:00-04:00","summary":"Git Delta is a command line utility that beautifies git diffs in the terminal. But did you know that it can do the same in Magit too?","type":"entry","url":"https://scripter.co/using-git-delta-with-magit/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#enabling-transliteration\"\u003eEnabling transliteration\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#toggling-the-input-method\"\u003eToggling the input method\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#caveats-with-gujarati-and-other-indic-language-transliteration\"\u003eCaveats with Gujarati and other Indic language transliteration\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#input-method-cheat-sheet\"\u003e\u0026ldquo;Input method\u0026rdquo; cheat sheet\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#closing\"\u003eClosing\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#gujarati-transliteration-references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eEmacs provides the transliteration feature using the\n\u003cstrong\u003eset-input-method\u003c/strong\u003e command. I\u0026rsquo;ll introduce that and few related\nfunctions in this post to get to help get started with transliteration\nquickly.\u003c/p\u003e\n\n\u003ch2 id=\"enabling-transliteration\"\u003eEnabling transliteration\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#enabling-transliteration\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eEmacs uses the \u0026ldquo;input method\u0026rdquo; feature to do character conversion from\nASCII to the target language or script. The \u0026ldquo;input method\u0026rdquo;, stored in\n\u003ccode\u003ecurrent-input-method\u003c/code\u003e, is \u003cem\u003enil\u003c/em\u003e by default. In this state, you see\nthe exact ASCII in Emacs buffer, that you typed on the\nkeyboard\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eIn this post, my target non-English language is \u003ca href=\"https://en.wikipedia.org/wiki/Gujarati_language\"\u003eGujarati\u003c/a\u003e. So I want to\ntype on my English keyboard and have Gujarati script letters show up\nin the buffer.\u003c/p\u003e\n\u003cp\u003eEmacs provides the \u003ccode\u003eset-input-method\u003c/code\u003e command to change the \u003cem\u003ecurrent\ninput method\u003c/em\u003e. This command is bound to \u003ckbd\u003eC-x\u003c/kbd\u003e \u003ckbd\u003eRET\u003c/kbd\u003e\n\u003ckbd\u003eC-\\\u003c/kbd\u003e by default. Pick the new input method after calling\nthat command.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eTo see the available input methods, do \u003ccode\u003eM-x list-input-methods\u003c/code\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eAs I want to do Gujarati transliteration, I pick the \u003ccode\u003egujarati-itrans\u003c/code\u003e\nmethod.\u003c/p\u003e\n\u003cp\u003eIf you don\u0026rsquo;t know Gujarati, don\u0026rsquo;t fret! The commands shown here will\nwork when transliterating to other languages too \u0026mdash; only the\nGujarati-specific \u003cem\u003einput method\u003c/em\u003e \u003ccode\u003egujarati-itrans\u003c/code\u003e will change to the\ninput method of your choice.\u003c/p\u003e\n\n\u003ch2 id=\"toggling-the-input-method\"\u003eToggling the input method\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#toggling-the-input-method\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eI often need to switch between the Gujarati and English languages in\nthe same document. You can see me doing that in this post next section\nonwards. The \u003ccode\u003etoggle-input-method\u003c/code\u003e command bound by default to\n\u003ckbd\u003eC-\\\u003c/kbd\u003e is helpful here.\u003c/p\u003e\n\u003cp\u003eSo if I am already in the \u0026ldquo;Gujarati transliteration mode\u0026rdquo; calling this\ncommand will set \u003ccode\u003ecurrent-input-method\u003c/code\u003e back to \u003cem\u003enil\u003c/em\u003e. Repeating that\nsame call will again set \u003ccode\u003ecurrent-input-method\u003c/code\u003e to \u003ccode\u003egujarati-itrans\u003c/code\u003e,\nand I will once again be in the \u0026ldquo;Gujarati transliteration mode\u0026rdquo;.\u003c/p\u003e\n\n\u003ch2 id=\"caveats-with-gujarati-and-other-indic-language-transliteration\"\u003eCaveats with Gujarati and other Indic language transliteration\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#caveats-with-gujarati-and-other-indic-language-transliteration\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eApologies, but this section is meaningful only if you know how to read\nGujarati. So you can safely skip to the next section.\u003c/p\u003e\n\u003cp\u003eBelow table is a quick glimpse of some nuances in Gujarati\ntransliteration. I will save my explanation and instead show some of\nthe mistakes I made in transliteration using examples.\u003c/p\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eASCII input\u003c/th\u003e\n\u003cth\u003eGujarati Transliteration\u003c/th\u003e\n\u003cth\u003eRough Translation\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003eram\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003eરમ્\u003c/td\u003e\n\u003ctd\u003e(incorrect spelling, no meaning)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003erama\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003eરમ\u003c/td\u003e\n\u003ctd\u003eplay\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003eraama\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003eરામ\u003c/td\u003e\n\u003ctd\u003ea popular name Raama (as in Lord Raama)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003eangreji\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003eઅન્ગ્રેજિ\u003c/td\u003e\n\u003ctd\u003e(incorrect spelling)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003ehu.n\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003eહું\u003c/td\u003e\n\u003ctd\u003eI\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003echhu.n\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003eછું\u003c/td\u003e\n\u003ctd\u003eam\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003ea.ngrejii\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003eઅંગ્રેજી\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/td\u003e\n\u003ctd\u003eEnglish (language)\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cem\u003eIme.cksa\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003eઈમૅક્સ\u003c/td\u003e\n\u003ctd\u003ethis literally reads \u0026ldquo;Emacs\u0026rdquo;\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003ch2 id=\"input-method-cheat-sheet\"\u003e\u0026ldquo;Input method\u0026rdquo; cheat sheet\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#input-method-cheat-sheet\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThankfully Emacs provides full help through the\n\u003ccode\u003edescribe-input-method\u003c/code\u003e command bound to \u003ckbd\u003eC-h\u003c/kbd\u003e\n\u003ckbd\u003eC-\\\u003c/kbd\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nIf you haven\u0026rsquo;t already noticed the consistency in these bindings, the\ndefault bindings with \u003ckbd\u003eC-\\\u003c/kbd\u003e in them are related to \u0026ldquo;input\nmethod\u0026rdquo; commands.\n\u003c/small\u003e\u003c/span\u003e\nby default.\u003c/p\u003e\n\u003cp\u003eFor example, \u003ccode\u003eM-x describe-input-method gujarati-itrans\u003c/code\u003e gives this:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--gujarati-itrans-help\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"gujarati-itrans-help.png\"\u003e\n        \u003cimg src=\"https://scripter.co/gujarati-transliteration/gujarati-itrans-help.png\" alt=\"Figure 1: Partial screen capture of Gujarati transliteration cheat sheet C-h C- gujarati-itrans\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003ePartial screen capture of Gujarati transliteration cheat sheet \u003ccode\u003eC-h C- gujarati-itrans\u003c/code\u003e\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eThe ∗Help∗ that shows up looks formidable at the first glance. Though,\nI found comfort in the fact that roughly half of the key sequences\nwere obvious and roughly half resulted in Gujarati characters that I\nhave never found the need of! 😃\u003c/p\u003e\n\n\u003ch2 id=\"closing\"\u003eClosing\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#closing\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eTyping this in the \u0026ldquo;transliteration mode\u0026rdquo;:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003emaaru naama kaushala chhe. mane e jaaNii ne aana.nda thaaya chhe ke\nhu.n aa sahelaaI thI lakhI shaku chhu.n. (joDanI-bhula maapha.)\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003ewill result in:\u003c/p\u003e\n\u003cp\u003eમારુ નામ કૌશલ છે. મને એ જાણી ને આનંદ થાય છે કે હું આ સહેલાઈ થી લખી શકુ\nછું. (જોડણી-ભુલ માફ.)\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eTranslation: My name is Kaushal. I am happy knowing that I can write\nthis easily.\u003c/em\u003e\u003c/p\u003e\n\n\u003ch2 id=\"gujarati-transliteration-references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#gujarati-transliteration-references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/emacs/Input-Methods.html\" title=\"Emacs Lisp: (info \u0026quot;(emacs) Input Methods\u0026quot;)\"\u003eEmacs Info: Input Methods\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/emacs/Select-Input-Method.html\" title=\"Emacs Lisp: (info \u0026quot;(emacs) Select Input Method\u0026quot;)\"\u003eEmacs Info: Select Input Method\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eM-x describe-input-method gujarati-itrans\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eI am assuming an English keyboard here.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eThis spelling might still render incorrectly on your browser\ndepending on the unicode character set available for Gujarati on your\nsystem.\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","text":" Table of Contents Enabling transliteration Toggling the input method Caveats with Gujarati and other Indic language transliteration \u0026ldquo;Input method\u0026rdquo; cheat sheet Closing References Emacs provides the transliteration feature using the set-input-method command. I\u0026rsquo;ll introduce that and few related functions in this post to get to help get started with transliteration quickly.\nEnabling transliteration\u0026nbsp;# Emacs uses the \u0026ldquo;input method\u0026rdquo; feature to do character conversion from ASCII to the target language or script. The \u0026ldquo;input method\u0026rdquo;, stored in current-input-method, is nil by default. In this state, you see the exact ASCII in Emacs buffer, that you typed on the keyboard1.\nIn this post, my target non-English language is Gujarati. So I want to type on my English keyboard and have Gujarati script letters show up in the buffer.\nEmacs provides the set-input-method command to change the current input method. This command is bound to C-x RET C-\\ by default. Pick the new input method after calling that command.\nTo see the available input methods, do M-x list-input-methods.\nAs I want to do Gujarati transliteration, I pick the gujarati-itrans method.\nIf you don\u0026rsquo;t know Gujarati, don\u0026rsquo;t fret! The commands shown here will work when transliterating to other languages too \u0026mdash; only the Gujarati-specific input method gujarati-itrans will change to the input method of your choice.\nToggling the input method\u0026nbsp;# I often need to switch between the Gujarati and English languages in the same document. You can see me doing that in this post next section onwards. The toggle-input-method command bound by default to C-\\ is helpful here.\nSo if I am already in the \u0026ldquo;Gujarati transliteration mode\u0026rdquo; calling this command will set current-input-method back to nil. Repeating that same call will again set current-input-method to gujarati-itrans, and I will once again be in the \u0026ldquo;Gujarati transliteration mode\u0026rdquo;.\nCaveats with Gujarati and other Indic language transliteration\u0026nbsp;# Apologies, but this section is meaningful only if you know how to read Gujarati. So you can safely skip to the next section.\nBelow table is a quick glimpse of some nuances in Gujarati transliteration. I will save my explanation and instead show some of the mistakes I made in transliteration using examples.\nASCII input Gujarati Transliteration Rough Translation ram રમ્ (incorrect spelling, no meaning) rama રમ play raama રામ a popular name Raama (as in Lord Raama) angreji અન્ગ્રેજિ (incorrect spelling) hu.n હું I chhu.n છું am a.ngrejii અંગ્રેજી2 English (language) Ime.cksa ઈમૅક્સ this literally reads \u0026ldquo;Emacs\u0026rdquo; \u0026ldquo;Input method\u0026rdquo; cheat sheet\u0026nbsp;# Thankfully Emacs provides full help through the describe-input-method command bound to C-h C-\\ If you haven\u0026rsquo;t already noticed the consistency in these bindings, the default bindings with C-\\ in them are related to \u0026ldquo;input method\u0026rdquo; commands. by default.\nFor example, M-x describe-input-method gujarati-itrans gives this:\nFigure 1: Partial screen capture of Gujarati transliteration cheat sheet C-h C- gujarati-itrans The ∗Help∗ that shows up looks formidable at the first glance. Though, I found comfort in the fact that roughly half of the key sequences were obvious and roughly half resulted in Gujarati characters that I have never found the need of! 😃\nClosing\u0026nbsp;# Typing this in the \u0026ldquo;transliteration mode\u0026rdquo;:\nmaaru naama kaushala chhe. mane e jaaNii ne aana.nda thaaya chhe ke hu.n aa sahelaaI thI lakhI shaku chhu.n. (joDanI-bhula maapha.)\nwill result in:\nમારુ નામ કૌશલ છે. મને એ જાણી ને આનંદ થાય છે કે હું આ સહેલાઈ થી લખી શકુ છું. (જોડણી-ભુલ માફ.)\nTranslation: My name is Kaushal. I am happy knowing that I can write this easily.\nReferences\u0026nbsp;# Emacs Info: Input Methods Emacs Info: Select Input Method M-x describe-input-method gujarati-itrans I am assuming an English keyboard here.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nThis spelling might still render incorrectly on your browser depending on the unicode character set available for Gujarati on your system.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"Gujarati Transliteration","published":"2022-06-27T18:43:00-04:00","summary":"You can phonetically write a non-English language on an English keyword in Emacs, and that transforms into that non-English script. This is called transliteration, and I demonstrate that for the Gujarati language in this post.","type":"entry","url":"https://scripter.co/gujarati-transliteration/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#locally-creating-a-branch-for-a-pr\"\u003eLocally creating a branch for a PR\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#getting-references-to-all-pull-requests\"\u003eGetting references to all Pull Requests\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#automatically-adding-pr-refs\"\u003eAutomatically adding PR refs\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#summary\"\u003eSummary\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eI have a few public projects in git repos, but I don\u0026rsquo;t get that much\ntraffic in \u003cem\u003ePull Requests (PR)\u003c/em\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nGitlab calls these \u003cem\u003eMerge Requests\u003c/em\u003e or MRs.\n\u003c/small\u003e\u003c/span\u003e\n. So when I need to add additional commits to a PR, I would just add\nthe PR author\u0026rsquo;s \u003cem\u003eremote\u003c/em\u003e to my local repo, \u003cem\u003echeck out\u003c/em\u003e their PR\nbranch, add my own commits and then merge that to my project\u0026rsquo;s \u003cem\u003emain\u003c/em\u003e\nbranch.\u003c/p\u003e\n\u003cp\u003eAs these occurrences were few and far apart, I didn\u0026rsquo;t have a need to\nview the \u003cem\u003ePR branches\u003c/em\u003e directly from within Emacs/Magit. Though, I\nsomehow knew that each GitHub Pull Request\u0026rsquo;s \u003cem\u003eHEAD\u003c/em\u003e got assigned a \u003ca href=\"https://git-scm.com/book/en/v2/Git-Internals-Git-References\"\u003egit\n\u003cstrong\u003ereference\u003c/strong\u003e\u003c/a\u003e. But I didn\u0026rsquo;t need to use that knowledge until today\n😃.\u003c/p\u003e\n\u003cp\u003eToday, when discussing \u003ca href=\"https://github.com/protesilaos/denote/pull/20\"\u003ePR # 20\u003c/a\u003e on \u003ca href=\"https://protesilaos.com/\"\u003eProt\u0026rsquo;s\u003c/a\u003e \u003ca href=\"https://protesilaos.com/emacs/denote\"\u003eDenote\u003c/a\u003e package\u0026rsquo;s GitHub\nmirror\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nProt uses \u003ca href=\"https://git.sr.ht/~protesilaos/denote\"\u003eSourceHut\u003c/a\u003e as the primary git forge for his Emacs\npackages. But I am glad that he doesn\u0026rsquo;t mind the activity in Issues\nand Pull Requests on the GitHub mirror.\n\u003c/small\u003e\u003c/span\u003e\n, he wrote \u003ca href=\"https://github.com/protesilaos/denote/pull/20#issuecomment-1164676013\"\u003ethis comment\u003c/a\u003e:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eNow I just need to figure out how best to incorporate your changes\ninto the \u003ccode\u003eorg-id\u003c/code\u003e branch so I can add the final bits. I am not too\nfamiliar with the PR workflow \u0026hellip;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e.. and that inspired this post today.\u003c/p\u003e\n\n\u003ch2 id=\"locally-creating-a-branch-for-a-pr\"\u003eLocally creating a branch for a PR\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#locally-creating-a-branch-for-a-pr\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eFrom the \u003ca href=\"https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally\"\u003eGitHub docs\u003c/a\u003e, the \u003ccode\u003egit\u003c/code\u003e command to create a local branch for a\nPR is this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit fetch origin pull/ID/head:BRANCHNAME\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI have the \u003ccode\u003edenote\u003c/code\u003e package cloned from its GitHub mirror. So the\n\u003cstrong\u003eorigin\u003c/strong\u003e remote\u0026rsquo;s \u003cstrong\u003eurl\u003c/strong\u003e is \u003ccode\u003ehttps://github.com/protesilaos/denote\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eMake sure that the remote name used in this command is pointing to a\nGitHub repo, and not a mirror forge like GitLab or SourceHut.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eWhen I ran the below command, I got a new branch \u003cstrong\u003epr-20\u003c/strong\u003e pointing to\nthe latest commit of that PR:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit fetch origin pull/20/head:pr-20\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAwesome!\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e.. But that wasn\u0026rsquo;t good enough\u003cbr /\u003e\n    .. Now I wanted more\u003cbr /\u003e\n        .. I didn\u0026rsquo;t want to manually create a branch for each PR.\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"getting-references-to-all-pull-requests\"\u003eGetting references to all Pull Requests\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#getting-references-to-all-pull-requests\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eNow that I was on that quest of \u0026ldquo;I want more\u0026rdquo;, it didn\u0026rsquo;t take me long\nto re-discover \u003ca href=\"https://oremacs.com/2015/03/11/git-tricks/#illusion-2-quickly-get-github-pull-requests-on-your-system\"\u003ethis 7-year old nugget\u003c/a\u003e by \u003ca href=\"https://oremacs.com\"\u003eOleh Krehel\u003c/a\u003e. Here are the\nrelevant bits from that post:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eOpen the local repo\u0026rsquo;s \u003ccode\u003e.git/config\u003c/code\u003e file.\u003c/li\u003e\n\u003cli\u003eFind the \u003ccode\u003e[remote \u0026quot;origin\u0026quot;]\u003c/code\u003e section\u003c/li\u003e\n\u003cli\u003eModify it by adding this one line with \u003cstrong\u003epull\u003c/strong\u003e refs. \u003cem\u003eThis is the\nsame for all GitHub repositories.\u003c/em\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-cfg\" data-lang=\"cfg\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e[remote \u0026#34;origin\u0026#34;]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"na\"\u003eurl\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"s\"\u003ehttps://github.com/USER/REPO.git\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    fetch = +refs/heads/*:refs/remotes/origin/*\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    fetch = +refs/pull/*/head:refs/pull/origin/*\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eWith that edit in place, when I did \u003ckbd\u003el\u003c/kbd\u003e \u003ckbd\u003ea\u003c/kbd\u003e (show\nthe log for all git references), followed by \u003ckbd\u003ef\u003c/kbd\u003e \u003ckbd\u003ea\u003c/kbd\u003e\n(fetch all the remotes) in the Magit, I could see the references to\nthe \u003ccode\u003edenote\u003c/code\u003e repo\u0026rsquo;s PRs!\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--magit-denote-pr-refs\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/view-github-pull-requests-in-magit/pr-20-ref.png\" alt=\"Figure 1: Viewing PR references from denote package\u0026rsquo;s GitHub repo\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eViewing PR references from \u003ccode\u003edenote\u003c/code\u003e package\u0026rsquo;s GitHub repo\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e.. But that still wasn\u0026rsquo;t good enough\u003cbr /\u003e\n    .. I didn\u0026rsquo;t want to manually edit the \u003ccode\u003e.git/config\u003c/code\u003e in each repo.\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"automatically-adding-pr-refs\"\u003eAutomatically adding PR refs\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#automatically-adding-pr-refs\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eOf course, I wasn\u0026rsquo;t the first one to think of this!\u003c/p\u003e\n\u003cp\u003eAnother Emacs veteran \u003ca href=\"https://endlessparentheses.com/\"\u003eArtur Malabarba\u003c/a\u003e had already had this covered\nalso around \u003ca href=\"https://endlessparentheses.com/automatically-configure-magit-to-access-github-prs.html\"\u003e7 years back\u003c/a\u003e. Coincidentally, that post was written as a\nresponse to that same blog post by Oleh where he shared the above\n\u003ccode\u003e.git/config\u003c/code\u003e tip.\u003c/p\u003e\n\u003cp\u003eIn that post, Artur shares an Emacs Lisp function that uses Magit\nfunctions like \u003ccode\u003emagit-get\u003c/code\u003e, \u003ccode\u003emagit-get-all\u003c/code\u003e and \u003ccode\u003emagit-git-string\u003c/code\u003e to\nauto-add the \u003ccode\u003efetch = +refs/pull/*/head:refs/pull/origin/*\u003c/code\u003e line in\nthe \u003ccode\u003e.git/config\u003c/code\u003e. This magic happens after checking that the \u003cstrong\u003eorigin\u003c/strong\u003e\nremote points to a GitHub repo, and if that line doesn\u0026rsquo;t already\nexist.\u003c/p\u003e\n\u003cp\u003eHere, I am lightly modifying the function shared in that post so that\nthe \u003cstrong\u003eorigin\u003c/strong\u003e remote name is not hard-coded\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThe reason is that sometimes, I name the original remote as \u003cstrong\u003eupstream\u003c/strong\u003e\nand my fork as \u003cstrong\u003efork\u003c/strong\u003e, and I might have no remote named \u003cstrong\u003eorigin\u003c/strong\u003e.\n\u003c/small\u003e\u003c/span\u003e\n. Credit for the main logic in this code still goes to Artur.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--add-PR-fetch-ref\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/add-PR-fetch-ref\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kp\"\u003e\u0026amp;optional\u003c/span\u003e \u003cspan class=\"nv\"\u003eremote-name\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;If refs/pull is not defined on a GH repo, define it.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eIf REMOTE-NAME is not specified, it defaults to the \u003c/span\u003e\u003cspan class=\"ss\"\u003e`remote\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e set\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003efor the \\\u0026#34;main\\\u0026#34; or \\\u0026#34;master\\\u0026#34; branch.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eremote-name\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"nv\"\u003eremote-name\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emagit-get\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;branch\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;main\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;remote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emagit-get\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;branch\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;master\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;remote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eremote-url\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emagit-get\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;remote\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eremote-name\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;url\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003efetch-refs\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003estringp\u003c/span\u003e \u003cspan class=\"nv\"\u003eremote-url\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003estring-match\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;github\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eremote-url\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emagit-get-all\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;remote\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eremote-name\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;fetch\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"c1\"\u003e;; https://oremacs.com/2015/03/11/git-tricks/\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003efetch-address\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;+refs/pull/*/head:refs/pull/%s/*\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eremote-name\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003efetch-refs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eunless\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emember\u003c/span\u003e \u003cspan class=\"nv\"\u003efetch-address\u003c/span\u003e \u003cspan class=\"nv\"\u003efetch-refs\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emagit-git-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;config\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"s\"\u003e\u0026#34;--add\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;remote.%s.fetch\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eremote-name\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"nv\"\u003efetch-address\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-hook\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;magit-mode-hook\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/add-PR-fetch-ref\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--add-PR-fetch-ref\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Function to auto-add GitHub PR references to the repo's \u003ccode\u003e.git/config\u003c/code\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"summary\"\u003eSummary\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#summary\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eWith the above snippet added to your Emacs config and evaluated, each\ntime you visit a repo cloned from GitHub in the Magit Status buffer\n(\u003ccode\u003eM-x magit-status\u003c/code\u003e), the PR refs will get auto-added to that repo\u0026rsquo;s\n\u003ccode\u003e.git/config\u003c/code\u003e if needed.\u003c/p\u003e\n\u003cp\u003eAfter that, you can easily view the commits from all the PRs by doing\n\u003ckbd\u003el\u003c/kbd\u003e \u003ckbd\u003ea\u003c/kbd\u003e \u003ckbd\u003ef\u003c/kbd\u003e \u003ckbd\u003ea\u003c/kbd\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://oremacs.com/2015/03/11/git-tricks/#illusion-2-quickly-get-github-pull-requests-on-your-system\"\u003eoremacs \u0026ndash; Some git/magit/github tricks\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://endlessparentheses.com/automatically-configure-magit-to-access-github-prs.html\"\u003eendlessparentheses \u0026ndash; Automatically configure Magit to access Github PRs\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally\"\u003eGitHub \u0026ndash; Checking out PR branches locally\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","text":" Table of Contents Locally creating a branch for a PR Getting references to all Pull Requests Automatically adding PR refs Summary References I have a few public projects in git repos, but I don\u0026rsquo;t get that much traffic in Pull Requests (PR) Gitlab calls these Merge Requests or MRs. . So when I need to add additional commits to a PR, I would just add the PR author\u0026rsquo;s remote to my local repo, check out their PR branch, add my own commits and then merge that to my project\u0026rsquo;s main branch.\nAs these occurrences were few and far apart, I didn\u0026rsquo;t have a need to view the PR branches directly from within Emacs/Magit. Though, I somehow knew that each GitHub Pull Request\u0026rsquo;s HEAD got assigned a git reference. But I didn\u0026rsquo;t need to use that knowledge until today 😃.\nToday, when discussing PR # 20 on Prot\u0026rsquo;s Denote package\u0026rsquo;s GitHub mirror Prot uses SourceHut as the primary git forge for his Emacs packages. But I am glad that he doesn\u0026rsquo;t mind the activity in Issues and Pull Requests on the GitHub mirror. , he wrote this comment:\nNow I just need to figure out how best to incorporate your changes into the org-id branch so I can add the final bits. I am not too familiar with the PR workflow \u0026hellip;\n.. and that inspired this post today.\nLocally creating a branch for a PR\u0026nbsp;# From the GitHub docs, the git command to create a local branch for a PR is this:\ngit fetch origin pull/ID/head:BRANCHNAME I have the denote package cloned from its GitHub mirror. So the origin remote\u0026rsquo;s url is https://github.com/protesilaos/denote.\nMake sure that the remote name used in this command is pointing to a GitHub repo, and not a mirror forge like GitLab or SourceHut.\nWhen I ran the below command, I got a new branch pr-20 pointing to the latest commit of that PR:\ngit fetch origin pull/20/head:pr-20 Awesome!\n.. But that wasn\u0026rsquo;t good enough\n.. Now I wanted more\n.. I didn\u0026rsquo;t want to manually create a branch for each PR.\nGetting references to all Pull Requests\u0026nbsp;# Now that I was on that quest of \u0026ldquo;I want more\u0026rdquo;, it didn\u0026rsquo;t take me long to re-discover this 7-year old nugget by Oleh Krehel. Here are the relevant bits from that post:\nOpen the local repo\u0026rsquo;s .git/config file. Find the [remote \u0026quot;origin\u0026quot;] section Modify it by adding this one line with pull refs. This is the same for all GitHub repositories. [remote \u0026#34;origin\u0026#34;] url = https://github.com/USER/REPO.git fetch = +refs/heads/*:refs/remotes/origin/* fetch = +refs/pull/*/head:refs/pull/origin/* With that edit in place, when I did l a (show the log for all git references), followed by f a (fetch all the remotes) in the Magit, I could see the references to the denote repo\u0026rsquo;s PRs!\nFigure 1: Viewing PR references from denote package\u0026rsquo;s GitHub repo .. But that still wasn\u0026rsquo;t good enough\n.. I didn\u0026rsquo;t want to manually edit the .git/config in each repo.\nAutomatically adding PR refs\u0026nbsp;# Of course, I wasn\u0026rsquo;t the first one to think of this!\nAnother Emacs veteran Artur Malabarba had already had this covered also around 7 years back. Coincidentally, that post was written as a response to that same blog post by Oleh where he shared the above .git/config tip.\nIn that post, Artur shares an Emacs Lisp function that uses Magit functions like magit-get, magit-get-all and magit-git-string to auto-add the fetch = +refs/pull/*/head:refs/pull/origin/* line in the .git/config. This magic happens after checking that the origin remote points to a GitHub repo, and if that line doesn\u0026rsquo;t already exist.\nHere, I am lightly modifying the function shared in that post so that the origin remote name is not hard-coded The reason is that sometimes, I name the original remote as upstream and my fork as fork, and I might have no remote named origin. . Credit for the main logic in this code still goes to Artur.\n(defun modi/add-PR-fetch-ref (\u0026amp;optional remote-name) \u0026#34;If refs/pull is not defined on a GH repo, define it. If REMOTE-NAME is not specified, it defaults to the `remote\u0026#39; set for the \\\u0026#34;main\\\u0026#34; or \\\u0026#34;master\\\u0026#34; branch.\u0026#34; (let* ((remote-name (or remote-name (magit-get \u0026#34;branch\u0026#34; \u0026#34;main\u0026#34; \u0026#34;remote\u0026#34;) (magit-get \u0026#34;branch\u0026#34; \u0026#34;master\u0026#34; \u0026#34;remote\u0026#34;))) (remote-url (magit-get \u0026#34;remote\u0026#34; remote-name \u0026#34;url\u0026#34;)) (fetch-refs (and (stringp remote-url) (string-match \u0026#34;github\u0026#34; remote-url) (magit-get-all \u0026#34;remote\u0026#34; remote-name \u0026#34;fetch\u0026#34;))) ;; https://oremacs.com/2015/03/11/git-tricks/ (fetch-address (format \u0026#34;+refs/pull/*/head:refs/pull/%s/*\u0026#34; remote-name))) (when fetch-refs (unless (member fetch-address fetch-refs) (magit-git-string \u0026#34;config\u0026#34; \u0026#34;--add\u0026#34; (format \u0026#34;remote.%s.fetch\u0026#34; remote-name) fetch-address))))) (add-hook \u0026#39;magit-mode-hook #\u0026#39;modi/add-PR-fetch-ref) Code Snippet 1: Function to auto-add GitHub PR references to the repo's .git/config Summary\u0026nbsp;# With the above snippet added to your Emacs config and evaluated, each time you visit a repo cloned from GitHub in the Magit Status buffer (M-x magit-status), the PR refs will get auto-added to that repo\u0026rsquo;s .git/config if needed.\nAfter that, you can easily view the commits from all the PRs by doing l a f a.\nReferences\u0026nbsp;# oremacs \u0026ndash; Some git/magit/github tricks endlessparentheses \u0026ndash; Automatically configure Magit to access Github PRs GitHub \u0026ndash; Checking out PR branches locally "},"name":"View GitHub Pull Requests in Magit","published":"2022-06-23T17:51:00-04:00","summary":"How to view GitHub Pull Request branches locally in the cloned repo,\nand more importantly, how to do that automatically from within Emacs.","type":"entry","url":"https://scripter.co/view-github-pull-requests-in-magit/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#setting-a-fontset-font\"\u003eSetting a \u0026ldquo;fontset\u0026rdquo; font\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#gujarati-fonts\"\u003eGujarati fonts\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eAll Emacs versions ship with a nifty \u003cstrong\u003eHELLO\u003c/strong\u003e file that you can quickly\nopen using \u003ccode\u003eM-x view-hello-file\u003c/code\u003e or its default binding \u003ccode\u003eC-h h\u003c/code\u003e. This\nfile lists \u0026ldquo;Hello\u0026rdquo; written in dozens of languages to demonstrate some\nof the character sets supported by Emacs.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--hello-buffer\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"hello.png\"\u003e\n        \u003cimg src=\"https://scripter.co/gujarati-fonts-in-emacs/hello.png\" alt=\"Figure 1: \u0026ldquo;Hello\u0026rdquo; buffer in Emacs\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003e\u0026ldquo;Hello\u0026rdquo; buffer in Emacs\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eBorn and raised in the Gujarat state in India, I grew up\nspeaking the \u003ca href=\"https://en.wikipedia.org/wiki/Gujarati_language\"\u003eGujarati (ગુજરાતી)\u003c/a\u003e language\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nIndia officially recognizes \u003ca href=\"https://en.wikipedia.org/wiki/Languages_of_India\"\u003e22 languages\u003c/a\u003e (as of \u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2022-06-19 Sun\u0026gt;\u003c/span\u003e\u003c/span\u003e) and\nGujarati is one of them.\n\u003c/small\u003e\u003c/span\u003e\nand so it\u0026rsquo;s also the language closest to my heart. So I was pleasantly\nsurprised to see a representation of Gujarati in the \u0026ldquo;Hello\u0026rdquo; buffer!\nIn the above screenshot, in the \u0026ldquo;South Asia\u0026rdquo; section, the script after\nthe yellow cursor is Gujarati, and it reads \u003cem\u003enamaste\u003c/em\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"setting-a-fontset-font\"\u003eSetting a \u0026ldquo;fontset\u0026rdquo; font\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#setting-a-fontset-font\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIt was on \u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2018-08-13 Mon\u0026gt; \u003c/span\u003e\u003c/span\u003e that I discovered the presence of Gujarati\nscript in that \u0026ldquo;Hello\u0026rdquo; buffer, and the reason I know that exact date\nis because I had \u003ca href=\"https://lists.gnu.org/r/help-gnu-emacs/2018-08/msg00033.html\"\u003easked a question\u003c/a\u003e regarding that on the\n\u003cem\u003ehelp-gnu-emacs\u003c/em\u003e mailing list 😃.\u003c/p\u003e\n\u003cp\u003eThis was the time when Emacs was using the \u003ca href=\"https://www.nongnu.org/m17n/\"\u003em17n\u003c/a\u003e library for\nmulti-lingual font rendering by default. The question was regarding a\nfont rendering issue I was seeing. As I learn later in that thread, it\nwas because I didn\u0026rsquo;t have the m17n database installed on my machine\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nAt least in 2022, the \u003ca href=\"https://github.com/harfbuzz/harfbuzz\"\u003eharfbuzz\u003c/a\u003e library is the recommended library for\ntext shaping and font rendering. Someone please correct me if that\u0026rsquo;s\nwrong. In any case, I have switched to using \u003cem\u003eharfbuzz\u003c/em\u003e instead of\n\u003cem\u003em17n\u003c/em\u003e for a while now and haven\u0026rsquo;t found any font-rendering issues\nwith non-English scripts.\n\u003c/small\u003e\u003c/span\u003e\n. But it\u0026rsquo;s in that support thread that, thanks to \u003cem\u003eAndy Moreton\u003c/em\u003e, I\nlearned that you can change the font for the Gujarati script using\n\u003ccode\u003eset-fontset-font\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThis applies in general to any script. You can read more details about\nthis function in \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/emacs/Modifying-Fontsets.html\" title=\"Emacs Lisp: (info \u0026quot;(emacs) Modifying Fontsets\u0026quot;)\"\u003eEmacs Info: Modifying Fontsets\u003c/a\u003e, but here\u0026rsquo;s the gist:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--gujarati-set-fontset-font\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eset-fontset-font\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;fontset-default\u0026#34;\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;gujarati\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026lt;FONT NAME\u0026gt;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--gujarati-set-fontset-font\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Setting default font for Gujarati script using \u003ccode\u003eset-fontset-font\u003c/code\u003e\n\u003c/div\u003e\n\u003cp\u003eThat led me down the path of exploring the available Gujarati fonts\nout there ..\u003c/p\u003e\n\n\u003ch2 id=\"gujarati-fonts\"\u003eGujarati fonts\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#gujarati-fonts\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eAfter looking around for a bit, I found a wonderful \u003ca href=\"https://github.com/samyakbhuta/chhapkaam/wiki/%E0%AA%97%E0%AB%81%E0%AA%9C%E0%AA%B0%E0%AA%BE%E0%AA%A4%E0%AB%80-%E0%AA%AF%E0%AB%81%E0%AA%A8%E0%AA%BF%E0%AA%95%E0%AB%8B%E0%AA%A1-%E0%AA%AB%E0%AB%8B%E0%AA%A8%E0%AB%8D%E0%AA%9F-%E0%AA%B8%E0%AB%82%E0%AA%9A%E0%AB%80---List-of-Gujarati-Unicode-Fonts\"\u003ecollection of\nGujarati fonts\u003c/a\u003e in this GitHub repository:\n\u003ca href=\"https://github.com/samyakbhuta/chhapkaam\"\u003egithub.com/samyakbhuta/chhapkaam\u003c/a\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThe repo name is \u003cem\u003echhapkaam\u003c/em\u003e (I\nwould have spelled it as \u003cem\u003echhaapkaam\u003c/em\u003e) which is the Gujarati word\nછાપકામ, meaning \u0026ldquo;printing\u0026rdquo;.\n\u003c/small\u003e\u003c/span\u003e\n.\u003c/p\u003e\n\u003cp\u003eBelow is my further curated list of fonts from the above list:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"table--gujarati-fonts\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"table-caption\"\u003e\n  \u003cspan class=\"table-number\"\u003e\u003ca href=\"#table--gujarati-fonts\"\u003eTable 1\u003c/a\u003e:\u003c/span\u003e\n  Gujarati Fonts\n\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eFont Name\u003c/th\u003e\n\u003cth\u003e\u003cem\u003eNamaste\u003c/em\u003e\u003c/th\u003e\n\u003cth\u003eCategory\u003c/th\u003e\n\u003cth\u003eHomepage\u003c/th\u003e\n\u003cth\u003eDownload\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eShruti\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"namaste_shruti.png\" alt=\"\"\u003e\u003c/td\u003e\n\u003ctd\u003eserif\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://www.wfonts.com/font/shruti\"\u003ewfonts.com\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eMukta Vaani\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"namaste_mukta_vaani.png\" alt=\"\"\u003e\u003c/td\u003e\n\u003ctd\u003eserif\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://ektype.in/scripts/gujarati/mukta-vaani.html\"\u003eEk Type \u0026ndash; Mukta Vaani\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://github.com/EkType/Mukta/releases\"\u003eGitHub\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003eLohit Gujarati\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"namaste_lohit.png\" alt=\"\"\u003e\u003c/td\u003e\n\u003ctd\u003esans serif\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://pagure.io/lohit\"\u003ePagure \u0026ndash; Lohit\u003c/a\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"https://releases.pagure.org/lohit/\"\u003epagure releases\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eTo use these fonts, after downloading and installing them on your\nsystem, evaluate \u003ca href=\"#code-snippet--gujarati-set-fontset-font\"\u003eCode Snippet 1\u003c/a\u003e above with the\ncorrect \u0026ldquo;FONT NAME\u0026rdquo;. For example, to set the Gujarati text to use the\n\u003cem\u003eShruti\u003c/em\u003e font, evaluate \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eset-fontset-font\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;fontset-default\u0026#34;\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;gujarati\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Shruti\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThanks for reading (વાંચવા બદલ આભાર) 🙏!\u003c/p\u003e\n","text":" Table of Contents Setting a \u0026ldquo;fontset\u0026rdquo; font Gujarati fonts All Emacs versions ship with a nifty HELLO file that you can quickly open using M-x view-hello-file or its default binding C-h h. This file lists \u0026ldquo;Hello\u0026rdquo; written in dozens of languages to demonstrate some of the character sets supported by Emacs.\nFigure 1: \u0026ldquo;Hello\u0026rdquo; buffer in Emacs Born and raised in the Gujarat state in India, I grew up speaking the Gujarati (ગુજરાતી) language India officially recognizes 22 languages (as of \u0026lt;2022-06-19 Sun\u0026gt;) and Gujarati is one of them. and so it\u0026rsquo;s also the language closest to my heart. So I was pleasantly surprised to see a representation of Gujarati in the \u0026ldquo;Hello\u0026rdquo; buffer! In the above screenshot, in the \u0026ldquo;South Asia\u0026rdquo; section, the script after the yellow cursor is Gujarati, and it reads namaste.\nSetting a \u0026ldquo;fontset\u0026rdquo; font\u0026nbsp;# It was on \u0026lt;2018-08-13 Mon\u0026gt; that I discovered the presence of Gujarati script in that \u0026ldquo;Hello\u0026rdquo; buffer, and the reason I know that exact date is because I had asked a question regarding that on the help-gnu-emacs mailing list 😃.\nThis was the time when Emacs was using the m17n library for multi-lingual font rendering by default. The question was regarding a font rendering issue I was seeing. As I learn later in that thread, it was because I didn\u0026rsquo;t have the m17n database installed on my machine At least in 2022, the harfbuzz library is the recommended library for text shaping and font rendering. Someone please correct me if that\u0026rsquo;s wrong. In any case, I have switched to using harfbuzz instead of m17n for a while now and haven\u0026rsquo;t found any font-rendering issues with non-English scripts. . But it\u0026rsquo;s in that support thread that, thanks to Andy Moreton, I learned that you can change the font for the Gujarati script using set-fontset-font.\nThis applies in general to any script. You can read more details about this function in Emacs Info: Modifying Fontsets, but here\u0026rsquo;s the gist:\n(set-fontset-font \u0026#34;fontset-default\u0026#34; \u0026#39;gujarati \u0026#34;\u0026lt;FONT NAME\u0026gt;\u0026#34;) Code Snippet 1: Setting default font for Gujarati script using set-fontset-font That led me down the path of exploring the available Gujarati fonts out there ..\nGujarati fonts\u0026nbsp;# After looking around for a bit, I found a wonderful collection of Gujarati fonts in this GitHub repository: github.com/samyakbhuta/chhapkaam The repo name is chhapkaam (I would have spelled it as chhaapkaam) which is the Gujarati word છાપકામ, meaning \u0026ldquo;printing\u0026rdquo;. .\nBelow is my further curated list of fonts from the above list:\nTable 1: Gujarati Fonts Font Name Namaste Category Homepage Download Shruti serif wfonts.com Mukta Vaani serif Ek Type \u0026ndash; Mukta Vaani GitHub Lohit Gujarati sans serif Pagure \u0026ndash; Lohit pagure releases To use these fonts, after downloading and installing them on your system, evaluate Code Snippet 1 above with the correct \u0026ldquo;FONT NAME\u0026rdquo;. For example, to set the Gujarati text to use the Shruti font, evaluate (set-fontset-font \u0026#34;fontset-default\u0026#34; \u0026#39;gujarati \u0026#34;Shruti\u0026#34;).\nThanks for reading (વાંચવા બદલ આભાર) 🙏!\n"},"name":"Gujarati fonts in Emacs","published":"2022-06-19T01:31:00-04:00","summary":"Setting a different font for a specific script or language in Emacs.","type":"entry","url":"https://scripter.co/gujarati-fonts-in-emacs/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#overview-on-using-advices\"\u003eOverview on using advices\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--before\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e \u003ccode\u003e:before\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--after\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e \u003ccode\u003e:after\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--override\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e \u003ccode\u003e:override\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--around\"\u003e\u003cspan class=\"section-num\"\u003e4\u003c/span\u003e \u003ccode\u003e:around\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--before-while\"\u003e\u003cspan class=\"section-num\"\u003e5\u003c/span\u003e \u003ccode\u003e:before-while\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--before-until\"\u003e\u003cspan class=\"section-num\"\u003e6\u003c/span\u003e \u003ccode\u003e:before-until\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--after-while\"\u003e\u003cspan class=\"section-num\"\u003e7\u003c/span\u003e \u003ccode\u003e:after-while\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--after-until\"\u003e\u003cspan class=\"section-num\"\u003e8\u003c/span\u003e \u003ccode\u003e:after-until\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--filter-args\"\u003e\u003cspan class=\"section-num\"\u003e9\u003c/span\u003e \u003ccode\u003e:filter-args\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--filter-return\"\u003e\u003cspan class=\"section-num\"\u003e10\u003c/span\u003e \u003ccode\u003e:filter-return\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#summary\"\u003eSummary\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#advice-combinators--references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eIf you have read some of my earlier posts, you would know that I\nreally enjoy using the Emacs Advice system 😃.\u003c/p\u003e\n\u003cp\u003eThe \u0026ldquo;advice\u0026rdquo; feature lets you add to the existing definition of a\nfunction, by \u003cem\u003eadvising the function\u003c/em\u003e.  This is a cleaner method than\nredefining the whole function, because it\u0026rsquo;s easier to debug and if you\ndon\u0026rsquo;t need it, you can just \u003cem\u003eremove\u003c/em\u003e the advice.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eYou can jump to the \u003ca href=\"#advice-combinators--references\"\u003eReferences section\u003c/a\u003e below if you need to look at\nthe related sections in the Emacs Lisp Manual.\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"overview-on-using-advices\"\u003eOverview on using advices\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#overview-on-using-advices\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eI do not plan to write a tutorial on how to write advices in\nEmacs-Lisp, but here\u0026rsquo;s a 3-second primer:\u003c/p\u003e\n\u003cdl\u003e\n\u003cdt\u003eTo add an advice\u003c/dt\u003e\n\u003cdd\u003e\u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvice-add\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;original-fn\u003c/span\u003e \u003cspan class=\"nv\"\u003e\u0026lt;combinator\u0026gt;\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvising-fn\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/code\u003e\u003c/dd\u003e\n\u003cdt\u003eTo remove an advice\u003c/dt\u003e\n\u003cdd\u003e\u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvice-remove\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;original-fn\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvising-fn\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/code\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\u003cp\u003eThis article attempts to briefly describe different ways of advising a\nfunction, using 10 different \u003cem\u003ecombinators\u003c/em\u003e. If you have never used\nadvices in your Emacs config, don\u0026rsquo;t worry. I am hopeful that the\ndiagrams in this post and the examples linked for some of the\ncombinators in the Summary section makes this concept a bit easier to\nassimilate.\u003c/p\u003e\n\u003cdl\u003e\n\u003cdt\u003eDiagram Legend\u003c/dt\u003e\n\u003cdd\u003e\u003cul\u003e\n\u003cli\u003eInitial black circle: Original Fn input arguments\u003c/li\u003e\n\u003cli\u003eYellow box: Original Fn\u003c/li\u003e\n\u003cli\u003eGray box: Advising Fn\u003c/li\u003e\n\u003cli\u003eBlack circle inside a white circle: Return values\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ch2 id=\"advice-combinators--before\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e \u003ccode\u003e:before\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--before\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-before\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/before.svg\" alt=\"Figure 1: :before advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003e\u003cstrong\u003e:before\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--after\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e \u003ccode\u003e:after\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--after\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-after\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/after.svg\" alt=\"Figure 2: :after advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 2: \u003c/span\u003e\u003cstrong\u003e:after\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--override\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e \u003ccode\u003e:override\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--override\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-override\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/override.svg\" alt=\"Figure 3: :override advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 3: \u003c/span\u003e\u003cstrong\u003e:override\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--around\"\u003e\u003cspan class=\"section-num\"\u003e4\u003c/span\u003e \u003ccode\u003e:around\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--around\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-around\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/around.svg\" alt=\"Figure 4: :around advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 4: \u003c/span\u003e\u003cstrong\u003e:around\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--before-while\"\u003e\u003cspan class=\"section-num\"\u003e5\u003c/span\u003e \u003ccode\u003e:before-while\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--before-while\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-before-while\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/before-while.svg\" alt=\"Figure 5: :before-while advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 5: \u003c/span\u003e\u003cstrong\u003e:before-while\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--before-until\"\u003e\u003cspan class=\"section-num\"\u003e6\u003c/span\u003e \u003ccode\u003e:before-until\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--before-until\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-before-until\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/before-until.svg\" alt=\"Figure 6: :before-until advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 6: \u003c/span\u003e\u003cstrong\u003e:before-until\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--after-while\"\u003e\u003cspan class=\"section-num\"\u003e7\u003c/span\u003e \u003ccode\u003e:after-while\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--after-while\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-after-while\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/after-while.svg\" alt=\"Figure 7: :after-while advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 7: \u003c/span\u003e\u003cstrong\u003e:after-while\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--after-until\"\u003e\u003cspan class=\"section-num\"\u003e8\u003c/span\u003e \u003ccode\u003e:after-until\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--after-until\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-after-until\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/after-until.svg\" alt=\"Figure 8: :after-until advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 8: \u003c/span\u003e\u003cstrong\u003e:after-until\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--filter-args\"\u003e\u003cspan class=\"section-num\"\u003e9\u003c/span\u003e \u003ccode\u003e:filter-args\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--filter-args\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-filter-args\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/filter-args.svg\" alt=\"Figure 9: :filter-args advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 9: \u003c/span\u003e\u003cstrong\u003e:filter-args\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"advice-combinators--filter-return\"\u003e\u003cspan class=\"section-num\"\u003e10\u003c/span\u003e \u003ccode\u003e:filter-return\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--filter-return\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"figure--advice-combinators-filter-return\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/emacs-lisp-advice-combinators/filter-return.svg\" alt=\"Figure 10: :filter-return advice\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 10: \u003c/span\u003e\u003cstrong\u003e:filter-return\u003c/strong\u003e advice\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"summary\"\u003eSummary\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#summary\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eHere\u0026rsquo;s a concise summary of what each advice combinator does. For\nbrevity, the \u003cem\u003eadvising function\u003c/em\u003e is called \u003cem\u003eA\u003c/em\u003e and the \u003cem\u003eoriginal\nfunction\u003c/em\u003e is called \u003cem\u003eO\u003c/em\u003e.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eOnce you click on any of the example posts, search for \u003ccode\u003eadvice-add\u003c/code\u003e on\nthat page to find the code example.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003ca id=\"table--advice-combinator-summary\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"table-caption\"\u003e\n  \u003cspan class=\"table-number\"\u003e\u003ca href=\"#table--advice-combinator-summary\"\u003eTable 1\u003c/a\u003e:\u003c/span\u003e\n  Summary of what each advice combinator means\n\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eCombinator\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003cth\u003eExample\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:before\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eA\u003c/em\u003e is called before \u003cem\u003eO\u003c/em\u003e. \u003cem\u003eO\u003c/em\u003e args and return values are not modified.\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:after\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eA\u003c/em\u003e is called after \u003cem\u003eO\u003c/em\u003e. \u003cem\u003eO\u003c/em\u003e args and return values are not modified.\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:override\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eA\u003c/em\u003e is called in lieu of \u003cem\u003eO\u003c/em\u003e. \u003cem\u003eA\u003c/em\u003e gets the same args as \u003cem\u003eO\u003c/em\u003e.\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"/zero-html-validation-errors/\"\u003eZero HTML Validation Errors!\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:around\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eA\u003c/em\u003e is called in lieu of \u003cem\u003eO\u003c/em\u003e. \u003cem\u003eA\u003c/em\u003e gets \u003cem\u003eO\u003c/em\u003e fn + \u003cem\u003eO\u003c/em\u003e args as args.\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"/using-emacs-advice-to-silence-messages-from-functions/\"\u003eUsing Emacs advice to silence messages from functions\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:before-while\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eA\u003c/em\u003e is called first. If it returns non-nil, \u003cem\u003eO\u003c/em\u003e is called.\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:before-until\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eA\u003c/em\u003e is called first. If it returns nil, \u003cem\u003eO\u003c/em\u003e is called.\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"/org-show-only-post-subtree-headings/\"\u003eOrg: Show only Post subtree headings\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:after-while\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eO\u003c/em\u003e is called first. If it returns non-nil, \u003cem\u003eA\u003c/em\u003e is called.\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:after-until\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eO\u003c/em\u003e is called first. If it returns nil, \u003cem\u003eA\u003c/em\u003e is called.\u003c/td\u003e\n\u003ctd\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:filter-args\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eA\u003c/em\u003e is called first. \u003cem\u003eO\u003c/em\u003e is called next with return value from \u003cem\u003eA\u003c/em\u003e as input.\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"/narrowing-the-author-column-in-magit/\"\u003eNarrowing the Author column in Magit\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e:filter-return\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003eO\u003c/em\u003e is called first. \u003cem\u003eA\u003c/em\u003e is called next with return value from \u003cem\u003eO\u003c/em\u003e as input.\u003c/td\u003e\n\u003ctd\u003e\u003ca href=\"/zero-html-validation-errors/\"\u003eZero HTML Validation Errors!\u003c/a\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eIf you have any feedback on how these diagrams can be made easier to\nunderstand, please let me know.\u003c/p\u003e\n\n\u003ch2 id=\"advice-combinators--references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#advice-combinators--references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html\" title=\"Emacs Lisp: (info \u0026quot;(elisp) Advising Functions\u0026quot;)\"\u003eElisp Info: Advising Functions\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Advice-Combinators.html\" title=\"Emacs Lisp: (info \u0026quot;(elisp) Advice Combinators\u0026quot;)\"\u003eElisp Info: Advice Combinators\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n","text":" Table of Contents Overview on using advices 1 :before 2 :after 3 :override 4 :around 5 :before-while 6 :before-until 7 :after-while 8 :after-until 9 :filter-args 10 :filter-return Summary References If you have read some of my earlier posts, you would know that I really enjoy using the Emacs Advice system 😃.\nThe \u0026ldquo;advice\u0026rdquo; feature lets you add to the existing definition of a function, by advising the function. This is a cleaner method than redefining the whole function, because it\u0026rsquo;s easier to debug and if you don\u0026rsquo;t need it, you can just remove the advice.\nYou can jump to the References section below if you need to look at the related sections in the Emacs Lisp Manual.\nOverview on using advices\u0026nbsp;# I do not plan to write a tutorial on how to write advices in Emacs-Lisp, but here\u0026rsquo;s a 3-second primer:\nTo add an advice (advice-add \u0026#39;original-fn \u0026lt;combinator\u0026gt; #\u0026#39;advising-fn) To remove an advice (advice-remove \u0026#39;original-fn #\u0026#39;advising-fn) This article attempts to briefly describe different ways of advising a function, using 10 different combinators. If you have never used advices in your Emacs config, don\u0026rsquo;t worry. I am hopeful that the diagrams in this post and the examples linked for some of the combinators in the Summary section makes this concept a bit easier to assimilate.\nDiagram Legend Initial black circle: Original Fn input arguments Yellow box: Original Fn Gray box: Advising Fn Black circle inside a white circle: Return values 1 :before\u0026nbsp;# Figure 1: :before advice 2 :after\u0026nbsp;# Figure 2: :after advice 3 :override\u0026nbsp;# Figure 3: :override advice 4 :around\u0026nbsp;# Figure 4: :around advice 5 :before-while\u0026nbsp;# Figure 5: :before-while advice 6 :before-until\u0026nbsp;# Figure 6: :before-until advice 7 :after-while\u0026nbsp;# Figure 7: :after-while advice 8 :after-until\u0026nbsp;# Figure 8: :after-until advice 9 :filter-args\u0026nbsp;# Figure 9: :filter-args advice 10 :filter-return\u0026nbsp;# Figure 10: :filter-return advice Summary\u0026nbsp;# Here\u0026rsquo;s a concise summary of what each advice combinator does. For brevity, the advising function is called A and the original function is called O.\nOnce you click on any of the example posts, search for advice-add on that page to find the code example.\nTable 1: Summary of what each advice combinator means Combinator Description Example :before A is called before O. O args and return values are not modified. :after A is called after O. O args and return values are not modified. :override A is called in lieu of O. A gets the same args as O. Zero HTML Validation Errors! :around A is called in lieu of O. A gets O fn + O args as args. Using Emacs advice to silence messages from functions :before-while A is called first. If it returns non-nil, O is called. :before-until A is called first. If it returns nil, O is called. Org: Show only Post subtree headings :after-while O is called first. If it returns non-nil, A is called. :after-until O is called first. If it returns nil, A is called. :filter-args A is called first. O is called next with return value from A as input. Narrowing the Author column in Magit :filter-return O is called first. A is called next with return value from O as input. Zero HTML Validation Errors! If you have any feedback on how these diagrams can be made easier to understand, please let me know.\nReferences\u0026nbsp;# Elisp Info: Advising Functions Elisp Info: Advice Combinators "},"name":"Emacs Lisp: Advice Combinators","published":"2022-06-17T21:30:00-04:00","summary":"My diagrammatic take on summarizing all the Emacs advice combinators.","type":"entry","url":"https://scripter.co/emacs-lisp-advice-combinators/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#org-global-cycle\"\u003eOrg Global Cycle\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#skeleton-of-only-post-headings\"\u003eSkeleton of only Post headings\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#the-collapse-all-posts-function\"\u003eThe \u0026ldquo;Collapse All Posts\u0026rdquo; function\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#binding-with-c-u-c-c-tab\"\u003eBinding with \u003ccode\u003eC-u C-c TAB\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#result\"\u003eResult\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eI start this post by introducing what the Org mode global cycling\ncommand does, what kind of subtree folding I actually need, and then\nshare the solution with code snippets.\u003c/p\u003e\n\n\u003ch2 id=\"org-global-cycle\"\u003eOrg Global Cycle\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#org-global-cycle\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eOrg mode has a built-in \u003ccode\u003eorg-global-cycle\u003c/code\u003e command that you might be\nfamiliar with. It\u0026rsquo;s bound by default to the \u003ccode\u003eS-TAB\u003c/code\u003e key. Each time\nthis command is called, the Org buffer will cycle through these\nstates:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eOverview: Show only the Level 1 headings and collapse everything\nunderneath.\u003c/li\u003e\n\u003cli\u003eContents: Show only the Org headings and collapse all the content.\u003c/li\u003e\n\u003cli\u003eShow All: Expand all the headings and show their contents too.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eIf a numeric prefix \u003cem\u003eN\u003c/em\u003e is used with this command, it will show only\nthe Org headings up to Level \u003cem\u003eN\u003c/em\u003e. For example, \u003ccode\u003eC-2 S-TAB\u003c/code\u003e will show\nonly the headings up to Level 2.\u003c/p\u003e\n\u003cp\u003eThis is a really helpful command, but I needed something different ..\u003c/p\u003e\n\n\u003ch2 id=\"skeleton-of-only-post-headings\"\u003eSkeleton of only Post headings\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#skeleton-of-only-post-headings\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eI maintain most of this website\u0026rsquo;s content in a single Org file. I have\ndozens of blog posts organized in Org subtrees, which I further\norganize under \u0026ldquo;category\u0026rdquo; headings .. It kind of looks like the below\nmock-up:\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nIt\u0026rsquo;s amazing how many features PlantUML has. If you are interested in\ncreating diagrams like these, check out the \u003ca href=\"https://plantuml.com/salt\"\u003ePlantUML Salt\u003c/a\u003e syntax.\n\u003c/small\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--post-subtrees-collapsed-mockup\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/org-show-only-post-subtree-headings/post-subtrees.svg\" alt=\"Figure 1: Post Subtrees at arbitrary heading levels\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003ePost Subtrees at arbitrary heading levels\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eAs we can see,\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAll the post subtrees are not at Level 1 headings.\u003c/li\u003e\n\u003cli\u003eThey are also not at a fixed Level \u003cem\u003eN\u003c/em\u003e.\u003c/li\u003e\n\u003cli\u003eThe heading level of the post depends on how many parent categories\nthat post has (and that will also change over time).\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eI needed to basically show everything leading up to a post subtree\nheading, and then collapse all the content under that post; even the\nsub-headings.\u003c/p\u003e\n\n\u003ch2 id=\"the-collapse-all-posts-function\"\u003eThe \u0026ldquo;Collapse All Posts\u0026rdquo; function\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#the-collapse-all-posts-function\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThe \u003ccode\u003emodi/org-hugo-collapse-all-posts\u003c/code\u003e function defined below meets\nthe above requirement:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eIt first widens the whole buffer and expands all the headings.\u003c/li\u003e\n\u003cli\u003eThen it loops through all the headings and collapses all the \u003cem\u003epost\nsubtrees\u003c/em\u003e i.e. all the subtrees that have the \u003ccode\u003eEXPORT_FILE_NAME\u003c/code\u003e\nproperty set. This is where I use the \u003ca href=\"/looping-through-org-mode-headings/\"\u003e\u003ccode\u003eorg-map-entries\u003c/code\u003e\u003c/a\u003e magic.\u003c/li\u003e\n\u003cli\u003eFinally it looks for Org headings that begin with \u0026ldquo;Footnotes\u0026rdquo; or\n\u0026ldquo;COMMENT\u0026rdquo; and collapses them as well.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eI am using the development version of Org mode (version 9.6, yet to be\nreleased as of \u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2022-06-15 Wed\u0026gt;\u003c/span\u003e\u003c/span\u003e) which has the new \u003ccode\u003eorg-fold\u003c/code\u003e\nlibrary. This library obsoletes the use of \u003ccode\u003eoutline.el\u003c/code\u003e library and\nother \u003cem\u003ecode-folding\u003c/em\u003e related functions in Org mode. So \u003ccode\u003ecl-flet\u003c/code\u003e is\nused to create function symbol aliases that use the \u003ccode\u003eorg-fold-*\u003c/code\u003e\nfunctions if available, otherwise they fall back to the legacy\nfunctions.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--collapse-all-posts-fn\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e 1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e 9\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e10\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e11\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e12\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e13\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e14\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e15\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e16\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e17\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e18\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\"\u003e19\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"lnt\"\u003e20\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e21\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e22\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\"\u003e23\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"lnt\"\u003e24\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e25\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-hugo-collapse-all-posts\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Collapse all post subtrees in the current buffer.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eAlso collapse the Footnotes subtree and COMMENT subtrees if\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003epresent.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eA post subtree is one that has the EXPORT_FILE_NAME property\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eset.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ecl-flet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eshow-all\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efboundp\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;org-fold-show-all\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-fold-show-all\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-show-all\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ehide-subtree\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efboundp\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;org-fold-hide-subtree\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                              \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-fold-hide-subtree\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eoutline-hide-subtree\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ewiden\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eshow-all\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eheadings\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; Collapse all the post subtrees (ones with EXPORT_FILE_NAME\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; property set).\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-map-entries\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003ehide-subtree\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;EXPORT_FILE_NAME\u0026lt;\u0026gt;\\\u0026#34;\\\u0026#34;\u0026#34;\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;file\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; Also hide Footnotes and comments.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003epoint-min\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-forward\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;^\\\\(\\\\* Footnotes\\\\|\\\\*+ COMMENT\\\\)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"nb\"\u003e:noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ehide-subtree\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--collapse-all-posts-fn\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Function that collapses all the post subtrees in the current buffer\n\u003c/div\u003e\n\n\u003ch2 id=\"binding-with-c-u-c-c-tab\"\u003eBinding with \u003ccode\u003eC-u C-c TAB\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#binding-with-c-u-c-c-tab\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThe function is ready, but let\u0026rsquo;s now add a bit of convenience to it.\u003c/p\u003e\n\u003cp\u003eIf a point is under a subtree, \u003ccode\u003eC-c TAB\u003c/code\u003e will collapse that subtree\nwhile showing only Level 1 headings, and if a numeric prefix is used,\nit will show only those many levels of headings. I decided to bind the\nabove function to \u003ccode\u003eC-u C-c TAB\u003c/code\u003e because,\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eThe behavior of \u003ccode\u003emodi/org-hugo-collapse-all-posts\u003c/code\u003e falls in the\nsame category as that of \u003ccode\u003eC-c TAB\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003eC-u C-c ..\u003c/code\u003e binding rolls off the fingers pretty\nnicely 😃.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis \u003cem\u003ebinding\u003c/em\u003e is achieved using one of my favorite Emacs features\n.. the \u003cstrong\u003eadvice\u003c/strong\u003e system. The \u003ccode\u003e:before-until\u003c/code\u003e \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Advice-Combinators.html\" title=\"Emacs Lisp: (info \u0026quot;(elisp) Advice Combinators\u0026quot;)\"\u003eAdvice Combinator\u003c/a\u003e is used\nhere, which means that if the \u003cem\u003eadvising\u003c/em\u003e function (below) returns a\n\u003cem\u003enil\u003c/em\u003e, the \u003cem\u003eadvised\u003c/em\u003e or the original function \u003ccode\u003eorg-ctrl-c-tab\u003c/code\u003e is not\ncalled.\u003c/p\u003e\n\u003cp\u003eThe \u003cem\u003eadvising\u003c/em\u003e function below detects if the \u003ccode\u003eC-u\u003c/code\u003e prefix argument is\nused. If it is, the \u003ccode\u003emodi/org-hugo-collapse-all-posts\u003c/code\u003e function is\ncalled, otherwise the original \u003ccode\u003eorg-ctrl-c-tab\u003c/code\u003e function is called.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--collapse-all-posts-binding\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"lnt\"\u003e5\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e6\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e7\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e8\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e9\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-ctrl-c-tab-advice\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kp\"\u003e\u0026amp;rest\u003c/span\u003e \u003cspan class=\"nv\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Run \u003c/span\u003e\u003cspan class=\"ss\"\u003e`modi/org-hugo-collapse-all-posts\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e when\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003edoing \\\\[universal-argument] \\\\[org-ctrl-c-tab].\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003edo-not-run-orig-fn\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eequal\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003ecurrent-prefix-arg\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003edo-not-run-orig-fn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/org-hugo-collapse-all-posts\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nv\"\u003edo-not-run-orig-fn\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvice-add\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;org-ctrl-c-tab\u003c/span\u003e \u003cspan class=\"nb\"\u003e:before-until\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/org-ctrl-c-tab-advice\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--collapse-all-posts-binding\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Bind \u003ccode\u003eC-u C-c TAB\u003c/code\u003e to call \u003ccode\u003emodi/org-hugo-collapse-all-posts\u003c/code\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"result\"\u003eResult\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#result\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eAfter evaluating the above two snippets, when I do \u003ccode\u003eC-u C-c TAB\u003c/code\u003e in\nmy \u0026ldquo;blog posts\u0026rdquo; Org buffer, I see this:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--post-subtrees-collapsed\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"post-subtrees-collapsed.png\"\u003e\n        \u003cimg src=\"https://scripter.co/org-show-only-post-subtree-headings/post-subtrees-collapsed.png\" alt=\"Figure 2: My \u0026ldquo;blog posts\u0026rdquo; Org buffer showing only the Post subtree headings\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 2: \u003c/span\u003eMy \u0026ldquo;blog posts\u0026rdquo; Org buffer showing only the Post subtree headings\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eIt matches \u003ca href=\"#figure--post-subtrees-collapsed-mockup\"\u003ethat earlier mockup\u003c/a\u003e \u0026mdash; Mission accomplished! 💯\u003c/p\u003e\n","text":" Table of Contents Org Global Cycle Skeleton of only Post headings The \u0026ldquo;Collapse All Posts\u0026rdquo; function Binding with C-u C-c TAB Result I start this post by introducing what the Org mode global cycling command does, what kind of subtree folding I actually need, and then share the solution with code snippets.\nOrg Global Cycle\u0026nbsp;# Org mode has a built-in org-global-cycle command that you might be familiar with. It\u0026rsquo;s bound by default to the S-TAB key. Each time this command is called, the Org buffer will cycle through these states:\nOverview: Show only the Level 1 headings and collapse everything underneath. Contents: Show only the Org headings and collapse all the content. Show All: Expand all the headings and show their contents too. If a numeric prefix N is used with this command, it will show only the Org headings up to Level N. For example, C-2 S-TAB will show only the headings up to Level 2.\nThis is a really helpful command, but I needed something different ..\nSkeleton of only Post headings\u0026nbsp;# I maintain most of this website\u0026rsquo;s content in a single Org file. I have dozens of blog posts organized in Org subtrees, which I further organize under \u0026ldquo;category\u0026rdquo; headings .. It kind of looks like the below mock-up: It\u0026rsquo;s amazing how many features PlantUML has. If you are interested in creating diagrams like these, check out the PlantUML Salt syntax. Figure 1: Post Subtrees at arbitrary heading levels As we can see,\nAll the post subtrees are not at Level 1 headings. They are also not at a fixed Level N. The heading level of the post depends on how many parent categories that post has (and that will also change over time). I needed to basically show everything leading up to a post subtree heading, and then collapse all the content under that post; even the sub-headings.\nThe \u0026ldquo;Collapse All Posts\u0026rdquo; function\u0026nbsp;# The modi/org-hugo-collapse-all-posts function defined below meets the above requirement:\nIt first widens the whole buffer and expands all the headings. Then it loops through all the headings and collapses all the post subtrees i.e. all the subtrees that have the EXPORT_FILE_NAME property set. This is where I use the org-map-entries magic. Finally it looks for Org headings that begin with \u0026ldquo;Footnotes\u0026rdquo; or \u0026ldquo;COMMENT\u0026rdquo; and collapses them as well. I am using the development version of Org mode (version 9.6, yet to be released as of \u0026lt;2022-06-15 Wed\u0026gt;) which has the new org-fold library. This library obsoletes the use of outline.el library and other code-folding related functions in Org mode. So cl-flet is used to create function symbol aliases that use the org-fold-* functions if available, otherwise they fall back to the legacy functions.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 (defun modi/org-hugo-collapse-all-posts () \u0026#34;Collapse all post subtrees in the current buffer. Also collapse the Footnotes subtree and COMMENT subtrees if present. A post subtree is one that has the EXPORT_FILE_NAME property set.\u0026#34; (interactive) (cl-flet ((show-all (if (fboundp \u0026#39;org-fold-show-all) #\u0026#39;org-fold-show-all #\u0026#39;org-show-all)) (hide-subtree (if (fboundp \u0026#39;org-fold-hide-subtree) #\u0026#39;org-fold-hide-subtree #\u0026#39;outline-hide-subtree))) (widen) (show-all \u0026#39;(headings)) ;; Collapse all the post subtrees (ones with EXPORT_FILE_NAME ;; property set). (org-map-entries #\u0026#39;hide-subtree \u0026#34;EXPORT_FILE_NAME\u0026lt;\u0026gt;\\\u0026#34;\\\u0026#34;\u0026#34; \u0026#39;file) ;; Also hide Footnotes and comments. (save-excursion (goto-char (point-min)) (while (re-search-forward \u0026#34;^\\\\(\\\\* Footnotes\\\\|\\\\*+ COMMENT\\\\)\u0026#34; nil :noerror) (hide-subtree))))) Code Snippet 1: Function that collapses all the post subtrees in the current buffer Binding with C-u C-c TAB\u0026nbsp;# The function is ready, but let\u0026rsquo;s now add a bit of convenience to it.\nIf a point is under a subtree, C-c TAB will collapse that subtree while showing only Level 1 headings, and if a numeric prefix is used, it will show only those many levels of headings. I decided to bind the above function to C-u C-c TAB because,\nThe behavior of modi/org-hugo-collapse-all-posts falls in the same category as that of C-c TAB. The C-u C-c .. binding rolls off the fingers pretty nicely 😃. This binding is achieved using one of my favorite Emacs features .. the advice system. The :before-until Advice Combinator is used here, which means that if the advising function (below) returns a nil, the advised or the original function org-ctrl-c-tab is not called.\nThe advising function below detects if the C-u prefix argument is used. If it is, the modi/org-hugo-collapse-all-posts function is called, otherwise the original org-ctrl-c-tab function is called.\n1 2 3 4 5 6 7 8 9 (defun modi/org-ctrl-c-tab-advice (\u0026amp;rest args) \u0026#34;Run `modi/org-hugo-collapse-all-posts\u0026#39; when doing \\\\[universal-argument] \\\\[org-ctrl-c-tab].\u0026#34; (let ((do-not-run-orig-fn (equal \u0026#39;(4) current-prefix-arg))) (when do-not-run-orig-fn (modi/org-hugo-collapse-all-posts)) do-not-run-orig-fn)) (advice-add \u0026#39;org-ctrl-c-tab :before-until #\u0026#39;modi/org-ctrl-c-tab-advice) Code Snippet 2: Bind C-u C-c TAB to call modi/org-hugo-collapse-all-posts Result\u0026nbsp;# After evaluating the above two snippets, when I do C-u C-c TAB in my \u0026ldquo;blog posts\u0026rdquo; Org buffer, I see this:\nFigure 2: My \u0026ldquo;blog posts\u0026rdquo; Org buffer showing only the Post subtree headings It matches that earlier mockup \u0026mdash; Mission accomplished! 💯\n"},"name":"Org: Show only Post subtree headings","published":"2022-06-16T00:21:00-04:00","summary":"How to define a custom org-global-cycle-like command that collapses only the Org subtrees with specific properties.","type":"entry","url":"https://scripter.co/org-show-only-post-subtree-headings/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#avoid-duplicate-heading-id-attributes\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Avoid duplicate heading \u003ccode\u003eid\u003c/code\u003e attributes\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#remove-inline-style-elements\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Remove inline \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e elements\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ensure-that-all-images-have-captions-or-alt-attributes\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e Ensure that all images have captions or \u003ccode\u003ealt\u003c/code\u003e attributes\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#do-not-have-hyperlinks-in-headings\"\u003e\u003cspan class=\"section-num\"\u003e4\u003c/span\u003e Do not have hyperlinks in headings\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#validation-ignores\"\u003eValidation Ignores\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#ignore-errors-due-to-hyperlinks-in-inline-svg\"\u003e\u003cspan class=\"section-num\"\u003e5\u003c/span\u003e Ignore errors due to hyperlinks in inline SVG\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#ignore-files-not-expected-to-serve-html-content\"\u003e\u003cspan class=\"section-num\"\u003e6\u003c/span\u003e Ignore files not expected to serve HTML content\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#summary\"\u003eSummary\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eIn my \u003ca href=\"/offline-html5-validator/\"\u003eprevious HTML5 Validator post\u003c/a\u003e, I mentioned:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI was a bit disappointed to see validation errors on my site, but then\nit wasn\u0026rsquo;t too bad .. 46 errors.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eBut they truly say ..\u003c/p\u003e\n\u003cdiv class=\"org-center\"\u003e\n\u003cp\u003eIgnorance is bliss.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eSo .. once I realized that my site had 46 validation errors, I lost\nthat \u003cem\u003ebliss\u003c/em\u003e .. and I couldn\u0026rsquo;t rest easy \u0026mdash; I had to fix them all\n😁.\u003c/p\u003e\n\u003cp\u003eThis post summarizes the categories of those errors and how I fixed\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThe fixes mentioned in this post refer to changes in Org mode\ncontent. But you should be able to derive equivalent fixes for\nMarkdown too.\n\u003c/small\u003e\u003c/span\u003e\nthem all.\u003c/p\u003e\n\n\u003ch2 id=\"avoid-duplicate-heading-id-attributes\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Avoid duplicate heading \u003ccode\u003eid\u003c/code\u003e attributes\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#avoid-duplicate-heading-id-attributes\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/notes/​string-fns-nim-vs-python/index.html\u0026#34;:636.34-636.46: error: Duplicate ID \u0026#34;notes\u0026#34;.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/notes/​nim-fmt/index.html\u0026#34;:300.34-300.52: error: Duplicate ID \u0026#34;older-issue\u0026#34;.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/notes/​nim-fmt/index.html\u0026#34;:306.20-306.33: error: Duplicate ID \u0026#34;floats\u0026#34;.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/page/6/index.html\u0026#34;:29.39-29.54: error: Duplicate ID \u0026#34;fnref:1\u0026#34;.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eErrors with above kind of signatures were fixed by,\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eConverting headings to description lists\u003c/p\u003e\n\u003cp\u003eI had a bunch of generic headings like \u0026ldquo;Notes\u0026rdquo; and \u0026ldquo;Older Issue\u0026rdquo; in\nsome of my posts. After taking a second look at those, it made more\nsense to convert those to description lists. So in Org mode, I\nconverted headings like \u003ccode class=\"code-inline language-org\"\u003e\u003cspan class=\"gh\"\u003e*\u003c/span\u003e\u003cspan class=\"gs\"\u003e Notes\u003c/span\u003e\u003c/code\u003e to\ndescription lists \u003ccode class=\"code-inline language-org\"\u003e\u003cspan class=\"k\"\u003e- \u003c/span\u003eNotes ::\u003c/code\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSetting \u003ccode\u003eCUSTOM_ID\u003c/code\u003e heading property\u003c/p\u003e\n\u003cp\u003eFor the cases, where the headings needed to be left as so, their\nIDs were uniquified by setting their \u003ccode\u003eCUSTOM_ID\u003c/code\u003e property. For\nexample, below fixed the \u003cem\u003eDuplicate ID \u0026ldquo;floats\u0026rdquo;\u003c/em\u003e errors.\n\u003ca id=\"code-snippet--using-custom-id-to-uniquify-heading-id\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-diff\" data-lang=\"diff\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e ** Precision\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e *** Floats\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e+:PROPERTIES:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e+:CUSTOM_ID: precision-floats\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e+:END:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e\u003c/span\u003e ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e ** Type (only for numbers)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e *** Floats\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e+:PROPERTIES:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e+:CUSTOM_ID: type-floats\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e+:END:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--using-custom-id-to-uniquify-heading-id\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Using \u003ccode\u003eCUSTOM_ID\u003c/code\u003e property to uniquify heading ID's\n\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003ePrevent footnote links in post summaries\u003c/p\u003e\n\u003cp\u003eThis issue was due to me not being conscious about how the footnote\nreferences work in a post \u003cem\u003eversus\u003c/em\u003e on a page outside that post\u0026rsquo;s\ncontext.  The issue was caused by footnote references getting into\nthe post summaries parsed by Hugo, which will then show up on the\nlist pages.\u003c/p\u003e\n\u003cp\u003eThe fix was simple \u0026mdash; Edit the post summaries so that they don\u0026rsquo;t\ncontain any footnote references.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"remove-inline-style-elements\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Remove inline \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e elements\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#remove-inline-style-elements\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/​grep-po/index.html\u0026#34;:51.139-51.145: error: Element \u0026#34;style\u0026#34; not allowed as child of element \u0026#34;div\u0026#34; in this context. (Suppressing further errors from this subtree.)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/​how-do-i-write-org-mode/index.html\u0026#34;:23.194-23.200: error: Element \u0026#34;style\u0026#34; not allowed as child of element \u0026#34;div\u0026#34; in this context. (Suppressing further errors from this subtree.)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eErrors with above kind of signatures were fixed by,\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eAvoiding export of raw \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e elements in the Markdown content\u003c/p\u003e\n\u003cp\u003eI figured out which functions were responsible for injecting\n\u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e elements in Markdown content and then advised them to\nstop that. After applying these advises, I lost the in-content\nrules for CSS classes \u003ccode\u003e.org-center\u003c/code\u003e and \u003ccode\u003e.csl-entry\u003c/code\u003e. So I put\nthose rules directly in this website\u0026rsquo;s CSS.\n\u003ca id=\"code-snippet--advices-to-prevent-style-elem-in-exports\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-blackfriday-center-block\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e_center-block\u003c/span\u003e \u003cspan class=\"nv\"\u003econtents\u003c/span\u003e \u003cspan class=\"nv\"\u003einfo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eclass\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;org-center\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026lt;div class=\\\u0026#34;%s\\\u0026#34;\u0026gt;%s\\n\\n%s\\n\u0026lt;/div\u0026gt;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nv\"\u003eclass\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-blackfriday--extra-div-hack\u003c/span\u003e \u003cspan class=\"nv\"\u003einfo\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003econtents\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvice-add\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;org-blackfriday-center-block\u003c/span\u003e \u003cspan class=\"nb\"\u003e:override\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/org-blackfriday-center-block\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-cite-csl-render-bibliography\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ebib-str\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026lt;style\u0026gt;\\\\.csl-entry[^\u0026lt;]+\u0026lt;/style\u0026gt;\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003ebib-str\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvice-add\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;org-cite-csl-render-bibliography\u003c/span\u003e \u003cspan class=\"nb\"\u003e:filter-return\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/org-cite-csl-render-bibliography\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--advices-to-prevent-style-elem-in-exports\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Emacs-Lisp advices to prevent \u003ccode\u003e\u0026lt;style\u0026gt;\u003c/code\u003e elements in exports\n\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRemoving unnecessary micro-styling\u003c/p\u003e\n\u003cp\u003eI found a single case, where an inline CSS rule was defined in\ncontent for CSS class \u003ccode\u003e.repr-type\u003c/code\u003e for a table. I just removed that\nwithout affecting the looks of that rendered table too much.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"ensure-that-all-images-have-captions-or-alt-attributes\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e Ensure that all images have captions or \u003ccode\u003ealt\u003c/code\u003e attributes\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#ensure-that-all-images-have-captions-or-alt-attributes\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/​hugo-use-goat-code-blocks-for-ascii-diagrams/index.html\u0026#34;:24.130-24.255: error: An \u0026#34;img\u0026#34; element must have an \u0026#34;alt\u0026#34; attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eErrors with above kind of signatures were easily fixed by ensuring\nthat all images had captions\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThankfully, there were only two images that were missing captions.\n\u003c/small\u003e\u003c/span\u003e\n. The Hugo \u003ccode\u003efigure\u003c/code\u003e shortcode adds the caption to the \u003ccode\u003ealt\u003c/code\u003e attribute if\nthe \u003ccode\u003ealt\u003c/code\u003e is not specified separately.\u003c/p\u003e\n\u003cp\u003eAs an example, here\u0026rsquo;s how I fixed the above error:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--adding-a-caption-to-an-image\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-diff\" data-lang=\"diff\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e+ #+name: fig__disproportionate_box_drawing\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e+ #+caption: Disproportionate box drawing characters\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e\u003c/span\u003e[[file:images/​hugo-use-goat-code-blocks-for-ascii-diagrams/ascii-diagram-rendered-in-plain-text-code-block.png]]\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--adding-a-caption-to-an-image\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  A \u003ccode\u003egit diff\u003c/code\u003e showing addition of caption to an image\n\u003c/div\u003e\n\n\u003ch2 id=\"do-not-have-hyperlinks-in-headings\"\u003e\u003cspan class=\"section-num\"\u003e4\u003c/span\u003e Do not have hyperlinks in headings\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#do-not-have-hyperlinks-in-headings\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/​using-emacs-advice-to-silence-messages-from-functions/index.html\u0026#34;:151.687-151.732: error: Start tag \u0026#34;a\u0026#34; seen but an element of the same type was already open.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/​using-emacs-advice-to-silence-messages-from-functions/index.html\u0026#34;:151.748-151.751: error: Stray end tag \u0026#34;a\u0026#34;.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/​auto-count-100daystooffload-posts/index.html\u0026#34;:114.446-114.475: error: Start tag \u0026#34;a\u0026#34; seen but an element of the same type was already open.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/​auto-count-100daystooffload-posts/index.html\u0026#34;:114.446-114.475: error: End tag \u0026#34;a\u0026#34; violates nesting rules.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/​auto-count-100daystooffload-posts/index.html\u0026#34;:114.526-114.529: error: Stray end tag \u0026#34;a\u0026#34;.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eWhile the hyperlinks in headings work well, they created invalid HTML\nin the Hugo-generated TOC. So while these errors were created\ntechnically because of a bug in Hugo\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nIt\u0026rsquo;s really cool when you end up finding a bug in an upstream project\nwhile trying to fix the errors in your own thing 😎.\n\u003c/small\u003e\u003c/span\u003e\n, I wanted to fix these errors on my end as soon as I can.\u003c/p\u003e\n\u003cp\u003eI reviewed the errors, and this is all it took to get rid of them all:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eRemove manually inserting hyperlinks in headings\n\u003ca id=\"code-snippet--removing-hyperlink-from-a-heading\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-diff\" data-lang=\"diff\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e show two methods of finding sources of any printed messages.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gd\"\u003e-***** Using plain-old /grep/ or [[https://github.com/BurntSushi/ripgrep][/rg/]]\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gd\"\u003e\u003c/span\u003e\u003cspan class=\"gi\"\u003e+***** Using plain-old /grep/ or /ripgrep (rg)/\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e\u003c/span\u003e This method is pretty easy (but not robust) to use if the search\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e Org source directory and search for the /\u0026#34;org-babel-exp process ..\u0026#34;/\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gd\"\u003e-string ..\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gd\"\u003e\u003c/span\u003e\u003cspan class=\"gi\"\u003e+string using [[https://github.com/BurntSushi/ripgrep][~rg~]] ..\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--removing-hyperlink-from-a-heading\"\u003eCode Snippet 4\u003c/a\u003e:\u003c/span\u003e\n  Removing hyperlink from a heading\n\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eRemove Org Radio links that created links in headings\u003c/p\u003e\n\u003cp\u003eHere, a Org heading happened to contain the string \u0026ldquo;Day count\u0026rdquo;,\nwhich was also an \u003ca href=\"https://orgmode.org/manual/Radio-Targets.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Radio Targets\u0026quot;)\"\u003ean Org Radio link\u003c/a\u003e in that post. While ideally\nthat shouldn\u0026rsquo;t have mattered, I removed that radio link to get\naround this Hugo bug.\n\u003ca id=\"code-snippet--removing-an-org-radio-link\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-diff\" data-lang=\"diff\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e .. /Just may be/. But regardless, I am already enjoying writing once\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gd\"\u003e-again, and it\u0026#39;s great to see the \u0026lt;\u0026lt;\u0026lt;Day count\u0026gt;\u0026gt;\u0026gt; (counting up to 100)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gd\"\u003e\u003c/span\u003e\u003cspan class=\"gi\"\u003e+again, and it\u0026#39;s great to see the Day count (counting up to 100)\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gi\"\u003e\u003c/span\u003e increase with each new post!\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--removing-an-org-radio-link\"\u003eCode Snippet 5\u003c/a\u003e:\u003c/span\u003e\n  Removing an Org Radio link\n\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"validation-ignores\"\u003eValidation Ignores\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#validation-ignores\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eAbove fixes fixed 43 out of 46 errors, but the remaining 3 were unfixable.\u003c/p\u003e\n\n\u003ch3 id=\"ignore-errors-due-to-hyperlinks-in-inline-svg\"\u003e\u003cspan class=\"section-num\"\u003e5\u003c/span\u003e Ignore errors due to hyperlinks in inline SVG\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#ignore-errors-due-to-hyperlinks-in-inline-svg\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/notes/​plantuml/index.html\u0026#34;:114.474-114.678: error: Attribute \u0026#34;title\u0026#34; not allowed on element \u0026#34;a\u0026#34; at this point.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThis error was caused by hyperlinks in inline SVG elements. These SVG\nelements are created by \u003ca href=\"https://plantuml.com/\"\u003ePlantUML\u003c/a\u003e. The \u003cem\u003ehyperlinks in SVG\u003c/em\u003e feature\nworks great, and as these are generated by PlantUML, I chose to just\nignore these errors.\u003c/p\u003e\n\u003cp\u003eI ignored this error by adding the \u003ccode\u003e--ignore-re 'notes/plantuml.*Attribute.*title.*not allowed'\u003c/code\u003e switch to the\n\u003ccode\u003ehtml5validator\u003c/code\u003e command.\u003c/p\u003e\n\n\u003ch3 id=\"ignore-files-not-expected-to-serve-html-content\"\u003e\u003cspan class=\"section-num\"\u003e6\u003c/span\u003e Ignore files not expected to serve HTML content\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#ignore-files-not-expected-to-serve-html-content\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u0026#34;file:/public/googleFOO.html\u0026#34;:1.1-1.52: error: Non-space characters found without seeing a doctype first. Expected \u0026#34;\u0026lt;!DOCTYPE html\u0026gt;\u0026#34;.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003egoogleFOO.html\u003c/code\u003e file here is not a valid HTML file. It\u0026rsquo;s a just a\n\u003cem\u003ecookie\u003c/em\u003e file that was used by Google to verify that I own this\ndomain.\u003c/p\u003e\n\u003cp\u003eThis error was masked by adding the \u003ccode\u003e--ignore 'googleFOO'\u003c/code\u003e switch to\nthe \u003ccode\u003ehtml5validator\u003c/code\u003e command.\u003c/p\u003e\n\n\u003ch2 id=\"summary\"\u003eSummary\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#summary\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eOnce I fixed the 43 errors by tweaking the Org mode content, and added\nthose two ignores, I had \u003cstrong\u003ezero validation errors\u003c/strong\u003e! 🎉\u003c/p\u003e\n\u003cp\u003eIf you are interested in the fix details, \u003ca href=\"https://gitlab.com/kaushalmodi/kaushalmodi.gitlab.io/-/compare/a7cac5dd1293442a51fd5020a3bcef8da7f75fdc...42d6c72d533c337b5c67fa09207f68e45efe6e6c\"\u003ehere are the commits\u003c/a\u003e.\u003c/p\u003e\n","text":" Table of Contents 1 Avoid duplicate heading id attributes 2 Remove inline \u0026lt;style\u0026gt; elements 3 Ensure that all images have captions or alt attributes 4 Do not have hyperlinks in headings Validation Ignores 5 Ignore errors due to hyperlinks in inline SVG 6 Ignore files not expected to serve HTML content Summary In my previous HTML5 Validator post, I mentioned:\nI was a bit disappointed to see validation errors on my site, but then it wasn\u0026rsquo;t too bad .. 46 errors.\nBut they truly say ..\nIgnorance is bliss.\nSo .. once I realized that my site had 46 validation errors, I lost that bliss .. and I couldn\u0026rsquo;t rest easy \u0026mdash; I had to fix them all 😁.\nThis post summarizes the categories of those errors and how I fixed The fixes mentioned in this post refer to changes in Org mode content. But you should be able to derive equivalent fixes for Markdown too. them all.\n1 Avoid duplicate heading id attributes\u0026nbsp;# \u0026#34;file:/public/notes/​string-fns-nim-vs-python/index.html\u0026#34;:636.34-636.46: error: Duplicate ID \u0026#34;notes\u0026#34;. \u0026#34;file:/public/notes/​nim-fmt/index.html\u0026#34;:300.34-300.52: error: Duplicate ID \u0026#34;older-issue\u0026#34;. \u0026#34;file:/public/notes/​nim-fmt/index.html\u0026#34;:306.20-306.33: error: Duplicate ID \u0026#34;floats\u0026#34;. \u0026#34;file:/public/page/6/index.html\u0026#34;:29.39-29.54: error: Duplicate ID \u0026#34;fnref:1\u0026#34;. Errors with above kind of signatures were fixed by,\nConverting headings to description lists\nI had a bunch of generic headings like \u0026ldquo;Notes\u0026rdquo; and \u0026ldquo;Older Issue\u0026rdquo; in some of my posts. After taking a second look at those, it made more sense to convert those to description lists. So in Org mode, I converted headings like * Notes to description lists - Notes ::.\nSetting CUSTOM_ID heading property\nFor the cases, where the headings needed to be left as so, their IDs were uniquified by setting their CUSTOM_ID property. For example, below fixed the Duplicate ID \u0026ldquo;floats\u0026rdquo; errors. ** Precision .. *** Floats +:PROPERTIES: +:CUSTOM_ID: precision-floats +:END: .. ** Type (only for numbers) .. *** Floats +:PROPERTIES: +:CUSTOM_ID: type-floats +:END: Code Snippet 1: Using CUSTOM_ID property to uniquify heading ID's Prevent footnote links in post summaries\nThis issue was due to me not being conscious about how the footnote references work in a post versus on a page outside that post\u0026rsquo;s context. The issue was caused by footnote references getting into the post summaries parsed by Hugo, which will then show up on the list pages.\nThe fix was simple \u0026mdash; Edit the post summaries so that they don\u0026rsquo;t contain any footnote references.\n2 Remove inline \u0026lt;style\u0026gt; elements\u0026nbsp;# \u0026#34;file:/public/​grep-po/index.html\u0026#34;:51.139-51.145: error: Element \u0026#34;style\u0026#34; not allowed as child of element \u0026#34;div\u0026#34; in this context. (Suppressing further errors from this subtree.) \u0026#34;file:/public/​how-do-i-write-org-mode/index.html\u0026#34;:23.194-23.200: error: Element \u0026#34;style\u0026#34; not allowed as child of element \u0026#34;div\u0026#34; in this context. (Suppressing further errors from this subtree.) Errors with above kind of signatures were fixed by,\nAvoiding export of raw \u0026lt;style\u0026gt; elements in the Markdown content\nI figured out which functions were responsible for injecting \u0026lt;style\u0026gt; elements in Markdown content and then advised them to stop that. After applying these advises, I lost the in-content rules for CSS classes .org-center and .csl-entry. So I put those rules directly in this website\u0026rsquo;s CSS. (defun modi/org-blackfriday-center-block (_center-block contents info) (let* ((class \u0026#34;org-center\u0026#34;)) (format \u0026#34;\u0026lt;div class=\\\u0026#34;%s\\\u0026#34;\u0026gt;%s\\n\\n%s\\n\u0026lt;/div\u0026gt;\u0026#34; class (org-blackfriday--extra-div-hack info) contents))) (advice-add \u0026#39;org-blackfriday-center-block :override #\u0026#39;modi/org-blackfriday-center-block) (defun modi/org-cite-csl-render-bibliography (bib-str) (replace-regexp-in-string \u0026#34;\u0026lt;style\u0026gt;\\\\.csl-entry[^\u0026lt;]+\u0026lt;/style\u0026gt;\u0026#34; \u0026#34;\u0026#34; bib-str)) (advice-add \u0026#39;org-cite-csl-render-bibliography :filter-return #\u0026#39;modi/org-cite-csl-render-bibliography) Code Snippet 2: Emacs-Lisp advices to prevent \u0026lt;style\u0026gt; elements in exports Removing unnecessary micro-styling\nI found a single case, where an inline CSS rule was defined in content for CSS class .repr-type for a table. I just removed that without affecting the looks of that rendered table too much.\n3 Ensure that all images have captions or alt attributes\u0026nbsp;# \u0026#34;file:/public/​hugo-use-goat-code-blocks-for-ascii-diagrams/index.html\u0026#34;:24.130-24.255: error: An \u0026#34;img\u0026#34; element must have an \u0026#34;alt\u0026#34; attribute, except under certain conditions. For details, consult guidance on providing text alternatives for images. Errors with above kind of signatures were easily fixed by ensuring that all images had captions Thankfully, there were only two images that were missing captions. . The Hugo figure shortcode adds the caption to the alt attribute if the alt is not specified separately.\nAs an example, here\u0026rsquo;s how I fixed the above error:\n+ #+name: fig__disproportionate_box_drawing + #+caption: Disproportionate box drawing characters [[file:images/​hugo-use-goat-code-blocks-for-ascii-diagrams/ascii-diagram-rendered-in-plain-text-code-block.png]] Code Snippet 3: A git diff showing addition of caption to an image 4 Do not have hyperlinks in headings\u0026nbsp;# \u0026#34;file:/public/​using-emacs-advice-to-silence-messages-from-functions/index.html\u0026#34;:151.687-151.732: error: Start tag \u0026#34;a\u0026#34; seen but an element of the same type was already open. \u0026#34;file:/public/​using-emacs-advice-to-silence-messages-from-functions/index.html\u0026#34;:151.748-151.751: error: Stray end tag \u0026#34;a\u0026#34;. \u0026#34;file:/public/​auto-count-100daystooffload-posts/index.html\u0026#34;:114.446-114.475: error: Start tag \u0026#34;a\u0026#34; seen but an element of the same type was already open. \u0026#34;file:/public/​auto-count-100daystooffload-posts/index.html\u0026#34;:114.446-114.475: error: End tag \u0026#34;a\u0026#34; violates nesting rules. \u0026#34;file:/public/​auto-count-100daystooffload-posts/index.html\u0026#34;:114.526-114.529: error: Stray end tag \u0026#34;a\u0026#34;. While the hyperlinks in headings work well, they created invalid HTML in the Hugo-generated TOC. So while these errors were created technically because of a bug in Hugo It\u0026rsquo;s really cool when you end up finding a bug in an upstream project while trying to fix the errors in your own thing 😎. , I wanted to fix these errors on my end as soon as I can.\nI reviewed the errors, and this is all it took to get rid of them all:\nRemove manually inserting hyperlinks in headings show two methods of finding sources of any printed messages. -***** Using plain-old /grep/ or [[https://github.com/BurntSushi/ripgrep][/rg/]] +***** Using plain-old /grep/ or /ripgrep (rg)/ This method is pretty easy (but not robust) to use if the search .. Org source directory and search for the /\u0026#34;org-babel-exp process ..\u0026#34;/ -string .. +string using [[https://github.com/BurntSushi/ripgrep][~rg~]] .. Code Snippet 4: Removing hyperlink from a heading Remove Org Radio links that created links in headings\nHere, a Org heading happened to contain the string \u0026ldquo;Day count\u0026rdquo;, which was also an an Org Radio link in that post. While ideally that shouldn\u0026rsquo;t have mattered, I removed that radio link to get around this Hugo bug. .. /Just may be/. But regardless, I am already enjoying writing once -again, and it\u0026#39;s great to see the \u0026lt;\u0026lt;\u0026lt;Day count\u0026gt;\u0026gt;\u0026gt; (counting up to 100) +again, and it\u0026#39;s great to see the Day count (counting up to 100) increase with each new post! Code Snippet 5: Removing an Org Radio link Validation Ignores\u0026nbsp;# Above fixes fixed 43 out of 46 errors, but the remaining 3 were unfixable.\n5 Ignore errors due to hyperlinks in inline SVG\u0026nbsp;# \u0026#34;file:/public/notes/​plantuml/index.html\u0026#34;:114.474-114.678: error: Attribute \u0026#34;title\u0026#34; not allowed on element \u0026#34;a\u0026#34; at this point. This error was caused by hyperlinks in inline SVG elements. These SVG elements are created by PlantUML. The hyperlinks in SVG feature works great, and as these are generated by PlantUML, I chose to just ignore these errors.\nI ignored this error by adding the --ignore-re 'notes/plantuml.*Attribute.*title.*not allowed' switch to the html5validator command.\n6 Ignore files not expected to serve HTML content\u0026nbsp;# \u0026#34;file:/public/googleFOO.html\u0026#34;:1.1-1.52: error: Non-space characters found without seeing a doctype first. Expected \u0026#34;\u0026lt;!DOCTYPE html\u0026gt;\u0026#34;. The googleFOO.html file here is not a valid HTML file. It\u0026rsquo;s a just a cookie file that was used by Google to verify that I own this domain.\nThis error was masked by adding the --ignore 'googleFOO' switch to the html5validator command.\nSummary\u0026nbsp;# Once I fixed the 43 errors by tweaking the Org mode content, and added those two ignores, I had zero validation errors! 🎉\nIf you are interested in the fix details, here are the commits.\n"},"name":"Zero HTML Validation Errors!","published":"2022-06-05T17:58:00-04:00","summary":"How I fixed my site content and went down from 46 HTML validations\nerrors down to 0!","type":"entry","url":"https://scripter.co/zero-html-validation-errors/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#org-map-entries-api\"\u003e\u003ccode\u003eorg-map-entries\u003c/code\u003e API\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#match-strings\"\u003e\u003cem\u003eMATCH\u003c/em\u003e strings\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#comparison-types\"\u003eComparison Types\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#other-notes\"\u003eOther notes\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#example-modifying-a-property-in-all-headings\"\u003eExample: Modifying a property in all headings\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org-map-entries-references\"\u003e\u003ccode\u003eorg-map-entries\u003c/code\u003e References\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003e\u003ca href=\"https://framapiaf.org/@postroutine/108313152514542145\"\u003eBelow question\u003c/a\u003e on Mastodon by the user \u003ca href=\"https://framapiaf.org/@postroutine\"\u003e@postroutine\u003c/a\u003e inspired me to\nwrite this post:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI got a lot of Org-Mode headings and I want to modify their properties\n(add, remove, edit). Is there a function to do the same modifications\non each heading?\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eI think that the best solution to that question is using the\n\u003cstrong\u003eorg-map-entries\u003c/strong\u003e function.\u003c/p\u003e\n\u003cp\u003eBut somehow when replying to that question then, that wasn\u0026rsquo;t what\nfirst came to my mind! .. when ironically that function is the \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/blob/2b169e5e83d608e80f4faee9d681b98d87041f58/ox-hugo.el#L4781-L4788\"\u003emain\nfunction\u003c/a\u003e that enables my preferred \u003cem\u003esubtree-based flow\u003c/em\u003e in \u003ccode\u003eox-hugo\u003c/code\u003e\n😆. So I am writing this post to better ingrain the following\nconcept in myself ..\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eIf you need to loop through headings in an Org buffer, and especially\nif you \u003cstrong\u003eneed to modify that buffer\u003c/strong\u003e in the process, use\n\u003cstrong\u003eorg-map-entries\u003c/strong\u003e\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eNext,\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eI will give a give introduction to the \u003ccode\u003eorg-map-entries\u003c/code\u003e API.\u003c/li\u003e\n\u003cli\u003eThen provide a super-short solution to the above question.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"org-map-entries-api\"\u003e\u003ccode\u003eorg-map-entries\u003c/code\u003e API\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#org-map-entries-api\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eI will give only a broad level overview on how to use this function. I\nwould encourage the reader to refer to the resources at the end of\nthis post to learn more about it.\u003c/p\u003e\n\u003cp\u003eSo let\u0026rsquo;s start by looking at this function\u0026rsquo;s signature:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--org-map-entries-signature\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-map-entries\u003c/span\u003e \u003cspan class=\"nv\"\u003eFUNC\u003c/span\u003e \u003cspan class=\"kp\"\u003e\u0026amp;optional\u003c/span\u003e \u003cspan class=\"nv\"\u003eMATCH\u003c/span\u003e \u003cspan class=\"nv\"\u003eSCOPE\u003c/span\u003e \u003cspan class=\"kp\"\u003e\u0026amp;rest\u003c/span\u003e \u003cspan class=\"nv\"\u003eSKIP\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--org-map-entries-signature\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Signature of the \u003ccode\u003eorg-map-entries\u003c/code\u003e function\n\u003c/div\u003e\n\u003cp\u003eThe \u003ccode\u003eorg-map-entries\u003c/code\u003e function iterates through all the headings\nmeeting the \u003cem\u003eMATCH\u003c/em\u003e criteria in the determined \u003cem\u003eSCOPE\u003c/em\u003e, and then calls\nthe specified function \u003cem\u003eFUNC\u003c/em\u003e at each of those headings.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe \u003ccode\u003eFUNC\u003c/code\u003e function accepts \u003cstrong\u003eno\u003c/strong\u003e arguments and is called at the\nbeginning of each Org heading.\u003c/li\u003e\n\u003cli\u003eThe optional second argument \u003cem\u003eMATCH\u003c/em\u003e is either \u003cem\u003enil\u003c/em\u003e, \u003ccode\u003et\u003c/code\u003e or a\n\u003cem\u003esearch string\u003c/em\u003e.\n\u003cul\u003e\n\u003cli\u003eIf \u003cem\u003eMATCH\u003c/em\u003e is \u003cem\u003enil\u003c/em\u003e or \u003ccode\u003et\u003c/code\u003e, \u003cstrong\u003eall\u003c/strong\u003e headings will be visited by the\niteration and \u003cem\u003eFUNC\u003c/em\u003e will be called on all of them.\u003c/li\u003e\n\u003cli\u003eBut if \u003cem\u003eMATCH\u003c/em\u003e is a string, the headings will first be filtered\nbased on that string and then the \u003cem\u003eFUNC\u003c/em\u003e will be called on only\nthose.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eFor explanations on the optional \u003cem\u003eSCOPE\u003c/em\u003e and \u003cem\u003eSKIP\u003c/em\u003e arguments, see\n\u003ca href=\"https://orgmode.org/manual/Using-the-Mapping-API.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Using the Mapping API\u0026quot;)\"\u003eOrg Info: Using the Mapping API\u003c/a\u003e or \u003ckbd\u003eC-h\u003c/kbd\u003e \u003ckbd\u003ef\u003c/kbd\u003e \u003ccode\u003eorg-map-entries\u003c/code\u003e from\nwithin Emacs.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eHere\u0026rsquo;s a typical \u003ccode\u003eorg-map-entries\u003c/code\u003e call that loops through \u003cstrong\u003eall\u003c/strong\u003e the\nheadings in the \u003cstrong\u003evisible\u003c/strong\u003e buffer: \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-map-entries\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003esome-function\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/code\u003e where all the optional\nargument values are \u003cem\u003enil\u003c/em\u003e. Next, we\u0026rsquo;ll see some examples of\nstring-type \u003cem\u003eMATCH\u003c/em\u003e arguments used for filtering the headings.\u003c/p\u003e\n\n\u003ch3 id=\"match-strings\"\u003e\u003cem\u003eMATCH\u003c/em\u003e strings\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#match-strings\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eBelow table shows few examples of match string patterns.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"table--org-map-entries-search-strings\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"table-caption\"\u003e\n  \u003cspan class=\"table-number\"\u003e\u003ca href=\"#table--org-map-entries-search-strings\"\u003eTable 1\u003c/a\u003e:\u003c/span\u003e\n  String-type \u003ci\u003eMATCH\u003c/i\u003e argument examples for \u003ccode\u003eorg-map-entries\u003c/code\u003e\n\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eSearch string\u003c/th\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003cth\u003eExample\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;TAG\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eTag name\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;foo\u0026quot;\u003c/code\u003e matches all headings with that tag\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;{TAG REGEXP}\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eRegexp matching tags\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;{f.*}\u0026quot;\u003c/code\u003e matches all headings whose tags match that regexp\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;TAG1+TAG2+..\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eTag set intersection\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;foo+bar\u0026quot;\u003c/code\u003e matches all headings with both of those tags\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;TAG1-TAG2+..\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eTag set difference\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;foo-bar\u0026quot;\u003c/code\u003e matches all headings with \u003ccode\u003efoo\u003c/code\u003e tag but without \u003ccode\u003ebar\u003c/code\u003e tag\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;TAG1\u003c/code\u003e|​\u003ccode\u003eTAG2\u003c/code\u003e|​\u003ccode\u003e..\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eTag set union or boolean \u003cem\u003eOR\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;foo\u003c/code\u003e​|​\u003ccode\u003ebar\u0026quot;\u003c/code\u003e matches all headings with either of those tags\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;TAG1\u0026amp;TAG2\u0026amp;..\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eTag set intersection or boolean \u003cem\u003eAND\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;foo\u0026amp;bar\u0026quot;\u003c/code\u003e is same as \u003ccode\u003e\u0026quot;foo+bar\u0026quot;\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;PROP\u003c/code\u003e​=​\u003ccode\u003e\\\u0026quot;STRVAL\\\u0026quot;\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eSpecified property value matching a string\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;color\u003c/code\u003e​=​\u003ccode\u003e\\\u0026quot;blue\\\u0026quot;\u0026quot;\u003c/code\u003e matches all headings where \u003ccode\u003ecolor\u003c/code\u003e property is \u003ccode\u003eblue\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;PROP\u0026lt;\u0026gt;\\\u0026quot;STRVAL\\\u0026quot;\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eSpecified property value not matching a string\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;color\u0026lt;\u0026gt;\\\u0026quot;blue\\\u0026quot;\u0026quot;\u003c/code\u003e matches all headings where \u003ccode\u003ecolor\u003c/code\u003e property is not \u003ccode\u003eblue\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;PROP\u003c/code\u003e​=​\u003ccode\u003e{VAL REGEXP}\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eSpecified property value matching a regexp\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;color={b.*}\u0026quot;\u003c/code\u003e matches all headings where \u003ccode\u003ecolor\u003c/code\u003e property value matches \u0026lsquo;\u003ccode\u003eb.*\u003c/code\u003e\u0026rsquo; regexp\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;PROP[OP]NUMVAL\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eSpecified property value compared with a numeric value\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;some_num\u003c/code\u003e​\u0026gt;=​\u003ccode\u003e10\u0026quot;\u003c/code\u003e matches all headings where \u003ccode\u003esome_num\u003c/code\u003e property is \u0026gt;=10\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;LEVEL[OP]VAL\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eCheck value of headline\u0026rsquo;s special property \u003cem\u003eLEVEL\u003c/em\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;level\u0026gt;2\u0026quot;\u003c/code\u003e matches all headlines at levels greater than 2\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cstrong\u003e\u003ccode\u003e\u0026quot;TODO[OP]\\\u0026quot;STRVAL\\\u0026quot;\u0026quot;\u003c/code\u003e\u003c/strong\u003e\u003c/td\u003e\n\u003ctd\u003eCheck value of headline\u0026rsquo;s \u003cem\u003eTODO\u003c/em\u003e state\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e\u0026quot;TODO\u003c/code\u003e​=​\u003ccode\u003e\\\u0026quot;DONE\\\u0026quot;\u0026quot;\u003c/code\u003e matches all headlines with \u003cem\u003eTODO\u003c/em\u003e state set to \u0026lsquo;DONE\u0026rsquo;\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003ch3 id=\"comparison-types\"\u003eComparison Types\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#comparison-types\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cul\u003e\n\u003cli\u003eIf the comparison value is a plain number, a numerical comparison is\ndone, and the allowed operators are \u0026lsquo;\u0026lt;\u0026rsquo;, \u0026lsquo;=​\u0026rsquo;, \u0026lsquo;\u0026gt;\u0026rsquo;, \u0026lsquo;\u0026lt;=​\u0026rsquo;, \u0026lsquo;\u0026gt;=​\u0026rsquo;,\nand \u0026lsquo;\u0026lt;\u0026gt;\u0026rsquo;.\u003c/li\u003e\n\u003cli\u003eIf the comparison value is enclosed in double quotes, a string\ncomparison is done, and the same operators are allowed.\u003c/li\u003e\n\u003cli\u003eIf the comparison value is enclosed in curly braces, a regexp match\nis performed. For this comparison, only \u0026lsquo;=​\u0026rsquo; (regexp matches) and\n\u0026lsquo;\u0026lt;\u0026gt;\u0026rsquo; (regexp does not match) operators are allowed.\u003c/li\u003e\n\u003cli\u003eComparison with dates and \u003ca href=\"https://orgmode.org/manual/Tag-Hierarchy.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Tag Hierarchy\u0026quot;)\"\u003eGroup Tags\u003c/a\u003e is also possible. See\n\u003ca href=\"https://orgmode.org/manual/Matching-tags-and-properties.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Matching tags and properties\u0026quot;)\"\u003eOrg Info: Matching tags and properties\u003c/a\u003e for more details.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch3 id=\"other-notes\"\u003eOther notes\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#other-notes\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cul\u003e\n\u003cli\u003eThe property names are case-insensitive. So these all work the\nsame: \u003ccode\u003e\u0026quot;COLOR\u0026lt;\u0026gt;\\\u0026quot;blue\\\u0026quot;\u0026quot;\u003c/code\u003e, \u003ccode\u003e\u0026quot;color\u0026lt;\u0026gt;\\\u0026quot;blue\\\u0026quot;\u0026quot;\u003c/code\u003e,\n\u003ccode\u003e\u0026quot;Color\u0026lt;\u0026gt;\\\u0026quot;blue\\\u0026quot;\u0026quot;\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe \u0026ldquo;tag\u0026rdquo; and \u0026ldquo;property\u0026rdquo; matches can be mixed up using the boolean\n\u0026lsquo;\u003ccode\u003e\u0026amp;\u003c/code\u003e\u0026rsquo;, \u0026lsquo;\u003ccode\u003e|\u003c/code\u003e\u0026rsquo;, \u0026lsquo;\u003ccode\u003e+\u003c/code\u003e\u0026rsquo; and \u0026lsquo;\u003ccode\u003e-\u003c/code\u003e​\u0026rsquo; operators. So searching\n\u0026lsquo;\u003ccode\u003e+LEVEL=3+boss-TODO​=\u0026quot;DONE\u0026quot;\u003c/code\u003e\u0026rsquo; lists all level three headlines\nthat have the tag \u0026lsquo;boss\u0026rsquo; and are \u003cspan class=\"underline\"\u003enot\u003c/span\u003e marked with the TODO\nkeyword \u0026lsquo;DONE\u0026rsquo;.\u003c/li\u003e\n\u003cli\u003e\u0026lsquo;\u003ccode\u003e\u0026amp;\u003c/code\u003e\u0026rsquo; binds more strongly than \u0026lsquo;\u003ccode\u003e|\u003c/code\u003e\u0026rsquo;.\u003c/li\u003e\n\u003cli\u003eGrouping of match expressions using parentheses is not\nsupported.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"example-modifying-a-property-in-all-headings\"\u003eExample: Modifying a property in all headings\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#example-modifying-a-property-in-all-headings\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eBelow is an example solution to the \u003ca href=\"https://framapiaf.org/@postroutine/108313152514542145\"\u003eMastoson question\u003c/a\u003e that I\nreferenced in the beginning of this post.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--set-props-all-headings\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003etest/set-property-at-heading\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Function to be called at the beginning of an Org heading.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eel\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-element-at-point\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-set-property\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;foo\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-element-property\u003c/span\u003e \u003cspan class=\"nb\"\u003e:title\u003c/span\u003e \u003cspan class=\"nv\"\u003eel\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-map-entries\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003etest/set-property-at-heading\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--set-props-all-headings\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Dummy example showing how to set a property for all Org headings using \u003ccode\u003eorg-map-entries\u003c/code\u003e\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003eIt defines a function that parses the Org element at point using\n\u003ccode\u003eorg-element-at-point\u003c/code\u003e, gets the \u003ccode\u003etitle\u003c/code\u003e property of the element\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThis function is designed to be called by \u003ccode\u003eorg-map-entries\u003c/code\u003e and so\nthe point at the time of calling this function will always be on a\nheading.\n\u003c/small\u003e\u003c/span\u003e\n, and sets that to the \u003cem\u003eheadline\u003c/em\u003e element\u0026rsquo;s \u003ccode\u003efoo\u003c/code\u003e property.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003eorg-map-entries\u003c/code\u003e call now simply calls this function on each\nheading in the visible scope of the Org buffer.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"org-map-entries-references\"\u003e\u003ccode\u003eorg-map-entries\u003c/code\u003e References\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#org-map-entries-references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ckbd\u003eC-h\u003c/kbd\u003e \u003ckbd\u003ef\u003c/kbd\u003e \u003ccode\u003eorg-map-entries\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://orgmode.org/manual/Using-the-Mapping-API.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Using the Mapping API\u0026quot;)\"\u003eOrg Info: Using the Mapping API\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://orgmode.org/manual/Matching-tags-and-properties.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Matching tags and properties\u0026quot;)\"\u003eOrg Info: Matching tags and properties\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eOrg mode has another popular mapping/looping API function\n\u003cstrong\u003eorg-element-map\u003c/strong\u003e. I won\u0026rsquo;t go into much detail about that in this post\n\u0026mdash; I\u0026rsquo;ll just mention that \u003ccode\u003eorg-element-map\u003c/code\u003e is not the best choice if\nyou need to modify the original Org buffer. It\u0026rsquo;s main use is to loop\nthrough a parsed \u003cabbr aria-label=\"Abstract Syntax Tree\" tabindex=0\u003eAST\u003c/abbr\u003e of an Org buffer\nand optional modify those elements \u003cem\u003ein memory\u003c/em\u003e.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","text":" Table of Contents org-map-entries API MATCH strings Comparison Types Other notes Example: Modifying a property in all headings org-map-entries References Below question on Mastodon by the user @postroutine inspired me to write this post:\nI got a lot of Org-Mode headings and I want to modify their properties (add, remove, edit). Is there a function to do the same modifications on each heading?\nI think that the best solution to that question is using the org-map-entries function.\nBut somehow when replying to that question then, that wasn\u0026rsquo;t what first came to my mind! .. when ironically that function is the main function that enables my preferred subtree-based flow in ox-hugo 😆. So I am writing this post to better ingrain the following concept in myself ..\nIf you need to loop through headings in an Org buffer, and especially if you need to modify that buffer in the process, use org-map-entries1.\nNext,\nI will give a give introduction to the org-map-entries API. Then provide a super-short solution to the above question. org-map-entries API\u0026nbsp;# I will give only a broad level overview on how to use this function. I would encourage the reader to refer to the resources at the end of this post to learn more about it.\nSo let\u0026rsquo;s start by looking at this function\u0026rsquo;s signature:\n(org-map-entries FUNC \u0026amp;optional MATCH SCOPE \u0026amp;rest SKIP) Code Snippet 1: Signature of the org-map-entries function The org-map-entries function iterates through all the headings meeting the MATCH criteria in the determined SCOPE, and then calls the specified function FUNC at each of those headings.\nThe FUNC function accepts no arguments and is called at the beginning of each Org heading. The optional second argument MATCH is either nil, t or a search string. If MATCH is nil or t, all headings will be visited by the iteration and FUNC will be called on all of them. But if MATCH is a string, the headings will first be filtered based on that string and then the FUNC will be called on only those. For explanations on the optional SCOPE and SKIP arguments, see Org Info: Using the Mapping API or C-h f org-map-entries from within Emacs. Here\u0026rsquo;s a typical org-map-entries call that loops through all the headings in the visible buffer: (org-map-entries #\u0026#39;some-function) where all the optional argument values are nil. Next, we\u0026rsquo;ll see some examples of string-type MATCH arguments used for filtering the headings.\nMATCH strings\u0026nbsp;# Below table shows few examples of match string patterns.\nTable 1: String-type MATCH argument examples for org-map-entries Search string Description Example \u0026quot;TAG\u0026quot; Tag name \u0026quot;foo\u0026quot; matches all headings with that tag \u0026quot;{TAG REGEXP}\u0026quot; Regexp matching tags \u0026quot;{f.*}\u0026quot; matches all headings whose tags match that regexp \u0026quot;TAG1+TAG2+..\u0026quot; Tag set intersection \u0026quot;foo+bar\u0026quot; matches all headings with both of those tags \u0026quot;TAG1-TAG2+..\u0026quot; Tag set difference \u0026quot;foo-bar\u0026quot; matches all headings with foo tag but without bar tag \u0026quot;TAG1|​TAG2|​..\u0026quot; Tag set union or boolean OR \u0026quot;foo​|​bar\u0026quot; matches all headings with either of those tags \u0026quot;TAG1\u0026amp;TAG2\u0026amp;..\u0026quot; Tag set intersection or boolean AND \u0026quot;foo\u0026amp;bar\u0026quot; is same as \u0026quot;foo+bar\u0026quot; \u0026quot;PROP​=​\\\u0026quot;STRVAL\\\u0026quot;\u0026quot; Specified property value matching a string \u0026quot;color​=​\\\u0026quot;blue\\\u0026quot;\u0026quot; matches all headings where color property is blue \u0026quot;PROP\u0026lt;\u0026gt;\\\u0026quot;STRVAL\\\u0026quot;\u0026quot; Specified property value not matching a string \u0026quot;color\u0026lt;\u0026gt;\\\u0026quot;blue\\\u0026quot;\u0026quot; matches all headings where color property is not blue \u0026quot;PROP​=​{VAL REGEXP}\u0026quot; Specified property value matching a regexp \u0026quot;color={b.*}\u0026quot; matches all headings where color property value matches \u0026lsquo;b.*\u0026rsquo; regexp \u0026quot;PROP[OP]NUMVAL\u0026quot; Specified property value compared with a numeric value \u0026quot;some_num​\u0026gt;=​10\u0026quot; matches all headings where some_num property is \u0026gt;=10 \u0026quot;LEVEL[OP]VAL\u0026quot; Check value of headline\u0026rsquo;s special property LEVEL \u0026quot;level\u0026gt;2\u0026quot; matches all headlines at levels greater than 2 \u0026quot;TODO[OP]\\\u0026quot;STRVAL\\\u0026quot;\u0026quot; Check value of headline\u0026rsquo;s TODO state \u0026quot;TODO​=​\\\u0026quot;DONE\\\u0026quot;\u0026quot; matches all headlines with TODO state set to \u0026lsquo;DONE\u0026rsquo; Comparison Types\u0026nbsp;# If the comparison value is a plain number, a numerical comparison is done, and the allowed operators are \u0026lsquo;\u0026lt;\u0026rsquo;, \u0026lsquo;=​\u0026rsquo;, \u0026lsquo;\u0026gt;\u0026rsquo;, \u0026lsquo;\u0026lt;=​\u0026rsquo;, \u0026lsquo;\u0026gt;=​\u0026rsquo;, and \u0026lsquo;\u0026lt;\u0026gt;\u0026rsquo;. If the comparison value is enclosed in double quotes, a string comparison is done, and the same operators are allowed. If the comparison value is enclosed in curly braces, a regexp match is performed. For this comparison, only \u0026lsquo;=​\u0026rsquo; (regexp matches) and \u0026lsquo;\u0026lt;\u0026gt;\u0026rsquo; (regexp does not match) operators are allowed. Comparison with dates and Group Tags is also possible. See Org Info: Matching tags and properties for more details. Other notes\u0026nbsp;# The property names are case-insensitive. So these all work the same: \u0026quot;COLOR\u0026lt;\u0026gt;\\\u0026quot;blue\\\u0026quot;\u0026quot;, \u0026quot;color\u0026lt;\u0026gt;\\\u0026quot;blue\\\u0026quot;\u0026quot;, \u0026quot;Color\u0026lt;\u0026gt;\\\u0026quot;blue\\\u0026quot;\u0026quot;. The \u0026ldquo;tag\u0026rdquo; and \u0026ldquo;property\u0026rdquo; matches can be mixed up using the boolean \u0026lsquo;\u0026amp;\u0026rsquo;, \u0026lsquo;|\u0026rsquo;, \u0026lsquo;+\u0026rsquo; and \u0026lsquo;-​\u0026rsquo; operators. So searching \u0026lsquo;+LEVEL=3+boss-TODO​=\u0026quot;DONE\u0026quot;\u0026rsquo; lists all level three headlines that have the tag \u0026lsquo;boss\u0026rsquo; and are not marked with the TODO keyword \u0026lsquo;DONE\u0026rsquo;. \u0026lsquo;\u0026amp;\u0026rsquo; binds more strongly than \u0026lsquo;|\u0026rsquo;. Grouping of match expressions using parentheses is not supported. Example: Modifying a property in all headings\u0026nbsp;# Below is an example solution to the Mastoson question that I referenced in the beginning of this post.\n(defun test/set-property-at-heading () \u0026#34;Function to be called at the beginning of an Org heading.\u0026#34; (let ((el (org-element-at-point))) (org-set-property \u0026#34;foo\u0026#34; (org-element-property :title el)))) (org-map-entries #\u0026#39;test/set-property-at-heading) Code Snippet 2: Dummy example showing how to set a property for all Org headings using org-map-entries It defines a function that parses the Org element at point using org-element-at-point, gets the title property of the element This function is designed to be called by org-map-entries and so the point at the time of calling this function will always be on a heading. , and sets that to the headline element\u0026rsquo;s foo property. The org-map-entries call now simply calls this function on each heading in the visible scope of the Org buffer. org-map-entries References\u0026nbsp;# C-h f org-map-entries Org Info: Using the Mapping API Org Info: Matching tags and properties Org mode has another popular mapping/looping API function org-element-map. I won\u0026rsquo;t go into much detail about that in this post \u0026mdash; I\u0026rsquo;ll just mention that org-element-map is not the best choice if you need to modify the original Org buffer. It\u0026rsquo;s main use is to loop through a parsed AST of an Org buffer and optional modify those elements in memory.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"Looping through Org mode headings","published":"2022-05-18T23:29:00-04:00","summary":"Using the org-map-entries API to loop through selected or all headings in an Org file.","type":"entry","url":"https://scripter.co/looping-through-org-mode-headings/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#prior-forms-of-adding-post-updates\"\u003ePrior forms of adding post updates\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#introducing-logbook\"\u003eIntroducing \u003ccode\u003e:LOGBOOK:\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#adding-notes-to-logbook\"\u003eAdding notes to \u003ccode\u003e:LOGBOOK:\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#logbook-notes-example\"\u003e\u003ccode\u003e:LOGBOOK:\u003c/code\u003e Notes Example\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eMost of my blog posts are mainly to serve as documentation for my\nfuture self\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThis post will serve to remind me how to get the \u003ccode\u003e:LOGBOOK:\u003c/code\u003e notes\nworking once again in case I end up with some issue there.\n\u003c/small\u003e\u003c/span\u003e\n. So when I get a chance, I try to fix outdated stuff in\nmy old blog posts. And along with the act of updating things, adding\nbrief notes describing those updates comes naturally to me.\u003c/p\u003e\n\n\u003ch2 id=\"prior-forms-of-adding-post-updates\"\u003ePrior forms of adding post updates\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#prior-forms-of-adding-post-updates\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eAs I author my posts in Org mode, I can easy enter a date stamp using\nthe \u003ccode\u003eorg-time-stamp\u003c/code\u003e command (bound by default to \u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003e.\u003c/kbd\u003e \u003ckbd\u003eRET\u003c/kbd\u003e) and\nfollow that by the update note.\u003c/p\u003e\n\u003cp\u003eWhile that worked, that approach bothered me because those notes\ndidn\u0026rsquo;t have consistent format across multiple posts. For example, I\nmight type the update as \u0026ldquo;\u003ccode class=\"code-inline language-org\"\u003e\u003cspan class=\"gs\"\u003e*Update (\u0026lt;time stamp\u0026gt;)*\u003c/span\u003e: \u0026lt;\u003cspan class=\"s\"\u003enote\u003c/span\u003e\u0026gt;\u003c/code\u003e\u0026rdquo; in one post, while I might type the same in a\n\u003cem\u003edescription list\u003c/em\u003e form in another: \u0026ldquo;\u003ccode class=\"code-inline language-org\"\u003e\u003cspan class=\"k\"\u003e- \u003c/span\u003e\u0026lt;\u003cspan class=\"s\"\u003etime stamp\u003c/span\u003e\u0026gt;) :: \u0026lt;\u003cspan class=\"s\"\u003enote\u003c/span\u003e\u0026gt;\u003c/code\u003e\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003eTo solve the consistency problem, I came up with this Org macro:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--update-org-macro\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+macro\u003c/span\u003e\u003cspan class=\"c\"\u003e: update - $1 :: $2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--update-org-macro\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  \u003ccode\u003e{{{update(..)}}}\u003c/code\u003e Org Macro\n\u003c/div\u003e\n\u003cp\u003eThis worked mostly \u0026hellip; except when the update text needed to be a bit\nlonger, like a paragraph. It didn\u0026rsquo;t look elegant in that case. Also,\nif the text had a \u003cem\u003ecomma\u003c/em\u003e character in there, it needed to be escaped\nwith a backslash (\u003ccode\u003e\\\u003c/code\u003e).\u003c/p\u003e\n\n\u003ch2 id=\"introducing-logbook\"\u003eIntroducing \u003ccode\u003e:LOGBOOK:\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#introducing-logbook\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eSo when I learned\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nA little bit of history .. I learned about the \u003ccode\u003e:LOGBOOK:\u003c/code\u003e drawer when\nAdam Porter mentioned it in \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/issues/203\"\u003e\u003ccode\u003eox-hugo\u003c/code\u003e Issue # 203\u003c/a\u003e back in\nSeptember 2018. I wanted to use that feature, but I didn\u0026rsquo;t have time\nand/or know-how on how exactly I would parse those Org Drawers in\n\u003ccode\u003eox-hugo\u003c/code\u003e until very recently (May 2022)!\n\u003c/small\u003e\u003c/span\u003e\nabout the Org \u003ccode\u003e:LOGBOOK:\u003c/code\u003e drawer, it solved all those problems: (i)\nconsistency in adding notes (ii) easy to add update notes \u0026ndash; in fact\nmuch easier (iii) easy to type long form notes (iv) no comma escaping\nneeded.\u003c/p\u003e\n\u003cp\u003eOrg Drawers look like this:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--code-org-drawers\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eContent before the drawer\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e:DRAWERNAME:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"cs\"\u003eContent inside the drawer\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e\u003c/span\u003e\u003cspan class=\"c\"\u003e:END:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eContent after the drawer\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--code-org-drawers\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Org Drawers\n\u003c/div\u003e\n\u003cp\u003eand they can be inserted anywhere in your Org content using the\n\u003ccode\u003eorg-insert-drawer\u003c/code\u003e command (bound by default to \u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003eC-x\u003c/kbd\u003e \u003ckbd\u003ed\u003c/kbd\u003e).\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003e:LOGBOOK:\u003c/code\u003e is a special kind of drawer that\u0026rsquo;s auto-inserted by Org\nmode when certain actions are detected, like changing the TODO state\nof a subtree, or\n\u003cmark\u003eadding a note\u003c/mark\u003e . That latter action is what this blog post is about.\u003c/p\u003e\n\n\u003ch2 id=\"adding-notes-to-logbook\"\u003eAdding notes to \u003ccode\u003e:LOGBOOK:\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#adding-notes-to-logbook\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eYou need to enable this feature using one of these methods:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eSet the \u003ccode\u003eorg-log-into-drawer\u003c/code\u003e variable to a non-nil value\n(typically \u003ccode\u003et\u003c/code\u003e) in your Emacs config, or as a file-local variable,\nor in your project\u0026rsquo;s \u003cstrong\u003e\u003ccode\u003e.dir-locals.el\u003c/code\u003e\u003c/strong\u003e (⭐ my preference).\u003c/li\u003e\n\u003cli\u003eSet \u003ccode\u003e#+startup: logdrawer\u003c/code\u003e to enable this for the whole Org file.\u003c/li\u003e\n\u003cli\u003eTo enable this feature for only selected subtrees, set the\n\u003ccode\u003e:LOG_INTO_DRAWER: t\u003c/code\u003e property in the subtree (or one of its parent\nsubtrees).\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eOnce this is set, call the \u003ccode\u003eorg-add-note\u003c/code\u003e command (bound by default to\n\u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003eC-z\u003c/kbd\u003e). That will open a window with ∗Org Note∗ buffer where-in\nyou will type your post update and then \u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003eC-c\u003c/kbd\u003e to save it to the\nsubtree\u0026rsquo;s \u003ccode\u003e:LOGBOOK:\u003c/code\u003e drawer. If that drawer didn\u0026rsquo;t exist already, it\nwill be created directly under the subtree\u0026rsquo;s heading.\u003c/p\u003e\n\u003cp\u003eThe note will get recorded in this format by default under the current\nsubtree:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--logbook-default-format\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"gh\"\u003e*\u003c/span\u003e\u003cspan class=\"gs\"\u003e Subtree title\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e:LOGBOOK:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"cs\"\u003e- Note taken on \u0026lt;current date and time\u0026gt; \\\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e  \u0026lt;note text\u0026gt;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e\u003c/span\u003e\u003cspan class=\"c\"\u003e:END:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--logbook-default-format\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  Default format of a \u003ccode\u003e:LOGBOOK:\u003c/code\u003e note\n\u003c/div\u003e\n\u003cp\u003eAs you see, you only type the note text, and the time-stamp is\ninserted automatically.\u003c/p\u003e\n\n\u003ch2 id=\"logbook-notes-example\"\u003e\u003ccode\u003e:LOGBOOK:\u003c/code\u003e Notes Example\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#logbook-notes-example\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eHere are the update notes from one of my posts:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--logbook-example\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e:LOGBOOK:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"cs\"\u003e- Note taken on \u0026lt;2018-08-26 Sun\u0026gt; \\\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e  Mention =org-babel-demarcate-block=, tweak the =org-meta-return= advice.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e- Note taken on \u0026lt;2018-08-23 Thu\u0026gt; \\\\\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e  Use ~M-return~ instead of ~C-return~ for splitting blocks and\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e  support upper-case blocks (though I [[* Converting Org keywords to lower-case][don\u0026#39;t prefer those]]!).\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e\u003c/span\u003e\u003cspan class=\"c\"\u003e:END:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--logbook-example\"\u003eCode Snippet 4\u003c/a\u003e:\u003c/span\u003e\n  Examples of post update notes added to the \u003ccode\u003e:LOGBOOK:\u003c/code\u003e drawer\n\u003c/div\u003e\n\u003cp\u003eYou can see how they rendered at the top of the \u003ca href=\"/splitting-an-org-block-into-two/\"\u003eSplitting an Org block into two\u003c/a\u003e post.\u003c/p\u003e\n\u003cp\u003eIf you are an \u003ccode\u003eox-hugo\u003c/code\u003e user following the \u003cem\u003esubtree-based export\nflow\u003c/em\u003e, and would like to export \u003ccode\u003e:LOGBOOK:\u003c/code\u003e notes in a similar\nfashion, check out the \u003ca href=\"https://ox-hugo.scripter.co/doc/drawers/\"\u003e\u003ccode\u003eox-hugo\u003c/code\u003e Manual: Drawers\u003c/a\u003e page for details.\u003c/p\u003e\n\n\u003ch2 id=\"references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://orgmode.org/manual/Drawers.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Drawers\u0026quot;)\"\u003eOrg Info: Drawers\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://orgmode.org/manual/Tracking-TODO-state-changes.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Tracking TODO state changes\u0026quot;)\"\u003eOrg Info: Tracking TODO state changes\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","text":" Table of Contents Prior forms of adding post updates Introducing :LOGBOOK: Adding notes to :LOGBOOK: :LOGBOOK: Notes Example References Most of my blog posts are mainly to serve as documentation for my future self This post will serve to remind me how to get the :LOGBOOK: notes working once again in case I end up with some issue there. . So when I get a chance, I try to fix outdated stuff in my old blog posts. And along with the act of updating things, adding brief notes describing those updates comes naturally to me.\nPrior forms of adding post updates\u0026nbsp;# As I author my posts in Org mode, I can easy enter a date stamp using the org-time-stamp command (bound by default to C-c . RET) and follow that by the update note.\nWhile that worked, that approach bothered me because those notes didn\u0026rsquo;t have consistent format across multiple posts. For example, I might type the update as \u0026ldquo;*Update (\u0026lt;time stamp\u0026gt;)*: \u0026lt;note\u0026gt;\u0026rdquo; in one post, while I might type the same in a description list form in another: \u0026ldquo;- \u0026lt;time stamp\u0026gt;) :: \u0026lt;note\u0026gt;\u0026rdquo;.\nTo solve the consistency problem, I came up with this Org macro:\n#+macro: update - $1 :: $2 Code Snippet 1: {{{update(..)}}} Org Macro This worked mostly \u0026hellip; except when the update text needed to be a bit longer, like a paragraph. It didn\u0026rsquo;t look elegant in that case. Also, if the text had a comma character in there, it needed to be escaped with a backslash (\\).\nIntroducing :LOGBOOK:\u0026nbsp;# So when I learned A little bit of history .. I learned about the :LOGBOOK: drawer when Adam Porter mentioned it in ox-hugo Issue # 203 back in September 2018. I wanted to use that feature, but I didn\u0026rsquo;t have time and/or know-how on how exactly I would parse those Org Drawers in ox-hugo until very recently (May 2022)! about the Org :LOGBOOK: drawer, it solved all those problems: (i) consistency in adding notes (ii) easy to add update notes \u0026ndash; in fact much easier (iii) easy to type long form notes (iv) no comma escaping needed.\nOrg Drawers look like this:\nContent before the drawer :DRAWERNAME: Content inside the drawer :END: Content after the drawer Code Snippet 2: Org Drawers and they can be inserted anywhere in your Org content using the org-insert-drawer command (bound by default to C-c C-x d).\n:LOGBOOK: is a special kind of drawer that\u0026rsquo;s auto-inserted by Org mode when certain actions are detected, like changing the TODO state of a subtree, or adding a note . That latter action is what this blog post is about.\nAdding notes to :LOGBOOK:\u0026nbsp;# You need to enable this feature using one of these methods:\nSet the org-log-into-drawer variable to a non-nil value (typically t) in your Emacs config, or as a file-local variable, or in your project\u0026rsquo;s .dir-locals.el (⭐ my preference). Set #+startup: logdrawer to enable this for the whole Org file. To enable this feature for only selected subtrees, set the :LOG_INTO_DRAWER: t property in the subtree (or one of its parent subtrees). Once this is set, call the org-add-note command (bound by default to C-c C-z). That will open a window with ∗Org Note∗ buffer where-in you will type your post update and then C-c C-c to save it to the subtree\u0026rsquo;s :LOGBOOK: drawer. If that drawer didn\u0026rsquo;t exist already, it will be created directly under the subtree\u0026rsquo;s heading.\nThe note will get recorded in this format by default under the current subtree:\n* Subtree title :LOGBOOK: - Note taken on \u0026lt;current date and time\u0026gt; \\\\ \u0026lt;note text\u0026gt; :END: Code Snippet 3: Default format of a :LOGBOOK: note As you see, you only type the note text, and the time-stamp is inserted automatically.\n:LOGBOOK: Notes Example\u0026nbsp;# Here are the update notes from one of my posts:\n:LOGBOOK: - Note taken on \u0026lt;2018-08-26 Sun\u0026gt; \\\\ Mention =org-babel-demarcate-block=, tweak the =org-meta-return= advice. - Note taken on \u0026lt;2018-08-23 Thu\u0026gt; \\\\ Use ~M-return~ instead of ~C-return~ for splitting blocks and support upper-case blocks (though I [[* Converting Org keywords to lower-case][don\u0026#39;t prefer those]]!). :END: Code Snippet 4: Examples of post update notes added to the :LOGBOOK: drawer You can see how they rendered at the top of the Splitting an Org block into two post.\nIf you are an ox-hugo user following the subtree-based export flow, and would like to export :LOGBOOK: notes in a similar fashion, check out the ox-hugo Manual: Drawers page for details.\nReferences\u0026nbsp;# Org Info: Drawers Org Info: Tracking TODO state changes "},"name":"Using Org Logbook Notes to record blog post updates","published":"2022-05-16T00:59:00-04:00","summary":"Quick introduction to Org mode\u0026rsquo;s :LOGBOOK: feature and how I use it to record time-stamped notes for blog post updates.","type":"entry","url":"https://scripter.co/using-org-logbook-notes-to-record-blog-post-updates/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#clone-the-org-repo\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Clone the Org repo\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#build-setup\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Build Setup\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#customizing-local-dot-mk--optional\"\u003eCustomizing \u003ccode\u003elocal.mk\u003c/code\u003e (Optional)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#build\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e Build\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#set-the-correct-paths-in-your-emacs-config\"\u003e\u003cspan class=\"section-num\"\u003e4\u003c/span\u003e Set the correct paths in your Emacs config\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#testing-that-the-right-org-version-got-loaded\"\u003e\u003cspan class=\"section-num\"\u003e5\u003c/span\u003e Testing that the right Org version got loaded\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#future-org-development-version-updates\"\u003eFuture Org development version updates\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eThis post is a re-write of \u003ca href=\"/building-org-development-version-2017/\"\u003ean earlier \u0026ldquo;Building Org Development\nversion\u0026rdquo; post\u003c/a\u003e but minus all the outdated stuff.\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eI am assuming that you already know what \u003ca href=\"https://orgmode.org/\"\u003eOrg mode\u003c/a\u003e is and that\u0026rsquo;s why\nyou are here 😃.\u003c/p\u003e\n\u003cp\u003eYou would want to build Org from its development branch (\u003ca href=\"https://git.savannah.gnu.org/cgit/emacs/org-mode.git/log/?h=main\"\u003e\u003cstrong\u003emain\u003c/strong\u003e\nbranch\u003c/a\u003e) to get the latest and greatest goodies \u003cem\u003eplus\u003c/em\u003e bug fixes! Go\nthrough the \u003ca href=\"https://git.savannah.gnu.org/cgit/emacs/org-mode.git/tree/etc/ORG-NEWS?h=main\"\u003e\u003ccode\u003eORG-NEWS\u003c/code\u003e\u003c/a\u003e file to read about what\u0026rsquo;s new in the \u003cstrong\u003emain\u003c/strong\u003e\nbranch.\u003c/p\u003e\n\u003cp\u003eIf you like what you see there, here are the steps for installing the\ndevelopment version of Org.\u003c/p\u003e\n\n\u003ch2 id=\"clone-the-org-repo\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Clone the Org repo\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#clone-the-org-repo\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit clone https://git.savannah.gnu.org/git/emacs/org-mode.git\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"build-setup\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Build Setup\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#build-setup\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003eCopy \u003ccode\u003e\u0026lt;REPO_ROOT\u0026gt;/mk/default.mk\u003c/code\u003e to \u003ccode\u003e\u0026lt;REPO_ROOT\u0026gt;/local.mk\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eTweak \u003ccode\u003elocal.mk\u003c/code\u003e (optional)\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch3 id=\"customizing-local-dot-mk--optional\"\u003eCustomizing \u003ccode\u003elocal.mk\u003c/code\u003e (Optional)\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#customizing-local-dot-mk--optional\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eHere are few variables that you might like to change in the \u003ccode\u003elocal.mk\u003c/code\u003e:\u003c/p\u003e\n\u003cdl\u003e\n\u003cdt\u003e\u003ccode\u003eprefix\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eOrg installation directory\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-makefile\" data-lang=\"makefile\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eprefix\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e /dir/where/you/want/to/install/org \u003cspan class=\"c1\"\u003e# Default: /usr/share\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThe \u003ccode\u003e.el\u003c/code\u003e files will go to \u003ccode\u003e$(prefix)/emacs/site-lisp/org\u003c/code\u003e by\ndefault. If you\u0026rsquo;d like to change that, change the \u003ccode\u003elispdir\u003c/code\u003e\nvariable too.\u003c/p\u003e\n\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003einfodir\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eOrg Info installation directory. I like to keep the\nInfo file for development version of Org in a separate directory.\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-makefile\" data-lang=\"makefile\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003einfodir\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"k\"\u003e$(\u003c/span\u003eprefix\u003cspan class=\"k\"\u003e)\u003c/span\u003e/org/info \u003cspan class=\"c1\"\u003e# Default: $(prefix)/info\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eORG_MAKE_DOC\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eTypes of Org documentation you\u0026rsquo;d like to build by\ndefault.  Setting below generates only the Org Info manual.\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-makefile\" data-lang=\"makefile\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eORG_MAKE_DOC\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e info \u003cspan class=\"c1\"\u003e# Default: html pdf\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ch2 id=\"build\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e Build\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#build\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emake autoloads\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emake\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emake doc\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emake install\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eType \u003ccode\u003emake help\u003c/code\u003e for help on the Org \u003ccode\u003eMakefile\u003c/code\u003e. Type \u003ccode\u003emake helpall\u003c/code\u003e\nto get a detailed help, or see the \u003ca href=\"https://orgmode.org/worg/dev/org-build-system.html\"\u003eOrg build system help\u003c/a\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"set-the-correct-paths-in-your-emacs-config\"\u003e\u003cspan class=\"section-num\"\u003e4\u003c/span\u003e Set the correct paths in your Emacs config\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#set-the-correct-paths-in-your-emacs-config\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003eUpdate \u003ccode\u003eload-path\u003c/code\u003e to remove the Org version that ships with\nEmacs. Do the same if you have Org installed via GNU ELPA\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nIf you need the latest stable version of Org mode, install it from\nGNU ELPA.\n\u003c/small\u003e\u003c/span\u003e\ntoo.\u003c/li\u003e\n\u003cli\u003eAlso remove the associated old Org mode Info manuals from\n\u003ccode\u003eInfo-directory-list\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eUpdate the \u003ccode\u003eload-path\u003c/code\u003e and \u003ccode\u003eInfo-directory-list\u003c/code\u003e variables to point\nto the Org mode source code and Info manual built using the \u003cstrong\u003emain\u003c/strong\u003e\nbranch.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003ca href=\"#code-snippet--org-load-path-info-update\"\u003eBelow code\u003c/a\u003e does all that but\n\u003cmark\u003emake sure this code is executed \u003cstrong\u003eafter\u003c/strong\u003e you do \u003ccode\u003e(package-initialize)\u003c/code\u003e,\nbut \u003cstrong\u003ebefore\u003c/strong\u003e you \u003ccode\u003erequire\u003c/code\u003e the \u003ccode\u003eorg\u003c/code\u003e package\u003c/mark\u003e . You can use \u003ca href=\"https://github.com/jwiegley/use-package\"\u003e\u003ccode\u003euse-package\u003c/code\u003e\u003c/a\u003e and make sure that this order of code\nevaluation is always correct \u0026mdash; Just put the code from\n\u003ca href=\"#code-snippet--org-load-path-info-update\"\u003eCode Snippet 2\u003c/a\u003e where \u003ccode\u003e\u0026lt;HERE\u0026gt;\u003c/code\u003e is shown in the below\nsnippet:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--use-package-org\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003euse-package\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nb\"\u003e:preface\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003e\u0026lt;HERE\u0026gt;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--use-package-org\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Update \u003ccode\u003eload-path\u003c/code\u003e and \u003ccode\u003eInfo-directory-list\u003c/code\u003e in \u003ccode\u003euse-package\u003c/code\u003e \u003ccode\u003e:preface\u003c/code\u003e\n\u003c/div\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--org-load-path-info-update\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefvar\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-version-select\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;dev\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Variable to choose the version of Org to be loaded.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eValid values are \u003c/span\u003e\u003cspan class=\"ss\"\u003e`dev\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e, \u003c/span\u003e\u003cspan class=\"ss\"\u003e`elpa\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e and \u003c/span\u003e\u003cspan class=\"ss\"\u003e`emacs\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eWhen set to \u003c/span\u003e\u003cspan class=\"ss\"\u003e`dev\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e, the development version of Org built locally\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eis loaded.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eWhen set to \u003c/span\u003e\u003cspan class=\"ss\"\u003e`elpa\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e, Org is installed and loaded from GNU ELPA.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eWhen set to \u003c/span\u003e\u003cspan class=\"ss\"\u003e`emacs\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e, the Org version shipped with Emacs is used.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefvar\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/default-lisp-directory\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;/your/emacs/share/dir/version/lisp/\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Directory containing lisp files for the Emacs installation.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eThis value must match the path to the lisp/ directory of your\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eEmacs installation.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eIf Emacs is installed using --prefix=\\\u0026#34;${PREFIX_DIR}\\\u0026#34; this value\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003ewould typically be\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\\\u0026#34;${PREFIX_DIR}/share/emacs/\u0026lt;VERSION\u0026gt;/lisp/\\\u0026#34;.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefvar\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-dev-lisp-directory\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;/value/of/lispdir/in/local.mk\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Directory containing lisp files for dev version of Org.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eThis value must match the \u003c/span\u003e\u003cspan class=\"ss\"\u003e`lispdir\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e variable in the Org local.mk.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eBy default the value is \\\u0026#34;$prefix/emacs/site-lisp/org\\\u0026#34;, where\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\u003c/span\u003e\u003cspan class=\"ss\"\u003e`prefix\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e must match that in local.mk too.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefvar\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-dev-info-directory\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;/value/of/infodir/in/local.mk\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Directory containing Info manual file for dev version of Org.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eThis value must match the \u003c/span\u003e\u003cspan class=\"ss\"\u003e`infodir\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e variable in the Org local.mk.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-dev-lisp-directory\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"nv\"\u003eorg-dev-info-directory\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewith-eval-after-load\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;package\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; If `modi/org-version-select\u0026#39; is *not* `emacs\u0026#39;, remove the Emacs\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; version of Org from the `load-path\u0026#39;.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eunless\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eeq\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-version-select\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;emacs\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; Remove Org that ships with Emacs from the `load-path\u0026#39;.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003edefault-org-path\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eexpand-file-name\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;org\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/default-lisp-directory\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eload-path\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edelete\u003c/span\u003e \u003cspan class=\"nv\"\u003edefault-org-path\u003c/span\u003e \u003cspan class=\"nv\"\u003eload-path\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; If `modi/org-version-select\u0026#39; is *not* `elpa\u0026#39;, remove the Elpa\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; version of Org from the `load-path\u0026#39;.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eunless\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eeq\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-version-select\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;elpa\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edolist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-elpa-install-path\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edirectory-files-recursively\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                      \u003cspan class=\"nv\"\u003epackage-user-dir\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                      \u003cspan class=\"s\"\u003e\u0026#34;\\\\`org-[0-9.]+\\\\\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                      \u003cspan class=\"nb\"\u003e:include-directories\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eload-path\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edelete\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-elpa-install-path\u003c/span\u003e \u003cspan class=\"nv\"\u003eload-path\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"c1\"\u003e;; Also ensure that the associated path is removed from Info\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"c1\"\u003e;; search list.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eInfo-directory-list\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edelete\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-elpa-install-path\u003c/span\u003e \u003cspan class=\"nv\"\u003eInfo-directory-list\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003edev-org-path\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edirectory-file-name\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-dev-lisp-directory\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edev-org-info\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edirectory-file-name\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-dev-info-directory\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eeq\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-version-select\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;dev\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eprogn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-to-list\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;load-path\u003c/span\u003e \u003cspan class=\"nv\"\u003edev-org-path\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e;; It\u0026#39;s possible that `org-dev-info-directory\u0026#39; is set to\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e;; an unconventional value, in which case, it will not be\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e;; automatically added to `Info-directory-alist\u0026#39;. So add\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e;; it to `Info-directory-alist\u0026#39; manually.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-to-list\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;Info-directory-list\u003c/span\u003e \u003cspan class=\"nv\"\u003edev-org-info\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"c1\"\u003e;; If `modi/org-version-select\u0026#39; is *not* `dev\u0026#39;, remove the\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"c1\"\u003e;; development version of Org from the `load-path\u0026#39;, and its\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"c1\"\u003e;; Info from the Info search list.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eload-path\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edelete\u003c/span\u003e \u003cspan class=\"nv\"\u003edev-org-path\u003c/span\u003e \u003cspan class=\"nv\"\u003eload-path\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewith-eval-after-load\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;info\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eInfo-directory-list\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edelete\u003c/span\u003e \u003cspan class=\"nv\"\u003edev-org-info\u003c/span\u003e \u003cspan class=\"nv\"\u003eInfo-directory-list\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--org-load-path-info-update\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Emacs config snippet to ensure that \u003ccode\u003eload-path\u003c/code\u003e and \u003ccode\u003eInfo-directory-list\u003c/code\u003e use the right Org version\n\u003c/div\u003e\n\u003cdl\u003e\n\u003cdt\u003eNote\u003c/dt\u003e\n\u003cdd\u003eRemember that you need to correctly set the values of these\n3 variables in the above snippet:\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003emodi/default-lisp-directory\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eorg-dev-lisp-directory\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eorg-dev-info-directory\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ch2 id=\"testing-that-the-right-org-version-got-loaded\"\u003e\u003cspan class=\"section-num\"\u003e5\u003c/span\u003e Testing that the right Org version got loaded\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#testing-that-the-right-org-version-got-loaded\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003eRestart Emacs\u003c/strong\u003e (\u003cem\u003eDon\u0026rsquo;t be lazy \u0026mdash; do it!\u003c/em\u003e)\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eM-x org-version\u003c/code\u003e \u0026ndash; That should show something like this in the\necho area:\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eOrg mode version 9.5.3 (release_9.5.3-482-gd5a52b @ /home/kmodi/usr_local/apps/7/emacs/emacs-28/share/emacs/site-lisp/org/)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003eThis message format is broken down as:\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eOrg mode version \u0026lt;ORG-VERSION\u0026gt; (release_\u0026lt;ORG-VERSION\u0026gt;-NNN-g\u0026lt;GIT-HASH\u0026gt; @ \u0026lt;PREFIX\u0026gt;/emacs/site-lisp/org/)\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eIf the \u003ccode\u003eGIT-HASH\u003c/code\u003e and \u003ccode\u003ePREFIX\u003c/code\u003e above are what you expect,\ncongratulations! You did it! 🎉\u003c/p\u003e\n\u003cp\u003eElse, let me know in comments if I can help you.\u003c/p\u003e\n\n\u003ch2 id=\"future-org-development-version-updates\"\u003eFuture Org development version updates\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#future-org-development-version-updates\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003eBelow will do \u003ccode\u003egit pull\u003c/code\u003e and build Org.\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-shell\" data-lang=\"shell\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emake update\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003eRestart Emacs.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-org.el\"\u003e\u003ccode\u003esetup-org.el\u003c/code\u003e in my Emacs config\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/setup-packages.el\"\u003e\u003ccode\u003esetup-packages.el\u003c/code\u003e in my Emacs config\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","text":" Table of Contents 1 Clone the Org repo 2 Build Setup Customizing local.mk (Optional) 3 Build 4 Set the correct paths in your Emacs config 5 Testing that the right Org version got loaded Future Org development version updates References This post is a re-write of an earlier \u0026ldquo;Building Org Development version\u0026rdquo; post but minus all the outdated stuff.\nI am assuming that you already know what Org mode is and that\u0026rsquo;s why you are here 😃.\nYou would want to build Org from its development branch (main branch) to get the latest and greatest goodies plus bug fixes! Go through the ORG-NEWS file to read about what\u0026rsquo;s new in the main branch.\nIf you like what you see there, here are the steps for installing the development version of Org.\n1 Clone the Org repo\u0026nbsp;# git clone https://git.savannah.gnu.org/git/emacs/org-mode.git 2 Build Setup\u0026nbsp;# Copy \u0026lt;REPO_ROOT\u0026gt;/mk/default.mk to \u0026lt;REPO_ROOT\u0026gt;/local.mk Tweak local.mk (optional) Customizing local.mk (Optional)\u0026nbsp;# Here are few variables that you might like to change in the local.mk:\nprefix Org installation directory prefix = /dir/where/you/want/to/install/org # Default: /usr/share The .el files will go to $(prefix)/emacs/site-lisp/org by default. If you\u0026rsquo;d like to change that, change the lispdir variable too.\ninfodir Org Info installation directory. I like to keep the Info file for development version of Org in a separate directory. infodir = $(prefix)/org/info # Default: $(prefix)/info ORG_MAKE_DOC Types of Org documentation you\u0026rsquo;d like to build by default. Setting below generates only the Org Info manual. ORG_MAKE_DOC = info # Default: html pdf 3 Build\u0026nbsp;# make autoloads make make doc make install Type make help for help on the Org Makefile. Type make helpall to get a detailed help, or see the Org build system help.\n4 Set the correct paths in your Emacs config\u0026nbsp;# Update load-path to remove the Org version that ships with Emacs. Do the same if you have Org installed via GNU ELPA If you need the latest stable version of Org mode, install it from GNU ELPA. too. Also remove the associated old Org mode Info manuals from Info-directory-list. Update the load-path and Info-directory-list variables to point to the Org mode source code and Info manual built using the main branch. Below code does all that but make sure this code is executed after you do (package-initialize), but before you require the org package . You can use use-package and make sure that this order of code evaluation is always correct \u0026mdash; Just put the code from Code Snippet 2 where \u0026lt;HERE\u0026gt; is shown in the below snippet:\n(use-package org :preface \u0026lt;HERE\u0026gt;) Code Snippet 1: Update load-path and Info-directory-list in use-package :preface (defvar modi/org-version-select \u0026#39;dev \u0026#34;Variable to choose the version of Org to be loaded. Valid values are `dev\u0026#39;, `elpa\u0026#39; and `emacs\u0026#39;. When set to `dev\u0026#39;, the development version of Org built locally is loaded. When set to `elpa\u0026#39;, Org is installed and loaded from GNU ELPA. When set to `emacs\u0026#39;, the Org version shipped with Emacs is used.\u0026#34;) (defvar modi/default-lisp-directory \u0026#34;/your/emacs/share/dir/version/lisp/\u0026#34; \u0026#34;Directory containing lisp files for the Emacs installation. This value must match the path to the lisp/ directory of your Emacs installation. If Emacs is installed using --prefix=\\\u0026#34;${PREFIX_DIR}\\\u0026#34; this value would typically be \\\u0026#34;${PREFIX_DIR}/share/emacs/\u0026lt;VERSION\u0026gt;/lisp/\\\u0026#34;.\u0026#34;) (defvar org-dev-lisp-directory \u0026#34;/value/of/lispdir/in/local.mk\u0026#34; \u0026#34;Directory containing lisp files for dev version of Org. This value must match the `lispdir\u0026#39; variable in the Org local.mk. By default the value is \\\u0026#34;$prefix/emacs/site-lisp/org\\\u0026#34;, where `prefix\u0026#39; must match that in local.mk too.\u0026#34;) (defvar org-dev-info-directory \u0026#34;/value/of/infodir/in/local.mk\u0026#34; \u0026#34;Directory containing Info manual file for dev version of Org. This value must match the `infodir\u0026#39; variable in the Org local.mk.\u0026#34;) (when (and org-dev-lisp-directory org-dev-info-directory) (with-eval-after-load \u0026#39;package ;; If `modi/org-version-select\u0026#39; is *not* `emacs\u0026#39;, remove the Emacs ;; version of Org from the `load-path\u0026#39;. (unless (eq modi/org-version-select \u0026#39;emacs) ;; Remove Org that ships with Emacs from the `load-path\u0026#39;. (let ((default-org-path (expand-file-name \u0026#34;org\u0026#34; modi/default-lisp-directory))) (setq load-path (delete default-org-path load-path)))) ;; If `modi/org-version-select\u0026#39; is *not* `elpa\u0026#39;, remove the Elpa ;; version of Org from the `load-path\u0026#39;. (unless (eq modi/org-version-select \u0026#39;elpa) (dolist (org-elpa-install-path (directory-files-recursively package-user-dir \u0026#34;\\\\`org-[0-9.]+\\\\\u0026#39;\u0026#34; :include-directories)) (setq load-path (delete org-elpa-install-path load-path)) ;; Also ensure that the associated path is removed from Info ;; search list. (setq Info-directory-list (delete org-elpa-install-path Info-directory-list)))) (let ((dev-org-path (directory-file-name org-dev-lisp-directory)) (dev-org-info (directory-file-name org-dev-info-directory))) (if (eq modi/org-version-select \u0026#39;dev) (progn (add-to-list \u0026#39;load-path dev-org-path) ;; It\u0026#39;s possible that `org-dev-info-directory\u0026#39; is set to ;; an unconventional value, in which case, it will not be ;; automatically added to `Info-directory-alist\u0026#39;. So add ;; it to `Info-directory-alist\u0026#39; manually. (add-to-list \u0026#39;Info-directory-list dev-org-info)) ;; If `modi/org-version-select\u0026#39; is *not* `dev\u0026#39;, remove the ;; development version of Org from the `load-path\u0026#39;, and its ;; Info from the Info search list. (setq load-path (delete dev-org-path load-path)) (with-eval-after-load \u0026#39;info (setq Info-directory-list (delete dev-org-info Info-directory-list))))))) Code Snippet 2: Emacs config snippet to ensure that load-path and Info-directory-list use the right Org version Note Remember that you need to correctly set the values of these 3 variables in the above snippet: modi/default-lisp-directory org-dev-lisp-directory org-dev-info-directory 5 Testing that the right Org version got loaded\u0026nbsp;# Restart Emacs (Don\u0026rsquo;t be lazy \u0026mdash; do it!) M-x org-version \u0026ndash; That should show something like this in the echo area: Org mode version 9.5.3 (release_9.5.3-482-gd5a52b @ /home/kmodi/usr_local/apps/7/emacs/emacs-28/share/emacs/site-lisp/org/) This message format is broken down as: Org mode version \u0026lt;ORG-VERSION\u0026gt; (release_\u0026lt;ORG-VERSION\u0026gt;-NNN-g\u0026lt;GIT-HASH\u0026gt; @ \u0026lt;PREFIX\u0026gt;/emacs/site-lisp/org/) If the GIT-HASH and PREFIX above are what you expect, congratulations! You did it! 🎉\nElse, let me know in comments if I can help you.\nFuture Org development version updates\u0026nbsp;# Below will do git pull and build Org. make update Restart Emacs. References\u0026nbsp;# setup-org.el in my Emacs config setup-packages.el in my Emacs config "},"name":"Building Org Development version (2022)","published":"2022-05-13T17:01:00-04:00","summary":"A guide on how to build Org mode from its main branch and load in Emacs without any path shadowing.","type":"entry","url":"https://scripter.co/building-org-development-version/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#single-file-patch\"\u003eSingle-file patch\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#multi-file-patch\"\u003eMulti-file patch\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#more-resources\"\u003eMore Resources\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eRecently I came across few instances where people were asking\nquestions related to creating patches for contributions to Emacs and\nOrg mode repos \u003ca href=\"https://www.reddit.com/r/emacs/comments/udjk8l/how_do_you_actually_send_pull_requests_in/\"\u003ehere\u003c/a\u003e and then \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/discussions/618#discussioncomment-2690410\"\u003ehere\u003c/a\u003e. I was in the same shoes back then\nwhen I was about to make my first contribution to Emacs. And so I\nthought of sharing this tip on how to use Magit to create patch files.\u003c/p\u003e\n\u003cp\u003eIf you have been using both Emacs and git, you might have already\nheard about the awesome \u003ca href=\"https://magit.vc/\"\u003eMagit\u003c/a\u003e package. If you haven\u0026rsquo;t 😲,\ncheck out \u003ca href=\"https://emacsair.me/2017/09/01/magit-walk-through/\"\u003ethis screenshot-annotated review of what Magit is\u003c/a\u003e. With that\nout of the way, and assuming that you already have it installed\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\n\u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003euse-package\u003c/span\u003e \u003cspan class=\"nv\"\u003emagit\u003c/span\u003e \u003cspan class=\"nb\"\u003e:ensure\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/code\u003e\n\u003c/small\u003e\u003c/span\u003e\n, here\u0026rsquo;s how to create a patch file using Magit ..\u003c/p\u003e\n\n\u003ch2 id=\"single-file-patch\"\u003eSingle-file patch\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#single-file-patch\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003eCommit your changes to the git repo first.\u003c/li\u003e\n\u003cli\u003eBring up the \u003cstrong\u003eMagit Log\u003c/strong\u003e view. From the Magit status buffer, you\nwould type \u003ckbd\u003el\u003c/kbd\u003e \u003ckbd\u003el\u003c/kbd\u003e to show the log of the current branch.\u003c/li\u003e\n\u003cli\u003eMove the point to the commit that you want to send as a patch file,\nand hit \u003ckbd\u003eW\u003c/kbd\u003e \u003ckbd\u003ec\u003c/kbd\u003e \u003ckbd\u003ec\u003c/kbd\u003e \u003ckbd\u003eRET\u003c/kbd\u003e.\n\u003cul\u003e\n\u003cli\u003eThe last \u003ckbd\u003eRET\u003c/kbd\u003e selects the commit the point is on, in the\n∗magit-log∗ buffer.\u003c/li\u003e\n\u003cli\u003eIf the first line of the commit log of the selected commit is\n\u0026ldquo;Update docstrings for shortdoc.el\u0026rdquo;, you\u0026rsquo;ll see a patch file\nnamed \u003ccode\u003e0001-Update-docstrings-for-shortdoc.el.patch\u003c/code\u003e created in\nyour git repo root.\u003c/li\u003e\n\u003cli\u003eYou can now email this patch file\n\u003cmark\u003eas an attachment\u003c/mark\u003e to \u003ca href=\"mailto:bug-gnu-emacs@gnu.org\"\u003ebug-gnu-emacs@gnu.org\u003c/a\u003e (if contributing to Emacs) or to\n\u003ca href=\"mailto:emacs-orgmode@gnu.org\"\u003eemacs-orgmode@gnu.org\u003c/a\u003e (if contributing to Org mode).\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"multi-file-patch\"\u003eMulti-file patch\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#multi-file-patch\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIf you need to create a multi-file patch i.e. patch files for a series\nof commits, select those commits in the ∗magit-log∗ buffer\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThe commit selection process is the same as how you would select\ntext in any Emacs buffer. For example, if I want to create a series\nof 5 patches, I would go to the latest commit in the series, hit\n\u003ckbd\u003eC-SPC\u003c/kbd\u003e and then \u003ckbd\u003eC-n\u003c/kbd\u003e 4 times to select 5 rows of commits.\n\u003c/small\u003e\u003c/span\u003e\n, and then use the same \u003ckbd\u003eW\u003c/kbd\u003e \u003ckbd\u003ec\u003c/kbd\u003e \u003ckbd\u003ec\u003c/kbd\u003e binding.\u003c/p\u003e\n\n\u003ch2 id=\"more-resources\"\u003eMore Resources\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#more-resources\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eHere are the official contribution guides for Emacs and Org mode:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://git.savannah.gnu.org/cgit/emacs.git/tree/CONTRIBUTE\"\u003eHow to contribute to Emacs \u0026ndash; Emacs CONTRIBUTE document\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://orgmode.org/worg/org-contribute.html\"\u003eHow to contribute to Org \u0026ndash; Worg\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eHere are some more resources that got shared in the \u003cem\u003eEmacsverse\u003c/em\u003e\nrecently (within the past year as of writing this):\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2022-04-23 Sat\u0026gt; \u003c/span\u003e\u003c/span\u003e \u003ca href=\"https://lists.gnu.org/r/emacs-orgmode/2022-04/orgYGCOr0hBKH.org\"\u003eContributing patches to Org \u0026ndash; Ihor Radchenko\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2022-04-09 Sat\u0026gt; \u003c/span\u003e\u003c/span\u003e \u003ca href=\"https://protesilaos.com/codelog/2022-04-09-simple-guide-git-patches-emacs/\"\u003ePrimer on formatting Git patches with Emacs (Magit) \u0026ndash; Protesilaos Stavrou\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2021-08-17 Tue\u0026gt; \u003c/span\u003e\u003c/span\u003e \u003ca href=\"https://www.fosskers.ca/en/blog/contributing-to-emacs\"\u003eContributing to Emacs \u0026ndash; Colin Woodbury\u003c/a\u003e\u003c/li\u003e\n\u003c/ol\u003e\n","text":" Table of Contents Single-file patch Multi-file patch More Resources Recently I came across few instances where people were asking questions related to creating patches for contributions to Emacs and Org mode repos here and then here. I was in the same shoes back then when I was about to make my first contribution to Emacs. And so I thought of sharing this tip on how to use Magit to create patch files.\nIf you have been using both Emacs and git, you might have already heard about the awesome Magit package. If you haven\u0026rsquo;t 😲, check out this screenshot-annotated review of what Magit is. With that out of the way, and assuming that you already have it installed (use-package magit :ensure t) , here\u0026rsquo;s how to create a patch file using Magit ..\nSingle-file patch\u0026nbsp;# Commit your changes to the git repo first. Bring up the Magit Log view. From the Magit status buffer, you would type l l to show the log of the current branch. Move the point to the commit that you want to send as a patch file, and hit W c c RET. The last RET selects the commit the point is on, in the ∗magit-log∗ buffer. If the first line of the commit log of the selected commit is \u0026ldquo;Update docstrings for shortdoc.el\u0026rdquo;, you\u0026rsquo;ll see a patch file named 0001-Update-docstrings-for-shortdoc.el.patch created in your git repo root. You can now email this patch file as an attachment to bug-gnu-emacs@gnu.org (if contributing to Emacs) or to emacs-orgmode@gnu.org (if contributing to Org mode). Multi-file patch\u0026nbsp;# If you need to create a multi-file patch i.e. patch files for a series of commits, select those commits in the ∗magit-log∗ buffer The commit selection process is the same as how you would select text in any Emacs buffer. For example, if I want to create a series of 5 patches, I would go to the latest commit in the series, hit C-SPC and then C-n 4 times to select 5 rows of commits. , and then use the same W c c binding.\nMore Resources\u0026nbsp;# Here are the official contribution guides for Emacs and Org mode:\nHow to contribute to Emacs \u0026ndash; Emacs CONTRIBUTE document How to contribute to Org \u0026ndash; Worg Here are some more resources that got shared in the Emacsverse recently (within the past year as of writing this):\n\u0026lt;2022-04-23 Sat\u0026gt; Contributing patches to Org \u0026ndash; Ihor Radchenko \u0026lt;2022-04-09 Sat\u0026gt; Primer on formatting Git patches with Emacs (Magit) \u0026ndash; Protesilaos Stavrou \u0026lt;2021-08-17 Tue\u0026gt; Contributing to Emacs \u0026ndash; Colin Woodbury "},"name":"Creating a patch file using Magit","published":"2022-05-08T08:48:00-04:00","summary":"Quick tip on how to create git patch files in Emacs using Magit.","type":"entry","url":"https://scripter.co/creating-a-patch-file-using-magit/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#my-flow-for-creating-this-library\"\u003eMy flow for creating this library\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#adapting-the-library-to-fit-ox-hugo\"\u003eAdapting the library to fit \u003ccode\u003eox-hugo\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#changes-in-ox-hugo-tests\"\u003eChanges in \u003ccode\u003eox-hugo\u003c/code\u003e tests\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#what-s-next\"\u003eWhat\u0026rsquo;s next?\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#unblocking-some-future-ox-hugo-improvements\"\u003eUnblocking some future \u003ccode\u003eox-hugo\u003c/code\u003e improvements\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eIn my previous post \u003ca href=\"/defining-tomelr/\"\u003eDefining \u003cem\u003etomelr\u003c/em\u003e\u003c/a\u003e, I started toying with the idea\nof creating a library that would help convert any Lisp expression to a\nTOML config, and I share my vision (specification) of what this\nlibrary would look like.\u003c/p\u003e\n\u003cp\u003eI wasn\u0026rsquo;t even sure if I would be able to make the \u003ca href=\"https://github.com/kaushalmodi/tomelr\"\u003e\u003cstrong\u003etomelr\u003c/strong\u003e\u003c/a\u003e library\nfeature-complete at least to the extent of what \u003ccode\u003eox-hugo\u003c/code\u003e was already\ndoing! But to my surprise, the library development snowballed to a\ncompletion much earlier than I thought, and additionally it helped fix\nsome inconsistencies that the older TOML generation code had in\n\u003ccode\u003eox-hugo\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eIn this post, I start by (i) giving a broad overview of how the\ndevelopment of \u003ccode\u003etomelr\u003c/code\u003e happened, then (ii) briefly describe how it\ngot integrated into \u003ccode\u003eox-hugo\u003c/code\u003e, and finally (iii) how the use of this\nlibrary will unblock the path to addition of some cool features to\n\u003ccode\u003eox-hugo\u003c/code\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"my-flow-for-creating-this-library\"\u003eMy flow for creating this library\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#my-flow-for-creating-this-library\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003eWrite the spec for the library.\n\u003cul\u003e\n\u003cli\u003eList all the formats of Lisp data I would expect it to process.\u003c/li\u003e\n\u003cli\u003eList the corresponding TOML data I would expect it to generate.\u003c/li\u003e\n\u003cli\u003eEnsure that I am not inventing my \u003cem\u003eown lisp syntax\u003c/em\u003e by confirming\nthat the expected TOML output matches the JSON generated from\nthat same lisp form (using the Emacs built-in \u003ccode\u003ejson.el\u003c/code\u003e library).\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eThat helped me write the tests first! \u0026ndash; \u003ca href=\"https://en.wikipedia.org/wiki/Test-driven_development\"\u003eTest Driven Development\n(TDD)\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003eI started with writing tests for TOML booleans and then\nimplementing that (because that was the simplest and easiest). Of\ncourse, I used \u003ca href=\"/quick-intro-to-emacs-lisp-regression-testing/\"\u003eert\u003c/a\u003e for this! \u003ccode\u003eert\u003c/code\u003e helped me quickly create small\nmodular tests\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\n\u003ca href=\"https://github.com/kaushalmodi/tomelr/blob/867c82c9e230309c748de59bf8c0937b10d6fc64/test/tscalar.el#L31-L43\"\u003eHere\u0026rsquo;s\u003c/a\u003e the \u003cem\u003eert\u003c/em\u003e test for booleans as an example.\n\u003c/small\u003e\u003c/span\u003e\nand efficiently iterate through modifications in the library code\nuntil I got the tests to pass.\u003c/li\u003e\n\u003cli\u003eOnce that got working, I set up a continuous integration system\nusing \u003ca href=\"https://docs.github.com/en/actions\"\u003eGitHub Actions (GHA)\u003c/a\u003e. I used GHA because I host my library on\nGitHub. Also I already have a tried and tested setup that I could\nget up and going in a matter of few seconds. In general, this\nconcept would apply to any \u003cem\u003eContinuous Integration system\u003c/em\u003e. The CI\nsetup step should come early in the development of any project so\nthat incremental feature additions don\u0026rsquo;t start breaking previously\nadded features 😃.\u003c/li\u003e\n\u003cli\u003eThe library development just snowballed after this point .. added\nsupport for integers, floats, regular strings, multi-line strings,\narrays, TOML tables, arrays of TOML tables. By this time, the\nlibrary was about 80% finished.\u003c/li\u003e\n\u003cli\u003eThen came the difficult part .. stabilizing the library to support\nall the varieties of Lisp data I can think of. I must have put in\ndouble the time spent so far to finish the remaining 20% of the\nplanned features for this library 👉 \u003ca href=\"https://github.com/kaushalmodi/tomelr/tree/main/test\"\u003e\u003cstrong\u003etomelr test suite\u003c/strong\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003eOnce I had the test suite complete and passing, it was time to do\nsome code cleanup:\n\u003cul\u003e\n\u003cli\u003eRemove duplicate code and break them off into smaller helper\nfunctions.\u003c/li\u003e\n\u003cli\u003eSee if the function defined in this library is already defined\nsomewhere else (in this case, I was able to use \u003ccode\u003ejson-plist-p\u003c/code\u003e\ndirectly from \u003ccode\u003ejson.el\u003c/code\u003e).\u003c/li\u003e\n\u003cli\u003eProof read the code.\u003c/li\u003e\n\u003cli\u003eProof read the docstrings and run \u003ccode\u003eM-x checkdoc\u003c/code\u003e to fix their\nformatting.\u003c/li\u003e\n\u003cli\u003eEnsure that the code compiles without any warnings.\u003c/li\u003e\n\u003cli\u003eRemove unnecessary customization options and case statements from\nthe library (while continuously ensuring that the \u003cem\u003eert\u003c/em\u003e tests\nstill pass).\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"adapting-the-library-to-fit-ox-hugo\"\u003eAdapting the library to fit \u003ccode\u003eox-hugo\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#adapting-the-library-to-fit-ox-hugo\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eAfter polishing the library by its stand-alone testing, I decided to\nuse it with \u003ccode\u003eox-hugo\u003c/code\u003e and see how the test suite in that repo fared.\u003c/p\u003e\n\u003cp\u003eOf course I saw that a lot of tests failed now 😁.\u003c/p\u003e\n\u003cp\u003eThe main issue was that \u003ccode\u003etomelr\u003c/code\u003e was constructing multi-line strings\nsuch that the spaces translated exactly from Lisp data to TOML. So\n\u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003etomelr-encode\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003efoo\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;line1\\nline2\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\u003c/code\u003e would generate:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--tomelr-mls-no-extra-ws\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-toml\" data-lang=\"toml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003efoo\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003eline1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003eline2\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--tomelr-mls-no-extra-ws\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Multi-line string with same white-space as in original data.. but not that \"pretty\"\n\u003c/div\u003e\n\u003cp\u003ewhereas \u003ccode\u003eox-hugo\u003c/code\u003e expected the same TOML to look like:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--tomelr-pretty-mls\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-toml\" data-lang=\"toml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003efoo\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003e  line1\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003e  line2\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003e  \u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--tomelr-pretty-mls\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Pretty multi-line string, but with extra white-space\n\u003c/div\u003e\n\u003cp\u003eI had intentionally decided for \u003ccode\u003eox-hugo\u003c/code\u003e to have this latter format\nfor multi-line strings because (i) it made it more readable with the\n\u003cem\u003etriple-quotes\u003c/em\u003e out of the way on their own lines, (ii) the indented\nlines prevented the multi-line string from getting mixed with\nsurrounding TOML parameters, and \u003cstrong\u003emost importantly\u003c/strong\u003e (iii) these\nstrings were processed by the Hugo Markdown parser, and so it wasn\u0026rsquo;t\nsensitive to horizontal spaces.\u003c/p\u003e\n\u003cp\u003eAnd so the \u003ccode\u003etomelr-indent-multi-line-strings\u003c/code\u003e feature was born\n(\u003ca href=\"https://github.com/kaushalmodi/tomelr/commit/3362213172237f40ff0d9aa3ddf12b4bb00a3564\"\u003ecommit\u003c/a\u003e) which optionally made \u003ccode\u003etomelr\u003c/code\u003e export multi-line strings as\nexpected by \u003ccode\u003eox-hugo\u003c/code\u003e 😎.\u003c/p\u003e\n\n\u003ch2 id=\"changes-in-ox-hugo-tests\"\u003eChanges in \u003ccode\u003eox-hugo\u003c/code\u003e tests\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#changes-in-ox-hugo-tests\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eOnce I had finalized the integration of \u003ccode\u003etomelr\u003c/code\u003e into \u003ccode\u003eox-hugo\u003c/code\u003e, I had\nonly about 30 tests change out of roughly 400 tests. These changes\nwere welcome as they fixed all the inconsistencies in the older TOML\ngeneration code in \u003ccode\u003eox-hugo\u003c/code\u003e. If interested, you can see \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/commit/c24ea792484598ffd2f8e786fadb823d48c8ec12\"\u003ethis commit\u003c/a\u003e\nfor the diff and details, but here\u0026rsquo;s the gist:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eNow \u003cem\u003enil\u003c/em\u003e value of a key in Lisp consistently implies that the key\nshould not be exported to TOML. So \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003efoo\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003c/code\u003e will result in \u003ccode\u003efoo\u003c/code\u003e \u003cstrong\u003enot\u003c/strong\u003e getting exported\nto TOML, whether that\u0026rsquo;s a top-level key or a key in a nested TOML\nmap or array. If you need to set a key to a boolean \u003cem\u003efalse\u003c/em\u003e, use\n\u003ccode\u003e\u0026quot;false\u0026quot;\u003c/code\u003e or any value from \u003ccode\u003etomelr-false\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eEarlier \u003cem\u003eempty string\u003c/em\u003e value as in \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003efoo\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003c/code\u003e behaved like the current \u003cem\u003enil\u003c/em\u003e\nimplementation. That\u0026rsquo;s not the case any more. Now that empty string\nwill export as \u003ccode class=\"code-inline language-toml\"\u003e\u003cspan class=\"nx\"\u003efoo\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003c/code\u003e in TOML.\u003c/li\u003e\n\u003cli\u003eNow if a string has a quote character (\u003ccode\u003e\u0026quot;\u003c/code\u003e) in it, that value will\nauto-export as TOML multi-line string. I like the readability of\nthis more than that of backslash-escaped double-quotes.\u003c/li\u003e\n\u003cli\u003eNow the nested tables like \u003ccode class=\"code-inline language-toml\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003emenu\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;nested menu\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003c/code\u003e export with their parent table keys like \u003ccode class=\"code-inline language-toml\"\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003emenu\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003c/code\u003e. As per the TOML spec, this is not required. But now\nthat \u003ccode\u003etomelr\u003c/code\u003e has added a generic support for any TOML table, this\nchange happens as a result of consistency 💯.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eIn summary, the changes in \u003ccode\u003eox-hugo\u003c/code\u003e TOML front-matter exports were\nmostly cosmetic, and if they were not cosmetic, they were consistency\nfixes.\u003c/p\u003e\n\n\u003ch2 id=\"what-s-next\"\u003eWhat\u0026rsquo;s next?\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#what-s-next\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdl\u003e\n\u003cdt\u003etomelr\u003c/dt\u003e\n\u003cdd\u003eThe library is pretty much feature complete ✨ as\nmany of the examples from \u003ca href=\"https://toml.io/en/v1.0.0\"\u003eTOML v1.0.0 spec\u003c/a\u003e have been added to its\ntest suite, and .. it is supporting all the \u003ccode\u003eox-hugo\u003c/code\u003e use cases.\n\u003cp\u003eThe library though has \u003ca href=\"https://github.com/kaushalmodi/tomelr#limitations\"\u003eone limitation\u003c/a\u003e that I\u0026rsquo;d like to resolve at\nsome point \u0026mdash; Right now, we require the Lisp data to first list all\nthe scalar keys and then list the TOML tables and arrays of\ntables. But at the moment, I don\u0026rsquo;t know how to fix that, and also\n\u003ccode\u003eox-hugo\u003c/code\u003e is not affected by that (because it already populates the\nfront-matter alist in the correct order). So fixing this is not\nurgent, but of course, if someone can help me out with that, I\u0026rsquo;d\nwelcome that! 🙏.\u003c/p\u003e\n\u003c/dd\u003e\n\u003cdt\u003eox-hugo\u003c/dt\u003e\n\u003cdd\u003eGiven that \u003ccode\u003etomelr\u003c/code\u003e allows robustly exporting any Lisp\ndata expression to TOML, I do not see any value in continuing with\nYAML generation support using the old custom code.\n\u003cp\u003e📢 In near future, I plan to get rid of the\n\u003ccode\u003eorg-hugo-front-matter-format\u003c/code\u003e customization variable from \u003ccode\u003eox-hugo\u003c/code\u003e\n\u0026mdash; thus deprecating YAML export support\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThis change should not functionally affect the YAML front-matter\nfans out there because the front-matter that \u003ccode\u003eox-hugo\u003c/code\u003e is exporting\nis mainly for Hugo\u0026rsquo;s consumption. The only scenario where I see that\nthis change can be breaking is if the user is using YAML format\n\u003cem\u003eextra front-matter\u003c/em\u003e blocks. If so, unfortunately, they will need to\nconvert those to TOML manually.\n\u003c/small\u003e\u003c/span\u003e\nand sticking with using just TOML for the front-matter.\u003c/p\u003e\n\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ch3 id=\"unblocking-some-future-ox-hugo-improvements\"\u003eUnblocking some future \u003ccode\u003eox-hugo\u003c/code\u003e improvements\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#unblocking-some-future-ox-hugo-improvements\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eThis decision will open up the doors to add more features to \u003ccode\u003eox-hugo\u003c/code\u003e\nlike:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eExporting Org \u003ccode\u003e:LOGBOOK:\u003c/code\u003e drawers to TOML front-matter (\u003ca href=\"https://github.com/kaushalmodi/ox-hugo/pull/504\"\u003eox-hugo #\n\u003cstrong\u003e504\u003c/strong\u003e\u003c/a\u003e)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eExporting Org Special Blocks to user-configurable front-matter\n(\u003ca href=\"https://github.com/kaushalmodi/ox-hugo/pull/627\"\u003eox-hugo # \u003cstrong\u003e627\u003c/strong\u003e\u003c/a\u003e)\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eSupporting more complex data in Lisp form using\n\u003ccode\u003e:EXPORT_HUGO_CUSTOM_FRONT_MATTER:\u003c/code\u003e which could translate to nested\nTOML tables or arrays of TOML tables.\u003c/p\u003e\n\u003cp\u003eFinally, there won\u0026rsquo;t be a need to use the \u003ca href=\"https://ox-hugo.scripter.co/doc/custom-front-matter/#front-matter-extra\"\u003e\u0026ldquo;Extra front-matter\u0026rdquo;\u003c/a\u003e\nworkaround. For example, it would be possible to represent the data\nin that first example on that page as \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"nb\"\u003e:foo\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003e:bar\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"nb\"\u003e:zoo\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;abc\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003e:bar\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"nb\"\u003e:zoo\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;def\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003c/code\u003e in the\n\u003ccode\u003e:EXPORT_HUGO_CUSTOM_FRONT_MATTER:\u003c/code\u003e property.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n","text":" Table of Contents My flow for creating this library Adapting the library to fit ox-hugo Changes in ox-hugo tests What\u0026rsquo;s next? Unblocking some future ox-hugo improvements In my previous post Defining tomelr, I started toying with the idea of creating a library that would help convert any Lisp expression to a TOML config, and I share my vision (specification) of what this library would look like.\nI wasn\u0026rsquo;t even sure if I would be able to make the tomelr library feature-complete at least to the extent of what ox-hugo was already doing! But to my surprise, the library development snowballed to a completion much earlier than I thought, and additionally it helped fix some inconsistencies that the older TOML generation code had in ox-hugo.\nIn this post, I start by (i) giving a broad overview of how the development of tomelr happened, then (ii) briefly describe how it got integrated into ox-hugo, and finally (iii) how the use of this library will unblock the path to addition of some cool features to ox-hugo.\nMy flow for creating this library\u0026nbsp;# Write the spec for the library. List all the formats of Lisp data I would expect it to process. List the corresponding TOML data I would expect it to generate. Ensure that I am not inventing my own lisp syntax by confirming that the expected TOML output matches the JSON generated from that same lisp form (using the Emacs built-in json.el library). That helped me write the tests first! \u0026ndash; Test Driven Development (TDD). I started with writing tests for TOML booleans and then implementing that (because that was the simplest and easiest). Of course, I used ert for this! ert helped me quickly create small modular tests Here\u0026rsquo;s the ert test for booleans as an example. and efficiently iterate through modifications in the library code until I got the tests to pass. Once that got working, I set up a continuous integration system using GitHub Actions (GHA). I used GHA because I host my library on GitHub. Also I already have a tried and tested setup that I could get up and going in a matter of few seconds. In general, this concept would apply to any Continuous Integration system. The CI setup step should come early in the development of any project so that incremental feature additions don\u0026rsquo;t start breaking previously added features 😃. The library development just snowballed after this point .. added support for integers, floats, regular strings, multi-line strings, arrays, TOML tables, arrays of TOML tables. By this time, the library was about 80% finished. Then came the difficult part .. stabilizing the library to support all the varieties of Lisp data I can think of. I must have put in double the time spent so far to finish the remaining 20% of the planned features for this library 👉 tomelr test suite Once I had the test suite complete and passing, it was time to do some code cleanup: Remove duplicate code and break them off into smaller helper functions. See if the function defined in this library is already defined somewhere else (in this case, I was able to use json-plist-p directly from json.el). Proof read the code. Proof read the docstrings and run M-x checkdoc to fix their formatting. Ensure that the code compiles without any warnings. Remove unnecessary customization options and case statements from the library (while continuously ensuring that the ert tests still pass). Adapting the library to fit ox-hugo\u0026nbsp;# After polishing the library by its stand-alone testing, I decided to use it with ox-hugo and see how the test suite in that repo fared.\nOf course I saw that a lot of tests failed now 😁.\nThe main issue was that tomelr was constructing multi-line strings such that the spaces translated exactly from Lisp data to TOML. So (tomelr-encode \u0026#39;((foo . \u0026#34;line1\\nline2\u0026#34;))) would generate:\nfoo = \u0026#34;\u0026#34;\u0026#34; line1 line2\u0026#34;\u0026#34;\u0026#34; Code Snippet 1: Multi-line string with same white-space as in original data.. but not that \"pretty\" whereas ox-hugo expected the same TOML to look like:\nfoo = \u0026#34;\u0026#34;\u0026#34; line1 line2 \u0026#34;\u0026#34;\u0026#34; Code Snippet 2: Pretty multi-line string, but with extra white-space I had intentionally decided for ox-hugo to have this latter format for multi-line strings because (i) it made it more readable with the triple-quotes out of the way on their own lines, (ii) the indented lines prevented the multi-line string from getting mixed with surrounding TOML parameters, and most importantly (iii) these strings were processed by the Hugo Markdown parser, and so it wasn\u0026rsquo;t sensitive to horizontal spaces.\nAnd so the tomelr-indent-multi-line-strings feature was born (commit) which optionally made tomelr export multi-line strings as expected by ox-hugo 😎.\nChanges in ox-hugo tests\u0026nbsp;# Once I had finalized the integration of tomelr into ox-hugo, I had only about 30 tests change out of roughly 400 tests. These changes were welcome as they fixed all the inconsistencies in the older TOML generation code in ox-hugo. If interested, you can see this commit for the diff and details, but here\u0026rsquo;s the gist:\nNow nil value of a key in Lisp consistently implies that the key should not be exported to TOML. So \u0026#39;((foo . nil)) will result in foo not getting exported to TOML, whether that\u0026rsquo;s a top-level key or a key in a nested TOML map or array. If you need to set a key to a boolean false, use \u0026quot;false\u0026quot; or any value from tomelr-false. Earlier empty string value as in \u0026#39;((foo . \u0026#34;\u0026#34;)) behaved like the current nil implementation. That\u0026rsquo;s not the case any more. Now that empty string will export as foo = \u0026#34;\u0026#34; in TOML. Now if a string has a quote character (\u0026quot;) in it, that value will auto-export as TOML multi-line string. I like the readability of this more than that of backslash-escaped double-quotes. Now the nested tables like [menu.\u0026#34;nested menu\u0026#34;] export with their parent table keys like [menu]. As per the TOML spec, this is not required. But now that tomelr has added a generic support for any TOML table, this change happens as a result of consistency 💯. In summary, the changes in ox-hugo TOML front-matter exports were mostly cosmetic, and if they were not cosmetic, they were consistency fixes.\nWhat\u0026rsquo;s next?\u0026nbsp;# tomelr The library is pretty much feature complete ✨ as many of the examples from TOML v1.0.0 spec have been added to its test suite, and .. it is supporting all the ox-hugo use cases. The library though has one limitation that I\u0026rsquo;d like to resolve at some point \u0026mdash; Right now, we require the Lisp data to first list all the scalar keys and then list the TOML tables and arrays of tables. But at the moment, I don\u0026rsquo;t know how to fix that, and also ox-hugo is not affected by that (because it already populates the front-matter alist in the correct order). So fixing this is not urgent, but of course, if someone can help me out with that, I\u0026rsquo;d welcome that! 🙏.\nox-hugo Given that tomelr allows robustly exporting any Lisp data expression to TOML, I do not see any value in continuing with YAML generation support using the old custom code. 📢 In near future, I plan to get rid of the org-hugo-front-matter-format customization variable from ox-hugo \u0026mdash; thus deprecating YAML export support This change should not functionally affect the YAML front-matter fans out there because the front-matter that ox-hugo is exporting is mainly for Hugo\u0026rsquo;s consumption. The only scenario where I see that this change can be breaking is if the user is using YAML format extra front-matter blocks. If so, unfortunately, they will need to convert those to TOML manually. and sticking with using just TOML for the front-matter.\nUnblocking some future ox-hugo improvements\u0026nbsp;# This decision will open up the doors to add more features to ox-hugo like:\nExporting Org :LOGBOOK: drawers to TOML front-matter (ox-hugo # 504)\nExporting Org Special Blocks to user-configurable front-matter (ox-hugo # 627)\nSupporting more complex data in Lisp form using :EXPORT_HUGO_CUSTOM_FRONT_MATTER: which could translate to nested TOML tables or arrays of TOML tables.\nFinally, there won\u0026rsquo;t be a need to use the \u0026ldquo;Extra front-matter\u0026rdquo; workaround. For example, it would be possible to represent the data in that first example on that page as :foo ((:bar 1 :zoo \u0026#34;abc\u0026#34;) (:bar 2 :zoo \u0026#34;def\u0026#34;)) in the :EXPORT_HUGO_CUSTOM_FRONT_MATTER: property.\n"},"name":"Presenting tomelr!","published":"2022-05-04T01:03:00-04:00","summary":"In this post, I introduce a little library I created for ox-hugo to have a robust mechanism for generating TOML from any Lisp expression.","type":"entry","url":"https://scripter.co/presenting-tomelr/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#using-json-encode-as-reference\"\u003eUsing \u003ccode\u003ejson-encode\u003c/code\u003e as reference\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#mapping-scalar-data-to-toml\"\u003eMapping scalar data to TOML\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#about-false\"\u003eAbout \u003ccode\u003e:false\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#mapping-lists-to-toml\"\u003eMapping lists to TOML\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#mapping-lists-of-lists-to-toml\"\u003eMapping lists of lists to TOML\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#mapping-other-object-types\"\u003eMapping other object types\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#closing\"\u003eClosing\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003e\u003ccode\u003eox-hugo\u003c/code\u003e has some custom code that generates \u003ca href=\"https://toml.io/en/\"\u003eTOML\u003c/a\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nI ❤️ TOML. As the makers of this config format put it.. \u0026ldquo;it\u0026rsquo;s a\nformat \u003cem\u003efor humans\u003c/em\u003e\u0026rdquo;! \u0026mdash; No need to deal with indentations, weird\nsyntax for multi-line strings, no prohibition on adding comments to\nthe config, or dealing with careful placement of commas and braces.\n\u003c/small\u003e\u003c/span\u003e\nfor \u003ca href=\"https://gohugo.io/\"\u003eHugo\u003c/a\u003e front-matter, based on the Org keywords and other meta-data\nthat the user sets in their Org file. But this TOML generation code is\nnot generic enough for any TOML object type.\u003c/p\u003e\n\u003cp\u003eAs I am \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/pull/504#issuecomment-1093592230\"\u003ewriting up a definition\u003c/a\u003e on how to export \u003ccode\u003e:LOGBOOK:\u003c/code\u003e \u003ca href=\"https://orgmode.org/manual/Drawers.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Drawers\u0026quot;)\"\u003edrawers\u003c/a\u003e,\nI felt it\u0026rsquo;s a good time to polish the whole \u003cstrong\u003eLisp data → TOML\u003c/strong\u003e\nconversion code, and may be package that into a separate library.\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e        It\u0026rsquo;s kind of an ambitious project \u0026mdash; I am calling it \u003ca href=\"https://github.com/kaushalmodi/tomelr\"\u003etom​\u003cstrong\u003eel\u003c/strong\u003e​r\u003c/a\u003e ✨\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eIt\u0026rsquo;s a big undertaking to create a generic library for this kind of\ndata format conversion. But even before I start coding or think if I\ncan complete this project, I need to \u003cem\u003espec\u003c/em\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nI am not sure if it\u0026rsquo;s a widely used verb, but \u003cem\u003eto spec\u003c/em\u003e means \u003cem\u003eto\nwrite a specification for something\u003c/em\u003e.\n\u003c/small\u003e\u003c/span\u003e\nit. I need to understand early-on how the \u003cem\u003eS-exp\u003c/em\u003e (Symbolic lisp\nexpression) would needed to look for each kind of generated TOML\nobject \u0026mdash; scalars, lists, lists of lists, maps, lists of maps, etc.\u003c/p\u003e\n\n\u003ch2 id=\"using-json-encode-as-reference\"\u003eUsing \u003ccode\u003ejson-encode\u003c/code\u003e as reference\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-json-encode-as-reference\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThe aim of the \u003ccode\u003etomelr\u003c/code\u003e library is to take some \u003ccode\u003e(lisp data)\u003c/code\u003e and\nconvert that TOML. But I did not want to invent my own \u003cem\u003elisp data\nconvention\u003c/em\u003e for this! So I decided to stick with the lisp expression\nconventions understood by the \u003ccode\u003ejson-encode\u003c/code\u003e function from the Emacs\ncore library \u003ccode\u003ejson.el\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eCredit for the \u003ccode\u003ejson.el\u003c/code\u003e idea goes to \u003ca href=\"https://twitter.com/pdcawley/status/1519007598896369664\"\u003ethis tweet\u003c/a\u003e by \u003ca href=\"https://twitter.com/pdcawley\"\u003ePiers Cawley\u003c/a\u003e:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI\u0026rsquo;d suggest that\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nBy \u0026ldquo;that\u0026rdquo;, he\u0026rsquo;s referring to adding support for exporting front-matter\nto JSON in \u003ccode\u003eox-hugo\u003c/code\u003e.\n\u003c/small\u003e\u003c/span\u003e\n, since emacs has built in JSON support these days, you\ndon\u0026rsquo;t really have to worry about the commas and braces, just build the\ns-exp you want and export, but it\u0026rsquo;s you that\u0026rsquo;s writing the code and\nI\u0026rsquo;m just delighted that it exists.\u003c/p\u003e\n\u003cp\u003eThank you for your efforts.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eI am not sold on adding support of yet another front-matter format to\n\u003ccode\u003eox-hugo\u003c/code\u003e. I might not use \u003ccode\u003ejson.el\u003c/code\u003e for that, but it definitely\nhelped me a lot with coming up with this library\u0026rsquo;s spec 😆.\u003c/p\u003e\n\n\u003ch2 id=\"mapping-scalar-data-to-toml\"\u003eMapping scalar data to TOML\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#mapping-scalar-data-to-toml\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eFiguring out the Lisp representation for scalar (plain key-value\npairs) TOML objects was easy. \u003ccode\u003ejson.el\u003c/code\u003e helped figure out how to deal\nwith \u003cem\u003enil\u003c/em\u003e and \u003cem\u003efalse\u003c/em\u003e values.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"table--mapping-scalar-lisp-to-toml\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"table-caption\"\u003e\n  \u003cspan class=\"table-number\"\u003e\u003ca href=\"#table--mapping-scalar-lisp-to-toml\"\u003eTable 1\u003c/a\u003e:\u003c/span\u003e\n  Mapping of \u003ci\u003escalar\u003c/i\u003e Lisp data to TOML\n\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eLisp S-exp\u003c/th\u003e\n\u003cth\u003eTOML\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((int_key . 123))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003eint_key = 123\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((float_key . 1.23))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003efloat_key = 1.23\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((date_key . 2022-04-27))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003edate_key = 2022-04-27\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((bool_key . t))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ebool_key = true\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((any_key . nil))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003e(key removed in TOML)\u003c/em\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((bool_key . :false))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003ebool_key = false\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003ch3 id=\"about-false\"\u003eAbout \u003ccode\u003e:false\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#about-false\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003e\u003ccode\u003ejson.el\u003c/code\u003e defines a variable \u003ccode\u003ejson-false\u003c/code\u003e that\u0026rsquo;s set to the value\n\u003ccode\u003e:json-false\u003c/code\u003e. This is because in JSON, the \u003cem\u003enull\u003c/em\u003e value is different\nfrom the boolean \u003ccode\u003efalse\u003c/code\u003e value.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003enil\u003c/em\u003e in Lisp → \u003cem\u003enull\u003c/em\u003e in JSON\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e:json-false\u003c/code\u003e in Lisp → \u003ccode\u003efalse\u003c/code\u003e in JSON\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eInspired by that decision of \u003ccode\u003ejson.el\u003c/code\u003e, I am thinking of using\n\u003ccode\u003e:false\u003c/code\u003e as the special value that will set the equivalent TOML value\nto boolean \u003ccode\u003efalse\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eTOML does not define a \u003cem\u003enull\u003c/em\u003e value, but if the Lisp value is \u003cem\u003enil\u003c/em\u003e,\nthat key will simply not be translated to TOML.\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"mapping-lists-to-toml\"\u003eMapping lists to TOML\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#mapping-lists-to-toml\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eMapping lists was simple.. because in Lisp, a list value of course\nlooks like \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003efoo\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e \u003cspan class=\"mi\"\u003e5\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\u003c/code\u003e\n😃.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"table--mapping-list-lisp-to-toml\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"table-caption\"\u003e\n  \u003cspan class=\"table-number\"\u003e\u003ca href=\"#table--mapping-list-lisp-to-toml\"\u003eTable 2\u003c/a\u003e:\u003c/span\u003e\n  Mapping of \u003ci\u003elist\u003c/i\u003e Lisp data to TOML\n\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eLisp S-exp\u003c/th\u003e\n\u003cth\u003eTOML\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((list_key1 . (1 2 3)))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003elist_key1 = [1, 2, 3]\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((list_key2 . (\u0026quot;a\u0026quot; \u0026quot;b\u0026quot; \u0026quot;c\u0026quot;)))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003elist_key2 = [\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;c\u0026quot;]\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003ch2 id=\"mapping-lists-of-lists-to-toml\"\u003eMapping lists of lists to TOML\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#mapping-lists-of-lists-to-toml\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"table--mapping-list-of-list-lisp-to-toml\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"table-caption\"\u003e\n  \u003cspan class=\"table-number\"\u003e\u003ca href=\"#table--mapping-list-of-list-lisp-to-toml\"\u003eTable 3\u003c/a\u003e:\u003c/span\u003e\n  Mapping of \u003ci\u003elist of list\u003c/i\u003e Lisp data to TOML\n\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eLisp S-exp\u003c/th\u003e\n\u003cth\u003eTOML\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e'((lol_key . [(1 2) (3 4)]))\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003elol_key = [ [1, 2], [3, 4] ]\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eI was going to use \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003elol_key\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\u003c/code\u003e as the reference Lisp expression for \u003ccode class=\"code-inline language-toml\"\u003e\u003cspan class=\"nx\"\u003elol_key\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003c/code\u003e. But I found out that\n\u003ccode\u003ejson-encode\u003c/code\u003e throws an error if you pass it that expression! I don\u0026rsquo;t\nunderstand the reason for that error, and so I have \u003ca href=\"https://lists.gnu.org/r/help-gnu-emacs/2022-04/msg00240.html\"\u003easked for help\u003c/a\u003e on\nthe \u003cem\u003ehelp-gnu-emacs\u003c/em\u003e mailing list.\u003c/p\u003e\n\u003cp\u003eBut while that question gets resolved, I wanted to move forward with\nthe spec definition. After some trial-and-error and\nreverse-engineering \u003ccode\u003ejson.el\u003c/code\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nI knew how I wanted TOML to look. So I used \u003ca href=\"https://toolkit.site/format.html\"\u003ean online JSON/TOML\nconverter\u003c/a\u003e to convert that TOML snippet to JSON, and then used\n\u003ccode\u003ejson-read\u003c/code\u003e to convert JSON to Lisp expression.\n\u003c/small\u003e\u003c/span\u003e\n, I learned that \u003cem\u003elist of list\u003c/em\u003e data needs to be represented using a \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Vector-Type.html\" title=\"Emacs Lisp: (info \u0026quot;(elisp) Vector Type\u0026quot;)\"\u003eVector type\u003c/a\u003e, and so \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003elol_key\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"p\"\u003e[(\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e \u003cspan class=\"mi\"\u003e4\u003c/span\u003e\u003cspan class=\"p\"\u003e)]))\u003c/span\u003e\u003c/code\u003e would be the correct expression \u0026ndash; \u003cem\u003eNotice the use\nof square brackets instead of parentheses for the outer vector\u003c/em\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"mapping-other-object-types\"\u003eMapping other object types\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#mapping-other-object-types\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eOnce I figured out how to map the above data types, mapping Lisp data\nto \u003cem\u003eTOML Tables\u003c/em\u003e aka \u003cem\u003edictionaries\u003c/em\u003e and \u003cem\u003earrays of Tables\u003c/em\u003e was a\nbreeze\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nOf course, the \u003cem\u003ebreeze\u003c/em\u003e is referring to the ease of writing the spec\nfor these 😆. Implementation-wise, the \u003cem\u003etables\u003c/em\u003e, \u003cem\u003earrays of\ntables\u003c/em\u003e, and the especially \u003cstrong\u003enested\u003c/strong\u003e variants of those are going to be\nthe most challenging.\n\u003c/small\u003e\u003c/span\u003e\n.\u003c/p\u003e\n\n\u003ch2 id=\"closing\"\u003eClosing\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#closing\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIt was fun coming up with an initial draft of the specification for\nthis library. My next steps would be to gradually add TOML generator\nfunctions (as I find time) to this library, along with \u003ca href=\"/quick-intro-to-emacs-lisp-regression-testing/\"\u003eERT tests\u003c/a\u003e!\nEventually, I will remove the existing TOML generation code from\n\u003ccode\u003eox-hugo\u003c/code\u003e and depend on this library.\u003c/p\u003e\n\u003cp\u003eGetting back to \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/pull/504#issuecomment-1093592230\"\u003emy plan\u003c/a\u003e for exporting \u003ccode\u003e:LOGBOOK:\u003c/code\u003e drawers in\n\u003ccode\u003eox-hugo\u003c/code\u003e, based on this spec, I will need to construct this date in\nEmacs-Lisp:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--org-logbook-lisp\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg_logbook\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"p\"\u003e(((\u003c/span\u003e\u003cspan class=\"nv\"\u003etimestamp\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"nv\"\u003e2022-04-08T14:53:00-04:00\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enote\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;This note addition prompt shows up on typing the `C-c C-z` binding.\\nSee [org#Drawers](https://www.gnu.org/software/emacs/manual/html_mono/org.html#Drawers).\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003etimestamp\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"nv\"\u003e2018-09-06T11:45:00-04:00\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enote\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Another note **bold** _italics_.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003etimestamp\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"nv\"\u003e2018-09-06T11:37:00-04:00\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enote\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;A note `mono`.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--org-logbook-lisp\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Example data from a \u003ccode\u003e:LOGBOOK:\u003c/code\u003e drawer in Lisp format\n\u003c/div\u003e\n\u003cp\u003e.. will translate to this in TOML:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--org-logbook-toml\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-toml\" data-lang=\"toml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[[\u003c/span\u003e\u003cspan class=\"nx\"\u003eorg_logbook\u003c/span\u003e\u003cspan class=\"p\"\u003e]]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003etimestamp\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"ld\"\u003e2022-04-08T14:53:00-04:00\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003enote\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u0026#34;This note addition prompt shows up on typing the `C-c C-z` binding.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s2\"\u003eSee [org#Drawers](https://www.gnu.org/software/emacs/manual/html_mono/org.html#Drawers).\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[[\u003c/span\u003e\u003cspan class=\"nx\"\u003eorg_logbook\u003c/span\u003e\u003cspan class=\"p\"\u003e]]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003etimestamp\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"ld\"\u003e2018-09-06T11:45:00-04:00\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003enote\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u0026#34;Another note **bold** _italics_.\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e[[\u003c/span\u003e\u003cspan class=\"nx\"\u003eorg_logbook\u003c/span\u003e\u003cspan class=\"p\"\u003e]]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003etimestamp\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"ld\"\u003e2018-09-06T11:37:00-04:00\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nx\"\u003enote\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u0026#34;A note `mono`.\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--org-logbook-toml\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Same example data from the \u003ccode\u003e:LOGBOOK:\u003c/code\u003e drawer translated to TOML format\n\u003c/div\u003e\n\u003chr\u003e\n\u003cp\u003eCheck out the below link where I have documented the equivalent\nexpressions between Lisp, TOML and JSON for all the object types.\u003c/p\u003e\n\u003cp\u003e👉 \u003ca href=\"https://github.com/kaushalmodi/tomelr/blob/main/README.org\"\u003etom​\u003cstrong\u003eel\u003c/strong\u003e​r Specification\u003c/a\u003e\u003c/p\u003e\n","text":" Table of Contents Using json-encode as reference Mapping scalar data to TOML About :false Mapping lists to TOML Mapping lists of lists to TOML Mapping other object types Closing ox-hugo has some custom code that generates TOML I ❤️ TOML. As the makers of this config format put it.. \u0026ldquo;it\u0026rsquo;s a format for humans\u0026rdquo;! \u0026mdash; No need to deal with indentations, weird syntax for multi-line strings, no prohibition on adding comments to the config, or dealing with careful placement of commas and braces. for Hugo front-matter, based on the Org keywords and other meta-data that the user sets in their Org file. But this TOML generation code is not generic enough for any TOML object type.\nAs I am writing up a definition on how to export :LOGBOOK: drawers, I felt it\u0026rsquo;s a good time to polish the whole Lisp data → TOML conversion code, and may be package that into a separate library.\nIt\u0026rsquo;s kind of an ambitious project \u0026mdash; I am calling it tom​el​r ✨\nIt\u0026rsquo;s a big undertaking to create a generic library for this kind of data format conversion. But even before I start coding or think if I can complete this project, I need to spec I am not sure if it\u0026rsquo;s a widely used verb, but to spec means to write a specification for something. it. I need to understand early-on how the S-exp (Symbolic lisp expression) would needed to look for each kind of generated TOML object \u0026mdash; scalars, lists, lists of lists, maps, lists of maps, etc.\nUsing json-encode as reference\u0026nbsp;# The aim of the tomelr library is to take some (lisp data) and convert that TOML. But I did not want to invent my own lisp data convention for this! So I decided to stick with the lisp expression conventions understood by the json-encode function from the Emacs core library json.el.\nCredit for the json.el idea goes to this tweet by Piers Cawley:\nI\u0026rsquo;d suggest that By \u0026ldquo;that\u0026rdquo;, he\u0026rsquo;s referring to adding support for exporting front-matter to JSON in ox-hugo. , since emacs has built in JSON support these days, you don\u0026rsquo;t really have to worry about the commas and braces, just build the s-exp you want and export, but it\u0026rsquo;s you that\u0026rsquo;s writing the code and I\u0026rsquo;m just delighted that it exists.\nThank you for your efforts.\nI am not sold on adding support of yet another front-matter format to ox-hugo. I might not use json.el for that, but it definitely helped me a lot with coming up with this library\u0026rsquo;s spec 😆.\nMapping scalar data to TOML\u0026nbsp;# Figuring out the Lisp representation for scalar (plain key-value pairs) TOML objects was easy. json.el helped figure out how to deal with nil and false values.\nTable 1: Mapping of scalar Lisp data to TOML Lisp S-exp TOML '((int_key . 123)) int_key = 123 '((float_key . 1.23)) float_key = 1.23 '((date_key . 2022-04-27)) date_key = 2022-04-27 '((bool_key . t)) bool_key = true '((any_key . nil)) (key removed in TOML) '((bool_key . :false)) bool_key = false About :false\u0026nbsp;# json.el defines a variable json-false that\u0026rsquo;s set to the value :json-false. This is because in JSON, the null value is different from the boolean false value.\nnil in Lisp → null in JSON :json-false in Lisp → false in JSON Inspired by that decision of json.el, I am thinking of using :false as the special value that will set the equivalent TOML value to boolean false.\nTOML does not define a null value, but if the Lisp value is nil, that key will simply not be translated to TOML.\nMapping lists to TOML\u0026nbsp;# Mapping lists was simple.. because in Lisp, a list value of course looks like \u0026#39;((foo . (1 2 3 4 5))) 😃.\nTable 2: Mapping of list Lisp data to TOML Lisp S-exp TOML '((list_key1 . (1 2 3))) list_key1 = [1, 2, 3] '((list_key2 . (\u0026quot;a\u0026quot; \u0026quot;b\u0026quot; \u0026quot;c\u0026quot;))) list_key2 = [\u0026quot;a\u0026quot;, \u0026quot;b\u0026quot;, \u0026quot;c\u0026quot;] Mapping lists of lists to TOML\u0026nbsp;# Table 3: Mapping of list of list Lisp data to TOML Lisp S-exp TOML '((lol_key . [(1 2) (3 4)])) lol_key = [ [1, 2], [3, 4] ] I was going to use \u0026#39;((lol_key . ((1 2) (3 4)))) as the reference Lisp expression for lol_key = [ [1, 2], [3, 4] ]. But I found out that json-encode throws an error if you pass it that expression! I don\u0026rsquo;t understand the reason for that error, and so I have asked for help on the help-gnu-emacs mailing list.\nBut while that question gets resolved, I wanted to move forward with the spec definition. After some trial-and-error and reverse-engineering json.el I knew how I wanted TOML to look. So I used an online JSON/TOML converter to convert that TOML snippet to JSON, and then used json-read to convert JSON to Lisp expression. , I learned that list of list data needs to be represented using a Vector type, and so \u0026#39;((lol_key . [(1 2) (3 4)])) would be the correct expression \u0026ndash; Notice the use of square brackets instead of parentheses for the outer vector.\nMapping other object types\u0026nbsp;# Once I figured out how to map the above data types, mapping Lisp data to TOML Tables aka dictionaries and arrays of Tables was a breeze Of course, the breeze is referring to the ease of writing the spec for these 😆. Implementation-wise, the tables, arrays of tables, and the especially nested variants of those are going to be the most challenging. .\nClosing\u0026nbsp;# It was fun coming up with an initial draft of the specification for this library. My next steps would be to gradually add TOML generator functions (as I find time) to this library, along with ERT tests! Eventually, I will remove the existing TOML generation code from ox-hugo and depend on this library.\nGetting back to my plan for exporting :LOGBOOK: drawers in ox-hugo, based on this spec, I will need to construct this date in Emacs-Lisp:\n(org_logbook . (((timestamp . 2022-04-08T14:53:00-04:00) (note . \u0026#34;This note addition prompt shows up on typing the `C-c C-z` binding.\\nSee [org#Drawers](https://www.gnu.org/software/emacs/manual/html_mono/org.html#Drawers).\u0026#34;)) ((timestamp . 2018-09-06T11:45:00-04:00) (note . \u0026#34;Another note **bold** _italics_.\u0026#34;)) ((timestamp . 2018-09-06T11:37:00-04:00) (note . \u0026#34;A note `mono`.\u0026#34;)))) Code Snippet 1: Example data from a :LOGBOOK: drawer in Lisp format .. will translate to this in TOML:\n[[org_logbook]] timestamp = 2022-04-08T14:53:00-04:00 note = \u0026#34;\u0026#34;\u0026#34;This note addition prompt shows up on typing the `C-c C-z` binding. See [org#Drawers](https://www.gnu.org/software/emacs/manual/html_mono/org.html#Drawers).\u0026#34;\u0026#34;\u0026#34; [[org_logbook]] timestamp = 2018-09-06T11:45:00-04:00 note = \u0026#34;\u0026#34;\u0026#34;Another note **bold** _italics_.\u0026#34;\u0026#34;\u0026#34; [[org_logbook]] timestamp = 2018-09-06T11:37:00-04:00 note = \u0026#34;\u0026#34;\u0026#34;A note `mono`.\u0026#34;\u0026#34;\u0026#34; Code Snippet 2: Same example data from the :LOGBOOK: drawer translated to TOML format Check out the below link where I have documented the equivalent expressions between Lisp, TOML and JSON for all the object types.\n👉 tom​el​r Specification\n"},"name":"Defining tomelr – A library for converting Lisp expressions to TOML","published":"2022-04-28T00:08:00-04:00","summary":"Creating a specification for an Emacs-Lisp library to convert Lisp\ndata expressions into easy-to-read TOML strings.","type":"entry","url":"https://scripter.co/defining-tomelr/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#flexed-biceps-1-exported-links-now-point-to-separate-pages-in-the-manual\"\u003e💪1: Exported links now point to separate pages in the manual\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#flexed-biceps-2-export-org-manual-links-to-orgmode-dot-org-urls\"\u003e💪 2: Export Org manual links to \u003ccode\u003eorgmode.org\u003c/code\u003e URLs\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#flexed-biceps-3-link-hover-text-shows-the-elisp-code-for-accessing-the-info-node\"\u003e💪 3: Link hover text shows the \u003cem\u003eelisp\u003c/em\u003e code for accessing the Info node\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#final-code-in-ox-hugo-that-exports-the-info-links\"\u003eFinal code in \u003ccode\u003eox-hugo\u003c/code\u003e that exports the \u003ccode\u003einfo:\u003c/code\u003e links\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eAfter writing my \u003ca href=\"/linking-and-exporting-org-info-links/\"\u003eprevious post\u003c/a\u003e, I had shared its link on the Org mode\nmailing list\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nFor folks who don\u0026rsquo;t know, you can email the Org mode mailing list\n(\u003ccode\u003eemacs-orgmode@gnu.org\u003c/code\u003e) about pretty much anything Org mode related:\nany help you want, a bug you want to report, a patch you want to\nsubmit, or just share your positive or negative experiences with Org\nmode or thank someone for their awesome work.\n\u003c/small\u003e\u003c/span\u003e\n\u003ca href=\"https://lists.gnu.org/r/emacs-orgmode/2022-04/msg00162.html\"\u003ehere\u003c/a\u003e, and received some helpful feedback from Max Nikulin.\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e        \u003cem\u003eThank you Max!\u003c/em\u003e\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eThis post is a response to his feedback, and it also describes a few\nimprovements made for \u003ccode\u003einfo:\u003c/code\u003e link exports in \u003ccode\u003eox-hugo\u003c/code\u003e based on that.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eThe commits for this \u003ccode\u003einfo:\u003c/code\u003e link export improvements can be found in\n\u003ccode\u003eox-hugo\u003c/code\u003e \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/pull/620\"\u003ePR # 620\u003c/a\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"flexed-biceps-1-exported-links-now-point-to-separate-pages-in-the-manual\"\u003e💪\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e 1: Exported links now point to separate pages in the manual\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#flexed-biceps-1-exported-links-now-point-to-separate-pages-in-the-manual\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdl\u003e\n\u003cdt\u003eFeedback\u003c/dt\u003e\n\u003cdd\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  For \u0026lt;info:emacs#Browse-URL\u0026gt; export to html produces the following link:\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      https://www.gnu.org/software/emacs/manual/html_mono/emacs.html#Browse_002dURL\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  I think, a better variant is\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      https://www.gnu.org/software/emacs/manual/html_node/emacs/Browse_002dURL.html\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  even though for the Org manual I often prefer single-page HTML version.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\u003cp\u003eI really liked this suggestion!\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEarlier, the Info node references were exporting to an \u003cspan class=\"underline\"\u003eanchor\u003c/span\u003e on a\nhuge single-page HTML manual e.g. \u003ccode\u003eemacs.html#Browse_002dURL\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eAfter implementing this fix, the exported link points to a \u003cspan class=\"underline\"\u003eseparate\nHTML page\u003c/span\u003e for that node e.g. \u003ccode\u003eemacs/Browse_002dURL.html\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eNow, \u003ccode class=\"code-inline language-org\"\u003e[[\u003cspan class=\"na\"\u003einfo:emacs#Screen\u003c/span\u003e]]\u003c/code\u003e exports and renders to\n\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/emacs/Screen.html\" title=\"Emacs Lisp: (info \u0026quot;(emacs) Screen\u0026quot;)\"\u003eEmacs Info: Screen\u003c/a\u003e, and a Top level node like \u003ccode class=\"code-inline language-org\"\u003e[[\u003cspan class=\"na\"\u003einfo:emacs#Top\u003c/span\u003e]]\u003c/code\u003e exports and renders to \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/emacs/index.html\" title=\"Emacs Lisp: (info \u0026quot;(emacs) Top\u0026quot;)\"\u003eEmacs Info\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eFor consistency, all \u003ccode\u003einfo:\u003c/code\u003e links will now be exported to URLs\npointing to the separate node HTML pages, even for Org manual links.\u003c/p\u003e\n\n\u003ch2 id=\"flexed-biceps-2-export-org-manual-links-to-orgmode-dot-org-urls\"\u003e💪 2: Export Org manual links to \u003ccode\u003eorgmode.org\u003c/code\u003e URLs\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#flexed-biceps-2-export-org-manual-links-to-orgmode-dot-org-urls\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdl\u003e\n\u003cdt\u003eFeedback\u003c/dt\u003e\n\u003cdd\u003e(About an example \u003ccode\u003einfo:\u003c/code\u003e link pointing to Org manual:\n\u003ccode class=\"code-inline language-org\"\u003e[[\u003cspan class=\"na\"\u003einfo:org#Top\u003c/span\u003e]]\u003c/code\u003e)\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eAnd the link target ideally should be https://orgmode.org/manual/index.html\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\u003cp\u003eThis was another great suggestion!\u003c/p\u003e\n\u003cp\u003eBy default, the Org manual \u003ccode\u003einfo:\u003c/code\u003e links will export to URLs pointing\nto the \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/org/index.html\"\u003eOrg manual shipped with Emacs\u003c/a\u003e. That manual will be associated\nwith the Org mode version that shipped with the last stable version of\nEmacs. \u003cem\u003eSo depending on how long it has been since the last Emacs\nrelease, you could be referring to quite an older version of the Org\nmanual.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eIf you install Org from GNU Elpa, you can get an\n\u003cmark\u003eupdate of the latest stable Org version every week\u003c/mark\u003e !\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThere\u0026rsquo;s a related post on \u003ca href=\"/org-contribution-flowchart/\"\u003eOrg mode\u0026rsquo;s Release Flow\u003c/a\u003e that might interest\nyou.\n\u003c/small\u003e\u003c/span\u003e\nAnd the manual hosted on \u003ca href=\"https://orgmode.org\"\u003ehttps://orgmode.org\u003c/a\u003e gets updated every week\nas well. I would like to always refer to the latest Org manual with\nthe latest fixes and documentation improvements, and so I agree with\nMax\u0026rsquo;s suggestion above.\u003c/p\u003e\n\u003cp\u003eNow \u003ccode class=\"code-inline language-org\"\u003e[[\u003cspan class=\"na\"\u003einfo:org#Top\u003c/span\u003e]]\u003c/code\u003e exports and renders as\n\u003ca href=\"https://orgmode.org/manual/index.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Top\u0026quot;)\"\u003eOrg Info\u003c/a\u003e and the Org manual nodes like \u003ccode class=\"code-inline language-org\"\u003e[[\u003cspan class=\"na\"\u003einfo:org#Working with Source Code\u003c/span\u003e]]\u003c/code\u003e also export as a link to a\npage in that manual: \u003cspan class=\"org-target\" id=\"org-target--improving-info-link-exports--last-link\"\u003e\u003c/span\u003e\n\u003ca href=\"https://orgmode.org/manual/Working-with-Source-Code.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Working with Source Code\u0026quot;)\"\u003eOrg Info: Working with Source Code\u003c/a\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"flexed-biceps-3-link-hover-text-shows-the-elisp-code-for-accessing-the-info-node\"\u003e💪 3: Link hover text shows the \u003cem\u003eelisp\u003c/em\u003e code for accessing the Info node\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#flexed-biceps-3-link-hover-text-shows-the-elisp-code-for-accessing-the-info-node\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdl\u003e\n\u003cdt\u003eFeedback\u003c/dt\u003e\n\u003cdd\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  I would prefer\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      info \u0026#34;(org) Top\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  to\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      Org Info: Top\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  since the former may be pasted to M-x : or to shell command prompt.\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\u003cp\u003eI wanted the link descriptions in the exported markdown to be more\n\u0026ldquo;English\u0026rdquo; and understandable to people not familiar with the Emacs\nInfo interface. So I decided to keep this \u003cem\u003emostly\u003c/em\u003e unchanged ..\u003c/p\u003e\n\u003cp\u003eI did not change the link \u003cem\u003edescription\u003c/em\u003e, but I did add a new HTML\n\u003cstrong\u003etitle\u003c/strong\u003e attribute to the link. This attribute contains the Emacs Lisp\ncode needed to access the Info manual from Emacs. The user will see\nthe text from this attribute when they hover the mouse over the\nlinks. If you haven\u0026rsquo;t already discovered this feature, try hovering\nthe mouse over \u003ca href=\"#org-target--improving-info-link-exports--last-link\"\u003ethat last link above\u003c/a\u003e and you should see this 😃 :\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--info-link-title-attribute\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/improving-ox-hugo-exported-org-info-links/info-link-title-attribute.png\" alt=\"Figure 1: Hovering the mouse over the exported info: links will show the Emacs Lisp code for accessing the same node from Emacs\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eHovering the mouse over the exported \u003ccode\u003einfo:\u003c/code\u003e links will show the Emacs Lisp code for accessing the same node from Emacs\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eOf course, the user will still not be able to copy that text and paste\nin Emacs. But it will still provide them enough hint on how to access\nInfo nodes in Emacs.\u003c/p\u003e\n\n\u003ch2 id=\"final-code-in-ox-hugo-that-exports-the-info-links\"\u003eFinal code in \u003ccode\u003eox-hugo\u003c/code\u003e that exports the \u003ccode\u003einfo:\u003c/code\u003e links\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#final-code-in-ox-hugo-that-exports-the-info-links\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eHere\u0026rsquo;s the version of the \u003ccode\u003eorg-hugo--org-info-export\u003c/code\u003e function that\nhandles the exports of \u003ccode\u003einfo:\u003c/code\u003e links as of today (\u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2022-04-15 Fri\u0026gt;\u003c/span\u003e\u003c/span\u003e):\u003c/p\u003e\n\u003cdetails title=\"Click to expand\"\u003e\n\u003csummary\u003e\u003ccode\u003eorg-hugo--org-info-export\u003c/code\u003e function from \u003ccode\u003eox-hugo\u003c/code\u003e\u003c/summary\u003e\n\u003cdiv class=\"details\"\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--org-hugo--org-info-export\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e888\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e889\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e890\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e891\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e892\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e893\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e894\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e895\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e896\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e897\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e898\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e899\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e900\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e901\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e902\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e903\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e904\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e905\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e906\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e907\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e908\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e909\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e910\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e911\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e912\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-hugo--org-info-export\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003epath\u003c/span\u003e \u003cspan class=\"nv\"\u003edesc\u003c/span\u003e \u003cspan class=\"nf\"\u003eformat\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Add support for exporting [[info:..]] links for \u003c/span\u003e\u003cspan class=\"ss\"\u003e`hugo\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e format.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eparts\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esplit-string\u003c/span\u003e \u003cspan class=\"nv\"\u003epath\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;#\\\\|::\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emanual\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecar\u003c/span\u003e \u003cspan class=\"nv\"\u003eparts\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enode\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enth\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"nv\"\u003eparts\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Top\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003etitle\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Emacs Lisp: (info \\\\\\\u0026#34;(%s) %s\\\\\\\u0026#34;)\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual\u003c/span\u003e \u003cspan class=\"nv\"\u003enode\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edesc\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"nv\"\u003edesc\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring=\u003c/span\u003e \u003cspan class=\"nv\"\u003enode\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Top\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s Info\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecapitalize\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s Info: %s\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecapitalize\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003enode\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"c1\"\u003e;; `link\u0026#39; below is mostly derived from the code in\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"c1\"\u003e;; `org-info-map-html-url\u0026#39;.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003elink\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003emember\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-info-emacs-documents\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003emanual-url\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edowncase\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;org\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                            \u003cspan class=\"s\"\u003e\u0026#34;https://orgmode.org/manual\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;https://www.gnu.org/software/emacs/manual/html_node/%s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enode-url\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring=\u003c/span\u003e \u003cspan class=\"nv\"\u003enode\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Top\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                          \u003cspan class=\"s\"\u003e\u0026#34;index.html\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-info--expand-node-name\u003c/span\u003e \u003cspan class=\"nv\"\u003enode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;.html\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s/%s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual-url\u003c/span\u003e \u003cspan class=\"nv\"\u003enode-url\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003ecdr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eassoc\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-info-other-documents\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"nv\"\u003emanual\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;.html\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emember\u003c/span\u003e \u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emd\u003c/span\u003e \u003cspan class=\"nv\"\u003ehugo\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;[%s](%s \\\u0026#34;%s\\\u0026#34;)\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003edesc\u003c/span\u003e \u003cspan class=\"nv\"\u003elink\u003c/span\u003e \u003cspan class=\"nv\"\u003etitle\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--org-hugo--org-info-export\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  \u003ccode\u003eox-hugo\u003c/code\u003e's version of \u003ccode\u003eorg-info-export\u003c/code\u003e (\u003ccode\u003eol-info.el\u003c/code\u003e) function\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/details\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/kaushalmodi/ox-hugo/blob/5b3a0d8a7da49f602785aa20486bbbbeb35ebb36/ox-hugo.el#L888-L912\"\u003eLink to code in the repo\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eI will leave it as an exercise for the reader to map the lines in\nabove code snippet to the features described in this post\n🍀.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eJust for giggles, I am using 💪 as a replacement\nfor \u0026ldquo;Improvement\u0026rdquo;\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","text":" Table of Contents 💪1: Exported links now point to separate pages in the manual 💪 2: Export Org manual links to orgmode.org URLs 💪 3: Link hover text shows the elisp code for accessing the Info node Final code in ox-hugo that exports the info: links After writing my previous post, I had shared its link on the Org mode mailing list For folks who don\u0026rsquo;t know, you can email the Org mode mailing list (emacs-orgmode@gnu.org) about pretty much anything Org mode related: any help you want, a bug you want to report, a patch you want to submit, or just share your positive or negative experiences with Org mode or thank someone for their awesome work. here, and received some helpful feedback from Max Nikulin.\nThank you Max!\nThis post is a response to his feedback, and it also describes a few improvements made for info: link exports in ox-hugo based on that.\nThe commits for this info: link export improvements can be found in ox-hugo PR # 620.\n💪1 1: Exported links now point to separate pages in the manual\u0026nbsp;# Feedback For \u0026lt;info:emacs#Browse-URL\u0026gt; export to html produces the following link: https://www.gnu.org/software/emacs/manual/html_mono/emacs.html#Browse_002dURL I think, a better variant is https://www.gnu.org/software/emacs/manual/html_node/emacs/Browse_002dURL.html even though for the Org manual I often prefer single-page HTML version. I really liked this suggestion!\nEarlier, the Info node references were exporting to an anchor on a huge single-page HTML manual e.g. emacs.html#Browse_002dURL After implementing this fix, the exported link points to a separate HTML page for that node e.g. emacs/Browse_002dURL.html. Now, [[info:emacs#Screen]] exports and renders to Emacs Info: Screen, and a Top level node like [[info:emacs#Top]] exports and renders to Emacs Info.\nFor consistency, all info: links will now be exported to URLs pointing to the separate node HTML pages, even for Org manual links.\n💪 2: Export Org manual links to orgmode.org URLs\u0026nbsp;# Feedback (About an example info: link pointing to Org manual: [[info:org#Top]]) And the link target ideally should be https://orgmode.org/manual/index.html This was another great suggestion!\nBy default, the Org manual info: links will export to URLs pointing to the Org manual shipped with Emacs. That manual will be associated with the Org mode version that shipped with the last stable version of Emacs. So depending on how long it has been since the last Emacs release, you could be referring to quite an older version of the Org manual.\nIf you install Org from GNU Elpa, you can get an update of the latest stable Org version every week ! There\u0026rsquo;s a related post on Org mode\u0026rsquo;s Release Flow that might interest you. And the manual hosted on https://orgmode.org gets updated every week as well. I would like to always refer to the latest Org manual with the latest fixes and documentation improvements, and so I agree with Max\u0026rsquo;s suggestion above.\nNow [[info:org#Top]] exports and renders as Org Info and the Org manual nodes like [[info:org#Working with Source Code]] also export as a link to a page in that manual: Org Info: Working with Source Code.\n💪 3: Link hover text shows the elisp code for accessing the Info node\u0026nbsp;# Feedback I would prefer info \u0026#34;(org) Top\u0026#34; to Org Info: Top since the former may be pasted to M-x : or to shell command prompt. I wanted the link descriptions in the exported markdown to be more \u0026ldquo;English\u0026rdquo; and understandable to people not familiar with the Emacs Info interface. So I decided to keep this mostly unchanged ..\nI did not change the link description, but I did add a new HTML title attribute to the link. This attribute contains the Emacs Lisp code needed to access the Info manual from Emacs. The user will see the text from this attribute when they hover the mouse over the links. If you haven\u0026rsquo;t already discovered this feature, try hovering the mouse over that last link above and you should see this 😃 :\nFigure 1: Hovering the mouse over the exported info: links will show the Emacs Lisp code for accessing the same node from Emacs Of course, the user will still not be able to copy that text and paste in Emacs. But it will still provide them enough hint on how to access Info nodes in Emacs.\nFinal code in ox-hugo that exports the info: links\u0026nbsp;# Here\u0026rsquo;s the version of the org-hugo--org-info-export function that handles the exports of info: links as of today (\u0026lt;2022-04-15 Fri\u0026gt;):\norg-hugo--org-info-export function from ox-hugo 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 (defun org-hugo--org-info-export (path desc format) \u0026#34;Add support for exporting [[info:..]] links for `hugo\u0026#39; format.\u0026#34; (let* ((parts (split-string path \u0026#34;#\\\\|::\u0026#34;)) (manual (car parts)) (node (or (nth 1 parts) \u0026#34;Top\u0026#34;)) (title (format \u0026#34;Emacs Lisp: (info \\\\\\\u0026#34;(%s) %s\\\\\\\u0026#34;)\u0026#34; manual node)) (desc (or desc (if (string= node \u0026#34;Top\u0026#34;) (format \u0026#34;%s Info\u0026#34; (capitalize manual)) (format \u0026#34;%s Info: %s\u0026#34; (capitalize manual) node)))) ;; `link\u0026#39; below is mostly derived from the code in ;; `org-info-map-html-url\u0026#39;. (link (cond ((member manual org-info-emacs-documents) (let ((manual-url (if (string= (downcase manual) \u0026#34;org\u0026#34;) \u0026#34;https://orgmode.org/manual\u0026#34; (format \u0026#34;https://www.gnu.org/software/emacs/manual/html_node/%s\u0026#34; manual))) (node-url (if (string= node \u0026#34;Top\u0026#34;) \u0026#34;index.html\u0026#34; (concat (org-info--expand-node-name node) \u0026#34;.html\u0026#34;)))) (format \u0026#34;%s/%s\u0026#34; manual-url node-url))) ((cdr (assoc manual org-info-other-documents))) (t (concat manual \u0026#34;.html\u0026#34;))))) (when (member format \u0026#39;(md hugo)) (format \u0026#34;[%s](%s \\\u0026#34;%s\\\u0026#34;)\u0026#34; desc link title)))) Code Snippet 1: ox-hugo's version of org-info-export (ol-info.el) function Link to code in the repo\nI will leave it as an exercise for the reader to map the lines in above code snippet to the features described in this post 🍀.\nJust for giggles, I am using 💪 as a replacement for \u0026ldquo;Improvement\u0026rdquo;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"  Improving ox-hugo exported Org \"info:\" links\n  ","published":"2022-04-15T22:50:00-04:00","summary":"In my previous post, I talked about how info: Org link export support got added to ox-hugo. This post is about making those exported links a tiny :pinching_hand: bit better.","type":"entry","url":"https://scripter.co/improving-ox-hugo-exported-org-info-links/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#storing-links-to-info-nodes\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Storing links to Info nodes\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#inserting-stored-links\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Inserting stored links\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#org-link-library-for-info-links--ol-info\"\u003eOrg Link library for \u003ccode\u003einfo:\u003c/code\u003e links (\u003ccode\u003eol-info\u003c/code\u003e)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#exporting-info-dot-dot-links-using-ox-hugo\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e Exporting \u003ccode\u003e[[info:..]]\u003c/code\u003e links using \u003ccode\u003eox-hugo\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#summary\"\u003eSummary\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eThis post was inspired out of the exercise of support \u003ccode\u003einfo:\u003c/code\u003e Org link\nexports in \u003ccode\u003eox-hugo\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThere are 3 steps:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eStoring a link from any buffer that you want to later document in\nan Org file.\u003c/li\u003e\n\u003cli\u003eInserting that link that you stored earlier.\u003c/li\u003e\n\u003cli\u003eExporting the Org document.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eI am focusing on the \u003ccode\u003einfo:\u003c/code\u003e Org links in this post, they these steps\napply to \u003ca href=\"https://orgmode.org/manual/External-Links.html\" title=\"Emacs Lisp: (info \u0026quot;(org) External Links\u0026quot;)\"\u003eany\u003c/a\u003e Org link type.\u003c/p\u003e\n\n\u003ch2 id=\"storing-links-to-info-nodes\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Storing links to Info nodes\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#storing-links-to-info-nodes\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIf you follow the instructions on \u003ca href=\"https://orgmode.org/manual/Activation.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Activation\u0026quot;)\"\u003eOrg Info: Activation\u003c/a\u003e, you\u0026rsquo;ll see that\nit is recommended\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThis post assumes that you have actually set this binding. If you\nhaven\u0026rsquo;t yet, go do it already! \u003ccode\u003e(global-set-key (kbd \u0026quot;C-c l\u0026quot;) #'org-store-link)\u003c/code\u003e\n\u003c/small\u003e\u003c/span\u003e\nto bind the \u003ccode\u003eorg-store-link\u003c/code\u003e command to \u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003el\u003c/kbd\u003e in your Emacs\n\u003cem\u003eglobal map\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eorg-store-link\u003c/code\u003e stores an Org Mode compatible link based on the\ncontext i.e. type of buffer where the point is.  Org supports a\nvariety of links as documented in \u003ca href=\"https://orgmode.org/manual/External-Links.html\" title=\"Emacs Lisp: (info \u0026quot;(org) External Links\u0026quot;)\"\u003eOrg Info: External Links\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eIf the point is in an ∗Info∗ buffer and \u003ccode\u003eorg-store-link\u003c/code\u003e is called, it\nstores an \u003ccode\u003einfo:\u003c/code\u003e type link that will lead back to the same node where\nthe point was.\u003c/p\u003e\n\u003cp\u003eLet\u0026rsquo;s say you have opened the Org Info manual and you hit \u003ckbd\u003eC-c\u003c/kbd\u003e\n\u003ckbd\u003el\u003c/kbd\u003e. You should then see this in the \u003cem\u003eEcho Area\u003c/em\u003e:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eStored: org#Top\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe link to Org manual\u0026rsquo;s \u003cem\u003eTop\u003c/em\u003e node is \u003cem\u003estored\u003c/em\u003e by that command, but\nonly temporarily \u0026ndash; it isn\u0026rsquo;t yet saved anywhere.\u003c/p\u003e\n\n\u003ch2 id=\"inserting-stored-links\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Inserting stored links\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#inserting-stored-links\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThese stored links can now be saved in an Org file. To do that,\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eVisit an Org file or a buffer and call \u003ckbd\u003eM-x\u003c/kbd\u003e \u003ckbd\u003eorg-insert-link\u003c/kbd\u003e\n(bound to \u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003eC-l\u003c/kbd\u003e by default) and follow the prompts.\u003c/li\u003e\n\u003cli\u003eAn immediate \u003ckbd\u003eRET\u003c/kbd\u003e after the prompt will select the last stored link\nto be inserted.\u003c/li\u003e\n\u003cli\u003eThe second prompt allows you to change the link description, and\nthen the link will be inserted.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIf I insert the \u003ccode\u003eorg#Top\u003c/code\u003e Info link that I stored earlier over here,\nand accept the default link description, it will paste as\n\u003ccode class=\"code-inline language-org\"\u003e[[\u003cspan class=\"na\"\u003einfo:org#Top\u003c/span\u003e][\u003cspan class=\"nt\"\u003eorg#Top\u003c/span\u003e]]\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eBut .. how did the link description become \u0026ldquo;\u003ccode\u003eorg#Top\u003c/code\u003e\u0026rdquo; by default?\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e        The \u003ca href=\"https://git.savannah.gnu.org/cgit/emacs/org-mode.git/tree/lisp/ol-info.el\"\u003e\u003ccode\u003eol-info.el\u003c/code\u003e\u003c/a\u003e library did that.\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch3 id=\"org-link-library-for-info-links--ol-info\"\u003eOrg Link library for \u003ccode\u003einfo:\u003c/code\u003e links (\u003ccode\u003eol-info\u003c/code\u003e)\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#org-link-library-for-info-links--ol-info\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eThe default description for \u003ccode\u003einfo:\u003c/code\u003e type links was set at the time of\nstoring those links, with the help of the \u003ca href=\"https://git.savannah.gnu.org/cgit/emacs/org-mode.git/tree/lisp/ol-info.el?id=f6813dbea9ef0c6be19bf68b4d9227ceb64c9449#n49\"\u003e\u003ccode\u003eorg-info-store-link\u003c/code\u003e\u003c/a\u003e\nfunction in \u003ccode\u003eol-info.el\u003c/code\u003e.  That same description is then suggested at\nthe time of inserting that link.\u003c/p\u003e\n\u003cp\u003eThis library defines these \u0026ldquo;actions\u0026rdquo; for \u003ccode\u003e[[info:..]]\u003c/code\u003e type of links:\u003c/p\u003e\n\u003cdl\u003e\n\u003cdt\u003e:store\u003c/dt\u003e\n\u003cdd\u003eDefines when (in which buffer, major mode, etc.) the\n\u0026ldquo;store\u0026rdquo; operation should store to an \u003ccode\u003einfo:\u003c/code\u003e type link, and what\nmetadata should be stored. Some of the stored metadata are: the Info\nfile name, node name, link string and description string.\u003c/dd\u003e\n\u003cdt\u003e:follow\u003c/dt\u003e\n\u003cdd\u003eDefines what action to perform when \u003ccode\u003eorg-open-at-point\u003c/code\u003e\n(\u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003eC-o\u003c/kbd\u003e) is called with point on the link.  Hitting this\nbinding with point on an \u003ccode\u003einfo:\u003c/code\u003e link will open or switch to that\n∗Info∗ node.\u003c/dd\u003e\n\u003cdt\u003e:export\u003c/dt\u003e\n\u003cdd\u003eDefines how the link should be exported for various\nbackends. \u003cem\u003e\u003ccode\u003eol-info\u003c/code\u003e defines how the \u003ccode\u003einfo:\u003c/code\u003e links should be\nexported, but only for \u003ccode\u003ehtml\u003c/code\u003e and \u003ccode\u003etexinfo\u003c/code\u003e backends.\u003c/em\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ch2 id=\"exporting-info-dot-dot-links-using-ox-hugo\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e Exporting \u003ccode\u003e[[info:..]]\u003c/code\u003e links using \u003ccode\u003eox-hugo\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#exporting-info-dot-dot-links-using-ox-hugo\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ccode\u003eol-info.el\u003c/code\u003e defines the \u003ccode\u003e:export\u003c/code\u003e \u0026ldquo;action\u0026rdquo; such that \u003ccode\u003einfo:\u003c/code\u003e links\nget converted to hyperlinks pointing to online Org manual pages, when\nexporting using \u003ccode\u003eox-html\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eBut it didn\u0026rsquo;t do the same when exporting using \u003ccode\u003eox-hugo\u003c/code\u003e. That feature\ngot added recently in \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/blob/d3d4c57444f03898e78d2ae11e97fdb94a4655c5/ox-hugo.el#L888-L899\"\u003ethis \u003ccode\u003eox-hugo\u003c/code\u003e commit\u003c/a\u003e. Now \u003ccode\u003eox-hugo\u003c/code\u003e exports\n\u003ccode class=\"code-inline language-org\"\u003e[[\u003cspan class=\"na\"\u003einfo:org#Top\u003c/span\u003e][\u003cspan class=\"nt\"\u003eorg#Top\u003c/span\u003e]]\u003c/code\u003e to \u003ca href=\"https://orgmode.org/manual/index.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Top\u0026quot;)\"\u003eorg#Top\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eI didn\u0026rsquo;t like the \u003ccode\u003e#\u003c/code\u003e that \u003ccode\u003eorg-info-store-link\u003c/code\u003e added to the default\ndescription (notice that previous link). So I added a tiny little\nfeature to the \u003ccode\u003einfo:\u003c/code\u003e export behavior 😁 \u0026mdash; If you leave the\n\u003ccode\u003einfo:\u003c/code\u003e link descriptions empty when inserting the links, \u003ccode\u003eox-hugo\u003c/code\u003e\ninjects its own \u0026ldquo;auto description\u0026rdquo; which are better (in my\nopinion).\u003c/p\u003e\n\u003cp\u003eNow when that same Info link is inserted description-less as\n\u003ccode class=\"code-inline language-org\"\u003e[[\u003cspan class=\"na\"\u003einfo:org#Top\u003c/span\u003e]]\u003c/code\u003e, it renders to: \u003ca href=\"https://orgmode.org/manual/index.html\" title=\"Emacs Lisp: (info \u0026quot;(org) Top\u0026quot;)\"\u003eOrg Info\u003c/a\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"summary\"\u003eSummary\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#summary\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003eStore link (from anywhere in Emacs) : \u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003el\u003c/kbd\u003e\u003c/li\u003e\n\u003cli\u003eInsert link (in an Org file) : \u003ckbd\u003eC-c\u003c/kbd\u003e \u003ckbd\u003eC-l\u003c/kbd\u003e\u003c/li\u003e\n\u003cli\u003eExport the Org file as usual.\u003c/li\u003e\n\u003c/ol\u003e\n","text":" Table of Contents 1 Storing links to Info nodes 2 Inserting stored links Org Link library for info: links (ol-info) 3 Exporting [[info:..]] links using ox-hugo Summary This post was inspired out of the exercise of support info: Org link exports in ox-hugo.\nThere are 3 steps:\nStoring a link from any buffer that you want to later document in an Org file. Inserting that link that you stored earlier. Exporting the Org document. I am focusing on the info: Org links in this post, they these steps apply to any Org link type.\n1 Storing links to Info nodes\u0026nbsp;# If you follow the instructions on Org Info: Activation, you\u0026rsquo;ll see that it is recommended This post assumes that you have actually set this binding. If you haven\u0026rsquo;t yet, go do it already! (global-set-key (kbd \u0026quot;C-c l\u0026quot;) #'org-store-link) to bind the org-store-link command to C-c l in your Emacs global map.\norg-store-link stores an Org Mode compatible link based on the context i.e. type of buffer where the point is. Org supports a variety of links as documented in Org Info: External Links.\nIf the point is in an ∗Info∗ buffer and org-store-link is called, it stores an info: type link that will lead back to the same node where the point was.\nLet\u0026rsquo;s say you have opened the Org Info manual and you hit C-c l. You should then see this in the Echo Area:\nStored: org#Top\nThe link to Org manual\u0026rsquo;s Top node is stored by that command, but only temporarily \u0026ndash; it isn\u0026rsquo;t yet saved anywhere.\n2 Inserting stored links\u0026nbsp;# These stored links can now be saved in an Org file. To do that,\nVisit an Org file or a buffer and call M-x org-insert-link (bound to C-c C-l by default) and follow the prompts. An immediate RET after the prompt will select the last stored link to be inserted. The second prompt allows you to change the link description, and then the link will be inserted. If I insert the org#Top Info link that I stored earlier over here, and accept the default link description, it will paste as [[info:org#Top][org#Top]].\nBut .. how did the link description become \u0026ldquo;org#Top\u0026rdquo; by default?\nThe ol-info.el library did that.\nOrg Link library for info: links (ol-info)\u0026nbsp;# The default description for info: type links was set at the time of storing those links, with the help of the org-info-store-link function in ol-info.el. That same description is then suggested at the time of inserting that link.\nThis library defines these \u0026ldquo;actions\u0026rdquo; for [[info:..]] type of links:\n:store Defines when (in which buffer, major mode, etc.) the \u0026ldquo;store\u0026rdquo; operation should store to an info: type link, and what metadata should be stored. Some of the stored metadata are: the Info file name, node name, link string and description string. :follow Defines what action to perform when org-open-at-point (C-c C-o) is called with point on the link. Hitting this binding with point on an info: link will open or switch to that ∗Info∗ node. :export Defines how the link should be exported for various backends. ol-info defines how the info: links should be exported, but only for html and texinfo backends. 3 Exporting [[info:..]] links using ox-hugo\u0026nbsp;# ol-info.el defines the :export \u0026ldquo;action\u0026rdquo; such that info: links get converted to hyperlinks pointing to online Org manual pages, when exporting using ox-html.\nBut it didn\u0026rsquo;t do the same when exporting using ox-hugo. That feature got added recently in this ox-hugo commit. Now ox-hugo exports [[info:org#Top][org#Top]] to org#Top.\nI didn\u0026rsquo;t like the # that org-info-store-link added to the default description (notice that previous link). So I added a tiny little feature to the info: export behavior 😁 \u0026mdash; If you leave the info: link descriptions empty when inserting the links, ox-hugo injects its own \u0026ldquo;auto description\u0026rdquo; which are better (in my opinion).\nNow when that same Info link is inserted description-less as [[info:org#Top]], it renders to: Org Info.\nSummary\u0026nbsp;# Store link (from anywhere in Emacs) : C-c l Insert link (in an Org file) : C-c C-l Export the Org file as usual. "},"name":"  Linking and Exporting Org \"info:\" links\n  ","published":"2022-04-12T13:51:00-04:00","summary":"Journey of Org links from copying (storing) them, inserting them in Org documents and exporting them. The focus of this post is on the info: type Org links, but the same concept would apply to any Org link type.","type":"entry","url":"https://scripter.co/linking-and-exporting-org-info-links/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#emacs-25-curved-quotes-rendering-feature\"\u003eEmacs 25 \u0026ndash; Curved quotes rendering feature\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#preventing-curved-quotes-in-documentation-strings\"\u003ePreventing curved quotes in documentation strings\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#preventing-curved-quotes-in-messages\"\u003ePreventing curved quotes in messages\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#summary\"\u003eSummary\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eThis post is related to the curved quotes feature from Emacs 25\n(September 2016), but I got inspired to write this as I was reading\nthe NEWS file of the recently released Emacs 28.1 ✨ .. \u003ca href=\"https://git.savannah.gnu.org/cgit/emacs.git/tree/etc/NEWS?h=emacs-28\u0026amp;id=886339747b8d34fc09fd69a143cf548daf92dce6#n219\"\u003ethis\nspecific part related to the \u003ccode\u003eshortdoc\u003c/code\u003e library\u003c/a\u003e. Turns out that I had\nnever used \u003ccode\u003eshortdoc\u003c/code\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nIf you also haven\u0026rsquo;t used this library before, it\u0026rsquo;s basically a \u0026ldquo;cheat\nsheet generator\u0026rdquo; or an aggregator of related functions grouped\ntogether with code examples and their outputs \u0026ndash; for example,\nfunctions related to string manipulation, buffer operations, etc. It\nis like \u003ca href=\"https://tldr.sh/\"\u003ehttps://tldr.sh/\u003c/a\u003e but for Emacs Lisp functions.\n\u003c/small\u003e\u003c/span\u003e\n. So as I was reading through the help for various user-facing\n\u003ccode\u003eshortdoc\u003c/code\u003e functions, \u003ccode\u003eC-h f shortdoc-add-function\u003c/code\u003e led me to\nthis:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--elisp-curved-quotes--docstring-unexpected-curved-quotes\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"shortdoc-add-function-curved-quotes-at-wrong-place.png\"\u003e\n        \u003cimg src=\"https://scripter.co/straight-and-curved-quotes-in-emacs-lisp/shortdoc-add-function-curved-quotes-at-wrong-place.png\" alt=\"Figure 1: Notice the curved closing single quotations in the Emacs Lisp example in that doc string\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eNotice the curved closing single quotations in the Emacs Lisp example in that doc string\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eWe don\u0026rsquo;t have curved quotes in Emacs Lisp syntax 🧐\n.. So I look up the \u003ca href=\"https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/emacs-lisp/shortdoc.el?h=emacs-28\u0026amp;id=98abf01fd681931f8870569ff559b547579d7cef#n1349\"\u003esource of \u003ccode\u003eshortdoc-add-function\u003c/code\u003e\u003c/a\u003e:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--elisp-curved-quotes--docstring-unescaped-single-quotes\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1349\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1350\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1351\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1352\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1353\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1354\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1355\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1356\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\"\u003e1357\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\"\u003e1358\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003eshortdoc-add-function\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003egroup\u003c/span\u003e \u003cspan class=\"nv\"\u003esection\u003c/span\u003e \u003cspan class=\"nv\"\u003eelem\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Add ELEM to shortdoc GROUP in SECTION.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eIf GROUP doesn\u0026#39;t exist, it will be created.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eIf SECTION doesn\u0026#39;t exist, it will be added.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eExample:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e  (shortdoc-add-function\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    \u0026#39;file \\\u0026#34;Predicates\\\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    \u0026#39;(file-locked-p :no-eval (file-locked-p \\\u0026#34;/tmp\\\u0026#34;)))\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--elisp-curved-quotes--docstring-unescaped-single-quotes\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Unescaped single quotes in Emacs Lisp documentation strings\n\u003c/div\u003e\n\u003cp\u003eThe documentation looks correct at first glance, but there\u0026rsquo;s a minor\nproblem. This post talks about how to fix that documentation and then\na bit more on how to deal with auto-conversion to curved quotes.\u003c/p\u003e\n\n\u003ch2 id=\"emacs-25-curved-quotes-rendering-feature\"\u003eEmacs 25 \u0026ndash; Curved quotes rendering feature\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#emacs-25-curved-quotes-rendering-feature\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eEmacs 25 had landed with one of my favorite new features \u0026mdash; the\nauto-rendering of grave accents (\u003ccode\u003e`\u003c/code\u003e) and straight quotes (\u003ccode\u003e'\u003c/code\u003e​) to\ncurved (or curly) quotes (\u003ccode\u003e‘\u003c/code\u003e, \u003ccode\u003e’\u003c/code\u003e). From \u003ca href=\"https://git.savannah.gnu.org/cgit/emacs.git/tree/etc/NEWS?h=emacs-25#n1284\"\u003eits \u003ccode\u003eNEWS\u003c/code\u003e file\u003c/a\u003e:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eNew variable \u0026rsquo;text-quoting-style\u0026rsquo; to control how Emacs translates\nquotes.  Set it to \u0026lsquo;curve\u0026rsquo; for curved single quotes, to \u0026lsquo;straight\u0026rsquo; for\nstraight apostrophes, and to \u0026lsquo;grave\u0026rsquo; for grave accent and apostrophe.\nThe default value nil acts like \u0026lsquo;curve\u0026rsquo; if curved single quotes are\ndisplayable, and like \u0026lsquo;grave\u0026rsquo; otherwise.  The new variable affects\ndisplay of diagnostics and help, but not of info.  As the variable is\nnot intended for casual use, it is not a user option.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eI like the rendering to curved quotes because it improves the\nreadability of documentation strings in the ∗Help∗ buffers (\u003ccode\u003eC-h v\u003c/code\u003e,\n\u003ccode\u003eC-h f\u003c/code\u003e, etc.), and they look great in ∗Messages∗ buffer. It helps\ndifferentiate between typographical use of quotes like in ‘Hello’\nversus the straight quotes used in Emacs Lisp syntax like\n\u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003efoo\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;some-symbol\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/code\u003e or the usage of\ngrave accents like \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003efoo\u003c/span\u003e \u003cspan class=\"o\"\u003e`\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eThis feature renders grave accents (\u003ccode\u003e`\u003c/code\u003e) to \u003ccode\u003e‘\u003c/code\u003e and straight quotes\n(\u003ccode\u003e'\u003c/code\u003e​) to \u003ccode\u003e’\u003c/code\u003e by default. But there would be times when you would want\nto literally print grave accents or straight quotes in ∗Help∗ and\n∗Messages∗ buffers.\u003c/p\u003e\n\n\u003ch2 id=\"preventing-curved-quotes-in-documentation-strings\"\u003ePreventing curved quotes in documentation strings\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#preventing-curved-quotes-in-documentation-strings\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIn documentation strings, some times you would want to show literal\nstraight quotes or grave accents, for instance, when showing some\nexample Emacs Lisp code snippets in there. \u003ca href=\"#figure--elisp-curved-quotes--docstring-unexpected-curved-quotes\"\u003eAbove image\u003c/a\u003e shows one of\nsuch examples.\u003c/p\u003e\n\u003cp\u003eMore than the visual inaccuracy of seeing curved quoted where straight\nquotes should be,\n\u003cmark\u003eif someone copies that code to try it out, it will\nnot work\u003c/mark\u003e !\u003c/p\u003e\n\u003cp\u003eThis should be fixed by escaping the \u003ccode\u003e'\u003c/code\u003e characters.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eEmacs Lisp uses a special escaping sequence in documentation strings:\n\u003ccode\u003e\\\\=\u003c/code\u003e.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eEscape \u003ccode\u003e`\u003c/code\u003e using \u003ccode\u003e\\\\=`\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eEscape \u003ccode\u003e'\u003c/code\u003e using \u003ccode\u003e\\\\='\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003cp\u003eBelow we see\n\u003ca href=\"#code-snippet--elisp-curved-quotes--docstring-unescaped-single-quotes\"\u003eCode Snippet 1\u003c/a\u003e after\nthis fix:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--elisp-curved-quotes--docstring-escaped-single-quotes\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1349\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1350\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1351\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1352\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1353\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1354\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1355\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e1356\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\"\u003e1357\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\"\u003e1358\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003eshortdoc-add-function\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003egroup\u003c/span\u003e \u003cspan class=\"nv\"\u003esection\u003c/span\u003e \u003cspan class=\"nv\"\u003eelem\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Add ELEM to shortdoc GROUP in SECTION.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eIf GROUP doesn\u0026#39;t exist, it will be created.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eIf SECTION doesn\u0026#39;t exist, it will be added.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eExample:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e  (shortdoc-add-function\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    \\\\=\u0026#39;file \\\u0026#34;Predicates\\\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    \\\\=\u0026#39;(file-locked-p :no-eval (file-locked-p \\\u0026#34;/tmp\\\u0026#34;)))\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--elisp-curved-quotes--docstring-escaped-single-quotes\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Correctly escaped single quotes in Emacs Lisp documentation strings\n\u003c/div\u003e\n\u003cp\u003e.. and now the straight quotes get rendered as straight quotes:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--elisp-curved-quotes--docstring-escaped-single-quotes\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"shortdoc-add-function-single-quotes-correctly-escaped.png\"\u003e\n        \u003cimg src=\"https://scripter.co/straight-and-curved-quotes-in-emacs-lisp/shortdoc-add-function-single-quotes-correctly-escaped.png\" alt=\"Figure 2: Correctly escaped single quotes in documentation strings\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 2: \u003c/span\u003eCorrectly escaped single quotes in documentation strings\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"preventing-curved-quotes-in-messages\"\u003ePreventing curved quotes in messages\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#preventing-curved-quotes-in-messages\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThe same auto-rendering of curved quotes happens in the messages that\nget printed to the ∗Messages∗ buffer and Echo Area as well. So the\nbelow behavior where \u003cstrong\u003e‘Hi’\u003c/strong\u003e gets printed is expected and nice:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--elisp-curved-quotes--message-lsqm-hi-rsqm\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"ss\"\u003e`Hi\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e      \u003cspan class=\"c1\"\u003e;=\u0026gt; \u0026#34;‘Hi’\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--elisp-curved-quotes--message-lsqm-hi-rsqm\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  \u003ccode\u003emessage\u003c/code\u003e auto-converting \u003ccode\u003e`Hi'\u003c/code\u003e to \u003ccode\u003e‘Hi’\u003c/code\u003e\n\u003c/div\u003e\n\u003cp\u003eBut if someone does below, the rendered \u003cstrong\u003e’Hi’\u003c/strong\u003e looks pretty odd:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--elisp-curved-quotes--message-rsqm-hi-rsqm\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#39;Hi\u0026#39;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e      \u003cspan class=\"c1\"\u003e;=\u0026gt; \u0026#34;’Hi’\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--elisp-curved-quotes--message-rsqm-hi-rsqm\"\u003eCode Snippet 4\u003c/a\u003e:\u003c/span\u003e\n  \u003ccode\u003emessage\u003c/code\u003e auto-converting \u003ccode\u003e'Hi'\u003c/code\u003e to \u003ccode\u003e’Hi’\u003c/code\u003e 😮\n\u003c/div\u003e\n\u003cp\u003eI had come across this surprise rendering in Emacs 25 and had raised\n\u003ca href=\"https://lists.gnu.org/archive/html/bug-gnu-emacs/2015-10/msg00234.html\"\u003ethis issue\u003c/a\u003e then. From Paul Eggert\u0026rsquo;s reply, I learned that to prevent\nthis curved quote conversion, we should make the \u003ccode\u003emessage\u003c/code\u003e function\nprint the string processed by the \u003ccode\u003eformat\u003c/code\u003e function and not the string\ndirectly. You could do this ..\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--elisp-curved-quotes--fix-message-format\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#39;Hi\u0026#39;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"c1\"\u003e;=\u0026gt;\u0026#34;\u0026#39;Hi\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--elisp-curved-quotes--fix-message-format\"\u003eCode Snippet 5\u003c/a\u003e:\u003c/span\u003e\n  Passing \u003ccode\u003eformat\u003c/code\u003e formatted string to \u003ccode\u003emessage\u003c/code\u003e\n\u003c/div\u003e\n\u003cp\u003eBut below will do the same thing and is much easier to type:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--elisp-curved-quotes--fix-message-format-indirect\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#39;Hi\u0026#39;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e;=\u0026gt; \u0026#34;\u0026#39;Hi\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"ss\"\u003e`Hi\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e;=\u0026gt; \u0026#34;`Hi\u0026#39;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--elisp-curved-quotes--fix-message-format-indirect\"\u003eCode Snippet 6\u003c/a\u003e:\u003c/span\u003e\n  Implicit passing of a string to \u003ccode\u003eformat\u003c/code\u003e for formatting, before getting printed by \u003ccode\u003emessage\u003c/code\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"summary\"\u003eSummary\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#summary\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"table--elisp-curved-quotes--summary\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"table-caption\"\u003e\n  \u003cspan class=\"table-number\"\u003e\u003ca href=\"#table--elisp-curved-quotes--summary\"\u003eTable 1\u003c/a\u003e:\u003c/span\u003e\n  Summary of techniques for enforcing straight quotes and grave accents in printed messages and documentation strings\n\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eDescription\u003c/th\u003e\n\u003cth\u003eSolution\u003c/th\u003e\n\u003cth\u003eOutcome\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eRender \u003ccode\u003e'\u003c/code\u003e in docstring\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003edoc string snippet\u003c/em\u003e: \u003ccode\u003e\u0026quot;foo \\\\='bar\u0026quot;\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003efoo 'bar\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eRender \u003ccode\u003e`\u003c/code\u003e in docstring\u003c/td\u003e\n\u003ctd\u003e\u003cem\u003edoc string snippet\u003c/em\u003e: \u003ccode\u003e\u0026quot;foo \\\\=`bar\u0026quot;\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003efoo `bar\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePrint \u003ccode\u003e'\u003c/code\u003e as \u003ccode\u003e'\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e(message \u0026quot;%s\u0026quot; \u0026quot;'foo\u0026quot;)\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e'foo\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003ePrint \u003ccode\u003e`\u003c/code\u003e as \u003ccode\u003e`\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e(message \u0026quot;%s\u0026quot; \u0026quot;`foo\u0026quot;)\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e\u003ccode\u003e`foo\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eBy the way, I submitted a patch for fixing the escaping of straight\nquotes in \u003ccode\u003eshortdoc-add-function\u003c/code\u003e documentation string\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nI planned to fix just this straight quote escaping issue, but then I\nalso ended up slightly improving the documentation of the \u003ccode\u003e(FUNC :eval EVAL)\u003c/code\u003e and other forms used for adding a function\u0026rsquo;s documentation to\n\u003ccode\u003eshortdoc\u003c/code\u003e.\n\u003c/small\u003e\u003c/span\u003e\nin \u003ca href=\"https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54782\"\u003edebbugs # 54782\u003c/a\u003e and now it\u0026rsquo;s \u003ca href=\"https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=cca47ae555bfddf87b4871988555738c335f8457\"\u003ein the emacs \u003cem\u003emaster\u003c/em\u003e branch\u003c/a\u003e! 🎉\u003c/p\u003e\n\n\u003ch2 id=\"references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdl\u003e\n\u003cdt\u003eFixing curved quotes conversion in documentation strings\u003c/dt\u003e\n\u003cdd\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Text-Quoting-Style.html\" title=\"Emacs Lisp: (info \u0026quot;(elisp) Text Quoting Style\u0026quot;)\"\u003eElisp Info: Text Quoting Style\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/dd\u003e\n\u003cdt\u003eFixing curved quotes conversion in printed messages\u003c/dt\u003e\n\u003cdd\u003e\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Formatting-Strings.html\" title=\"Emacs Lisp: (info \u0026quot;(elisp) Formatting Strings\u0026quot;)\"\u003eElisp Info: Formatting Strings\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/dd\u003e\n\u003c/dl\u003e\n","text":" Table of Contents Emacs 25 \u0026ndash; Curved quotes rendering feature Preventing curved quotes in documentation strings Preventing curved quotes in messages Summary References This post is related to the curved quotes feature from Emacs 25 (September 2016), but I got inspired to write this as I was reading the NEWS file of the recently released Emacs 28.1 ✨ .. this specific part related to the shortdoc library. Turns out that I had never used shortdoc If you also haven\u0026rsquo;t used this library before, it\u0026rsquo;s basically a \u0026ldquo;cheat sheet generator\u0026rdquo; or an aggregator of related functions grouped together with code examples and their outputs \u0026ndash; for example, functions related to string manipulation, buffer operations, etc. It is like https://tldr.sh/ but for Emacs Lisp functions. . So as I was reading through the help for various user-facing shortdoc functions, C-h f shortdoc-add-function led me to this:\nFigure 1: Notice the curved closing single quotations in the Emacs Lisp example in that doc string We don\u0026rsquo;t have curved quotes in Emacs Lisp syntax 🧐 .. So I look up the source of shortdoc-add-function:\n1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 (defun shortdoc-add-function (group section elem) \u0026#34;Add ELEM to shortdoc GROUP in SECTION. If GROUP doesn\u0026#39;t exist, it will be created. If SECTION doesn\u0026#39;t exist, it will be added. Example: (shortdoc-add-function \u0026#39;file \\\u0026#34;Predicates\\\u0026#34; \u0026#39;(file-locked-p :no-eval (file-locked-p \\\u0026#34;/tmp\\\u0026#34;)))\u0026#34; Code Snippet 1: Unescaped single quotes in Emacs Lisp documentation strings The documentation looks correct at first glance, but there\u0026rsquo;s a minor problem. This post talks about how to fix that documentation and then a bit more on how to deal with auto-conversion to curved quotes.\nEmacs 25 \u0026ndash; Curved quotes rendering feature\u0026nbsp;# Emacs 25 had landed with one of my favorite new features \u0026mdash; the auto-rendering of grave accents (`) and straight quotes ('​) to curved (or curly) quotes (‘, ’). From its NEWS file:\nNew variable \u0026rsquo;text-quoting-style\u0026rsquo; to control how Emacs translates quotes. Set it to \u0026lsquo;curve\u0026rsquo; for curved single quotes, to \u0026lsquo;straight\u0026rsquo; for straight apostrophes, and to \u0026lsquo;grave\u0026rsquo; for grave accent and apostrophe. The default value nil acts like \u0026lsquo;curve\u0026rsquo; if curved single quotes are displayable, and like \u0026lsquo;grave\u0026rsquo; otherwise. The new variable affects display of diagnostics and help, but not of info. As the variable is not intended for casual use, it is not a user option.\nI like the rendering to curved quotes because it improves the readability of documentation strings in the ∗Help∗ buffers (C-h v, C-h f, etc.), and they look great in ∗Messages∗ buffer. It helps differentiate between typographical use of quotes like in ‘Hello’ versus the straight quotes used in Emacs Lisp syntax like (setq foo \u0026#39;some-symbol) or the usage of grave accents like (setq foo `(,(+ 1 1))).\nThis feature renders grave accents (`) to ‘ and straight quotes ('​) to ’ by default. But there would be times when you would want to literally print grave accents or straight quotes in ∗Help∗ and ∗Messages∗ buffers.\nPreventing curved quotes in documentation strings\u0026nbsp;# In documentation strings, some times you would want to show literal straight quotes or grave accents, for instance, when showing some example Emacs Lisp code snippets in there. Above image shows one of such examples.\nMore than the visual inaccuracy of seeing curved quoted where straight quotes should be, if someone copies that code to try it out, it will not work !\nThis should be fixed by escaping the ' characters.\nEmacs Lisp uses a special escaping sequence in documentation strings: \\\\=.\nEscape ` using \\\\=`. Escape ' using \\\\='. Below we see Code Snippet 1 after this fix:\n1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 (defun shortdoc-add-function (group section elem) \u0026#34;Add ELEM to shortdoc GROUP in SECTION. If GROUP doesn\u0026#39;t exist, it will be created. If SECTION doesn\u0026#39;t exist, it will be added. Example: (shortdoc-add-function \\\\=\u0026#39;file \\\u0026#34;Predicates\\\u0026#34; \\\\=\u0026#39;(file-locked-p :no-eval (file-locked-p \\\u0026#34;/tmp\\\u0026#34;)))\u0026#34; Code Snippet 2: Correctly escaped single quotes in Emacs Lisp documentation strings .. and now the straight quotes get rendered as straight quotes:\nFigure 2: Correctly escaped single quotes in documentation strings Preventing curved quotes in messages\u0026nbsp;# The same auto-rendering of curved quotes happens in the messages that get printed to the ∗Messages∗ buffer and Echo Area as well. So the below behavior where ‘Hi’ gets printed is expected and nice:\n(message \u0026#34;`Hi\u0026#39;\u0026#34;) ;=\u0026gt; \u0026#34;‘Hi’\u0026#34; Code Snippet 3: message auto-converting `Hi' to ‘Hi’ But if someone does below, the rendered ’Hi’ looks pretty odd:\n(message \u0026#34;\u0026#39;Hi\u0026#39;\u0026#34;) ;=\u0026gt; \u0026#34;’Hi’\u0026#34; Code Snippet 4: message auto-converting 'Hi' to ’Hi’ 😮 I had come across this surprise rendering in Emacs 25 and had raised this issue then. From Paul Eggert\u0026rsquo;s reply, I learned that to prevent this curved quote conversion, we should make the message function print the string processed by the format function and not the string directly. You could do this ..\n(message \u0026#34;%s\u0026#34; (format \u0026#34;%s\u0026#34; \u0026#34;\u0026#39;Hi\u0026#39;\u0026#34;)) ;=\u0026gt;\u0026#34;\u0026#39;Hi\u0026#39;\u0026#34; Code Snippet 5: Passing format formatted string to message But below will do the same thing and is much easier to type:\n(message \u0026#34;%s\u0026#34; \u0026#34;\u0026#39;Hi\u0026#39;\u0026#34;) ;=\u0026gt; \u0026#34;\u0026#39;Hi\u0026#39;\u0026#34; (message \u0026#34;%s\u0026#34; \u0026#34;`Hi\u0026#39;\u0026#34;) ;=\u0026gt; \u0026#34;`Hi\u0026#39;\u0026#34; Code Snippet 6: Implicit passing of a string to format for formatting, before getting printed by message Summary\u0026nbsp;# Table 1: Summary of techniques for enforcing straight quotes and grave accents in printed messages and documentation strings Description Solution Outcome Render ' in docstring doc string snippet: \u0026quot;foo \\\\='bar\u0026quot; foo 'bar Render ` in docstring doc string snippet: \u0026quot;foo \\\\=`bar\u0026quot; foo `bar Print ' as ' (message \u0026quot;%s\u0026quot; \u0026quot;'foo\u0026quot;) 'foo Print ` as ` (message \u0026quot;%s\u0026quot; \u0026quot;`foo\u0026quot;) `foo By the way, I submitted a patch for fixing the escaping of straight quotes in shortdoc-add-function documentation string I planned to fix just this straight quote escaping issue, but then I also ended up slightly improving the documentation of the (FUNC :eval EVAL) and other forms used for adding a function\u0026rsquo;s documentation to shortdoc. in debbugs # 54782 and now it\u0026rsquo;s in the emacs master branch! 🎉\nReferences\u0026nbsp;# Fixing curved quotes conversion in documentation strings Elisp Info: Text Quoting Style Fixing curved quotes conversion in printed messages Elisp Info: Formatting Strings "},"name":"Straight and Curved Quotes in Emacs Lisp","published":"2022-04-10T10:05:00-04:00","summary":"A short guide for getting the single quotes rendered as expected (straight or curved) in Emacs Lisp function and variable documentation strings and message outputs.","type":"entry","url":"https://scripter.co/straight-and-curved-quotes-in-emacs-lisp/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#problem-statement\"\u003eProblem Statement\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#course-of-action\"\u003eCourse of action\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#finding-the-culprit-functions\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Finding the culprit functions\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#using-plain-old-grep-or-ripgrep--rg\"\u003eUsing plain-old \u003cem\u003egrep\u003c/em\u003e or \u003cem\u003eripgrep (rg)\u003c/em\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#using-debug-on-message\"\u003eUsing \u003ccode\u003edebug-on-message\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#figure-out-how-to-silence-those-messages\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Figure out how to silence those messages\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#applying-the-silence-advice\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e Applying the \u0026lsquo;silence\u0026rsquo; advice\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#limiting-the-scope-of-these-advices\"\u003eLimiting the scope of these advices\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#conclusion\"\u003eConclusion\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eToday I was working on a minor cleanup of the \u003ccode\u003eox-hugo\u003c/code\u003e package and as\na part of that, I figured out a way to reduce the noisy messages\nprinted in the ∗Messages∗\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nRandom tidbit: You can quickly access the ∗Messages∗ buffer using the\ndefault binding \u003ccode\u003eC-h e\u003c/code\u003e.\n\u003c/small\u003e\u003c/span\u003e\nbuffer. This post describes how I used the \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html\"\u003e📖 Emacs Advice\nfeature\u003c/a\u003e to solve the noisy-messages-buffer problem.\u003c/p\u003e\n\u003cdl\u003e\n\u003cdt\u003eWhat is this \u0026lsquo;advising\u0026rsquo;?\u003c/dt\u003e\n\u003cdd\u003eIn Emacs, \u003cem\u003eadvising\u003c/em\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\n\u003cem\u003eAdvice\u003c/em\u003e with a \u0026lsquo;c\u0026rsquo; is the \u003cem\u003enoun\u003c/em\u003e form. The \u003cem\u003enoun\u003c/em\u003e form is used\neverywhere in the Emacs advising API e.g. \u003ccode\u003eadvice-add\u003c/code\u003e,\n\u003ccode\u003eadvice-remove\u003c/code\u003e. \u003cem\u003eAdvise\u003c/em\u003e with an \u0026rsquo;s\u0026rsquo; is the \u003cem\u003everb\u003c/em\u003e form. \u003ca href=\"https://www.merriam-webster.com/words-at-play/advise-vs-advice-usage\"\u003eMore\nReading\u003c/a\u003e.\n\u003c/small\u003e\u003c/span\u003e\nis a means to modify a function defined in any library \u0026mdash; You can\nmodify the arguments to the function, return values of that\nfunction, run other functions before and/or after that advised\nfunction, .. or may be just replace that function with something\nelse entirely!\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ch2 id=\"problem-statement\"\u003eProblem Statement\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#problem-statement\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIf I run \u003ccode\u003eC-c C-e H A\u003c/code\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThis is the default binding of \u003ccode\u003eox-hugo\u003c/code\u003e to export all the post\nsubtrees in the current Org file.\n\u003c/small\u003e\u003c/span\u003e\nin this site\u0026rsquo;s Org file, I will see a wall of messages, which won\u0026rsquo;t be\ntoo useful to look at if I am exporting dozens of posts in one go.\u003c/p\u003e\n\u003cp\u003eHere\u0026rsquo;s a snippet from that which shows the text printed while two of\nthe posts were being exporting:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--silence-messages-noise\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e[ox-hugo] 60/ Exporting ‘Nim: Deploying static binaries’ ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process nim at position 246918...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEvaluation of this nim code block is disabled.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process shell at position 246985...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process shell at position 247505...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process shell at position 248054...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process nim at position 250620...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEvaluation of this nim code block (code__musl_config_nims) is disabled.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process yaml at position 253830...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003eWrote /home/kmodi/hugo/scripter.co/content/posts/nim-deploying-static-binaries/index.md\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e[ox-hugo] 61/ Exporting ‘Binding Nim to C++ std::list’ ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process nim at position 261418...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEvaluation of this nim code block (code__nim_bindings_importcpp) is disabled.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process nim at position 262802...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEvaluation of this nim code block (code__nim_std_list_bindings) is disabled.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process cpp at position 266921...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process nim at position 267957...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEvaluation of this nim code block (code__nim_bindings_emit) is disabled.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process nim at position 268861...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEvaluation of this nim code block (code__nim_bindings_test_nim_code) is disabled.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process text at position 269849...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process nim at position 270412...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEvaluation of this nim code block (code__nim_bindings_toSeq) is disabled.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eorg-babel-exp process nim at position 271808...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eEvaluation of this nim code block (code__nim_bindings_full_code) is disabled.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eWrote /home/kmodi/hugo/scripter.co/content/posts/binding-nim-to-c-plus-plus-std-list/index.md\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--silence-messages-noise\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Snippet of the noise seen in the \u0026lowast;Messages\u0026lowast; buffer when exporting all post subtrees using \u003ccode\u003eox-hugo\u003c/code\u003e\n\u003c/div\u003e\n\u003cp\u003eAfter applying the advices described in this post, that output\nreduced to this:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--silence-messages-denoised\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e[ox-hugo] 60/ Exporting ‘Nim: Deploying static binaries’ ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e[ox-hugo] 61/ Exporting ‘Binding Nim to C++ std::list’ ..\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--silence-messages-denoised\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Snippet of the \u0026lowast;Messages\u0026lowast; buffer after applying the \u003ci\u003esilencing\u003c/i\u003e advices\n\u003c/div\u003e\n\n\u003ch2 id=\"course-of-action\"\u003eCourse of action\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#course-of-action\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eHere is how I tackled this problem:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eFind the functions responsible for printing those messages.\u003c/li\u003e\n\u003cli\u003eFigure out how to silence those messages.\u003c/li\u003e\n\u003cli\u003eAdvise those functions (temporarily, while the export is happening)\nto not print those messages.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"finding-the-culprit-functions\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Finding the culprit functions\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#finding-the-culprit-functions\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIn \u003ca href=\"#code-snippet--silence-messages-noise\"\u003eCode Snippet 1\u003c/a\u003e, I have highlighted 2 lines. I first\nneeded to figure out which functions printed those messages.  I\u0026rsquo;ll\nshow two methods of finding sources of any printed messages.\u003c/p\u003e\n\n\u003ch3 id=\"using-plain-old-grep-or-ripgrep--rg\"\u003eUsing plain-old \u003cem\u003egrep\u003c/em\u003e or \u003cem\u003eripgrep (rg)\u003c/em\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-plain-old-grep-or-ripgrep--rg\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eThis method is pretty easy (but not robust) to use if the search\nstring is unique enough. The first highlighted line above is a good\ncandidate for this:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eorg-babel-exp process nim at position 246918\u0026hellip;\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe message gives me a clue that it\u0026rsquo;s originating somewhere in the\n\u003cem\u003eOrg Babel\u003c/em\u003e source code (one of the \u003ccode\u003eob-*.el\u003c/code\u003e files). So I \u003cem\u003ecd\u003c/em\u003e to the\nOrg source directory and search for the \u003cem\u003e\u0026ldquo;org-babel-exp process ..\u0026rdquo;\u003c/em\u003e\nstring using \u003ca href=\"https://github.com/BurntSushi/ripgrep\"\u003e\u003ccode\u003erg\u003c/code\u003e\u003c/a\u003e ..\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--finding-org-babel-exp-process-message\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"finding-org-babel-exp-process-message.png\"\u003e\n        \u003cimg src=\"https://scripter.co/using-emacs-advice-to-silence-messages-from-functions/finding-org-babel-exp-process-message.png\" alt=\"Figure 1: Finding the source of \u0026ldquo;org-babel-exp process ..\u0026rdquo; message using ripgrep (rg) in Org source\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eFinding the source of \u0026ldquo;org-babel-exp process ..\u0026rdquo; message using ripgrep (\u003ccode\u003erg\u003c/code\u003e) in Org source\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003e.. and sure enough, there is this one and only one hit .. in the\n\u003ccode\u003eorg-babel-exp-src-block\u003c/code\u003e function in \u003ca href=\"https://git.savannah.gnu.org/cgit/emacs/org-mode.git/tree/lisp/ob-exp.el/?id=91681fc03334285dc0879fcb9a27583bd7ab9782#n93\"\u003e\u003ccode\u003elisp/ob-exp.el\u003c/code\u003e\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eBut this method is not robust for some obvious reasons like,\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ethe string being \u003cem\u003egrepped\u003c/em\u003e might not be present in raw literal form\nlike above,\u003c/li\u003e\n\u003cli\u003emay be it\u0026rsquo;s created through variable interpolation, or\u003c/li\u003e\n\u003cli\u003emay be that whole string is not present on the same line; may be it\nwrapped to the next line.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eWhile this \u003cem\u003egrep\u003c/em\u003e method helped find the source of \u003cem\u003e\u0026ldquo;org-babel-exp\nprocess ..\u0026rdquo;\u003c/em\u003e, let\u0026rsquo;s use a better way of source tracing for the next\nmessage.\u003c/p\u003e\n\n\u003ch3 id=\"using-debug-on-message\"\u003eUsing \u003ccode\u003edebug-on-message\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-debug-on-message\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eFrom \u003ccode\u003eC-h v debug-on-message\u003c/code\u003e, we see:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eIf non-nil, debug if a message matching this regexp is displayed.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThis means that each time a message gets displayed that matches the\nregular expression set in this variable, we get a backtrace to that\nmessage. \u003cem\u003eWho said we can get backtraces for errors only‽\u003c/em\u003e 🤓\u003c/p\u003e\n\u003cp\u003eThe second highlighted line from \u003ca href=\"#code-snippet--silence-messages-noise\"\u003eCode Snippet 1\u003c/a\u003e is:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWrote /home/kmodi/hugo/scripter.co/content/posts/nim-deploying-static-binaries/index.md\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eAfter evaluating \u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003edebug-on-message\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Wrote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/code\u003e, when I exported this post, I saw a backtrace that looked\nlike this.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--debug-on-message-backtrace\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eDebugger entered--Lisp error: \u0026#34;Wrote /home/kmodi/hugo/scripter.co/content/posts/u...\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e  write-region(nil nil \u0026#34;/home/kmodi/hugo/scripter.co/ ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  basic-save-buffer-2()\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  basic-save-buffer-1()\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  basic-save-buffer(nil)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  save-buffer()\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  write-file(\u0026#34;/home/kmodi/hugo/scripter.co/content/posts/using-e...\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  org-export-to-file(hugo \u0026#34;/home/kmodi/hugo/scripter.co/content/posts/using-e...\u0026#34; ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  org-hugo-export-to-md(nil :subtreep nil)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  ..\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--debug-on-message-backtrace\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  Backtrace created on setting \u003ccode\u003edebug-on-message\u003c/code\u003e to \u003ccode\u003e\"Wrote\u003c/code\u003e\"\n\u003c/div\u003e\n\u003cp\u003eThe top line of that backtrace shows the source of that message:\n\u003ccode\u003ewrite-region\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eRemember to reset \u003ccode\u003edebug-on-message\u003c/code\u003e back to \u003cem\u003enil\u003c/em\u003e by evaluating\n\u003ccode class=\"code-inline language-emacs-lisp\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003edebug-on-message\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003c/code\u003e once\nyou are done with this debug!\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"figure-out-how-to-silence-those-messages\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Figure out how to silence those messages\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#figure-out-how-to-silence-those-messages\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eNow that I knew that I needed to alter the \u003ccode\u003eorg-babel-exp-src-block\u003c/code\u003e\nand \u003ccode\u003ewrite-region\u003c/code\u003e functions\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThere was a third function too that I found using this second method:\n\u003ccode\u003etable-generate-source\u003c/code\u003e. This was printing \u003cem\u003e\u0026ldquo;Generating source\u0026hellip;\u0026rdquo;\u003c/em\u003e\nwhen parsing each \u003ccode\u003etable.el\u003c/code\u003e message.\n\u003c/small\u003e\u003c/span\u003e\n, I wanted to quiet these messages in both the \u003cem\u003eecho\u003c/em\u003e area and the\n∗Messages∗ buffer, but only when exporting all the post\nsubtrees from a file.\u003c/p\u003e\n\u003cp\u003eEmacs provides us ways to separately control the displaying of\nmessages in those regions:\u003c/p\u003e\n\u003cdl\u003e\n\u003cdt\u003ePrevent messages in the \u003cem\u003eecho\u003c/em\u003e area\u003c/dt\u003e\n\u003cdd\u003eFrom \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Displaying-Messages.html\"\u003e📖 Elisp \u0026ndash;\nDisplaying Messages\u003c/a\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nYou can visit the same manual page from within Emacs by \u003ccode\u003eC-h i g (elisp)Displaying Messages\u003c/code\u003e.\n\u003c/small\u003e\u003c/span\u003e\n, if\n\u003cmark\u003e\u003ccode\u003einhibit-message\u003c/code\u003e is set to \u003cem\u003et\u003c/em\u003e\u003c/mark\u003e , \u003ccode\u003emessage\u003c/code\u003e outputs are not shown in the \u003cem\u003eecho\u003c/em\u003e area (though they\nwould still be logged in the ∗Messages∗ buffer.\u003c/dd\u003e\n\u003cdt\u003ePrevent messages in the ∗Messages∗ buffer\u003c/dt\u003e\n\u003cdd\u003eFrom \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Logging-Messages.html\"\u003e📖 Elisp\n\u0026ndash; Logging Messages\u003c/a\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\n\u003ccode\u003eC-h i g (elisp)Logging Messages\u003c/code\u003e\n\u003c/small\u003e\u003c/span\u003e\n, if\n\u003cmark\u003e\u003ccode\u003emessage-log-max\u003c/code\u003e is set to \u003cem\u003enil\u003c/em\u003e\u003c/mark\u003e , no messages will be printed in the ∗Messages∗ buffer.\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ch2 id=\"applying-the-silence-advice\"\u003e\u003cspan class=\"section-num\"\u003e3\u003c/span\u003e Applying the \u0026lsquo;silence\u0026rsquo; advice\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#applying-the-silence-advice\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eWith that information, I created this \u003cem\u003eadvising function\u003c/em\u003e which calls\nthe function name it receives in its first argument.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--silence-messages-advising-fn\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e3\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e4\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e5\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003eorg-hugo--advice-silence-messages\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorig-fun\u003c/span\u003e \u003cspan class=\"kp\"\u003e\u0026amp;rest\u003c/span\u003e \u003cspan class=\"nv\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Advice function that silences all messages in ORIG-FUN.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003einhibit-message\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e      \u003cspan class=\"c1\"\u003e;Don\u0026#39;t show the messages in Echo area\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emessage-log-max\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e   \u003cspan class=\"c1\"\u003e;Don\u0026#39;t show the messages in the *Messages* buffer\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eapply\u003c/span\u003e \u003cspan class=\"nv\"\u003eorig-fun\u003c/span\u003e \u003cspan class=\"nv\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--silence-messages-advising-fn\"\u003eCode Snippet 4\u003c/a\u003e:\u003c/span\u003e\n  Advising function to silence the messages in the advised \u003ccode\u003eorig-fun\u003c/code\u003e\n\u003c/div\u003e\n\u003cp\u003eNote that the above function does not set the \u003ccode\u003einhibit-message\u003c/code\u003e and\n\u003ccode\u003emessage-log-max\u003c/code\u003e variables globally (e.g. using \u003ccode\u003esetq\u003c/code\u003e). We do not\nwant to permanently stop the printing of messages for all the\nfunctions! That\u0026rsquo;s why they are set in the \u003ccode\u003elet\u003c/code\u003e scope or the local\nscope, and the \u003ccode\u003eorig-fun\u003c/code\u003e is called within that scope.\u003c/p\u003e\n\u003cp\u003eThis snippet, though, only defines the advising function. The advices\nare actually applied using the \u003ccode\u003eadvice-add\u003c/code\u003e\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThe counterpart of \u003ccode\u003eadvice-add\u003c/code\u003e is \u003ccode\u003eadvice-remove\u003c/code\u003e, to remove the\nadvising functions from the original functions.\n\u003c/small\u003e\u003c/span\u003e\nfunction.\u003c/p\u003e\n\u003cp\u003eEmacs provides a \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Advice-Combinators.html\"\u003evariety\u003c/a\u003e of \u003cem\u003eAdvice Combinators\u003c/em\u003e. These combinators\nare used to specify \u003cem\u003ehow\u003c/em\u003e an advice should be applied to the original\nfunction. I have found the \u003ccode\u003e:around\u003c/code\u003e combinator to usually fit my\nneeds because the advices I add typically look like:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eDo something before.\u003c/li\u003e\n\u003cli\u003eSet some variables in a \u003ccode\u003elet\u003c/code\u003e scope.\u003c/li\u003e\n\u003cli\u003eCall the original function with its arguments inside that scope.\u003c/li\u003e\n\u003cli\u003eDo something afterwards.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eAs I wanted to apply the same advice to multiple functions\n(\u003ccode\u003eorg-babel-exp-src-block\u003c/code\u003e and \u003ccode\u003ewrite-region\u003c/code\u003e), I used \u003ccode\u003edolist\u003c/code\u003e to\nloop through them and advise them to 🤫 :\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--silence-messages-advice-add\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\"\u003e1\n\u003c/span\u003e\u003cspan class=\"lnt\"\u003e2\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edolist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003efn\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-babel-exp-src-block\u003c/span\u003e \u003cspan class=\"nf\"\u003ewrite-region\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvice-add\u003c/span\u003e \u003cspan class=\"nv\"\u003efn\u003c/span\u003e \u003cspan class=\"nb\"\u003e:around\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-hugo--advice-silence-messages\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--silence-messages-advice-add\"\u003eCode Snippet 5\u003c/a\u003e:\u003c/span\u003e\n  Enabling the advices\n\u003c/div\u003e\n\n\u003ch3 id=\"limiting-the-scope-of-these-advices\"\u003eLimiting the scope of these advices\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#limiting-the-scope-of-these-advices\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eYou might wonder \u0026mdash; If \u003ccode\u003eox-hugo\u003c/code\u003e is applying these advices, wouldn\u0026rsquo;t\nit affect the global behavior of \u003ccode\u003ewrite-region\u003c/code\u003e, etc. outside of\n\u003ccode\u003eox-hugo\u003c/code\u003e exports as well?\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e    The answer is \u0026ldquo;no\u0026rdquo;.\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eIn \u003ccode\u003eox-hugo\u003c/code\u003e, the \u003ccode\u003eadvice-add\u003c/code\u003e calls are made just before the \u0026ldquo;export\nall post subtrees\u0026rdquo; operation begins. Once the export command finishes,\n\u003ccode\u003eadvice-remove\u003c/code\u003e calls remove those advices from those functions. So\nthose advices are effective only \u003cspan class=\"underline\"\u003efor the duration of the export\u003c/span\u003e.\u003c/p\u003e\n\u003cp\u003eDetails of the implementation can be seen in \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/commit/6e4f74d20dcb7e5da65cd504d1c64c944319c5f0\"\u003ethis \u003ccode\u003eox-hugo\u003c/code\u003e commit\u003c/a\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"conclusion\"\u003eConclusion\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#conclusion\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThe main effort here was to (i) identify the problem, (ii) find out\nwhich functions were causing the problem, and (iii) what knobs or\nvariables are available to us to help fix that.\u003c/p\u003e\n\u003cp\u003eOnce that is done, you write an \u003cem\u003eadvising\u003c/em\u003e function and \u003ccode\u003eadvice-add\u003c/code\u003e\nthat function to the original function using a combinator of your\nchoice\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nIf you are not sure which combinator to use, pick \u003ccode\u003e:around\u003c/code\u003e 😃.\n\u003c/small\u003e\u003c/span\u003e\n.\u003c/p\u003e\n\u003cp\u003eIn this post, I am using Emacs advices to make \u003ccode\u003eox-hugo\u003c/code\u003e exports less\nnoisy. But you can add similar advices to your Emacs config\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nYou can find the ways I am using advices in my Emacs config \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/search?q=advice-add\"\u003ehere\u003c/a\u003e.\n\u003c/small\u003e\u003c/span\u003e\nto tweak and fine-tune any function that\u0026rsquo;s getting on your nerves\n😄.\u003c/p\u003e\n","text":" Table of Contents Problem Statement Course of action 1 Finding the culprit functions Using plain-old grep or ripgrep (rg) Using debug-on-message 2 Figure out how to silence those messages 3 Applying the \u0026lsquo;silence\u0026rsquo; advice Limiting the scope of these advices Conclusion Today I was working on a minor cleanup of the ox-hugo package and as a part of that, I figured out a way to reduce the noisy messages printed in the ∗Messages∗ Random tidbit: You can quickly access the ∗Messages∗ buffer using the default binding C-h e. buffer. This post describes how I used the 📖 Emacs Advice feature to solve the noisy-messages-buffer problem.\nWhat is this \u0026lsquo;advising\u0026rsquo;? In Emacs, advising Advice with a \u0026lsquo;c\u0026rsquo; is the noun form. The noun form is used everywhere in the Emacs advising API e.g. advice-add, advice-remove. Advise with an \u0026rsquo;s\u0026rsquo; is the verb form. More Reading. is a means to modify a function defined in any library \u0026mdash; You can modify the arguments to the function, return values of that function, run other functions before and/or after that advised function, .. or may be just replace that function with something else entirely! Problem Statement\u0026nbsp;# If I run C-c C-e H A This is the default binding of ox-hugo to export all the post subtrees in the current Org file. in this site\u0026rsquo;s Org file, I will see a wall of messages, which won\u0026rsquo;t be too useful to look at if I am exporting dozens of posts in one go.\nHere\u0026rsquo;s a snippet from that which shows the text printed while two of the posts were being exporting:\n[ox-hugo] 60/ Exporting ‘Nim: Deploying static binaries’ .. org-babel-exp process nim at position 246918... Evaluation of this nim code block is disabled. org-babel-exp process shell at position 246985... org-babel-exp process shell at position 247505... org-babel-exp process shell at position 248054... org-babel-exp process nim at position 250620... Evaluation of this nim code block (code__musl_config_nims) is disabled. org-babel-exp process yaml at position 253830... Wrote /home/kmodi/hugo/scripter.co/content/posts/nim-deploying-static-binaries/index.md [ox-hugo] 61/ Exporting ‘Binding Nim to C++ std::list’ .. org-babel-exp process nim at position 261418... Evaluation of this nim code block (code__nim_bindings_importcpp) is disabled. org-babel-exp process nim at position 262802... Evaluation of this nim code block (code__nim_std_list_bindings) is disabled. org-babel-exp process cpp at position 266921... org-babel-exp process nim at position 267957... Evaluation of this nim code block (code__nim_bindings_emit) is disabled. org-babel-exp process nim at position 268861... Evaluation of this nim code block (code__nim_bindings_test_nim_code) is disabled. org-babel-exp process text at position 269849... org-babel-exp process nim at position 270412... Evaluation of this nim code block (code__nim_bindings_toSeq) is disabled. org-babel-exp process nim at position 271808... Evaluation of this nim code block (code__nim_bindings_full_code) is disabled. Wrote /home/kmodi/hugo/scripter.co/content/posts/binding-nim-to-c-plus-plus-std-list/index.md Code Snippet 1: Snippet of the noise seen in the \u0026lowast;Messages\u0026lowast; buffer when exporting all post subtrees using ox-hugo After applying the advices described in this post, that output reduced to this:\n[ox-hugo] 60/ Exporting ‘Nim: Deploying static binaries’ .. [ox-hugo] 61/ Exporting ‘Binding Nim to C++ std::list’ .. Code Snippet 2: Snippet of the \u0026lowast;Messages\u0026lowast; buffer after applying the silencing advices Course of action\u0026nbsp;# Here is how I tackled this problem:\nFind the functions responsible for printing those messages. Figure out how to silence those messages. Advise those functions (temporarily, while the export is happening) to not print those messages. 1 Finding the culprit functions\u0026nbsp;# In Code Snippet 1, I have highlighted 2 lines. I first needed to figure out which functions printed those messages. I\u0026rsquo;ll show two methods of finding sources of any printed messages.\nUsing plain-old grep or ripgrep (rg)\u0026nbsp;# This method is pretty easy (but not robust) to use if the search string is unique enough. The first highlighted line above is a good candidate for this:\norg-babel-exp process nim at position 246918\u0026hellip;\nThe message gives me a clue that it\u0026rsquo;s originating somewhere in the Org Babel source code (one of the ob-*.el files). So I cd to the Org source directory and search for the \u0026ldquo;org-babel-exp process ..\u0026rdquo; string using rg ..\nFigure 1: Finding the source of \u0026ldquo;org-babel-exp process ..\u0026rdquo; message using ripgrep (rg) in Org source .. and sure enough, there is this one and only one hit .. in the org-babel-exp-src-block function in lisp/ob-exp.el.\nBut this method is not robust for some obvious reasons like,\nthe string being grepped might not be present in raw literal form like above, may be it\u0026rsquo;s created through variable interpolation, or may be that whole string is not present on the same line; may be it wrapped to the next line. While this grep method helped find the source of \u0026ldquo;org-babel-exp process ..\u0026rdquo;, let\u0026rsquo;s use a better way of source tracing for the next message.\nUsing debug-on-message\u0026nbsp;# From C-h v debug-on-message, we see:\nIf non-nil, debug if a message matching this regexp is displayed.\nThis means that each time a message gets displayed that matches the regular expression set in this variable, we get a backtrace to that message. Who said we can get backtraces for errors only‽ 🤓\nThe second highlighted line from Code Snippet 1 is:\nWrote /home/kmodi/hugo/scripter.co/content/posts/nim-deploying-static-binaries/index.md\nAfter evaluating (setq debug-on-message \u0026#34;Wrote\u0026#34;), when I exported this post, I saw a backtrace that looked like this.\nDebugger entered--Lisp error: \u0026#34;Wrote /home/kmodi/hugo/scripter.co/content/posts/u...\u0026#34; write-region(nil nil \u0026#34;/home/kmodi/hugo/scripter.co/ .. basic-save-buffer-2() basic-save-buffer-1() .. basic-save-buffer(nil) save-buffer() write-file(\u0026#34;/home/kmodi/hugo/scripter.co/content/posts/using-e...\u0026#34;) .. org-export-to-file(hugo \u0026#34;/home/kmodi/hugo/scripter.co/content/posts/using-e...\u0026#34; .. org-hugo-export-to-md(nil :subtreep nil) .. Code Snippet 3: Backtrace created on setting debug-on-message to \"Wrote\" The top line of that backtrace shows the source of that message: write-region.\nRemember to reset debug-on-message back to nil by evaluating (setq debug-on-message nil) once you are done with this debug!\n2 Figure out how to silence those messages\u0026nbsp;# Now that I knew that I needed to alter the org-babel-exp-src-block and write-region functions There was a third function too that I found using this second method: table-generate-source. This was printing \u0026ldquo;Generating source\u0026hellip;\u0026rdquo; when parsing each table.el message. , I wanted to quiet these messages in both the echo area and the ∗Messages∗ buffer, but only when exporting all the post subtrees from a file.\nEmacs provides us ways to separately control the displaying of messages in those regions:\nPrevent messages in the echo area From 📖 Elisp \u0026ndash; Displaying Messages You can visit the same manual page from within Emacs by C-h i g (elisp)Displaying Messages. , if inhibit-message is set to t , message outputs are not shown in the echo area (though they would still be logged in the ∗Messages∗ buffer. Prevent messages in the ∗Messages∗ buffer From 📖 Elisp \u0026ndash; Logging Messages C-h i g (elisp)Logging Messages , if message-log-max is set to nil , no messages will be printed in the ∗Messages∗ buffer. 3 Applying the \u0026lsquo;silence\u0026rsquo; advice\u0026nbsp;# With that information, I created this advising function which calls the function name it receives in its first argument.\n1 2 3 4 5 (defun org-hugo--advice-silence-messages (orig-fun \u0026amp;rest args) \u0026#34;Advice function that silences all messages in ORIG-FUN.\u0026#34; (let ((inhibit-message t) ;Don\u0026#39;t show the messages in Echo area (message-log-max nil)) ;Don\u0026#39;t show the messages in the *Messages* buffer (apply orig-fun args))) Code Snippet 4: Advising function to silence the messages in the advised orig-fun Note that the above function does not set the inhibit-message and message-log-max variables globally (e.g. using setq). We do not want to permanently stop the printing of messages for all the functions! That\u0026rsquo;s why they are set in the let scope or the local scope, and the orig-fun is called within that scope.\nThis snippet, though, only defines the advising function. The advices are actually applied using the advice-add The counterpart of advice-add is advice-remove, to remove the advising functions from the original functions. function.\nEmacs provides a variety of Advice Combinators. These combinators are used to specify how an advice should be applied to the original function. I have found the :around combinator to usually fit my needs because the advices I add typically look like:\nDo something before. Set some variables in a let scope. Call the original function with its arguments inside that scope. Do something afterwards. As I wanted to apply the same advice to multiple functions (org-babel-exp-src-block and write-region), I used dolist to loop through them and advise them to 🤫 :\n1 2 (dolist (fn \u0026#39;(org-babel-exp-src-block write-region) (advice-add fn :around #\u0026#39;org-hugo--advice-silence-messages)) Code Snippet 5: Enabling the advices Limiting the scope of these advices\u0026nbsp;# You might wonder \u0026mdash; If ox-hugo is applying these advices, wouldn\u0026rsquo;t it affect the global behavior of write-region, etc. outside of ox-hugo exports as well?\nThe answer is \u0026ldquo;no\u0026rdquo;.\nIn ox-hugo, the advice-add calls are made just before the \u0026ldquo;export all post subtrees\u0026rdquo; operation begins. Once the export command finishes, advice-remove calls remove those advices from those functions. So those advices are effective only for the duration of the export.\nDetails of the implementation can be seen in this ox-hugo commit.\nConclusion\u0026nbsp;# The main effort here was to (i) identify the problem, (ii) find out which functions were causing the problem, and (iii) what knobs or variables are available to us to help fix that.\nOnce that is done, you write an advising function and advice-add that function to the original function using a combinator of your choice If you are not sure which combinator to use, pick :around 😃. .\nIn this post, I am using Emacs advices to make ox-hugo exports less noisy. But you can add similar advices to your Emacs config You can find the ways I am using advices in my Emacs config here. to tweak and fine-tune any function that\u0026rsquo;s getting on your nerves 😄.\n"},"name":"Using Emacs advice to silence messages from functions","published":"2022-03-19T02:25:00-04:00","summary":"Using the :around advice to prevent messages from being displayed in the echo area or the ∗Messages∗ buffer.","type":"entry","url":"https://scripter.co/using-emacs-advice-to-silence-messages-from-functions/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#test-directory\"\u003eTest directory\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#test-files\"\u003eTest Files\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#feature-test\"\u003eFeature-specific \u003ccode\u003et***.el\u003c/code\u003e test files\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#wrapper-test-file-all-tests-dot-el\"\u003eWrapper test file \u003ccode\u003eall-tests.el\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#makefile\"\u003eMakefile\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#summary\"\u003eSummary\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003e\u003cabbr aria-label=\"Emacs Lisp Regression Testing\" tabindex=0\u003eERT\u003c/abbr\u003e is a testing library\nthat comes with Emacs i.e. you do not need to install from GNU Elpa or\nMelpa. The aim of this post is to serve as a quick guide on how to\nstart using ERT with your Emacs Lisp library\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nHere, a \u0026ldquo;library\u0026rdquo; could even be a set of custom Emacs Lisp code that\nyou wrote for your Emacs config.\n\u003c/small\u003e\u003c/span\u003e\n.\u003c/p\u003e\n\u003cp\u003eThe ERT manual\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nYou can quickly visit the ERT manual from within Emacs using the\nwonderful \u003cem\u003eInfo\u003c/em\u003e system by typing \u003ccode\u003eC-h i m ert\u003c/code\u003e, you can visit \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/ert/\"\u003eEmacs\nManual \u0026ndash; ERT\u003c/a\u003e in a web browser.\n\u003c/small\u003e\u003c/span\u003e\nis really well-written and here\u0026rsquo;s how it introduces this testing\nlibrary:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eERT is a tool for automated testing in Emacs Lisp. Its main features\nare facilities for defining tests, running them and reporting the\nresults, and for debugging test failures interactively.\u003c/p\u003e\n\u003cp\u003e..it\n\u003cmark\u003eworks well both for \u003ca href=\"https://en.wikipedia.org/wiki/Test-driven_development\"\u003etest-driven development\u003c/a\u003e\u003c/mark\u003e and for traditional software development methods.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThe part about \u003cem\u003etest-driven development\u003c/em\u003e is so true! At the moment, I\nam developing an Emacs library called \u003ca href=\"https://github.com/kaushalmodi/baser\"\u003e\u003ccode\u003ebaser\u003c/code\u003e\u003c/a\u003e that does signed number\nconversions among base 10, base 2 and base 16 formats. Before adding\nnew features, I first write the \u003ccode\u003eert\u003c/code\u003e tests, and then I develop and\nrefine the functions until they start passing.\u003c/p\u003e\n\u003cp\u003eIn this post, I will use that \u003cem\u003ebaser\u003c/em\u003e library as an example of how to\nset up ERT \u0026ndash; which I believe would be applicable to other Emacs Lisp\nprojects too.\u003c/p\u003e\n\n\u003ch2 id=\"test-directory\"\u003eTest directory\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#test-directory\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eBelow shows how the \u003ccode\u003etest/\u003c/code\u003e directory is created with respect to the\nlibrary being tested.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--test-dir-structure-ert\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ebaser/                (repo root)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e├── baser.el\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e├── ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e├── test/\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│  ├── all-tests.el\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│  ├── ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e│  └── tdec-hex.el\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e└── Makefile\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--test-dir-structure-ert\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Test directory structure from \u003ca href=\"https://github.com/kaushalmodi/baser\"\u003e\u003cb\u003ebaser\u003c/b\u003e\u003c/a\u003e\n\u003c/div\u003e\n\u003cp\u003eHere,\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003ccode\u003ebaser.el\u003c/code\u003e is the Emacs Lisp library being tested.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etest/\u003c/code\u003e is the directory containing all the tests.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eMakefile\u003c/code\u003e defines a \u003ccode\u003etest\u003c/code\u003e target so that running tests is as easy\nas \u003ccode\u003emake test\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"test-files\"\u003eTest Files\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#test-files\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIn the \u003ccode\u003etest/\u003c/code\u003e directory, I have a main \u003ccode\u003eall-tests.el\u003c/code\u003e file that\nrequires all other test files named in \u003ccode\u003et***.el\u003c/code\u003e style.\u003c/p\u003e\n\n\u003ch3 id=\"feature-test\"\u003eFeature-specific \u003ccode\u003et***.el\u003c/code\u003e test files\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#feature-test\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eI like to follow the convention of starting all test file names with\n\u003ccode\u003et\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eI break up the test files such that each file tests only a particular\nfeature. In \u003cem\u003ebaser\u003c/em\u003e, I have \u003ccode\u003etdec-hex.el\u003c/code\u003e to test the conversions\nbetween decimal and hexidecimal formats. Similarly I have\n\u003ccode\u003etdec-bin.el\u003c/code\u003e and \u003ccode\u003ethex-bin.el\u003c/code\u003e.\u003c/p\u003e\n\n\u003ch4 id=\"general-structure-of-each-feature-test\"\u003eGeneral structure of each feature test\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#general-structure-of-each-feature-test\"\u003e#\u003c/a\u003e\u003c/h4\u003e\n\n\n\u003cp\u003eThe structure of each \u003ccode\u003etfeature.el\u003c/code\u003e file looks like this:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--tfeature-file-structure\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-1\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-1\"\u003e 1\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-2\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-2\"\u003e 2\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-3\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-3\"\u003e 3\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-4\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-4\"\u003e 4\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-5\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-5\"\u003e 5\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-6\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-6\"\u003e 6\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-7\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-7\"\u003e 7\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-8\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-8\"\u003e 8\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-9\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-9\"\u003e 9\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-10\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-10\"\u003e10\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-11\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-11\"\u003e11\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-12\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-12\"\u003e12\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-13\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-13\"\u003e13\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-14\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-14\"\u003e14\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-15\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-15\"\u003e15\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--7f5520-16\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--7f5520-16\"\u003e16\u003c/a\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; tfeature.el                    -*- lexical-binding: t; -*-\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Require the emacs-lisp library being tested.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Example: (require \u0026#39;baser)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Test things that *should* happen.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eert-deftest\u003c/span\u003e \u003cspan class=\"nv\"\u003eaddition-test\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eshould\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e+\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Test things that your library *should trigger errors* for.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eert-deftest\u003c/span\u003e \u003cspan class=\"nv\"\u003ediv-by-0-test\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eshould-error\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e/\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"nb\"\u003e:type\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;arith-error\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eprovide\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;tfeature\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--tfeature-file-structure\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Structure of each \u003ccode\u003etfeature.el\u003c/code\u003e test file\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003eLines \u003ca href=\"#org-coderef--7f5520-7\"\u003e7\u003c/a\u003e and \u003ca href=\"#org-coderef--7f5520-11\"\u003e11\u003c/a\u003e define the \u003cem\u003eert\u003c/em\u003e tests using\n\u003ccode\u003eert-deftest\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe first \u003ccode\u003eert_deftest\u003c/code\u003e uses a \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/ert/The-should-Macro.html\"\u003e\u003ccode\u003eshould\u003c/code\u003e macro\u003c/a\u003e that checks if its\nbody evaluates to \u003cem\u003enon-nil\u003c/em\u003e. It is similar to constructs like\n\u003ccode class=\"code-inline language-systemverilog\"\u003e\u003cspan class=\"k\"\u003eassert\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esomething\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"mh\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003c/code\u003e or\n\u003ccode class=\"code-inline language-nim\"\u003e\u003cspan class=\"n\"\u003edoAssert\u003c/span\u003e \u003cspan class=\"n\"\u003esomething\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"kp\"\u003etrue\u003c/span\u003e\u003c/code\u003e in\n\u003cspan title=\"SystemVerilog\"\u003eother\u003c/span\u003e \u003cspan title=\"Nim\"\u003eprogramming\u003c/span\u003e languages.\u003c/li\u003e\n\u003cli\u003eThe \u003ca href=\"#org-coderef--7f5520-11\"\u003esecond \u003ccode\u003eert_deftest\u003c/code\u003e​\u003c/a\u003e uses kind the \u003ccode\u003eshould-error\u003c/code\u003e macro that\nasserts if the evaluation of its body resulted in an error. Here,\nthe test fails if the body does \u003cstrong\u003enot\u003c/strong\u003e throw an error. The optional\n\u003ccode\u003e:type \u0026lt;error type\u0026gt;\u003c/code\u003e argument makes the test stricter; in addition\nto checking if evaluating that body throws an error, it also checks\nif the thrown error is of that specific type.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003e\u003ccode\u003eert\u003c/code\u003e does not need to be \u003cem\u003erequired\u003c/em\u003e manually because \u003ccode\u003eert-deftest\u003c/code\u003e\nwill autoload it.\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch3 id=\"wrapper-test-file-all-tests-dot-el\"\u003eWrapper test file \u003ccode\u003eall-tests.el\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#wrapper-test-file-all-tests-dot-el\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eA wrapper test file \u003ccode\u003eall-tests.el\u003c/code\u003e is created for convenience so that\nloading just this one file loads all the tests. Having such a wrapper\nfile is helpful as you will see in the \u003cem\u003eMakefile\u003c/em\u003e section next.\u003c/p\u003e\n\u003cp\u003eThis file simply requires all the feature test files like the ones\nexplained \u003ca href=\"#feature-test\"\u003eabove\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--all-tests-ert\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; all-tests.el\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; If the directory happens to have both compiled and uncompiled\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; version, prefer to use the newer (typically the uncompiled) version.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eload-prefer-newer\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;tdec-hex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e  \u003cspan class=\"c1\"\u003e;Require the dec\u0026lt;-\u0026gt;hex conversion feature test\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; more feature tests ..\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--all-tests-ert\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  Wrapper test file \u003ccode\u003eall-tests.el\u003c/code\u003e to require all other tests\n\u003c/div\u003e\n\n\u003ch2 id=\"makefile\"\u003eMakefile\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#makefile\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eFinally, we create a \u003ccode\u003eMakefile\u003c/code\u003e so that we can run \u003ccode\u003emake test\u003c/code\u003e to run\nthe ERT tests.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eRun \u003ccode\u003emake test\u003c/code\u003e to run all tests.\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003emake test MATCH=foo\u003c/code\u003e to run only the tests whose names match\n\u0026ldquo;foo\u0026rdquo;. The test names are the ones defined by the \u003ccode\u003eert-deftest\u003c/code\u003e\nmacro.\u003c/li\u003e\n\u003c/ol\u003e\n\u003c!--listend--\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--makefile-ert\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-makefile\" data-lang=\"makefile\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eEMACS\u003c/span\u003e \u003cspan class=\"o\"\u003e?=\u003c/span\u003e emacs\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eTEST_DIR\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"k\"\u003e$(\u003c/span\u003eshell \u003cspan class=\"nb\"\u003epwd\u003c/span\u003e\u003cspan class=\"k\"\u003e)\u003c/span\u003e/test\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e# Run all tests by default.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"nv\"\u003eMATCH\u003c/span\u003e \u003cspan class=\"o\"\u003e?=\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003e.PHONY\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e \u003cspan class=\"n\"\u003etest\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nf\"\u003etest\u003c/span\u003e\u003cspan class=\"o\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003e$(\u003c/span\u003eEMACS\u003cspan class=\"k\"\u003e)\u003c/span\u003e --batch -L . -L \u003cspan class=\"k\"\u003e$(\u003c/span\u003eTEST_DIR\u003cspan class=\"k\"\u003e)\u003c/span\u003e -l all-tests.el -eval \u003cspan class=\"s1\"\u003e\u0026#39;(ert-run-tests-batch-and-exit \u0026#34;$(MATCH)\u0026#34;)\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--makefile-ert\"\u003eCode Snippet 4\u003c/a\u003e:\u003c/span\u003e\n  \u003ccode\u003emake test\u003c/code\u003e recipe for running ERT tests\n\u003c/div\u003e\n\u003cp\u003eSee \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/ert/Running-Tests-in-Batch-Mode.html\"\u003eERT \u0026ndash; Running Tests in Batch Mode\u003c/a\u003e for reference.\u003c/p\u003e\n\n\u003ch2 id=\"summary\"\u003eSummary\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#summary\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eYou can quickly create a nice test setup for your Emacs Lisp library\nor Emacs config by adding a test file with tests defined using\n\u003ccode\u003eerf-deftest\u003c/code\u003e with \u003ccode\u003eshould\u003c/code\u003e and \u003ccode\u003eshould-error\u003c/code\u003e macros, and then\nrunning \u003ccode\u003emake test\u003c/code\u003e with the help of a \u003ccode\u003eMakefile\u003c/code\u003e like the one shown\nabove.\u003c/p\u003e\n\u003cp\u003eWhile this post might help you get started with using ERT quickly, do\ngo through its manual \u0026mdash; it\u0026rsquo;s short and sweet, and well-written, and\ncovers a lot more than this post.\u003c/p\u003e\n\n\u003ch2 id=\"references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/ert/\"\u003eEmacs Manual \u0026ndash; ERT\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/kaushalmodi/baser\"\u003e\u003ccode\u003ebaser\u003c/code\u003e library\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","text":" Table of Contents Test directory Test Files Feature-specific t***.el test files Wrapper test file all-tests.el Makefile Summary References ERT is a testing library that comes with Emacs i.e. you do not need to install from GNU Elpa or Melpa. The aim of this post is to serve as a quick guide on how to start using ERT with your Emacs Lisp library Here, a \u0026ldquo;library\u0026rdquo; could even be a set of custom Emacs Lisp code that you wrote for your Emacs config. .\nThe ERT manual You can quickly visit the ERT manual from within Emacs using the wonderful Info system by typing C-h i m ert, you can visit Emacs Manual \u0026ndash; ERT in a web browser. is really well-written and here\u0026rsquo;s how it introduces this testing library:\nERT is a tool for automated testing in Emacs Lisp. Its main features are facilities for defining tests, running them and reporting the results, and for debugging test failures interactively.\n..it works well both for test-driven development and for traditional software development methods.\nThe part about test-driven development is so true! At the moment, I am developing an Emacs library called baser that does signed number conversions among base 10, base 2 and base 16 formats. Before adding new features, I first write the ert tests, and then I develop and refine the functions until they start passing.\nIn this post, I will use that baser library as an example of how to set up ERT \u0026ndash; which I believe would be applicable to other Emacs Lisp projects too.\nTest directory\u0026nbsp;# Below shows how the test/ directory is created with respect to the library being tested.\nbaser/ (repo root) ├── baser.el ├── .. ├── test/ │ ├── all-tests.el │ ├── .. │ └── tdec-hex.el └── Makefile Code Snippet 1: Test directory structure from baser Here,\nbaser.el is the Emacs Lisp library being tested. test/ is the directory containing all the tests. Makefile defines a test target so that running tests is as easy as make test. Test Files\u0026nbsp;# In the test/ directory, I have a main all-tests.el file that requires all other test files named in t***.el style.\nFeature-specific t***.el test files\u0026nbsp;# I like to follow the convention of starting all test file names with t.\nI break up the test files such that each file tests only a particular feature. In baser, I have tdec-hex.el to test the conversions between decimal and hexidecimal formats. Similarly I have tdec-bin.el and thex-bin.el.\nGeneral structure of each feature test\u0026nbsp;# The structure of each tfeature.el file looks like this:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ;; tfeature.el -*- lexical-binding: t; -*- ;; Require the emacs-lisp library being tested. ;; Example: (require \u0026#39;baser) ;; Test things that *should* happen. (ert-deftest addition-test () (should (= (+ 1 2) 3))) ;; Test things that your library *should trigger errors* for. (ert-deftest div-by-0-test () (should-error (/ 0 0) :type \u0026#39;arith-error)) (provide \u0026#39;tfeature) Code Snippet 2: Structure of each tfeature.el test file Lines 7 and 11 define the ert tests using ert-deftest. The first ert_deftest uses a should macro that checks if its body evaluates to non-nil. It is similar to constructs like assert (something == 1); or doAssert something == true in other programming languages. The second ert_deftest​ uses kind the should-error macro that asserts if the evaluation of its body resulted in an error. Here, the test fails if the body does not throw an error. The optional :type \u0026lt;error type\u0026gt; argument makes the test stricter; in addition to checking if evaluating that body throws an error, it also checks if the thrown error is of that specific type. ert does not need to be required manually because ert-deftest will autoload it.\nWrapper test file all-tests.el\u0026nbsp;# A wrapper test file all-tests.el is created for convenience so that loading just this one file loads all the tests. Having such a wrapper file is helpful as you will see in the Makefile section next.\nThis file simply requires all the feature test files like the ones explained above.\n;; all-tests.el ;; If the directory happens to have both compiled and uncompiled ;; version, prefer to use the newer (typically the uncompiled) version. (setq load-prefer-newer t) (require \u0026#39;tdec-hex) ;Require the dec\u0026lt;-\u0026gt;hex conversion feature test ;; more feature tests .. Code Snippet 3: Wrapper test file all-tests.el to require all other tests Makefile\u0026nbsp;# Finally, we create a Makefile so that we can run make test to run the ERT tests.\nRun make test to run all tests. Run make test MATCH=foo to run only the tests whose names match \u0026ldquo;foo\u0026rdquo;. The test names are the ones defined by the ert-deftest macro. EMACS ?= emacs TEST_DIR=$(shell pwd)/test # Run all tests by default. MATCH ?= .PHONY: test test: $(EMACS) --batch -L . -L $(TEST_DIR) -l all-tests.el -eval \u0026#39;(ert-run-tests-batch-and-exit \u0026#34;$(MATCH)\u0026#34;)\u0026#39; Code Snippet 4: make test recipe for running ERT tests See ERT \u0026ndash; Running Tests in Batch Mode for reference.\nSummary\u0026nbsp;# You can quickly create a nice test setup for your Emacs Lisp library or Emacs config by adding a test file with tests defined using erf-deftest with should and should-error macros, and then running make test with the help of a Makefile like the one shown above.\nWhile this post might help you get started with using ERT quickly, do go through its manual \u0026mdash; it\u0026rsquo;s short and sweet, and well-written, and covers a lot more than this post.\nReferences\u0026nbsp;# Emacs Manual \u0026ndash; ERT baser library "},"name":"Quick Intro to Emacs Lisp Regression Testing","published":"2022-03-06T14:40:00-05:00","summary":"A quick introduction to using ERT (Emacs Lisp Regression Testing) for your next elisp library.","type":"entry","url":"https://scripter.co/quick-intro-to-emacs-lisp-regression-testing/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#hugo-shortcode\"\u003eHugo shortcode\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org-mode-special-block\"\u003eOrg mode special block\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#summary\"\u003eSummary\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#one-time-configuration\"\u003eOne-time configuration\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org-special-block-sidenote\"\u003eOrg special block: \u003ccode\u003esidenote\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eThe main focus of my \u003ca href=\"/sidenotes-using-only-css/\"\u003e previous post \u003c/a\u003e was the CSS for sidenotes. I also\nshowed the companion HTML wrapper needed for that CSS to work. Here it\nis again for convenience:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--sidenote-html-example\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003espan\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;sidenote-number\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003esmall\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;sidenote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    sidenote content\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003esmall\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003espan\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--sidenote-html-example\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Sidenote HTML example\n\u003c/div\u003e\n\n\u003ch2 id=\"hugo-shortcode\"\u003eHugo shortcode\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#hugo-shortcode\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eNow .. You might be thinking that it\u0026rsquo;s not too practical to type that\nthing for each new sidenote. And you are right! That\u0026rsquo;s where we use\nthe \u003ca href=\"https://gohugo.io/content-management/shortcodes/\"\u003eHugo Shortcode\u003c/a\u003e feature.\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\n\u003cem\u003eHugo Shortcodes\u003c/em\u003e are like Org Macros that are typically used to\ninsert some HTML template around the user entered content.\n\u003c/small\u003e\u003c/span\u003e\nIf you look at the \u003ca href=\"#code-snippet--sidenote-html-example\"\u003eabove snippet\u003c/a\u003e, the outer \u003ccode\u003espan\u003c/code\u003e and \u003ccode\u003esmall\u003c/code\u003e tags\nare just HTML boilerplate that the user will need to type mechanically\naround each sidenote. So the shortcodes are perfect for solving this\nannoyance.\u003c/p\u003e\n\u003cp\u003eIf we design a \u003cem\u003epaired\u003c/em\u003e shortcode for this, the above HTML example\nwill change to below:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--sidenote-shortcode-use\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-md\" data-lang=\"md\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e{{% sidenote %}}\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esidenote content\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e{{% /sidenote %}}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--sidenote-shortcode-use\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Example use of the \u003ccode\u003esidenote\u003c/code\u003e shortcode\n\u003c/div\u003e\n\u003cp\u003eAs you can see, this shortcode\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nThis is a markdown-rendering shortcode i.e. a shortcode with \u003ccode\u003e{{​% .. %}}\u003c/code\u003e instead of \u003ccode\u003e{{​\u0026lt; .. \u0026gt;}}\u003c/code\u003e. So the insides of this shortcode\nwill passed on to the Hugo Markdown renderer.\n\u003c/small\u003e\u003c/span\u003e\n\u003cem\u003enow\u003c/em\u003e enables the user to\n\u003cmark\u003efocus on content writing\u003c/mark\u003e than on writing boilerplate HTML. And the definition of that shortcode\nis pretty simple as well:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--sidenote-shortcode\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003espan\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;sidenote-number\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003esmall\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;sidenote\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e{{ .Inner }}\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003esmall\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003espan\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--sidenote-shortcode\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  \"sidenote.html\" Hugo shortcode\n\u003c/div\u003e\n\u003cp\u003eThe only Hugo-templating syntax used here is \u003ccode\u003e{{ .Inner }}\u003c/code\u003e. You can\nread more about it \u003ca href=\"https://gohugo.io/templates/shortcode-templates/#inner\"\u003ehere\u003c/a\u003e, but the \u003cem\u003etl;dr\u003c/em\u003e is that the \u003ccode\u003e.Inner\u003c/code\u003e holds\nwhatever content the user entered \u003cem\u003einside\u003c/em\u003e the \u003ccode\u003e{{​% sidenote %}}\u003c/code\u003e and\n\u003ccode\u003e{{​% /sidenote %}}\u003c/code\u003e tags.\u003c/p\u003e\n\u003cp\u003eOnce you save \u003ca href=\"#code-snippet--sidenote-shortcode\"\u003ethat shortcode snippet\u003c/a\u003e to a \u003ccode\u003elayouts/sidenote.html\u003c/code\u003e file\nin your Hugo site\u0026rsquo;s directory, you are ready to use it.\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e        🛑 But wait! 🛑\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"org-mode-special-block\"\u003eOrg mode special block\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#org-mode-special-block\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIt would be a shame to populate the Org source of this blog with\nHugo-specific shortcodes when I am using \u003ca href=\"https://ox-hugo.scripter.co/\"\u003eox-hugo\u003c/a\u003e 😄.\u003c/p\u003e\n\u003cp\u003eSo instead, we just use the plain-old Org special blocks and tell\n\u003cem\u003eox-hugo\u003c/em\u003e that this \u0026ldquo;sidenote\u0026rdquo; special block be exported as a\nmarkdown-rendering Hugo shortcode. I do that by just placing this at\nthe top of my Org file\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nSee the \u003ca href=\"https://ox-hugo.scripter.co/doc/shortcodes/#hugo-paired-shortcodes\"\u003eHugo Paired Shortcodes\u003c/a\u003e section in the \u003cem\u003eox-hugo\u003c/em\u003e manual to learn\nmore about this.\n\u003c/small\u003e\u003c/span\u003e\n:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--sidenote-hugo-paired-shortcode\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+hugo_paired_shortcodes\u003c/span\u003e\u003cspan class=\"c\"\u003e: %sidenote\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--sidenote-hugo-paired-shortcode\"\u003eCode Snippet 4\u003c/a\u003e:\u003c/span\u003e\n  \u003ccode\u003e#+hugo_paired_shortcodes\u003c/code\u003e keyword for specifying \"shortcode\" special blocks\n\u003c/div\u003e\n\u003cp\u003e.. and then writing a \u0026ldquo;sidenote\u0026rdquo; type Org special block:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--sidenote-special-block-use\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eabc\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_sidenote\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eexample sidenote content\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_sidenote\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edef\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--sidenote-special-block-use\"\u003eCode Snippet 5\u003c/a\u003e:\u003c/span\u003e\n  Example use of the \u003ccode\u003esidenote\u003c/code\u003e special block\n\u003c/div\u003e\n\u003cp\u003eNormally, Org mode would insert a paragraph break where any Org block\n(like that \u003cem\u003esidenote\u003c/em\u003e special block) is used. So above would render\nas:\u003c/p\u003e\n\u003cdiv style=\"color:green;\" class=\"green\"\u003e\n\u003cp\u003eabc\u003c/p\u003e\n\u003cp\u003e\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nexample sidenote content\n\u003c/small\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003edef\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eBut I am pretty sure that nobody would render sidenote references in\ntheir main text as above\u0026mdash;instead, below is more \u003cem\u003enormal\u003c/em\u003e 😄.\u003c/p\u003e\n\u003cdiv style=\"color:green;\" class=\"green\"\u003e\n\u003cp\u003eabc\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nexample sidenote content\n\u003c/small\u003e\u003c/span\u003e\ndef\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eIn that \u003cem\u003enormal\u003c/em\u003e example of the sidenote, \u003cem\u003eox-hugo\u003c/em\u003e trims the whitespace\naround the \u003cem\u003esidenote\u003c/em\u003e block. That is configured by customizing the\n\u003ccode\u003eorg-hugo-special-block-type-properties\u003c/code\u003e variable:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--sidenote-whitespace-trimming\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewith-eval-after-load\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;ox-hugo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-to-list\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;org-hugo-special-block-type-properties\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;sidenote\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003e:trim-pre\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e \u003cspan class=\"nb\"\u003e:trim-post\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--sidenote-whitespace-trimming\"\u003eCode Snippet 6\u003c/a\u003e:\u003c/span\u003e\n  Whitespace trimming enabled by default for \u003ccode\u003esidenote\u003c/code\u003e special blocks\n\u003c/div\u003e\n\u003cp\u003eYou can read more about this \u003cem\u003ewhitespace trimming\u003c/em\u003e feature in the\n\u003ca href=\"https://ox-hugo.scripter.co/doc/org-special-blocks/#whitespace-trimming\"\u003eox-hugo manual\u003c/a\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"summary\"\u003eSummary\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#summary\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\u003ch3 id=\"one-time-configuration\"\u003eOne-time configuration\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#one-time-configuration\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003col\u003e\n\u003cli\u003eCreate and save a \u0026ldquo;sidenote\u0026rdquo; Hugo shortcode as shown \u003ca href=\"#code-snippet--sidenote-shortcode\"\u003ehere\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003eConfigure \u003cem\u003eox-hugo\u003c/em\u003e to export \u0026ldquo;sidenote\u0026rdquo; special block as a\nmarkdown-rendering shortcode.\u003c/li\u003e\n\u003cli\u003eConfigure whitespace to be trimmed around those blocks using\n\u003ccode\u003eorg-hugo-special-block-type-properties\u003c/code\u003e customization variable.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch3 id=\"org-special-block-sidenote\"\u003eOrg special block: \u003ccode\u003esidenote\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#org-special-block-sidenote\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eNow just use the \u003ccode\u003e#+begin_sidenote\u003c/code\u003e .. \u003ccode\u003e#+end_sidenote\u003c/code\u003e Org special\nblocks wherever you need sidenotes.\u003c/p\u003e\n","text":" Table of Contents Hugo shortcode Org mode special block Summary One-time configuration Org special block: sidenote The main focus of my previous post was the CSS for sidenotes. I also showed the companion HTML wrapper needed for that CSS to work. Here it is again for convenience:\n\u0026lt;span class=\u0026#34;sidenote-number\u0026#34;\u0026gt; \u0026lt;small class=\u0026#34;sidenote\u0026#34;\u0026gt; sidenote content \u0026lt;/small\u0026gt; \u0026lt;/span\u0026gt; Code Snippet 1: Sidenote HTML example Hugo shortcode\u0026nbsp;# Now .. You might be thinking that it\u0026rsquo;s not too practical to type that thing for each new sidenote. And you are right! That\u0026rsquo;s where we use the Hugo Shortcode feature. Hugo Shortcodes are like Org Macros that are typically used to insert some HTML template around the user entered content. If you look at the above snippet, the outer span and small tags are just HTML boilerplate that the user will need to type mechanically around each sidenote. So the shortcodes are perfect for solving this annoyance.\nIf we design a paired shortcode for this, the above HTML example will change to below:\n{{% sidenote %}} sidenote content {{% /sidenote %}} Code Snippet 2: Example use of the sidenote shortcode As you can see, this shortcode This is a markdown-rendering shortcode i.e. a shortcode with {{​% .. %}} instead of {{​\u0026lt; .. \u0026gt;}}. So the insides of this shortcode will passed on to the Hugo Markdown renderer. now enables the user to focus on content writing than on writing boilerplate HTML. And the definition of that shortcode is pretty simple as well:\n\u0026lt;span class=\u0026#34;sidenote-number\u0026#34;\u0026gt;\u0026lt;small class=\u0026#34;sidenote\u0026#34;\u0026gt;{{ .Inner }}\u0026lt;/small\u0026gt;\u0026lt;/span\u0026gt; Code Snippet 3: \"sidenote.html\" Hugo shortcode The only Hugo-templating syntax used here is {{ .Inner }}. You can read more about it here, but the tl;dr is that the .Inner holds whatever content the user entered inside the {{​% sidenote %}} and {{​% /sidenote %}} tags.\nOnce you save that shortcode snippet to a layouts/sidenote.html file in your Hugo site\u0026rsquo;s directory, you are ready to use it.\n🛑 But wait! 🛑\nOrg mode special block\u0026nbsp;# It would be a shame to populate the Org source of this blog with Hugo-specific shortcodes when I am using ox-hugo 😄.\nSo instead, we just use the plain-old Org special blocks and tell ox-hugo that this \u0026ldquo;sidenote\u0026rdquo; special block be exported as a markdown-rendering Hugo shortcode. I do that by just placing this at the top of my Org file See the Hugo Paired Shortcodes section in the ox-hugo manual to learn more about this. :\n#+hugo_paired_shortcodes: %sidenote Code Snippet 4: #+hugo_paired_shortcodes keyword for specifying \"shortcode\" special blocks .. and then writing a \u0026ldquo;sidenote\u0026rdquo; type Org special block:\nabc #+begin_sidenote example sidenote content #+end_sidenote def Code Snippet 5: Example use of the sidenote special block Normally, Org mode would insert a paragraph break where any Org block (like that sidenote special block) is used. So above would render as:\nabc\nexample sidenote content def\nBut I am pretty sure that nobody would render sidenote references in their main text as above\u0026mdash;instead, below is more normal 😄.\nabc example sidenote content def\nIn that normal example of the sidenote, ox-hugo trims the whitespace around the sidenote block. That is configured by customizing the org-hugo-special-block-type-properties variable:\n(with-eval-after-load \u0026#39;ox-hugo (add-to-list \u0026#39;org-hugo-special-block-type-properties \u0026#39;(\u0026#34;sidenote\u0026#34; . (:trim-pre t :trim-post t)))) Code Snippet 6: Whitespace trimming enabled by default for sidenote special blocks You can read more about this whitespace trimming feature in the ox-hugo manual.\nSummary\u0026nbsp;# One-time configuration\u0026nbsp;# Create and save a \u0026ldquo;sidenote\u0026rdquo; Hugo shortcode as shown here. Configure ox-hugo to export \u0026ldquo;sidenote\u0026rdquo; special block as a markdown-rendering shortcode. Configure whitespace to be trimmed around those blocks using org-hugo-special-block-type-properties customization variable. Org special block: sidenote\u0026nbsp;# Now just use the #+begin_sidenote .. #+end_sidenote Org special blocks wherever you need sidenotes.\n"},"name":"Sidenotes using ox-hugo","published":"2022-02-05T18:14:00-05:00","summary":"Adding sidenotes using a Hugo shortcode and ox-hugo.","type":"entry","url":"https://scripter.co/sidenotes-using-ox-hugo/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#problem\"\u003eProblem\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#action-plan\"\u003eAction Plan\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org-in-any-block-p\"\u003eAm I in an Org block?\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org-block-split\"\u003eIf so, split the block\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#M-return-split-block-dwim\"\u003eNow make \u003ckbd\u003eM-return\u003c/kbd\u003e do that\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#full-code\"\u003eFull code\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\n\u003ch2 id=\"problem\"\u003eProblem\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#problem\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIf I have a huge Org Src block, I\u0026rsquo;d like to split it into multiple Org\nSrc blocks so that I can write my explanations in-between.\u003c/p\u003e\n\u003cp\u003eSo I\u0026rsquo;d like to quickly split up:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;one\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;two\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003einto:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;one\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;two\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e.. \u003ca href=\"org-block-splitting-in-action.gif\"\u003elike this\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003e☝ \u003cem\u003eClick for animation.\u003c/em\u003e\u003c/p\u003e\n\n\u003ch2 id=\"action-plan\"\u003eAction Plan\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#action-plan\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003eWrite a function to return \u003cem\u003enon-nil\u003c/em\u003e if point is in \u003cstrong\u003eany\u003c/strong\u003e Org block\n\u0026ndash; Not just \u0026ldquo;src\u0026rdquo;, \u0026ldquo;example\u0026rdquo;, \u0026ldquo;export\u0026rdquo; or any of the inbuilt Org\nblocks.. but also any Org Special block like \u003ccode\u003e#+begin_foo .. #+end_foo\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eWrite a function that does this imagined block splitting.\u003c/li\u003e\n\u003cli\u003eOverload the \u003ckbd\u003eM-return\u003c/kbd\u003e binding so that this block splitting\nfunction gets called only when the point is inside an Org block\n(detected using that first function).\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003e\u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2018-08-26 Sun\u0026gt; \u003c/span\u003e\u003c/span\u003e Thanks to the comment by reader \u003cstrong\u003eMankoff\u003c/strong\u003e, I learnt\nabout the \u003ccode\u003eorg-babel-demarcate-block\u003c/code\u003e function (bound by default to\n\u003ckbd\u003eC-c C-v d\u003c/kbd\u003e and \u003ckbd\u003eC-c C-v C-d\u003c/kbd\u003e).\u003c/p\u003e\n\u003cp\u003eThis function varies from the solution in this post in at least two\nways:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eIt works only for Org Src blocks.\u003c/li\u003e\n\u003cli\u003eIt splits the block exactly at where the point is, whereas I would\nlike to always split only at EOL or BOL.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eBut I can see that \u003ccode\u003eorg-babel-demarcate-block\u003c/code\u003e can cover most of the\nblock splitting use cases.\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"org-in-any-block-p\"\u003eAm I in an Org block?\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#org-in-any-block-p\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eBefore venturing into writing this function, I looked at these\nexisting ones, but none did what I exactly wanted:\u003c/p\u003e\n\u003cdl\u003e\n\u003cdt\u003e\u003ccode\u003eorg-in-src-block-p\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eReturns \u003cem\u003enon-nil\u003c/em\u003e only if the point is in a\n\u003ccode\u003e#+begin_src .. #+end_src\u003c/code\u003e block; not when point is in any other\nOrg block.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eorg-in-block-p\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eReturns \u003cem\u003enon-nil\u003c/em\u003e only if the point is in one of\nthe pre-defined block names passed as a list (\u003ccode\u003e'(\u0026quot;src\u0026quot; \u0026quot;example\u0026quot; \u0026quot;quote\u0026quot; ..)\u003c/code\u003e). So this again won\u0026rsquo;t work as I cannot pre-define all\nOrg Special blocks.\u003c/dd\u003e\n\u003c/dl\u003e\n\u003cp\u003eSo I define the below \u003ccode\u003emodi/org-in-any-block-p\u003c/code\u003e function that returns\n\u003cem\u003enon-nil\u003c/em\u003e if the point is in-between any \u003ccode\u003e#+begin_FOOBAR .. #+end_FOOBAR\u003c/code\u003e. Thankfully, I was able to reuse a lot of logic from\nthe \u003ccode\u003eorg-between-regexps-p\u003c/code\u003e function (\u003ccode\u003eorg-in-block-p\u003c/code\u003e uses that\nfunction internally).\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--modi-org-in-any-block-p\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-in-any-block-p\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Return non-nil if the point is in any Org block.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eThe Org block can be *any*: src, example, verse, etc., even any\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eOrg Special block.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eThis function is heavily adapted from \u003c/span\u003e\u003cspan class=\"ss\"\u003e`org-between-regexps-p\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-match-data\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003epos\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003epoint\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ecase-fold-search\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eblock-begin-re\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;^[[:blank:]]*#\\\\+begin_\\\\(?1:.+?\\\\)\\\\(?: .*\\\\)*$\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003elimit-up\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eoutline-previous-heading\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003elimit-down\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eoutline-next-heading\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"nv\"\u003ebeg\u003c/span\u003e \u003cspan class=\"nv\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"c1\"\u003e;; Point is on a block when on BLOCK-BEGIN-RE or if\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"c1\"\u003e;; BLOCK-BEGIN-RE can be found before it...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-in-regexp\u003c/span\u003e \u003cspan class=\"nv\"\u003eblock-begin-re\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-backward\u003c/span\u003e \u003cspan class=\"nv\"\u003eblock-begin-re\u003c/span\u003e \u003cspan class=\"nv\"\u003elimit-up\u003c/span\u003e \u003cspan class=\"nb\"\u003e:noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003ebeg\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ematch-beginning\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"c1\"\u003e;; ... and BLOCK-END-RE after it...\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eblock-end-re\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;^[[:blank:]]*#\\\\+end_\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ematch-string-no-properties\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                         \u003cspan class=\"s\"\u003e\u0026#34;\\\\( .*\\\\)*$\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e               \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ematch-end\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e               \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-forward\u003c/span\u003e \u003cspan class=\"nv\"\u003eblock-end-re\u003c/span\u003e \u003cspan class=\"nv\"\u003elimit-down\u003c/span\u003e \u003cspan class=\"nb\"\u003e:noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ematch-end\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"nv\"\u003epos\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"c1\"\u003e;; ... without another BLOCK-BEGIN-RE in-between.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ematch-beginning\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enot\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-backward\u003c/span\u003e \u003cspan class=\"nv\"\u003eblock-begin-re\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e1+\u003c/span\u003e \u003cspan class=\"nv\"\u003ebeg\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nb\"\u003e:noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"c1\"\u003e;; Return value.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econs\u003c/span\u003e \u003cspan class=\"nv\"\u003ebeg\u003c/span\u003e \u003cspan class=\"nv\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e))))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--modi-org-in-any-block-p\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Function to check if point is in any Org block\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e(case-fold-search t)\u003c/code\u003e ensures that either \u003ccode\u003e#+BEGIN_ ..\u003c/code\u003e or \u003ccode\u003e#+begin_ ..\u003c/code\u003e match.\u003c/li\u003e\n\u003cli\u003eThe regular expression in \u003ccode\u003eblock-begin-re\u003c/code\u003e matches with\n\u003ccode\u003e\u0026quot;#+begin_src foo\u0026quot;\u003c/code\u003e or \u003ccode\u003e\u0026quot;   #+begin_src foo\u0026quot;\u003c/code\u003e or \u003ccode\u003e\u0026quot;#+BEGIN_EXAMPLE\u0026quot;\u003c/code\u003e\nor \u003ccode\u003e\u0026quot;#+begin_FOOBAR\u0026quot;\u003c/code\u003e or ..\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003elimit-up\u003c/code\u003e and \u003ccode\u003elimit-down\u003c/code\u003e are set to the buffer locations of\nthe previous and next Org headings. The following regexp searches\nare limited to happen in those bounds for better performance.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003eblock-end-re\u003c/code\u003e is dynamically constructed based on the string\nmatched using \u003ccode\u003eblock-begin-re\u003c/code\u003e. This is so that if \u003ccode\u003e\u0026quot;#+begin_quote\u0026quot;\u003c/code\u003e\nis found initially, it matches the block ending with specifically\n\u003ccode\u003e\u0026quot;#+end_quote\u0026quot;\u003c/code\u003e and not something like \u003ccode\u003e\u0026quot;#+end_src\u0026quot;\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003cem\u003enil\u003c/em\u003e is returned if the point is not between \u003ccode\u003e#+begin_FOOBAR .. #+end_FOOBAR\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!--listend--\u003e\n\u003cdl\u003e\n\u003cdt\u003eCaveat\u003c/dt\u003e\n\u003cdd\u003eI haven\u0026rsquo;t gone extra lengths to support nested block cases,\nspecifically where the point is outside the inner-most\nblock, but still inside the outer block:\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e#+begin_src org\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e▮\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e#+begin_src emacs-lisp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e(message \u0026#34;hello!\u0026#34;)\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e#+end_src\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e#+end_src\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/dd\u003e\n\u003c/dl\u003e\n\n\u003ch2 id=\"org-block-split\"\u003eIf so, split the block\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#org-block-split\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eWith the \u0026ldquo;point in an Org block\u0026rdquo; detection working, I now needed the\nsplit to happen with these rules:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eIf the point is anywhere on the line, but not at the beginning of\nthe line (BOL),\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eGo to the end of the line, and then split the block.\u003c/p\u003e\n\u003cp\u003eSo if the point\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e is after the first \u003ccode\u003emessage\u003c/code\u003e identifier,\nor at the end of that first \u003ccode\u003emessage\u003c/code\u003e line:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;one\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"err\"\u003e▮\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;two\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eSplit the block at the point \u003cstrong\u003eafter\u003c/strong\u003e \u003ccode\u003e(message \u0026quot;one\u0026quot;)\u003c/code\u003e and move\nthe point to between the split blocks:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;one\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e▮\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;two\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eOtherwise (if point is at BOL),\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eSplit the block exactly at that point.\u003c/p\u003e\n\u003cp\u003eSo if the point is at the beginning of the second \u003ccode\u003emessage\u003c/code\u003e line:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;one\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"err\"\u003e▮\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;two\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eSplit the block at the point \u003cstrong\u003ebefore\u003c/strong\u003e \u003ccode\u003e(message \u0026quot;two\u0026quot;)\u003c/code\u003e and move\nthe point to between the split blocks:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;one\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e▮\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+begin_src \u003c/span\u003e\u003cspan class=\"cs\"\u003eemacs-lisp\u003c/span\u003e\u003cspan class=\"c\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;two\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c\"\u003e#+end_src\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eSo here\u0026rsquo;s the code that follows that spec:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--modi-org-split-block\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-split-block\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Sensibly split the current Org block at point.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/org-in-any-block-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-match-data\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-restriction\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ewiden\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003ecase-fold-search\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eat-bol\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebolp\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"nv\"\u003eblock-start\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"nv\"\u003eblock-end\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-backward\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;^\\\\(?1:[[:blank:]]*#\\\\+begin_.+?\\\\)\\\\(?: .*\\\\)*$\u0026#34;\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eblock-start\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ematch-string-no-properties\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eblock-end\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"s\"\u003e\u0026#34;begin_\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;end_\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e;Replaces \u0026#34;begin_\u0026#34; with \u0026#34;end_\u0026#34;, \u0026#34;BEGIN_\u0026#34; with \u0026#34;END_\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ematch-string-no-properties\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e;; Go to the end of current line, if not at the BOL\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eunless\u003c/span\u003e \u003cspan class=\"nv\"\u003eat-bol\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eend-of-line\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003einsert\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"nv\"\u003eat-bol\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"nv\"\u003eblock-end\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"s\"\u003e\u0026#34;\\n\\n\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"nv\"\u003eblock-start\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"nv\"\u003eat-bol\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\\n\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e;; Go to the line before the inserted \u0026#34;#+begin_ ..\u0026#34; line\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebeginning-of-line\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"nv\"\u003eat-bol\u003c/span\u003e \u003cspan class=\"mi\"\u003e-1\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Point is not in an Org block\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--modi-org-split-block\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Function to split the current Org block in sensible fashion\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003eThe regexp for extracting \u003ccode\u003eblock-start\u003c/code\u003e is the same as\n\u003ccode\u003eblock-begin-re\u003c/code\u003e in \u003ca href=\"#code-snippet--modi-org-in-any-block-p\"\u003eCode Snippet 1\u003c/a\u003e, but with\ndifferent sub-grouping.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003eblock-end\u003c/code\u003e string is derived from sub-group 1 of \u003ccode\u003eblock-start\u003c/code\u003e\nstring \u0026ndash; just replacing \u0026ldquo;begin_\u0026rdquo; with \u0026ldquo;end_\u0026rdquo;.\u003c/li\u003e\n\u003cli\u003eAnd then based on if the point was initially at BOL (\u003ccode\u003eat-bol\u003c/code\u003e), the\ninsertion of newlines and movement of point is done accordingly.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"M-return-split-block-dwim\"\u003eNow make \u003ckbd\u003eM-return\u003c/kbd\u003e do that\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#M-return-split-block-dwim\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eWith these two functions evaluated, \u003ccode\u003eM-x modi/org-split-block\u003c/code\u003e will\nwork right away.\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e    But where\u0026rsquo;s the fun in that‽\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eI needed to have the Org block splitting happen with an intuitive\nbinding \u0026mdash; like \u003ckbd\u003eM-return\u003c/kbd\u003e.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eBy default, \u003ckbd\u003eM-return\u003c/kbd\u003e is used to either create new headings, or do\nother things like insert an item, wrap a region in table, etc. based\non the context. See the doc-string of \u003ccode\u003eorg-meta-return\u003c/code\u003e (function\nbound to this key by default) for more info.\u003c/li\u003e\n\u003cli\u003eBut it doesn\u0026rsquo;t have a context for \u0026ldquo;point in an Org block\u0026rdquo;. So it\ntries to create a heading when inside a block too, which doesn\u0026rsquo;t\nmake much sense.\u003c/li\u003e\n\u003cli\u003eSo fix that by adding that context.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eSo I \u003cstrong\u003eadvise\u003c/strong\u003e \u003ccode\u003eorg-meta-return\u003c/code\u003e to call \u003ccode\u003emodi/org-split-block\u003c/code\u003e when\nthe point is inside an Org block.\u003c/p\u003e\n\u003cp\u003eThe advising function \u003ccode\u003emodi/org-meta-return\u003c/code\u003e is the same as the\nadvised function \u003ccode\u003eorg-meta-return\u003c/code\u003e (as of \u003cspan class=\"timestamp-wrapper\"\u003e\u003cspan class=\"timestamp\"\u003e\u0026lt;2018-08-26 Sun\u0026gt;\u003c/span\u003e\u003c/span\u003e), except\nthat a new context \u003ccode\u003e(modi/org-in-any-block-p)\u003c/code\u003e is added.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eYou can tweak the precedence of this new context by moving the\n\u003ccode\u003e((modi/org-in-any-block-p) #'modi/org-split-block)\u003c/code\u003e form in that\n\u003ccode\u003econd\u003c/code\u003e form.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--modi-org-meta-return\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/org-meta-return\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kp\"\u003e\u0026amp;optional\u003c/span\u003e \u003cspan class=\"nv\"\u003earg\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Insert a new heading or wrap a region in a table.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eCalls \u003c/span\u003e\u003cspan class=\"ss\"\u003e`org-insert-heading\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e, \u003c/span\u003e\u003cspan class=\"ss\"\u003e`org-insert-item\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\u003c/span\u003e\u003cspan class=\"ss\"\u003e`org-table-wrap-region\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e, or \u003c/span\u003e\u003cspan class=\"ss\"\u003e`modi/org-split-block\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e depending on\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003econtext.  When called with an argument, unconditionally call\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\u003c/span\u003e\u003cspan class=\"ss\"\u003e`org-insert-heading\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;P\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-check-before-invisible-edit\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;insert\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003erun-hook-with-args-until-success\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;org-metareturn-hook\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecall-interactively\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003earg\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-insert-heading\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-at-table-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-table-wrap-region\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-in-item-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-insert-item\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/org-in-any-block-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/org-split-block\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eorg-insert-heading\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvice-add\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;org-meta-return\u003c/span\u003e \u003cspan class=\"nb\"\u003e:override\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/org-meta-return\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--modi-org-meta-return\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  Advising \u003ccode\u003eorg-meta-return\u003c/code\u003e to add context of point being inside any Org block\n\u003c/div\u003e\n\u003cp\u003eNow with the point in \u003cstrong\u003eany\u003c/strong\u003e Org block, \u003ckbd\u003eM-return\u003c/kbd\u003e away!\u003c/p\u003e\n\n\u003ch2 id=\"full-code\"\u003eFull code\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#full-code\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eLook for the source of \u003ccode\u003emodi/org-split-block\u003c/code\u003e (and dependent\nfunctions) added to \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-org.el\"\u003e\u003ccode\u003esetup-org.el\u003c/code\u003e\u003c/a\u003e in my Emacs config.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eThe point is denoted by the \u003cem\u003eBLACK VERTICAL RECTANGLE\u003c/em\u003e unicode\nchar (▮).\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","text":" Table of Contents Problem Action Plan Am I in an Org block? If so, split the block Now make M-return do that Full code Problem\u0026nbsp;# If I have a huge Org Src block, I\u0026rsquo;d like to split it into multiple Org Src blocks so that I can write my explanations in-between.\nSo I\u0026rsquo;d like to quickly split up:\n#+begin_src emacs-lisp (message \u0026#34;one\u0026#34;) (message \u0026#34;two\u0026#34;) #+end_src into:\n#+begin_src emacs-lisp (message \u0026#34;one\u0026#34;) #+end_src #+begin_src emacs-lisp (message \u0026#34;two\u0026#34;) #+end_src .. like this.\n☝ Click for animation.\nAction Plan\u0026nbsp;# Write a function to return non-nil if point is in any Org block \u0026ndash; Not just \u0026ldquo;src\u0026rdquo;, \u0026ldquo;example\u0026rdquo;, \u0026ldquo;export\u0026rdquo; or any of the inbuilt Org blocks.. but also any Org Special block like #+begin_foo .. #+end_foo. Write a function that does this imagined block splitting. Overload the M-return binding so that this block splitting function gets called only when the point is inside an Org block (detected using that first function). \u0026lt;2018-08-26 Sun\u0026gt; Thanks to the comment by reader Mankoff, I learnt about the org-babel-demarcate-block function (bound by default to C-c C-v d and C-c C-v C-d).\nThis function varies from the solution in this post in at least two ways:\nIt works only for Org Src blocks. It splits the block exactly at where the point is, whereas I would like to always split only at EOL or BOL. But I can see that org-babel-demarcate-block can cover most of the block splitting use cases.\nAm I in an Org block?\u0026nbsp;# Before venturing into writing this function, I looked at these existing ones, but none did what I exactly wanted:\norg-in-src-block-p Returns non-nil only if the point is in a #+begin_src .. #+end_src block; not when point is in any other Org block. org-in-block-p Returns non-nil only if the point is in one of the pre-defined block names passed as a list ('(\u0026quot;src\u0026quot; \u0026quot;example\u0026quot; \u0026quot;quote\u0026quot; ..)). So this again won\u0026rsquo;t work as I cannot pre-define all Org Special blocks. So I define the below modi/org-in-any-block-p function that returns non-nil if the point is in-between any #+begin_FOOBAR .. #+end_FOOBAR. Thankfully, I was able to reuse a lot of logic from the org-between-regexps-p function (org-in-block-p uses that function internally).\n(defun modi/org-in-any-block-p () \u0026#34;Return non-nil if the point is in any Org block. The Org block can be *any*: src, example, verse, etc., even any Org Special block. This function is heavily adapted from `org-between-regexps-p\u0026#39;.\u0026#34; (save-match-data (let ((pos (point)) (case-fold-search t) (block-begin-re \u0026#34;^[[:blank:]]*#\\\\+begin_\\\\(?1:.+?\\\\)\\\\(?: .*\\\\)*$\u0026#34;) (limit-up (save-excursion (outline-previous-heading))) (limit-down (save-excursion (outline-next-heading))) beg end) (save-excursion ;; Point is on a block when on BLOCK-BEGIN-RE or if ;; BLOCK-BEGIN-RE can be found before it... (and (or (org-in-regexp block-begin-re) (re-search-backward block-begin-re limit-up :noerror)) (setq beg (match-beginning 0)) ;; ... and BLOCK-END-RE after it... (let ((block-end-re (concat \u0026#34;^[[:blank:]]*#\\\\+end_\u0026#34; (match-string-no-properties 1) \u0026#34;\\\\( .*\\\\)*$\u0026#34;))) (goto-char (match-end 0)) (re-search-forward block-end-re limit-down :noerror)) (\u0026gt; (setq end (match-end 0)) pos) ;; ... without another BLOCK-BEGIN-RE in-between. (goto-char (match-beginning 0)) (not (re-search-backward block-begin-re (1+ beg) :noerror)) ;; Return value. (cons beg end)))))) Code Snippet 1: Function to check if point is in any Org block (case-fold-search t) ensures that either #+BEGIN_ .. or #+begin_ .. match. The regular expression in block-begin-re matches with \u0026quot;#+begin_src foo\u0026quot; or \u0026quot; #+begin_src foo\u0026quot; or \u0026quot;#+BEGIN_EXAMPLE\u0026quot; or \u0026quot;#+begin_FOOBAR\u0026quot; or .. The limit-up and limit-down are set to the buffer locations of the previous and next Org headings. The following regexp searches are limited to happen in those bounds for better performance. The block-end-re is dynamically constructed based on the string matched using block-begin-re. This is so that if \u0026quot;#+begin_quote\u0026quot; is found initially, it matches the block ending with specifically \u0026quot;#+end_quote\u0026quot; and not something like \u0026quot;#+end_src\u0026quot;. nil is returned if the point is not between #+begin_FOOBAR .. #+end_FOOBAR. Caveat I haven\u0026rsquo;t gone extra lengths to support nested block cases, specifically where the point is outside the inner-most block, but still inside the outer block: #+begin_src org ▮ #+begin_src emacs-lisp (message \u0026#34;hello!\u0026#34;) #+end_src #+end_src If so, split the block\u0026nbsp;# With the \u0026ldquo;point in an Org block\u0026rdquo; detection working, I now needed the split to happen with these rules:\nIf the point is anywhere on the line, but not at the beginning of the line (BOL),\nGo to the end of the line, and then split the block.\nSo if the point1 is after the first message identifier, or at the end of that first message line:\n#+begin_src emacs-lisp (message \u0026#34;one\u0026#34;)▮ (message \u0026#34;two\u0026#34;) #+end_src Split the block at the point after (message \u0026quot;one\u0026quot;) and move the point to between the split blocks:\n#+begin_src emacs-lisp (message \u0026#34;one\u0026#34;) #+end_src ▮ #+begin_src emacs-lisp (message \u0026#34;two\u0026#34;) #+end_src Otherwise (if point is at BOL),\nSplit the block exactly at that point.\nSo if the point is at the beginning of the second message line:\n#+begin_src emacs-lisp (message \u0026#34;one\u0026#34;) ▮(message \u0026#34;two\u0026#34;) #+end_src Split the block at the point before (message \u0026quot;two\u0026quot;) and move the point to between the split blocks:\n#+begin_src emacs-lisp (message \u0026#34;one\u0026#34;) #+end_src ▮ #+begin_src emacs-lisp (message \u0026#34;two\u0026#34;) #+end_src So here\u0026rsquo;s the code that follows that spec:\n(defun modi/org-split-block () \u0026#34;Sensibly split the current Org block at point.\u0026#34; (interactive) (if (modi/org-in-any-block-p) (save-match-data (save-restriction (widen) (let ((case-fold-search t) (at-bol (bolp)) block-start block-end) (save-excursion (re-search-backward \u0026#34;^\\\\(?1:[[:blank:]]*#\\\\+begin_.+?\\\\)\\\\(?: .*\\\\)*$\u0026#34; nil nil 1) (setq block-start (match-string-no-properties 0)) (setq block-end (replace-regexp-in-string \u0026#34;begin_\u0026#34; \u0026#34;end_\u0026#34; ;Replaces \u0026#34;begin_\u0026#34; with \u0026#34;end_\u0026#34;, \u0026#34;BEGIN_\u0026#34; with \u0026#34;END_\u0026#34; (match-string-no-properties 1)))) ;; Go to the end of current line, if not at the BOL (unless at-bol (end-of-line 1)) (insert (concat (if at-bol \u0026#34;\u0026#34; \u0026#34;\\n\u0026#34;) block-end \u0026#34;\\n\\n\u0026#34; block-start (if at-bol \u0026#34;\\n\u0026#34; \u0026#34;\u0026#34;))) ;; Go to the line before the inserted \u0026#34;#+begin_ ..\u0026#34; line (beginning-of-line (if at-bol -1 0))))) (message \u0026#34;Point is not in an Org block\u0026#34;))) Code Snippet 2: Function to split the current Org block in sensible fashion The regexp for extracting block-start is the same as block-begin-re in Code Snippet 1, but with different sub-grouping. The block-end string is derived from sub-group 1 of block-start string \u0026ndash; just replacing \u0026ldquo;begin_\u0026rdquo; with \u0026ldquo;end_\u0026rdquo;. And then based on if the point was initially at BOL (at-bol), the insertion of newlines and movement of point is done accordingly. Now make M-return do that\u0026nbsp;# With these two functions evaluated, M-x modi/org-split-block will work right away.\nBut where\u0026rsquo;s the fun in that‽\nI needed to have the Org block splitting happen with an intuitive binding \u0026mdash; like M-return.\nBy default, M-return is used to either create new headings, or do other things like insert an item, wrap a region in table, etc. based on the context. See the doc-string of org-meta-return (function bound to this key by default) for more info. But it doesn\u0026rsquo;t have a context for \u0026ldquo;point in an Org block\u0026rdquo;. So it tries to create a heading when inside a block too, which doesn\u0026rsquo;t make much sense. So fix that by adding that context. So I advise org-meta-return to call modi/org-split-block when the point is inside an Org block.\nThe advising function modi/org-meta-return is the same as the advised function org-meta-return (as of \u0026lt;2018-08-26 Sun\u0026gt;), except that a new context (modi/org-in-any-block-p) is added.\nYou can tweak the precedence of this new context by moving the ((modi/org-in-any-block-p) #'modi/org-split-block) form in that cond form.\n(defun modi/org-meta-return (\u0026amp;optional arg) \u0026#34;Insert a new heading or wrap a region in a table. Calls `org-insert-heading\u0026#39;, `org-insert-item\u0026#39;, `org-table-wrap-region\u0026#39;, or `modi/org-split-block\u0026#39; depending on context. When called with an argument, unconditionally call `org-insert-heading\u0026#39;.\u0026#34; (interactive \u0026#34;P\u0026#34;) (org-check-before-invisible-edit \u0026#39;insert) (or (run-hook-with-args-until-success \u0026#39;org-metareturn-hook) (call-interactively (cond (arg #\u0026#39;org-insert-heading) ((org-at-table-p) #\u0026#39;org-table-wrap-region) ((org-in-item-p) #\u0026#39;org-insert-item) ((modi/org-in-any-block-p) #\u0026#39;modi/org-split-block) (t #\u0026#39;org-insert-heading))))) (advice-add \u0026#39;org-meta-return :override #\u0026#39;modi/org-meta-return) Code Snippet 3: Advising org-meta-return to add context of point being inside any Org block Now with the point in any Org block, M-return away!\nFull code\u0026nbsp;# Look for the source of modi/org-split-block (and dependent functions) added to setup-org.el in my Emacs config.\nThe point is denoted by the BLACK VERTICAL RECTANGLE unicode char (▮).\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"Splitting an Org block into two","published":"2018-08-22T17:47:00-04:00","summary":"I ventured out to start writing about a 100+ line Emacs Lisp snippet in my config, and then I thought \u0026mdash; Wouldn\u0026rsquo;t it be nice if I can quickly split out that huge snippet into smaller Org Src blocks?\nAnd so this blog post happened.\n","type":"entry","url":"https://scripter.co/splitting-an-org-block-into-two/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#a-super-quick-intro-to-org-mode\"\u003eA super-quick intro to Org mode\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#inconsistency\"\u003eInconsistency\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#the-right-way\"\u003eThe right way\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#reference\"\u003eReference\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\n\u003ch2 id=\"a-super-quick-intro-to-org-mode\"\u003eA super-quick intro to Org mode\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#a-super-quick-intro-to-org-mode\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca href=\"https://orgmode.org\"\u003eOrg mode\u003c/a\u003e is a fantastic major mode for Emacs, and people use it for\nall sorts of things like keeping notes, maintaining TODO lists,\nwriting documentation, or even blogging\u0026mdash;like I am doing here.\u003c/p\u003e\n\n\u003ch2 id=\"inconsistency\"\u003eInconsistency\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#inconsistency\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eEvery now and then, I would see \u0026ldquo;Org mode\u0026rdquo; and related phrases written\nin the \u0026ldquo;wild\u0026rdquo; (like blogs, Reddit posts, tweets) as \u003cem\u003eOrg-mode\u003c/em\u003e,\n\u003cem\u003eorg-manual\u003c/em\u003e, \u003cem\u003eorg file\u003c/em\u003e, etc., with a mix-and-match of cases and\nhyphens.\u003c/p\u003e\n\u003cp\u003eSo here is an attempt to familiarize more people with the\ndocumentation standard for referring to \u0026ldquo;Org\u0026rdquo; stuff. Below I am\nquoting the text from the official Org Documentation Standards:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cul\u003e\n\u003cli\u003ePrefer \u0026ldquo;Org mode\u0026rdquo; to \u0026ldquo;Org-mode\u0026rdquo; or \u0026ldquo;org-mode\u0026rdquo;. This is simply\nbecause it reflects an existing convention in \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/emacs/index.html\"\u003eThe Emacs Manual\u003c/a\u003e which\nconsistently documents mode names in this form - \u0026ldquo;Text mode\u0026rdquo;,\n\u0026ldquo;Outline mode\u0026rdquo;, \u0026ldquo;Mail mode\u0026rdquo;, etc.\u003c/li\u003e\n\u003cli\u003eLikewise refer, if at all possible, to \u0026ldquo;Org file or \u0026ldquo;Org buffer\u0026rdquo;\nmeaning with, great generality, any file or buffer which requires\nuse of some part of Org to edit it properly.\u003c/li\u003e\n\u003cli\u003eOrg uses \u0026ldquo;org-\u0026hellip;\u0026rdquo; to ring fence a name space for itself in the\nEmacs code base. This is obviously retained in code snippets.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/blockquote\u003e\n\n\u003ch2 id=\"the-right-way\"\u003eThe right way\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#the-right-way\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cdiv class=\"org-center\"\u003e\n\u003cp\u003e\u003cstrong\u003eOrg mode\u003c/strong\u003e, \u003cstrong\u003eOrg manual\u003c/strong\u003e, \u003cstrong\u003eOrg file\u003c/strong\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eOnly in the Elisp code, is it called \u003ccode\u003eorg-mode\u003c/code\u003e, because it is a\n\u003cem\u003emajor mode\u003c/em\u003e, and has to be named so in code by convention, and for\nits separate \u003ccode\u003eorg-*\u003c/code\u003e name space.\u003c/p\u003e\n\u003cp\u003eBut for blogging, documentation, etc. \u0026ndash;\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e    \u003cstrong\u003eOrg foo\u003c/strong\u003e it is.\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"reference\"\u003eReference\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#reference\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://code.orgmode.org/bzg/org-mode/src/master/doc/Documentation_Standards.org#referencing-systems-packages-modes-and-much-else\"\u003eOrg mode Documentation Standard\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","text":" Table of Contents A super-quick intro to Org mode Inconsistency The right way Reference A super-quick intro to Org mode\u0026nbsp;# Org mode is a fantastic major mode for Emacs, and people use it for all sorts of things like keeping notes, maintaining TODO lists, writing documentation, or even blogging\u0026mdash;like I am doing here.\nInconsistency\u0026nbsp;# Every now and then, I would see \u0026ldquo;Org mode\u0026rdquo; and related phrases written in the \u0026ldquo;wild\u0026rdquo; (like blogs, Reddit posts, tweets) as Org-mode, org-manual, org file, etc., with a mix-and-match of cases and hyphens.\nSo here is an attempt to familiarize more people with the documentation standard for referring to \u0026ldquo;Org\u0026rdquo; stuff. Below I am quoting the text from the official Org Documentation Standards:\nPrefer \u0026ldquo;Org mode\u0026rdquo; to \u0026ldquo;Org-mode\u0026rdquo; or \u0026ldquo;org-mode\u0026rdquo;. This is simply because it reflects an existing convention in The Emacs Manual which consistently documents mode names in this form - \u0026ldquo;Text mode\u0026rdquo;, \u0026ldquo;Outline mode\u0026rdquo;, \u0026ldquo;Mail mode\u0026rdquo;, etc. Likewise refer, if at all possible, to \u0026ldquo;Org file or \u0026ldquo;Org buffer\u0026rdquo; meaning with, great generality, any file or buffer which requires use of some part of Org to edit it properly. Org uses \u0026ldquo;org-\u0026hellip;\u0026rdquo; to ring fence a name space for itself in the Emacs code base. This is obviously retained in code snippets. The right way\u0026nbsp;# Org mode, Org manual, Org file\nOnly in the Elisp code, is it called org-mode, because it is a major mode, and has to be named so in code by convention, and for its separate org-* name space.\nBut for blogging, documentation, etc. \u0026ndash;\nOrg foo it is.\nReference\u0026nbsp;# Org mode Documentation Standard "},"name":"  How do I write \"Org mode\"?\n  ","published":"2018-05-21T16:35:00-04:00","summary":"You write it just like that in the title \u0026mdash; \u0026ldquo;Org\u0026rdquo; with capital \u0026ldquo;O\u0026rdquo;,\nand then lower-case \u0026ldquo;mode\u0026rdquo; separated by a space.","type":"entry","url":"https://scripter.co/how-do-i-write-org-mode/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#json-docs\"\u003eJSON Docs\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#devdocs-dot-io\"\u003eDevdocs.io\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#christopher-wellon-s-devdocs-lookup\"\u003eChristopher Wellon\u0026rsquo;s \u003ccode\u003edevdocs-lookup\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#making-devdocs-lookup-dwim\"\u003eMaking \u003ccode\u003edevdocs-lookup\u003c/code\u003e DWIM\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#using-devdocs-lookup\"\u003eUsing \u003ccode\u003edevdocs-lookup\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#devdocs-lookup-demo\"\u003eDemo\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#devdocs-lookup-code\"\u003eCode\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eNim lang has good documentation for all its \u003ccode\u003estdlib\u003c/code\u003e functions\n\u003ca href=\"https://nim-lang.org/docs/lib.html\"\u003eonline\u003c/a\u003e. But the Emacs user in me does not like to switch back and\nforth between the Nim code in Emacs buffers and the docs outside in an\nexternal browser.\u003c/p\u003e\n\u003cp\u003eWell.. a solution to that, that this post is about, \u003cem\u003estill\u003c/em\u003e needs one\nto look up the Nim docs in an external browser.. but the workflow is a\nbit better \u0026mdash; You don\u0026rsquo;t need to manually launch the doc site, and you\ndon\u0026rsquo;t need to then manually type in the search query.\u003c/p\u003e\n\u003cdiv class=\"note\"\u003e\n\u003cp\u003eIf you want to skip the history and code analysis, you can directly\njump to the \u003ca href=\"#devdocs-lookup-demo\"\u003eDemo\u003c/a\u003e or the \u003ca href=\"#devdocs-lookup-code\"\u003eFinal Code\u003c/a\u003e.\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"json-docs\"\u003eJSON Docs\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#json-docs\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eI tried asking folks on \u003ca href=\"https://www.reddit.com/r/nim/comments/8ia1xk/is_there_a_way_to_access_the_nim_docs_from_the/\"\u003er/nim\u003c/a\u003e if there was a good solution for\n\u003cem\u003ein-editor\u003c/em\u003e Nim doc access. \u003ca href=\"https://www.reddit.com/user/PMunch\"\u003e\u003cstrong\u003e/u/PMunch\u003c/strong\u003e\u003c/a\u003e from Reddit gave a wonderful\n\u003ca href=\"https://www.reddit.com/r/nim/comments/8ia1xk/is_there_a_way_to_access_the_nim_docs_from_the/dyqcb2m/\"\u003esolution\u003c/a\u003e\u0026mdash;To generate JSON docs for the Nim stdlib, and then parse\nthose to display the docs within Emacs.\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e    I would love that solution!\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003e.. just that I don\u0026rsquo;t know how to get a nice single \u003ccode\u003e.json\u003c/code\u003e for the\nwhole of Nim documentation.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eIf someone knows how to do that, please let me know.\u003c/em\u003e\u003c/p\u003e\n\n\u003ch2 id=\"devdocs-dot-io\"\u003eDevdocs.io\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#devdocs-dot-io\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eSo I continued my search online.. I was looking if someone had already\nimplemented a way to access Nim docs from the command line, and that\nsomehow led me to \u003ca href=\"https://devdocs.io/nim/\"\u003ehttps://devdocs.io/nim/\u003c/a\u003e!\u003c/p\u003e\n\u003cp\u003eAnd after searching further for \u003cem\u003e\u0026ldquo;devdocs Emacs\u0026rdquo;\u003c/em\u003e, I found these two\nEmacs packages:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/xuchunyang/DevDocs.el\"\u003ehttps://github.com/xuchunyang/DevDocs.el\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/skeeto/devdocs-lookup\"\u003ehttps://github.com/skeeto/devdocs-lookup\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch3 id=\"christopher-wellon-s-devdocs-lookup\"\u003eChristopher Wellon\u0026rsquo;s \u003ccode\u003edevdocs-lookup\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#christopher-wellon-s-devdocs-lookup\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eAfter reviewing the two packages, I decided to build my solution\nfurther upon the \u003ccode\u003edevdocs-lookup\u003c/code\u003e package\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e by \u003cem\u003eChristopher\nWellons\u003c/em\u003e aka \u003ca href=\"https://www.github.com/skeeto\"\u003e\u003cstrong\u003e@skeeto\u003c/strong\u003e\u003c/a\u003e from GitHub.\u003c/p\u003e\n\u003cp\u003eHere\u0026rsquo;s why \u0026mdash;\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eHe first fetches the whole JSON \u003cem\u003esearch index\u003c/em\u003e (\u003ca href=\"#org-coderef--e4865e-5\"\u003eline 5\u003c/a\u003e) from\ndocs.devdocs.io for the picked \u0026ldquo;subject\u0026rdquo; (which would be \u0026ldquo;Nim\u0026rdquo; for\nthis post). So the search index for Nim documentation would be at\n\u003ca href=\"https://docs.devdocs.io/nim/index.json\"\u003ehttps://docs.devdocs.io/nim/index.json\u003c/a\u003e\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e.\u003c/p\u003e\n\u003cp\u003eThe retrieved JSON is then parsed using \u003ccode\u003ejson-read\u003c/code\u003e (\u003ca href=\"#org-coderef--e4865e-13\"\u003eline\n13\u003c/a\u003e).\n\u003ca id=\"code-snippet--devdocs-index\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-1\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-1\"\u003e 1\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-2\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-2\"\u003e 2\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-3\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-3\"\u003e 3\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-4\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-4\"\u003e 4\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-5\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-5\"\u003e 5\u003c/a\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-6\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-6\"\u003e 6\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-7\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-7\"\u003e 7\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-8\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-8\"\u003e 8\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-9\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-9\"\u003e 9\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-10\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-10\"\u003e10\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-11\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-11\"\u003e11\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-12\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-12\"\u003e12\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-13\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-13\"\u003e13\u003c/a\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-14\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-14\"\u003e14\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-15\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-15\"\u003e15\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-16\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-16\"\u003e16\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-17\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-17\"\u003e17\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-18\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-18\"\u003e18\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-19\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-19\"\u003e19\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e4865e-20\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e4865e-20\"\u003e20\u003c/a\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-index\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"kp\"\u003e\u0026amp;optional\u003c/span\u003e \u003cspan class=\"nv\"\u003ecallback\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Return the devdocs.io index for SUBJECT, optionally async via CALLBACK.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ecl-declare\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003especial\u003c/span\u003e \u003cspan class=\"nv\"\u003eurl-http-end-of-headers\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eindex\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egethash\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-index\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eurl\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s/%s/index.json\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-base-index-url\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nv\"\u003eindex\u003c/span\u003e \u003cspan class=\"nv\"\u003ecallback\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003ecallback\u003c/span\u003e \u003cspan class=\"nv\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nv\"\u003eindex\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enot\u003c/span\u003e \u003cspan class=\"nv\"\u003ecallback\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"nv\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enot\u003c/span\u003e \u003cspan class=\"nv\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enot\u003c/span\u003e \u003cspan class=\"nv\"\u003ecallback\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewith-current-buffer\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eurl-retrieve-synchronously\u003c/span\u003e \u003cspan class=\"nv\"\u003eurl\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"nv\"\u003eurl-http-end-of-headers\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetf\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egethash\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-index\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ejson-read\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003enot\u003c/span\u003e \u003cspan class=\"nv\"\u003eindex\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003ecallback\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eurl-retrieve\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"nv\"\u003eurl\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elambda\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e_\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"nv\"\u003eurl-http-end-of-headers\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetf\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egethash\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-index\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ejson-read\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003ecallback\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egethash\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-index\u003c/span\u003e\u003cspan class=\"p\"\u003e))))))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--devdocs-index\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Function to fetch the search index from devdocs.io and parse the JSON\n\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThe \u003ccode\u003ename\u003c/code\u003e and \u003ccode\u003epath\u003c/code\u003e properties from the parsed JSON are then\nstored in an association list on lines \u003ca href=\"#org-coderef--6fba6a-4\"\u003e4\u003c/a\u003e and \u003ca href=\"#org-coderef--6fba6a-5\"\u003e5\u003c/a\u003e.\n\u003ca id=\"code-snippet--devdocs-entries\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\" id=\"org-coderef--6fba6a-1\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--6fba6a-1\"\u003e1\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--6fba6a-2\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--6fba6a-2\"\u003e2\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--6fba6a-3\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--6fba6a-3\"\u003e3\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\" id=\"org-coderef--6fba6a-4\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--6fba6a-4\"\u003e4\u003c/a\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\" id=\"org-coderef--6fba6a-5\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--6fba6a-5\"\u003e5\u003c/a\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-entries\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Return an association list of the entries in SUBJECT.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ecl-loop\u003c/span\u003e \u003cspan class=\"nv\"\u003efor\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e \u003cspan class=\"nv\"\u003eacross\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecdr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eassoc\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;entries\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-index\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"nv\"\u003ecollect\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econs\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecdr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eassoc\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;name\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e                         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecdr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eassoc\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;path\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--devdocs-entries\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Function to store the \u003ccode\u003ename\u003c/code\u003e and \u003ccode\u003epath\u003c/code\u003e properties to alists\n\u003c/div\u003e\n\u003cp\u003eSo a JSON entry like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;os.walkDirRec\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026#34;path\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;os#walkDirRec.i,string\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026#34;type\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;os\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003ewould translate to this Emacs-Lisp alist element:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;os.walkDirRec\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e.\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;os#walkDirRec.i,string\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThen the \u003cem\u003elist\u003c/em\u003e of all the \u003cem\u003ecar\u003c/em\u003e\u0026rsquo;s of such elements is used to\ncreate a collection of entries for completion (\u003ca href=\"#org-coderef--25a1bb-3\"\u003eline 3\u003c/a\u003e).\n\u003ca id=\"code-snippet--devdocs-read-entry\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\" id=\"org-coderef--25a1bb-1\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--25a1bb-1\"\u003e1\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--25a1bb-2\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--25a1bb-2\"\u003e2\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\" id=\"org-coderef--25a1bb-3\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--25a1bb-3\"\u003e3\u003c/a\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--25a1bb-4\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--25a1bb-4\"\u003e4\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--25a1bb-5\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--25a1bb-5\"\u003e5\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--25a1bb-6\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--25a1bb-6\"\u003e6\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--25a1bb-7\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--25a1bb-7\"\u003e7\u003c/a\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-read-entry\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Interactively ask the user for an entry in SUBJECT.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003enames\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emapcar\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;car\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-entries\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ehist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eintern\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;devdocs--hist-%s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eunless\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eboundp\u003c/span\u003e \u003cspan class=\"nv\"\u003ehist\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eset\u003c/span\u003e \u003cspan class=\"nv\"\u003ehist\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecompleting-read\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Entry: \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003enames\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"nb\"\u003e:match\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"nv\"\u003ehist\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--devdocs-read-entry\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  Function to show completion list based on \"names\" from the JSON-parsed database\n\u003c/div\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eAnd finally, for the selected \u003cem\u003ename\u003c/em\u003e, the associated \u003cem\u003epath\u003c/em\u003e is\nretrieved from that \u003cem\u003ealist\u003c/em\u003e (\u003ca href=\"#org-coderef--e484ad-7\"\u003eline 7\u003c/a\u003e), and we browse\nto that path using the Emacs \u003ccode\u003ebrowse-url\u003c/code\u003e function (\u003ca href=\"#org-coderef--e484ad-9\"\u003eline\n9\u003c/a\u003e). \u003cem\u003eUser can of course configure the browser to be used\nwhen that function is called.\u003c/em\u003e\n\u003ca id=\"code-snippet--devdocs-lookup\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cdiv class=\"chroma\"\u003e\n\u003ctable class=\"lntable\"\u003e\u003ctr\u003e\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-1\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-1\"\u003e 1\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-2\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-2\"\u003e 2\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-3\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-3\"\u003e 3\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-4\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-4\"\u003e 4\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-5\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-5\"\u003e 5\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-6\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-6\"\u003e 6\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-7\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-7\"\u003e 7\u003c/a\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-8\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-8\"\u003e 8\u003c/a\u003e\n\u003c/span\u003e\u003cspan class=\"hl\"\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-9\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-9\"\u003e 9\u003c/a\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"lnt\" id=\"org-coderef--e484ad-10\"\u003e\u003ca style=\"outline: none; text-decoration:none; color:inherit\" href=\"#org-coderef--e484ad-10\"\u003e10\u003c/a\u003e\n\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\n\u003ctd class=\"lntd\"\u003e\n\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-lookup\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Visit the documentation for ENTRY from SUBJECT in a browser.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-read-subject\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eentry\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-read-entry\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003epath\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecdr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eassoc\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-entries\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003epath\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ebrowse-url\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s/%s/%s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-base-url\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nb\"\u003e:found\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/td\u003e\u003c/tr\u003e\u003c/table\u003e\n\u003c/div\u003e\n\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--devdocs-lookup\"\u003eCode Snippet 4\u003c/a\u003e:\u003c/span\u003e\n  Function to browse the doc page associated with the user-selected \"name\"\n\u003c/div\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eAll of that worked beautifully. As I used it a few times though, I\nfelt a need to add a touch of \u003cabbr aria-label=\"Do What I Mean\" tabindex=0\u003eDWIM\u003c/abbr\u003e to that.\u003c/p\u003e\n\n\u003ch3 id=\"making-devdocs-lookup-dwim\"\u003eMaking \u003ccode\u003edevdocs-lookup\u003c/code\u003e DWIM\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#making-devdocs-lookup-dwim\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eHere are the 2 things that I wanted to happen automatically:\u003c/p\u003e\n\n\u003ch4 id=\"auto-select-subject-based-on-major-mode-if-possible\"\u003eAuto-select subject based on \u003ccode\u003emajor-mode\u003c/code\u003e if possible\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#auto-select-subject-based-on-major-mode-if-possible\"\u003e#\u003c/a\u003e\u003c/h4\u003e\n\n\n\u003cp\u003eIn the original code, if I used \u003ccode\u003edevdocs-lookup\u003c/code\u003e function, I needed to\nmanually select the \u0026ldquo;Nim\u0026rdquo; subject even when I called that function\nfrom a \u003ccode\u003enim-mode\u003c/code\u003e buffer. \u003cem\u003eAt least for my use cases, I would want to\naccess only Nim docs if I am looking up devdocs while in a Nim code\nbuffer.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eThe package has an interesting function called \u003ccode\u003edevdocs-setup\u003c/code\u003e which\nwould generate a function specific to each subject.. so for \u0026ldquo;Nim\u0026rdquo;\nsubject, it would generate a \u003ccode\u003edevdocs-lookup-nim\u003c/code\u003e function.\u003c/p\u003e\n\u003cp\u003eBut I wanted to avoid calling \u003ccode\u003edevdocs-setup\u003c/code\u003e too.\u003c/p\u003e\n\u003cp\u003eSo below is what I did:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--devdocs-lookup-modified\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-lookup\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Visit the documentation for ENTRY from SUBJECT in a browser.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ecl-letf\u003c/span\u003e \u003cspan class=\"p\"\u003e(((\u003c/span\u003e\u003cspan class=\"nf\"\u003esymbol-function\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;string-match-case-insensitive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elambda\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estr1\u003c/span\u003e \u003cspan class=\"nv\"\u003estr2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring=\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edowncase\u003c/span\u003e \u003cspan class=\"nv\"\u003estr1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edowncase\u003c/span\u003e \u003cspan class=\"nv\"\u003estr2\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003emajor-mode-str\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;-mode\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003esymbol-name\u003c/span\u003e \u003cspan class=\"nv\"\u003emajor-mode\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e;; If major mode is `nim-mode\u0026#39;, the (\u0026#34;Nim\u0026#34; \u0026#34;nim\u0026#34;) element\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"c1\"\u003e;; will be auto-picked from `devdocs-subjects\u0026#39;.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject-dwim\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ecadr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eassoc\u003c/span\u003e \u003cspan class=\"nv\"\u003emajor-mode-str\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-subjects\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e                                       \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003estring-match-case-insensitive\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject-dwim\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-read-subject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eentry\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-read-entry\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003epath\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecdr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eassoc\u003c/span\u003e \u003cspan class=\"nv\"\u003eentry\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-entries\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003epath\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ebrowse-url\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s/%s/%s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-base-url\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e \u003cspan class=\"nv\"\u003epath\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nb\"\u003e:found\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--devdocs-lookup-modified\"\u003eCode Snippet 5\u003c/a\u003e:\u003c/span\u003e\n  Modification of the original \u003ccode\u003edevdocs-lookup\u003c/code\u003e \u0026#x2013; Now auto-selects the subject if the \u003ccode\u003emajor-mode\u003c/code\u003e matches.\n\u003c/div\u003e\n\n\u003ch4 id=\"auto-filter-using-the-symbol-at-point\"\u003eAuto-filter using the symbol at point\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#auto-filter-using-the-symbol-at-point\"\u003e#\u003c/a\u003e\u003c/h4\u003e\n\n\n\u003cp\u003eThe second thing that I wanted to work upon was to make Emacs kind of\n\u0026ldquo;know\u0026rdquo; what I was trying to search.\u003c/p\u003e\n\u003cp\u003eOriginally, \u003ccode\u003edevdocs-read-entry\u003c/code\u003e would always show the completion-list\npointing at the first entry. I wanted to make that a bit more\nintelligent.. If my point were on the \u003ccode\u003ewalkDirRec\u003c/code\u003e \u003cem\u003eproc\u003c/em\u003e identifier\non a line like below,\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-nim\" data-lang=\"nim\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003efilepath\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003ewalkDirRec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eappPath\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eyieldFilter\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003epcFile\u003c/span\u003e\u003cspan class=\"p\"\u003e}):\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI wanted the collection to narrow down to only the entries that\nmatched \u0026ldquo;walkDirRec\u0026rdquo;.\u003c/p\u003e\n\u003cp\u003eBelow is my modification to do that.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--devdocs-read-entry-modified\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003edevdocs-read-entry\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Interactively ask the user for an entry in SUBJECT.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003enames\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emapcar\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;car\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edevdocs-entries\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ehist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eintern\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;devdocs--hist-%s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003einit\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003esymbol-name\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esymbol-at-point\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eunless\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eboundp\u003c/span\u003e \u003cspan class=\"nv\"\u003ehist\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eset\u003c/span\u003e \u003cspan class=\"nv\"\u003ehist\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecompleting-read\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Entry (%s): \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003esubject\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003enames\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"nb\"\u003e:require-match\u003c/span\u003e \u003cspan class=\"nv\"\u003einit\u003c/span\u003e \u003cspan class=\"nv\"\u003ehist\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--devdocs-read-entry-modified\"\u003eCode Snippet 6\u003c/a\u003e:\u003c/span\u003e\n  Modification of the original \u003ccode\u003edevdocs-read-entry\u003c/code\u003e \u0026#x2013; Now auto-filters the entries that match the symbol at point.\n\u003c/div\u003e\n\u003cp\u003eAbove function just pre-sets the filter.. If the user wants to change\nthe search string, they can still do that.\u003c/p\u003e\n\n\u003ch2 id=\"using-devdocs-lookup\"\u003eUsing \u003ccode\u003edevdocs-lookup\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-devdocs-lookup\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eFinally, I like the \u003ca href=\"https://www.emacswiki.org/emacs/key-chord.el\"\u003e\u003ccode\u003ekey-chord.el\u003c/code\u003e\u003c/a\u003e package. So using that, I bind the\n\u003ccode\u003e??\u003c/code\u003e key-chord to the modified \u003ccode\u003edevdocs-lookup\u003c/code\u003e function.\u003c/p\u003e\n\u003cp\u003eSo if I want to look up the docs for \u003ccode\u003ewalkDirRec\u003c/code\u003e on that line in the\nabove example, I just move the point there, and hit \u003ccode\u003e??\u003c/code\u003e, and the docs\nfor that will pop up in my browser..\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eNo manual launching of the browser.\u003c/li\u003e\n\u003cli\u003eNo manual typing of the search string.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"devdocs-lookup-demo\"\u003eDemo\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#devdocs-lookup-demo\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIt won\u0026rsquo;t be fun if I did not end this post without a demo. So here it\nis \u0026mdash;\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--nim-devdocs-gif\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"nim-devdocs.gif\"\u003e\n        \u003cimg src=\"https://scripter.co/accessing-devdocs-from-emacs/nim-devdocs-screenshot.png\" alt=\"Figure 1: Click the above image to see the devdocs.io access from Emacs in action (GIF)\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eClick the above image to see the devdocs.io access from Emacs in action (GIF)\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\n\u003ch2 id=\"devdocs-lookup-code\"\u003eCode\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#devdocs-lookup-code\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eYou can find the modified \u003ccode\u003edevdocs-lookup\u003c/code\u003e code \u003ca href=\"https://github.com/kaushalmodi/devdocs-lookup\"\u003ehere\u003c/a\u003e.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eAll of the code snippets from Christopher Wellon\u0026rsquo;s\n\u003ccode\u003edevdocs-lookup\u003c/code\u003e that now follow in this post are from \u003ca href=\"https://github.com/skeeto/devdocs-lookup/tree/021c3c95030b4ee0d83a6961804c7a347faa72de\"\u003ethis commit\u003c/a\u003e.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eIf you visit that file in Firefox, it will show up in a\nwonderful formatted form with collapsible drawers, search, etc.\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","text":" Table of Contents JSON Docs Devdocs.io Christopher Wellon\u0026rsquo;s devdocs-lookup Making devdocs-lookup DWIM Using devdocs-lookup Demo Code Nim lang has good documentation for all its stdlib functions online. But the Emacs user in me does not like to switch back and forth between the Nim code in Emacs buffers and the docs outside in an external browser.\nWell.. a solution to that, that this post is about, still needs one to look up the Nim docs in an external browser.. but the workflow is a bit better \u0026mdash; You don\u0026rsquo;t need to manually launch the doc site, and you don\u0026rsquo;t need to then manually type in the search query.\nIf you want to skip the history and code analysis, you can directly jump to the Demo or the Final Code.\nJSON Docs\u0026nbsp;# I tried asking folks on r/nim if there was a good solution for in-editor Nim doc access. /u/PMunch from Reddit gave a wonderful solution\u0026mdash;To generate JSON docs for the Nim stdlib, and then parse those to display the docs within Emacs.\nI would love that solution!\n.. just that I don\u0026rsquo;t know how to get a nice single .json for the whole of Nim documentation.\nIf someone knows how to do that, please let me know.\nDevdocs.io\u0026nbsp;# So I continued my search online.. I was looking if someone had already implemented a way to access Nim docs from the command line, and that somehow led me to https://devdocs.io/nim/!\nAnd after searching further for \u0026ldquo;devdocs Emacs\u0026rdquo;, I found these two Emacs packages:\nhttps://github.com/xuchunyang/DevDocs.el https://github.com/skeeto/devdocs-lookup Christopher Wellon\u0026rsquo;s devdocs-lookup\u0026nbsp;# After reviewing the two packages, I decided to build my solution further upon the devdocs-lookup package1 by Christopher Wellons aka @skeeto from GitHub.\nHere\u0026rsquo;s why \u0026mdash;\nHe first fetches the whole JSON search index (line 5) from docs.devdocs.io for the picked \u0026ldquo;subject\u0026rdquo; (which would be \u0026ldquo;Nim\u0026rdquo; for this post). So the search index for Nim documentation would be at https://docs.devdocs.io/nim/index.json2.\nThe retrieved JSON is then parsed using json-read (line 13). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (defun devdocs-index (subject \u0026amp;optional callback) \u0026#34;Return the devdocs.io index for SUBJECT, optionally async via CALLBACK.\u0026#34; (cl-declare (special url-http-end-of-headers)) (let ((index (gethash subject devdocs-index)) (url (format \u0026#34;%s/%s/index.json\u0026#34; devdocs-base-index-url subject))) (cond ((and index callback) (funcall callback index)) ((and index (not callback)) index) ((and (not index) (not callback)) (with-current-buffer (url-retrieve-synchronously url nil t) (goto-char url-http-end-of-headers) (setf (gethash subject devdocs-index) (json-read)))) ((and (not index) callback) (url-retrieve url (lambda (_) (goto-char url-http-end-of-headers) (setf (gethash subject devdocs-index) (json-read)) (funcall callback (gethash subject devdocs-index)))))))) Code Snippet 1: Function to fetch the search index from devdocs.io and parse the JSON The name and path properties from the parsed JSON are then stored in an association list on lines 4 and 5. 1 2 3 4 5 (defun devdocs-entries (subject) \u0026#34;Return an association list of the entries in SUBJECT.\u0026#34; (cl-loop for entry across (cdr (assoc \u0026#39;entries (devdocs-index subject))) collect (cons (cdr (assoc \u0026#39;name entry)) (cdr (assoc \u0026#39;path entry))))) Code Snippet 2: Function to store the name and path properties to alists So a JSON entry like this:\n{ \u0026#34;name\u0026#34;: \u0026#34;os.walkDirRec\u0026#34;, \u0026#34;path\u0026#34;: \u0026#34;os#walkDirRec.i,string\u0026#34;, \u0026#34;type\u0026#34;: \u0026#34;os\u0026#34; } would translate to this Emacs-Lisp alist element:\n(\u0026#34;os.walkDirRec\u0026#34; . \u0026#34;os#walkDirRec.i,string\u0026#34;) Then the list of all the car\u0026rsquo;s of such elements is used to create a collection of entries for completion (line 3). 1 2 3 4 5 6 7 (defun devdocs-read-entry (subject) \u0026#34;Interactively ask the user for an entry in SUBJECT.\u0026#34; (let ((names (mapcar #\u0026#39;car (devdocs-entries subject))) (hist (intern (format \u0026#34;devdocs--hist-%s\u0026#34; subject)))) (unless (boundp hist) (set hist nil)) (completing-read \u0026#34;Entry: \u0026#34; names nil :match nil hist))) Code Snippet 3: Function to show completion list based on \"names\" from the JSON-parsed database And finally, for the selected name, the associated path is retrieved from that alist (line 7), and we browse to that path using the Emacs browse-url function (line 9). User can of course configure the browser to be used when that function is called. 1 2 3 4 5 6 7 8 9 10 (defun devdocs-lookup (subject entry) \u0026#34;Visit the documentation for ENTRY from SUBJECT in a browser.\u0026#34; (interactive (let* ((subject (devdocs-read-subject)) (entry (devdocs-read-entry subject))) (list subject entry))) (let ((path (cdr (assoc entry (devdocs-entries subject))))) (when path (browse-url (format \u0026#34;%s/%s/%s\u0026#34; devdocs-base-url subject path)) :found))) Code Snippet 4: Function to browse the doc page associated with the user-selected \"name\" All of that worked beautifully. As I used it a few times though, I felt a need to add a touch of DWIM to that.\nMaking devdocs-lookup DWIM\u0026nbsp;# Here are the 2 things that I wanted to happen automatically:\nAuto-select subject based on major-mode if possible\u0026nbsp;# In the original code, if I used devdocs-lookup function, I needed to manually select the \u0026ldquo;Nim\u0026rdquo; subject even when I called that function from a nim-mode buffer. At least for my use cases, I would want to access only Nim docs if I am looking up devdocs while in a Nim code buffer.\nThe package has an interesting function called devdocs-setup which would generate a function specific to each subject.. so for \u0026ldquo;Nim\u0026rdquo; subject, it would generate a devdocs-lookup-nim function.\nBut I wanted to avoid calling devdocs-setup too.\nSo below is what I did:\n(defun devdocs-lookup (subject entry) \u0026#34;Visit the documentation for ENTRY from SUBJECT in a browser.\u0026#34; (interactive (cl-letf (((symbol-function \u0026#39;string-match-case-insensitive) (lambda (str1 str2) (string= (downcase str1) (downcase str2))))) (let* ((major-mode-str (replace-regexp-in-string \u0026#34;-mode\u0026#34; \u0026#34;\u0026#34; (symbol-name major-mode))) ;; If major mode is `nim-mode\u0026#39;, the (\u0026#34;Nim\u0026#34; \u0026#34;nim\u0026#34;) element ;; will be auto-picked from `devdocs-subjects\u0026#39;. (subject-dwim (cadr (assoc major-mode-str devdocs-subjects #\u0026#39;string-match-case-insensitive))) (subject (or subject-dwim (devdocs-read-subject))) (entry (devdocs-read-entry subject))) (list subject entry)))) (let ((path (cdr (assoc entry (devdocs-entries subject))))) (when path (browse-url (format \u0026#34;%s/%s/%s\u0026#34; devdocs-base-url subject path)) :found))) Code Snippet 5: Modification of the original devdocs-lookup \u0026#x2013; Now auto-selects the subject if the major-mode matches. Auto-filter using the symbol at point\u0026nbsp;# The second thing that I wanted to work upon was to make Emacs kind of \u0026ldquo;know\u0026rdquo; what I was trying to search.\nOriginally, devdocs-read-entry would always show the completion-list pointing at the first entry. I wanted to make that a bit more intelligent.. If my point were on the walkDirRec proc identifier on a line like below,\nfor filepath in walkDirRec(appPath, yieldFilter={pcFile}): I wanted the collection to narrow down to only the entries that matched \u0026ldquo;walkDirRec\u0026rdquo;.\nBelow is my modification to do that.\n(defun devdocs-read-entry (subject) \u0026#34;Interactively ask the user for an entry in SUBJECT.\u0026#34; (let ((names (mapcar #\u0026#39;car (devdocs-entries subject))) (hist (intern (format \u0026#34;devdocs--hist-%s\u0026#34; subject))) (init (symbol-name (symbol-at-point)))) (unless (boundp hist) (set hist nil)) (completing-read (format \u0026#34;Entry (%s): \u0026#34; subject) names nil :require-match init hist))) Code Snippet 6: Modification of the original devdocs-read-entry \u0026#x2013; Now auto-filters the entries that match the symbol at point. Above function just pre-sets the filter.. If the user wants to change the search string, they can still do that.\nUsing devdocs-lookup\u0026nbsp;# Finally, I like the key-chord.el package. So using that, I bind the ?? key-chord to the modified devdocs-lookup function.\nSo if I want to look up the docs for walkDirRec on that line in the above example, I just move the point there, and hit ??, and the docs for that will pop up in my browser..\nNo manual launching of the browser. No manual typing of the search string. Demo\u0026nbsp;# It won\u0026rsquo;t be fun if I did not end this post without a demo. So here it is \u0026mdash;\nFigure 1: Click the above image to see the devdocs.io access from Emacs in action (GIF) Code\u0026nbsp;# You can find the modified devdocs-lookup code here.\nAll of the code snippets from Christopher Wellon\u0026rsquo;s devdocs-lookup that now follow in this post are from this commit.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nIf you visit that file in Firefox, it will show up in a wonderful formatted form with collapsible drawers, search, etc.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"Accessing Devdocs from Emacs","published":"2018-05-10T12:45:00-04:00","summary":"Spoiled by being able to access in-built docs in Emacs at fingertips, here\u0026rsquo;s an attempt to kind-of do that for Nim documentation too, using devdocs.io.","type":"entry","url":"https://scripter.co/accessing-devdocs-from-emacs/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#fontawesome-5-setup\"\u003eFontAwesome 5 Setup\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#problem\"\u003eProblem\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#solution\"\u003eSolution\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#code\"\u003eCode\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#result\"\u003eResult\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eThis post briefly goes through the FontAwesome 5 setup, the problem\nstatement and a solution for that.\u003c/p\u003e\n\u003cp\u003eI signed up for the \u003ca href=\"https://www.kickstarter.com/projects/232193852/font-awesome-5\"\u003eFontAwesome 5 Pro Kickstarter\u003c/a\u003e, and I have to say\nthat this is one of my few Kickstarter fundings that delivered really\nwell!\u003c/p\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e    \u003cem\u003eThank you FontAwesome!\u003c/em\u003e\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\n\u003ch2 id=\"fontawesome-5-setup\"\u003eFontAwesome 5 Setup\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#fontawesome-5-setup\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eFontAwesome 5 supports an awesome new way of loading icons, using\n\u003ca href=\"https://fontawesome.com/get-started/svg-with-js\"\u003eSVG with JS\u003c/a\u003e. The benefit is that you simply load one\n\u003ccode\u003efontawesome-all.js\u003c/code\u003e file and \u003cem\u003eeverything just works\u003c/em\u003e!.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--fa-setup\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ehead\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!--load everything--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003escript\u003c/span\u003e \u003cspan class=\"na\"\u003edefer\u003c/span\u003e \u003cspan class=\"na\"\u003esrc\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;/static/fontawesome/fontawesome-all.js\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003escript\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ehead\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c\"\u003e\u0026lt;!--icon--\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003ei\u003c/span\u003e \u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;fas fa-user\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ei\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--fa-setup\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Fontawesome 5 Setup\n\u003c/div\u003e\n\n\u003ch2 id=\"problem\"\u003eProblem\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#problem\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eWith FontAwesome 5 Pro, I get about 2700 icons packed in that\n\u003ccode\u003efontawesome-all.js\u003c/code\u003e. While that is great, there are 2 issues:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eI don\u0026rsquo;t need all of those 2700 icons on my site. That file is\nroughly 1.7 \u003cstrong\u003eMB\u003c/strong\u003e (minified or not) which I need not unnecessarily\nload for all my visitors.\u003c/li\u003e\n\u003cli\u003eAnyone can easily pirate the whole JS file and use it for free!\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"solution\"\u003eSolution\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#solution\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThe solution is simple \u0026mdash; I just comment out all the lines with SVG\ncode for the icons that I don\u0026rsquo;t use.\u003c/p\u003e\n\u003cp\u003eBut searching for the icons I need in all the icon packs (Solid,\nRegular, Light, Brand) in that single 5k+ line JS file is not fun,\nespecially when I want to add/remove icons occasionally.\u003c/p\u003e\n\u003cp\u003eAnd so \u003ccode\u003efontawesome-choose\u003c/code\u003e was born!\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eI list the icons I need in \u003ccode\u003efontawesome-choose-icons\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003eM-x fontawesome-choose\u003c/code\u003e in the \u003ccode\u003efontawesome-all.js\u003c/code\u003e file\nbuffer.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe code is in the next section, but you can also find the latest\nversion \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/elisp/misc/fontawesome-choose.el\"\u003ein my repo\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eNote that while I have used this on Fontawesome 5 Pro, it should work\njust as well on Fontawesome 5 Free too.\u003c/em\u003e\u003c/p\u003e\n\n\u003ch2 id=\"code\"\u003eCode\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#code\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"code-snippet--fontawesome-choose\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Helper function `fontawesome-choose\u0026#39; used to uncomment only the\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; icons the user cares about in `fontawesome-all.js\u0026#39;.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefconst\u003c/span\u003e \u003cspan class=\"nv\"\u003efontawesome-choose-icons\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;list-alt\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e;categories\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;tags\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;rss\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;link\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;heart\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e;like\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;reply\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;retweet\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;github\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e;\u0026#34;github-alt\u0026#34; \u0026#34;github-square\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;twitter\u0026#34;\u003c/span\u003e \u003cspan class=\"c1\"\u003e;\u0026#34;twitter-square\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                     \u003cspan class=\"s\"\u003e\u0026#34;gitlab\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;List of icons to choose from fontawesome-all.js.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eUsed in \u003c/span\u003e\u003cspan class=\"ss\"\u003e`fontawesome-choose\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003efontawesome-choose\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Comment out all icons in fontawesome-all.js except the selected few.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eMinifying the resultant .js will then remove the commented icons,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003ethus drastically reducing the minified JS size.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eSet the \u003c/span\u003e\u003cspan class=\"ss\"\u003e`fontawesome-choose-icons\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e variable to the list of icons\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003ethat you want to keep uncommented.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003ecase-fold-search\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ecount\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003epoint-min\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-forward\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;^var icons\u0026#34;\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"nb\"\u003e:noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003ebegin\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eprogn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eforward-line\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003epoint\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"nv\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-forward\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;^\\\\};\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eforward-line\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebackward-char\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003epoint\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"c1\"\u003e;; First comment all the lines\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enarrow-to-region\u003c/span\u003e \u003cspan class=\"nv\"\u003ebegin\u003c/span\u003e \u003cspan class=\"nv\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003epoint-min\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-forward\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;^\\\\s-*\\\\(\\\u0026#34;\\\\)\u0026#34;\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"nb\"\u003e:noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ereplace-match\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;// \\\\1\u0026#34;\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ewiden\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"c1\"\u003e;; Now uncomment only the selected icons\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enarrow-to-region\u003c/span\u003e \u003cspan class=\"nv\"\u003ebegin\u003c/span\u003e \u003cspan class=\"nv\"\u003eend\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003epoint-min\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eicon-regexp\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eregexp-opt\u003c/span\u003e \u003cspan class=\"nv\"\u003efontawesome-choose-icons\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;symbols\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eregexp\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;^\\\\s-*\\\\(//\\\\s-*\\\\)\\\u0026#34;%s\\\u0026#34;:\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eicon-regexp\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-forward\u003c/span\u003e \u003cspan class=\"nv\"\u003eregexp\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"nb\"\u003e:noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ereplace-match\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003ecount\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e1+\u003c/span\u003e \u003cspan class=\"nv\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ewiden\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;fontawesome-choose: Uncommented %d icons matching %S\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e               \u003cspan class=\"nv\"\u003ecount\u003c/span\u003e \u003cspan class=\"nv\"\u003efontawesome-choose-icons\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--fontawesome-choose\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  \u003ccode\u003efontawesome-choose\u003c/code\u003e \u0026#x2014; Comment out all the FontAwesome icons you don't need\n\u003c/div\u003e\n\n\u003ch2 id=\"result\"\u003eResult\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#result\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThis solution solves the first problem wonderfully \u0026mdash; After\nminification, \u003ccode\u003efontawesome-all.js\u003c/code\u003e is just 71 \u003cstrong\u003eKB\u003c/strong\u003e (down from 1.7\n\u003cstrong\u003eMB\u003c/strong\u003e).\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s a 25x factor reduction! The minification step is important\nbecause that removes all the commented lines from the JS. I do the\nminification using \u003ca href=\"https://github.com/tdewolff/minify\"\u003e\u003ccode\u003etdewolff/minify\u003c/code\u003e\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eThe second problem, that of piracy, is difficult to solve completely\nusing this. But whoever pirates this \u003cem\u003ereduced\u003c/em\u003e FontAwesome from my\nsite won\u0026rsquo;t get the real deal 😎.\u003c/p\u003e\n\u003cp\u003eEmacs-Lisp saves the day once again!\u003c/p\u003e\n","text":" Table of Contents FontAwesome 5 Setup Problem Solution Code Result This post briefly goes through the FontAwesome 5 setup, the problem statement and a solution for that.\nI signed up for the FontAwesome 5 Pro Kickstarter, and I have to say that this is one of my few Kickstarter fundings that delivered really well!\nThank you FontAwesome!\nFontAwesome 5 Setup\u0026nbsp;# FontAwesome 5 supports an awesome new way of loading icons, using SVG with JS. The benefit is that you simply load one fontawesome-all.js file and everything just works!.\n\u0026lt;head\u0026gt; \u0026lt;!--load everything--\u0026gt; \u0026lt;script defer src=\u0026#34;/static/fontawesome/fontawesome-all.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;!--icon--\u0026gt; \u0026lt;i class=\u0026#34;fas fa-user\u0026#34;\u0026gt;\u0026lt;/i\u0026gt; \u0026lt;/body\u0026gt; Code Snippet 1: Fontawesome 5 Setup Problem\u0026nbsp;# With FontAwesome 5 Pro, I get about 2700 icons packed in that fontawesome-all.js. While that is great, there are 2 issues:\nI don\u0026rsquo;t need all of those 2700 icons on my site. That file is roughly 1.7 MB (minified or not) which I need not unnecessarily load for all my visitors. Anyone can easily pirate the whole JS file and use it for free! Solution\u0026nbsp;# The solution is simple \u0026mdash; I just comment out all the lines with SVG code for the icons that I don\u0026rsquo;t use.\nBut searching for the icons I need in all the icon packs (Solid, Regular, Light, Brand) in that single 5k+ line JS file is not fun, especially when I want to add/remove icons occasionally.\nAnd so fontawesome-choose was born!\nI list the icons I need in fontawesome-choose-icons. Run M-x fontawesome-choose in the fontawesome-all.js file buffer. The code is in the next section, but you can also find the latest version in my repo.\nNote that while I have used this on Fontawesome 5 Pro, it should work just as well on Fontawesome 5 Free too.\nCode\u0026nbsp;# ;; Helper function `fontawesome-choose\u0026#39; used to uncomment only the ;; icons the user cares about in `fontawesome-all.js\u0026#39;. (defconst fontawesome-choose-icons \u0026#39;(\u0026#34;list-alt\u0026#34; ;categories \u0026#34;tags\u0026#34; \u0026#34;rss\u0026#34; \u0026#34;link\u0026#34; \u0026#34;heart\u0026#34; ;like \u0026#34;reply\u0026#34; \u0026#34;retweet\u0026#34; \u0026#34;github\u0026#34; ;\u0026#34;github-alt\u0026#34; \u0026#34;github-square\u0026#34; \u0026#34;twitter\u0026#34; ;\u0026#34;twitter-square\u0026#34; \u0026#34;gitlab\u0026#34;) \u0026#34;List of icons to choose from fontawesome-all.js. Used in `fontawesome-choose\u0026#39;.\u0026#34;) (defun fontawesome-choose () \u0026#34;Comment out all icons in fontawesome-all.js except the selected few. Minifying the resultant .js will then remove the commented icons, thus drastically reducing the minified JS size. Set the `fontawesome-choose-icons\u0026#39; variable to the list of icons that you want to keep uncommented.\u0026#34; (interactive) (let ((case-fold-search nil) (count 0)) (save-excursion (goto-char (point-min)) (while (re-search-forward \u0026#34;^var icons\u0026#34; nil :noerror) (let ((begin (progn (forward-line 1) (point))) end) (re-search-forward \u0026#34;^\\\\};\u0026#34;) (forward-line 0) (backward-char 1) (setq end (point)) ;; First comment all the lines (save-excursion (narrow-to-region begin end) (goto-char (point-min)) (while (re-search-forward \u0026#34;^\\\\s-*\\\\(\\\u0026#34;\\\\)\u0026#34; nil :noerror) (replace-match \u0026#34;// \\\\1\u0026#34; nil nil nil 1)) (widen)) ;; Now uncomment only the selected icons (save-excursion (narrow-to-region begin end) (goto-char (point-min)) (let* ((icon-regexp (regexp-opt fontawesome-choose-icons \u0026#39;symbols)) (regexp (format \u0026#34;^\\\\s-*\\\\(//\\\\s-*\\\\)\\\u0026#34;%s\\\u0026#34;:\u0026#34; icon-regexp))) (while (re-search-forward regexp nil :noerror) (replace-match \u0026#34;\u0026#34; nil nil nil 1) (setq count (1+ count)))) (widen)))) (message \u0026#34;fontawesome-choose: Uncommented %d icons matching %S\u0026#34; count fontawesome-choose-icons)))) Code Snippet 2: fontawesome-choose \u0026#x2014; Comment out all the FontAwesome icons you don't need Result\u0026nbsp;# This solution solves the first problem wonderfully \u0026mdash; After minification, fontawesome-all.js is just 71 KB (down from 1.7 MB).\nThat\u0026rsquo;s a 25x factor reduction! The minification step is important because that removes all the commented lines from the JS. I do the minification using tdewolff/minify.\nThe second problem, that of piracy, is difficult to solve completely using this. But whoever pirates this reduced FontAwesome from my site won\u0026rsquo;t get the real deal 😎.\nEmacs-Lisp saves the day once again!\n"},"name":"Optimize your FontAwesome","published":"2018-04-04T15:20:00-04:00","summary":"How to trim the FontAwesome JS for your website, using Emacs Lisp.","type":"entry","url":"https://scripter.co/optimize-your-fontawesome/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#normalizing\"\u003eNormalizing\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#equations-breakdown\"\u003eEquations Breakdown\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#evaluate-the-whole-table\"\u003eEvaluate the whole table\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\n\u003ch2 id=\"normalizing\"\u003eNormalizing\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#normalizing\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003ca id=\"table--org-table-norm\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"table-caption\"\u003e\n  \u003cspan class=\"table-number\"\u003e\u003ca href=\"#table--org-table-norm\"\u003eTable 1\u003c/a\u003e:\u003c/span\u003e\n  Org table Normalizing\n\u003c/div\u003e\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e\u003c/th\u003e\n\u003cth\u003eNormalized col \u003ccode\u003e$1\u003c/code\u003e\u003c/th\u003e\n\u003cth\u003e\u003c/th\u003e\n\u003cth\u003eNormalized col \u003ccode\u003e$3\u003c/code\u003e\u003c/th\u003e\n\u003cth\u003eRatio of col \u003ccode\u003e$2\u003c/code\u003e / \u003ccode\u003e$4\u003c/code\u003e\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eCol \u003ccode\u003e$1\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eCol \u003ccode\u003e$2\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eCol \u003ccode\u003e$3\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eCol \u003ccode\u003e$4\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eCol \u003ccode\u003e$5\u003c/code\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e79922.1\u003c/td\u003e\n\u003ctd\u003e6.85\u003c/td\u003e\n\u003ctd\u003e0.146993824\u003c/td\u003e\n\u003ctd\u003e4.27\u003c/td\u003e\n\u003ctd\u003e1.60\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e79185.9\u003c/td\u003e\n\u003ctd\u003e6.78\u003c/td\u003e\n\u003ctd\u003e0.146976008\u003c/td\u003e\n\u003ctd\u003e4.27\u003c/td\u003e\n\u003ctd\u003e1.59\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e64041.0\u003c/td\u003e\n\u003ctd\u003e5.48\u003c/td\u003e\n\u003ctd\u003e0.147067031\u003c/td\u003e\n\u003ctd\u003e4.27\u003c/td\u003e\n\u003ctd\u003e1.28\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e15452.5\u003c/td\u003e\n\u003ctd\u003e1.32\u003c/td\u003e\n\u003ctd\u003e0.034456713\u003c/td\u003e\n\u003ctd\u003e1.00\u003c/td\u003e\n\u003ctd\u003e1.32\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e11675.7\u003c/td\u003e\n\u003ctd\u003e1.00\u003c/td\u003e\n\u003ctd\u003e0.034460162\u003c/td\u003e\n\u003ctd\u003e1.00\u003c/td\u003e\n\u003ctd\u003e1.00\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003ch3 id=\"equations-breakdown\"\u003eEquations Breakdown\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#equations-breakdown\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eEquation: \u003ccode\u003e#+tblfm: $2=$1/@7$1;%0.2f::$4=$3/@7$3;%0.2f::$5=$2/$4;%0.2f\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e$2=$1/@7$1\u003c/code\u003e \u0026ndash; Assign the value of a field in \u003cstrong\u003ecolumn\u003c/strong\u003e 2 (\u003ccode\u003e$2\u003c/code\u003e) to\nthe value of the field in \u003cstrong\u003ecolumn\u003c/strong\u003e 1 \u003cstrong\u003ein the same row\u003c/strong\u003e (\u003ccode\u003e$1\u003c/code\u003e)\ndivided by the value of the field in \u003cstrong\u003erow\u003c/strong\u003e 7, \u003cstrong\u003ecolumn\u003c/strong\u003e 1 (\u003ccode\u003e@7$1\u003c/code\u003e).\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e@\u003c/code\u003e is row, \u003ccode\u003e$\u003c/code\u003e is column.\u003c/li\u003e\n\u003cli\u003eRow and column numbers start with \u003cstrong\u003e1\u003c/strong\u003e (not 0).\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e$4=$3/@7$3\u003c/code\u003e \u0026ndash; Similar to above, but with different row/column numbers.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e$5=$2/$4\u003c/code\u003e \u0026ndash; Assign the value of a field in \u003cstrong\u003ecolumn\u003c/strong\u003e 5 (\u003ccode\u003e$5\u003c/code\u003e) to the\nvalue of the field in \u003cstrong\u003ecolumn\u003c/strong\u003e 2 \u003cstrong\u003ein the same row\u003c/strong\u003e (\u003ccode\u003e$2\u003c/code\u003e) divided by\nthe value of the field in \u003cstrong\u003ecolumn\u003c/strong\u003e 4 \u003cstrong\u003ein the same row\u003c/strong\u003e as well (\u003ccode\u003e$4\u003c/code\u003e).\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e;\u003c/code\u003e is used to separate the equation from the \u003cem\u003eformatting\u003c/em\u003e.\u003c/li\u003e\n\u003cli\u003eFor all the 3 equations, formatting is applied using \u003ccode\u003e%0.2f\u003c/code\u003e\ni.e. the numbers will be formatted with 2 decimal places. See \u003ca href=\"/field-formatters-in-org-table/\"\u003eField\nFormatters in Org table\u003c/a\u003e for more info.\u003c/li\u003e\n\u003cli\u003eEach of those equations are applied to the same table by\nconcatenating them with \u003ccode\u003e::\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch3 id=\"evaluate-the-whole-table\"\u003eEvaluate the whole table\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#evaluate-the-whole-table\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eDo \u003ccode\u003eC-u C-c C-c\u003c/code\u003e with point anywhere in the table, or do \u003ccode\u003eC-c C-c\u003c/code\u003e\nwith point on the \u003ccode\u003e#+tblfm\u003c/code\u003e line.\u003c/p\u003e\n\n\u003ch2 id=\"references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/org/Formula-syntax-for-Calc.html\"\u003e\u003cabbr title=\"Read the same section within Emacs by doing 'C-h i g (org) Formula syntax for Calc'\"\u003e(org) Formula syntax for Calc\u003c/abbr\u003e\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n","text":" Table of Contents Normalizing Equations Breakdown Evaluate the whole table References Normalizing\u0026nbsp;# Table 1: Org table Normalizing Normalized col $1 Normalized col $3 Ratio of col $2 / $4 Col $1 Col $2 Col $3 Col $4 Col $5 79922.1 6.85 0.146993824 4.27 1.60 79185.9 6.78 0.146976008 4.27 1.59 64041.0 5.48 0.147067031 4.27 1.28 15452.5 1.32 0.034456713 1.00 1.32 11675.7 1.00 0.034460162 1.00 1.00 Equations Breakdown\u0026nbsp;# Equation: #+tblfm: $2=$1/@7$1;%0.2f::$4=$3/@7$3;%0.2f::$5=$2/$4;%0.2f\n$2=$1/@7$1 \u0026ndash; Assign the value of a field in column 2 ($2) to the value of the field in column 1 in the same row ($1) divided by the value of the field in row 7, column 1 (@7$1). @ is row, $ is column. Row and column numbers start with 1 (not 0). $4=$3/@7$3 \u0026ndash; Similar to above, but with different row/column numbers. $5=$2/$4 \u0026ndash; Assign the value of a field in column 5 ($5) to the value of the field in column 2 in the same row ($2) divided by the value of the field in column 4 in the same row as well ($4). ; is used to separate the equation from the formatting. For all the 3 equations, formatting is applied using %0.2f i.e. the numbers will be formatted with 2 decimal places. See Field Formatters in Org table for more info. Each of those equations are applied to the same table by concatenating them with ::. Evaluate the whole table\u0026nbsp;# Do C-u C-c C-c with point anywhere in the table, or do C-c C-c with point on the #+tblfm line.\nReferences\u0026nbsp;# (org) Formula syntax for Calc "},"name":"Org Table Spreadsheet","published":"2018-04-02T00:00:00Z","summary":"My notes on Org Table Spreadsheet feature.","type":"entry","url":"https://scripter.co/notes/org-table-spreadsheet/"},{"content":{"html":"\u003cp\u003eI have often seen questions and confusion about why certain fixes or\nfeatures added to Org mode did not show up in its update on GNU Elpa.\u003c/p\u003e\n\u003cp\u003eBelow flow chart is an attempt to answer all such questions, and also\nmy first attempt at creating one using \u003cstrong\u003ePlantUML\u003c/strong\u003e (\u003cem\u003elegacy syntax\u003c/em\u003e)\n\u003cspan class=\"sidenote-number\"\u003e\u003csmall class=\"sidenote\"\u003e\nSee the \u003ca href=\"http://plantuml.com/activity-diagram-legacy\"\u003elegacy\u003c/a\u003e vs \u003ca href=\"http://plantuml.com/activity-diagram-beta\"\u003enew (beta)\u003c/a\u003e PlantUML syntax for activity\ndiagrams. When I tried the new (beta) syntax, it did not allow using\nthe \u0026ldquo;labels\u0026rdquo;.. see the \u003ccode\u003eas bugfix\u003c/code\u003e, \u003ccode\u003eas main\u003c/code\u003e syntax in the \u003ca href=\"#org-target--org-contrib-plantuml-source-code\"\u003eflowchart\nsource code\u003c/a\u003e.\n\u003c/small\u003e\u003c/span\u003e\n.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"figure--org-contribution-flow-chart\"\u003e\u003c/a\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/org-contribution-flowchart/flowchart.svg\" alt=\"Figure 1: Flow of a commit in Org mode repo from bugfix branch to main branch to Emacs repo\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eFlow of a commit in Org mode repo from \u003ccode\u003ebugfix\u003c/code\u003e branch to \u003ccode\u003emain\u003c/code\u003e branch to Emacs repo\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003e\u003cspan class=\"org-target\" id=\"org-target--org-contrib-plantuml-source-code\"\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cdetails\u003e\n\u003csummary\u003ePlantUML source code\u003c/summary\u003e\n\u003cdiv class=\"details\"\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode class=\"language-plantuml\" data-lang=\"plantuml\"\u003e(*) --\u0026gt; \u0026#34;My Org commit\u0026#34;\n\n--\u0026gt; \u0026#34;Discuss on Org mailing list\u0026#34;\n\nif \u0026#34;Bug fix commit?\u0026#34; then\n  --\u0026gt;[yes] \u0026#34;Commit to Org **bugfix**\u0026#34; as bugfix\nelse\n  -\u0026gt;[no] if \u0026#34;**bugfix** compatible doc fix commit?\u0026#34; then\n    --\u0026gt;[yes] bugfix\n  else\n    -\u0026gt;[no] \u0026#34;Commit to Org **main**\u0026#34; as main\n  endif\nendif\n\nbugfix --\u0026gt; \u0026#34;Merge to Org **main**\u0026#34;\n  --\u0026gt; main\nbugfix --\u0026gt; \u0026#34;Wait till next Monday\u0026#34;\n  --\u0026gt; \u0026#34;Push to GNU Elpa\u0026#34; as push\nbugfix --\u0026gt; \u0026#34;Short maturity time\u0026#34;\n  --\u0026gt; \u0026#34;Cut a minor release\u0026#34; as minor_release\n\nminor_release --\u0026gt; ===RELEASE===\nminor_release --\u0026gt; main\n\nmain --\u0026gt; \u0026#34;**Long maturity time**\u0026#34;\n  --\u0026gt; \u0026#34;Cut a major release\u0026#34; as major_release\n\nmajor_release --\u0026gt; ===RELEASE===\nmajor_release --\u0026gt; \u0026#34;Merge to Org **bugfix**\u0026#34;\n  --\u0026gt; bugfix\n\n===RELEASE=== --\u0026gt; push\n===RELEASE=== --\u0026gt; \u0026#34;Squash and commit to Emacs release or main branch\u0026#34;\n  --\u0026gt; (*)\n\npush --\u0026gt; (*)\n\u003c/code\u003e\u003c/pre\u003e\u003cdl\u003e\n\u003cdt\u003eFew notes on PlantUML syntax\u003c/dt\u003e\n\u003cdd\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003eSyntax\u003c/th\u003e\n\u003cth\u003eOutput\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e-​-​\u0026gt;\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eVertical arrow\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e-​\u0026gt;\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eHorizontal arrow\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e(*) -​-​\u0026gt;\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eStart point\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003e-​-​\u0026gt; (*)\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003eEnd point\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/dd\u003e\n\u003c/dl\u003e\n\u003c/div\u003e\n\u003c/details\u003e\n","text":"I have often seen questions and confusion about why certain fixes or features added to Org mode did not show up in its update on GNU Elpa.\nBelow flow chart is an attempt to answer all such questions, and also my first attempt at creating one using PlantUML (legacy syntax) See the legacy vs new (beta) PlantUML syntax for activity diagrams. When I tried the new (beta) syntax, it did not allow using the \u0026ldquo;labels\u0026rdquo;.. see the as bugfix, as main syntax in the flowchart source code. .\nFigure 1: Flow of a commit in Org mode repo from bugfix branch to main branch to Emacs repo PlantUML source code (*) --\u0026gt; \u0026#34;My Org commit\u0026#34; --\u0026gt; \u0026#34;Discuss on Org mailing list\u0026#34; if \u0026#34;Bug fix commit?\u0026#34; then --\u0026gt;[yes] \u0026#34;Commit to Org **bugfix**\u0026#34; as bugfix else -\u0026gt;[no] if \u0026#34;**bugfix** compatible doc fix commit?\u0026#34; then --\u0026gt;[yes] bugfix else -\u0026gt;[no] \u0026#34;Commit to Org **main**\u0026#34; as main endif endif bugfix --\u0026gt; \u0026#34;Merge to Org **main**\u0026#34; --\u0026gt; main bugfix --\u0026gt; \u0026#34;Wait till next Monday\u0026#34; --\u0026gt; \u0026#34;Push to GNU Elpa\u0026#34; as push bugfix --\u0026gt; \u0026#34;Short maturity time\u0026#34; --\u0026gt; \u0026#34;Cut a minor release\u0026#34; as minor_release minor_release --\u0026gt; ===RELEASE=== minor_release --\u0026gt; main main --\u0026gt; \u0026#34;**Long maturity time**\u0026#34; --\u0026gt; \u0026#34;Cut a major release\u0026#34; as major_release major_release --\u0026gt; ===RELEASE=== major_release --\u0026gt; \u0026#34;Merge to Org **bugfix**\u0026#34; --\u0026gt; bugfix ===RELEASE=== --\u0026gt; push ===RELEASE=== --\u0026gt; \u0026#34;Squash and commit to Emacs release or main branch\u0026#34; --\u0026gt; (*) push --\u0026gt; (*) Few notes on PlantUML syntax Syntax Output -​-​\u0026gt; Vertical arrow -​\u0026gt; Horizontal arrow (*) -​-​\u0026gt; Start point -​-​\u0026gt; (*) End point "},"name":"Org Contribution Flow-chart","published":"2018-03-06T00:23:00-05:00","summary":"A handy flow-chart if you are confused about when commits happen to Org bugfix branch vs main branch, what ends up in the GNU Elpa version, and so on.","type":"entry","url":"https://scripter.co/org-contribution-flowchart/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#using-printf-style-0-dot-1f-formatter\"\u003eUsing \u003ccode\u003eprintf\u003c/code\u003e style \u003ccode\u003e%0.1f\u003c/code\u003e formatter\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#using-calc-f1-formatter\"\u003eUsing \u003cem\u003eCalc\u003c/em\u003e \u003ccode\u003ef1\u003c/code\u003e formatter\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eIf you have a simple Org table like:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 0.5 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 1.5 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e|-----|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e|     |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eAnd you want the \u003cem\u003eA3\u003c/em\u003e cell to contain the sum of \u003cem\u003eA1\u003c/em\u003e and \u003cem\u003eA2\u003c/em\u003e cells,\nyou would add this at the bottom on that table and evaluate it (\u003ckbd\u003eC-c\nC-c\u003c/kbd\u003e).\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+tblfm\u003c/span\u003e\u003cspan class=\"c\"\u003e: @\u0026gt;$1=vsum(@1..@\u0026gt;\u0026gt;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThat formula reads as: \u0026ldquo;Set the value of the cell is last row\n(\u003ccode\u003e@\u0026gt;\u003c/code\u003e)\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e, first column (\u003ccode\u003e$1\u003c/code\u003e) be equal to the sum of all cells in\nthe same column from row 1 (\u003ccode\u003e@1\u003c/code\u003e) to second-to-the-last row (\u003ccode\u003e@\u0026gt;\u0026gt;\u003c/code\u003e).\u0026rdquo;\u003c/p\u003e\n\u003cp\u003eBut then you end up with an odd-looking \u003ccode\u003e2.\u003c/code\u003e instead of \u003ccode\u003e2.0\u003c/code\u003e in the\nresult cell:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 0.5 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 1.5 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e|-----|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e|  2. |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+tblfm\u003c/span\u003e\u003cspan class=\"c\"\u003e: @\u0026gt;$1=vsum(@1..@\u0026gt;\u0026gt;)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eSo I had \u003ca href=\"https://lists.gnu.org/r/emacs-orgmode/2016-04/msg00581.html\"\u003eposted\u003c/a\u003e a question on the Org mailing list to understand if\nthis was a bug \u0026mdash; \u003cem\u003eit was not\u003c/em\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"using-printf-style-0-dot-1f-formatter\"\u003eUsing \u003ccode\u003eprintf\u003c/code\u003e style \u003ccode\u003e%0.1f\u003c/code\u003e formatter\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-printf-style-0-dot-1f-formatter\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eThanks to the reply from Thierry Banel to that question, one of the\nsolutions is to use \u003cem\u003efield formatters\u003c/em\u003e, like in \u003ccode\u003eprintf\u003c/code\u003e in C (and\nmany other languages):\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 0.5 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 1.5 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e|-----|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 2.0 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+tblfm\u003c/span\u003e\u003cspan class=\"c\"\u003e: @\u0026gt;$1=vsum(@1..@\u0026gt;\u0026gt;);%0.1f\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"using-calc-f1-formatter\"\u003eUsing \u003cem\u003eCalc\u003c/em\u003e \u003ccode\u003ef1\u003c/code\u003e formatter\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-calc-f1-formatter\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eAnother solution, also from Thierry, was to use the \u003cem\u003eCalc\u003c/em\u003e \u003ccode\u003ef1\u003c/code\u003e\nformatter instead of \u003ccode\u003e%0.1f\u003c/code\u003e (and similarly \u003ccode\u003ef5\u003c/code\u003e instead of \u003ccode\u003e%0.5f\u003c/code\u003e).\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 0.5 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 1.5 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e|-----|\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e| 2.0 |\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+tblfm\u003c/span\u003e\u003cspan class=\"c\"\u003e: @\u0026gt;$1=vsum(@1..@\u0026gt;\u0026gt;);f1\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdl\u003e\n\u003cdt\u003eNote\u003c/dt\u003e\n\u003cdd\u003eWhile the \u003ccode\u003e%.1f\u003c/code\u003e format is handy for those who are used to\n\u003ccode\u003eprintf()\u003c/code\u003e syntax, note that Calc unlimited precision\nnumbers are converted to double floats before applying\n\u003ccode\u003e%.1f\u003c/code\u003e. Whereas \u003ccode\u003ef1\u003c/code\u003e operates on Calc numbers without\nconversion.\u003c/dd\u003e\n\u003c/dl\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eSee \u003ca href=\"https://orgmode.org/manual/References.html\"\u003e\u003cabbr title=\"Read the same section within Emacs by doing 'C-h i g (org) References'\"\u003e(org) References\u003c/abbr\u003e\u003c/a\u003e for more information on those field references.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n","text":" Table of Contents Using printf style %0.1f formatter Using Calc f1 formatter If you have a simple Org table like:\n| 0.5 | | 1.5 | |-----| | | And you want the A3 cell to contain the sum of A1 and A2 cells, you would add this at the bottom on that table and evaluate it (C-c C-c).\n#+tblfm: @\u0026gt;$1=vsum(@1..@\u0026gt;\u0026gt;) That formula reads as: \u0026ldquo;Set the value of the cell is last row (@\u0026gt;)1, first column ($1) be equal to the sum of all cells in the same column from row 1 (@1) to second-to-the-last row (@\u0026gt;\u0026gt;).\u0026rdquo;\nBut then you end up with an odd-looking 2. instead of 2.0 in the result cell:\n| 0.5 | | 1.5 | |-----| | 2. | #+tblfm: @\u0026gt;$1=vsum(@1..@\u0026gt;\u0026gt;) So I had posted a question on the Org mailing list to understand if this was a bug \u0026mdash; it was not.\nUsing printf style %0.1f formatter\u0026nbsp;# Thanks to the reply from Thierry Banel to that question, one of the solutions is to use field formatters, like in printf in C (and many other languages):\n| 0.5 | | 1.5 | |-----| | 2.0 | #+tblfm: @\u0026gt;$1=vsum(@1..@\u0026gt;\u0026gt;);%0.1f Using Calc f1 formatter\u0026nbsp;# Another solution, also from Thierry, was to use the Calc f1 formatter instead of %0.1f (and similarly f5 instead of %0.5f).\n| 0.5 | | 1.5 | |-----| | 2.0 | #+tblfm: @\u0026gt;$1=vsum(@1..@\u0026gt;\u0026gt;);f1 Note While the %.1f format is handy for those who are used to printf() syntax, note that Calc unlimited precision numbers are converted to double floats before applying %.1f. Whereas f1 operates on Calc numbers without conversion. See (org) References for more information on those field references.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"Field Formatters in Org table","published":"2018-03-05T17:40:00-05:00","summary":"Using field-formatters to format results of Org table formulae.","type":"entry","url":"https://scripter.co/field-formatters-in-org-table/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#code\"\u003eCode\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#tests\"\u003eTests\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#test-output\"\u003eTest Output\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#source\"\u003eSource\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#closing\"\u003eClosing\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#appendix\"\u003eAppendix\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#test-output-using-format-seconds\"\u003eTest output using \u003ccode\u003eformat-seconds\u003c/code\u003e\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#code--revision-1\"\u003eCode (Revision 1)\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cdiv class=\"verse\"\u003e\n\u003cp\u003e    Huh? 😕\u003cbr /\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003cp\u003eWell, a mechanic usually wouldn\u0026rsquo;t give you a time estimate in seconds,\nbut a tool I am using prints something like this at the end:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThe simulation took 54227.9 seconds in CPU time.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eThat triggered me to write a \u0026ldquo;little\u0026rdquo; script to convert seconds to\n\u003cem\u003ehuman time\u003c/em\u003e i.e. time in \u003cem\u003edays\u003c/em\u003e, \u003cem\u003ehours\u003c/em\u003e, \u003cem\u003eminutes\u003c/em\u003e and \u003cem\u003eseconds\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eThanks to \u003ca href=\"https://www.reddit.com/user/xiongtx\"\u003e\u003cstrong\u003e/u/xiongtx\u003c/strong\u003e\u003c/a\u003e from Reddit, I learned about the built-in function\n\u003ca href=\"https://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/calendar/time-date.el?id=04c5bd5b1f1dc07994d70caa640a07da6b5a54b5#n260\"\u003e\u003ccode\u003eformat-seconds\u003c/code\u003e\u003c/a\u003e that does what I wanted to do \u0026ndash; \u003cem\u003ebut not exactly in a\nway I wanted to see\u003c/em\u003e. Though, \u003ccode\u003eformat-seconds\u003c/code\u003e gave me an idea for a\nbig optimization (code \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/commit/db9e1a7c54a4c822e80b0308b7fc644db44fe1eb\"\u003ecommit diff\u003c/a\u003e).\u003c/p\u003e\n\u003cp\u003eBelow Code section is updated to reflect that. If you like, you can\nreview older version of the same section at the \u003ca href=\"#code--revision-1\"\u003eend of this\npost\u003c/a\u003e. Also, at the end, you will find a \u003ca href=\"#test-output-using-format-seconds\"\u003ecomparison\u003c/a\u003e between the outputs\nfrom \u003ccode\u003eformat-seconds\u003c/code\u003e and \u003ccode\u003emodi/seconds-to-human-time\u003c/code\u003e.\u003c/p\u003e\n\u003chr\u003e\n\n\u003ch2 id=\"code\"\u003eCode\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#code\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eHere\u0026rsquo;s the \u003cstrong\u003eupdated\u003c/strong\u003e code, and notes about that follow after that:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--seconds-to-human-time\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kp\"\u003e\u0026amp;optional\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Convert SECONDS to \\\u0026#34;DDd HHh MMm SSs\\\u0026#34; string.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eSECONDS is a non-negative integer or fractional number.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eSECONDS can also be a list of such numbers, which is the case\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003ewhen this function is called recursively.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eWhen called interactively, if a region is selected SECONDS is\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eextracted from that, else the user is prompted to enter those.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003einter\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ecalled-interactively-p\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;interactive\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eseconds-str\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003euse-region-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebuffer-substring-no-properties\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eregion-beginning\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eregion-end\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eread-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Enter seconds: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003estring-to-number\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds-str\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e \u003cspan class=\"c1\"\u003e;\u0026#34;1\u0026#34; -\u0026gt; 1, \u0026#34;1.2\u0026#34; -\u0026gt; 1.2, \u0026#34;\u0026#34; -\u0026gt; 0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eDAY\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e24\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003elistp\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e         \u003cspan class=\"c1\"\u003e;This is entered only by recursive calls\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecar\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003elast\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enumberp\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e  \u003cspan class=\"c1\"\u003e;This is entered only in the first entry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"ne\"\u003euser-error\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Invalid argument %S\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003egen-time-string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elambda\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003etime\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"s\"\u003e\u0026#34;Return string representation of TIME.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eTIME is of the type (DD HH MM SS), where each of those elements\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eare numbers.  If INTER is non-nil, echo the time string in a\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003ewell-formatted manner instead of returning it.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003efiller\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;    \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estr\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edolist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eunit\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;d\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;h\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;m\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;s\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecar\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003erassoc\u003c/span\u003e \u003cspan class=\"nv\"\u003eunit\u003c/span\u003e \u003cspan class=\"nv\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eval-str\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                   \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring=\u003c/span\u003e \u003cspan class=\"nv\"\u003eunit\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;s\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e;0 seconds\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring-match-p\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\\\\\u003c/span\u003e\u003cspan class=\"ss\"\u003e`\\\\s-*\\\\\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                    \u003cspan class=\"s\"\u003e\u0026#34; 0s\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                   \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring=\u003c/span\u003e \u003cspan class=\"nv\"\u003eunit\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;s\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eintegerp\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%2d%s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"nv\"\u003eunit\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%5.2f%s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"nv\"\u003eunit\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                   \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%2d%s \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"nv\"\u003eunit\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                    \u003cspan class=\"nv\"\u003efiller\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003estr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"nv\"\u003estr\u003c/span\u003e \u003cspan class=\"nv\"\u003eval-str\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"c1\"\u003e;; (message \u0026#34;debug: %S\u0026#34; time)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%0.2f seconds → %s\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                             \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring-trim\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34; +\u0026#34;\u003c/span\u003e  \u003cspan class=\"s\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring-trim-right\u003c/span\u003e \u003cspan class=\"nv\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003etime\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"nv\"\u003eDAY\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e          \u003cspan class=\"c1\"\u003e;\u0026gt; day\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003edays\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e/\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efloor\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003eDAY\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e-\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"nv\"\u003edays\u003c/span\u003e \u003cspan class=\"nv\"\u003eDAY\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"c1\"\u003e;; Note that (list rem) instead of just `rem\u0026#39; is\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"c1\"\u003e;; being passed to the recursive call to\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"c1\"\u003e;; `modi/seconds-to-human-time\u0026#39;.  This helps us\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"c1\"\u003e;; distinguish between direct and re-entrant\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"c1\"\u003e;; calls to this function.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econs\u003c/span\u003e \u003cspan class=\"nv\"\u003edays\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e         \u003cspan class=\"c1\"\u003e;\u0026gt; hour AND \u0026lt; day\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003ehours\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e/\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efloor\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e-\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"nv\"\u003ehours\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econs\u003c/span\u003e \u003cspan class=\"nv\"\u003ehours\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;h\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e       \u003cspan class=\"c1\"\u003e;\u0026gt; minute AND \u0026lt; hour\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003emins\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e/\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efloor\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e-\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"nv\"\u003emins\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econs\u003c/span\u003e \u003cspan class=\"nv\"\u003emins\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;m\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e                    \u003cspan class=\"c1\"\u003e;\u0026lt; minute\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econs\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;s\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; If `seconds\u0026#39; is a number and not a list, this is *not* a\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; recursive call.  Return the time as a string only then.  For\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; re-entrant executions, return the `time\u0026#39; list instead.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enumberp\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003egen-time-string\u003c/span\u003e \u003cspan class=\"nv\"\u003etime\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nv\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--seconds-to-human-time\"\u003eCode Snippet 1\u003c/a\u003e:\u003c/span\u003e\n  Seconds to Human Time\n\u003c/div\u003e\n\u003cp\u003eMost of this snippet is just the day/hour/minute/second math. Apart\nfrom that, here are some points that I found of interest:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eI did not always want to prompt the user to enter the input\nargument. If a region was selected, the function assumes that the\nuser selected a number, and skips the prompt step. So I used a plain\n\u003ccode\u003e(interactive)\u003c/code\u003e form instead of using \u003ccode\u003e(interactive \u0026quot;sPrompt: \u0026quot;)\u003c/code\u003e or\n\u003ccode\u003e(interactive \u0026quot;r\u0026quot;)\u003c/code\u003e. See \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/eintr/Interactive-Options.html\"\u003e\u003cem\u003e(eintr) Interactive Options\u003c/em\u003e\u003c/a\u003e and \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Interactive-Codes.html\"\u003e\u003cem\u003e(elisp)\nInteractive Codes\u003c/em\u003e\u003c/a\u003e to learn about \u003ccode\u003einteractive\u003c/code\u003e and its codes.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eInstead of in-lining a modular chunk of logic, like the one where I\nconvert a list like \u003ccode\u003e(1 2 3 4)\u003c/code\u003e into \u003ccode\u003e\u0026quot;1d 2h 3m 4s\u0026quot;\u003c/code\u003e, I assigned it\nto a \u003cem\u003elet\u003c/em\u003e-bound symbol \u003ccode\u003egen-time-string\u003c/code\u003e. That allowed the logic to\nbe more discernible when used in:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enumberp\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003egen-time-string\u003c/span\u003e \u003cspan class=\"nv\"\u003etime\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eAlso interesting is the fact that these \u003cem\u003elet\u003c/em\u003e-bound lambdas can\nhave their own doc-strings too.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eI make use of \u003cstrong\u003erecursion\u003c/strong\u003e in this function! But I needed this\nfunction to return a string (using that \u003ccode\u003egen-time-string\u003c/code\u003e function)\nonly when all the nested calls to itself were returned. So to\ndistinguish between a direct call to the function, and re-entrant\ncalls, when doing the latter, I make the input number a \u003cem\u003elist of\nthat number\u003c/em\u003e.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSo while the function might take an input number like \u003ccode\u003e7\u003c/code\u003e for a\ndirect call, that same number, when needed to call to a recursive\ncall, would get passed as \u003ccode\u003e(list 7)\u003c/code\u003e or \u003ccode\u003e'(7)\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eIf you glance back as that little snippet above, I return the\n\u003ccode\u003etime\u003c/code\u003e as a string only if the input \u003ccode\u003eseconds\u003c/code\u003e is a \u003cem\u003enumber\u003c/em\u003e \u0026mdash; and\nnot a list i.e. only when I am in the \u0026ldquo;direct call instance\u0026rdquo;.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003eThe internal variable \u003ccode\u003etime\u003c/code\u003e is now an alist\u003c/strong\u003e and can have up to 4\ncons elements. Each cons is of the type \u003ccode\u003e(TIMEVALUE . TIMEUNIT)\u003c/code\u003e. So\n\u003ccode\u003etime\u003c/code\u003e now looks like \u003ccode\u003e((DAYS . \u0026quot;d\u0026quot;) (HOURS . \u0026quot;h\u0026quot;) (MINUTES . \u0026quot;m\u0026quot;) (SECONDS . \u0026quot;s\u0026quot;))\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eIf the input \u003ccode\u003eseconds\u003c/code\u003e is 7200 seconds i.e. 2 hours, I cannot allow\n\u003ccode\u003etime\u003c/code\u003e to be just \u003ccode\u003e(2)\u003c/code\u003e, because then I wouldn\u0026rsquo;t know the unit of\nthat \u003ccode\u003e2\u003c/code\u003e (2 days? 2 hours? ..). With the above technique to \u003cem\u003etag\u003c/em\u003e the\ntime value with its unit (inspired from \u003ccode\u003eformat-seconds\u003c/code\u003e), the\n\u003ccode\u003etime\u003c/code\u003e value will be set as \u003ccode\u003e((2 . \u0026quot;h\u0026quot;))\u003c/code\u003e instead. That way, it\nwould read clearly as \u003cem\u003e2 hours, 0 minutes, and 0 seconds\u003c/em\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eBack inside \u003ccode\u003egen-time-string\u003c/code\u003e, I then skip printing the time units\nthat are 0 (unless everything is 0, in which case I print\n\u003ccode\u003e\u0026quot;0s\u0026quot;\u003c/code\u003e).\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%2d%s \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eval\u003c/span\u003e \u003cspan class=\"nv\"\u003eunit\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e \u003cspan class=\"nv\"\u003efiller\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e                                \u003cspan class=\"c1\"\u003e;`filler\u0026#39; is just white-space\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eSo instead of printing \u003ccode\u003e\u0026quot;1d 0h 0m 5s\u0026quot;\u003c/code\u003e, it would print \u003ccode\u003e\u0026quot;1d 5s\u0026quot;\u003c/code\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"tests\"\u003eTests\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#tests\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003cem\u003eThe test generator did not need to be updated, because the code\noptimization was completely internal \u0026mdash; Return values were not\naffected.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eA code isn\u0026rsquo;t complete without tests!\u003c/p\u003e\n\u003cp\u003eAs much fun I had writing the above function, I had equal fun in\nwriting its little tester too.\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--seconds-to-human-time-test\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003erand-bool\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elambda\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"s\"\u003e\u0026#34;(random 2) will return either 1 or 0, so\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e                    frac will be either t or nil\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003erandom\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ecount\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esecs\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e \u003cspan class=\"mi\"\u003e61\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"mi\"\u003e3600\u003c/span\u003e \u003cspan class=\"mi\"\u003e3601\u003c/span\u003e \u003cspan class=\"mi\"\u003e3660\u003c/span\u003e \u003cspan class=\"mi\"\u003e3661\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"mi\"\u003e86400\u003c/span\u003e \u003cspan class=\"mi\"\u003e86401\u003c/span\u003e \u003cspan class=\"mi\"\u003e86460\u003c/span\u003e \u003cspan class=\"mi\"\u003e86461\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"mi\"\u003e90000\u003c/span\u003e \u003cspan class=\"mi\"\u003e90001\u003c/span\u003e \u003cspan class=\"mi\"\u003e90060\u003c/span\u003e \u003cspan class=\"mi\"\u003e90061\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003elen-secs\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elength\u003c/span\u003e \u003cspan class=\"nv\"\u003esecs\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esecs-rand1\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emapcar\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elambda\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-sec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003erand-bool\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-min\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003erand-bool\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-hr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003erand-bool\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-day\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003erand-bool\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003eadd-sec\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003es\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e+\u003c/span\u003e \u003cspan class=\"nv\"\u003es\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003eadd-min\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003es\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e+\u003c/span\u003e \u003cspan class=\"nv\"\u003es\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003eadd-hr\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003es\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e+\u003c/span\u003e \u003cspan class=\"nv\"\u003es\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003eadd-day\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003es\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e+\u003c/span\u003e \u003cspan class=\"nv\"\u003es\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e \u003cspan class=\"mi\"\u003e24\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"nv\"\u003es\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                           \u003cspan class=\"nv\"\u003esecs\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e       \u003cspan class=\"nv\"\u003esecs-rand2\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edotimes\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003e_\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"nv\"\u003elen-secs\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003efrac\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003erand-bool\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"nv\"\u003efrac\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e/\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003erandom\u003c/span\u003e \u003cspan class=\"mi\"\u003e100000000\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"mf\"\u003e100.00\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003erandom\u003c/span\u003e \u003cspan class=\"mi\"\u003e1000000\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003epush\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"nv\"\u003esecs-rand2\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edolist\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"nv\"\u003esecs\u003c/span\u003e \u003cspan class=\"nv\"\u003esecs-rand1\u003c/span\u003e \u003cspan class=\"nv\"\u003esecs-rand2\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%9.2f seconds → %s\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ecl-incf\u003c/span\u003e \u003cspan class=\"nv\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emod\u003c/span\u003e \u003cspan class=\"nv\"\u003ecount\u003c/span\u003e \u003cspan class=\"nv\"\u003elen-secs\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emake-string\u003c/span\u003e \u003cspan class=\"mi\"\u003e40\u003c/span\u003e \u003cspan class=\"sc\"\u003e?─\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--seconds-to-human-time-test\"\u003eCode Snippet 2\u003c/a\u003e:\u003c/span\u003e\n  Test Generator\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003eThe test also makes use of a \u003cem\u003elet\u003c/em\u003e-bound lambda, for the \u003ccode\u003erand-bool\u003c/code\u003e\nfunction which I use to randomly return \u003ccode\u003et\u003c/code\u003e or \u003ccode\u003enil\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003esecs\u003c/code\u003e list is a set of directed tests, in which the \u003cem\u003eday\u003c/em\u003e,\n\u003cem\u003ehour\u003c/em\u003e, \u003cem\u003eminute\u003c/em\u003e and \u003cem\u003esecond\u003c/em\u003e units in \u003ccode\u003etime\u003c/code\u003e get set to \u003ccode\u003e1\u003c/code\u003e in all\npossible combinations. (If you are into binary numbers, think of\n\u003ccode\u003e0000\u003c/code\u003e, \u003ccode\u003e0001\u003c/code\u003e, .. up to \u003ccode\u003e1111\u003c/code\u003e.)\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003esecs-rand1\u003c/code\u003e is a partly randomized version of \u003ccode\u003esecs\u003c/code\u003e where one\nor more of the above time units would get randomly added by 1.\u003c/li\u003e\n\u003cli\u003eThe \u003ccode\u003esecs-rand2\u003c/code\u003e is a totally randomized list of time in seconds\nwhere the time could be anywhere in the \u003ccode\u003e[0, 1000000)\u003c/code\u003e range,\nfractional times with 2 decimal places included.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch3 id=\"test-output\"\u003eTest Output\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#test-output\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eUpon evaluating both \u003ca href=\"#code-snippet--seconds-to-human-time\"\u003eCode Snippet 1\u003c/a\u003e and\n\u003ca href=\"#code-snippet--seconds-to-human-time-test\"\u003eCode Snippet 2\u003c/a\u003e, you will get an output like below:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     0.00 seconds →              0s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     1.00 seconds →              1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    60.00 seconds →          1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    61.00 seconds →          1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  3600.00 seconds →      1h\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  3601.00 seconds →      1h      1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  3660.00 seconds →      1h  1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  3661.00 seconds →      1h  1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 86400.00 seconds →  1d\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 86401.00 seconds →  1d          1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 86460.00 seconds →  1d      1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 86461.00 seconds →  1d      1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 90000.00 seconds →  1d  1h\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 90001.00 seconds →  1d  1h      1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 90060.00 seconds →  1d  1h  1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 90061.00 seconds →  1d  1h  1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e────────────────────────────────────────\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    60.00 seconds →          1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 86402.00 seconds →  1d          2s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 86521.00 seconds →  1d      2m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  3722.00 seconds →      1h  2m  2s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  3661.00 seconds →      1h  1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 90061.00 seconds →  1d  1h  1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 90121.00 seconds →  1d  1h  2m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 93662.00 seconds →  1d  2h  1m  2s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e172861.00 seconds →  2d      1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e176462.00 seconds →  2d  1h  1m  2s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e176520.00 seconds →  2d  1h  2m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 86521.00 seconds →  1d      2m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e176460.00 seconds →  2d  1h  1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 90062.00 seconds →  1d  1h  1m  2s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 93660.00 seconds →  1d  2h  1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 93661.00 seconds →  1d  2h  1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e────────────────────────────────────────\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e429733.00 seconds →  4d 23h 22m 13s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e902957.30 seconds → 10d 10h 49m 17.30s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e684313.07 seconds →  7d 22h  5m 13.07s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 62058.42 seconds →     17h 14m 18.42s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e799077.55 seconds →  9d  5h 57m 57.55s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e347952.39 seconds →  4d     39m 12.39s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 31041.30 seconds →      8h 37m 21.30s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e242839.97 seconds →  2d 19h 27m 19.97s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e852518.67 seconds →  9d 20h 48m 38.67s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e160038.24 seconds →  1d 20h 27m 18.24s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e689297.00 seconds →  7d 23h 28m 17s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 64048.00 seconds →     17h 47m 28s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e870956.98 seconds → 10d  1h 55m 56.98s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e608767.00 seconds →  7d  1h  6m  7s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e167796.00 seconds →  1d 22h 36m 36s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e114940.07 seconds →  1d  7h 55m 40.07s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e────────────────────────────────────────\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e106163.46 seconds →  1d  5h 29m 23.46s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e701980.00 seconds →  8d  2h 59m 40s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e258706.73 seconds →  2d 23h 51m 46.73s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 33609.98 seconds →      9h 20m  9.98s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e639774.63 seconds →  7d  9h 42m 54.63s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e338533.00 seconds →  3d 22h  2m 13s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e365910.00 seconds →  4d  5h 38m 30s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e140002.00 seconds →  1d 14h 53m 22s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e365024.20 seconds →  4d  5h 23m 44.20s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e497072.00 seconds →  5d 18h  4m 32s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e304307.67 seconds →  3d 12h 31m 47.67s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e337126.00 seconds →  3d 21h 38m 46s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e711862.00 seconds →  8d  5h 44m 22s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e746474.22 seconds →  8d 15h 21m 14.22s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e200503.00 seconds →  2d  7h 41m 43s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e952391.00 seconds → 11d     33m 11s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e────────────────────────────────────────\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"source\"\u003eSource\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#source\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eYou can find the latest version of this code at\n\u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/elisp/misc/seconds-to-human-time.el\"\u003e\u003ccode\u003eseconds-to-human-time.el\u003c/code\u003e\u003c/a\u003e (\u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/d620b4afb5ff4c531e2944015646ec6708692bb9/elisp/misc/seconds-to-human-time.el\"\u003e\u003cem\u003efirst revision\u003c/em\u003e\u003c/a\u003e).\u003c/p\u003e\n\n\u003ch2 id=\"closing\"\u003eClosing\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#closing\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003e\u003cem\u003eYour car will be ready in 2h 13m 20s, and the simulation took 15h 3m\n47.90s in CPU time.\u003c/em\u003e\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \n        \u003cimg src=\"https://scripter.co/convert-seconds-to-human-time/images/seconds-to-human-time.png\" alt=\"Figure 1: Screenshot of seconds-to-human-time.el in Emacs\"/\u003e \u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eScreenshot of \u003ccode\u003eseconds-to-human-time.el\u003c/code\u003e in Emacs\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cdiv class=\"center\"\u003e\u003cb\u003e§\u003c/b\u003e\u003c/div\u003e\n\u003chr\u003e\n\n\u003ch2 id=\"appendix\"\u003eAppendix\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#appendix\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\u003ch3 id=\"test-output-using-format-seconds\"\u003eTest output using \u003ccode\u003eformat-seconds\u003c/code\u003e\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#test-output-using-format-seconds\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eInstead of using \u003ccode\u003e(modi/seconds-to-human-time sec)\u003c/code\u003e in the \u003ca href=\"#tests\"\u003etest\ngenerator\u003c/a\u003e, if I use the below form using \u003ccode\u003eformat-seconds\u003c/code\u003e to get as\nclose as to what I want:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%9.2f seconds → %s\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"s\"\u003e\u0026#34; days?\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;d\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"s\"\u003e\u0026#34; hours?\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;h\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"s\"\u003e\u0026#34; minutes?\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;m\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"s\"\u003e\u0026#34; seconds?\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;s\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eformat-seconds\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%2D %2H %2M %z%2S\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e))))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eI get the output on the \u003cem\u003eleft below\u003c/em\u003e. For brevity, I have pasted only\nfew snippets of the whole test for comparison:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--seconds-to-human-time-comparison\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     0.00 seconds →  0s                                     0.00 seconds →              0s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     1.00 seconds →  1s                                     1.00 seconds →              1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e    60.00 seconds →  1m  0s                                60.00 seconds →          1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    61.00 seconds →  1m  1s                                61.00 seconds →          1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e  3600.00 seconds →  1h  0m  0s                          3600.00 seconds →      1h\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  3661.00 seconds →  1h  1m  1s                          3661.00 seconds →      1h  1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e 86400.00 seconds →  1d  0h  0m  0s                     86400.00 seconds →  1d\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e 86401.00 seconds →  1d  0h  0m  1s                     86401.00 seconds →  1d          1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e 86460.00 seconds →  1d  0h  1m  0s                     86460.00 seconds →  1d      1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e 86461.00 seconds →  1d  0h  1m  1s                     86461.00 seconds →  1d      1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e 90000.00 seconds →  1d  1h  0m  0s                     90000.00 seconds →  1d  1h\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e 90001.00 seconds →  1d  1h  0m  1s                     90001.00 seconds →  1d  1h      1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e 90060.00 seconds →  1d  1h  1m  0s                     90060.00 seconds →  1d  1h  1m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 90061.00 seconds →  1d  1h  1m  1s                     90061.00 seconds →  1d  1h  1m  1s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# Below the random numbers are different on both sides, but the thing to note is the loss\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# fractional values (on the left) when seconds are not integers.\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e288128.50 seconds →  3d  8h  2m  8s                    902957.30 seconds → 10d 10h 49m 17.30s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line hl\"\u003e\u003cspan class=\"cl\"\u003e989679.28 seconds → 11d 10h 54m 39s                    684313.07 seconds →  7d 22h  5m 13.07s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e803137.00 seconds →  9d  7h  5m 37s                    347952.39 seconds →  4d     39m 12.39s\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e 39361.00 seconds → 10h 56m  1s                        689297.00 seconds →  7d 23h 28m 17s\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--seconds-to-human-time-comparison\"\u003eCode Snippet 3\u003c/a\u003e:\u003c/span\u003e\n  Using \u003ccode\u003eformat-seconds\u003c/code\u003e (\u003ci\u003eLeft\u003c/i\u003e), using \u003ccode\u003emodi/seconds-to-human-time\u003c/code\u003e (\u003ci\u003eRight\u003c/i\u003e)\n\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003eNotice the redundant \u003ccode\u003e0h\u003c/code\u003e, \u003ccode\u003e0m\u003c/code\u003e, \u003ccode\u003e0s\u003c/code\u003e on the left, and also the loss\nof seconds precision (\u003cem\u003ethe latter point is not a big deal though\u003c/em\u003e).\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch3 id=\"code--revision-1\"\u003eCode (Revision 1)\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#code--revision-1\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eHere\u0026rsquo;s the code, and notes about that follow after that:\u003c/p\u003e\n\u003cp\u003e\u003ca id=\"code-snippet--seconds-to-human-time-rev-1\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kp\"\u003e\u0026amp;optional\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Convert SECONDS to \\\u0026#34;DDd HHh MMm SSs\\\u0026#34; string.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eSECONDS is a non-negative integer or fractional number.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eSECONDS can also be a list of such numbers, which is the case\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003ewhen this function is called recursively.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eWhen called interactively, if a region is selected SECONDS is\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eextracted from that, else the user is prompted to enter those.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003einter\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ecalled-interactively-p\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;interactive\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eseconds-str\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003euse-region-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebuffer-substring-no-properties\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eregion-beginning\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eregion-end\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eread-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Enter seconds: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003estring-to-number\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds-str\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e \u003cspan class=\"c1\"\u003e;\u0026#34;1\u0026#34; -\u0026gt; 1, \u0026#34;1.2\u0026#34; -\u0026gt; 1.2, \u0026#34;\u0026#34; -\u0026gt; 0\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eDAY\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e24\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003elistp\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e         \u003cspan class=\"c1\"\u003e;This is entered only by recursive calls\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecar\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003elast\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enumberp\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e  \u003cspan class=\"c1\"\u003e;This is entered only in the first entry\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"ne\"\u003euser-error\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Invalid argument %S\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003egen-time-string\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elambda\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003etime\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"s\"\u003e\u0026#34;Return string representation of TIME.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eTIME is of the type (DD HH MM SS), where each of those elements\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eare numbers.  If INTER is non-nil, echo the time string in a\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003ewell-formatted manner instead of returning it.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003erev-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ereverse\u003c/span\u003e \u003cspan class=\"nv\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enth\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"nv\"\u003erev-time\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emin\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enth\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"nv\"\u003erev-time\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ehr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enth\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"nv\"\u003erev-time\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eday\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enth\u003c/span\u003e \u003cspan class=\"mi\"\u003e3\u003c/span\u003e \u003cspan class=\"nv\"\u003erev-time\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003efiller\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;    \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003esec-str\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eintegerp\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%2ds\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%5.2fs\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enull\u003c/span\u003e \u003cspan class=\"nf\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enull\u003c/span\u003e \u003cspan class=\"nv\"\u003ehr\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enull\u003c/span\u003e \u003cspan class=\"nv\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"c1\"\u003e;0 seconds\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"s\"\u003e\u0026#34; 0s\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emin-str\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nf\"\u003emin\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nf\"\u003emin\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%2dm \u0026#34;\u003c/span\u003e \u003cspan class=\"nf\"\u003emin\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"nv\"\u003efiller\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ehr-str\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nv\"\u003ehr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nv\"\u003ehr\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                 \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%2dh \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003ehr\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                               \u003cspan class=\"nv\"\u003efiller\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eday-str\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nv\"\u003eday\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;\u003c/span\u003e \u003cspan class=\"nv\"\u003eday\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%2dd \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eday\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                \u003cspan class=\"nv\"\u003efiller\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring-trim-right\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"nv\"\u003eday-str\u003c/span\u003e \u003cspan class=\"nv\"\u003ehr-str\u003c/span\u003e \u003cspan class=\"nv\"\u003emin-str\u003c/span\u003e \u003cspan class=\"nv\"\u003esec-str\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%0.2f seconds → %s\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                             \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring-trim\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34; +\u0026#34;\u003c/span\u003e  \u003cspan class=\"s\"\u003e\u0026#34; \u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"nv\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003etime\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"nv\"\u003eDAY\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e          \u003cspan class=\"c1\"\u003e;\u0026gt; day\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003edays\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e/\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efloor\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003eDAY\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e-\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"nv\"\u003edays\u003c/span\u003e \u003cspan class=\"nv\"\u003eDAY\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003edays\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"c1\"\u003e;; Note that (list rem) instead of just `rem\u0026#39; is being\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"c1\"\u003e;; passed to the recursive call to\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"c1\"\u003e;; `modi/seconds-to-human-time\u0026#39;.  This helps us\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"c1\"\u003e;; distinguish between direct and re-entrant calls to\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"c1\"\u003e;; this function.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003edays\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003edays\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003edays\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e         \u003cspan class=\"c1\"\u003e;\u0026gt; hour AND \u0026lt; day\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003ehours\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e/\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efloor\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e-\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"nv\"\u003ehours\u003c/span\u003e \u003cspan class=\"nv\"\u003eHOUR\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003ehours\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026lt;\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003ehours\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003ehours\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e\u0026gt;=\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e       \u003cspan class=\"c1\"\u003e;\u0026gt; minute AND \u0026lt; hour\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003emins\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e/\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efloor\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e-\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"nv\"\u003emins\u003c/span\u003e \u003cspan class=\"nv\"\u003eMINUTE\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003emins\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                       \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eappend\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003emins\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/seconds-to-human-time\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003erem\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e                    \u003cspan class=\"c1\"\u003e;\u0026lt; minute\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e \u003cspan class=\"nv\"\u003esec\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; If `seconds\u0026#39; is a number and not a list, this is *not* a recursive\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; call.  Return the time as a string only then.  For re-entrant\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; executions, return the `time\u0026#39; list instead.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enumberp\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003egen-time-string\u003c/span\u003e \u003cspan class=\"nv\"\u003etime\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nv\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"src-block-caption\"\u003e\n  \u003cspan class=\"src-block-number\"\u003e\u003ca href=\"#code-snippet--seconds-to-human-time-rev-1\"\u003eCode Snippet 4\u003c/a\u003e:\u003c/span\u003e\n  Seconds to Human Time (Revision 1)\n\u003c/div\u003e\n\u003cp\u003eMost of this snippet is just the day/hour/minute/second math. Apart\nfrom that, here are some points that I found of interest:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003cp\u003eI did not always want to prompt the user to enter the input\nargument. If a region was selected, the function assumes that the\nuser selected a number, and skips the prompt step. So I used a plain\n\u003ccode\u003e(interactive)\u003c/code\u003e form instead of using \u003ccode\u003e(interactive \u0026quot;sPrompt: \u0026quot;)\u003c/code\u003e or\n\u003ccode\u003e(interactive \u0026quot;r\u0026quot;)\u003c/code\u003e. See \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/eintr/Interactive-Options.html\"\u003e\u003cem\u003e(eintr) Interactive Options\u003c/em\u003e\u003c/a\u003e and \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/elisp/Interactive-Codes.html\"\u003e\u003cem\u003e(elisp)\nInteractive Codes\u003c/em\u003e\u003c/a\u003e to learn about \u003ccode\u003einteractive\u003c/code\u003e and its codes.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eInstead of in-lining a modular chunk of logic, like the one where I\nconvert a list like \u003ccode\u003e(1 2 3 4)\u003c/code\u003e into \u003ccode\u003e\u0026quot;1d 2h 3m 4s\u0026quot;\u003c/code\u003e, I assigned it\nto a \u003cem\u003elet\u003c/em\u003e-bound symbol \u003ccode\u003egen-time-string\u003c/code\u003e. That allowed the logic to\nbe more discernible when used in:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enumberp\u003c/span\u003e \u003cspan class=\"nv\"\u003eseconds\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003egen-time-string\u003c/span\u003e \u003cspan class=\"nv\"\u003etime\u003c/span\u003e \u003cspan class=\"nv\"\u003einter\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nv\"\u003etime\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003eAlso interesting is the fact that these \u003cem\u003elet\u003c/em\u003e-bound lambdas can\nhave their own doc-strings too.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eI make use of \u003cstrong\u003erecursion\u003c/strong\u003e in this function! But I needed this\nfunction to return a string (using that \u003ccode\u003egen-time-string\u003c/code\u003e function)\nonly when all the nested calls to itself were returned. So to\ndistinguish between a direct call to the function, and re-entrant\ncalls, when doing the latter, I make the input number a \u003cem\u003elist of\nthat number\u003c/em\u003e.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eSo while the function might take an input number like \u003ccode\u003e7\u003c/code\u003e for a\ndirect call, that same number, when needed to call to a recursive\ncall, would get passed as \u003ccode\u003e(list 7)\u003c/code\u003e or \u003ccode\u003e'(7)\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eIf you glance back as that little snippet above, I return the\n\u003ccode\u003etime\u003c/code\u003e as a string only if the input \u003ccode\u003eseconds\u003c/code\u003e is a \u003cem\u003enumber\u003c/em\u003e \u0026mdash; and\nnot a list i.e. only when I am in the \u0026ldquo;direct call instance\u0026rdquo;.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThe internal variable \u003ccode\u003etime\u003c/code\u003e is a list and can have up to 4 number\nelements: \u003ccode\u003e(DAYS HOURS MINUTES SECONDS)\u003c/code\u003e. The key was to always have\neach of those elements at their respective positions in the list.\u003c/p\u003e\n\u003cp\u003eIf the input \u003ccode\u003eseconds\u003c/code\u003e is 7200 seconds i.e. 2 hours, I cannot allow\n\u003ccode\u003etime\u003c/code\u003e to be just \u003ccode\u003e(2)\u003c/code\u003e, because then I wouldn\u0026rsquo;t know the unit of\nthat \u003ccode\u003e2\u003c/code\u003e (2 days? 2 hours? ..) \u0026mdash; The nested \u003ccode\u003econd\u003c/code\u003e logic for setting\nthe \u003ccode\u003etime\u003c/code\u003e variable ensures it gets set to \u003ccode\u003e(2 0 0)\u003c/code\u003e instead. That\nway, it would read clearly as \u003cem\u003e2 hours, 0 minutes, and 0 seconds\u003c/em\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eBack inside \u003ccode\u003egen-time-string\u003c/code\u003e, I then skip printing the time units\nthat are 0 (unless everything is 0, in which case I print\n\u003ccode\u003e\u0026quot;0s\u0026quot;\u003c/code\u003e). So instead of printing \u003ccode\u003e\u0026quot;1d 0h 0m 5s\u0026quot;\u003c/code\u003e, it would print just\n\u003ccode\u003e\u0026quot;1d 5s\u0026quot;\u003c/code\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ul\u003e","text":" Table of Contents Code Tests Test Output Source Closing Appendix Test output using format-seconds Code (Revision 1) Huh? 😕\nWell, a mechanic usually wouldn\u0026rsquo;t give you a time estimate in seconds, but a tool I am using prints something like this at the end:\nThe simulation took 54227.9 seconds in CPU time.\nThat triggered me to write a \u0026ldquo;little\u0026rdquo; script to convert seconds to human time i.e. time in days, hours, minutes and seconds.\nThanks to /u/xiongtx from Reddit, I learned about the built-in function format-seconds that does what I wanted to do \u0026ndash; but not exactly in a way I wanted to see. Though, format-seconds gave me an idea for a big optimization (code commit diff).\nBelow Code section is updated to reflect that. If you like, you can review older version of the same section at the end of this post. Also, at the end, you will find a comparison between the outputs from format-seconds and modi/seconds-to-human-time.\nCode\u0026nbsp;# Here\u0026rsquo;s the updated code, and notes about that follow after that:\n(defun modi/seconds-to-human-time (\u0026amp;optional seconds) \u0026#34;Convert SECONDS to \\\u0026#34;DDd HHh MMm SSs\\\u0026#34; string. SECONDS is a non-negative integer or fractional number. SECONDS can also be a list of such numbers, which is the case when this function is called recursively. When called interactively, if a region is selected SECONDS is extracted from that, else the user is prompted to enter those.\u0026#34; (interactive) (let ((inter (called-interactively-p \u0026#39;interactive))) (when inter (let ((seconds-str (if (use-region-p) (buffer-substring-no-properties (region-beginning) (region-end)) (read-string \u0026#34;Enter seconds: \u0026#34;)))) (setq seconds (string-to-number seconds-str)))) ;\u0026#34;1\u0026#34; -\u0026gt; 1, \u0026#34;1.2\u0026#34; -\u0026gt; 1.2, \u0026#34;\u0026#34; -\u0026gt; 0 (let* ((MINUTE 60) (HOUR (* 60 MINUTE)) (DAY (* 24 HOUR)) (sec (cond ((listp seconds) ;This is entered only by recursive calls (car (last seconds))) ((and (numberp seconds) ;This is entered only in the first entry (\u0026gt;= seconds 0)) seconds) (t (user-error \u0026#34;Invalid argument %S\u0026#34; seconds)))) (gen-time-string (lambda (time inter) \u0026#34;Return string representation of TIME. TIME is of the type (DD HH MM SS), where each of those elements are numbers. If INTER is non-nil, echo the time string in a well-formatted manner instead of returning it.\u0026#34; (let ((filler \u0026#34; \u0026#34;) (str \u0026#34;\u0026#34;)) (dolist (unit \u0026#39;(\u0026#34;d\u0026#34; \u0026#34;h\u0026#34; \u0026#34;m\u0026#34; \u0026#34;s\u0026#34;)) (let* ((val (car (rassoc unit time))) (val-str (cond ((and (string= unit \u0026#34;s\u0026#34;) ;0 seconds (= val 0) (string-match-p \u0026#34;\\\\`\\\\s-*\\\\\u0026#39;\u0026#34; str)) \u0026#34; 0s\u0026#34;) ((and (string= unit \u0026#34;s\u0026#34;) (\u0026gt; val 0)) (if (integerp val) (format \u0026#34;%2d%s\u0026#34; val unit) (format \u0026#34;%5.2f%s\u0026#34; val unit))) ((and val (\u0026gt; val 0)) (format \u0026#34;%2d%s \u0026#34; val unit)) (t filler)))) (setq str (concat str val-str)))) ;; (message \u0026#34;debug: %S\u0026#34; time) (if inter (message \u0026#34;%0.2f seconds → %s\u0026#34; seconds (string-trim (replace-regexp-in-string \u0026#34; +\u0026#34; \u0026#34; \u0026#34; str))) (string-trim-right str))))) (time (cond ((\u0026gt;= sec DAY) ;\u0026gt; day (let* ((days (/ (floor sec) DAY)) (rem (- sec (* days DAY)))) ;; Note that (list rem) instead of just `rem\u0026#39; is ;; being passed to the recursive call to ;; `modi/seconds-to-human-time\u0026#39;. This helps us ;; distinguish between direct and re-entrant ;; calls to this function. (append (list (cons days \u0026#34;d\u0026#34;)) (modi/seconds-to-human-time (list rem))))) ((\u0026gt;= sec HOUR) ;\u0026gt; hour AND \u0026lt; day (let* ((hours (/ (floor sec) HOUR)) (rem (- sec (* hours HOUR)))) (append (list (cons hours \u0026#34;h\u0026#34;)) (modi/seconds-to-human-time (list rem))))) ((\u0026gt;= sec MINUTE) ;\u0026gt; minute AND \u0026lt; hour (let* ((mins (/ (floor sec) MINUTE)) (rem (- sec (* mins MINUTE)))) (append (list (cons mins \u0026#34;m\u0026#34;)) (modi/seconds-to-human-time (list rem))))) (t ;\u0026lt; minute (list (cons sec \u0026#34;s\u0026#34;)))))) ;; If `seconds\u0026#39; is a number and not a list, this is *not* a ;; recursive call. Return the time as a string only then. For ;; re-entrant executions, return the `time\u0026#39; list instead. (if (numberp seconds) (funcall gen-time-string time inter) time)))) Code Snippet 1: Seconds to Human Time Most of this snippet is just the day/hour/minute/second math. Apart from that, here are some points that I found of interest:\nI did not always want to prompt the user to enter the input argument. If a region was selected, the function assumes that the user selected a number, and skips the prompt step. So I used a plain (interactive) form instead of using (interactive \u0026quot;sPrompt: \u0026quot;) or (interactive \u0026quot;r\u0026quot;). See (eintr) Interactive Options and (elisp) Interactive Codes to learn about interactive and its codes.\nInstead of in-lining a modular chunk of logic, like the one where I convert a list like (1 2 3 4) into \u0026quot;1d 2h 3m 4s\u0026quot;, I assigned it to a let-bound symbol gen-time-string. That allowed the logic to be more discernible when used in:\n(if (numberp seconds) (funcall gen-time-string time inter) time) Also interesting is the fact that these let-bound lambdas can have their own doc-strings too. I make use of recursion in this function! But I needed this function to return a string (using that gen-time-string function) only when all the nested calls to itself were returned. So to distinguish between a direct call to the function, and re-entrant calls, when doing the latter, I make the input number a list of that number.\nSo while the function might take an input number like 7 for a direct call, that same number, when needed to call to a recursive call, would get passed as (list 7) or '(7). If you glance back as that little snippet above, I return the time as a string only if the input seconds is a number \u0026mdash; and not a list i.e. only when I am in the \u0026ldquo;direct call instance\u0026rdquo;. The internal variable time is now an alist and can have up to 4 cons elements. Each cons is of the type (TIMEVALUE . TIMEUNIT). So time now looks like ((DAYS . \u0026quot;d\u0026quot;) (HOURS . \u0026quot;h\u0026quot;) (MINUTES . \u0026quot;m\u0026quot;) (SECONDS . \u0026quot;s\u0026quot;)).\nIf the input seconds is 7200 seconds i.e. 2 hours, I cannot allow time to be just (2), because then I wouldn\u0026rsquo;t know the unit of that 2 (2 days? 2 hours? ..). With the above technique to tag the time value with its unit (inspired from format-seconds), the time value will be set as ((2 . \u0026quot;h\u0026quot;)) instead. That way, it would read clearly as 2 hours, 0 minutes, and 0 seconds.\nBack inside gen-time-string, I then skip printing the time units that are 0 (unless everything is 0, in which case I print \u0026quot;0s\u0026quot;).\n((and val (\u0026gt; val 0)) (format \u0026#34;%2d%s \u0026#34; val unit)) (t filler) ;`filler\u0026#39; is just white-space So instead of printing \u0026quot;1d 0h 0m 5s\u0026quot;, it would print \u0026quot;1d 5s\u0026quot;.\nTests\u0026nbsp;# The test generator did not need to be updated, because the code optimization was completely internal \u0026mdash; Return values were not affected.\nA code isn\u0026rsquo;t complete without tests!\nAs much fun I had writing the above function, I had equal fun in writing its little tester too.\n(let* ((rand-bool (lambda() \u0026#34;(random 2) will return either 1 or 0, so frac will be either t or nil\u0026#34; (= 1 (random 2)))) (count 0) (secs \u0026#39;(0 1 60 61 3600 3601 3660 3661 86400 86401 86460 86461 90000 90001 90060 90061)) (len-secs (length secs)) (secs-rand1 (mapcar (lambda (s) (let ((add-sec (funcall rand-bool)) (add-min (funcall rand-bool)) (add-hr (funcall rand-bool)) (add-day (funcall rand-bool))) (when add-sec (setq s (+ s 1))) (when add-min (setq s (+ s 60))) (when add-hr (setq s (+ s (* 60 60)))) (when add-day (setq s (+ s (* 60 60 24)))) s)) secs)) secs-rand2) (dotimes (_ (* 2 len-secs)) (let* ((frac (funcall rand-bool)) (sec (if frac (/ (random 100000000) 100.00) (random 1000000)))) (push sec secs-rand2))) (dolist (sec (append secs secs-rand1 secs-rand2)) (message \u0026#34;%9.2f seconds → %s\u0026#34; sec (modi/seconds-to-human-time sec)) (cl-incf count) (when (= 0 (mod count len-secs)) (message (make-string 40 ?─))))) Code Snippet 2: Test Generator The test also makes use of a let-bound lambda, for the rand-bool function which I use to randomly return t or nil. The secs list is a set of directed tests, in which the day, hour, minute and second units in time get set to 1 in all possible combinations. (If you are into binary numbers, think of 0000, 0001, .. up to 1111.) The secs-rand1 is a partly randomized version of secs where one or more of the above time units would get randomly added by 1. The secs-rand2 is a totally randomized list of time in seconds where the time could be anywhere in the [0, 1000000) range, fractional times with 2 decimal places included. Test Output\u0026nbsp;# Upon evaluating both Code Snippet 1 and Code Snippet 2, you will get an output like below:\n0.00 seconds → 0s 1.00 seconds → 1s 60.00 seconds → 1m 61.00 seconds → 1m 1s 3600.00 seconds → 1h 3601.00 seconds → 1h 1s 3660.00 seconds → 1h 1m 3661.00 seconds → 1h 1m 1s 86400.00 seconds → 1d 86401.00 seconds → 1d 1s 86460.00 seconds → 1d 1m 86461.00 seconds → 1d 1m 1s 90000.00 seconds → 1d 1h 90001.00 seconds → 1d 1h 1s 90060.00 seconds → 1d 1h 1m 90061.00 seconds → 1d 1h 1m 1s ──────────────────────────────────────── 60.00 seconds → 1m 86402.00 seconds → 1d 2s 86521.00 seconds → 1d 2m 1s 3722.00 seconds → 1h 2m 2s 3661.00 seconds → 1h 1m 1s 90061.00 seconds → 1d 1h 1m 1s 90121.00 seconds → 1d 1h 2m 1s 93662.00 seconds → 1d 2h 1m 2s 172861.00 seconds → 2d 1m 1s 176462.00 seconds → 2d 1h 1m 2s 176520.00 seconds → 2d 1h 2m 86521.00 seconds → 1d 2m 1s 176460.00 seconds → 2d 1h 1m 90062.00 seconds → 1d 1h 1m 2s 93660.00 seconds → 1d 2h 1m 93661.00 seconds → 1d 2h 1m 1s ──────────────────────────────────────── 429733.00 seconds → 4d 23h 22m 13s 902957.30 seconds → 10d 10h 49m 17.30s 684313.07 seconds → 7d 22h 5m 13.07s 62058.42 seconds → 17h 14m 18.42s 799077.55 seconds → 9d 5h 57m 57.55s 347952.39 seconds → 4d 39m 12.39s 31041.30 seconds → 8h 37m 21.30s 242839.97 seconds → 2d 19h 27m 19.97s 852518.67 seconds → 9d 20h 48m 38.67s 160038.24 seconds → 1d 20h 27m 18.24s 689297.00 seconds → 7d 23h 28m 17s 64048.00 seconds → 17h 47m 28s 870956.98 seconds → 10d 1h 55m 56.98s 608767.00 seconds → 7d 1h 6m 7s 167796.00 seconds → 1d 22h 36m 36s 114940.07 seconds → 1d 7h 55m 40.07s ──────────────────────────────────────── 106163.46 seconds → 1d 5h 29m 23.46s 701980.00 seconds → 8d 2h 59m 40s 258706.73 seconds → 2d 23h 51m 46.73s 33609.98 seconds → 9h 20m 9.98s 639774.63 seconds → 7d 9h 42m 54.63s 338533.00 seconds → 3d 22h 2m 13s 365910.00 seconds → 4d 5h 38m 30s 140002.00 seconds → 1d 14h 53m 22s 365024.20 seconds → 4d 5h 23m 44.20s 497072.00 seconds → 5d 18h 4m 32s 304307.67 seconds → 3d 12h 31m 47.67s 337126.00 seconds → 3d 21h 38m 46s 711862.00 seconds → 8d 5h 44m 22s 746474.22 seconds → 8d 15h 21m 14.22s 200503.00 seconds → 2d 7h 41m 43s 952391.00 seconds → 11d 33m 11s ──────────────────────────────────────── Source\u0026nbsp;# You can find the latest version of this code at seconds-to-human-time.el (first revision).\nClosing\u0026nbsp;# Your car will be ready in 2h 13m 20s, and the simulation took 15h 3m 47.90s in CPU time.\nFigure 1: Screenshot of seconds-to-human-time.el in Emacs § Appendix\u0026nbsp;# Test output using format-seconds\u0026nbsp;# Instead of using (modi/seconds-to-human-time sec) in the test generator, if I use the below form using format-seconds to get as close as to what I want:\n(message \u0026#34;%9.2f seconds → %s\u0026#34; sec (replace-regexp-in-string \u0026#34; days?\u0026#34; \u0026#34;d\u0026#34; (replace-regexp-in-string \u0026#34; hours?\u0026#34; \u0026#34;h\u0026#34; (replace-regexp-in-string \u0026#34; minutes?\u0026#34; \u0026#34;m\u0026#34; (replace-regexp-in-string \u0026#34; seconds?\u0026#34; \u0026#34;s\u0026#34; (format-seconds \u0026#34;%2D %2H %2M %z%2S\u0026#34; sec)))))) I get the output on the left below. For brevity, I have pasted only few snippets of the whole test for comparison:\n0.00 seconds → 0s 0.00 seconds → 0s 1.00 seconds → 1s 1.00 seconds → 1s 60.00 seconds → 1m 0s 60.00 seconds → 1m 61.00 seconds → 1m 1s 61.00 seconds → 1m 1s 3600.00 seconds → 1h 0m 0s 3600.00 seconds → 1h 3661.00 seconds → 1h 1m 1s 3661.00 seconds → 1h 1m 1s 86400.00 seconds → 1d 0h 0m 0s 86400.00 seconds → 1d 86401.00 seconds → 1d 0h 0m 1s 86401.00 seconds → 1d 1s 86460.00 seconds → 1d 0h 1m 0s 86460.00 seconds → 1d 1m 86461.00 seconds → 1d 0h 1m 1s 86461.00 seconds → 1d 1m 1s 90000.00 seconds → 1d 1h 0m 0s 90000.00 seconds → 1d 1h 90001.00 seconds → 1d 1h 0m 1s 90001.00 seconds → 1d 1h 1s 90060.00 seconds → 1d 1h 1m 0s 90060.00 seconds → 1d 1h 1m 90061.00 seconds → 1d 1h 1m 1s 90061.00 seconds → 1d 1h 1m 1s # Below the random numbers are different on both sides, but the thing to note is the loss # fractional values (on the left) when seconds are not integers. 288128.50 seconds → 3d 8h 2m 8s 902957.30 seconds → 10d 10h 49m 17.30s 989679.28 seconds → 11d 10h 54m 39s 684313.07 seconds → 7d 22h 5m 13.07s 803137.00 seconds → 9d 7h 5m 37s 347952.39 seconds → 4d 39m 12.39s 39361.00 seconds → 10h 56m 1s 689297.00 seconds → 7d 23h 28m 17s Code Snippet 3: Using format-seconds (Left), using modi/seconds-to-human-time (Right) Notice the redundant 0h, 0m, 0s on the left, and also the loss of seconds precision (the latter point is not a big deal though). Code (Revision 1)\u0026nbsp;# Here\u0026rsquo;s the code, and notes about that follow after that:\n(defun modi/seconds-to-human-time (\u0026amp;optional seconds) \u0026#34;Convert SECONDS to \\\u0026#34;DDd HHh MMm SSs\\\u0026#34; string. SECONDS is a non-negative integer or fractional number. SECONDS can also be a list of such numbers, which is the case when this function is called recursively. When called interactively, if a region is selected SECONDS is extracted from that, else the user is prompted to enter those.\u0026#34; (interactive) (let ((inter (called-interactively-p \u0026#39;interactive))) (when inter (let ((seconds-str (if (use-region-p) (buffer-substring-no-properties (region-beginning) (region-end)) (read-string \u0026#34;Enter seconds: \u0026#34;)))) (setq seconds (string-to-number seconds-str)))) ;\u0026#34;1\u0026#34; -\u0026gt; 1, \u0026#34;1.2\u0026#34; -\u0026gt; 1.2, \u0026#34;\u0026#34; -\u0026gt; 0 (let* ((MINUTE 60) (HOUR (* 60 MINUTE)) (DAY (* 24 HOUR)) (sec (cond ((listp seconds) ;This is entered only by recursive calls (car (last seconds))) ((and (numberp seconds) ;This is entered only in the first entry (\u0026gt;= seconds 0)) seconds) (t (user-error \u0026#34;Invalid argument %S\u0026#34; seconds)))) (gen-time-string (lambda (time inter) \u0026#34;Return string representation of TIME. TIME is of the type (DD HH MM SS), where each of those elements are numbers. If INTER is non-nil, echo the time string in a well-formatted manner instead of returning it.\u0026#34; (let* ((rev-time (reverse time)) (sec (nth 0 rev-time)) (min (nth 1 rev-time)) (hr (nth 2 rev-time)) (day (nth 3 rev-time)) (filler \u0026#34; \u0026#34;) (sec-str (cond ((\u0026gt; sec 0) (if (integerp sec) (format \u0026#34;%2ds\u0026#34; sec) (format \u0026#34;%5.2fs\u0026#34; sec))) ((and (= sec 0) (null min) (null hr) (null day)) ;0 seconds \u0026#34; 0s\u0026#34;))) (min-str (if (and min (\u0026gt; min 0)) (format \u0026#34;%2dm \u0026#34; min) filler)) (hr-str (if (and hr (\u0026gt; hr 0)) (format \u0026#34;%2dh \u0026#34; hr) filler)) (day-str (if (and day (\u0026gt; day 0)) (format \u0026#34;%2dd \u0026#34; day) filler)) (str (string-trim-right (concat day-str hr-str min-str sec-str)))) (if inter (message \u0026#34;%0.2f seconds → %s\u0026#34; seconds (string-trim (replace-regexp-in-string \u0026#34; +\u0026#34; \u0026#34; \u0026#34; str))) str)))) (time (cond ((\u0026gt;= sec DAY) ;\u0026gt; day (let* ((days (/ (floor sec) DAY)) (rem (- sec (* days DAY)))) (cond ((= rem 0) (list days 0 0 0)) ((\u0026lt; rem MINUTE) ;; Note that (list rem) instead of just `rem\u0026#39; is being ;; passed to the recursive call to ;; `modi/seconds-to-human-time\u0026#39;. This helps us ;; distinguish between direct and re-entrant calls to ;; this function. (append (list days 0 0) (modi/seconds-to-human-time (list rem)))) ((\u0026lt; rem HOUR) (append (list days 0) (modi/seconds-to-human-time (list rem)))) (t (append (list days) (modi/seconds-to-human-time (list rem))))))) ((\u0026gt;= sec HOUR) ;\u0026gt; hour AND \u0026lt; day (let* ((hours (/ (floor sec) HOUR)) (rem (- sec (* hours HOUR)))) (cond ((= rem 0) (list hours 0 0)) ((\u0026lt; rem MINUTE) (append (list hours 0) (modi/seconds-to-human-time (list rem)))) (t (append (list hours) (modi/seconds-to-human-time (list rem))))))) ((\u0026gt;= sec MINUTE) ;\u0026gt; minute AND \u0026lt; hour (let* ((mins (/ (floor sec) MINUTE)) (rem (- sec (* mins MINUTE)))) (cond ((= rem 0) (list mins 0)) (t (append (list mins) (modi/seconds-to-human-time (list rem))))))) (t ;\u0026lt; minute (list sec))))) ;; If `seconds\u0026#39; is a number and not a list, this is *not* a recursive ;; call. Return the time as a string only then. For re-entrant ;; executions, return the `time\u0026#39; list instead. (if (numberp seconds) (funcall gen-time-string time inter) time)))) Code Snippet 4: Seconds to Human Time (Revision 1) Most of this snippet is just the day/hour/minute/second math. Apart from that, here are some points that I found of interest:\nI did not always want to prompt the user to enter the input argument. If a region was selected, the function assumes that the user selected a number, and skips the prompt step. So I used a plain (interactive) form instead of using (interactive \u0026quot;sPrompt: \u0026quot;) or (interactive \u0026quot;r\u0026quot;). See (eintr) Interactive Options and (elisp) Interactive Codes to learn about interactive and its codes.\nInstead of in-lining a modular chunk of logic, like the one where I convert a list like (1 2 3 4) into \u0026quot;1d 2h 3m 4s\u0026quot;, I assigned it to a let-bound symbol gen-time-string. That allowed the logic to be more discernible when used in:\n(if (numberp seconds) (funcall gen-time-string time inter) time) Also interesting is the fact that these let-bound lambdas can have their own doc-strings too. I make use of recursion in this function! But I needed this function to return a string (using that gen-time-string function) only when all the nested calls to itself were returned. So to distinguish between a direct call to the function, and re-entrant calls, when doing the latter, I make the input number a list of that number.\nSo while the function might take an input number like 7 for a direct call, that same number, when needed to call to a recursive call, would get passed as (list 7) or '(7). If you glance back as that little snippet above, I return the time as a string only if the input seconds is a number \u0026mdash; and not a list i.e. only when I am in the \u0026ldquo;direct call instance\u0026rdquo;. The internal variable time is a list and can have up to 4 number elements: (DAYS HOURS MINUTES SECONDS). The key was to always have each of those elements at their respective positions in the list.\nIf the input seconds is 7200 seconds i.e. 2 hours, I cannot allow time to be just (2), because then I wouldn\u0026rsquo;t know the unit of that 2 (2 days? 2 hours? ..) \u0026mdash; The nested cond logic for setting the time variable ensures it gets set to (2 0 0) instead. That way, it would read clearly as 2 hours, 0 minutes, and 0 seconds.\nBack inside gen-time-string, I then skip printing the time units that are 0 (unless everything is 0, in which case I print \u0026quot;0s\u0026quot;). So instead of printing \u0026quot;1d 0h 0m 5s\u0026quot;, it would print just \u0026quot;1d 5s\u0026quot;.\n"},"name":"Your car will be ready in 8000 seconds","published":"2018-02-07T18:10:00-05:00","summary":" Table of Contents Code Tests Test Output Source Closing Appendix Test output using format-seconds Code (Revision 1) Huh? 😕\nWell, a mechanic usually wouldn\u0026rsquo;t give you a time estimate in seconds, but a tool I am using prints something like this at the end:\nThe simulation took 54227.9 seconds in CPU time.\nThat triggered me to write a \u0026ldquo;little\u0026rdquo; script to convert seconds to human time i.e. time in days, hours, minutes and seconds.\n","type":"entry","url":"https://scripter.co/convert-seconds-to-human-time/"},{"content":{"html":"\u003cdiv class=\"ox-hugo-toc toc has-section-numbers\"\u003e\n\u003cdiv class=\"heading\"\u003eTable of Contents\u003c/div\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e \u003ca href=\"#using-mathjax\"\u003eUsing MathJax\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e \u003ca href=\"#using-html-plus-css\"\u003eUsing HTML + CSS\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#define-these-macros-in-org\"\u003eDefine these macros in Org\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#css\"\u003eCSS\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#use-the-org-macros\"\u003eUse the Org macros\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#references\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c!--endtoc--\u003e\n\u003cp\u003eEver wondered how to show \u003cspan class=\"latex\"\u003eL\u003csup\u003ea\u003c/sup\u003eT\u003csub\u003ee\u003c/sub\u003eX\u003c/span\u003e in HTML or a \u003ca href=\"https://ox-hugo.scripter.co\"\u003eHugo blog post\u003c/a\u003e\nexported from Org?\u003c/p\u003e\n\u003cp\u003eThere are 2 ways to do this:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eUsing MathJax \u0026ndash; \\(\\LaTeX\\).\u003c/li\u003e\n\u003cli\u003eUsing HTML + CSS \u0026ndash; \u003cspan class=\"latex\"\u003eL\u003csup\u003ea\u003c/sup\u003eT\u003csub\u003ee\u003c/sub\u003eX\u003c/span\u003e.\u003c/li\u003e\n\u003c/ol\u003e\n\n\u003ch2 id=\"using-mathjax\"\u003e\u003cspan class=\"section-num\"\u003e1\u003c/span\u003e Using MathJax\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-mathjax\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eIf you don\u0026rsquo;t mind including the \u003ca href=\"https://gitlab.com/kaushalmodi/hugo-theme-refined/blob/master/layouts/partials/mathjax.html\"\u003eMathJax script\u003c/a\u003e, it\u0026rsquo;s as simple as\ntyping \u003ccode\u003e$\\LaTeX$\u003c/code\u003e in Org, which results in \\(\\LaTeX\\).\u003c/p\u003e\n\u003cp\u003eSimilarly \\(\\TeX\\) (\u003ccode\u003e$\\TeX$\u003c/code\u003e) also works, though not \u003ccode\u003e$\\XeTeX$\u003c/code\u003e.\u003c/p\u003e\n\n\u003ch2 id=\"using-html-plus-css\"\u003e\u003cspan class=\"section-num\"\u003e2\u003c/span\u003e Using HTML + CSS\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-html-plus-css\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eAnd here\u0026rsquo;s another way if you don\u0026rsquo;t want to include MathJax.\u003c/p\u003e\n\n\u003ch3 id=\"define-these-macros-in-org\"\u003eDefine these macros in Org\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#define-these-macros-in-org\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+macro\u003c/span\u003e\u003cspan class=\"c\"\u003e: tex @@html:\u0026lt;span class=\u0026#34;tex\u0026#34;\u0026gt;T\u0026lt;sub\u0026gt;e\u0026lt;/sub\u0026gt;X\u0026lt;/span\u0026gt;@@\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+macro\u003c/span\u003e\u003cspan class=\"c\"\u003e: latex @@html:\u0026lt;span class=\u0026#34;latex\u0026#34;\u0026gt;L\u0026lt;sup\u0026gt;a\u0026lt;/sup\u0026gt;T\u0026lt;sub\u0026gt;e\u0026lt;/sub\u0026gt;X\u0026lt;/span\u0026gt;@@\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"cs\"\u003e#+macro\u003c/span\u003e\u003cspan class=\"c\"\u003e: xetex @@html:\u0026lt;span class=\u0026#34;xetex\u0026#34;\u0026gt;X\u0026lt;sub\u0026gt;\u0026amp;#398;\u0026lt;/sub\u0026gt;T\u0026lt;sub\u0026gt;E\u0026lt;/sub\u0026gt;X\u0026lt;/span\u0026gt;@@\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"css\"\u003eCSS\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#css\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eAdd this CSS directly in the page within a \u003ccode\u003e#+begin_export html\u003c/code\u003e /\n\u003ccode\u003e#+end_export\u003c/code\u003e block, or add that CSS your site\u0026rsquo;s stylesheet.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-html\" data-lang=\"html\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;\u003c/span\u003e\u003cspan class=\"nt\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003etex\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003elatex\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003etex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003elatex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003exetex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003efont-size\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"kt\"\u003eem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003etex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003elatex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003elatex\u003c/span\u003e \u003cspan class=\"nt\"\u003esup\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003exetex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003etext-transform\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"kc\"\u003euppercase\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003etex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003elatex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003exetex\u003c/span\u003e \u003cspan class=\"nt\"\u003esub\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003evertical-align\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mf\"\u003e-0.5\u003c/span\u003e\u003cspan class=\"kt\"\u003eex\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003emargin-left\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mf\"\u003e-0.1667\u003c/span\u003e\u003cspan class=\"kt\"\u003eem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003emargin-right\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mf\"\u003e-0.125\u003c/span\u003e\u003cspan class=\"kt\"\u003eem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nc\"\u003elatex\u003c/span\u003e \u003cspan class=\"nt\"\u003esup\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003efont-size\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mf\"\u003e0.85\u003c/span\u003e\u003cspan class=\"kt\"\u003eem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003evertical-align\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mf\"\u003e0.15\u003c/span\u003e\u003cspan class=\"kt\"\u003eem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003emargin-left\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mf\"\u003e-0.36\u003c/span\u003e\u003cspan class=\"kt\"\u003eem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"k\"\u003emargin-right\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"mf\"\u003e-0.15\u003c/span\u003e\u003cspan class=\"kt\"\u003eem\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e\u0026lt;/\u003c/span\u003e\u003cspan class=\"nt\"\u003estyle\u003c/span\u003e\u003cspan class=\"p\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"use-the-org-macros\"\u003eUse the Org macros\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#use-the-org-macros\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-org\" data-lang=\"org\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e- \u003c/span\u003e\u003cspan class=\"nb\"\u003e{{{tex}}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e- \u003c/span\u003e\u003cspan class=\"nb\"\u003e{{{latex}}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003e- \u003c/span\u003e\u003cspan class=\"nb\"\u003e{{{xetex}}}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eExport that from Org to HTML or Hugo, and you get:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cspan class=\"tex\"\u003eT\u003csub\u003ee\u003c/sub\u003eX\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"latex\"\u003eL\u003csup\u003ea\u003c/sup\u003eT\u003csub\u003ee\u003c/sub\u003eX\u003c/span\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan class=\"xetex\"\u003eX\u003csub\u003eƎ\u003c/sub\u003eT\u003csub\u003eE\u003c/sub\u003eX\u003c/span\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"references\"\u003eReferences\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#references\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://stackoverflow.com/a/8160532/1219634\"\u003estackoverflow.com\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"http://tess.oconnor.cx/2007/08/tex-poshlet\"\u003etess.oconnor.cx\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://hroy.eu/tips/TeX/htmlAndCss/\"\u003ehroy.eu\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e","text":" Table of Contents 1 Using MathJax 2 Using HTML + CSS Define these macros in Org CSS Use the Org macros References Ever wondered how to show LaTeX in HTML or a Hugo blog post exported from Org?\nThere are 2 ways to do this:\nUsing MathJax \u0026ndash; \\(\\LaTeX\\). Using HTML + CSS \u0026ndash; LaTeX. 1 Using MathJax\u0026nbsp;# If you don\u0026rsquo;t mind including the MathJax script, it\u0026rsquo;s as simple as typing $\\LaTeX$ in Org, which results in \\(\\LaTeX\\).\nSimilarly \\(\\TeX\\) ($\\TeX$) also works, though not $\\XeTeX$.\n2 Using HTML + CSS\u0026nbsp;# And here\u0026rsquo;s another way if you don\u0026rsquo;t want to include MathJax.\nDefine these macros in Org\u0026nbsp;# #+macro: tex @@html:\u0026lt;span class=\u0026#34;tex\u0026#34;\u0026gt;T\u0026lt;sub\u0026gt;e\u0026lt;/sub\u0026gt;X\u0026lt;/span\u0026gt;@@ #+macro: latex @@html:\u0026lt;span class=\u0026#34;latex\u0026#34;\u0026gt;L\u0026lt;sup\u0026gt;a\u0026lt;/sup\u0026gt;T\u0026lt;sub\u0026gt;e\u0026lt;/sub\u0026gt;X\u0026lt;/span\u0026gt;@@ #+macro: xetex @@html:\u0026lt;span class=\u0026#34;xetex\u0026#34;\u0026gt;X\u0026lt;sub\u0026gt;\u0026amp;#398;\u0026lt;/sub\u0026gt;T\u0026lt;sub\u0026gt;E\u0026lt;/sub\u0026gt;X\u0026lt;/span\u0026gt;@@ CSS\u0026nbsp;# Add this CSS directly in the page within a #+begin_export html / #+end_export block, or add that CSS your site\u0026rsquo;s stylesheet.\n\u0026lt;style\u0026gt; .tex, .latex, .tex sub, .latex sub, .xetex sub { font-size: 1em; } .tex sub, .latex sub, .latex sup, .xetex sub { text-transform: uppercase; } .tex sub, .latex sub, .xetex sub { vertical-align: -0.5ex; margin-left: -0.1667em; margin-right: -0.125em; } .latex sup { font-size: 0.85em; vertical-align: 0.15em; margin-left: -0.36em; margin-right: -0.15em; } \u0026lt;/style\u0026gt; Use the Org macros\u0026nbsp;# - {{{tex}}} - {{{latex}}} - {{{xetex}}} Export that from Org to HTML or Hugo, and you get:\nTeX LaTeX XƎTEX References\u0026nbsp;# stackoverflow.com tess.oconnor.cx hroy.eu "},"name":"LaTeX in HTML","published":"2018-02-02T18:58:00-05:00","summary":" Table of Contents 1 Using MathJax 2 Using HTML + CSS Define these macros in Org CSS Use the Org macros References Ever wondered how to show LaTeX in HTML or a Hugo blog post exported from Org?\n","type":"entry","url":"https://scripter.co/latex-in-html/"},{"content":{"html":"\u003cp\u003eI never quite liked the trend to have upper-cased keywords in Org\ndocuments, like \u003ccode\u003e#+TITLE\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eSo it was a pleasure to see that trend start changing in this \u003ca href=\"https://code.orgmode.org/bzg/org-mode/commit/13424336a6f30c50952d291e7a82906c1210daf0\"\u003eOrg\ncommit\u003c/a\u003e.. so that that same keyword would now be written as \u003ccode\u003e#+title\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eBut now I have quite a few Org documents with the ALL-CAPS keywords\nand block identifiers. So I came up with this little \u0026ldquo;lower-case all\nthe Org keywords and block identifiers in the current document\u0026rdquo; Elisp\ncommand:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/lower-case-org-keywords\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Lower case Org keywords and block identifiers.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eExample: \\\u0026#34;#+TITLE\\\u0026#34; -\u0026gt; \\\u0026#34;#+title\\\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e         \\\u0026#34;#+BEGIN_EXAMPLE\\\u0026#34; -\u0026gt; \\\u0026#34;#+begin_example\\\u0026#34;\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eInspiration:\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003ehttps://code.orgmode.org/bzg/org-mode/commit/13424336a6f30c50952d291e7a82906c1210daf0.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003egoto-char\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003epoint-min\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003ecase-fold-search\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ecount\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; Match examples: \u0026#34;#+FOO bar\u0026#34;, \u0026#34;#+FOO:\u0026#34;, \u0026#34;=#+FOO=\u0026#34;, \u0026#34;~#+FOO~\u0026#34;,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;;                 \u0026#34;‘#+FOO’\u0026#34;, \u0026#34;“#+FOO”\u0026#34;, \u0026#34;,#+FOO bar\u0026#34;,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;;                 \u0026#34;#+FOO_bar\u0026lt;eol\u0026gt;\u0026#34;, \u0026#34;#+FOO\u0026lt;eol\u0026gt;\u0026#34;.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhile\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ere-search-forward\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\\\\(?1:#\\\\+[A-Z_]+\\\\(?:_[[:alpha:]]+\\\\)*\\\\)\\\\(?:[ :=~’”]\\\\|$\\\\)\u0026#34;\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"nb\"\u003e:noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003ecount\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e1+\u003c/span\u003e \u003cspan class=\"nv\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ereplace-match\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edowncase\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ematch-string-no-properties\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"nb\"\u003e:fixedcase\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Lower-cased %d matches\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003ecount\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eHere are \u003ca href=\"https://github.com/kaushalmodi/ox-hugo/commit/ad1b513c0847383d19bf37becce6413697d14bd0\"\u003efew\u003c/a\u003e \u003ca href=\"https://github.com/kaushalmodi/eless/commit/f2eee31be46f6f296541d840f74fdd7dc1f5acd2\"\u003eexamples\u003c/a\u003e where \u003ckbd\u003eM-x\u003c/kbd\u003e \u003ccode\u003emodi/lower-case-org-keywords\u003c/code\u003e did\nhundreds of replacements for me, saving me a \u003cstrong\u003elot\u003c/strong\u003e of time\n😎.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/56a2d3ad42e6640ddae46b5afd3f93044b6d5172/setup-files/setup-org.el#L267-L286\"\u003eSource\u003c/a\u003e\u003c/p\u003e","text":"I never quite liked the trend to have upper-cased keywords in Org documents, like #+TITLE.\nSo it was a pleasure to see that trend start changing in this Org commit.. so that that same keyword would now be written as #+title.\nBut now I have quite a few Org documents with the ALL-CAPS keywords and block identifiers. So I came up with this little \u0026ldquo;lower-case all the Org keywords and block identifiers in the current document\u0026rdquo; Elisp command:\n(defun modi/lower-case-org-keywords () \u0026#34;Lower case Org keywords and block identifiers. Example: \\\u0026#34;#+TITLE\\\u0026#34; -\u0026gt; \\\u0026#34;#+title\\\u0026#34; \\\u0026#34;#+BEGIN_EXAMPLE\\\u0026#34; -\u0026gt; \\\u0026#34;#+begin_example\\\u0026#34; Inspiration: https://code.orgmode.org/bzg/org-mode/commit/13424336a6f30c50952d291e7a82906c1210daf0.\u0026#34; (interactive) (save-excursion (goto-char (point-min)) (let ((case-fold-search nil) (count 0)) ;; Match examples: \u0026#34;#+FOO bar\u0026#34;, \u0026#34;#+FOO:\u0026#34;, \u0026#34;=#+FOO=\u0026#34;, \u0026#34;~#+FOO~\u0026#34;, ;; \u0026#34;‘#+FOO’\u0026#34;, \u0026#34;“#+FOO”\u0026#34;, \u0026#34;,#+FOO bar\u0026#34;, ;; \u0026#34;#+FOO_bar\u0026lt;eol\u0026gt;\u0026#34;, \u0026#34;#+FOO\u0026lt;eol\u0026gt;\u0026#34;. (while (re-search-forward \u0026#34;\\\\(?1:#\\\\+[A-Z_]+\\\\(?:_[[:alpha:]]+\\\\)*\\\\)\\\\(?:[ :=~’”]\\\\|$\\\\)\u0026#34; nil :noerror) (setq count (1+ count)) (replace-match (downcase (match-string-no-properties 1)) :fixedcase nil nil 1)) (message \u0026#34;Lower-cased %d matches\u0026#34; count)))) Here are few examples where M-x modi/lower-case-org-keywords did hundreds of replacements for me, saving me a lot of time 😎.\nSource\n"},"name":"Converting Org keywords to lower-case","published":"2018-02-02T13:42:00-05:00","summary":"I never quite liked the trend to have upper-cased keywords in Org documents, like #+TITLE.\nSo it was a pleasure to see that trend start changing in this Org commit.. so that that same keyword would now be written as #+title.\n","type":"entry","url":"https://scripter.co/org-keywords-lower-case/"},{"content":{"html":"\u003cp\u003eThe Org and \u003ca href=\"https://orgmode.org/worg/\"\u003eWorg\u003c/a\u003e git repos can be committed to only via \u003cem\u003essh\u003c/em\u003e protocol\n(and not \u003cem\u003ehttps\u003c/em\u003e), and for technical reasons, I cannot commit to those\nrepos via \u003cem\u003essh\u003c/em\u003e from my primary development machine. So I ended up\nwith a flow that involves pushing commits to those repos using my\nNexus 6p phone.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://magit.vc/\"\u003eMagit\u003c/a\u003e is how I \u003cem\u003egit\u003c/em\u003e, and I love to primarily work from the\n\u003cem\u003e∗magit-log∗\u003c/em\u003e buffer (\u003ccode\u003eM-x magit-status\u003c/code\u003e, \u003ckbd\u003el\u003c/kbd\u003e \u003ckbd\u003eb\u003c/kbd\u003e). But the default\ncolumn widths were not optimal on a Nexus 6p 5.7\u0026quot; screen. And that\u0026rsquo;s\nwhat inspired this tweak, which looks great on a regular desktop\nmonitor too.\u003c/p\u003e\n\u003cp\u003eBefore I jump to the code, you can see in the below figure how the\nauthor and commit age columns took up roughly half the screen width on\nmy phone before the tweak (left), and how much easier it is to read\nthe commit messages after the tweak (right).\u003c/p\u003e\n\n\n\n\u003cfigure\u003e\n    \u003ca href=\"/images/magit_author_column.png\"\u003e\n        \u003cimg src=\"https://scripter.co/images/magit_author_column.png\" alt=\"Figure 1: Org-mode Worg commit log : Before (Left), After (Right)\"/\u003e \u003c/a\u003e\u003cfigcaption\u003e\n                \u003cp\u003e\n                    \u003cspan class=\"figure-number\"\u003eFigure 1: \u003c/span\u003eOrg-mode Worg commit log : Before (Left), After (Right)\n                    \n                        \n                        \u003c/p\u003e\n                \n            \u003c/figcaption\u003e\u003c/figure\u003e\n\n\u003cp\u003eSo the Magit Log columns tweaks are basically:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eAbbreviate the authors\u0026rsquo; first names to just their initials.\u003c/li\u003e\n\u003cli\u003eAbbreviate the commit ages to 1-character time units.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eTo implement those tweaks, I started digging through \u003ccode\u003emagit-log.el\u003c/code\u003e\nand found that I would need to customize (i) the \u003ccode\u003emagit-log-margin\u003c/code\u003e\nvariable and (ii) \u003ccode\u003emagit-log-format-margin\u003c/code\u003e function.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eCustomizing \u003ccode\u003emagit-log-margin\u003c/code\u003e variable allows me to use the\nabbreviated age instead of the verbose age strings (minute→m,\nhour→h, day→d, week→w, month→M, year→Y). It\u0026rsquo;s also where I specify\nhow wide I want the author column to be.. I can now reduce that\ncolumn width from the default value of 18 to 11 as I am abbreviating\nthe author name too.\u003c/li\u003e\n\u003cli\u003eReviewing the \u003ccode\u003emagit-log.el\u003c/code\u003e code, I realized that I also need to\nadvise the \u003ccode\u003emagit-log-format-margin\u003c/code\u003e function to implement the\nauthor name abbreviation.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eIn the below code snippet, I am using \u003ca href=\"https://github.com/jwiegley/use-package\"\u003e\u003ccode\u003euse-package\u003c/code\u003e\u003c/a\u003e\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e to customize\nthat variable and function in \u003ccode\u003emagit-log\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003euse-package\u003c/span\u003e \u003cspan class=\"nv\"\u003emagit-log\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nb\"\u003e:init\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eprogn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; (setq magit-log-margin \u0026#39;(t age magit-log-margin-width t 18)) ;Default value\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003emagit-log-margin\u003c/span\u003e \u003cspan class=\"o\"\u003e\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e \u003cspan class=\"nv\"\u003eage-abbreviated\u003c/span\u003e \u003cspan class=\"nv\"\u003emagit-log-margin-width\u003c/span\u003e \u003cspan class=\"nb\"\u003e:author\u003c/span\u003e \u003cspan class=\"mi\"\u003e11\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nb\"\u003e:config\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eprogn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; Abbreviate author name. I added this so that I can view Magit log without\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; too much commit message truncation even on narrow screens (like on phone).\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/magit-log--abbreviate-author\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kp\"\u003e\u0026amp;rest\u003c/span\u003e \u003cspan class=\"nv\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"s\"\u003e\u0026#34;The first arg is AUTHOR, abbreviate it.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eFirst Last  -\u0026gt; F Last\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eFirst.Last  -\u0026gt; F Last\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eLast, First -\u0026gt; F Last\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eFirst       -\u0026gt; First (no change).\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eIt is assumed that the author has only one or two names.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; ARGS               -\u0026gt; \u0026#39;((REV AUTHOR DATE))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; (car ARGS)         -\u0026gt; \u0026#39;(REV AUTHOR DATE)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"c1\"\u003e;; (nth 1 (car ARGS)) -\u0026gt; AUTHOR\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eauthor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enth\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecar\u003c/span\u003e \u003cspan class=\"nv\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e             \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eauthor-abbr\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003estring-match-p\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;,\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eauthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                              \u003cspan class=\"c1\"\u003e;; Last, First -\u0026gt; F Last\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\\\\(.*?\\\\), *\\\\(.\\\\).*\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\\\\2 \\\\1\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eauthor\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"c1\"\u003e;; First Last -\u0026gt; F Last\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ereplace-regexp-in-string\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\\\\(.\\\\).*?[. ]+\\\\(.*\\\\)\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;\\\\1 \\\\2\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003eauthor\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetf\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enth\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecar\u003c/span\u003e \u003cspan class=\"nv\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"nv\"\u003eauthor-abbr\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecar\u003c/span\u003e \u003cspan class=\"nv\"\u003eargs\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e                       \u003cspan class=\"c1\"\u003e;\u0026#39;(REV AUTHOR-ABBR DATE)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadvice-add\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;magit-log-format-margin\u003c/span\u003e \u003cspan class=\"nb\"\u003e:filter-args\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003emodi/magit-log--abbreviate-author\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cstrong\u003eNOTES\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eI need to set the \u003ccode\u003emagit-log-margin\u003c/code\u003e value in the \u003ccode\u003e:init\u003c/code\u003e block\nbecause that variable dynamically sets many other variables in\n\u003ccode\u003emagit-log\u003c/code\u003e at the time of loading. So we cannot wait for the whole\n\u003ccode\u003emagit-log\u003c/code\u003e to load before setting that variable. I wouldn\u0026rsquo;t need to\nworry about this if I were using the Emacs \u003cem\u003eCustomize\u003c/em\u003e interface to\nset this variable.\u003c/li\u003e\n\u003cli\u003eI use \u003ccode\u003emodi/magit-log--abbreviate-author\u003c/code\u003e to add a \u003ccode\u003e:filter-args\u003c/code\u003e\nadvice to \u003ccode\u003emagit-log-format-margin\u003c/code\u003e. The signature of the advised\nfunction is \u003ccode\u003e(magit-log-format-margin REV AUTHOR DATE)\u003c/code\u003e (as of\n\u003cem\u003eMagit 20180809.1716\u003c/em\u003e). So the advice basically replaces the\n\u003ccode\u003eAUTHOR\u003c/code\u003e arg with its abbreviated form as explained in the\n\u003ccode\u003emodi/magit-log--abbreviate-author\u003c/code\u003e doc-string.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eFeel free to ask for more explanation in comments in the case\nyou don\u0026rsquo;t use \u003ccode\u003euse-package\u003c/code\u003e.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e","text":"The Org and Worg git repos can be committed to only via ssh protocol (and not https), and for technical reasons, I cannot commit to those repos via ssh from my primary development machine. So I ended up with a flow that involves pushing commits to those repos using my Nexus 6p phone.\nMagit is how I git, and I love to primarily work from the ∗magit-log∗ buffer (M-x magit-status, l b). But the default column widths were not optimal on a Nexus 6p 5.7\u0026quot; screen. And that\u0026rsquo;s what inspired this tweak, which looks great on a regular desktop monitor too.\nBefore I jump to the code, you can see in the below figure how the author and commit age columns took up roughly half the screen width on my phone before the tweak (left), and how much easier it is to read the commit messages after the tweak (right).\nFigure 1: Org-mode Worg commit log : Before (Left), After (Right) So the Magit Log columns tweaks are basically:\nAbbreviate the authors\u0026rsquo; first names to just their initials. Abbreviate the commit ages to 1-character time units. To implement those tweaks, I started digging through magit-log.el and found that I would need to customize (i) the magit-log-margin variable and (ii) magit-log-format-margin function.\nCustomizing magit-log-margin variable allows me to use the abbreviated age instead of the verbose age strings (minute→m, hour→h, day→d, week→w, month→M, year→Y). It\u0026rsquo;s also where I specify how wide I want the author column to be.. I can now reduce that column width from the default value of 18 to 11 as I am abbreviating the author name too. Reviewing the magit-log.el code, I realized that I also need to advise the magit-log-format-margin function to implement the author name abbreviation. In the below code snippet, I am using use-package1 to customize that variable and function in magit-log.\n(use-package magit-log :init (progn ;; (setq magit-log-margin \u0026#39;(t age magit-log-margin-width t 18)) ;Default value (setq magit-log-margin \u0026#39;(t age-abbreviated magit-log-margin-width :author 11))) :config (progn ;; Abbreviate author name. I added this so that I can view Magit log without ;; too much commit message truncation even on narrow screens (like on phone). (defun modi/magit-log--abbreviate-author (\u0026amp;rest args) \u0026#34;The first arg is AUTHOR, abbreviate it. First Last -\u0026gt; F Last First.Last -\u0026gt; F Last Last, First -\u0026gt; F Last First -\u0026gt; First (no change). It is assumed that the author has only one or two names.\u0026#34; ;; ARGS -\u0026gt; \u0026#39;((REV AUTHOR DATE)) ;; (car ARGS) -\u0026gt; \u0026#39;(REV AUTHOR DATE) ;; (nth 1 (car ARGS)) -\u0026gt; AUTHOR (let* ((author (nth 1 (car args))) (author-abbr (if (string-match-p \u0026#34;,\u0026#34; author) ;; Last, First -\u0026gt; F Last (replace-regexp-in-string \u0026#34;\\\\(.*?\\\\), *\\\\(.\\\\).*\u0026#34; \u0026#34;\\\\2 \\\\1\u0026#34; author) ;; First Last -\u0026gt; F Last (replace-regexp-in-string \u0026#34;\\\\(.\\\\).*?[. ]+\\\\(.*\\\\)\u0026#34; \u0026#34;\\\\1 \\\\2\u0026#34; author)))) (setf (nth 1 (car args)) author-abbr)) (car args)) ;\u0026#39;(REV AUTHOR-ABBR DATE) (advice-add \u0026#39;magit-log-format-margin :filter-args #\u0026#39;modi/magit-log--abbreviate-author))) NOTES\nI need to set the magit-log-margin value in the :init block because that variable dynamically sets many other variables in magit-log at the time of loading. So we cannot wait for the whole magit-log to load before setting that variable. I wouldn\u0026rsquo;t need to worry about this if I were using the Emacs Customize interface to set this variable. I use modi/magit-log--abbreviate-author to add a :filter-args advice to magit-log-format-margin. The signature of the advised function is (magit-log-format-margin REV AUTHOR DATE) (as of Magit 20180809.1716). So the advice basically replaces the AUTHOR arg with its abbreviated form as explained in the modi/magit-log--abbreviate-author doc-string. Feel free to ask for more explanation in comments in the case you don\u0026rsquo;t use use-package.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"Narrowing the Author column in Magit","published":"2017-12-18T16:36:00-05:00","summary":"The Org and Worg git repos can be committed to only via ssh protocol (and not https), and for technical reasons, I cannot commit to those repos via ssh from my primary development machine. So I ended up with a flow that involves pushing commits to those repos using my Nexus 6p phone.\nMagit is how I git, and I love to primarily work from the ∗magit-log∗ buffer (M-x magit-status, l b). But the default column widths were not optimal on a Nexus 6p 5.7\u0026quot; screen. And that\u0026rsquo;s what inspired this tweak, which looks great on a regular desktop monitor too.\n","type":"entry","url":"https://scripter.co/narrowing-the-author-column-in-magit/"},{"content":{"html":"\u003cp\u003eI use emacs \u0026ndash; with a \u003ca href=\"https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html\"\u003eserver\u003c/a\u003e\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e and client setup \u0026ndash; so that I\ncan quickly open new files in it using \u003ccode\u003eemacsclient\u003c/code\u003e. My typical setup\nis to have \u003ccode\u003exterm\u003c/code\u003e + \u003ccode\u003etmux\u003c/code\u003e on one monitor and a single emacs(client)\nframe on another. But there are times when I do not want to\nshift focus from one monitor to another, like when I just need to\nreview some log file. So I started using an alias to \u003ccode\u003eemacs -nw -Q\u003c/code\u003e to\nquickly open log files, review, filter, and \u003ccode\u003eC-x C-c\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eOf course, that\u0026rsquo;s not where this post ends.  An alias was no longer\nadequate to do what I wanted it to do more ..\u003c/p\u003e\n\u003cp\u003eI typically do my text editing in the emacs frame, while do just\nnon-editing actions like viewing, navigating, searching, filtering in\nquick emacs sessions from \u003ccode\u003etmux\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eI wanted that \u0026ldquo;tmux emacs\u0026rdquo; to be independent of my config, independent\nof the server \u0026ndash; Just something really quick that I can launch, \u003cem\u003edo\u003c/em\u003e,\nand quit. I wanted something \u003cem\u003elike\u003c/em\u003e \u003ccode\u003eless\u003c/code\u003e, but better .. better in\nthese ways:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDo syntax highlighting\u003c/li\u003e\n\u003cli\u003eRender Org-mode files\u003c/li\u003e\n\u003cli\u003eA better navigable man page viewer\u003c/li\u003e\n\u003cli\u003eDired, especially \u003ccode\u003ewdired\u003c/code\u003e (batch edit symbolic links, for example?)\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e\u003c/li\u003e\n\u003cli\u003eShow colored diffs\u003c/li\u003e\n\u003cli\u003eFilter log files to only show or not show lines matching a regexp\u003c/li\u003e\n\u003cli\u003eStart auto-reverting log files when I want (like \u003ccode\u003etail -f\u003c/code\u003e)\u003c/li\u003e\n\u003cli\u003eQuickly change frame and font sizes\u003c/li\u003e\n\u003cli\u003e.. and more; basically everything that emacs has to offer!\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eI call it \u003ccode\u003eeless\u003c/code\u003e and here\u0026rsquo;s a little taste of what it looks like:\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eClick the below image to see a GIF animation in larger size.\u003c/em\u003e\n\u003ca href=\"/gifs/eless.gif\"\u003e\u003cimg src=\"/images/eless.png\" alt=\"eless\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp\u003eAs a bonus:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cinput checked=\"\" disabled=\"\" type=\"checkbox\"\u003e This script passes \u003ca href=\"https://www.shellcheck.net\"\u003eShellCheck\u003c/a\u003e, and\u003c/li\u003e\n\u003cli\u003e\u003cinput checked=\"\" disabled=\"\" type=\"checkbox\"\u003e Unofficial Bash \u003ca href=\"http://redsymbol.net/articles/unofficial-bash-strict-mode\"\u003estrict mode\u003c/a\u003e is enabled.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/kaushalmodi/eless\"\u003eTry it out\u003c/a\u003e and let me know how you find it. As you will see,\n\u003ccode\u003eeless\u003c/code\u003e is a bash script where most of it is a string containing a\n\u003cem\u003esane\u003c/em\u003e emacs configuration for \u003ccode\u003eview-mode\u003c/code\u003e. I wanted \u003ccode\u003eeless\u003c/code\u003e to be a\nmonolithic script, and not a multi-file setup.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eeless -h \u003cspan class=\"p\"\u003e|\u003c/span\u003e eless\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003chr\u003e\n\u003cp\u003e\u003cstrong\u003eUpdate (2017/04/25)\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003eThanks to the \u003ca href=\"https://github.com/kaushalmodi/eless/pull/2\"\u003ePR\u003c/a\u003e by \u003ca href=\"https://github.com/iqbalansari\"\u003eIqbal Ansari\u003c/a\u003e, \u003ccode\u003eeless\u003c/code\u003e now supports\nreading piped-in data even when emacs is run in terminal mode. The\nsolution was to:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAlways start the emacs process in a sub-shell, and\u003c/li\u003e\n\u003cli\u003eRedirect \u003ccode\u003e/dev/tty\u003c/code\u003e into that emacs instance.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThat way, that emacs instance would always \u003cem\u003ethink\u003c/em\u003e that it is\nreceiving input from tty \u0026ndash; even when the wrapper bash script is\nreceiving input from the pipe.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eYou can also do \u003ckbd\u003eC-h\u003c/kbd\u003e\u003ckbd\u003ei\u003c/kbd\u003e\u003ckbd\u003eg\u003c/kbd\u003e \u003ccode\u003e(emacs) Emacs Server\u003c/code\u003e from within emacs.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eDo: \u003ckbd\u003eC-h\u003c/kbd\u003e\u003ckbd\u003ei\u003c/kbd\u003e\u003ckbd\u003eg\u003c/kbd\u003e \u003ccode\u003e(emacs) Wdired\u003c/code\u003e\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e","text":"I use emacs \u0026ndash; with a server1 and client setup \u0026ndash; so that I can quickly open new files in it using emacsclient. My typical setup is to have xterm + tmux on one monitor and a single emacs(client) frame on another. But there are times when I do not want to shift focus from one monitor to another, like when I just need to review some log file. So I started using an alias to emacs -nw -Q to quickly open log files, review, filter, and C-x C-c.\nOf course, that\u0026rsquo;s not where this post ends. An alias was no longer adequate to do what I wanted it to do more ..\nI typically do my text editing in the emacs frame, while do just non-editing actions like viewing, navigating, searching, filtering in quick emacs sessions from tmux.\nI wanted that \u0026ldquo;tmux emacs\u0026rdquo; to be independent of my config, independent of the server \u0026ndash; Just something really quick that I can launch, do, and quit. I wanted something like less, but better .. better in these ways:\nDo syntax highlighting Render Org-mode files A better navigable man page viewer Dired, especially wdired (batch edit symbolic links, for example?)2 Show colored diffs Filter log files to only show or not show lines matching a regexp Start auto-reverting log files when I want (like tail -f) Quickly change frame and font sizes .. and more; basically everything that emacs has to offer! I call it eless and here\u0026rsquo;s a little taste of what it looks like:\nClick the below image to see a GIF animation in larger size. As a bonus:\nThis script passes ShellCheck, and Unofficial Bash strict mode is enabled. Try it out and let me know how you find it. As you will see, eless is a bash script where most of it is a string containing a sane emacs configuration for view-mode. I wanted eless to be a monolithic script, and not a multi-file setup.\neless -h | eless Update (2017/04/25)\nThanks to the PR by Iqbal Ansari, eless now supports reading piped-in data even when emacs is run in terminal mode. The solution was to:\nAlways start the emacs process in a sub-shell, and Redirect /dev/tty into that emacs instance. That way, that emacs instance would always think that it is receiving input from tty \u0026ndash; even when the wrapper bash script is receiving input from the pipe.\nYou can also do C-hig (emacs) Emacs Server from within emacs.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nDo: C-hig (emacs) Wdired\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"A Better less","published":"2017-04-24T17:54:51-04:00","summary":"I use emacs \u0026ndash; with a server1 and client setup \u0026ndash; so that I can quickly open new files in it using emacsclient. My typical setup is to have xterm + tmux on one monitor and a single emacs(client) frame on another. But there are times when I do not want to shift focus from one monitor to another, like when I just need to review some log file. So I started using an alias to emacs -nw -Q to quickly open log files, review, filter, and C-x C-c.\nOf course, that\u0026rsquo;s not where this post ends. An alias was no longer adequate to do what I wanted it to do more ..\n","type":"entry","url":"https://scripter.co/a-better-less/"},{"content":{"html":"\u003cp\u003eUsing \u003cem\u003eemacsclient\u003c/em\u003e instead of the \u003cem\u003eemacs\u003c/em\u003e binary is a very useful technique to prevent loading emacs from scratch each time you open a new file. That technique is useful on Windows too. But for this to work on Windows, we need some more elisp and Windows environment variable configuration than just the below code,\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;server\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Start a server if (server-running-p) does not return t (e.g. if it\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; returns nil or :other)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eeq\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eserver-running-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eserver-start\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"setup-in-elisp\"\u003eSetup in elisp\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#setup-in-elisp\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\n\u003ch3 id=\"use-tcp-sockets\"\u003eUse TCP sockets\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#use-tcp-sockets\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eI do not understand what this means, but you need to use TCP sockets instead of local sockets for the server to run on Windows. By default the value of \u003ccode\u003eserver-use-tcp\u003c/code\u003e is \u003ccode\u003enil\u003c/code\u003e. So for Windows, we need this,\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eequal\u003c/span\u003e \u003cspan class=\"nf\"\u003ewindow-system\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;w32\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eserver-use-tcp\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch3 id=\"uniquify-the-server-authentication-directory\"\u003eUniquify the server authentication directory\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#uniquify-the-server-authentication-directory\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eWhen \u003ccode\u003eserver-use-tcp\u003c/code\u003e is a non-nil value, the \u003ccode\u003eserver-auth-dir\u003c/code\u003e is used to store the server authentication files. It is not unusual for me to have emacs running on two different machines (possibly different versions of emacs on the same machine too in rare occassions) sharing the same \u003ccode\u003e~/.emacs.d/\u003c/code\u003e via Dropbox. So I \u003cem\u003euniquify\u003c/em\u003e the \u003ccode\u003eserver-auth-dir\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Below needs to be set before you require \u0026#39;server\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eserver-auth-dir\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003edir\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"nv\"\u003euser-emacs-directory\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                         \u003cspan class=\"s\"\u003e\u0026#34;server_\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eformat\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%s_%s\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                           \u003cspan class=\"nv\"\u003eemacs-major-version\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                           \u003cspan class=\"nv\"\u003eemacs-minor-version\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                         \u003cspan class=\"s\"\u003e\u0026#34;_\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003esystem-name\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e; Use the var `system-name\u0026#39; directly\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                                        \u003cspan class=\"c1\"\u003e; if using emacs older than 25.1.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                         \u003cspan class=\"s\"\u003e\u0026#34;/\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emake-directory\u003c/span\u003e \u003cspan class=\"nv\"\u003edir\u003c/span\u003e \u003cspan class=\"nb\"\u003e:parents\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nv\"\u003edir\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eSo, if am running emacs 25.1, and if my Windows machine name is \u003ccode\u003eFOO\u003c/code\u003e, the value of \u003ccode\u003eserver-auth-dir\u003c/code\u003e will be set to \u003ccode\u003e~/.emacs.d/server_25_1_FOO/\u003c/code\u003e.\u003c/p\u003e\n\n\u003ch3 id=\"prevent-server-is-unsafe-errors\"\u003ePrevent \u0026lsquo;server is unsafe\u0026rsquo; errors\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#prevent-server-is-unsafe-errors\"\u003e#\u003c/a\u003e\u003c/h3\u003e\n\n\n\u003cp\u003eI also had to put the below hack in order for the server to start on Windows.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewith-eval-after-load\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;server\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eequal\u003c/span\u003e \u003cspan class=\"nf\"\u003ewindow-system\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;w32\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; Suppress error \u0026#34;directory  ~/.emacs.d/server is unsafe\u0026#34;. It is needed\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"c1\"\u003e;; needed for the server to start on Windows.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003eserver-ensure-safe-dir\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edir\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Noop\u0026#34;\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"windows-environment-variables\"\u003eWindows environment variables\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#windows-environment-variables\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eYou will need to set \u003ccode\u003eEMACS_SERVER_FILE\u003c/code\u003e and \u003ccode\u003eHOME\u003c/code\u003e environment variables in Windows. I came up with the below steps that work on Windows 7.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eClick on \u003cem\u003eStart \u0026gt; Control Panel\u003c/em\u003e.\u003c/li\u003e\n\u003cli\u003eSearch for \u003cem\u003eenvironment\u003c/em\u003e in the search field.\u003c/li\u003e\n\u003cli\u003eClick on \u003cem\u003eEdit environment variables for your account\u003c/em\u003e.\u003c/li\u003e\n\u003cli\u003eClick on \u003cem\u003eNew\u003c/em\u003e under \u003cem\u003eUser variables for ..\u003c/em\u003e.\u003c/li\u003e\n\u003cli\u003eEnter \u003ccode\u003eEMACS_SERVER_FILE\u003c/code\u003e in the \u003cem\u003eVariable name\u003c/em\u003e field and appropriate value in the \u003cem\u003eVariable value\u003c/em\u003e field to match the value set in \u003ccode\u003eserver-auth-dir\u003c/code\u003e, appended by \u003ccode\u003eserver\u003c/code\u003e.\n\u003cul\u003e\n\u003cli\u003eMy \u003ccode\u003eserver-auth-dir\u003c/code\u003e value is \u003ccode\u003e~/.emacs.d/server_25_1_FOO/\u003c/code\u003e. So I have set \u003cem\u003eVariable value\u003c/em\u003e to \u003ccode\u003eC:\\Users\\KModi\\Dropbox\\home\\.emacs.d\\server_25_1_FOO\\server\u003c/code\u003e. Note the use of \u003ccode\u003e/\u003c/code\u003e instead of \u003ccode\u003e\\\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eAlso I have set my user environment variable \u003ccode\u003eHOME\u003c/code\u003e in Windows to \u003ccode\u003eC:\\Users\\KModi\\Dropbox\\home\u003c/code\u003e using the same steps as above.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eHit \u003cem\u003eOK\u003c/em\u003e to save your environment variable setup.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"start-the-server\"\u003eStart the server\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#start-the-server\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eAnd then you need to have the below snippet that starts the server when you start emacs.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;server\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Start a server if (server-running-p) does not return t (e.g. if it\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; returns nil or :other)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eeq\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eserver-running-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eserver-start\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"using-the-emacsclient\"\u003eUsing the emacsclient\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#using-the-emacsclient\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003col\u003e\n\u003cli\u003eStart emacs using the \u003ccode\u003erunemacs.exe\u003c/code\u003e executable for the first time on starting Windows.\u003c/li\u003e\n\u003cli\u003eUse the \u003ccode\u003eemacsclientw.exe\u003c/code\u003e executable after that.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eTo makes things easy, I add \u003ccode\u003erunemacs.exe\u003c/code\u003e \u003cem\u003eShortcut\u003c/em\u003e to \u003cem\u003eAll Programs \u0026gt; Startup\u003c/em\u003e. So emacs starts automatically each time I boot Windows.\u003c/p\u003e\n\u003cp\u003eIf you need to always open certain files in emacs using \u003cem\u003eemacsclient\u003c/em\u003e,\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cem\u003eShift + Right-click\u003c/em\u003e on that file.\u003c/li\u003e\n\u003cli\u003eSelect \u003cem\u003eOpen with\u003c/em\u003e.\u003c/li\u003e\n\u003cli\u003eClick \u003cem\u003eSelect default program\u003c/em\u003e and choose the \u003ccode\u003eemacsclientw.exe\u003c/code\u003e executable.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"closing\"\u003eClosing\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#closing\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cul\u003e\n\u003cli\u003eYou can find my full setup related to emacs server setup \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/6c7b77af6ea39fd6e016a873fad763a712547223/setup-files/setup-server.el\"\u003ehere\u003c/a\u003e.\u003c/li\u003e\n\u003cli\u003eThis has been tested to work on emacs 25.1 on the \u003ca href=\"https://ftp.gnu.org/gnu/emacs/windows/\"\u003eofficial emacs Windows\u003c/a\u003e as well as \u003ca href=\"https://github.com/zklhp/emacs-w64/releases\"\u003e\u003cem\u003eemacs-w64\u003c/em\u003e\u003c/a\u003e builds.\u003c/li\u003e\n\u003c/ul\u003e","text":"Using emacsclient instead of the emacs binary is a very useful technique to prevent loading emacs from scratch each time you open a new file. That technique is useful on Windows too. But for this to work on Windows, we need some more elisp and Windows environment variable configuration than just the below code,\n(require \u0026#39;server) ;; Start a server if (server-running-p) does not return t (e.g. if it ;; returns nil or :other) (or (eq (server-running-p) t) (server-start)) Setup in elisp\u0026nbsp;# Use TCP sockets\u0026nbsp;# I do not understand what this means, but you need to use TCP sockets instead of local sockets for the server to run on Windows. By default the value of server-use-tcp is nil. So for Windows, we need this,\n(when (equal window-system \u0026#39;w32) (setq server-use-tcp t)) Uniquify the server authentication directory\u0026nbsp;# When server-use-tcp is a non-nil value, the server-auth-dir is used to store the server authentication files. It is not unusual for me to have emacs running on two different machines (possibly different versions of emacs on the same machine too in rare occassions) sharing the same ~/.emacs.d/ via Dropbox. So I uniquify the server-auth-dir.\n;; Below needs to be set before you require \u0026#39;server (setq server-auth-dir (let ((dir (concat user-emacs-directory \u0026#34;server_\u0026#34; (format \u0026#34;%s_%s\u0026#34; emacs-major-version emacs-minor-version) \u0026#34;_\u0026#34; (system-name) ; Use the var `system-name\u0026#39; directly ; if using emacs older than 25.1. \u0026#34;/\u0026#34;))) (make-directory dir :parents) dir)) So, if am running emacs 25.1, and if my Windows machine name is FOO, the value of server-auth-dir will be set to ~/.emacs.d/server_25_1_FOO/.\nPrevent \u0026lsquo;server is unsafe\u0026rsquo; errors\u0026nbsp;# I also had to put the below hack in order for the server to start on Windows.\n(with-eval-after-load \u0026#39;server (when (equal window-system \u0026#39;w32) ;; Suppress error \u0026#34;directory ~/.emacs.d/server is unsafe\u0026#34;. It is needed ;; needed for the server to start on Windows. (defun server-ensure-safe-dir (dir) \u0026#34;Noop\u0026#34; t))) Windows environment variables\u0026nbsp;# You will need to set EMACS_SERVER_FILE and HOME environment variables in Windows. I came up with the below steps that work on Windows 7.\nClick on Start \u0026gt; Control Panel. Search for environment in the search field. Click on Edit environment variables for your account. Click on New under User variables for ... Enter EMACS_SERVER_FILE in the Variable name field and appropriate value in the Variable value field to match the value set in server-auth-dir, appended by server. My server-auth-dir value is ~/.emacs.d/server_25_1_FOO/. So I have set Variable value to C:\\Users\\KModi\\Dropbox\\home\\.emacs.d\\server_25_1_FOO\\server. Note the use of / instead of \\. Also I have set my user environment variable HOME in Windows to C:\\Users\\KModi\\Dropbox\\home using the same steps as above. Hit OK to save your environment variable setup. Start the server\u0026nbsp;# And then you need to have the below snippet that starts the server when you start emacs.\n(require \u0026#39;server) ;; Start a server if (server-running-p) does not return t (e.g. if it ;; returns nil or :other) (or (eq (server-running-p) t) (server-start)) Using the emacsclient\u0026nbsp;# Start emacs using the runemacs.exe executable for the first time on starting Windows. Use the emacsclientw.exe executable after that. To makes things easy, I add runemacs.exe Shortcut to All Programs \u0026gt; Startup. So emacs starts automatically each time I boot Windows.\nIf you need to always open certain files in emacs using emacsclient,\nShift + Right-click on that file. Select Open with. Click Select default program and choose the emacsclientw.exe executable. Closing\u0026nbsp;# You can find my full setup related to emacs server setup here. This has been tested to work on emacs 25.1 on the official emacs Windows as well as emacs-w64 builds. "},"name":"Emacsclient on Windows","published":"2016-11-19T21:37:14-05:00","summary":"Using emacsclient instead of the emacs binary is a very useful technique to prevent loading emacs from scratch each time you open a new file. That technique is useful on Windows too. But for this to work on Windows, we need some more elisp and Windows environment variable configuration than just the below code,\n(require \u0026#39;server) ;; Start a server if (server-running-p) does not return t (e.g. if it ;; returns nil or :other) (or (eq (server-running-p) t) (server-start)) ","type":"entry","url":"https://scripter.co/emacsclient-on-windows/"},{"content":{"html":"\u003cp\u003eIn almost all of my \u003ccode\u003eediff\u003c/code\u003e use cases, I would have windows open\nside-by-side in a frame, and then I would want to do a diff between\nthe two using \u003ccode\u003eediff-buffers\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eBut emacs doesn\u0026rsquo;t know that I obviously want to diff those two\nside-by-side buffers! So it always asks me to select the buffers to be\ndiffed. The same problem is when using \u003ccode\u003eediff-files\u003c/code\u003e too.\u003c/p\u003e\n\u003cp\u003eSo I came up with the following helper function to pick the correct\n\u003ccode\u003eediff\u003c/code\u003e command.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003emodi/ediff-dwim\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Do ediff as I mean.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eIf a region is active, call \u003c/span\u003e\u003cspan class=\"ss\"\u003e`ediff-regions-wordwise\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eElse if the frame has 2 windows with identical major modes,\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e  - Do \u003c/span\u003e\u003cspan class=\"ss\"\u003e`ediff-files\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e if the buffers are associated to files and the buffers\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e    have not been modified.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003e  - Do \u003c/span\u003e\u003cspan class=\"ss\"\u003e`ediff-buffers\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e otherwise.\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eElse if the current is a file buffer with a VC backend, call \u003c/span\u003e\u003cspan class=\"ss\"\u003e`vc-ediff\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003eElse call \u003c/span\u003e\u003cspan class=\"ss\"\u003e`ediff-buffers\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elet*\u003c/span\u003e \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003enum-win\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003esafe-length\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ewindow-list\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ebufa\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eget-buffer\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebuffer-name\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003efilea\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebuffer-file-name\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufa\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003emodea\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewith-current-buffer\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufa\u003c/span\u003e \u003cspan class=\"nv\"\u003emajor-mode\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e         \u003cspan class=\"nv\"\u003ebufb\u003c/span\u003e \u003cspan class=\"nv\"\u003efileb\u003c/span\u003e \u003cspan class=\"nv\"\u003emodeb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esave-excursion\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eother-window\u003c/span\u003e \u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufb\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eget-buffer\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebuffer-name\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003efileb\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebuffer-file-name\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufb\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003emodeb\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewith-current-buffer\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufb\u003c/span\u003e \u003cspan class=\"nv\"\u003emajor-mode\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003econd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"c1\"\u003e;; If a region is selected\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nv\"\u003eregion-active-p\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecall-interactively\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eediff-regions-wordwise\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"c1\"\u003e;; Else if 2 windows with same major modes\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e=\u003c/span\u003e \u003cspan class=\"mi\"\u003e2\u003c/span\u003e \u003cspan class=\"nv\"\u003enum-win\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eeq\u003c/span\u003e \u003cspan class=\"nv\"\u003emodea\u003c/span\u003e \u003cspan class=\"nv\"\u003emodeb\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eif\u003c/span\u003e \u003cspan class=\"c1\"\u003e;; If either of the buffers is not associated to a file,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"c1\"\u003e;; or if either of the buffers is modified\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eor\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enull\u003c/span\u003e \u003cspan class=\"nv\"\u003efilea\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003enull\u003c/span\u003e \u003cspan class=\"nv\"\u003efileb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebuffer-modified-p\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufa\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e              \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ebuffer-modified-p\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufb\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eprogn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Running (ediff-buffers \\\u0026#34;%s\\\u0026#34; \\\u0026#34;%s\\\u0026#34;) ..\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufa\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e            \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eediff-buffers\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufa\u003c/span\u003e \u003cspan class=\"nv\"\u003ebufb\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eprogn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003emessage\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Running (ediff-files \\\u0026#34;%s\\\u0026#34; \\\u0026#34;%s\\\u0026#34;) ..\u0026#34;\u003c/span\u003e \u003cspan class=\"nv\"\u003efilea\u003c/span\u003e \u003cspan class=\"nv\"\u003efileb\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e          \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eediff-files\u003c/span\u003e \u003cspan class=\"nv\"\u003efilea\u003c/span\u003e \u003cspan class=\"nv\"\u003efileb\u003c/span\u003e\u003cspan class=\"p\"\u003e))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"c1\"\u003e;; Else if file in current buffer has a vc backend\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"p\"\u003e((\u003c/span\u003e\u003cspan class=\"nb\"\u003eand\u003c/span\u003e \u003cspan class=\"nv\"\u003efilea\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003evc-registered\u003c/span\u003e \u003cspan class=\"nv\"\u003efilea\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecall-interactively\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003evc-ediff\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"c1\"\u003e;; Else call `ediff-buffers\u0026#39;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"no\"\u003et\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003ecall-interactively\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eediff-buffers\u003c/span\u003e\u003cspan class=\"p\"\u003e)))))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003ca href=\"https://github.com/search?utf8=%E2%9C%93\u0026amp;q=user:kaushalmodi+extension:el++%22defun+modi/ediff-dwim%22\u0026amp;type=Code\"\u003eFind this function in my emacs config\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eMy favorite \u003ccode\u003eediff\u003c/code\u003e settings are:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-emacs-lisp\" data-lang=\"emacs-lisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; No separate frame for ediff control buffer\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eediff-window-setup-function\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003eediff-setup-windows-plain\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Split windows horizontally in ediff (instead of vertically)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eediff-split-window-function\u003c/span\u003e \u003cspan class=\"nf\"\u003e#\u0026#39;\u003c/span\u003e\u003cspan class=\"nv\"\u003esplit-window-horizontally\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","text":"In almost all of my ediff use cases, I would have windows open side-by-side in a frame, and then I would want to do a diff between the two using ediff-buffers.\nBut emacs doesn\u0026rsquo;t know that I obviously want to diff those two side-by-side buffers! So it always asks me to select the buffers to be diffed. The same problem is when using ediff-files too.\nSo I came up with the following helper function to pick the correct ediff command.\n(defun modi/ediff-dwim () \u0026#34;Do ediff as I mean. If a region is active, call `ediff-regions-wordwise\u0026#39;. Else if the frame has 2 windows with identical major modes, - Do `ediff-files\u0026#39; if the buffers are associated to files and the buffers have not been modified. - Do `ediff-buffers\u0026#39; otherwise. Else if the current is a file buffer with a VC backend, call `vc-ediff\u0026#39; Else call `ediff-buffers\u0026#39;.\u0026#34; (interactive) (let* ((num-win (safe-length (window-list))) (bufa (get-buffer (buffer-name))) (filea (buffer-file-name bufa)) (modea (with-current-buffer bufa major-mode)) bufb fileb modeb) (save-excursion (other-window 1) (setq bufb (get-buffer (buffer-name))) (setq fileb (buffer-file-name bufb)) (setq modeb (with-current-buffer bufb major-mode))) (cond ;; If a region is selected ((region-active-p) (call-interactively #\u0026#39;ediff-regions-wordwise)) ;; Else if 2 windows with same major modes ((and (= 2 num-win) (eq modea modeb)) (if ;; If either of the buffers is not associated to a file, ;; or if either of the buffers is modified (or (null filea) (null fileb) (buffer-modified-p bufa) (buffer-modified-p bufb)) (progn (message \u0026#34;Running (ediff-buffers \\\u0026#34;%s\\\u0026#34; \\\u0026#34;%s\\\u0026#34;) ..\u0026#34; bufa bufb) (ediff-buffers bufa bufb)) (progn (message \u0026#34;Running (ediff-files \\\u0026#34;%s\\\u0026#34; \\\u0026#34;%s\\\u0026#34;) ..\u0026#34; filea fileb) (ediff-files filea fileb)))) ;; Else if file in current buffer has a vc backend ((and filea (vc-registered filea)) (call-interactively #\u0026#39;vc-ediff)) ;; Else call `ediff-buffers\u0026#39; (t (call-interactively #\u0026#39;ediff-buffers))))) Find this function in my emacs config.\nMy favorite ediff settings are:\n;; No separate frame for ediff control buffer (setq ediff-window-setup-function #\u0026#39;ediff-setup-windows-plain) ;; Split windows horizontally in ediff (instead of vertically) (setq ediff-split-window-function #\u0026#39;split-window-horizontally) "},"name":"Do Ediff as I mean","published":"2015-03-09T17:31:45-04:00","summary":"In almost all of my ediff use cases, I would have windows open side-by-side in a frame, and then I would want to do a diff between the two using ediff-buffers.\nBut emacs doesn\u0026rsquo;t know that I obviously want to diff those two side-by-side buffers! So it always asks me to select the buffers to be diffed. The same problem is when using ediff-files too.\nSo I came up with the following helper function to pick the correct ediff command.\n","type":"entry","url":"https://scripter.co/do-ediff-as-i-mean/"},{"content":{"html":"\u003cp\u003eIn Magit buffer \u003ccode\u003e*magit: ..*\u003c/code\u003e,\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eHit \u003ccode\u003ex\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eSelect \u003ccode\u003eorigin/master\u003c/code\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eAbove action will undo all the commits that haven\u0026rsquo;t been pushed to\n\u003ccode\u003eorigin/master\u003c/code\u003e. It will still preserve the modified states of the yet-to-be\nstaged/committed files.\u003c/p\u003e","text":"In Magit buffer *magit: ..*,\nHit x Select origin/master Above action will undo all the commits that haven\u0026rsquo;t been pushed to origin/master. It will still preserve the modified states of the yet-to-be staged/committed files.\n"},"name":"How to undo the unpushed commits in magit?","published":"2014-10-15T11:17:52-04:00","summary":"In Magit buffer *magit: ..*,\nHit x Select origin/master ","type":"entry","url":"https://scripter.co/how-to-undo-the-unpushed-commits-in-magit/"},{"content":{"html":"\u003cp\u003eI am in the process of converting traditional verilog test benches to\nSystemVerilog UVM test benches. As per the UVM methodology, it is recommended to\nuse \u003ccode\u003e `uvm_info\u003c/code\u003e instead of \u003ccode\u003e$display\u003c/code\u003e statements so that the \u003ccode\u003einfo\u003c/code\u003e statement\nencodes a \u003cem\u003eMessage ID\u003c/em\u003e and \u003cem\u003eMessage Verbosity\u003c/em\u003e along with the message required\nto be printed.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eI won\u0026rsquo;t go in more detail about UVM and verilog as this post is about how I can\nsave a macro that I use very frequently into an elisp function.\u003c/em\u003e\u003c/p\u003e\n\u003chr\u003e\n\u003cul\u003e\n\u003cli\u003eRegex Search Expression\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e\\$display(\\(.*?\\));\\(.*\\)\n\u003c/code\u003e\u003c/pre\u003e\u003cul\u003e\n\u003cli\u003eReplace Expression\u003c/li\u003e\n\u003c/ul\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e`uvm_info(\u0026#34;REPLACE_THIS_GENERIC_ID\u0026#34;, $sformatf(\\1), UVM_MEDIUM) \\2\n\u003c/code\u003e\u003c/pre\u003e\u003chr\u003e\n\u003cp\u003eAs it can be seen that it very time consuming if I need to type these search and\nreplace expressions every time (even if I use the \u003ccode\u003eM-n\u003c/code\u003e and \u003ccode\u003eM-p\u003c/code\u003e key bindings\nduring the \u003ccode\u003equery-replace-regexp\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003eSo the solution is to save the search-replace operation into a macro and then\nsave that macro as an elisp function.\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eSelect the region you want to do the search-replace.\u003c/li\u003e\n\u003cli\u003eStart recording macro \u003ccode\u003estart-kbd-macro\u003c/code\u003e. \u003cem\u003eI have bound this to \u003ccode\u003eC-F4\u003c/code\u003e.\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eDo the above search-replace and use \u003ccode\u003e!\u003c/code\u003e to force search-replace in the whole region.\u003c/li\u003e\n\u003cli\u003eStop recording macro \u003ccode\u003ekmacro-end-or-call-macro\u003c/code\u003e. \u003cem\u003eI have bound this to \u003ccode\u003eF4\u003c/code\u003e.\u003c/em\u003e\u003c/li\u003e\n\u003cli\u003eDo \u003ccode\u003eM-x kmacro-name-last-macro\u003c/code\u003e and give the macro a descriptive name. You will then be able to call that macro again by doing \u003ccode\u003eM-x\u003c/code\u003e and the macro name you picked. For this example, I named the macro \u003ccode\u003euvm-convert-display-to-uvm_info\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eNow save this macro as a function to a file that you load during your emacs initialization\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e. To do that do \u003ccode\u003eM-x insert-kbd-macro\u003c/code\u003e and select your named macro to be inserted there.\u003c/li\u003e\n\u003cli\u003eNow save that file and your named macro will be loaded in all of your future emacs sessions.\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThe inserted \u003ccode\u003euvm-convert-display-to-uvm_info\u003c/code\u003e function definition looks like this:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efset\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;uvm-convert-display-to-uvm_info\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e   \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003elambda\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kp\"\u003e\u0026amp;optional\u003c/span\u003e \u003cspan class=\"nv\"\u003earg\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;Keyboard macro.\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;p\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ekmacro-exec-ring-item\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003equote\u003c/span\u003e \u003cspan class=\"p\"\u003e([\u003c/span\u003e\u003cspan class=\"mi\"\u003e3\u003c/span\u003e \u003cspan class=\"mi\"\u003e113\u003c/span\u003e \u003cspan class=\"mi\"\u003e92\u003c/span\u003e \u003cspan class=\"mi\"\u003e36\u003c/span\u003e \u003cspan class=\"mi\"\u003e100\u003c/span\u003e \u003cspan class=\"mi\"\u003e105\u003c/span\u003e \u003cspan class=\"mi\"\u003e115\u003c/span\u003e \u003cspan class=\"mi\"\u003e112\u003c/span\u003e \u003cspan class=\"mi\"\u003e108\u003c/span\u003e \u003cspan class=\"mi\"\u003e97\u003c/span\u003e \u003cspan class=\"mi\"\u003e121\u003c/span\u003e \u003cspan class=\"mi\"\u003e40\u003c/span\u003e \u003cspan class=\"mi\"\u003e92\u003c/span\u003e \u003cspan class=\"mi\"\u003e40\u003c/span\u003e \u003cspan class=\"mi\"\u003e46\u003c/span\u003e \u003cspan class=\"mi\"\u003e42\u003c/span\u003e \u003cspan class=\"mi\"\u003e63\u003c/span\u003e \u003cspan class=\"mi\"\u003e92\u003c/span\u003e \u003cspan class=\"mi\"\u003e41\u003c/span\u003e \u003cspan class=\"mi\"\u003e41\u003c/span\u003e \u003cspan class=\"mi\"\u003e59\u003c/span\u003e \u003cspan class=\"mi\"\u003e92\u003c/span\u003e \u003cspan class=\"mi\"\u003e40\u003c/span\u003e \u003cspan class=\"mi\"\u003e46\u003c/span\u003e \u003cspan class=\"mi\"\u003e42\u003c/span\u003e \u003cspan class=\"mi\"\u003e92\u003c/span\u003e \u003cspan class=\"mi\"\u003e41\u003c/span\u003e \u003cspan class=\"nb\"\u003ereturn\u003c/span\u003e \u003cspan class=\"mi\"\u003e96\u003c/span\u003e \u003cspan class=\"mi\"\u003e117\u003c/span\u003e \u003cspan class=\"mi\"\u003e118\u003c/span\u003e \u003cspan class=\"mi\"\u003e109\u003c/span\u003e \u003cspan class=\"mi\"\u003e95\u003c/span\u003e \u003cspan class=\"mi\"\u003e105\u003c/span\u003e \u003cspan class=\"mi\"\u003e110\u003c/span\u003e \u003cspan class=\"mi\"\u003e102\u003c/span\u003e \u003cspan class=\"mi\"\u003e111\u003c/span\u003e \u003cspan class=\"mi\"\u003e40\u003c/span\u003e \u003cspan class=\"mi\"\u003e34\u003c/span\u003e \u003cspan class=\"mi\"\u003e82\u003c/span\u003e \u003cspan class=\"mi\"\u003e69\u003c/span\u003e \u003cspan class=\"mi\"\u003e80\u003c/span\u003e \u003cspan class=\"mi\"\u003e76\u003c/span\u003e \u003cspan class=\"mi\"\u003e65\u003c/span\u003e \u003cspan class=\"mi\"\u003e67\u003c/span\u003e \u003cspan class=\"mi\"\u003e69\u003c/span\u003e \u003cspan class=\"mi\"\u003e95\u003c/span\u003e \u003cspan class=\"mi\"\u003e84\u003c/span\u003e \u003cspan class=\"mi\"\u003e72\u003c/span\u003e \u003cspan class=\"mi\"\u003e73\u003c/span\u003e \u003cspan class=\"mi\"\u003e83\u003c/span\u003e \u003cspan class=\"mi\"\u003e95\u003c/span\u003e \u003cspan class=\"mi\"\u003e71\u003c/span\u003e \u003cspan class=\"mi\"\u003e69\u003c/span\u003e \u003cspan class=\"mi\"\u003e78\u003c/span\u003e \u003cspan class=\"mi\"\u003e69\u003c/span\u003e \u003cspan class=\"mi\"\u003e82\u003c/span\u003e \u003cspan class=\"mi\"\u003e73\u003c/span\u003e \u003cspan class=\"mi\"\u003e67\u003c/span\u003e \u003cspan class=\"mi\"\u003e95\u003c/span\u003e \u003cspan class=\"mi\"\u003e73\u003c/span\u003e \u003cspan class=\"mi\"\u003e68\u003c/span\u003e \u003cspan class=\"mi\"\u003e34\u003c/span\u003e \u003cspan class=\"mi\"\u003e44\u003c/span\u003e \u003cspan class=\"mi\"\u003e32\u003c/span\u003e \u003cspan class=\"mi\"\u003e36\u003c/span\u003e \u003cspan class=\"mi\"\u003e115\u003c/span\u003e \u003cspan class=\"mi\"\u003e102\u003c/span\u003e \u003cspan class=\"mi\"\u003e111\u003c/span\u003e \u003cspan class=\"mi\"\u003e114\u003c/span\u003e \u003cspan class=\"mi\"\u003e109\u003c/span\u003e \u003cspan class=\"mi\"\u003e97\u003c/span\u003e \u003cspan class=\"mi\"\u003e116\u003c/span\u003e \u003cspan class=\"mi\"\u003e102\u003c/span\u003e \u003cspan class=\"mi\"\u003e40\u003c/span\u003e \u003cspan class=\"mi\"\u003e92\u003c/span\u003e \u003cspan class=\"mi\"\u003e49\u003c/span\u003e \u003cspan class=\"mi\"\u003e41\u003c/span\u003e \u003cspan class=\"mi\"\u003e44\u003c/span\u003e \u003cspan class=\"mi\"\u003e32\u003c/span\u003e \u003cspan class=\"mi\"\u003e85\u003c/span\u003e \u003cspan class=\"mi\"\u003e86\u003c/span\u003e \u003cspan class=\"mi\"\u003e77\u003c/span\u003e \u003cspan class=\"mi\"\u003e95\u003c/span\u003e \u003cspan class=\"mi\"\u003e77\u003c/span\u003e \u003cspan class=\"mi\"\u003e69\u003c/span\u003e \u003cspan class=\"mi\"\u003e68\u003c/span\u003e \u003cspan class=\"mi\"\u003e73\u003c/span\u003e \u003cspan class=\"mi\"\u003e85\u003c/span\u003e \u003cspan class=\"mi\"\u003e77\u003c/span\u003e \u003cspan class=\"mi\"\u003e41\u003c/span\u003e \u003cspan class=\"mi\"\u003e32\u003c/span\u003e \u003cspan class=\"mi\"\u003e92\u003c/span\u003e \u003cspan class=\"mi\"\u003e50\u003c/span\u003e \u003cspan class=\"nb\"\u003ereturn\u003c/span\u003e \u003cspan class=\"mi\"\u003e33\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"mi\"\u003e0\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;%d\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"nv\"\u003earg\u003c/span\u003e\u003cspan class=\"p\"\u003e)))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eNow I can simply \u003ccode\u003eM-x uvm-convert-display-to-uvm_info\u003c/code\u003e the next time I need to replace those \u003ccode\u003e$display\u003c/code\u003es with \u003ccode\u003e `uvm_info\u003c/code\u003es.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eI save my verilog related macros to my \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-verilog.el\"\u003e\u003cem\u003esetup-verilog-mode.el\u003c/em\u003e\u003c/a\u003e.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e","text":"I am in the process of converting traditional verilog test benches to SystemVerilog UVM test benches. As per the UVM methodology, it is recommended to use `uvm_info instead of $display statements so that the info statement encodes a Message ID and Message Verbosity along with the message required to be printed.\nI won\u0026rsquo;t go in more detail about UVM and verilog as this post is about how I can save a macro that I use very frequently into an elisp function.\nRegex Search Expression \\$display(\\(.*?\\));\\(.*\\) Replace Expression `uvm_info(\u0026#34;REPLACE_THIS_GENERIC_ID\u0026#34;, $sformatf(\\1), UVM_MEDIUM) \\2 As it can be seen that it very time consuming if I need to type these search and replace expressions every time (even if I use the M-n and M-p key bindings during the query-replace-regexp).\nSo the solution is to save the search-replace operation into a macro and then save that macro as an elisp function.\nSelect the region you want to do the search-replace. Start recording macro start-kbd-macro. I have bound this to C-F4. Do the above search-replace and use ! to force search-replace in the whole region. Stop recording macro kmacro-end-or-call-macro. I have bound this to F4. Do M-x kmacro-name-last-macro and give the macro a descriptive name. You will then be able to call that macro again by doing M-x and the macro name you picked. For this example, I named the macro uvm-convert-display-to-uvm_info. Now save this macro as a function to a file that you load during your emacs initialization1. To do that do M-x insert-kbd-macro and select your named macro to be inserted there. Now save that file and your named macro will be loaded in all of your future emacs sessions. The inserted uvm-convert-display-to-uvm_info function definition looks like this:\n(fset \u0026#39;uvm-convert-display-to-uvm_info (lambda (\u0026amp;optional arg) \u0026#34;Keyboard macro.\u0026#34; (interactive \u0026#34;p\u0026#34;) (kmacro-exec-ring-item (quote ([3 113 92 36 100 105 115 112 108 97 121 40 92 40 46 42 63 92 41 41 59 92 40 46 42 92 41 return 96 117 118 109 95 105 110 102 111 40 34 82 69 80 76 65 67 69 95 84 72 73 83 95 71 69 78 69 82 73 67 95 73 68 34 44 32 36 115 102 111 114 109 97 116 102 40 92 49 41 44 32 85 86 77 95 77 69 68 73 85 77 41 32 92 50 return 33] 0 \u0026#34;%d\u0026#34;)) arg))) Now I can simply M-x uvm-convert-display-to-uvm_info the next time I need to replace those $displays with `uvm_infos.\nI save my verilog related macros to my setup-verilog-mode.el.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"Save a macro as a function in emacs","published":"2014-07-27T15:50:47-04:00","summary":"I am in the process of converting traditional verilog test benches to SystemVerilog UVM test benches. As per the UVM methodology, it is recommended to use `uvm_info instead of $display statements so that the info statement encodes a Message ID and Message Verbosity along with the message required to be printed.\nI won\u0026rsquo;t go in more detail about UVM and verilog as this post is about how I can save a macro that I use very frequently into an elisp function.\n","type":"entry","url":"https://scripter.co/save-a-macro-as-a-function-in-emacs/"},{"content":{"html":"\u003cp\u003eLately I was having an issue in the org to html conversion where the newline\ncharacters got appended with funky unicode characters.\u003c/p\u003e\n\u003cp\u003eFull detail is in \u003ca href=\"https://www.reddit.com/r/emacs/comments/2b5x5g/funny_characters_appended_at_new_line_to_source/\"\u003ethis\u003c/a\u003e reddit post I started.\u003c/p\u003e\n\u003cp\u003eThe fix was to add the following code after the line \u003ccode\u003e(funcall lang-mode)\u003c/code\u003e in\nthe \u003ccode\u003eorg-html-fontify-code\u003c/code\u003e defun in \u003ccode\u003eox-html.el\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;fill-column-indicator\u003c/span\u003e \u003cspan class=\"no\"\u003enil\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;noerror\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003efci-mode\u003c/span\u003e \u003cspan class=\"mi\"\u003e-1\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e\u003cem\u003eMake sure you delete ox-html.elc else your patched ox-html.el won\u0026rsquo;t be effective.\u003c/em\u003e\u003c/p\u003e","text":"Lately I was having an issue in the org to html conversion where the newline characters got appended with funky unicode characters.\nFull detail is in this reddit post I started.\nThe fix was to add the following code after the line (funcall lang-mode) in the org-html-fontify-code defun in ox-html.el.\n(when (require \u0026#39;fill-column-indicator nil \u0026#39;noerror) (fci-mode -1)) Make sure you delete ox-html.elc else your patched ox-html.el won\u0026rsquo;t be effective.\n"},"name":"Org-to-HTML and fill-column-indicator","published":"2014-07-21T13:06:09-04:00","summary":"Lately I was having an issue in the org to html conversion where the newline characters got appended with funky unicode characters.\nFull detail is in this reddit post I started.\n","type":"entry","url":"https://scripter.co/org-to-html-and-fill-column-indicator/"},{"content":{"html":"\u003cp\u003eAt times you might need your org exported pdf to have the exact font rendering\nas generated by a snippet of LaTeX code. To do that, wrap that code inbetween\nthe \u003ccode\u003e\\(\u003c/code\u003e and \u003ccode\u003e\\)\u003c/code\u003e delimiters.\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003e* Section in org mode\nText in org mode. And here is the LaTeX snippet \\(\\sim 2000k \\approx 2^{21}\\).\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e\u003ca href=\"https://orgmode.org/manual/LaTeX-fragments.html\"\u003eSource\u003c/a\u003e\u003c/p\u003e","text":"At times you might need your org exported pdf to have the exact font rendering as generated by a snippet of LaTeX code. To do that, wrap that code inbetween the \\( and \\) delimiters.\n* Section in org mode Text in org mode. And here is the LaTeX snippet \\(\\sim 2000k \\approx 2^{21}\\). Source\n"},"name":"Inline LaTeX code fragments in Org","published":"2014-05-28T17:31:24-04:00","summary":"At times you might need your org exported pdf to have the exact font rendering as generated by a snippet of LaTeX code. To do that, wrap that code inbetween the \\( and \\) delimiters.\n","type":"entry","url":"https://scripter.co/inline-latex-code-fragments-in-org/"},{"content":{"html":"\u003cp\u003eSet the buffer major mode to \u003ccode\u003eorg-mode\u003c/code\u003e. If the file extension is\n\u003ccode\u003e.org\u003c/code\u003e, that major mode would be set automatically by emacs.\u003c/p\u003e\n\u003cp\u003eFollow the below steps to create a table ..\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eStart writing the headers of the table starting with a vertical pipe\n\u003ccode\u003e|\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e| Header1 | Header2 | Header3 |▮\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eOnce you have finished writing the headers, do \u003ccode\u003eC-u C-c -\u003c/code\u003e to insert\na horizontal line above the header row.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|---------+---------+---------|\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e| Header1 | Header2 | Header3 |▮\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThen do \u003ccode\u003eC-c -\u003c/code\u003e to insert a horizontal line below the header row.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|---------+---------+---------|\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e| Header1 | Header2 | Header3 |▮\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|---------+---------+---------|\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eGo down one row ( \u003ccode\u003eC-n\u003c/code\u003e ) and hit TAB and org-mode will figure out\nthat you need to create a new row and will put the cursor in the\nfirst cell of the new row.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|---------+---------+---------|\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e| Header1 | Header2 | Header3 |\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|---------+---------+---------|\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|▮        |         |         |\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eYou can now use TAB and Shift + TAB to navigate the cells and new\nrows will be created when you hit TAB when you are in the last cell\nof the last created row.\u003c/p\u003e\n\u003cp\u003eWhen you want to close the table with a bottom border, hit \u003ccode\u003eC-c -\u003c/code\u003e\nwhen the cursor is in the last row.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|---------+---------+---------|\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e| Header1 | Header2 | Header3 |\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|---------+---------+---------|\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e| A       | B       | C▮      |\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e|---------+---------+---------|\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003c/ol\u003e","text":"Set the buffer major mode to org-mode. If the file extension is .org, that major mode would be set automatically by emacs.\nFollow the below steps to create a table ..\nStart writing the headers of the table starting with a vertical pipe |.\n| Header1 | Header2 | Header3 |▮ Once you have finished writing the headers, do C-u C-c - to insert a horizontal line above the header row.\n|---------+---------+---------| | Header1 | Header2 | Header3 |▮ Then do C-c - to insert a horizontal line below the header row.\n|---------+---------+---------| | Header1 | Header2 | Header3 |▮ |---------+---------+---------| Go down one row ( C-n ) and hit TAB and org-mode will figure out that you need to create a new row and will put the cursor in the first cell of the new row.\n|---------+---------+---------| | Header1 | Header2 | Header3 | |---------+---------+---------| |▮ | | | You can now use TAB and Shift + TAB to navigate the cells and new rows will be created when you hit TAB when you are in the last cell of the last created row.\nWhen you want to close the table with a bottom border, hit C-c - when the cursor is in the last row.\n|---------+---------+---------| | Header1 | Header2 | Header3 | |---------+---------+---------| | A | B | C▮ | |---------+---------+---------| "},"name":"How to quickly create a table in Org mode","published":"2014-05-28T12:44:06-04:00","summary":"Set the buffer major mode to org-mode. If the file extension is .org, that major mode would be set automatically by emacs.\nFollow the below steps to create a table ..\n","type":"entry","url":"https://scripter.co/how-to-quickly-create-a-table-in-org-mode/"},{"content":{"html":"\u003cp\u003eThis posts explain how the emacs in-built \u003ccode\u003equery-replace-regexp\u003c/code\u003e\ncommand can be used to convert upper-cased strings to lower case.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eDo \u003ccode\u003eM-x query-replace-regexp\u003c/code\u003e or use the default binding \u003ccode\u003eC-M-%\u003c/code\u003e to\nactivate the regular expression search/replace.\u003c/li\u003e\n\u003cli\u003eEnter the regexp for the strings to be replaced in the *Query regexp:\u0026quot;\nfield. For instance, if I want to convert \u003ccode\u003eI_data\u003c/code\u003e and \u003ccode\u003eQ_data\u003c/code\u003e to\n\u003ccode\u003ei_data\u003c/code\u003e and \u003ccode\u003eq_data\u003c/code\u003e respectively, then my search regular expression\nwill be \u003ccode\u003e\\([IQ]\\)_data\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eIt is important to use the \u003cstrong\u003eescaped\u003c/strong\u003e grouping brackets \u003ccode\u003e\\(\u003c/code\u003e and \u003ccode\u003e\\)\u003c/code\u003e\nto wrap an expression that you want to upcase or downcase.\u003c/li\u003e\n\u003cli\u003eIn the next \u003cem\u003eQuery replace:\u003c/em\u003e prompt, the expression will be\n\u003ccode\u003e\\,(downcase \\1)_data\u003c/code\u003e\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eUse \u003ccode\u003e\\,(upcase \\REGEXGROUPNUMBER)\u003c/code\u003e to convert to upper case instead.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e","text":"This posts explain how the emacs in-built query-replace-regexp command can be used to convert upper-cased strings to lower case.\nDo M-x query-replace-regexp or use the default binding C-M-% to activate the regular expression search/replace. Enter the regexp for the strings to be replaced in the *Query regexp:\u0026quot; field. For instance, if I want to convert I_data and Q_data to i_data and q_data respectively, then my search regular expression will be \\([IQ]\\)_data. It is important to use the escaped grouping brackets \\( and \\) to wrap an expression that you want to upcase or downcase. In the next Query replace: prompt, the expression will be \\,(downcase \\1)_data1. Use \\,(upcase \\REGEXGROUPNUMBER) to convert to upper case instead.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n"},"name":"How to change upper case to lower via search/replace?","published":"2014-03-14T09:46:58-04:00","summary":"This posts explain how the emacs in-built query-replace-regexp command can be used to convert upper-cased strings to lower case.\n","type":"entry","url":"https://scripter.co/how-to-change-upper-case-to-lower-via-search-replace/"},{"content":{"html":"\u003cp\u003eI have a couple of theme packages installed on my emacs but I would\nlike to assign a default theme.\u003c/p\u003e\n\u003cp\u003eI set the \u003ca href=\"https://github.com/bbatsov/zenburn-emacs\"\u003ezenburn theme\u003c/a\u003e via a function \u003ccode\u003ezenburn\u003c/code\u003e. I set the\n\u003ca href=\"https://github.com/fniessen/emacs-leuven-theme\"\u003eleuven theme\u003c/a\u003e via another function \u003ccode\u003eleuven\u003c/code\u003e. But in my emacs\nstartup I didn\u0026rsquo;t want to hard-code either of these function and thus\narose the need to set a variable to one of these functions.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eYou assign the function to a variable using \u003ccode\u003edefvar\u003c/code\u003e and you call\nthat function linked to that variable using \u003ccode\u003efuncall\u003c/code\u003e.\u003c/em\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefvar\u003c/span\u003e \u003cspan class=\"nv\"\u003edefault-theme\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;zenburn\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; zenburn\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003ezenburn\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Activate zenburn theme.\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"c1\"\u003e;; disable other themes before setting this theme\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003edisable-theme\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;leuven\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eload-theme\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;zenburn\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003efuncall\u003c/span\u003e \u003cspan class=\"nv\"\u003edefault-theme\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e;; Set the default theme\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eYou can check out my full emacs config for visual settings on\nmy \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-visual.el\"\u003egit\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://stackoverflow.com/questions/9942675/in-elisp-how-do-i-put-a-function-in-a-variable\"\u003eReference\u003c/a\u003e\u003c/p\u003e","text":"I have a couple of theme packages installed on my emacs but I would like to assign a default theme.\nI set the zenburn theme via a function zenburn. I set the leuven theme via another function leuven. But in my emacs startup I didn\u0026rsquo;t want to hard-code either of these function and thus arose the need to set a variable to one of these functions.\nYou assign the function to a variable using defvar and you call that function linked to that variable using funcall.\n(defvar default-theme \u0026#39;zenburn) ;; zenburn (defun zenburn () \u0026#34;Activate zenburn theme.\u0026#34; (interactive) ;; disable other themes before setting this theme (disable-theme \u0026#39;leuven) (load-theme \u0026#39;zenburn t)) (funcall default-theme) ;; Set the default theme You can check out my full emacs config for visual settings on my git.\nReference\n"},"name":"How to save a function name in a variable in elisp?","published":"2014-03-12T15:53:31-04:00","summary":"I have a couple of theme packages installed on my emacs but I would like to assign a default theme.\nI set the zenburn theme via a function zenburn. I set the leuven theme via another function leuven. But in my emacs startup I didn\u0026rsquo;t want to hard-code either of these function and thus arose the need to set a variable to one of these functions.\n","type":"entry","url":"https://scripter.co/how-to-save-a-function-name-in-a-variable-in-elisp/"},{"content":{"html":"\u003cp\u003e\u003cstrong\u003eUpdate (2017/02/23)\u003c/strong\u003e \u0026mdash; Now I use \u003ca href=\"https://www.gnu.org/software/global/\"\u003e\u003cem\u003eGNU Global\u003c/em\u003e\u003c/a\u003e with \u003ca href=\"https://github.com/universal-ctags\"\u003e\u003cem\u003eUniversal\nCtags\u003c/em\u003e\u003c/a\u003e as back-end to generate the tag files. In emacs, I use the\n\u003ca href=\"https://github.com/leoliu/ggtags\"\u003e\u003ccode\u003eggtags\u003c/code\u003e\u003c/a\u003e package \u0026ndash; \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-tags.el\"\u003e[config]\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eThis post still has value if you are interesting in configuring\n\u003ccode\u003ectags\u003c/code\u003e only.\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003eThis posts shows how to set up \u003ccode\u003ectags\u003c/code\u003e to parse SystemVerilog code and\nhow to access that tag database in emacs.\u003c/p\u003e\n\u003ch1 id=\"exuberant-ctags\"\u003eExuberant ctags\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#exuberant-ctags\"\u003e#\u003c/a\u003e\u003c/h1\u003e\n\n\n\u003cp\u003e\u003ccode\u003ectags\u003c/code\u003e is an awesome application which crawls through all your code\nand indexes everything you want, as you want as all of that can be\ncontrolled using regular expressions. Here\u0026rsquo;s a scenario where ctags\ncomes helpful. Say you are in pqr.v file in which a function xyz is\ncalled. Now that function may neither be defined in the same file nor\nin some other file in the same directory. The function xyz could be\ndefined in some other folder in a file called abc.v. But with the help\nof ctags, you can jump directly to the function xyz definition from\nthe place where it is called!\u003c/p\u003e\n\u003cp\u003eI code in Verilog and ctags helps be jump to the point where a\nvariable/module/task/function/interface/define(or macro)/class/..\netc. is defined.\u003c/p\u003e\n\n\u003ch2 id=\"ctags-customizations\"\u003ectags customizations\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#ctags-customizations\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eCustom configuration for ctags is usually stored in \u003ccode\u003e~/.ctags\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-text\" data-lang=\"text\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--exclude=.SOS\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--exclude=.git\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--extra=+q\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# Hide the warning: ctags: Warning: xcmd recognizes\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# /home/kmodi/usr_local2/libexec/ctags/drivers/coffeetags is not available\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e# https://github.com/fishman/ctags/issues/131#issuecomment-69467247\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--quiet\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--langmap=SystemVerilog:.sv.v.svh.vg.tv.vinc\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--languages=SystemVerilog,C,C++,HTML,Lisp,Make,Matlab,Perl,Python,Sh,Tex\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e--regex-SystemVerilog=/^\\s*`define\\b\\s*(\\w+)/`\\1/d,define/\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eHere are some notes about my customizations in \u003ccode\u003e.ctags\u003c/code\u003e file:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003ectags doesn\u0026rsquo;t have a language defined systemverilog. But I can\ndefine my own language called so: \u003ccode\u003e--langdef=systemverilog\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eI can define which files should be parsed for systemverilog code:\n\u003ccode\u003e--langmap=systemverilog:.v.vg.sv.svh.tv.vinc\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eSyntax to define your custom regex:\n\u003ccode\u003e--regex-LANGUAGE=/REGEX/REGEX_GROUP/CTAGS_KIND_ABBREV, CTAGS_KIND_NAME/\u003c/code\u003e\n\u003cul\u003e\n\u003cli\u003eREGEX is the regular expression to define to find the line\ncontaining the task, function, module, etc. You would normally\nuse atleast 1 regex grouping to filter out the portion of the\nline that would contain the function / task / etc name. Example:\n\u003ccode\u003e^\\s*\\bfunction\\b.*(\\b\\w+\\b)\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003eREGEX_GROUP section specifes what string you want to do the data\nentry under. This is usually the task / function / etc name. For\nexample, for function xyz, the data entry would happen under the\nstring \u003ccode\u003exyz\u003c/code\u003e. The REGEX_GROUP defined for the Verilog \u003ccode\u003edefines\u003c/code\u003e\nor \u003ccode\u003emacros\u003c/code\u003e is a special case because I wanted to also prefix\nthe define/macro string with backtick \u003ccode\u003e`\u003c/code\u003e. The reason is\nthat in emacs when I have the cursor on a define like \u003ccode\u003e `XYZ\u003c/code\u003e,\netags-select-find-tag-at-point function uses that whole string\nincluding the backtick for searching in the TAGS file.\u003c/li\u003e\n\u003cli\u003eExamples of ctags kinds and their abbreviations: \u003ccode\u003et,task\u003c/code\u003e\n\u003ccode\u003ef,function\u003c/code\u003e \u003ccode\u003em,module\u003c/code\u003e. Specifying the kind is important\nbecause you can later specify which kinds of matches\nyou want to log in the TAGS file. This is done using\n\u003ccode\u003e--systemverilog-kinds=+ctfmpied\u003c/code\u003e.\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003eYou can specify which language files ctags should parse for tag generation:\n\u003ccode\u003e--languages=systemverilog,C,C++,HTML,Lisp,Make,Matlab,Perl,Python,Sh,Tex\u003c/code\u003e.\n\u003cem\u003eNOTE: I learnt that specifying the language files you want to parse\nis better because if a particular extension is defined for more than\n1 language, then they result in duplicate tag entries in the TAGS\nfile. I am not sure if that duplication is done by ctags or emacs, but\nonce I specified the languages I wanted to parse, I stopped getting\nduplicate entries when using the etags-select package in emacs. In my\ncase, the .v extension was associated with Verilog language predefined\nin ctags, and it was also defined for systemverilog language in my\n\u003ccode\u003e.ctags\u003c/code\u003e.\u003c/em\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003ch2 id=\"ctags-execution\"\u003ectags execution\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#ctags-execution\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eOnce you have your .ctags file ready, generate the TAGS file using\nthe command, \u003ccode\u003ectags -Re -f /project/root/dir/TAGS /project/root/dir\u003c/code\u003e.\nExample: \u003ccode\u003ectags -Re -f ~/.emacs.d/TAGS ~/.emacs.d\u003c/code\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eThe -R option makes ctags crawl through all directories recursively\nfrom the specified root directory.\u003c/li\u003e\n\u003cli\u003eThe -e option makes ctags generate the TAGS file in a format\ncompatible with emacs.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eI use \u003ca href=\"http://ctags.sourceforge.net/\"\u003eExuberant ctags 5.8\u003c/a\u003e with emacs 24.3. My \u003ccode\u003e.ctags\u003c/code\u003e is heavily\ninspired from a \u003cem\u003everificationguild.com\u003c/em\u003e forum.\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eEnsure that you are using Exuberant ctags and not the ctags\nthat\u0026rsquo;s installed along with emacs by checking the output of\n\u003ccode\u003ectags --version\u003c/code\u003e. Usually you would need to install ctags AFTER\ninstalling emacs so that the ctags binary in \u003ccode\u003e/usr/local/bin\u003c/code\u003e or\n\u003ccode\u003e$HOME/local/bin\u003c/code\u003e is the Exuberant version and not emacs.\u003c/em\u003e\u003c/p\u003e\n\n\u003ch1 id=\"emacs--ctags\"\u003eemacs + ctags\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#emacs--ctags\"\u003e#\u003c/a\u003e\u003c/h1\u003e\n\n\n\u003cp\u003eHere is my emacs configuration for ctags: \u003ca href=\"https://github.com/kaushalmodi/.emacs.d/blob/master/setup-files/setup-tags.el\"\u003e[github]\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eMy emacs ctags config starts by setting few variables to avoid any\nannoyances:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ccode\u003e(setq tags-revert-without-query t)\u003c/code\u003e This prevents emacs from asking\nyou every time if you want to reread that updated TAGS file. Of\ncourse you would want to!\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e(setq large-file-warning-threshold 30000000)\u003c/code\u003e In most of the cases,\nTAGS files will be large (\u0026gt; 10MB). I didn\u0026rsquo;t want emacs warning me\nabout that every time it accessed the TAGS files. So I increased the\nthreshold to 30MB. So set the threshold as per your needs. You can\nalso disable that warning completely by setting the value to \u003ccode\u003enil\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003e(setq tags-case-fold-search nil)\u003c/code\u003e I like the searches to be\ncase-insensitive. It is useful when I manually search for a tag. But\nusually the way I use tags is: I put my cursor on the name of\nfunction/task/.. etc I want to jump to and hit my key-binding for\ntag search.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eI rely on few packages to makes the emacs and TAGS files'\ninteraction seemless: \u003ca href=\"https://www.emacswiki.org/emacs/etags-table.el\"\u003eetags-table\u003c/a\u003e, \u003ca href=\"https://github.com/jixiuf/ctags-update\"\u003ectags-update\u003c/a\u003e,\n\u003ca href=\"https://www.emacswiki.org/emacs/etags-select.el\"\u003eetags-select\u003c/a\u003e. All are available through MELPA.\u003c/p\u003e\n\n\u003ch2 id=\"etags-table\"\u003eetags-table\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#etags-table\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eetags-table will help you load the correct TAGS file based on your\nfile path. \u003cstrong\u003eBut you have to load all the project path possibilities\ninto \u003ccode\u003eetags-table-alist\u003c/code\u003e first!\u003c/strong\u003e Let\u0026rsquo;s say one of the project roots\nentered in that list is $PRJ. If your TAGS path is $PRJ/TAGS and you\nsearch a tag in $PRJ/any/nested/path/file.c, etags-table will figure\nout that you want to search in $PRJ/TAGS.\u003c/p\u003e\n\u003cp\u003eIn my ctags setup file I check for a \u003ccode\u003eproject-root\u003c/code\u003e var and load that\ninto \u0026rsquo;etags-table-list\u0026rsquo; if available. I update the project-root var\nusing a shell env var. \u003cem\u003eI haven\u0026rsquo;t committed that project-root var\nassignment to github\u003c/em\u003e. But you can update that using projectile or any\nother mechanism.\u003c/p\u003e\n\u003cp\u003eThe beauty is that etags-table won\u0026rsquo;t load the TAGS files from ALL\nthe paths in \u0026rsquo;etags-table-alist\u0026rsquo;. It will load only the relevant\none(s). Note that each entry in \u0026rsquo;etags-table-alist\u0026rsquo; is another\nlist. Each of those lists is of the nature \u003ccode\u003e'( PROJECT_PATH, TAGS_FILE_1, [OPTIONAL_TAGS_FILE_2, ..] )\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;etags-table\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eetags-table-alist\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003elist\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e       \u003cspan class=\"o\"\u003e`\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"nv\"\u003euser-emacs-directory\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;/.*\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e,\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"nv\"\u003euser-emacs-directory\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;/TAGS\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e       \u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003eetags-table-search-up-depth\u003c/span\u003e \u003cspan class=\"mi\"\u003e15\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e;; Max depth to search up for a tags file.  nil means don\u0026#39;t search.\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Below function comes useful when you change the project-root symbol to a\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; different value (when switching projects)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003edefun\u003c/span\u003e \u003cspan class=\"nv\"\u003eupdate-etags-table-then-find-tag\u003c/span\u003e \u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"s\"\u003e\u0026#34;Update etags-table based on the current value of project-root and then do\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"s\"\u003etag find\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003einteractive\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003ewhen\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eboundp\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;project-root\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"c1\"\u003e;; add-to-list if project-root symbol is defined\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-to-list\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;etags-table-alist\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                 \u003cspan class=\"o\"\u003e`\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"nv\"\u003eproject-root\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;/.*\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e,\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003econcat\u003c/span\u003e \u003cspan class=\"nv\"\u003eproject-root\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;/TAGS\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eetags-select-find-tag-at-point\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"ctags-update\"\u003ectags-update\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#ctags-update\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003ectags-update will update the \u003cem\u003efirst\u003c/em\u003e TAGS file that is found while\nsearching up the parent directories from the path of the file that\ngets modified. You can configure how frequent you want the update\nfrequency to be.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;ctags-update\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003esetq\u003c/span\u003e \u003cspan class=\"nv\"\u003ectags-update-delay-seconds\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003e*\u003c/span\u003e \u003cspan class=\"mi\"\u003e30\u003c/span\u003e \u003cspan class=\"mi\"\u003e60\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e \u003cspan class=\"c1\"\u003e;; every 1/2 hour\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003eautoload\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;turn-on-ctags-auto-update-mode\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;ctags-update\u0026#34;\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;turn on \u003c/span\u003e\u003cspan class=\"ss\"\u003e`ctags-auto-update-mode\u0026#39;\u003c/span\u003e\u003cspan class=\"s\"\u003e.\u0026#34;\u003c/span\u003e \u003cspan class=\"no\"\u003et\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-hook\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;verilog-mode-hook\u003c/span\u003e    \u003cspan class=\"ss\"\u003e\u0026#39;turn-on-ctags-auto-update-mode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eadd-hook\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;emacs-lisp-mode-hook\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;turn-on-ctags-auto-update-mode\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"etags-select\"\u003eetags-select\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#etags-select\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eYou can use \u003ccode\u003eetags-select\u003c/code\u003e to pick one of\nmultiple tag matches. It is useful when a same function/task/.. has\nmultiple definitions and you need to pick the definition to jump\nto. If multiple matches don\u0026rsquo;t exist, finding a tag at point will make\nyou jump directly to the definition file.\u003c/p\u003e\n\u003cp\u003eI prefer etags-select as helm-etags+ doesn\u0026rsquo;t play well with tags\nthat have a \u003ccode\u003e`\u003c/code\u003e prefix (which is very crucial for jumping to\ndefine/macro definitions in Verilog).\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003erequire\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;etags-select\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edefine-key\u003c/span\u003e \u003cspan class=\"nv\"\u003eetags-select-mode-map\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ekbd\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;C-g\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e   \u003cspan class=\"ss\"\u003e\u0026#39;etags-select-quit\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e;; Also quit etags-select when cursor moves to another window\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edefine-key\u003c/span\u003e \u003cspan class=\"nv\"\u003eetags-select-mode-map\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ekbd\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;C-x o\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;etags-select-quit\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edefine-key\u003c/span\u003e \u003cspan class=\"nv\"\u003eetags-select-mode-map\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ekbd\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;C-x O\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;etags-select-quit\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edefine-key\u003c/span\u003e \u003cspan class=\"nv\"\u003eetags-select-mode-map\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ekbd\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;C-p\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e   \u003cspan class=\"ss\"\u003e\u0026#39;etags-select-previous-tag\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nf\"\u003edefine-key\u003c/span\u003e \u003cspan class=\"nv\"\u003eetags-select-mode-map\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ekbd\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;C-n\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e   \u003cspan class=\"ss\"\u003e\u0026#39;etags-select-next-tag\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003ch2 id=\"key-bindings\"\u003eKey Bindings\u0026nbsp;\u003ca class=\"headline-hash no-text-decoration\" href=\"#key-bindings\"\u003e#\u003c/a\u003e\u003c/h2\u003e\n\n\n\u003cp\u003eFinally here is the key-binding I have set to my quick hyper-space\njumps to definitions of any kind.\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-elisp\" data-lang=\"elisp\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eglobal-set-key\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003ekbd\u003c/span\u003e \u003cspan class=\"s\"\u003e\u0026#34;M-.\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"ss\"\u003e\u0026#39;update-etags-table-then-find-tag\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","text":"Update (2017/02/23) \u0026mdash; Now I use GNU Global with Universal Ctags as back-end to generate the tag files. In emacs, I use the ggtags package \u0026ndash; [config].\nThis post still has value if you are interesting in configuring ctags only.\nThis posts shows how to set up ctags to parse SystemVerilog code and how to access that tag database in emacs.\nExuberant ctags\u0026nbsp;# ctags is an awesome application which crawls through all your code and indexes everything you want, as you want as all of that can be controlled using regular expressions. Here\u0026rsquo;s a scenario where ctags comes helpful. Say you are in pqr.v file in which a function xyz is called. Now that function may neither be defined in the same file nor in some other file in the same directory. The function xyz could be defined in some other folder in a file called abc.v. But with the help of ctags, you can jump directly to the function xyz definition from the place where it is called!\nI code in Verilog and ctags helps be jump to the point where a variable/module/task/function/interface/define(or macro)/class/.. etc. is defined.\nctags customizations\u0026nbsp;# Custom configuration for ctags is usually stored in ~/.ctags.\n--exclude=.SOS --exclude=.git --extra=+q # Hide the warning: ctags: Warning: xcmd recognizes # /home/kmodi/usr_local2/libexec/ctags/drivers/coffeetags is not available # https://github.com/fishman/ctags/issues/131#issuecomment-69467247 --quiet --langmap=SystemVerilog:.sv.v.svh.vg.tv.vinc --languages=SystemVerilog,C,C++,HTML,Lisp,Make,Matlab,Perl,Python,Sh,Tex --regex-SystemVerilog=/^\\s*`define\\b\\s*(\\w+)/`\\1/d,define/ Here are some notes about my customizations in .ctags file:\nctags doesn\u0026rsquo;t have a language defined systemverilog. But I can define my own language called so: --langdef=systemverilog I can define which files should be parsed for systemverilog code: --langmap=systemverilog:.v.vg.sv.svh.tv.vinc Syntax to define your custom regex: --regex-LANGUAGE=/REGEX/REGEX_GROUP/CTAGS_KIND_ABBREV, CTAGS_KIND_NAME/ REGEX is the regular expression to define to find the line containing the task, function, module, etc. You would normally use atleast 1 regex grouping to filter out the portion of the line that would contain the function / task / etc name. Example: ^\\s*\\bfunction\\b.*(\\b\\w+\\b) REGEX_GROUP section specifes what string you want to do the data entry under. This is usually the task / function / etc name. For example, for function xyz, the data entry would happen under the string xyz. The REGEX_GROUP defined for the Verilog defines or macros is a special case because I wanted to also prefix the define/macro string with backtick `. The reason is that in emacs when I have the cursor on a define like `XYZ, etags-select-find-tag-at-point function uses that whole string including the backtick for searching in the TAGS file. Examples of ctags kinds and their abbreviations: t,task f,function m,module. Specifying the kind is important because you can later specify which kinds of matches you want to log in the TAGS file. This is done using --systemverilog-kinds=+ctfmpied. You can specify which language files ctags should parse for tag generation: --languages=systemverilog,C,C++,HTML,Lisp,Make,Matlab,Perl,Python,Sh,Tex. NOTE: I learnt that specifying the language files you want to parse is better because if a particular extension is defined for more than 1 language, then they result in duplicate tag entries in the TAGS file. I am not sure if that duplication is done by ctags or emacs, but once I specified the languages I wanted to parse, I stopped getting duplicate entries when using the etags-select package in emacs. In my case, the .v extension was associated with Verilog language predefined in ctags, and it was also defined for systemverilog language in my .ctags. ctags execution\u0026nbsp;# Once you have your .ctags file ready, generate the TAGS file using the command, ctags -Re -f /project/root/dir/TAGS /project/root/dir. Example: ctags -Re -f ~/.emacs.d/TAGS ~/.emacs.d\nThe -R option makes ctags crawl through all directories recursively from the specified root directory. The -e option makes ctags generate the TAGS file in a format compatible with emacs. I use Exuberant ctags 5.8 with emacs 24.3. My .ctags is heavily inspired from a verificationguild.com forum.\nEnsure that you are using Exuberant ctags and not the ctags that\u0026rsquo;s installed along with emacs by checking the output of ctags --version. Usually you would need to install ctags AFTER installing emacs so that the ctags binary in /usr/local/bin or $HOME/local/bin is the Exuberant version and not emacs.\nemacs + ctags\u0026nbsp;# Here is my emacs configuration for ctags: [github].\nMy emacs ctags config starts by setting few variables to avoid any annoyances:\n(setq tags-revert-without-query t) This prevents emacs from asking you every time if you want to reread that updated TAGS file. Of course you would want to! (setq large-file-warning-threshold 30000000) In most of the cases, TAGS files will be large (\u0026gt; 10MB). I didn\u0026rsquo;t want emacs warning me about that every time it accessed the TAGS files. So I increased the threshold to 30MB. So set the threshold as per your needs. You can also disable that warning completely by setting the value to nil. (setq tags-case-fold-search nil) I like the searches to be case-insensitive. It is useful when I manually search for a tag. But usually the way I use tags is: I put my cursor on the name of function/task/.. etc I want to jump to and hit my key-binding for tag search. I rely on few packages to makes the emacs and TAGS files' interaction seemless: etags-table, ctags-update, etags-select. All are available through MELPA.\netags-table\u0026nbsp;# etags-table will help you load the correct TAGS file based on your file path. But you have to load all the project path possibilities into etags-table-alist first! Let\u0026rsquo;s say one of the project roots entered in that list is $PRJ. If your TAGS path is $PRJ/TAGS and you search a tag in $PRJ/any/nested/path/file.c, etags-table will figure out that you want to search in $PRJ/TAGS.\nIn my ctags setup file I check for a project-root var and load that into \u0026rsquo;etags-table-list\u0026rsquo; if available. I update the project-root var using a shell env var. I haven\u0026rsquo;t committed that project-root var assignment to github. But you can update that using projectile or any other mechanism.\nThe beauty is that etags-table won\u0026rsquo;t load the TAGS files from ALL the paths in \u0026rsquo;etags-table-alist\u0026rsquo;. It will load only the relevant one(s). Note that each entry in \u0026rsquo;etags-table-alist\u0026rsquo; is another list. Each of those lists is of the nature '( PROJECT_PATH, TAGS_FILE_1, [OPTIONAL_TAGS_FILE_2, ..] ).\n(require \u0026#39;etags-table) (setq etags-table-alist (list `(,(concat user-emacs-directory \u0026#34;/.*\u0026#34;) ,(concat user-emacs-directory \u0026#34;/TAGS\u0026#34;)) )) (setq etags-table-search-up-depth 15) ;; Max depth to search up for a tags file. nil means don\u0026#39;t search. ;; Below function comes useful when you change the project-root symbol to a ;; different value (when switching projects) (defun update-etags-table-then-find-tag () \u0026#34;Update etags-table based on the current value of project-root and then do tag find\u0026#34; (interactive) (when (boundp \u0026#39;project-root) ;; add-to-list if project-root symbol is defined (add-to-list \u0026#39;etags-table-alist `(,(concat project-root \u0026#34;/.*\u0026#34;) ,(concat project-root \u0026#34;/TAGS\u0026#34;)) t)) (etags-select-find-tag-at-point) ) ctags-update\u0026nbsp;# ctags-update will update the first TAGS file that is found while searching up the parent directories from the path of the file that gets modified. You can configure how frequent you want the update frequency to be.\n(require \u0026#39;ctags-update) (setq ctags-update-delay-seconds (* 30 60)) ;; every 1/2 hour (autoload \u0026#39;turn-on-ctags-auto-update-mode \u0026#34;ctags-update\u0026#34; \u0026#34;turn on `ctags-auto-update-mode\u0026#39;.\u0026#34; t) (add-hook \u0026#39;verilog-mode-hook \u0026#39;turn-on-ctags-auto-update-mode) (add-hook \u0026#39;emacs-lisp-mode-hook \u0026#39;turn-on-ctags-auto-update-mode) etags-select\u0026nbsp;# You can use etags-select to pick one of multiple tag matches. It is useful when a same function/task/.. has multiple definitions and you need to pick the definition to jump to. If multiple matches don\u0026rsquo;t exist, finding a tag at point will make you jump directly to the definition file.\nI prefer etags-select as helm-etags+ doesn\u0026rsquo;t play well with tags that have a ` prefix (which is very crucial for jumping to define/macro definitions in Verilog).\n(require \u0026#39;etags-select) (define-key etags-select-mode-map (kbd \u0026#34;C-g\u0026#34;) \u0026#39;etags-select-quit) ;; Also quit etags-select when cursor moves to another window (define-key etags-select-mode-map (kbd \u0026#34;C-x o\u0026#34;) \u0026#39;etags-select-quit) (define-key etags-select-mode-map (kbd \u0026#34;C-x O\u0026#34;) \u0026#39;etags-select-quit) (define-key etags-select-mode-map (kbd \u0026#34;C-p\u0026#34;) \u0026#39;etags-select-previous-tag) (define-key etags-select-mode-map (kbd \u0026#34;C-n\u0026#34;) \u0026#39;etags-select-next-tag) Key Bindings\u0026nbsp;# Finally here is the key-binding I have set to my quick hyper-space jumps to definitions of any kind.\n(global-set-key (kbd \u0026#34;M-.\u0026#34;) \u0026#39;update-etags-table-then-find-tag) "},"name":"ctags, systemverilog and emacs","published":"2014-03-09T03:44:36-04:00","summary":"Update (2017/02/23) \u0026mdash; Now I use GNU Global with Universal Ctags as back-end to generate the tag files. In emacs, I use the ggtags package \u0026ndash; [config].\nThis post still has value if you are interesting in configuring ctags only.\nThis posts shows how to set up ctags to parse SystemVerilog code and how to access that tag database in emacs.\n","type":"entry","url":"https://scripter.co/ctags-systemverilog-and-emacs/"}],"name":"emacs","type":"feed","url":"https://scripter.co/categories/emacs/"}