Protesilaos Stavrou: Emacs: denote version 0.5.0

Denote is a simple note-taking tool. It is based on the idea that notes should follow a predictable and descriptive file-naming scheme. The file name must offer a clear indication of what the note is about, without reference to any other metadata. Denote basically streamlines the creation of such files while providing facilities to link between them.

Below are the release notes.

The general theme of this release is to refine what we already offer. As I explained in some discussions, Denote is feature-complete. We can always improve the code or add some ancillary function/command/variable, though all the main ideas have already been implemented. Additional functionality can be provided by other packages: I remain at the disposal of anyone willing to write such a package.

The present release covers more than 150 commits since version 0.4.0 on 2022-07-25.

All release notes:

Templates for new notes

We now provide the denote-templates user option. A “template” is arbitrary text that Denote will add to a newly created note right below the front matter.

Templates are expressed as a (KEY . STRING) association.

  • The KEY is the name which identifies the template. It is an arbitrary symbol, such as report, memo, statement.

  • The STRING is ordinary text that Denote will insert as-is. It can contain newline characters to add spacing. The manual of Denote contains examples on how to use the concat function, beside writing a generic string:

The user can choose a template either by invoking the new command denote-template or by changing the user option denote-prompts to always prompt for a template when calling the denote command.

Thanks to Jean-Philippe Gagné Guay for refinements to this facility. Done in pull request 77 on the GitHub mirror:

[ Jean-Philippe has assigned copyright to the Free Software Foundation. ]

Revised format for Org #+filetags entry

Denote used to format tags in Org files by separating them with two spaces:

#+filetags:  tag1  tag2

While this worked for some obvious use-cases, it is not supported by Org. The Org documentation stipulates that tags be separated by the colon sign. The above would then be written thus:

#+filetags:  :tag1:tag2:

Denote now conforms with Org’s specifications. To help users update their existing notes, we provide the denote-migrate-old-org-filetags command. It will perform the conversion in all Org files that had the old notation. As with all Denote operations that rewrite file contents, it DOES NOT SAVE BUFFERS. The user is expected to review the changes, such as by using diff-buffer-with-file. Multiple buffers can be saved with save-some-buffers (check its doc string).

This command is provided for the convenience of the user. It shall be deprecated and eventually removed from future versions of Denote.

If you need help with any of this, please do not hesitate to contact me either in private or in one of Denote’s official channels (mailing list, GitHub/GitLab mirror).

Thanks to Alan Schmitt for bringing this matter to my attention: Also thanks to Jean-Philippe Gagné Guay for commenting on it as it helped me decide to include the command in denote.el:

Revised format for Markdown+YAML tags: entry

This is the same idea as above. Before, we were making the mistake of using incorrect YAML notation:

tags:  tag1  tag2

Now we do:

tags:  ["tag1", "tag2"]

This is how the TOML variant always worked.

For the user’s convenience, we provide a command to migrate from the old to the new syntax: denote-migrate-old-markdown-yaml-tags.

Changes to file renaming and front matter rewriting

Denote adds “front matter” to newly created notes which includes data such as the title and keywords/tags of the document. Strictly speaking, the front matter is not required by Denote. It is provided for the user’s convenience, such as for readability or if they want to use the note with other programs (e.g. Org export, a blog with Hugo/Jekyll, …).

Denote provides commands which help the user rename their notes, by changing the file name’s TITLE and/or KEYWORDS components (per Denote’s file-naming scheme). These commands also operate on the front matter to keep the data between file name and file contents in sync (again, for the user’s convenience).

For this release we have consolidated and refined our offerings in order to improve their ergonomics. All changes are the result of fruitful discussions on the mailing list and the issue tracker of the GitHub mirror:

Thanks to (A-Z) Hanspeter Gisler, Jean-Philippe Gagné Guay, and Peter Prevos for their participation.

Also thanks to Jean-Philippe Gagné Guay for relevant code contributions (please consult the Git log for the minutiae):

Renaming a single file

The commands denote-dired-rename-file-and-add-front-matter and denote-dired-rename-file are deprecated and superseded by the new denote-rename-file. Please update any key bindings in your setup.

The difference between the old commands and the new denote-rename-file is that the latter will now insert front matter to supported file types (per denote-file-type) if they have none. This basically means that, e.g., renaming a generic Org/Markdown/Plain text file with denote-rename-file will update its file name to comply with Denote’s file-naming scheme and also add the appropriate front matter (it “converts” it to a Denote note). If front matter exists, this command will rewrite it to reflect the changes to the file name’s TITLE and/or KEYWORDS.

Consult the manual for the details:

Or, if the new version of the GNU ELPA package is installed, evaluate:

(info "(denote) Rename a single file")

The user option denote-dired-rename-expert is obsolete. Denote always asks for confirmation when renaming a single file. This is because the user can rely on batch-renaming commands which ask for confirmation only once per batch.

Renaming multiple files at once

The command denote-dired-rename-marked-files-and-add-front-matter is deprecated and its functionality is absorbed by the existing denote-dired-rename-marked-files command. The deprecated command was used to insert front matter to supported file types (per denote-file-type) that had none. We now handle this internally, thus streamlining the experience for the user.

Refer to the manual for the details:

Assuming the latest Info manual is installed, evaluate:

(info "(denote) Rename multiple files at once")

Renaming a single file based on its front matter

Introduced the denote-rename-file-using-front-matter command. This is new functionality we provide which uses the front matter as input to perform a rename of the file. The aforementioned offerings prompt for input via the minibuffer and propagate the changes firstly to the file name and subsequently to the front matter. Whereas with the command denote-rename-file-using-front-matter, the user can edit the front matter manually and then invoke the command to pass the changes to the file name, subject to a confirmation. Relevant entries are the title and tags/filetags (depending on the file type). The date and the identifier are not pertinent. Identifiers in file names are NEVER rewritten by Denote.

Consult the manual:

With the latest package, evaluate:

(info "(denote) Rename a single file based on its front matter")

Renaming multiple files based on their front matter

The command denote-dired-rename-marked-files-using-front-matter completes the set of features we provide for syncing between file name and front matter. It applies to all marked files in a Dired buffer.

Read the manual to understand how the command works and what it does exactly:

Or evaluate:

(info "(denote) Rename multiple files based on their front matter")

Add missing front matter on demand

Sometimes the user may have incomplete front matter, perhaps due to a mistake that was saved on disk. The command denote-add-front-matter appends a new front matter block to the current note.


Or evaluate:

(info "(denote) Regenerate front matter")

Faces for Denote links

We provide the denote-faces-link and the denote-faces-broken-link. The latter is only relevant for Org, as Emacs’ standard button mechanism does not have a way to apply a face dynamically.

This is a change for themes/tinkerers who need to differentiate denote: links from other links. Otherwise, the presentation is the same as before.

Thanks to Peter Prevos for asking about it on the mailing list:

Use of XDG path in denote-directory

The default value of the denote-directory user option used to be ~/Documents/notes (subject to some conversion via Elisp). Denote now conforms with the specifications by using the XDG directory for DOCUMENTS instead of ~/Documents:

Users who already bind the denote-directory are not affected by this change. Same for those who do not tinker with XDG environment variables and/or do not use some exotic setup.

Thanks to Philip Kaludercic for the patch:

Bespoke major-mode for the backlinks’ buffer

The backlinks’ buffer now uses the denote-backlink-mode instead of the generic special-mode. The former derives from the latter. It binds keys to move between links with n (next) and p (previous). These are stored in the denote-backlink-mode-map (use M-x describe-mode (C-h m) in an unfamiliar buffer to learn more about it).

Thanks to Philip Kaludercic for the patch:

Changes to the manual

  • Documented all of the aforementioned. Improved how information is presented and, generally, iterated on an already comprehensive document.

  • Introduced a node which explains how to tweak the front matter: Or evaluate:

    (info "(denote) Change the front matter format")
  • Updated the reference to consult-notes. This is a package that uses the consult interface to provide access and search facilities for notes. It can integrate with Denote. Thanks to Colin McLear for the change in pull request 70 on the GitHub mirror:

    [ The change is below the ~15 line threshold and thus does not require copyright assignment to the Free Software Foundation. ]

Internal restructuring

  • All Denote code is consolidated in denote.el. We no longer maintain separate files like denote-link.el, denote-dired.el, etc. Users who had require calls to such libraries must remove them and only keep:

    (require 'denote)
  • User options that have an entry in the manual will now provide a link to it via their Help buffer and/or the Custom UI. This is done by adding the :link attribute to their declaration.

    Furthermore, user options and faces now specify the version of Denote that last affected their value (e.g. denote-directory, which was mentioned above for the XDG spec, now informs the user that it changed for version 0.5.0).

    [ I learnt these by developing the modus-themes. ]

  • The variables denote-last-title, denote-last-keywords, denote-last-buffer, and denote-last-front-matter are all obsolete. These were used prior to version 0.1.0 to help with development but are now deemed surplus to requirements.

  • Lots of changes were made to private functions, variables, doc strings, and comments, in the interest of simplifying the code and/or ensuring consistency in how operations are carried out. Though everything is the same for the end-user.

Thanks to Jean-Philippe Gagné Guay for the numerous contributions on the GitHub mirror. They are important for Denote, though the user does not need to know what is happening internally (consult the Git log for the details):


Encrypting Denote notes

Paul van Gelder asked about this on the mailing list. I provided guidelines on what can be done, though did not record anything in the manual: I prefer to elicit more feedback from users. The gist is that Emacs already has all the requisite functionality, though encryption per se is outside the scope of Denote:

Denote’s relevant internal mechanisms will recognise files ending in .gpg (e.g. for fontification in Dired).

Visualise usage of Denote keywords

Peter Prevos shared a proof-of-concept way to visualise keywords in the denote-directory and show usage statistics:

We do not include this information in the manual, as we wait for the fully fledged code. Though do give it a try if you are interested and, perhaps, share your thoughts for Peter’s consideration.

Conflict between denote-dired-mode and diredfl-mode

Hilde Rhyne shared a workaround they have to disable diredfl-mode in the buffers where denote-dired-mode is enabled. The conflict between the two is a known issue that is acknowledged in the manual:

I think we need a proper solution in the code we provide, so this workaround is not mentioned in the manual.

Why doesn’t Denote provide a search facility?

There was a discussion started by Fourchaux, with the participation of basaran and Andre0991 on the GitHub mirror:

The gist of my answer is that Denote does not need to provide such a facility because notes are ordinary files: whatever the user already has for them should apply to Denote. If the user has nothing to search through files, they anyhow need something that works outside the confines of Denote: a denote-SEARCH command is not an adequate solution.

Emacs has numerous built-in commands, such as grep (lgrep and rgrep), project-find-regexp, find-grep-dired, ibuffer-do-occur, … Furthermore, there are lots of high quality packages that have their own wrappers or extensions for searching file contents, such as the ivy and helm completion frameworks, as well as consult (the commands consult-grep and consult-ripgrep), consult-notes, rg, deadgrep, deft, and probably plenty more that do not come to mind right now.

I strongly encourage the user to find a universal search solution to the problem of searching file contents.

-1:-- Emacs: denote version 0.5.0 (Post)--L0--C0--August 10, 2022 12:00 AM

Irreal: A Graduate Student Research Workflow

Koustuv Sinha is a PhD student in machine learning and natural language processing. Because much of his time is devoted to reading research papers in his field, he’s devoted significant effort into optimizing his workflow.

The TL;DR is that he’s used Emacs and Org-mode to develop an efficient method of discovering and curating interesting papers. It starts with the discovery. For this he uses Elfeed to subscribe to various Arxiv feeds in his areas of interest. He uses the elfeed-score package to rank these papers in the approximate order of his interest in them.

When he reads an abstract in the Elfeed results that seems interesting, he fires off a process that captures the paper’s metadata to his bibliography file; grabs a copy of the paper, renaming it to the bibtext key, and storing it in a central repository; and adds it to an Org file listing the papers we wants to read.

A lot of this is accomplished by leveraging John Kitchin’s org-ref. He calls org-ref functions directly to get and store the paper’s data. It’s a nice example of reusing someone else’s codebase in your own.

Sinha provides a huge number of details in his post so be sure to take a look. If you have similar needs, this is an excellent starting point for your own workflow or even something worth stealing wholesale.

-1:-- A Graduate Student Research Workflow (Post jcs)--L0--C0--August 08, 2022 04:12 PM

Marcin Borkowski: Copying the current location revisited

Some time ago I wrote about a snippet of Elisp for copying my current location. I’ve been using that snippet all the time, and soon I discovered two of its limitations.
-1:-- Copying the current location revisited (Post)--L0--C0--August 08, 2022 03:56 PM

Sacha Chua: 2022-08-08 Emacs news

Links from, r/orgmode, r/spacemacs, r/planetemacs, Hacker News,,, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for links!

-1:-- 2022-08-08 Emacs news (Post Sacha Chua)--L0--C0--August 08, 2022 03:50 PM

Manuel Uberti: Ugrep in Emacs

Almost a year ago I wrote about my handy mu-recursive-grep, an easy way to combine rgrep and vc-git-grep. But after Leah Neukirchen mentioned ugrep recently, I could not resist checking whether it was a good fit for my daily Emacs usage. A couple of benchmark (see 54608#14 and 54608#20) impressed me enough to add support for it directly via xref-search-program-alist.

The details to configure everything you need are over at Using ugrep within Emacs on the project README. Once set, you can just hit C-x p g (project-find-regexp) in your project and let ugrep do his magic.

Moreover, as the README mentions, it’s possible to leverage grep-template to have commands like lgrep rely on ugrep.

(setq-default grep-template (string-join '("ugrep"
                                         " "))

Thus, mu-recursive-grep becomes a bit simpler:

(defun mu-recursive-grep (search-term search-path)
  "Recursively search for SEARCH-TERM in SEARCH-PATH."
     (unless grep-command
     (let ((search-term (grep-read-regexp))
           (search-path (expand-file-name
                          "Directory: " nil default-directory t))))
       (list search-term search-path))))
  (lgrep search-term "*" search-path))

As mentioned in Grep’s good rep, for project-wide searches C-x p g is my go-to key binding. However, there are situations when I want to limit the search to specific paths, and that’s where I prefer using mu-recursive-grep.

A closing remark: before blindly leaving grep, ripgrep, or even vc-git-grep behind, I suggest to benchmark the performance of each tool and see what actually suits you best. You may find that whatever you are using at the moment is already the best choice.

-1:-- Ugrep in Emacs (Post)--L0--C0--August 07, 2022 12:00 AM

FrostyX: Emacs - Evil :set option

Do you miss all the easy-to-use :set commands from Vim? You know, :set wrap, :set number, :set colorcolumn, :set expandtab, etc.

Narcissistic rant

Even though the Evil project itself doesn’t claim any such title, urban legends say that Evil is the best Vim emulator ever implemented. Naturally, my expectations were high. And yet, I was blown away. Evil does everything perfectly (or at least well enough to fool me) - modes, macros, window management, plugins, colon commands (although not all of them are implemented - I am looking at you :retab).

For me, the only major letdown was missing support for :set options such as :set wrap, :set number, and so on. Of course, Emacs has its own commands for achieving the same behavior. My issue is simply the non-existing:set command and, therefore, inability to use the options that I already know.

Introducing evil-set-option

For this reason, I created evil-set-option.

Click, it's a gif!


Use Quelpa (or any package manager that you prefer) to install the package.

(use-package evil-set-option
  :ensure t
  :quelpa (evil-set-option
           :fetcher github
           :repo "FrostyX/evil-set-option"
           :branch "main")

And now you can run your favorite :set commands.

:set wrap
:set number
:set colorcolumn=80

Supported options

Currently, only a dozen of options that seemed to be the most popular, are supported. Vim comes with hundreds of options, and for understandable reasons, I wasn’t going to implement all of them within the first release. Please let me know what are your favorite options that we simply must have.

The list of all currently supported options can be found here.

Custom option behavior

Sometimes the default implementation of an option might not be applicable. You might want to use a different mode that suits your build more, you might run an older version of Emacs, that doesn’t support some modes, etc. In such cases, you can override the default implementation.

;; The default implementation for `:set number' uses
;; `display-line-numbers-mode' which is available since Emacs 26.
;; See
;; You can override it to use `linum-mode' instead

(defun evil-set-option-number (value)
  (linum-mode (if value 1 0)))

Future plans

I have a bigger picture in mind. The evil-set-option package won’t get bloated with another functionality apart from supporting more and more options. My plan is to create a new package called evil-vimrc that will provide the ability to parse a .vimrc file - although very naively. VimL is a full-featured scripting language and it would require executing the config file code to parse the options accurately. I don’t think that would be time worth spending. A dummy implementation that parses all set statements is still going to be useful in many cases.

The hypothetical usage will look like this

(evil-vimrc-load "~/.vimrc")

And the ~/.vimrc as expected.

set nocompatible
set nowrap
set title
set expandtab

Or alternativelly, defining the .vimrc configuration within Emacs Lisp.

 (:set nocompatible)
 (:set nowrap)
 (:set title)
 (:set expandtab))

Stay tuned.

-1:-- Emacs - Evil :set option (Post)--L0--C0--August 07, 2022 12:00 AM

Irreal: Org-mode Versus Jupyter Notebook

John D. Cook, a consulting mathematician, who runs the TeX and Typography Twitter feed as well as several similar—mostly mathematically focused—feeds has two posts that consider using Org-mode instead of Jupyter Notebook. It’s interesting because it comes from someone who is neither a developer nor a dedicated Org user.

The first post considers Org-mode as a light weight Jupyter Notebook. It stresses how easy it is to mix text, LaTeX markup, code, and the results of running that code in a single file. That’s a real win if you’re trying to do reproducible research or simply trying to simplify your workflow. Since everything is text, it’s easy to integrate it into your version control system.

The second post is reminiscent of Mike Hamrick’s video of using Org and Org Babel to create documents that automatically maintain their consistency as parameters change. Cook’s post covers exactly that: how to specify parameters separately from their use in order to maintain consistency as things change.

If you’re a hardcore Emacs/Org user or even a long time Irreal reader, none of this will be new to you but it’s a really excellent introduction to one tiny aspect of Org’s power. It’s definitely worth your while if you’re new to this aspect of Org-mode.

-1:-- Org-mode Versus Jupyter Notebook (Post jcs)--L0--C0--August 06, 2022 04:49 PM

Daniils Petrovs: Implementing a local ETag cache system in Go

While I was developing a small CLI in Go that made HTTP requests to an API, I encountered a small optimization: the API used ETags to cache resource request responses. Of course, it does not make sense to always requests the entire resource anew, so just like a browser client, we should:

  1. Make a request
  2. Save the ETag and the corresponding response payload
  3. If we make a request again to the same resource, include the ETag
  4. If the response is not_modified, then we can just return the cached response with confidence, otherwise we return the response and cache it

So let’s see how this can be done in one small file and how it can be integrated with net/http.

Creating the cache system

Defining the object store

Since Go has really great facilities for serialization/deserialization of data structures, we will go ahead and define a struct for storing two things:

  • The ETag
  • The response payload
type Cache struct {
	Etag string `json:"etag"`
	Data interface{} `json:"data"`

Implementing the helpers

A typical cache system needs only a few basic functions:

  • Init (create and setup the cache system on the host)
  • Get (get a cache entry by key)
  • Save (save a cache entry by key)
  • Purge (manually purge the entire cache and reset it)
// Initialize ETag based cache system
func Init() {
	os.Mkdir(CacheDir(), 0770)

// Purge all cache entries manually by deleting all ETag files
func Purge() {
	fmt.Println("Purging cache...")

// Try to get a cache entry. Returns empty cache and falsy if does not exist, otherwise truthy.
func Get(key string) (Cache, bool) {
	file, err := os.OpenFile(filepath.Join(CacheDir(), key), os.O_RDONLY, 0666)
	defer file.Close()
	if errors.Is(err, os.ErrNotExist) {
		return Cache{}, false

	bytes, _ := ioutil.ReadAll(file)
	var cache Cache
	json.Unmarshal(bytes, &cache)
	return cache, true

// Save data under a SHA1 key hash, with an ETag and raw data
func Save(key, etag string, raw []byte) error {
	var data interface{}
	json.Unmarshal(raw, &data)
	cache := Cache{etag, data}

	cacheData, err := json.Marshal(cache)
	if err != nil {
		return err

	err = ioutil.WriteFile(filepath.Join(CacheDir(), key), cacheData, 0666)
	if err != nil {
		return err

	return nil

And that is it! The way we identify unique resources in the HTTP client is by passing the request path into a hashing function like SHA1, and then saving the cache files using it as the file name, then looking it up later.

You can see a full example in action here.

-1:-- Implementing a local ETag cache system in Go (Post Daniils Petrovs)--L0--C0--August 06, 2022 04:40 PM

John D. Cook: Naming probability functions

Given a random variable X, you often want to compute the probability that X will take on a value less than x or greater than x. Define the functions

FX(x) = Prob(Xx)


GX(x) = Prob(X > x)

What do you call F and G? I tend to call them the CDF (cumulative distribution function) and CCDF (complementary cumulative distribution function) but conventions vary.

The names of software functions to compute these two functions can be confusing. For example, Python (SciPy) uses the names cdf and sf (the latter for “survival function”) while the R functions to compute the CDF take an optional argument to return the CCDF instead [1].

In the Emacs calculator, the function ltpn computes the CDF. At first glace I thought this was horribly cryptic. It’s actually a very nice naming convention; it just wasn’t what I was expecting.

The “ltp” stands for lower tail probability and “n” stands for normal. The complementary probability function is utpn where “utp” stands for upper tail probability. Unlike other software libraries, Emacs gives symmetric names to these two symmetrically related functions.

“Lower tail” probability is clearer than “cumulative” probability because it leaves no doubt whether you’re accumulating from the left or the right.

You can replace the “n” at the end of ltpn and utpn with the first letters of binomial, chi-square, t, F, and Poisson to get the corresponding functions for these distributions. For example, utpt gives the upper tail probability for the Student t distribution [2].

The Emacs calculator can be quirky, but props to the developers for choosing good names for the probability functions.

Related posts

[1] Incidentally, the CCDF cannot always be computed by simply computing the CDF first and subtracting the value from 1. In theory this is possible, but not in floating point practice. See the discussion of erf and erfc in this post for an explanation.

[2] These names are very short and only a handful of distribution families are supported. But that’s fine in context. The reason to use the Emacs calculator is to do a quick calculation without having to leave Emacs, not to develop production quality statistical software.

The post Naming probability functions first appeared on John D. Cook.
-1:-- Naming probability functions (Post John)--L0--C0--August 05, 2022 02:09 PM

Eric MacAdie: 2022-08 Austin Emacs Meetup

There was another meeting a couple of days ago of EmacsATX, the Austin Emacs Meetup group. For this meeting there was no predetermined topic.

I will tell you up front there was a lot of talk about Doom and running Emacs on Windows, neither of which interest me. Then again, you can get Emacs to do anything you want, so this may interest you.

#1 was one of the organizers, and is active in the Austin Clojure group.

#2 was a developer in the Dallas-Fort Worth area. He tends to talk quite a bit. Kind of like our non-professor developer in OKC. Now that I think about it, I don’t those two have ever been at the same meeting. Coincidence? I think not.

#3 was one of the organizers, formerly worked for the City of Austin. Now your complaints must be taken elsewhere. He did not say much while I was on the call.

#4 had just come back from Europe, and is a developer in Austin. Everyone else seemed to know him, but I did not recognize his face, his voice or his handle. At one point he made a comment that he got a programming job “off the street”. I do not know if that means he scraped by getting a CS degree, or if he was in a non-STEM related field and decided to do something different with his life.

I called in a bit late. #1 was sharing his screen and trying to get emacsclient working on his Mac.

Then #2 and #4 talked about getting Emacs working on Windows with Windows Subsystem for Linux. If you can use Emacs, then you should have no problem with Linux. And why not just run straight Linux? I do not like MS, and I do not trust MS. I got a mini from System 76 with PopOS pre-installed, and it works flawlessly. MS might consider people running Linux to be a problem; I think that is the solution. WSL might be solving a problem MS has, it is not solving a problem I have. Maybe the guy is a hardcore gamer. Still, I think most developers can shell out enough cash for another system. I would never want to discourage people from running Emacs, but it looks like #2 and I see some things differently. (Perhaps that is inevitable with something as customizable as Emacs.)

Granted, he has a job where he uses Emacs all day, so he is doing something right. #2 also mentioned they recently converted a few vim users to Doom Emacs, and one of them said it changed their life.

#2 said running Doom Emacs on Windows was difficult. Apparently Doom uses some C libraries that are not available on Windows. I have no interest in Doom, so I did not ask for details. Later #2 mentioned that he was able to run Doom with multiple profiles without using Chemacs. I would not be surprised if multiple profiles becomes a feature in future versions of Emacs.

#2 also mentioned MS Powertoys. At first I thought he was being facetious and making fun of something called “Power Tools”, but I checked, and, no, it is actually called PowerToys. The jokes write themselves. The page on MS’s site describes PowerToys as “Utilities to customize Windows”. Unfortunately, MSPT would not let #2 make the adjustment he REALLY wanted to make, which sounds like Peak Microsoft.

#4 said they use Emacs for Ruby and Go, and that led to several minutes of people offering their opinions on Go. I have tried it out a bit, and constantly checking if something is nil gets old fast. #4 had heard people say bad things about it, but when he tried it he liked it. #2 and #4 both use Doom, and like #1 use Emacs for Clojure.

#2 mentioned that a recent change in Emacs resolved the “long lines” issue. I think he might be referring to so-long, which was mentioned on Mastering Emacs (also see EmacsWiki page, ELPA page, Savannah page and source page).

The last topic was Brushes With Greatness. #2 had a talk with Simon Peyton Jones at Strange Loop where SPJ gave a talk on “Shaping our children’s education in computing“. #2 mentioned a few things about Haskell that he did not like, and realized it was a mistake. SPJ was not a jerk, and he actually seemed interested in making Haskell better and hearing what #2 had to say, but he was asking questions at a level of detail that #2 was not able to answer.

#1 talked with Rich Hickey at ClojureConj a few years ago. RH uses a minimal setup: Just paredit (see pages on EmacsWiki and WikiEmacs) and Inferior Lisp mode. #1 asked RH if he did any web development, and RH said that he thought web development was too complicated. #1 and #2 thought it was interesting that some big names in development who work on some important projects have some of the simplest setups.

I give people numbers since I do not know if they want their names in this write-up. Think of it as the stoner’s version of the Chatham House Rule. I figured that numbers are a little clearer than “someone said this, and someone else said that, and a third person said something else”. People’s numbers are based on the order they are listed on the call screen, and the same person may be referred to by different numbers in different months.

Image from Harley MS 5647, an 11th century manuscript housed at the British Library, assumed to be under public domain.

-1:-- 2022-08 Austin Emacs Meetup (Post Eric MacAdie)--L0--C0--August 05, 2022 08:10 AM

Irreal: Mickey on Evaluating Elisp

Mickey from Mastering Emacs has an excellent post on the various ways of evaluating Elisp in Emacs. As Mickey says, there are several ways of doing it depending on the context and it pays to be familiar with them all.

The most familiar way is probably eval-last-sexp (Ctrl+x Ctrl+e). It’s really useful because it will evaluate almost anything: s-expressions (of course) but also numbers, strings, and most special forms. The situation for special forms has improved a bit in Emacs 28 so be sure to take a look at Mickey’s post to get the details.

There’s also eval-buffer and eval-region, which do as their names suggest. These commands generally don’t evaluate special forms such as devar, defface, and defcustom. That’s generally what you want so it’s a feature instead of a bug. Again, see the post for the details.

The method that I always tend to forget about is eval-defun, bound to Ctrl+Meta+x. It’s especially handy for evaluating functions because, unlike eval-last-sexp, you can call it from anywhere within the function instead of needing to be at the end. If you call it with the universal argument, it will turn on debugging for the function. It’s worth reading Mickey’s article just for the section on this command.

Finally, there’s Eshell and IELM. Most Eshell users know you can evaluate many Elisp expressions there but when you want a real Elisp REPL, IELM is what you want. It’s perfect for experimenting with code that’s longer than a single expression. I use it fairly often and love it.

Like all of Mickey’s posts, this one is definitely worth your time and effort.

-1:-- Mickey on Evaluating Elisp (Post jcs)--L0--C0--August 04, 2022 06:07 PM

jao: inline snippets and grouping in consult-recoll

I've just released a new version of consult-recoll, which implements a couple of features that i am really liking, namely, grouping of search results by mime type:


and inline snippets:


Happy searches!

-1:-- inline snippets and grouping in consult-recoll (Post)--L0--C0--August 04, 2022 05:29 PM

John Herrlin: Emacs on Macos Monterey

Intro Got a new computer from work, this is some quick notes on how my Emacs setup looks. Run Emacs as daemon with LaunchAgent. Fetch mails periodically with mbsync via LaunchAgent. Install brew install --cask emacs brew install mu brew install isync brew install gpg brew ls --verbose emacs brew ls --verbose mu Mu4a Replace USERNAME with your info. mkdir -p ~/.mail/work ~/.mail/gmail mu init --maildir=~/.mail mu index mbsync -Va mu index Mbsync config cat ~/.
-1:-- Emacs on Macos Monterey (Post)--L0--C0--August 04, 2022 06:15 AM

Emacs Notes: Create an `Excel’ / `LibreOffice Calc’ Spreadsheet from an `Org’ spreadsheet

Introduction: A word about Org mode‘s spreadsheet capabilities Power users of Emacs Org mode swear by its Spreadsheet capabilities. I know of dons in universities who use the feature to score their students in exams. This example in the Org Reference Manual suggests how one may prepare mark cards with Org spreadsheets. As far as … Continue reading Create an `Excel’ / `LibreOffice Calc’ Spreadsheet from an `Org’ spreadsheet
-1:-- Create an `Excel’ / `LibreOffice Calc’ Spreadsheet from an `Org’ spreadsheet (Post Emacks)--L0--C0--August 04, 2022 05:51 AM

Protesilaos Stavrou: The case of git-gutter, the modus-themes, and Doom Emacs

The git-gutter package (and its git-gutter-fringe extension) highlights in the margin or fringe of the window the status of affected version-controlled lines. By default, git-gutter uses a colour-coded background, such as green for additions, together with the character or bitmap of an appropriate sign, like the + for added lines.

When I test git-gutter in my capacity as the maintainer of the modus-themes for the purposes of supporting the faces it defines, I use what the upstream source provides. As such, I apply a combination of background and foreground that works the way the original package intends to. I add a colour-coded background and the correct foreground (black for modus-operandi, white for modus-vivendi). As a result, the modus-themes work as intended with git-gutter and git-gutter-fringe.

[ Colour-coding is influenced by modus-themes-deuteranopia for those who need to opt-in to it. ]

Doom Emacs, the popular configuration of our favourite computing environment, uses git-gutter (git-gutter-fringe) by default. However, it is effectively running a soft fork of the package, as it introduces changes which refashion its appearance; changes which were not anticipated upstream and, consequently, could not have been foreseen by theme developers. Doom Emacs adds its own custom bitmaps, which replace those signs with contiguous lines.

;; Copied from Doom Emacs (commit 55544200b)

;; places the git gutter outside the margins.
(setq-default fringes-outside-margins t)

;; thin fringe bitmaps
(define-fringe-bitmap 'git-gutter-fr:added [224]
  nil nil '(center repeated))
(define-fringe-bitmap 'git-gutter-fr:modified [224]
  nil nil '(center repeated))
(define-fringe-bitmap 'git-gutter-fr:deleted [128 192 224 240]
  nil nil 'bottom)

Sample of the original bitmap, as seen in git-gutter-fringe.el:

(fringe-helper-define 'git-gutter-fr:added nil

Taken in a vacuum, I like the visuals of this change: I prefer to have a contiguous, colour-coded line that has no symbols or other embellishments. It is how the diff-hl package that I use looks with one minor tweak to a relevant user option. However, Doom’s otherwise innocuous modifications have a negative effect on themes that are not designed specifically for Doom Emacs. What once was a plus sign with a black/white foreground now turns into a straight line that either covers or is adjacent to the standard colour-coded background.

2022-08-04-doom-modus-git-gutter.png sample

In other words, Doom breaks the modus-themes. There is nothing we can do about it because its soft fork of git-gutter is not a standalone package with the appropriate points of entry that we could configure.

This has been known for a while now. The manual of the modus-themes, informs users of Doom Emacs about the problem and what they can do to fix it using local tweaks: Excerpt with just the code, while the docs explain the details:

(defun my-modus-themes-custom-faces ()
     ;; Replace green with blue if you use `modus-themes-deuteranopia'.
     `(git-gutter-fr:added ((,class :foreground ,green-fringe-bg)))
     `(git-gutter-fr:deleted ((,class :foreground ,red-fringe-bg)))
     `(git-gutter-fr:modified ((,class :foreground ,yellow-fringe-bg))))))

(add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-custom-faces)

The user evaluates this code and then re-loads the theme for changes to take effect. An unpleasant experience for what ought to just work. What the code does is remove the black/white foreground and replace it with the same colour as the background. We cannot have such code in the themes because it breaks standard git-gutter (technically, it is git-gutter-fringe which is specifically for the fringes, but the point is the same).

Looking at the code of git-gutter, we have user options like this one:

(defcustom git-gutter:added-sign "+"
  "Added sign."
  :type 'string
  :group 'git-gutter)

Instead of dirty hacks, we can have a contiguous colour-coded presentation by replacing the character with an empty space:

(setq git-gutter:added-sign " ")

No need to use the fringes. This works for all users and with all themes that cover git-gutter. You get the idea.

Good citizenship and responsibility

I am a proponent of community building. Emacs is a fairly small space and we all know each other, more or less. As package maintainers, we contribute to the wellness of the community by writing code that does not have a negative impact on third parties; code which has a clear scope, conforms with the principle of least surprise, and can be integrated in wider workflows. Put simply, when our code breaks stuff elsewhere, we fix our code.

This is not about the technicalities of the intersection between the modus-themes, git-gutter, and Doom Emacs. Every maintainer has a responsibility towards the community.

Doom Emacs happens to be a very popular choice, especially for new users who are not yet familiar with all the minutiae of Emacs. When a soft fork breaks my package, I get to deal with the problem even though my package works correctly. This is not nice and it detracts from my other projects.

[ I keep calling the modus-themes “my package” though note that it is built into Emacs. The soft fork thus breaks standard Emacs. ]

I feel disempowered because even though I want to help users get the best experience out-of-the-box, I cannot do anything more than write documentation about the issue and hope for the best. I do that, yet I keep getting emails about it…

The manual is not the right place to fix bugs. It is there to inform the user about how to set up the package, what the customisation options are, and, for the more adventurous, provide guidance on possible do-it-yourself extensions.

Soft forks are quasi-proprietary in practice, as they are not publicly available for me as a third party to interface with them using standard mechanisms (i.e. not ad-hoc arrangements). I cannot maintain dirty hacks to accommodate soft forks: it debases the quality of my package and makes it harder to maintain it. Besides, makeshift solutions of this sort have no place in emacs.git, where I push my themes after every tagged release (I did so yesterday for version 2.5.0).

I strongly encourage maintainers of soft forks, such as Doom Emacs in this case, to upstream their changes or, at the very least, subject their feature to an opt-in toggle so that the user is informed about the matter.

More broadly, each of us must consider that there exists a wider community outside our particular milieu which is affected by our decisions. It is our duty to keep this place pleasant. The more influential and widely-used the code is, the greater the concomitant responsibility.

Why am I not reporting this in the Doom repo? Because (1) I am not a user and (2) this is not about Doom Emacs per se. It is an opportunity for me to address a general topic and raise awareness about it. Keeping the information limited to an issue tracker does not help in this regard.

Finally, a note for users who copy snippets without considering the implications: if something looks broken, consider the possibility that your custom code is the cause of it. When reporting issues, make your customisations explicit, otherwise you are unintentionally spreading misinformation.

-1:-- The case of git-gutter, the modus-themes, and Doom Emacs (Post)--L0--C0--August 04, 2022 12:00 AM

Alvaro Ramirez: Emacs freebie: macOS emoji picker

03 August 2022 Emacs freebie: macOS emoji picker

I recently ran a little experiment to bring macOS's long-press-accents-like behavior to Emacs. What I forgot to mention is that macOS's character viewer just works from our beloved editor.

If you have a newer MacBook model, you can press the 🌐 key to summon the emoji picker (character viewer). You may need to set this key binding from macOS keyboard preferences.

I'm happy to take this Emacs freebie, kthxbye.



  • Like other macOS apps, this dialog can be invoked via control-command-space (thanks mtndewforbreakfast). Note: you'd lose this ability if you (setq mac-command-modifier 'meta) in your config.
  • The 🌐 key is a feature on newer MacBook hardware and likely needs configuration (thanks Fabbi-).
-1:-- Emacs freebie: macOS emoji picker (Post)--L0--C0--August 03, 2022 09:45 PM

John D. Cook: Inline computed content in org-mode

The previous post discussed how to use org-mode as a notebook. You can have blocks of code and blocks of results, analogous to cells in a Jupyter notebook. The code and the results export as obvious blocks when you export the org file to another format, such as LaTeX or HTML. And that’s fine for a notebook.

Now suppose you want to do something more subtle. You want to splice in the result of a computed value without being obvious about it. Maybe you want to compute a value rather than directly enter it so that the document will remain consistent. Maybe you have a template and you want to set the parameters of the template at the top of the file.

Web development languages like PHP do this well. You can write a PHP file that is essentially an HTML file with pieces of code spliced in. You do this my inserting

    <?php … ?>

into the HTML code, and when the page is rendered the code between the <?php and ?> tags is replaced with the result of executing the code. We’d like to do something analogous in org-mode with org-babel. (org-babel is the subsystem of org-mode that interacts with code.)

Here’s an org-mode example that sets length and width as variables at the top of a file and multiplies them later in the body of the file to get area.

We define our variables as follows. The block is marked :exports none because we do not want to display the code or the values. We just want the code to run when we export the file.

    #+begin_src python :session :exports none
    length, width = 7, 13

The following almost does what we want [1].

    Area equals src_python[:session]{length*width}.

This renders as

Area equals 91.

if we export our org file to HTML The number 91 is typeset differently than the words before it. This would be more obvious if the computed value were a string rather than a number.

Org-mode is wrapping <code> tags around the computed result. If we were to export the org file to LaTeX it would wrap the result with \texttt{}. This is because, by default, the output of a computation is displayed as computer output, which is conventionally set in a monospace font like Courier. That’s fine in a technical document when we want to make it obvious that a calculation is a calculation, but typically not in a business context. You wouldn’t want, for example, to generate a letter that starts

Dear Michael,

with Michael’s name set in Courier, announcing that this is a form letter.

The fix is to add :results raw to the header session, the part in square brackets between src_python and the Python code.

    Area equals src_python[:session :results raw]{length*width}.

Now the calculation result is reported “raw”, i.e. without any special markup surrounding it.


[1] In this example I’m using Python, and so I used the function src_python. org-babel supports dozens of languages, and each has its src_<language> counterpart.

The post Inline computed content in org-mode first appeared on John D. Cook.
-1:-- Inline computed content in org-mode (Post John)--L0--C0--August 03, 2022 01:05 PM

TAONAW - Emacs: Of Grep and Finding Stuff

I can make a safe assumption that 90% of the people reading this blog know how to use grep, at least on a basic level. But what about those of us who don’t? Here’s a quick look into grep and grep in Emacs specifically. Before we dive in there’s a bit of a realization I want to expend on in the footnotes though1.

Back? Good.

The classic scenario: use Dired to get into a directory, and then use grep and its various siblings to search for a text pattern in all the files in that directory.

M-x grep will automatically call grep --color -nH --null -e. This works with the syntax like so: grep --color -nH --null -e "<pattern to match>" <file pattern>.

For example, I can search for “burger” in a folder with old org files that are no longer indexed in org-agenda2 by calling grep and using it like so: grep --color -nH --null -e "burger" *.org. This will give me a list of all the files along with a blurb of text (showing the results in context) with the word burger highlighted.

This command also works for two terms, in the form of term1 or term2, like so: grep --color -nH -e "burger" -e "restaurant" *org. It will show us burger or restaurant, but not burger and restaurant. So if I want to search for restaurants that served me with a juicy burger some years back, I’m out of luck: grep will bring up all occurrences of restaurants and /all occurrences of burger.

In shell, we can pipe one grep into another: grep burger *.org | grep restaurant is all that’s needed to give us basic results. In Emacs, however, we can’t pipe grep like we do in shell3. We can call shell in Emacs (with M-!) and execute this in the folder we’re in, or just run Shell from inside Emacs, but there are quicker ways.

Occur (M-s O)4 will search for regex strings in the active buffer on the screen by default. This means that if you just preformed a grep search and got results for one term, I can use Occur on the results for the second term.

To use the example above, I will first call grep --color -nH --null -e "restaurant" *.org, and then use Occur on the results to look for “burger” (without the quotations). Since I use Swiper, part of Abo-abo’s must-have Ivy package, I could run a simple search (C-s) on those results and apply another filter, like “black bean5” because I barely eat any meat burgers anymore. I rarely need to apply a third filter like, and if I ever need to apply a fourth, it’s probably better to just change my search tragedy.

This post and much of what I’ve learned about grep in Emacs is thanks to the awesome folks over at Mastodon. Check the original thread here.


Reply to this post on Mastodon,Twitter, or you can always email me: taonaw<at>protonmail<dot>ch (for GPG, click the lock icon on the navbar to the left).


  1. After going over this post, I realize it starts somewhere in the middle. There are people who don’t know what grep is, and, lacking the right questions to find information about it, they will have hard time learning about this command. Consider, for example, a person who’s coming from their Mac’s spotlight feature which indexes everything for them. It’s a stretch enough for them to use the terminal, but even then, what are they actually looking for? The terms “Words” and “text” are so rudimentary to us that they might omit searching for those. A user who’s new to Linux might search for “how to find stuff in Linux” or “how to find documents” or “how to find what I wrote” before they search for “how to find text in Linux,” which is still a bit of a stretch.

    The Emacs manual throws this question back at the user: “Just as you can run a compiler from Emacs and then visit the lines where there were compilation errors, you can also run grep and then visit the lines on which matches were found. This works by treating the matches reported by grep as if they were “errors."” What does that even mean?

    I look at my post now, and I think, I know this today, I know what to ask today, how would I know to ask this not even 5 years ago? Where do I even start? ↩︎

  2. For those who don’t use org-mode: org-mode comes with a powerful built-in “search engine”, the agenda. It loads a list of folder and files when Emacs starts, so you can execute various function on them like scheduling tasks or assign tags. The agenda dispatcher comes with powerful search options that let you search by date, keyword, tags, etc. ↩︎

  3. I’m still learning more about this, and I’m not sure why, but I think it’s because the | character is not a special character in Emacs, so grep grabs it literally and looks for the pipe character in the text. ↩︎

  4. Occur has its on various siblings in Emacs and can be largely used in the same exact way as grep, though there are differences. It’s worth taking a look if you’re not familiar with it. ↩︎

  5. This double space is not a mistake. In Swiper search, double space is how you ask to look for space. ↩︎

-1:-- Of Grep and Finding Stuff (Post)--L0--C0--August 03, 2022 12:00 AM

Protesilaos Stavrou: Modus themes 2.5.0 for GNU Emacs

I just published the latest stable release of the Modus themes. The change log entry is reproduced below. For any questions, feel welcome to contact me.

I will now prepare the patch for emacs.git which will then trickle down to GNU ELPA (the modus-themes is a :core package). Thank you for your patience!


This entry documents the changes made to the project since the publication of version 2.4.0 on 2022-06-01. It spans more than 60 commits to an already stable project.

The modus-operandi and modus-vivendi themes are built into Emacs-28 (latest stable release) or later, and are available on GNU ELPA as well as other archives. Emacs-28 ships version 1.6.0, while the current master branch (i.e. Emacs-29) and, by extension, GNU ELPA include the latest tagged release. The packaged version is available as modus-themes.

Read the manual inside Emacs by evaluating:

(info "(modus-themes) Top")

Or visit: (the website only documents the latest version).

Enhancement to the user option ‘modus-themes-headings’

The user option modus-themes-headings now reads a level 0 heading in addition to numbers 1–8. Heading 0 accepts the same list of properties as all other levels (please consult the doc string of the user option or the corresponding entry in the manual). Currently only the value of the Org #+title is affected (face is org-document-title), but we may cover more faces if needed.

Sample configuration:

;; The `modus-themes-headings' is an alist with lots of possible
;; combinations, including per-heading-level tweaks: read the
;; manual or its doc string.
(setq modus-themes-headings
      '((0 . (variable-pitch light (height 2.2)))
        (1 . (rainbow variable-pitch light (height 1.6)))
        (2 . (rainbow variable-pitch light (height 1.4)))
        (3 . (rainbow variable-pitch regular (height 1.3)))
        (4 . (rainbow regular (height 1.2)))
        (5 . (rainbow (height 1.1)))
        (t . (variable-pitch extrabold)))

Given this change, I am also tweaking the default foreground value of the org-document-title. It is a bit more saturated than before, but remains close to the spirit of the previous one.

Thanks to Rudolf Adamkovič for proposing the idea on the mailing list:

Stylistic tweak to the user option ‘modus-themes-syntax’

Prevented the alt-syntax property from desaturating the effect of the yellow-comments property when the two would be combined. Such as:

(setq modus-themes-syntax '(alt-syntax yellow-comments))

The previous design was incorrect because it was always using the faint variant of the yellow comments, as if the user had specified:

(setq modus-themes-syntax '(alt-syntax faint yellow-comments))

[ Read the doc string of modus-themes-syntax or the manual for an explanation of all properties and their combinations. ]

Review of the Isearch (and related) colours

Emacs’ standard search has a face for the currently matched query and all its inactive matches. The faces are isearch and lazy-highlight, respectively. Before, we were using a green background by default for the isearch face and a cyan background for the lazy-highlight. This was a choice that was made in the early days of the project when the palette was not yet fully realised.

Green and cyan do not always contrast well side-by-side (subject to hardware capabilities and environmental lighting), so the isearch face also had an added bold weight. This was not my preference, but it was necessary under the circumstances. The previous combinations were also not ideal when the user option modus-themes-deuteranopia was set to a non-nil value: the blue background which was used instead of the green one could be conflated with the subtle teal of the lazy-highlight under certain circumstances, such as poor colour reproduction at the monitor level or in terminal emulators with limited colour support.

The new colours (intense yellow for active matches and subtle cyan for lazy ones) are complementary, meaning that they are naturally easy to tell apart.

[ Read “Colour theory and techniques used in the Modus themes”: ]

These specific hues are also well-suited for users with red-green colour deficiency: yellow stays as-is, while the cyan colour becomes a bit more grey though remains distinct. As such, we do not need to run the helper function modus-themes--deuteran to set the style based on the value of modus-themes-deuteranopia.

The new colours do not clash with the style of the relevant match face (used by M-x occur, M-x grep, and related), nor with the various permutations of the region face (subject to the user option modus-themes-region).

Finally, the bold weight has been removed from the isearch face. It was always a kludge. Also, it would make paragraphs rendered in the variable-pitch face (or proportional fonts in general) jump around as the user would move between the matches, because bold letters occupy more space than their regular weight counterparts so they affect the length of the line. This problem was reported by Augusto Stoffel on the mailing list:

Rewrote parts of the colour preview commands

The modus-themes-list-colors, modus-themes-list-colors-current are commands that produce a buffer which shows previews of every entry in the palette. Their code has been simplified and they now produce a warning when the display terminal has limited colour support. Furthermore, they read any overrides as specified in the user options modus-themes-operandi-color-overrides, modus-themes-vivendi-color-overrides.

The “summertime” re-spin of colour overrides

The manual now includes a complete hand-crafted example of a pair of themes that override the default palette. This is done as a technology demonstration. It is not considered an “official” extension of the Modus themes and will never be part of the code base as it does not conform with our lofty accessibility standards. However, I took great care in picking the colour overrides in the hope that users will (i) have a usable theme, should they opt for it, and (ii) they recognise the potential of our colour-overriding feature.

Screenshots and related information:

Thanks to user “Summer Emacs” for (i) suggesting the name “summertime”, (ii) testing variants of this in her setup, and (iii) sending me feedback on possible tweaks and refinements. All errors are my own.

The idea for this project came from an exchange where Summer discovered an old theme of mine (from my pre-Emacs days) and asked if I had anything like it for Emacs. Voilà!

[ This information is shared with permission. ]

As for whether I have more plans… “Perhaps!” ;)

Removed support for certain packages or face groups

I periodically install and use the packages we support to see if they have any updates we need to cover but also to confirm that they work. Usually, the user does not learn about this work, as I don’t need to make any changes or will make some minor tweaks. When I think that the package is not in a good shape, I remove it from the list of explicitly supported packages, meaning that the modus-themes no longer cover the faces it defines. The removal of any package is done on a case-by-case basis. If you disagree with this decision, please inform me about and I shall reconsider.

  • centaur-tabs :: Those of you who have been reading these release notes are aware of a bug in centaur-tabs which basically prevents us from using the standard :inherit attribute to style the centaur-tabs faces. I have sent a patch to fix it, but have received no response since February: To me, this gives the package the “unmaintained” status, though I am happy to revert the change as soon as it gets the maintenance it needs.

    Relevant reports (and I got many others in my private inbox):

  • cursor-flash :: its default face should be visible enough.

  • dynamic-ruler :: The package does not build on my Emacs 29. Also, its default faces are usable even without our recolouring.

  • emacs-dashboard :: Its default faces inherit from basic faces that we already support.

  • frog-menu :: I have not seen this package being used anywhere. I suspect it is because it has not found a niche between transient, hydra, and embark.

  • mct :: A few months ago I announced that its development is discontinued. Either use vertico or switch to what Emacs provides as a built-in option:

  • org-treescope :: The package points to a GitHub repo, which is archived. The current source is on GitLab, but the package is not updated accordingly. This makes me believe it is not actively maintained and am thus removing it from the list.

  • paradox :: When I tried paradox, it took over my C-c g binding which I have for Magit. As an Emacs user, I consider this an unacceptable transgression. Looking at paradox’s git repo, the project is not maintained. If things change, I am happy to reinstate support for it.

  • vc-annotate (built-in) :: It has not been working properly for a long time now. Colours are unset and are not re-applied when switching between the modus-operandi and modus-vivendi themes.

    Furthermore, the way vc-annotate-color-map intersects with vc-annotate-background-mode puts us in an awkward spot: when the mode is non-nil, the mapped values are used as backgrounds WITHOUT giving us the chance to make the appropriate adjustments to the foreground (so we end up with inaccessible colour combinations). This means that we must fix a problem which is not ours by overriding the user option of the background altogether. A theme outright disabling user options is bad form.

    Even documenting a user-level set of configurations will not suffice, as the results are unreliable. I tried the code which I copy further below to test annotation with/without background, plus the change in values when switching between modus-operandi and modus-vivendi. Again, colours are not updated properly (I know the buffer of M-x vc-annotate needs to be generated again), as modus-operandi may retain the values set by modus-vivendi or vice-versa.

    Ultimately, I feel vc-annotate needs to be refactored to use ordinary faces in ordinary ways. Or, at least, not try to outsmart the user/theme about the choice of colours.

    Thanks to Philip Kaludercic for starting the thread about the vc-annotate-background-mode which reminded me about this problem:

    The code I alluded to:

    (setq vc-annotate-background-mode nil)
    (defun my-modus-themes-vc-annotate ()
      ;; Actual values are for demo purposes
        (if vc-annotate-background-mode
            (setq vc-annotate-background bg-alt
                  `((20 .  ,red-intense-bg)
                    (40 .  ,red-subtle-bg)
                    (60 .  ,red-refine-bg)
                    (80 .  ,yellow-intense-bg)
                    (100 . ,yellow-subtle-bg)
                    (120 . ,yellow-refine-bg)
                    (140 . ,magenta-intense-bg)
                    (160 . ,magenta-subtle-bg)
                    (180 . ,magenta-refine-bg)
                    (200 . ,cyan-intense-bg)
                    (220 . ,cyan-subtle-bg)
                    (240 . ,cyan-refine-bg)
                    (260 . ,green-intense-bg)
                    (280 . ,green-subtle-bg)
                    (300 . ,green-refine-bg)
                    (320 . ,blue-intense-bg)
                    (340 . ,blue-subtle-bg)
                    (360 . ,blue-refine-bg)))
          (setq vc-annotate-background nil
                `((20 . ,red)
                  (40 . ,magenta)
                  (60 . ,magenta-alt)
                  (80 . ,red-alt)
                  (100 . ,yellow)
                  (120 . ,yellow-alt)
                  (140 . ,fg-special-warm)
                  (160 . ,fg-special-mild)
                  (180 . ,green)
                  (200 . ,green-alt)
                  (220 . ,cyan-alt-other)
                  (240 . ,cyan-alt)
                  (260 . ,cyan)
                  (280 . ,fg-special-cold)
                  (300 . ,blue)
                  (320 . ,blue-alt)
                  (340 . ,blue-alt-other)
                  (360 . ,magenta-alt-other))))))
    (add-hook 'modus-themes-after-load-theme-hook #'my-modus-themes-vc-annotate)

Revised supported faces or face groups

  • Enhanced the default background colour of the current date in the Org agenda. This is a subtle change, all things considered, which makes it easier to discern where the highlight is while it remains close to the spirit of the previous design. The idea is to not add too much saturation here, because the buffer is already “busy” with lots of highlights. Thanks to Daniel Mendler for the feedback on the mailing list:

  • Restyled the M-x man and M-x woman faces to have a bit more saturation. A while ago I desaturated the Man-overstrike and woman-bold faces on the premise that the added bold weight would be sufficient. However, the bold weight may sometimes not draw the desired attention, such as at small point sizes or with certain font configurations. As such, the added intensity in colour is necessary.

  • Changed the Selectrum quick key faces (selectrum-quick-keys-match and selectrum-quick-keys-highlight) to have the same style as Avy, Vertico’s own “quick keys”, and related. For a technical analysis, read “Modus themes: case study on Avy faces and colour combinations”:

  • Made internal adjustments so that M-x list-packages inherits from the standard success, warning, and error faces instead of adding its own face attributes. In practice, the user will notice a change for new packages in the listing if modus-themes-deuteranopia is non-nil.

  • Introduced the same inheritance rules as above for the syslog package (mutatis mutandis).

  • Increased the saturation of the package-status-available face, which is shown in the M-x list-packages buffer. The overall effect is subtle, though sufficiently noticeable.

  • Revised the faces of the deft package to make it look consistent with the rest of the theme’s relevant interfaces (to the extent possible as Deft uses a non-standard presentation).

  • Aligned the speedbar-highlight-face with the user option modus-themes-intense-mouseovers.

  • Refined the highlight-thing face (see package of the same name). This makes it stand out more and it also aligns it with the standard match face, which is pertinent here.

  • Amplified the saturation of the dired-git-info face. Makes it easier to differentiate the Git commit text from the Dired listing, without drawing too much attention to itself.

  • Adjusted the hue of the easy-jekyll-help-face from teal to blue. This makes it look more like the standard help-key-binding face, although easy-jekyll does not align with upstream Emacs in this regard.

  • Intensified the background of rectangle-preview to work even in cases where a grey background is already on display. This face is used for the string-rectangle command (e.g. C-x SPC to draw a rectangle and C-t to insert text in its stead—works as a simple “multiple cursors” on a straight line).

Support for new faces or face groups

  • chart (built-in)
  • denote
  • edmacro-label (Emacs 29)
  • info+
  • leerzeichen

A comment on info+. As is the case with PACKAGE+ packages from the Emacs Wiki, info+ defines lots of faces that hardcode colour values instead of inheriting from basic faces. It does so for no good reason and the results will likely not look decent in any theme. Furthermore, these faces colourise too much even when the colour values can be appropriately combined (ceteris paribus), making the buffer harder to read.

The support I add for info+ is consistent with the design principles of the modus-themes, one of which is to avoid exaggerations as those indirectly affect legibility. As such, some of the changes I introduce here outright remove colouration, while others align the various constructs with the overall aesthetic of the themes.

Note that, by default, info+ adds clickable buttons to glossary terms. This produces awkward combinations such as by buttonising the “string” component inside of what actually is a function’s argument. So you have, say, FORMAT-[STRING] where “[]” represents the button: the FORMAT gets one face and the [STRING] another, even though they are part of a single argument. To me this looks broken and is counter-productive, though it is not up to the theme to decide how packages fontify the various constructs. At any rate, button styles at the theme level are controlled by the user option modus-themes-box-buttons.

Thanks to Jonas Collberg for the feedback in issue 33 over at the GitHub mirror:


  • Named the mailing list address as the =Maintainer:= of Denote. Together with the other package headers, they help the user find our primary sources and/or communication channels. This change conforms with work being done upstream in package.el by Philip Kaludercic. I was informed about it here:

  • Addressed byte compilation warnings in doc strings pertaining to the use of literal quotes. Thanks to Matt Armstrong and Rudolf Adamkovič for the feedback on the mailing list:

  • Fixed the :link value in the declaration of the user options modus-themes-operandi-color-overrides, modus-themes-vivendi-color-overrides. It once again directs to the correct heading in the manual.

  • Documented all the aforementioned, where necessary.

  • Mentioned my fontaine and lin packages in the relevant sections of the manual. The former helps set fonts and switch between font presents. The latter is a stylistic variant of hl-line (its documentation explains its raison d’être).

-1:-- Modus themes 2.5.0 for GNU Emacs (Post)--L0--C0--August 03, 2022 12:00 AM

Irreal: Dired-rsync

Yi Tang has an interesting post on the dired-rsync package. It’s been around for a while, apparently, but I hadn’t heard of it before Tang’s post. The TL;DR is it allows you to use rsync in dired in the same contexts that you would otherwise use Copy.

Tang lists all sorts of reasons why he believes rsync is superior to cp and scp but, oddly, doesn’t mention the major one: rsync only send the parts of the file that are different from the target. It is, in short, a tool optimized for copying an updated file.

Much of the post is devoted to explaining how Tang has integrated the package into his workflow. It’s perfect for downloading large data files from a server to his local machine where he can manipulate and analyze them. He explains how he set everything up in case you have a similar use case and want to recreate his workflow.

It’s a nice post that also explains some of the gotchas if you want to use dired-rsync yourself. It’s on Melpa and setting it up is simple. You can simply copy Tang’s use-package configuration for an excellent starting—or permanent—setup.

-1:-- Dired-rsync (Post jcs)--L0--C0--August 02, 2022 05:37 PM

John D. Cook: Org-mode as a lightweight notebook

You can think of org-mode as simply a kind of markdown, a plain text file that can be exported to fancier formats such as HTML or PDF. It’s a lot more than that, but that’s a reasonable place to start.

Org-mode also integrates with source code. You can embed code in your file and have the code and/or the result of running the code appear when you export the file to another format.

Org-mode as notebook

You can use org-mode as a notebook, something like a Jupyter notebook, but much simpler. An org file is a plain text file, and you can execute embedded code right there in your editor. You don’t need a browser, and there’s no hidden state.

Here’s an example of mixing markup and code:

    The volume of an n-sphere of radius r is 

    $$\frac{\pi^{\frac{n}{2}}}{\Gamma\left(\frac{n}{2} + 1\right)}r^n.$$

    #+begin_src python :session
    from scipy import pi
    from scipy.special import gamma

    def vol(r, n):
        return pi**(n/2)*r**n/gamma(n/2 + 1)

    vol(1, 5)

If you were to export the file to PDF, the equation for the volume of a sphere would be compiled into a image using LaTeX.

To run the code [1], put your cursor somewhere in the code block and type C-c C-c. When you do, the following lines will appear below your code.

    : 5.263789013914324

If you think of your org-mode file as primary, and you’re just inserting some code as a kind of scratch area, an advantage of org-mode is that you never leave your editor.

Jupyter notebooks

Now let’s compare that to a Jupyter notebook. Jupyter organizes everything by cells, and a cell can contain markup or code. So you could create a markup cell and enter the exact same introductory text [2].

    The volume of an n-sphere of radius r is 

    $$\frac{\pi^{\frac{n}{2}}}{\Gamma\left(\frac{n}{2} + 1\right)}r^n$$.

When you “run” the cell, the LaTeX is processed and you see the typeset expression rather than its LaTeX source. You can click on the cell to see the LaTeX code again.

Then you would enter the Python code in another cell. When you run the cell you see the result, much as in org-mode. And you could export your notebook to PDF as with org-mode.

File diff

Now suppose we make a couple small changes. We want the n and r in the comment section set in math italic, and we’d like to find the volume of a 5-sphere of radius 2 rather than radius 1. We do this, in Jupyter and in org-mode [3], by putting dollar signs around the “n” and the “r”, and we change vol(1, 5) to vol(2, 5).

Let’s run diff on the two versions of the org-mode file and on the two versions of the Jupyter notebook.

The differences in the org files are easy to spot:

    < The volume of an n-sphere of radius r is 
    > The volume of an \(n\)-sphere of radius \(r\) is 
    < vol(1, 5)
    > vol(2, 5)
    < : 5.263789013914324
    > : 168.44124844525837

However, the differences in the Jupyter files are more complicated:

    <    "id": "2a1b0bc4",
    >    "id": "a0a89fcf",
    <     "The volume of an n-sphere of radius r is \n",
    >     "The volume of an $n$-sphere of radius $r$ is \n",
    <    "execution_count": 1,
    <    "id": "888660a2",
    >    "execution_count": 2,
    >    "id": "1adcd8b1",
    <        "5.263789013914324"
    >        "168.44124844525837"
    <      "execution_count": 1,
    >      "execution_count": 2,
    <     "vol(1, 5)"
    >     "vol(2, 5)"
    <    "id": "f8d4d1b0",

There’s a lot of extra stuff in a Jupyter notebook. This is a trivial notebook, and more complex notebooks have more extra stuff. An apparently small change to the notebook can cause a large change in the underlying notebook file. This makes it difficult to track changes in a Jupyter notebook in a version control system.

Related posts

[1] Before this will work, you have to tell Emacs that Python is one of the languages you want to run inside org-mode. I have the following line in my init file to tell Emacs that I want to be able to run Python, DITAA, R, and Perl.

    (org-babel-do-load-languages 'org-babel-load-languages '((python . t) (ditaa . t) (R . t) (perl . t)))

[2] Org-mode will let you use \[ and \] to bracket LaTeX code for a displayed equation, and it will also let you use $$. Jupyter only supports the latter.

[3] In org-mode, putting dollar signs around variables sometimes works and sometimes doesn’t. And in this example, it works for the “r” but not for the “n”. This is very annoying, but it can be fixed by using \( and \) to enter and leave math mode rather than use a dollar sign for both.

The post Org-mode as a lightweight notebook first appeared on John D. Cook.
-1:-- Org-mode as a lightweight notebook (Post John)--L0--C0--August 02, 2022 02:49 PM

Zachary Kanfer: Deleting files in Emacs

"Picture your dream home. I bet it’s not filled with clutter."

Joshua Becker

When my computer is cluttered, I delete some files.

And I do that in Emacs. Because of course I do. Emacs has delete-file, but that leaves the buffer in Emacs. Why keep a buffer around if you wanted its associated file to disappear? You risk accidentally saving the buffer again, resurrecting the file. Also, any list of buffers you look at has some buffers you explicitly got rid of.

So let's kill the buffer.

kill-buffer works fine. But it's two steps: delete-file, followed by kill-buffer. And I have to remember to do both of them. Two steps is worse than one.

I wrote the following function to do everything in one step.

(defun delete-visited-file (buffer-name)  "Delete the file visited by the buffer named BUFFER-NAME."  (interactive "bDelete file visited by buffer ")  (let* ((buffer (get-buffer buffer-name))         (filename (buffer-file-name buffer)))    (when buffer      (when (and filename                 (file-exists-p filename))        (delete-file filename))      (kill-buffer buffer))))    

To use this function, add it to your config file. You can then run it with M-x delete-visited-file.

I submitted it to Emacs, but the maintainers believe it would be unpopular, so they declined it. If you use this function, please let me know.

-1:-- Deleting files in Emacs (Post)--L0--C0--August 02, 2022 05:00 AM

Sacha Chua: 2022-08-01 Emacs news

Links from, r/orgmode, r/spacemacs, r/planetemacs, Hacker News,,, YouTube, the Emacs NEWS file, Emacs Calendar, emacs-devel, and lemmy/c/emacs. Thanks to Andrés Ramírez for links!

-1:-- 2022-08-01 Emacs news (Post Sacha Chua)--L0--C0--August 01, 2022 10:40 PM

Alvaro Ramirez: dwim-shell-command video streams

01 August 2022 dwim-shell-command video streams

I continue hunting for use-cases I can migrate to dwim-shell-command… After adding clipboard support (via ) I found one more.

  1. Copy URL from browser.
  2. Invoke dwim-shell-commands-mpv-stream-clipboard-url.
  3. Enjoy picture in picture from Emacs ;)


What's the secret sauce? Very little. Invoke the awesome mpv with a wrapping function using dwim-shell-command-on-marked-files.

(defun  dwim-shell-commands-mpv-stream-clipboard-url ()
   "Stream clipboard URL using mpv."
    "mpv --geometry=30%x30%+100%+0% \"\""
    :utils  "mpv"
    :no-progress t
    :error-autofocus t
    :silent-success t))

The typical progress bar kinda got in the way, so I added a new option :no-progress to dwim-shell-command-on-marked-files, so it can be used for cases like this one.

-1:-- dwim-shell-command video streams (Post)--L0--C0--August 01, 2022 09:39 PM

Tassilo Horn: Difftastic diffing with Magit

difftastic is a structural diff tool that compares files based on their syntax. So for example, if you conditionalize some statement, the diff would only show the addition of one if with its condition instead of showing one line added (the if (condition)) and the line with the statement being removed and re-added (because of indentation changes). In many cases, such structural diffs transport the meaning of a change much better than the typical line-based diffs.

Of course, that comes with a price: difftastic has to understand the language's syntax (it currently supports these languages) and computing a structural diff is a quite expensive operation. Also, there are certain kinds of changes where a line-based diff with changed-word highlighting gives better results, namely when the changed syntactic unit is a large blob with no sub-structure, e.g., a docstring or a comment.

Git allows to use an external diff tool in many commands by setting the environment variable GIT_EXTERNAL_DIFF=<tool> and in the following I make use of that for being able to use difftastic for git show and git diff when operating on a git repository from inside Emacs using Magit. Because the aforementioned downsides, I want that as opt-in behavior, i.e., separate commands. Also, Magit has some assumptions on how a git diff looks like which are not met by difftastic, e.g., difftastic prints line numbers and generates side-by-side diffs for changes which are not plain additions or deletions.

So here we go. Let's first define a helper function which sets GIT_EXTERNAL_DIFF to difft (the difftastic binary), runs the given git command in a new process asynchronously, and pops up a buffer with the result once the process finished.

(defun th/magit--with-difftastic (buffer command)
  "Run COMMAND with GIT_EXTERNAL_DIFF=difft then show result in BUFFER."
  (let ((process-environment
         (cons (concat "GIT_EXTERNAL_DIFF=difft --width="
                       (number-to-string (frame-width)))
    ;; Clear the result buffer (we might regenerate a diff, e.g., for
    ;; the current changes in our working directory).
    (with-current-buffer buffer
      (setq buffer-read-only nil)
    ;; Now spawn a process calling the git COMMAND.
     :name (buffer-name buffer)
     :buffer buffer
     :command command
     ;; Don't query for running processes when emacs is quit.
     :noquery t
     ;; Show the result buffer once the process has finished.
     :sentinel (lambda (proc event)
                 (when (eq (process-status proc) 'exit)
                   (with-current-buffer (process-buffer proc)
                     (goto-char (point-min))
                     (ansi-color-apply-on-region (point-min) (point-max))
                     (setq buffer-read-only t)
                     ;; difftastic diffs are usually 2-column side-by-side,
                     ;; so ensure our window is wide enough.
                     (let ((width (current-column)))
                       (while (zerop (forward-line 1))
                         (setq width (max (current-column) width)))
                       ;; Add column size of fringes
                       (setq width (+ width
                                      (fringe-columns 'left)
                                      (fringe-columns 'right)))
                       (goto-char (point-min))
                        `(;; If the buffer is that wide that splitting the frame in
                          ;; two side-by-side windows would result in less than
                          ;; 80 columns left, ensure it's shown at the bottom.
                          ,(when (> 80 (- (frame-width) width))
                           . ,(min width (frame-width))))))))))))

The crucial parts of that helper function are that we "wash" the result using ansi-color-apply-on-region so that the difftastic highlighting using shell escape codes is transformed to emacs faces. Also, the needed width of the possibly wide side-by-side difftastic diff is computed and tried to be accommodated for.

Next, let's define our first command basically doing a git show for some revision which defaults to the commit or branch at point or queries the user if there's none.

(defun th/magit-show-with-difftastic (rev)
  "Show the result of \"git show REV\" with GIT_EXTERNAL_DIFF=difft."
   (list (or
          ;; If REV is given, just use it.
          (when (boundp 'rev) rev)
          ;; If not invoked with prefix arg, try to guess the REV from
          ;; point's position.
          (and (not current-prefix-arg)
               (or (magit-thing-at-point 'git-revision t)
          ;; Otherwise, query the user.
          (magit-read-branch-or-commit "Revision"))))
  (if (not rev)
      (error "No revision specified")
     (get-buffer-create (concat "*git show difftastic " rev "*"))
     (list "git" "--no-pager" "show" "--ext-diff" rev))))

And here the second command which basically does a git diff. It tries to guess what one wants to diff, e.g., when point is on the Staged changes section in a magit buffer, it will run git diff --cached to show a diff of all staged changes. If no context can be guessed, it'll query the user for a range or commit for diffing.

(defun th/magit-diff-with-difftastic (arg)
  "Show the result of \"git diff ARG\" with GIT_EXTERNAL_DIFF=difft."
   (list (or
          ;; If RANGE is given, just use it.
          (when (boundp 'range) range)
          ;; If prefix arg is given, query the user.
          (and current-prefix-arg
               (magit-diff-read-range-or-commit "Range"))
          ;; Otherwise, auto-guess based on position of point, e.g., based on
          ;; if we are in the Staged or Unstaged section.
          (pcase (magit-diff--dwim)
            ('unmerged (error "unmerged is not yet implemented"))
            ('unstaged nil)
            ('staged "--cached")
            (`(stash . ,value) (error "stash is not yet implemented"))
            (`(commit . ,value) (format "%s^..%s" value value))
            ((and range (pred stringp)) range)
            (_ (magit-diff-read-range-or-commit "Range/Commit"))))))
  (let ((name (concat "*git diff difftastic"
                      (if arg (concat " " arg) "")
     (get-buffer-create name)
     `("git" "--no-pager" "diff" "--ext-diff" ,@(when arg (list arg))))))

What's left is integrating these two new commands in Magit. For that purpose, I've created a new transient prefix for my personal commands.

(transient-define-prefix th/magit-aux-commands ()
  "My personal auxiliary magit commands."
  ["Auxiliary commands"
   ("d" "Difftastic Diff (dwim)" th/magit-diff-with-difftastic)
   ("s" "Difftastic Show" th/magit-show-with-difftastic)])

I want my personal commands transient to be bound to # and be shown in the Magit dispatch transient (which is bound to ? in Magit status buffers and C-x M-g in any Magit enabled buffer) after the Run (!) transient.

(transient-append-suffix 'magit-dispatch "!"
  '("#" "My Magit Cmds" th/magit-aux-commands))

(define-key magit-status-mode-map (kbd "#") #'th/magit-aux-commands)

And that's it!

Finally, here's a screenshot showing how it looks like:

Screenshot of Magit showing a difftastic diff
-1:-- Difftastic diffing with Magit (Post)--L0--C0--August 01, 2022 07:08 PM

Bozhidar Batsov: Clojure Tricks: Number to Digits

If you’re into programming puzzles you probably know that there’s a whole class of problems about doing something (e.g. some calculations) with the digits of a number. This means you need to break down a number into its digits first. I’ve always assumed that those problems exist just because decomposing a number to its digits is a classic example of recursion:

(defn digits [n]
  (if (< n 10)
    (conj (digits (quot n 10)) (rem n 10))))

(digits 3361346435)
;; => [3 3 6 1 3 4 6 4 3 5]

That being said, I’ve also noticed that many people are approaching the problem differently when faced with it (including me) - they typically convert the number to string and then convert back the digit characters into numbers. Probably the simplest way to do this is something like this:

(defn digits [n]
  (map #(read-string (str %)) (str n)))

(digits 3361346435)
;; => (3 3 6 1 3 4 6 4 3 5)

Notably, this solution doesn’t require using the Java interop or any clever tricks. If you know Java’s API a bit better you might think of leveraging Character/digit instead:

(defn digits [n]
  (map #(Character/digit % 10) (str n)))

Much simpler, right? Now it’s time for the final approach to solving the problem that is relatively common - namely a simple but clever trick to convert digit characters into numbers:

(defn char->int [c]
  (- (int c) 48))

(defn digits [n]
  (map char->int (str n)))

This relies on the fact that the integer value for \0 is 48, for \1 is 49 and so on. For some reason that’s my favorite solution - probably because I love programming puzzles and I like (occasionally) writing unreadable code.

So, who has a different approach for converting a number to its digits? I’ve to hear about it!

-1:-- Clojure Tricks: Number to Digits (Post Bozhidar Batsov ( 01, 2022 07:42 AM

Marcin Borkowski: Making secrets with Emacs

Let’s play with encryption! Well, not real encryption – but fun encryption. And few things are more fun than playing ciphers with kids!
-1:-- Making secrets with Emacs (Post)--L0--C0--August 01, 2022 06:35 AM

Philip K.: Using Guix Environments in Emacs using buffer-env

GNU Guix (just like Nix) can easily spawn development environments with all the necessary dependencies one may need to work on a project.

For example: In a shell session, all you would have to do is to run

$ guix shell gcc

and a new shell is launched with adjusted environmental variables, so that GCC can now be used. Likewise, you can instruct Guix to fetch the developmental dependencies, i.e. exactly what you need to build a package

$ guix shell --development gcc

As a matter of convenience, one can also specify what an environment should consist of and store that in a file. An easy way to generate such a file is using the --export-manifest option:

$ guix shell --export-manifest --development gcc > manifest.scm

On my system this generates this file:

;; What follows is a "manifest" equivalent to the command line you gave.
;; You can store it in a file that you may then pass to any 'guix' command
;; that accepts a '--manifest' (or '-m') option.
  (specification->package "gcc"))

More details on other options can be found in the manual.

This is fine, but if you use Emacs, then the shell and the editor are “inverted”, or rather Emacs performs the function of a shell (generic user interface, that wraps the kernel). To use something like guix shell, you’d have to either

  1. Start Emacs in a guix shell session so that it inherits the environmental variables set by Guix.
  2. Prefix any command you might execute in M-x shell, using shell-command, compile, etc. with a guix shell ... -- prefix.`

Neither of these two options are that convenient, so I was unusually delighted when I found a simple solution in the recently updated buffer-env by Augusto Stoffel (author of many under-appreciated packages). Reading through the source for the first time was a real joy, and I kept thinking about it like one would after hearing a good, catchy song.

The package has as simple interface, and for the most part it can be configured in a single line:

(add-hook 'hack-local-variables-hook 'buffer-env-update)

The package was added to GNU ELPA earlier this year, and was initially just described as a pure-elisp direnv implementation. If this is all you need, you don’t need to bother yourself with anything else.

For those unfamiliar with hack-local-variables-hook, here is the docstring:

Normal hook run after processing a file’s local variables specs. Major modes can use this to examine user-specified local variables in order to initialize other data structure based on them.

So what buffer-env-update does, in the case of Guix, is check the buffer-env-commands variable and find an entry that says “if you find a manifest.scm command”, run

guix shell -D -f \"$0\" -- env -0

(where $0 is replaced with the absolute file path), parse the output and update variables such as process-environment and exec-path, that influence how processes are spawned.

The Guix documentation mentions something similar to this idea, but I find it much more complicated than what buffer-env allows me to do.

My configuration goes a bit further than just modifying hack-local-variables-hook: Using Setup I have the following in my init.el:

;;;;; Dynamic Environments
(setup (:if-package buffer-env)
  (:option buffer-env-script-name "manifest.scm")
  (add-hook 'comint-mode-hook #'hack-dir-local-variables-non-file-buffer)
  (add-hook 'hack-local-variables-hook #'buffer-env-update))

In other words, this changes two notable things:

  1. Setting buffer-env-script-name to looks for manifest.scm files, so that buffer-env automatically picks up on manifest.scm files. Could be a list as well, if I also wanted to use guix.scm files.
  2. Load directory local variables in comint buffers (REPLs, M-x shell, …) so that buffer-env also takes effect in these kinds of buffers that have no files associated with them.

What I found particularly clever is that there is no need for an ongoing guix shell session, but that by calling env -0 we extract all the environmental variables and apply them manually. This might run into issues if you use guix gc concurrently though. And after all, all there is to Guix or Nix are just a few clever symbolic links and environmental variables.

-1:-- Using Guix Environments in Emacs using buffer-env (Post)--L0--C0--July 31, 2022 04:47 PM

Irreal: Changing How Emacs Works

Karthik has a nifty video on how to change the way Emacs works. We’re all fond of saying that Emacs is infinitely extensible and customizable but then we usually go out for a beer without saying how. Kathink remedies that by showing us how to change Emacs’s behavior even when we don’t know what we’re doing.

Kathink uses Notmuch to read his email from within Emacs but he’s got a problem. He’s a developer so a lot his email includes a patch or a diff as a MIME attachment. That’s fine but most of the time he doesn’t want to see large patches or diffs. What he’d like is for those two MIME types to be folded by default so that they don’t clutter up his emails but so that he can unfold them when he does want to see their content.

He begins by saying he has no idea how Notmuch works but he doesn’t let that stop him from resolving the issue. What follows is his step-by-step discovery of how to solve his problem. He beings with the usual checking of the documentation and customize subsystems but, sadly, that was of no avail. Instead, he had to turn to the source code.

Notmuch has a lot of code, none of which he’s familiar with so it seems like an impossible task but Karthik shows definitively that that’s not the case. He doesn’t use a debugger or any fancy tools; he just burrows around in the code until he zeroes in on the solution. His method resonates with me because it’s pretty much what I do. Most of the time I don’t really know exactly where I’m heading but just follow the clues until I arrive at the solution. That’s exactly what Karthik does.

The video also demonstrates somethings that I already knew but didn’t appreciate enough until I saw them in action. The first of those is using xref-find-defintions to navigate through the code. The second is setting what Karthik calls “pins” to remember locations so that you can return to them at will. He does that with point-to-register to set the pin and jump-to-register to return to it.

This is a really good video and I recommend it to all Emacs users. It’s 29 minutes, 44 seconds so plan accordingly but do try to find the time.

Update [2022-08-01 Mon 13:10]: Work → Works

-1:-- Changing How Emacs Works (Post jcs)--L0--C0--July 31, 2022 04:29 PM

Bozhidar Batsov: Clojure Tricks: Zipping Things Together

Many programming languages have a function for combining the elements of multiple collections (e.g. arrays or lists) together. Typically this function is named zip. Here’s an example from Haskell:

zip [1, 2] ['a', 'b'] -- => [(1, 'a'), (2, 'b')]

Clojure doesn’t have a zip function in the standard library, which leads many newcomers to the language to wonder what to use in its place. The answer is quite simple:

;; let's zip a couple of lists, even if no one really uses them in Clojure
(map vector '(1 2 3) '(4 5 6))
;; => ([1 4] [2 5] [3 6])

;; works with vectors as well
(map vector [1 2 3] [4 5 6])
;; => ([1 4] [2 5] [3 6])

;; actually this works with anything seq-able
(map vector "this" "that")
;; => ([\t \t] [\h \h] [\i \a] [\s \t])

;; and you can mix and match different seq types
(map vector [1 2 3 4] "this")
;; => ([1 \t] [2 \h] [3 \i] [4 \s])

The function vector takes a variable number of arguments and produces a vector out of them. And vectors happen to be the idiomatic way to represent the concept of tuples (common in other functional programming languages) in Clojure. By the way, you can zip as many sequences together as your heart desires:1

(map vector [1 2 3] [4 5 6] [7 8 9])
;; => ([1 4 7] [2 5 8] [3 6 9])

And they don’t all have to be of the same length either:

(map vector [1 2 3] [4 5 6] [7 8 9] [10 11])
;; => ([1 4 7 10] [2 5 8 11])

One more thing… Clojure also has a function named zipmap that can zip a couple of seqs into a map:

(zipmap [:a :b :c :d :e] [1 2 3 4 5])
;; => {:a 1, :b 2, :c 3, :d 4, :e 5}

That’s all I have for you today. Zip long and prosper!

  1. That’s a big advantage over Haskell’s zip mentioned earlier, as it can only combine two lists. There’s a similar function called zip3 that can combine three lists. 

-1:-- Clojure Tricks: Zipping Things Together (Post Bozhidar Batsov ( 31, 2022 11:10 AM

Bozhidar Batsov: Clojure Tricks: Replace in String

Today I saw a clever bit of Clojure code involving clojure.string/replace, that reminded me how powerful the Clojure standard library is. I guess pretty much everyone knows that replace is normally used to replace some part of a string using a regular expression to describe what exactly to replace:

(str/replace "OCaml rocks!" #"([Hh]askell)|([Oo][Cc]aml)" "Clojure")
;; => "Clojure rocks!"

;; we can refer to the match groups in the replacement string
(str/replace "Haskell rocks!" #"([Hh]askell)|([Oo][Cc]aml)" "$1 is nice, but Clojure")
;; => "Haskell is nice, but Clojure rocks!"

Pretty useful and pretty straightforward. But wait, there’s more! I had forgotten you can actually use a function for the replacement, which allows us to do more sophisticated things. Here’s how we can capitalize every word with 5 or more letters in a string:

(str/replace "master of Clojure is pulling the strings" #"\w{5,}" str/upper-case)

If you’ve got more match groups in your regular expression you can use all of them in the function that you’re using to generate the replacements:

(str/replace "pom kon sor" #"(.)o(.)" (fn [[_ a b]] (str (str/upper-case a) "-o-" (str/upper-case b))))
"P-o-M K-o-N S-o-R"

Note here the use of deconstructing to account that each match is essentially a vector of the full match and each group match (e.g. ["pom" "p" "m"]).

That’s I have for you today! Feel free to share with me more fun usages of replace!

-1:-- Clojure Tricks: Replace in String (Post Bozhidar Batsov ( 31, 2022 08:12 AM

Yi Tang: Machine Learning in Emacs - Copy Files from Remote Server to Local Machine

dired-rsync is a great additional to my Machine Learning workflow in Emacs

Table of Contents

For machine learning projects, I tweaked my workflow so the interaction with remote server is kept as less as possible. I prefer to do everything locally on my laptop (M1 Pro) where I have all the tools for the job to do data analysis, visualisation, debugging etc and I can do all those without lagging or WI-FI.

The only usage of servers is running computation extensive tasks like recursive feature selection, hyperparameter tuning etc. For that I ssh to the server, start tmux, git pull to update the codebase, run a bash script that I prepared locally to fire hundreds of experiments. All done in Emacs of course thanks to Lukas Fürmetz’s vterm.

The only thing left is getting the experiment results back to my laptop. I used two approaches for copying the data to local: file manager GUI and rsync tool in CLI.

Recently I discovered dired-rsync that works like a charm - it combines the two approaches above, providing a interactive way of running rsync tool in Emacs. What’s more, it is integrated seamlessly into my current workflow.

They all have their own use case. In this post, I brief describe those three approaches for coping files with a focus on dired-rsync in terms of how to use it, how to setup, and my thoughts on how to enhance it.

Note the RL stands for remote location, i.e. a folder a in remote server, and LL stands for local location, the RL’s counterpart. The action in discussion is how to efficiently copying files from RL to LL.

File Manager GUI

This is the simplest approach requires little technical skills. The RL is mounted in the file manager which acts as an access point so it can be used just like a local folder.

I usually have two tabs open side by side, one for RL, and one for LL, compare the differences, and then copy what are useful and exists in RL but not in LL.

I used this approach on my Windows work laptop where rsync is not available so I have to copy files manually.

Rsync Tool in CLI

The rsync tool is similar to cp and scp but it is much more power:

  1. It copies files incrementally so it can stop at anytime without losing progress
  2. The output shows what files are copied, what are remaining, copying speed, overall progress etc
  3. Files and folders can be included/excluded by specifying patterns

I have a bash function in the project’s script folder as a shorthand like this

copy_from_debian_to_laptop () {
    # first argument to this function
    # define where the RL is 
    # define where the LL is 
    rsync -avh --progress \
	  ${remote_project_dir}/${folder_to_sync}/ \

To use it, I firstly cd (change directory) to the project directory in terminal, call copy_from_debian_to_laptop function, and use the TAB completion to quickly get the directory I want to copy, for example

copy_from_debian_to_laptop experiment/2022-07-17-FE

This function is called more often from a org-mode file where I kept track of all the experiments.

Emacs’ Way: dired-rsync

This approach is a blend of the previous two, enable user to enjoy the benefits of GUI for exploring and the power of rsync.

What’s more, it integrates so well into the current workflow by simply switching from calling dired-copy to calling dired-rsync, or pressing r key instead of C key by using the configuration in this post.

To those who are not familiar with copying files using dired in Emacs, here is the step by step process:

  1. Open two dired buffer, one at RL and one at LL, either manually or using bookmarks
  2. Mark the files/folders to copy in the RL dired buffer
  3. Press r key to invoke dired-rsync
  4. It asks for what to copy to. The default destination is LL so press Enter to confirm.

After that, a unique process buffer, named *rsync with a timestamp suffix, is created to show the rsync output. I can stop the copying by killing the process buffer.

Setup for dired=rsync

The dired-rsync-options control the output shown in the process buffer. It defaults to “-az –info=progress2”. It shows the overall progress in one-line, clean and neat (not in MacOS though, see Issue 36). Sometimes I prefer “-azh –progress” so I can see exactly which files are copied.

There are other options for showing progress in modeline (dired-rsync-modeline-status), hooks for sending notifications on failure/success (dired-rsync-failed-hook and dired-rsync-success-hook).

Overall the library is well designed, and the default options work for me, so I can have a bare-minimal configuration as below (borrowed from ispinfx):

(use-package dired-rsync
  :demand t
  :after dired
  :bind (:map dired-mode-map ("r" . dired-rsync))
  :config (add-to-list 'mode-line-misc-info '(:eval dired-rsync-modeline-status 'append))

There are two more things to do on the system side:

  1. In macOS, the default rsync is a 2010 version. It does not work with the latest rsync I have on Debian server so I upgrade it using brew install rsync.

  2. There no way of typing password as a limitation of using process buffer so I have to ensure I can rsync without remote server asking for password. It sounds complicated but fortunately it takes few steps to do as in Setup Rsync Between Two Servers Without Password.

Enhance dired-rsync with compilation mode

It’s such a great library that makes my life much easier. It can be improved further to provide greater user experience, for example, keep the process buffer alive as a log after the coping finished because the user might want to have a look later.

At the moment, there’s no easy way of changing the arguments send to rsync. I might want to test a dry-run (adding -n argument) so I can see exactly what files are going to be copied before running, or I need to exclude certain files/folders, or rerun the coping if there’s new files generated on RL.

If you used compilation buffer before, you know where I am going. That’s right, I am thinking of turning the rsync process buffer into compilation mode, then it would inherit these two features:

  1. Press g to rerun the rsync command when I know there are new files generated on the RL
  2. Press C-u g (g with prefix) to change the rsync arguments before running it for dry-run, inclusion or exclusion

I don’t have much experience in elisp but I had a quick look at source code, it seems there’s no easy of implementing this idea so something to add to my ever-growing Emacs wish-list.

In fact, the limitation comes from using lower level elisp functions. The Emacs Lisp manual on Process Buffers states that

Many applications of processes also use the buffer for editing input to be sent to the process, but this is not built into Emacs Lisp.

What a pity. For now I enjoy using it and look for opportunities to use it.

-1:-- Machine Learning in Emacs - Copy Files from Remote Server to Local Machine (Post)--L0--C0--July 30, 2022 11:00 PM

Irreal: Improvements to dwim-shell-command

Álvaro Ramírez has been busy making improvements to his excellent dwim-shell-command package. I’ve written a lot about this package recently but that’s okay because it’s something most Irreal readers would want to know about. The TL;DR is that the package provides a DWIM interface between Emacs and the shell making it easy to invoke various utilities from Emacs that would normally be started from the shell.

The new version allows dwim-shell-command to operate on a set of files in a region rather than having to be marked in dired. There’s also a marker to insert the contents of the clipboard into a command. That’s perfect for inserting a URL that you’ve clipped from, say, the browser and using it in a shell command.

Finally, Ramírez has added numeric and alphabetic counters that allow for names that are the same except for the counter value. That works just as you’d think it would. The package is, after all, meant to provide do what I mean actions.

As far as I can see, this package started out as a quick hack that allowed Ramírez to create an easy way of invoking frequent but complex shell commands. Once he’d laid down the framework, new applications kept suggesting themselves to him and the project has grown.

As I wrote the other day, the package is now available on Melpa so it’s easy to try it out if you’re interested.

-1:-- Improvements to dwim-shell-command (Post jcs)--L0--C0--July 30, 2022 04:50 PM

Alvaro Ramirez: An accentuated Emacs experiment (à la macOS)

30 July 2022 An accentuated Emacs experiment (à la macOS)

macOS has a wonderful input mechanism where you press and hold a key on your keyboard to display the accent menu. It's easy to internalize: long press "a" if you want to input "á".


On Emacs, C-x 8 ' a would be the equivalent, but it just didn't stick for me. Fortunately, there's an alternative, using dead keys. Mickey Petersen gives a wonderful introduction. Having said all this, I still longed for macOS's input mechanism.

Thanks to Christian Tietze's post, I discovered the accent package. While it doesn't handle press-and-hold, it does the heavy lifting of offering a menu with character options. If I could just bring that press-and-hold

My initial attempt was to use key chords (via use-package):

(use-package  accent
   :ensure t
   :chords (("aa" . ar/spanish-accent-menu)
           ("ee" . ar/spanish-accent-menu)
           ("ii" . ar/spanish-accent-menu)
           ("oo" . ar/spanish-accent-menu)
           ("uu" . ar/spanish-accent-menu)
           ("AA" . ar/spanish-accent-menu)
           ("EE" . ar/spanish-accent-menu)
           ("II" . ar/spanish-accent-menu)
           ("OO" . ar/spanish-accent-menu)
           ("UU" . ar/spanish-accent-menu)
           ("nn" . ar/spanish-accent-menu)
           ("NN" . ar/spanish-accent-menu)
           ("??" . ar/spanish-accent-menu)
           ("!!" . ar/spanish-accent-menu))
  (defun  ar/spanish-accent-menu ()
    (let ((accent-diacritics
           '((a (á))
             (e (é))
             (i (í))
             (o (ó))
             (u (ú ü))
             (A (Á))
             (E (É))
             (I (Í))
             (O (Ó))
             (U (Ú Ü))
             (n (ñ))
             (N (Ñ))
             (\? (¿))
             (! (¡)))))
      (ignore-error quit

While it kinda works, "nn" quickly got in the way of my n/p magit navigation. Perhaps key chords are still an option for someone who doesn't need the "nn" chord, but being a Spanish speaker, I need that "ñ" from long "n" presses!

I'm now trying a little experiment using an after-change-functions hook to monitor text input and present the accent menu. I'm sure there's a better way (anyone with ideas?). For now, it gives me something akin to press-and-hold.


I'm wrapping the hook with a minor mode to easily enable/disable whenever needed. I'm also overriding accent-diacritics to only include the characters I typically need.

(use-package  accent
   :ensure t
   :hook ((text-mode . accent-menu-mode)
         (org-mode . accent-menu-mode)
         (message-mode . accent-menu-mode))
  (setq accent-diacritics '((a (á))
                            (e (é))
                            (i (í))
                            (o (ó))
                            (u (ú ü))
                            (A (Á))
                            (E (É))
                            (I (Í))
                            (O (Ó))
                            (U (Ú Ü))
                            (n (ñ))
                            (N (Ñ))
                            (\? (¿))
                            (! (¡))))
  (defvar  accent-menu-monitor--last-edit-time nil)

  (define-minor-mode  accent-menu-mode
     "Toggle ` accent-menu ' if repeated keys are detected."
     :lighter  " accent-menu mode"
    (if accent-menu-mode
          (remove-hook 'after-change-functions #'accent-menu-monitor--text-change t)
          (add-hook 'after-change-functions #'accent-menu-monitor--text-change 0 t))
      (remove-hook 'after-change-functions #'accent-menu-monitor--text-change t)))

  (defun  accent-menu-monitor--text-change (beginning end length)
     "Monitors text change BEGINNING, END, and LENGTH."
    (let ((last-edit-time accent-menu-monitor--last-edit-time)
          (edit-time (float-time)))
      (when (and (> end beginning)
                 (eq length 0)
                 (not undo-in-progress)
                  ;;  0.27 seems to work for my macOS keyboard settings.
                  ;;  Key Repeat: Fast | Delay Until Repeat: Short.
                 (< (- edit-time last-edit-time) 0.27)
                 (float-time (time-subtract (current-time) edit-time))
                 (accent-menu-monitor--buffer-char-string (1- beginning))
                 (seq-contains-p (mapcar (lambda (item)
                                           (symbol-name (car item)))
                                 (accent-menu-monitor--buffer-char-string beginning))
                 (string-equal (accent-menu-monitor--buffer-char-string (1- beginning))
                               (accent-menu-monitor--buffer-char-string beginning)))
        (delete-backward-char 1)
        (ignore-error quit
      (setq accent-menu-monitor--last-edit-time edit-time)))

  (defun  accent-menu-monitor--buffer-char-string (at)
    (when (> at 0)
      (buffer-substring-no-properties at (+ at 1)))))

As a bonus, it ocurred to me that I could use the same press-and-hold to handle question marks in Spanish (from my UK keyboard).


-1:-- An accentuated Emacs experiment (à la macOS) (Post)--L0--C0--July 30, 2022 09:58 AM

Cameron Desautels: Emacs: Running Shell Commands on the Current File

I’ve long thought it was a little funny that Emacs doesn’t provide an easy way to run a shell command on the current file. It turns out it does, but it’s not as obvious as you might expect.

Emacs provides lots of great commands for conveniently running shell commands:

  • M-! (shell-command): executes the given shell command, displays output in a new buffer or the echo area (depending on output length). Optionally inserts the output into the current buffer when given a prefix argument.
  • M-& (async-shell-command): as above, but executed asynchronously.
  • M-| (shell-command-on-region): pass the current region as input to a shell command and display output. Optionally replaces the region when given a prefix argument.

Of course we can also run a shell within Emacs, via shell (the basic option), eshell (a shell implemented in Emacs Lisp, with access to Emacs Lisp functions), and term (a more fully-featured terminal emulator).

We also have compile, which will run a shell command (often make), streaming in the output and overlaying functionality to easily jump to files referenced in the output (compilation warnings, grep results, etc.).

But what has always been notably missing for me, is a quick way to run a shell command on the current file. Not buffer / file contents, not region, but file.

From dired-mode, we can easily do this with !, but invoking Dired just to run a shell command is more disruptive to my workflow than it needs to be when I just want to run open <current-file> or similar.

It turns out there is a built-in two-keystroke solution via the “future history” mechanism I wrote about on the CollBox Engineering blog:

If you use M-! (shell-command) and then press M-n (next-history-element), the current file name will be inserted into the minibuffer with point before it. Then you just need to type the command you want to run and hit return.

It’s a good reminder that with 46 years of history behind it, if something obvious appears to be missing from Emacs, there’s probably a good reason why.

-1:-- Emacs: Running Shell Commands on the Current File (Post)--L0--C0--July 29, 2022 12:48 PM

Gretzuni: Emacs as 21stC interdisciplinary tool

This is a general post explaining how Emacs turns out to be directly related to my distant epistemic domains of inquiry, why it is that I prefer to explore what Emacs has within it before using apps, and link to a thought-provoking online book about Emacs.

-1:-- Emacs as 21stC interdisciplinary tool (Post Greta)--L0--C0--July 29, 2022 09:21 AM

Andrea: A YASnippet to make it easy debugging clojure code with atoms

Speed up your Clojure debuging with a YASnippet
-1:-- A YASnippet to make it easy debugging clojure code with atoms (Post)--L0--C0--July 29, 2022 12:00 AM

Alvaro Ramirez: dwim-shell-command improvements

28 July 2022 dwim-shell-command improvements

Added a few improvements to dwim-shell-command.

Dired region

In DWIM style, if you happen to have a dired region selected, use region files instead. There's no need to explicitly mark them.


Clipboard (kill-ring) replacement

Use to substitute with clipboard content. This is handy for cloning git repos, using a URL copied from your browser.

git clone 


This illustrates usage, but you may want to use dwim-shell-commands-git-clone-clipboard-url from dwim-shell-commands.el instead. It does the same thing internally, but makes the command more accessible.

(defun  dwim-shell-commands-git-clone-clipboard-url ()
   "Clone git URL in clipboard to ` default-directory '."
   (format  "Clone %s" (file-name-base (current-kill 0)))
    "git clone "
    :utils  "git"))

Counter replacement

Use to substitute with a counter. You can also use <<3n>> to start the counter at 3.

Handy if you'd like to consistently rename or copy files.

mv  ''  'image().png'


Can also use an alphabetic counter with . Like the numeric version, can use any letter to start the counter with.

mv  ''  'image().png'


Prefix counter

Use a prefix command argument on dwim-shell-commands to repeat the command a number of times. Combined with a counter, you can make multiple copies of a single file.


Optional error prompt

Set dwim-shell-command-prompt-on-error to nil to skip error prompts. Focus process buffers automatically instead.


Configurable prompt

By default, dwim-shell-command shows all supported placeholders. You can change that prompt to something shorter using dwim-shell-command-prompt.


⚠️ Use with care ⚠️

The changes are pretty fresh. Please use with caution (specially the counter support).

-1:-- dwim-shell-command improvements (Post)--L0--C0--July 28, 2022 09:27 PM

Irreal: Why Use Emacs in 2022

Torstein Johansen has a short video that addresses the question of why he uses Emacs in 2022. The backstory is that every time he takes a new job or consulting position, the incumbents—who all use things like IntelliJ, Eclipse, or even VS Code—stare in disbelief when they see he is using Emacs and lecture him on how much more efficient he could be if he was using a Modern Editor™.

Johansen disagrees. Maybe, he says, there isn’t a button in Emacs to automatically refactor a section of code—although such a thing could be, and perhaps has been, implemented by any user who feels the need—but what Emacs offers is speed. Speed in the sense of being the shortest path between your brain and what appears on the screen.

Johansen also makes the familiar point that Emacs has a consistent set of shortcuts that work for virtually all the packages that run inside it. Those shortcuts allow efficient navigation of editing of whatever buffer happens to have focus. He notes that this is so comfortable that Emacs users typically try to stay within Emacs as much as possible.

This leads to the well-known phenomena of Emacs users trying to migrate as many tasks as possible to within Emacs. Johansen considers himself “a bit out there” because he handles his email from within Emacs. I found that amusing since I do the same and more. As I said many times, virtually all my tube time is spent in either Emacs or the browser and I’ve migrated as many Emacs shortcuts as possible to the browser and other macOS utilities.

The kids can say whatever they want about their fancy editors but the fact remains most serious programmers use Emacs or Vim.

-1:-- Why Use Emacs in 2022 (Post jcs)--L0--C0--July 28, 2022 06:23 PM

Kisaragi Hiu: GitHub Actions / GitLab CI: deploy to branch

Why? Now your latest release is one git clone <url> -b release <local-path> away. That's what I want. GitLab CI image: archlinux:latest variables: SSH_PRIVATE_KEY: $SSH_PRIVATE_KEY before_script: - pacman -Syu --noconfirm make git openssh "default": stage: "build" script: - make public after_script: - mkdir ~/.ssh - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - touch ~/.ssh/known_hosts - ssh-keyscan >> ~/.ssh/known_hosts - cd public - git init --initial-branch=release - git config user.
-1:-- GitHub Actions / GitLab CI: deploy to branch (Post Kisaragi Hiu)--L0--C0--July 28, 2022 03:26 PM