<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/custom-pretty-feed-v3.xsl" type="text/xsl"?><rss version="2.0"><channel><title>Kristoffer Balintona — #Tips and Tricks</title><description>Entries tagged with &quot;Tips and Tricks&quot;</description><link>https://kristofferbalintona.me/</link><language>en-us</language><image><url>https://kristofferbalintona.me/favicon-rss.png</url><title>Kristoffer Balintona — #Tips and Tricks</title><link>https://kristofferbalintona.me</link></image><item><title>Keeping a tidy .emacs.d/ with no-littering.el</title><link>https://kristofferbalintona.me/posts/202504210034/</link><guid isPermaLink="true">https://kristofferbalintona.me/posts/202504210034/</guid><description>&lt;p&gt;&lt;a href=&quot;https://github.com/emacscollective/no-littering&quot;&gt;No-littering.el&lt;/a&gt; keeps your .emacs.d clean. I’ve been using it for years—in fact it’s one of the only third-party packages I first installed several years ago when I started using Emacs that I still have in my config today.&lt;/p&gt;
&lt;p&gt;It establishes conventions for keeping files created from packages:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;no-littering-etc-directory&lt;/code&gt;. The directory where packages place their configuration files.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;no-littering-var-directory&lt;/code&gt;. The directory where packages place their persistent data files.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If every package followed this convention, then no files should litter (pun intended) your emacs configuration directory. Unfortunately, not every package does… fortunately, no-littering already sets the relevant option of dozens of packages to use these directories. But if you use a package that isn’t already set, you can easily use &lt;code&gt;no-littering-expand-var-file-name&lt;/code&gt; and &lt;code&gt;no-littering-expand-etc-file-name&lt;/code&gt; to change that. For example: &lt;code&gt;(setopt cursory-latest-state-file (no-littering-expand-var-file-name &quot;cursory/cursory-latest-state&quot;))&lt;/code&gt; sets &lt;code&gt;cursory-latest-state-file&lt;/code&gt; to &lt;code&gt;~/.emacs.d/var/cursory/cursory-latest-state&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s a look at my own directories.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;My &lt;code&gt;no-littering-etc-directory&lt;/code&gt;, located at &lt;code&gt;~/.emacs.d/etc/&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$ tree -L 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── abbrev.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── custom.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── gnus&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;└── transient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;3 directories, 2 files&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My &lt;code&gt;no-littering-var-directory&lt;/code&gt;, located at &lt;code&gt;~/.emacs.d/var/&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$ tree -L 1&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── abbrev-mode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── amx-save.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── anaconda-mode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── annotations.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── auto-save&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── backup&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── bookmark-default.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── citre&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── company&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── cursory&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── dap&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── dape-adapters&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── desktop&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── devdocs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── diary&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── eaf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── eafpdf&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── eglot-java&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── elfeed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── emacs-gc-stats.eld.gz&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── emms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── emojify&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── erc&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── eshell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── eww&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── flycheck&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── fontaine&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── fontaine-latest-state.eld&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── forge&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── gamegrid-user-score&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── gdb-bp-session&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── .gitignore&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── .gitmodules&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── gnus&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── helm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── ielm-history.eld&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── image-dired&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── irony&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── ispell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── keyfreq.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── languagetool&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── ledger&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── logview-cache&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── lsp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── mc-list.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── multisession&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── newsticker&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── nov-save-place.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── nsm-settings.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── org&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── org-remark&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── persist&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── popweb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── prescient-save.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── projectile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── project-list.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── project-x&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── psession&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── racket-mode&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── recentf-save.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── request&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── savehist.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── save-place.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── semantic&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── shadow&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── speed-type&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── spell-fu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── srecode-map.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── svg-lib&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── tempel-templates&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── tramp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── transient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── trash&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── treemacs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── treesit&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── tree-sitter&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── type-break.el&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── undohist&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── url&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── vimish-fold&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;└── wombag&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;60 directories, 22 files&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Without no-littering, I would either (i) have a ton of directories in my .emacs.d or (ii) have to define my own variables whose values are directories and manually, whenever I install a new package, set their options to write their files into these directories—basically what no-littering already does but without no-littering’s existing integrations. This way, my Emacs directory is neater.&lt;/p&gt;
&lt;h2&gt;Bonus: &lt;code&gt;(no-littering-theme-backups)&lt;/code&gt; &lt;a href=&quot;#bonus-no-littering-theme-backups&quot;&gt;  
§
&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;No-littering also provides the little-known &lt;code&gt;no-littering-theme-backups&lt;/code&gt;. The TL;DR is this: this function makes Emacs’s built-in auto-saving and backing up functions create files within no-littering’s directories so that sensitive data is not written to disk in unsecured locations. Calling this function sets the value of three variables:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;auto-save-file-name-transforms&lt;/code&gt;: Transforms to apply to buffer file name before making auto-save file name.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;backup-directory-alist&lt;/code&gt;: Similar to &lt;code&gt;auto-save-file-name-transforms&lt;/code&gt; but for backup files.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;undo-tree-history-directory-alist&lt;/code&gt; (from undo-tree): Similar to &lt;code&gt;auto-save-file-name-transforms&lt;/code&gt; but for backup files.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Its docstring elaborates the mechanism and purpose of this function in greater depth:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;no-littering-theme-backups is an autoloaded native-comp-function in&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;no-littering.el.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;(no-littering-theme-backups)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Theme locations where backups of various sorts are created.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;The purpose of this package is to store data files of various&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;sorts in a handful of central locations, instead of spreading&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;them all over the place.  When doing that for temporary files,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;which contain backups of some sort, that increases the odds that&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;sensitive data is written to disk in clear text and/or that such&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;clear text files persist longer, if they would be created anyway.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Because of that, simply loading ‘no-littering’ does not theme&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;certain, potentially unsafe variables.  Instead, this function is&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;provided, so that you can decide whether to take the risk or not.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Calling this function sets these variables:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;- auto-save-file-name-transforms (built-in)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;- backup-directory-alist (built-in)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;- undo-tree-history-directory-alist (from ‘undo-tree’)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;The default values of these variables cause additional files to&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;be created in the same directories as the files that are being&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;visited.  Calling this function changes the values of these&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;variables, so that this is only done for visited files located in&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;certain directories.  For all other visited files, the additional&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;files are created in files inside no-littering-var-directory.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Additional files are created in the same directory as the visited&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;file, for files located in:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;- &quot;/tmp/&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;- &quot;/dev/shm&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;- temporary-file-directory&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;With these settings it is still possible that sensitive data is&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;written to additional files, but you are more likely to spot it,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;and because these directories usually use a ‘tmpfs’ file-system,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;the leaked secrets should not persist after a reboot.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;If you do *not* call this function, then these additional files&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;are always created in the same directory as the visited files,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;regardless of the location of the visited files.  In other words,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;even when using the default values, there is a significant risk&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;of leaking sensitive data, and if you want to reduce that, then&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;you must turn of these features completely.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;</description><pubDate>Mon, 21 Apr 2025 00:34:00 GMT</pubDate><category>Emacs</category><category>Tips and Tricks</category></item><item><title>Complement corfu, vertico, and completion-preview with prescient.el sorting</title><link>https://kristofferbalintona.me/posts/202504051423/</link><guid isPermaLink="true">https://kristofferbalintona.me/posts/202504051423/</guid><description>&lt;blockquote&gt; &lt;p&gt;&lt;time&gt; &lt;span&gt;Apr 7, 2025&lt;/span&gt;  &lt;/time&gt; With several commits made on April 6, 2025, vertico spun off its sorting functionality into an extension: &lt;a href=&quot;https://github.com/minad/vertico/blob/main/extensions/vertico-sort.el&quot;&gt;vertico-sort&lt;/a&gt;. As explained in vertico-sort.el’s commentary section, it includes a new feature: when &lt;code&gt;history-delete-duplicates&lt;/code&gt; is nil, all sorting functions defined in vertico-sort.el now rank &lt;em&gt;recently&lt;/em&gt; selected candidates above frequently selected candidates. This approximates the sorting strategy of prescient.el. I think I’ll stick with prescient.el sorting because I like &lt;code&gt;history-delete-duplicates&lt;/code&gt; set to non-nil, but try it out yourself!&lt;/p&gt; &lt;/blockquote&gt;
&lt;blockquote&gt; &lt;p&gt;&lt;time&gt; &lt;span&gt;Apr 22, 2025&lt;/span&gt;  &lt;/time&gt; Corfu now offers a similar functionality as vertic-sort does for vertico with the new &lt;a href=&quot;https://github.com/minad/corfu/blob/main/extensions/corfu-history.el&quot;&gt;corfu-sort&lt;/a&gt; extension. Like vertico-sort, corfu-sort requires &lt;code&gt;history-delete-duplicates&lt;/code&gt; to be nil.&lt;/p&gt; &lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/radian-software/prescient.el&quot;&gt;Prescient.el&lt;/a&gt; is a package that was popular during the era of ivy and helm. Nowadays, I don’t see it mentioned much because of the very popular corfu + vertico + marginalia + orderless combination which enhance built-in Emacs completion and overtaken ivy and helm in terms of popularity. (And it’s deserved! I use this combination, too.)&lt;sup&gt;&lt;a href=&quot;#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; But I’ve found prescient.el a noticeable convenience that complements this set of packages.&lt;/p&gt;
&lt;p&gt;The reason is prescient.el’s sorting. Roughly, we can think of completion as having two halves: filtering and sorting. Filtering is what &lt;code&gt;completion-styles&lt;/code&gt; does: among the generated completion candidates, which are shown to the user? Sorting is the order in which the filtered candidates are shown. One might think that orderless, which is filters candidates with its completion-style, also sorts candidates—but it doesn’t. As explained in the &lt;a href=&quot;https://github.com/oantolin/orderless?tab=readme-ov-file#prescient&quot;&gt;orderless README&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/radian-software/prescient.el&quot;&gt;prescient.el&lt;/a&gt; library also provides matching of space-separated components in any order. It offers a completion-style that can be used with Emacs’ default completion UI, Mct, Vertico or with Icomplete. Furthermore Ivy is supported. The components can be matched literally, as regexps, as initialisms or in the flex style (called “fuzzy” in prescient). Prescient does not offer the same flexibility as Orderless with its style dispatchers. However in addition to matching, &lt;strong&gt;Prescient supports sorting of candidates, while Orderless leaves that up to the candidate source and the completion UI.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As such, in the corfu + vertico + marginalia + orderless world, vertico (for minibuffer completions) and corfu (for in-inline completions) are responsible for sorting candidates.&lt;/p&gt;
&lt;p&gt;The problem is this: although orderless brilliantly narrows down candidates, both vertico and corfu have somewhat naive sorting algorithms (see &lt;code&gt;vertico-sort-function&lt;/code&gt; and &lt;code&gt;corfu-sort-function&lt;/code&gt;). Vertico offers &lt;code&gt;vertico-sort-history-alpha&lt;/code&gt; and &lt;code&gt;vertico-sort-history-length-alpha&lt;/code&gt;, and corfu offers &lt;code&gt;corfu-history-mode&lt;/code&gt;. In my limited experience, however, I give prescient.el’s sorting algorithm an edge to both. (YMMV—feel free to try them!) Oftentimes vertico and corfu will &lt;strong&gt;consistently show the candidate you have in mind later in the list&lt;/strong&gt;. This tends to be the case when using certain common commands and certain &lt;code&gt;completion-at-point-functions&lt;/code&gt;: I would common seek out certain candidates that orderless would place third or fourth in the list.&lt;/p&gt;
&lt;p&gt;Prescient.el almost entirely solved this issue for me. Prescient.el offers a &lt;code&gt;completion-style&lt;/code&gt;—this is its filtering functionality—but it also offers sorting functionality. The sorting functionality is what’s relevant here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When sorting, &lt;strong&gt;the last few candidates you selected are displayed first, followed by the most frequently selected ones&lt;/strong&gt;, and then the remaining candidates are sorted by length.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Prescient.el is the core package, and there are several &lt;a href=&quot;https://github.com/radian-software/prescient.el?tab=readme-ov-file#usage&quot;&gt;auxiliary packages&lt;/a&gt; to integrate prescient with vertico, corfu, and others. We can enable prescient’s sorting for vertico and corfu (but not its filtering; I want to leave this to orderless) with something like the following:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; Core package&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;use-package&lt;/span&gt;&lt;span&gt; prescient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:custom&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; My settings for relevant user options:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; (prescient-aggressive-file-save t)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; (prescient-sort-length-enable nil)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; (prescient-sort-full-matches-first t)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; (prescient-history-length 200)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; (prescient-frequency-decay 0.997)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; (prescient-frequency-threshold 0.05)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:config&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; Optional: persist prescient statistics to an on-disk cache&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; (&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;prescient-save-file&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;prescient-persist-mode &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; Integration with corfu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;use-package&lt;/span&gt;&lt;span&gt; corfu-prescient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; The :after keyword defers loading this package, meaning this package is&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; only loaded until something else wants something from it.  If we want&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-prescient-mode&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; to be enabled in the :config block, we need to&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; prevent deferral with the :demand keyword. In combination with our :after&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; block, the package is immediately loaded only after both corfu and&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; prescient are loaded.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:demand&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:after&lt;/span&gt;&lt;span&gt; corfu prescient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:custom&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; Sorting.  These are the default values but I include them here to be&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; explicit.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;corfu-prescient-enable-sorting t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;corfu-prescient-override-sorting &lt;/span&gt;&lt;span&gt;nil)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;; Don&apos;t override &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;display-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; Filtering&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;corfu-prescient-enable-filtering &lt;/span&gt;&lt;span&gt;nil)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;; We want orderless to do the filtering&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; See also &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-prescient-completion-styles&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-prescient-completion-category-overrides&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; and&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;prescient--completion-recommended-overrides&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;.  Those options apply only&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; when &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-prescient-enable-filtering&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; is non-nil.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:config&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;corfu-prescient-mode &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; Integration with vertico&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;use-package&lt;/span&gt;&lt;span&gt; vertico-prescient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; The :after keyword defers loading this package, meaning this package is&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; only loaded until something else wants something from it.  If we want&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;vertico-prescient-mode&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; to be enabled in the :config block, we need to&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; prevent deferral with the :demand keyword. In combination with our :after&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; block, the package is immediately loaded only after both vertico and&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; prescient are loaded.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:demand&lt;/span&gt;&lt;span&gt; t&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:after&lt;/span&gt;&lt;span&gt; vertico prescient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:custom&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; Sorting.  These are the default values but I include them here to be&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; explicit.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;vertico-prescient-enable-sorting t&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;vertico-prescient-override-sorting &lt;/span&gt;&lt;span&gt;nil)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;; Don&apos;t override &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;display-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; Filtering&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;vertico-prescient-enable-filtering &lt;/span&gt;&lt;span&gt;nil)&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;; We want orderless to do the filtering&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; See also &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;vertico-prescient-completion-styles&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;vertico-prescient-completion-category-overrides&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;, and&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;prescient--completion-recommended-overrides&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;.  Those options apply only&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; when when &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;vertico-prescient-enable-filtering&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; is non-nil.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;:config&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;vertico-prescient-mode &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The result is using orderless for completion filtering and prescient for completion sorting everywhere—for in-line completions with corfu and minibuffer completions with vertico. With this, among the candidates filtered by orderless, the most recent and common ones will be bumped up to the beginning. Try it out!&lt;/p&gt;
&lt;h2&gt;Bonus: integration with &lt;code&gt;completion-preview-mode&lt;/code&gt; &lt;a href=&quot;#bonus-integration-with-completion-preview-mode&quot;&gt;  
§
&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Emacs 30.1 ships with the new &lt;code&gt;completion-preview-mode&lt;/code&gt;. You can read about it &lt;a href=&quot;https://eshelyaron.com/posts/2023-11-17-completion-preview-in-emacs.html&quot;&gt;in this blog post&lt;/a&gt; but also in the Emacs 30.1 news (i.e., &lt;code&gt;C-u 30 C-h n&lt;/code&gt;). Apparently, &lt;code&gt;completion-preview-mode&lt;/code&gt;
has its own sorting function—which makes sense, since it isn’t hooked into either corfu nor vertico (which we set up to use prescient above). The relevant user option to modify its sorting is &lt;code&gt;completion-preview-sort-function&lt;/code&gt;. So we just have to make sure that function matches prescient’s. We can do that like this:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;with-eval-after-load&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;prescient&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;;; Have &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;completion-preview-mode&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; use prescient&apos;s sorting algorithm&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;setopt completion-preview-sort-function &lt;/span&gt;&lt;span&gt;#&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;prescient-completion-sort))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;But, if you also use corfu on top of &lt;code&gt;completion-preview-mode&lt;/code&gt;, you’ll still notice a discrepancy between corfu’s first candidate and completion-preview’s candidate. They should be the same with the same sorting algorithm but they’re not! I’m not 100%, but I’m fairly confident that corfu-prescient keeps track of corfu-specific completion usage, which is separate from non-corfu-specific use. Consequently, the statistics used to sort candidates ends up different between corfu and &lt;code&gt;prescient-completion-sort&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In any case, below is a simple fix that gets corfu and completion-preview on the same page:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; We set completion-preview&apos;s sorting function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; (&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;completion-preview-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;) to corfu&apos;s sorting function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; (&lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;).&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;with-eval-after-load&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;corfu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;setopt completion-preview-sort-function corfu-sort-function&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; Alternative: for a solution that ensures &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;completion-preview-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; always matches &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;, we can use a variable watcher.  This is&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; my preference.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; The below accounts for cases in which (i) the user has buffer-local values&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; for &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; or (ii) the user changes the global value of&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; (e.g., from minor modes that disable/enable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; functionality).  It is a robust solution, and although I have not tested its&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;;; performance overhead, it should cause no problems.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;add-variable-watcher&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;corfu-sort-function&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                      &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;lambda&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;_symbol&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;newval&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;operation&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;where&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;Match the value of &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;completion-preview-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; to &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;If &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; is set buffer-locally, also set&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;completion-preview-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; buffer-locally.  Otherwise, change&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;the default value of &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;completion-preview-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; accordingly.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;This action only applies when the value of &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;span&gt;corfu-sort-function&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt; is&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;set (i.e., OPERATION is \\=&apos;set).  This excludes, e.g., let bindings.&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;when&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;equal&lt;/span&gt;&lt;span&gt; operation &lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;set)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                          &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; where&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                              &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;with-current-buffer&lt;/span&gt;&lt;span&gt; where&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                                &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;setq-local&lt;/span&gt;&lt;span&gt; completion-preview-sort-function newval&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;                            &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;setopt completion-preview-sort-function newval&lt;/span&gt;&lt;span&gt;)))))&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;h2&gt;Changelog &lt;a href=&quot;#changelog&quot;&gt;  
§
&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;time&gt; &lt;span&gt;Apr 7, 2025&lt;/span&gt;  &lt;/time&gt;
&lt;ul&gt;
&lt;li&gt;Fixed several typos.&lt;/li&gt;
&lt;li&gt;Added clarity to several phrases.&lt;/li&gt;
&lt;li&gt;Added a note mentioning the new vertico-sort extension.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;time&gt; &lt;span&gt;Apr 5, 2025&lt;/span&gt;  &lt;/time&gt;
&lt;ul&gt;
&lt;li&gt;Correction to explanation according to &lt;a href=&quot;https://www.reddit.com/r/emacs/comments/1js6xvw/comment/mlkpge6/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button&quot;&gt;r/JDRiverRun’s comment&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;time&gt; &lt;span&gt;Apr 22, 2025&lt;/span&gt;  &lt;/time&gt;
&lt;ul&gt;
&lt;li&gt;Added a note mentioning the new corfu-history extension.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;footer&gt; &lt;h2&gt;&lt;p&gt;Footnotes&lt;/p&gt;&lt;/h2&gt; &lt;ol&gt; &lt;li&gt;   &lt;a href=&quot;#fnref-1&quot;&gt;[1]&lt;/a&gt; &lt;div&gt; &lt;p&gt;In my opinion, each package is much more modular than the helm or ivy ecosystems while being more performant, integrated with existing Emacs functionality, and just as useful, if not more. Though a bit dated, I’ve previously written a big about how to configure this set of packages: &lt;a href=&quot;https://kristofferbalintona.me/articles/vertico-marginalia-all-the-icons-completion-and-orderless/&quot;&gt;Vertico, Marginalia, All-the-icons-completion, and Orderless&lt;/a&gt;.&lt;/p&gt;  &lt;a href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/footer&gt;</description><pubDate>Sat, 05 Apr 2025 14:23:00 GMT</pubDate><category>Emacs</category><category>Tips and Tricks</category></item><item><title>Jujutsu (jj) VCS workflows and the convenience of its “operation log”</title><link>https://kristofferbalintona.me/posts/202503270835/</link><guid isPermaLink="true">https://kristofferbalintona.me/posts/202503270835/</guid><description>&lt;p&gt;Over the last month or two I’ve been trying out the relatively new &lt;a href=&quot;https://jj-vcs.github.io/jj/latest/&quot;&gt;jujutsu&lt;/a&gt; version control system (VCS) — and loving it. At first, I discovered it and read their &lt;a href=&quot;https://github.com/jj-vcs/jj&quot;&gt;GitHub README&lt;/a&gt; with curiosity but skepticism. Then I sought a few &lt;a href=&quot;https://www.youtube.com/results?search_query=what+is+jujutsu+vcs&quot;&gt;YouTube videos&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; demonstrating jj in action, and &lt;a href=&quot;https://jj-vcs.github.io/jj/latest/&quot;&gt;a tutorial&lt;/a&gt; for a text-based reference. I became very interested. I initialized a jj repo in one of my small git projects and played around. Since then, I’ve migrated all of my personal repositories to jj, and use jj for practically everything.&lt;/p&gt;
&lt;p&gt;From the time I’ve spent with jj, I’ve felt myself sliding into some general workflows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;jj squash&lt;/code&gt; workflow&lt;br /&gt;
In git, this would be a workflow where you make a commit and continually amend/extend that commit until its intended goal is completed.
&lt;ol&gt;
&lt;li&gt;Make progress toward a desired goal.&lt;/li&gt;
&lt;li&gt;Commit (&lt;code&gt;jj commit&lt;/code&gt;, or &lt;code&gt;jj new&lt;/code&gt; then &lt;code&gt;jj describe -m &quot;...&quot;&lt;/code&gt;) with a message describing this unit of work.&lt;/li&gt;
&lt;li&gt;Continue making changes.&lt;/li&gt;
&lt;li&gt;Squash (perhaps interactively: &lt;code&gt;jj squash -i&lt;/code&gt;&lt;sup&gt;&lt;a href=&quot;#fn-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;) new changes until the desired goal is accomplished.&lt;/li&gt;
&lt;li&gt;Maybe change the description of the previous commit commit.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Work in the working copy
&lt;ol&gt;
&lt;li&gt;Envision a goal for a new commit. Express that into the description of the working copy commit: &lt;code&gt;jj describe -m &quot;...&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Work until much of that goal is met.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jj new&lt;/code&gt; to work on the next goal. Or &lt;code&gt;jj split -i&lt;/code&gt; if some of the changes in the working copy belong in the next commit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jj edit&lt;/code&gt; to hop between commits and work on each until completion. Perhaps &lt;code&gt;jj new -A ...&lt;/code&gt; one or more times when when you don’t want certain changes in a commit: make changes across however many of those commits, then &lt;code&gt;jj squash&lt;/code&gt; them all into your original commit when you’re happy. (You’re basically creating a new git branch!)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Concurrent commits workflow&lt;br /&gt;
Work on several commits simultaneously, using combinations of &lt;code&gt;jj squash&lt;/code&gt;, &lt;code&gt;jj new&lt;/code&gt;, and &lt;code&gt;jj rebase&lt;/code&gt; to make make reversible changes while having a clean &lt;code&gt;jj log&lt;/code&gt; at the end. In essence, this is point (3.4) above but with room for added complexity.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’m not a VCS expert, and my projects are small, but I’ve gravitated to (1) and (2) without feeling any mental strain of keeping track of where this and that change is and what CLI operations avoid x problem or y merging conflict (which, by the way, jj permits! Jujutsu treats conflicts as first-class, so conflicts and their resolutions percolate through ancestors and descendants without problem.)&lt;sup&gt;&lt;a href=&quot;#fn-3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Perhaps the most exciting part of using jj is fearlessly making changes and experimenting. This has been an extraordinary boon for my learning about how to use jj in accordance to its VCS concepts. The reason is jj’s operation log (&lt;code&gt;jj op log&lt;/code&gt;) and the ability to &lt;strong&gt;revert back to &lt;em&gt;any&lt;/em&gt; past repository state&lt;/strong&gt; (&lt;code&gt;jj op restore OPERATION_ID&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;jj op restore&lt;/code&gt;, I can merge branches, create conflicts, resolve conflicts, mess up… then go back as if it never happened. I can make sweeping repository changes without fear! In git, I’d be walking on egg shells, worried about the potential to ruin the entire state of my local repository if I’m not careful…&lt;/p&gt;
&lt;p&gt;I’d definitely recommend trying jj out if you haven’t already! Easily turn a git repo into a jj repo with a git backend: &lt;code&gt;jj git init \-\-colocate&lt;/code&gt;.&lt;/p&gt;
&lt;footer&gt; &lt;h2&gt;&lt;p&gt;Footnotes&lt;/p&gt;&lt;/h2&gt; &lt;ol&gt; &lt;li&gt;   &lt;a href=&quot;#fnref-1&quot;&gt;[1]&lt;/a&gt; &lt;div&gt; &lt;p&gt;I found &lt;a href=&quot;https://www.youtube.com/watch?v=bx_LGilOuE4&quot;&gt;this talk&lt;/a&gt; by the originator of jujutsu, Martin von Zweigbergk, a senior software engineer at Google, especially insightful with respect to the technical merits of jj over git. If jj is meant to potentially eventually handle Google’s gigantic monorepo (86 terabytes of data, ~2 billion lines of code across 9 million source files!), then surely there’s something to it! The talk justifies the existence of jj.&lt;/p&gt;  &lt;a href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt;&lt;li&gt;   &lt;a href=&quot;#fnref-2&quot;&gt;[2]&lt;/a&gt; &lt;div&gt; &lt;p&gt;Without the &lt;code&gt;-u&lt;/code&gt; flag, &lt;code&gt;jj squash -i&lt;/code&gt; effectively behaves like &lt;code&gt;git commit \-\-amend&lt;/code&gt; when your working copy has a description (e.g., with &lt;code&gt;jj desc -m &quot;...&quot;&lt;/code&gt; or if you &lt;code&gt;jj edit&lt;/code&gt; to a past commit). Without a commit, &lt;code&gt;jj squash -i&lt;/code&gt; is like &lt;code&gt;git commit \-\-amend \-\-no-edit&lt;/code&gt;.&lt;/p&gt;  &lt;a href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt;&lt;li&gt;   &lt;a href=&quot;#fnref-3&quot;&gt;[3]&lt;/a&gt; &lt;div&gt; &lt;p&gt;A great resource on the matter of “conflicts as first-class” is &lt;a href=&quot;https://youtu.be/LV0JzI8IcCY?si=n0xrGZfRx6vZGNmr&amp;amp;t=553&quot;&gt;this talk&lt;/a&gt; by the mind behind jj.&lt;/p&gt;  &lt;a href=&quot;#fnref-3&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/footer&gt;</description><pubDate>Thu, 27 Mar 2025 08:35:00 GMT</pubDate><category>VCS</category><category>Tips and Tricks</category></item><item><title>A surprising upside to vc-dir marks over magit</title><link>https://kristofferbalintona.me/posts/202411270440/</link><guid isPermaLink="true">https://kristofferbalintona.me/posts/202411270440/</guid><description>&lt;p&gt;Vc.el is Emacs’s built-in interface for version control CLI tools. With respect to Git, magit has for several years now been the most favored (with respect to popularity) Git&lt;sup&gt;&lt;a href=&quot;#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; interface. At least in the r/emacs subreddit, magit is frequently considered a killer-feature—an irreplaceable feature unique to Emacs.&lt;/p&gt;
&lt;p&gt;For the most part I am inclined to agree. However, in the last few months, I’ve been regularly experimenting using &lt;code&gt;vc&lt;/code&gt;. This is in part motivated by recent improvements to &lt;code&gt;vc&lt;/code&gt;’s implementation of Git, and another part motivated by a curiosity to see whether I’d end up enjoying some parts of the &lt;code&gt;vc&lt;/code&gt;-way of doing things over the magit-way of doing things.&lt;sup&gt;&lt;a href=&quot;#fn-2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;On such insight has been the surprising benefits of calling &lt;code&gt;vc-dir&lt;/code&gt; instead of &lt;code&gt;magit-status&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;The nicety of &lt;code&gt;vc-dir&lt;/code&gt; marks &lt;a href=&quot;#the-nicety-of-vc-dir-marks&quot;&gt;  
§
&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In &lt;code&gt;magit-status&lt;/code&gt;, I would typically stage various files and hunks and commit them when ready. &lt;code&gt;vc&lt;/code&gt; does not use Git’s “staging” concept (because not all version control systems use such a concept). So instead, to achieve something analogous, a user might call &lt;code&gt;vc-dir&lt;/code&gt; (or, much more commonly for me, &lt;code&gt;project-vc-dir&lt;/code&gt;), mark edited files (or entire directories!) using &lt;code&gt;vc-dir-mark&lt;/code&gt; (&lt;code&gt;m&lt;/code&gt;), and check out (commit) those changes via &lt;code&gt;vc-next-action&lt;/code&gt; (&lt;code&gt;v&lt;/code&gt;) or see a diff of those changes with &lt;code&gt;vc-diff&lt;/code&gt; (&lt;code&gt;=&lt;/code&gt;) and commit the changes in that diff-mode buffer (&lt;code&gt;v&lt;/code&gt;).&lt;sup&gt;&lt;a href=&quot;#fn-3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;A problem for the magit interface, however, is &lt;em&gt;visual clarity&lt;/em&gt; when it comes to focusing on changes in a certain subset of files. For example, sometimes I am working with changes in files within a single directory alongside many other uncommitted changes elsewhere in the repository. To make a commit with magit, I would need to navigate past or fold changed hunks/files I want to ignore. With many unstaged changes this means many files to ignore. &lt;strong&gt;This leads to a significant reduction in visual clarity since I end up having to ignore more files than I’m currently working on.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There is a subtle solution in vc.el. The secret lies in the fact that &lt;em&gt;marks, which can be used to selectively create diff buffers and commit changes from those buffers, are preserved&lt;/em&gt; in &lt;code&gt;vc-dir&lt;/code&gt; buffers after changes are committed. A mark is only removed once the corresponding line is removed via something like &lt;code&gt;vc-dir-hide-up-to-date&lt;/code&gt; (&lt;code&gt;x&lt;/code&gt;) or &lt;code&gt;vc-dir-kill-line&lt;/code&gt; (&lt;code&gt;C-k&lt;/code&gt;). Marks are magical because they let me &lt;em&gt;focus&lt;/em&gt; on the files relevant to my current work: I can mark the files and directories I am focusing on &lt;strong&gt;then call &lt;code&gt;vc-next-action&lt;/code&gt; in the &lt;code&gt;vc-dir&lt;/code&gt; buffer to commit changes only in those files and directories&lt;/strong&gt; (or, if I want to be selective about the hunks I commit: first call &lt;code&gt;vc-diff&lt;/code&gt; to see the diff of just the marked files, kill/remove the hunks I don’t want to commit, then &lt;code&gt;vc-next-action&lt;/code&gt;).Then I can write more changes and make more commits in the same way. (Furthermore, while this &lt;code&gt;vc&lt;/code&gt; workflow might seem like it would necessarily involve many more keystrokes, I found this not to be the case under certain scenarios.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In short,&lt;/strong&gt; with vc.el, a really efficient workflow is&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;vc-diff&lt;/code&gt; or &lt;code&gt;vc-root-diff&lt;/code&gt; → &lt;code&gt;vc-next-action&lt;/code&gt; and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vc-dir&lt;/code&gt; (with persistent marks) → &lt;code&gt;vc-diff&lt;/code&gt; → &lt;code&gt;vc-next-action&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The latter is unique to vc.el, and a feature I don’t think the magit UI can replicate. So while magit can sometimes become visually cluttered, &lt;code&gt;vc-dir&lt;/code&gt; marks let users focus on their current work by easily excluding &lt;em&gt;from view&lt;/em&gt; files and directories one is not concerned with currently.&lt;/p&gt;
&lt;h2&gt;A caveat &lt;a href=&quot;#a-caveat&quot;&gt;  
§
&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Historically, I’ve found this especially fruitful when working on my literate Emacs config&lt;sup&gt;&lt;a href=&quot;#fn-4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; (wherein any “single change” involves changes to the .org file as well as the resulting tangled file(s)) and Emacs packages. Still, I think I prefer magit in cases where the staging functionality of Git is crucial. For instance, I have a repository that houses all my org notes and org-agenda files. There are frequently many changes for this repository, so the convenience of staging/unstaging has been crucial for me. In cases like these, I haven’t found an equivalent for vc.el yet.&lt;/p&gt;
&lt;h2&gt;Changelog &lt;a href=&quot;#changelog&quot;&gt;  
§
&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;time&gt; &lt;span&gt;Mar 25, 2025&lt;/span&gt;  &lt;/time&gt;
&lt;ul&gt;
&lt;li&gt;Add clarifying prose to paragraph.&lt;/li&gt;
&lt;li&gt;Change formatting of “vc.el” and “magit.”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;footer&gt; &lt;h2&gt;&lt;p&gt;Footnotes&lt;/p&gt;&lt;/h2&gt; &lt;ol&gt; &lt;li&gt;   &lt;a href=&quot;#fnref-1&quot;&gt;[1]&lt;/a&gt; &lt;div&gt; &lt;p&gt;magit is an interface for Git, whereas vc.el is an interface for other version control tools, albeit older ones, some of which may follow a non-decentralized version control paradigm (read the Emacs Info node &lt;code&gt;(emacs) Version Control Systems&lt;/code&gt; for more information):&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;CVS&lt;/li&gt;
&lt;li&gt;Subversion (svn)&lt;/li&gt;
&lt;li&gt;SCCS&lt;/li&gt;
&lt;li&gt;CSSC&lt;/li&gt;
&lt;li&gt;Mercurial (hg)&lt;/li&gt;
&lt;li&gt;Bazaar (bzr)&lt;/li&gt;
&lt;li&gt;SRC (src)&lt;/li&gt;
&lt;/ul&gt;  &lt;a href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt;&lt;li&gt;   &lt;a href=&quot;#fnref-2&quot;&gt;[2]&lt;/a&gt; &lt;div&gt; &lt;p&gt;A philosophical tangent: the interface of a tool (digital or analog/physical) influences how users interact with that tool and how users accomplish the purposes of the tool. As such, what seems at first as a subtle difference in workflow or interface to achieve the same end almost always overlooks aspects relevant to the workflow’s effectiveness.&lt;/p&gt;&lt;p&gt;For instance, users of Emacs will readily recognize that Emacs is thoroughly characterized by an “emacs-y” way of doing things. The total network of keybinds, conventions, and procedures of using Emacs might accomplish the same purposes as other software (combined or standalone), but this specific network of “ways to interface with Emacs-as-a-tool” enables Emacs to offer a uniquely effective experience.&lt;/p&gt;  &lt;a href=&quot;#fnref-2&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt;&lt;li&gt;   &lt;a href=&quot;#fnref-3&quot;&gt;[3]&lt;/a&gt; &lt;div&gt; &lt;p&gt;If I want to commit changes with much fewer unstaged changes present, then a faster method would be: call &lt;code&gt;vc-root-diff&lt;/code&gt; (&lt;code&gt;C-x v D&lt;/code&gt;), modify the diff-mode buffer accordingly with &lt;code&gt;diff-hunk-kill&lt;/code&gt; (&lt;code&gt;k&lt;/code&gt;) or &lt;code&gt;diff-delete-other-hunks&lt;/code&gt; (&lt;code&gt;C-c RET n&lt;/code&gt;; a recent addition to Emacs-30), then commit the changes with &lt;code&gt;vc-next-action&lt;/code&gt; (&lt;code&gt;v&lt;/code&gt;). &lt;a&gt;&lt;/a&gt;&lt;/p&gt;  &lt;a href=&quot;#fnref-3&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt;&lt;li&gt;   &lt;a href=&quot;#fnref-4&quot;&gt;[4]&lt;/a&gt; &lt;div&gt; &lt;p&gt;See also &lt;a href=&quot;#target-1&quot;&gt;footnote 3&lt;/a&gt;.&lt;/p&gt;  &lt;a href=&quot;#fnref-4&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/footer&gt;</description><pubDate>Wed, 27 Nov 2024 04:40:00 GMT</pubDate><category>Emacs</category><category>VCS</category><category>Tips and Tricks</category></item><item><title>Neat behavior of M-x occur</title><link>https://kristofferbalintona.me/posts/202411090600/</link><guid isPermaLink="true">https://kristofferbalintona.me/posts/202411090600/</guid><description>&lt;p&gt;Having used Emacs for several years now, I somehow hadn’t come across the prefix argument and active region behavior for one of the most well-known commands: &lt;code&gt;occur&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Below is the docstring of &lt;code&gt;occur&lt;/code&gt; reads, with the relevant portions preserved:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;occur is an interactive native-comp-function in replace.el.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;It is bound to M-s o.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;(occur REGEXP &amp;amp;optional &lt;strong&gt;NLINES REGION&lt;/strong&gt;)&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Inferred type: (function (t &amp;amp;optional t t) t)&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Show all lines in the current buffer containing a match for REGEXP.&lt;br /&gt;
If a match spreads across multiple lines, all those lines are shown.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;[…]&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Each line is displayed with NLINES lines before and after, or -NLINES&lt;br /&gt;
before if NLINES is negative.&lt;br /&gt;
NLINES defaults to list-matching-lines-default-context-lines.&lt;br /&gt;
Interactively it is the prefix arg.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Optional arg REGION, if non-nil, mean restrict search to the&lt;br /&gt;
specified region.  Otherwise search the entire buffer.*&lt;br /&gt;
*REGION must be a list of (START . END) positions as returned by&lt;br /&gt;
region-bounds.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;[…]&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When NLINES is a string or when the function is called&lt;br /&gt;
interactively with prefix argument without a number (C-u alone&lt;br /&gt;
as prefix) the matching strings are collected into the ‘*Occur*’&lt;br /&gt;
buffer by using NLINES as a replacement regexp.  NLINES may&lt;br /&gt;
contain \&amp;amp; and \N which convention follows replace-match.&lt;br /&gt;
For example, providing “defun\s +$\S +$” for REGEXP and&lt;br /&gt;
“\1” for NLINES collects all the function names in a lisp&lt;br /&gt;
program.  When there is no parenthesized subexpressions in REGEXP&lt;br /&gt;
the entire match is collected.  In any case the searched buffer&lt;br /&gt;
is not modified.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;[…]&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;So:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When called on a region, on that region is searched.&lt;/li&gt;
&lt;li&gt;When called with a numerical prefix argument, that many lines before and after every match is added to the search results. (This reminds me of &lt;code&gt;next-screen-context-lines&lt;/code&gt;.) &lt;em&gt;This functionality is particularly useful to me since added context is sometimes necessary.&lt;/em&gt;&lt;sup&gt;&lt;a href=&quot;#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;When called with a universal argument, just the matching string (not the entire line) is inserted into a line in a read-only buffer.&lt;/li&gt;
&lt;li&gt;If called from elisp and &lt;code&gt;NLINES&lt;/code&gt; is provided (as a regexp string), then the behavior is like &lt;code&gt;C-u&lt;/code&gt; but matches can be modified like &lt;code&gt;replace-match&lt;/code&gt;. (See &lt;code&gt;(elisp) Replacing Match&lt;/code&gt; for more information.)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also, searching “NLINES” with &lt;code&gt;apropos-documentation&lt;/code&gt; brings up a few other built-in commands that have similar functionality. &lt;code&gt;isearch-occur&lt;/code&gt;, &lt;code&gt;multi-occur&lt;/code&gt;, &lt;code&gt;list-matching-lines&lt;/code&gt;, and &lt;code&gt;occur-context-lines&lt;/code&gt; to name a few.&lt;/p&gt;
&lt;p&gt;Pretty neat!&lt;/p&gt;
&lt;h2&gt;Further Reading &lt;a href=&quot;#further-reading&quot;&gt;  
§
&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.masteringemacs.org/article/searching-buffers-occur-mode&quot;&gt;Searching and Editing in Buffers with Occur Mode - Mastering Emacs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.reddit.com/r/emacs/comments/1466y8d/what_do_you_use_for_occur/&quot;&gt;What do you use for occur?  - Reddit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://protesilaos.com/codelog/2019-08-04-emacs-occur/&quot;&gt;Emacs’ powerful OCCUR function in practice | Protesilaos Stavrou&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.emacswiki.org/emacs/OccurMode&quot;&gt;EmacsWiki: Occur Mode&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;footer&gt; &lt;h2&gt;&lt;p&gt;Footnotes&lt;/p&gt;&lt;/h2&gt; &lt;ol&gt; &lt;li&gt;   &lt;a href=&quot;#fnref-1&quot;&gt;[1]&lt;/a&gt; &lt;div&gt; &lt;p&gt;I sometimes use &lt;code&gt;occur-edit-mode&lt;/code&gt; (bound to &lt;code&gt;e&lt;/code&gt; in &lt;code&gt;occur-mode&lt;/code&gt; buffers), and the added context lines can be relevant to the edits I want to make to the matched text.&lt;/p&gt;  &lt;a href=&quot;#fnref-1&quot;&gt;↩&lt;/a&gt; &lt;/div&gt; &lt;/li&gt; &lt;/ol&gt; &lt;/footer&gt;</description><pubDate>Sat, 09 Nov 2024 06:00:00 GMT</pubDate><category>Emacs</category><category>Tips and Tricks</category></item></channel></rss>