Cursory provides a thin wrapper around built-in variables that affect
the style of the Emacs cursor on graphical terminals. The intent is
to allow the user to define preset configurations such as “block with
slow blinking” or “bar with fast blinking” and set them on demand.
The use-case for such presets is to adapt to evolving interface
requirements and concomitant levels of expected comfort, such as in
the difference between writing and reading.
Cursory has been in a stable state for a long time. I use it daily
and am happy with what it does. This version refactors parts of the
code in the interest of legibility/hackability, while providing a
quality-of-life feature for users.
A preset can now inherit from another
In the interest of defining multiple presets while avoiding
duplication, the user option cursory-presets now accepts an
:inherit property. For example:
(setqcursory-presets'(;; Sample code here ...(bar:cursor-type(bar.2):cursor-in-non-selected-windowshollow:blink-cursor-mode1:blink-cursor-blinks10:blink-cursor-interval0.5:blink-cursor-delay0.2)(bar-no-other-window:inheritbar:cursor-in-non-selected-windowsnil);; More sample code here ...))
Presets were already capable of getting properties from a default t
preset. Now they can be controlled with greater precision.
The value of cursory-presets is updated accordingly to benefit from
this mechanism and to showcase how it is done:
(defcustomcursory-presets'((box:blink-cursor-interval0.8)(box-no-blink:blink-cursor-mode-1)(bar:cursor-type(bar.2):blink-cursor-interval0.5)(bar-no-other-window:inheritbar:cursor-in-non-selected-windowsnil)(underscore:cursor-type(hbar.3):blink-cursor-blinks50)(underscore-thin-other-window:inheritunderscore:cursor-in-non-selected-windows(hbar.1))(t; the default values:cursor-typebox:cursor-in-non-selected-windowshollow:blink-cursor-mode1:blink-cursor-blinks10:blink-cursor-interval0.2:blink-cursor-delay0.2));; Omitting the doc string for demo purposes...)
In the above sample, we notice both the :inherit property and the
default t preset with all its properties. Presets beside t act as
overrides of the defaults and, as such, need only consist of the
properties that change from the default. In the case of an
:inherit, properties are first taken from the inherited preset and
then the default one.
As you all know by now, I really love SICP and consider it among the best—if not the best—books on computer science of all time. I didn’t read it until fairly late in my career and yet I can’t overstate how much I learned from it and how much it changed the way I think about our craft. There are those—including Abelson and Sussman—who say that the approach employed by SICP is no longer applicable but I disagree vehemently. If you don’t understand its lessons then you don’t understand computer programming no matter how many robots you program.
You won’t really understand those lessons unless you work most of the problems. I mostly skipped over them on my first reading but later went back to reread SICP and work the problems. Again, I learned new things and deepened my understanding of what I thought I already knew.
Getting, finally, to the point, Konstantinos Chousos has just started reading SICP and is working the exercises as he goes along. He has a blog post that describes his workflow for studying the book. His is by no means to only such workflow possible but it’s a good one and worth emulating if you, too, want to become enlightened by SICP.
The TL;DR is that he installed SICP as an Info file so he can read it in Emacs and then installed Racket as his Scheme environment because it offers an SICP extension that recreates the original MIT Scheme that SICP uses. He also installed the emacs-ob-racket package for working with Racket from within Emacs.
He describes in detail how to install all these so it’s pretty easy to duplicate his setup. If you want to study SICP, and you should, Chousos’ workflow is an excellent way of doing so. And, you’ll end up with SICP installed in Emacs as an Info file. What’s not to like?
While currently piecing together my git repositories and figuring out which files to commit I am invariably going to have some Untracked files but I also would like to see the Tracked files in magit-status
Well emacs being emacs this can be easily achieved, I added the following to my use-package magit declaration.
The ef-themes is a collection of light and dark themes for GNU Emacs
whose goal is to provide colourful (“pretty”) yet legible options for
users who want something with a bit more flair than the modus-themes
(also designed by me).
Backronym: Eclectic Fashion in Themes Hides Exaggerated Markings,
Embellishments, and Sparkles.
Below are the release notes.
This release introduces several minor refinements to the project,
while adding support for more third-party packages or built-in face
groups.
Tabs have their own semantic colour mappings
The Ef themes are designed to abstract away common patterns based on
the semantics of the elements involved. For example, all strings in
programming modes use the string colour that each theme defines in
its palette. This allows the themes to share the same code base yet
remain distinct from each other.
Colours used for tab-bar-mode, tab-line-mode, and related are now
part of this design. The new semantic mappings are bg-tab-bar,
bg-tab-current, bg-tab-other.
[ A theme palette can have user-defined overrides (e.g. tweak the
main background). Consult the manual for the technicalities or
contact me if there is any doubt. ]
Added support for the centaur-tabs package
The aforementioned semantic colours are applied to the faces of the
centaur-tabs. Using it with the themes now works as expected,
instead of defaulting to its own dark background colour (a default
that doesn’t work with most themes, anyway).
Covered the nerd-icons, nerd-icons-dired, nerd-icons-ibuffer packages
These are a new family of packages that are gaining traction in the
Emacs milieu (for instance, the doom-modeline now uses the Nerd
icons, which must be installed with M-x nerd-icons-install-fonts).
Their colours are now consistent with all the Ef themes.
Tweaked the colouration of the all-the-icons glyphs
I refined some of the colours in use to introduce greater variety and
amplify certain values while avoiding exaggerations. In short, they
should look nice and pretty.
The whitespace-mode indicators are much more subtle
The previous style involved the use of a dim grey background. While
this is good to spot invisible characters quickly, it is bad for users
who want to run whitespace-mode at all times (e.g. for Python which
is space-sensitive).
We thus remove the backgrounds by default but provide the option to
reinstate them via palette overrides (as documented at length in the
manual). To this end, we have new semantic colour mappings for
ordinary negative space and its invisible characters:
bg-space
fg-space
bg-space-err
Ediff faces no longer have an implicit dependency on diff-mode
I made a mistake where the Ediff faces would inherit the styles of
their diff-mode counterparts. This usually works, such as when
ediff is invoked from magit, though it will not do the right thing
if the user invokes some Ediff command directly without first loading
diff-mode.
This no longer happens. Ediff always works. Stylistically,
everything looks the same.
The git-gutter and git-gutter-fr packages are supported
These now use the appropriate colours defined by the Ef themes. This
is especially important for themese that do not use the generic
red-green colour coding scheme.
image-dired marked items are easier to spot
With image-dired the user can apply selection or deletion marks to
image thumbnails. Those marks are colour-coded the same way they are
in Dired (the exact hues depend on the theme to account for
accessibility, e.g. for deuteranopia or tritanopia). Sometimes the
colour of the mark is obscured by the same colour found in the
thumbnail. To make the mark stand out, a border is drawn around it,
making the selection unambiguous.
Holidays and diary entries are more distinct and have no background
The holidays and diary entries that are found in the M-x calendar or
M-x diary buffers no longer use a subtle background colour. The old
design was not consistent with similar patterns established by the
themes, such as how a date/timestamp should be represented.
Furthermore, the given constructs are assigned to contrasting hues to
stand apart from each other and also be easy spot in their context
(especially holidays in the Calendar view).
The mood-line is covered by the themes
This is a package that refashions the Emacs mode line. It is
conceptually similar to the doom-modeline.
Miscellaneous
Added links in the Custom User Interface to the ef-themes web
pages for the manual and sample pictures, respectively. Those links
are visible when perusing the various M-x customize buffers where
entries related to the Ef themes are present.
Made ef-themes--load-theme return the THEME argument it operates
on. The intent is to allow other functions that call this one to
capture the return value for their purposes.
Extended support for the built-in ERT faces, which are used in
regression tests of Emacs Lisp code.
A little exploration of Go from a Clojure perspective
I have been looking into Go recently and I decided to find out how to
do things that I usually do in Clojure. These are (a cleaned up
version of) my notes.
First let's start from iterations. Clojure (as any good Lisp language)
focuses on sequences. So changing a sequence into a new one is key (and super easy):
(map inc [1 2 3])
(2 3 4)
While Clojure focuses on immutability to keep things simple, Go focuses on performance.
The easiest way to achieve the same is with a for loop:
list := []int{1,2,3}
for i, value := range list {
list[i] = value + 1
}
list
[]int{
1,
2,
3,
.....
[]int{
2,
3,
4,
Next Clojure focuses on data transformation and the most used data
structure is the map. So let's iterate over a map's values:
And to complete our little exploration, I would say polymorphism is a
must. In Clojure we can make interfaces via protocols:
(defprotocol StringMyself
(who-am-i [x]))
(deftype Duck []
StringMyself
(who-am-i [x] "I am a duck!"))
(deftype Octopus []
StringMyself
(who-am-i [x] "I am an octopus!"))
(who-am-i (Octopus.))
StringMyself
user.Duck
user.Octopus
"I am an octopus!"
In Go is beautifully simple as well:
type StringMyself interface {
WhoAmI() string
}
type Duck struct {}
func (d Duck) WhoAmI () string {
return "I am a duck!"
}
type Octopus struct {}
func (d Octopus) WhoAmI () string {
return "I am an octopus!"
}
var o StringMyself = Octopus{}
o.WhoAmI()
.....
main.Octopus{
\"I am an octopus!\""
Not bad as a first go at go. And it seems to be pretty succinct!
After yesterday’s post I started thinking about what the real advantage of Emacs is. There are, as I’ve said many times, plenty of advantages but if you had to choose the most important one, what would it be?
My recent experience with elfeed-webkit crystallized this for me. It started with Christopher Wellons feeling that he needed a better RSS reader and that he’d like it to run in Emacs. The result of that itch was what I consider the best RSS reader in any environment: elfeed. The point here is that Wellons is just a guy with a problem but Emacs made it easy for him to solve that problem and make the result available to all of us.
But wait. There’s more. Fritz Grabo was an Elfeed user and liked it but many times he had to switch to his browser to read a post and then switch back to Elfeed. That was a pain so he started wondering if there was some way of faithfully rendering the HTML directly in Emacs. It turned out that of course there was. You can compile Emacs with XWidget support and then use Webkit to render HTML accurately directly in an Emacs buffer. Grabo used that to make elfeed-webkit and suddenly reading your RSS feed is even easier and more pleasant than it was before.
That’s the thing about Emacs: everything is available for you to extend it in any way you like, sometimes in surprising ways. Reading RSS feeds is, after all, only marginally related to text editing but as I’ve written so many times before, Emacs is much more than an editor so it has us covered.
For me, therefore, the most important advantage of Emacs is its extensibility. If it isn’t quite what you want, Emacs makes it possible to make it exactly what you want.
Read-Evaluate-Print Loops are great for doing quick experiments. I recently released two new REPL packages for Emacs to GNU ELPA. This is the first in a two part series.
I wanted something along the lines of SLIME or CIDER’s REPL (just the REPL part) but for JavaScript. There have been many options for this over the years, MozRepl, skewer-mode, jsSlime 1, and more recently dap-mode. I tried all of these existing options but all except for dap-mode are no longer maintained. The Firefox Remote Debugging Protocol has evolved over the past decade, and it has not always maintained backward compatibility. It is not meant to be an API, I guess, but more a reflection of Firefox internals.
I did try dap-mode, but I couldn’t install it on my development version of Emacs; there seemed to be Elisp compatibility problems with some of its many dependencies. It also seemed to require on the Firefox side a JavaScript extension from the repository for an unrelated proprietary IDE, which I found strange.
I just wanted a simple Emacs mode to communicate with Firefox directly, for small JavaScript experimentation. It seemed like everything was already available in Emacs and Firefox to do that.
I started with the Mastering Emacs Comint guide, and for the Firefox side, the geckordp project does a great job of documenting the Firefox Remote Debugging Protocol. Firefox needs to run in a special debug mode for the protocol to be available, so I added that logic to the new Emacs command.
The result is firefox-javascript-repl, available in GNU ELPA. I tested it on GNU/Linux. I would like this to work on other operating systems too, patches accepted.
I made sure this mode works on Emacs versions 26.1 (released in 2018) and newer 2. I’ve also tested on the most recent Firefox (113.0.2) and Firefox ESR (102.11.0esr). I’ll strive to keep up with changes in the Firefox Remote Debugging Protocol, to minimally keep firefox-javascript-repl working for the latest Firefox and Firefox ESR releases (though if the FRDP breaks compatibility, firefox-javascript-repl will also break compatibility with older browser versions, to avoid a large test matrix).
I was going to do a video of this working but it’s easy enough to try yourself. It creates a new temporary Firefox profile, so it doesn’t mess with any of your existing profiles. Try M-x package-install RET firefox-javascript-repl RET; M-x firefox-javascript-repl RET. If Firefox starts and everything succeeds, you should see an interesting JavaScript quirk-of-the-day, courtesy of the wtfjs project.
I wish jsSlime were still maintained, in which case I wouldn’t need to write this post or this REPL.^
I welcome patches to make it work on older versions of Emacs, but I can’t build anything older than Emacs 26.1 to test against.^
What do you think? Is Emacs slow or is that just another instance of Emacs hater FUD? The most frequent complaint I see about Emacs—with the possible exception of its lack of bling—is that it’s too slow.
I don’t understand that. Maybe that’s because I’m old enough to have used some genuinely slow tools but I’m pretty sure it’s just that I have more sensible standards. Sure, other editors may be faster at one task or another but I have always found the differences in speed essentially undetectable by human beings in their normal workflows. In other words, Emacs is fast enough where it counts.
Corwin Brust over at Corwin’s Emacs Blog examines this question in his blog post, The Turtle and the Snail. The title comes from a joke involving a turtle and snail that has application to the question of Emacs’ speed. I’ll let you check out the joke on Brust’s post but the TL;DR is that speed—at least if we aren’t speaking of light—depends on the observer.
Brust mentions a related complaint: “[I]t consumes too much of my time, to understand and configure, and to enhance it.” That’s just plain silly. Unless you’re one of those people who demands instant gratification and are unwilling to expend any effort to attain it, the complaint is frivolous. When I started, I printed out the cheat sheet and was using Emacs reasonably productively on the first day. To be sure, I wasn’t as fast as I was with Vim but that came fairly quickly.
As for understanding and configuring it, we all know that that’s a lifetime journey. Like every other Emacs user, I’m still learning new things about Emacs and my init.el is a lifelong project. If this idea of a lifetime commitment bothers you, perhaps Emacs is not for you.
Can we ever stop setting up emacs? I don't think it's possible, no. Lets do it again, with a nice clean setup using Nano Emacs.
Compiling emacs First lets get ourselves a clean emacs from d12frosted/homebrew-emacs-plus.
1 2 3 $ brew tap d12frosted/emacs-plus $ brew install emacs-plus --with-imagemagick --with-native-comp --with-modern-sexy-v2-icon --with-xwidgets $ ln -s /opt/homebrew/opt/emacs-plus@28/Emacs.app /Applications This will take a nice little while.
Also, some fonts:
1 2 3 4 $ brew tap homebrew/cask-fonts $ brew install font-roboto $ brew install font-roboto-slab $ brew install font-roboto-mono Installing straight.
Robert Johnson has a useful post on Everyday editor extensions in Emacs. Most Emacs n00bs and even many seasoned Emacers assume Elisp is too obscure and hard for “normal” users so they avoid it. Of course, that’s not true at all. As Johnson shows, it’s pretty easy to get started making simple extensions without having to know much about Elisp.
He demonstrates this by making a very simple Emacs function that simply opens the browser at some fixed site—github/spacemacs in his case. From there, he adds the ability to enter parameters, first by having the user enter them, then by using thing-at-point, and finally by using a prompt if thing-at-point fails.
At that point Johnson has a useful function that anyone could customize for their own workflow. Next he considers calling a shell command rather than the browser and having the results put in an Emacs buffer. That’s great, of course, because you can stay in Emacs and don’t have to switch out to the browser.
All of this uses only a minuscule fraction of the Elisp language, of course, but still manages to produce useful extensions. The important, unstated, advantage, though, is that once you get comfortable with this tiny portion of Elisp, it’s much easier to move on to the rest of the language. Developing even a minimal working knowledge of Elisp will open up a whole new dimension of Emacs to you.
People are always talking about how fast they work, either because Emacs or because Not Emacs.
That reminds me of this joke…
For me, the idea "getting things done faster" hits a little funny. I attempt all sorts of crazy things in my own technology (particularly coding) projects. Moreover, as a general rule, I don't strive to "get stuff done fast" so much as struggle to get things done, at all.
I am currently hacking around with my org files and in fact macro removing quite a few unnecessary lines. However this has had the side effect of leaving some significant holes in the form of blank lines. Sometimes just two duplicate blank lines and sometimes more!
I found that I can quickly trim them down by using delete-duplicate-lines and making sure the identical lines must be adjacent argument is set by passing in a C-u C-u prefix.
So the process is:
open the org file
mark-whole-buffer
C-u C-udelete-duplicate-lines
and that’s it!, the key here is the prefix argument otherwise all the blank lines will be deleted which is not what I want.
Of course this method would delete all duplicate adjacent lines and not just the blank ones so I guess you would generally need to be a little careful, but I know I don’t have any of these and if I am not too sure then I can just inspect a git diff.
Ashton Wiersdorf has a very interesting post on refactoring in Emacs. His problem is a simple one: we wants to replace all occurrences of set_XXX_config! (where XXX varies) to config_XXX! for all files in a directory. He uses several packages to support this but the only one really necessary is wgrep, which make a search results buffer writable and saves the changes to it back to the original files.
His strategy is to
grep for the appropriate regex,
put the search results in a separate buffer
make the buffer writable with wgrep
use something like replace-regexp to change the identifiers
save the results back to the original files
If you’ve been around Irreal for a while, this probably seems familiar. In abo-abo’s original post, he used rgrep so he didn’t need to worry about getting the results into another buffer but my process uses counsel-rg so I need a Ctrl+cCtrl+o to move the results from the minibuffer to a separate buffer. After that, things are mostly the same. The nice thing is that Ivy handles all this for me and I don’t need any other packages besides wgrep.
This is a great way to refactor. The process, Wiersdorf says, is better than trying to do it from within an IDE using some sort of language server because it finds and changes all occurrences of the target identifiers including those in, say, documentation files that a language server is not going to find. It’s my favorite way of solving this problem. After you try it, it will probably become yours too.
Some time ago (well, a long time ago) someone posted an interesting discovery in Org mode agenda: “clockcheck mode”. I stored the link to that message with the intention of blogging about it and forgot about it. I rediscovered it some time ago and decided to take a look.
I just published a new project called spacious-padding. This is yet
another package of mine for GNU Emacs. It increases the padding or
spacing of frames and windows on demand.
The idea with this package is to provide the means to easily toggle
between terse and spacious views, depending on the user’s needs.
Below are a couple of pictures to show what I mean.
Default spacing 😒
M-x spacious-padding-mode 🤩
Coming soon
There will be no widely available GNU ELPA package for the first days
of spacious-padding. Only those who track the GNU ELPA-devel
archive or pull directly from source can get it right now. I want to
test this for a while longer before tagging version 0.1.0. Expect
the formal release some time next week.
Whenever I think of artificial intelligence, Ghost in the Machine, the seventh
episode of the first season of The X-Files, comes to my mind.1 Almost
thirty years have gone since that episode first aired, but it has always been
one of my favourites. The plot is fairly straightforward: the Central Operating
System (a.k.a. the AI) of a software company develops both survival instinct and
morbid care for its creator; killings ensues; Mulder and Scully manage to stop
the evil technology. Or do they? As a teenager I loved the openness of The
X-Files, always leaving room for unsolved dilemmas episode after episode. I
also wanted to believe as Mulder did, but that is a different story.
Today it is not uncommon to laugh at the overtly pessimistic views of shows such
as this, casting aside wrongly perceived assumptions with an indulgent smirk.
Beside the fact that usually the characters who never doubt common sense are the
first ones to die in these tales, this sort of cynicism reveals more than it
conceals.
My firm belief is that the outcomes of and the concerns about the recent
developments in artificial intelligence are nothing more than the inevitable
consequence of the society we have built. We have been putting our faith in
technology for so long by now that it is nearly impossible to look at it from a
rather different perspective. The one who does so is generally ridiculed. This
is even more interesting when we think about the distinction between science and
technology and how we relate to them. Think of the pandemic. What COVID-deniers’
reactions highlighted is how easily we can criticise science for its
shortcomings while at the same time relying on the technology that science
itself made available for our rants to be out in the public.
Technology says as much of our times as fiction does. It mirrors points of view,
it asks questions, and offers problems just as it looks for answers and tries to
offer solutions. Like telling a story, developing a specific technology is an
effort situated in a precise place at a particular time, and we can understand
more of that time and that place if we read them through the stories and the
technology that were born within their constraints.
However, we do not want to look at technology as we look at fiction, because we
cannot believe technology to live in the realm of the uncertain, the implausible
or the unreal. Technology is tangible, its immediate effects readily perceivable
in our lives. Technology fixes problems, creates comfort, enables people to do
things that seemed impossible. And yet, like fiction, this is a story told from
a narrator who, like us, is a finite human being. A story makes sense when it
ends, but we cannot make sense of our lives because we do not know when they
will end and, just as well, we can never know the whole that constitutes other
people’s lives. Being a finite product of finite beings, how do we make sense of
technology then?
One possible answer, or at least the only answer I can think of, is critical
thinking. We may never find reliable replies to metaphysical doubts, but we can
still stop ourselves from mindlessly consuming technology and pause for a
moment, a moment long enough to figure out whether the full impact of new
technology is clear and understood. It is fairly obvious to me that this was not
the case for mobile technology. Have we ever stopped to think about how a
smartphone could change the life of a teenager? Do we not see what happened to
the attention span of people after years of push notifications? My university
has already issued a statement warning that papers will be proof read to avoid
misuses of ChatGPT, which is telling of how little to zero thought has been put
into the pivotal transformations artificial intelligence will bring upon us.
Lost in our market-driven technological bubble we please ourselves by being
concerned about the dangers of AI during lunch breaks or between rounds of beer.
I know we are still capable of critical thought, but I am not sure for how long
we will be. I cannot help but think that the smarter technology becomes, the
dumber end users might get.
Along with Kill Switch from Season 5, yes, but only when I am in a
deeply apocalyptic mood that usually drives me to watch The Terminator one
more time. ↩
Recently I’ve been toying with a literate configuration1 of Emacs. My init.el took a straightforward form:
1 (org-babel-load-file "~/.emacs.d/config.org") And all of my configuration lives in an org-file. This alone gives me very little benefit for now, but in the future, it will make it easier to have it as a dedicated page on this site.
However, one thing completely surprised me: the elfeed configuration. Until now, I used the standard way of configuring feeds with Elisp.
If you’re the type of person who likes to annotate files but keep your notes external to the file itself, you may be interested in nobiot’s org-remark. There are a couple of videos [1, 2] that show how it works and some of the features. There’s also a user manual that describes its features and how to use them in detail.
The TL;DR is that you simply select some text and org-remark highlights it and opens a separate window in which you can make notes. You can also open existing notes corresponding to an already highlighted area. There are different colored “pens” available for highlighting text and you can define others if you need them.
All of this is demonstrated in the videos and explained in the users manual so take a look if you’re interested. I have no need for this capability but lots of people do. If you’re one of them, take at look org-remark. It’s available from the GNU ELPA repository or, if you’re adventurous, the GNU-devel ELPA repository for the development releases.
The problem: rebulding packages This was discussed in an issue on straight1
With the notorious orgmode updates and breakages, combined with the amount that I depend upon orgmode, I am trying to just stick with the built in version and not ever build it. As such, my Straight orgmode invocation looks like this:
(use-package org :straight (:type built-in) Nonetheless, some packages seem to cause org to “build” and use a straight version.
Here’s a nifty Emacs workflow for doing a project-wide search-and-replace on steroids. While I do use refactor tools that come with language servers,1 sometimes those aren’t enough. Consider the case where you not only need to change the name of a function, but also e.g. need to swap the order of two of its arguments. Or you’ve broken one function out into two that need to be chained together. Whatever—there are plenty of ways where the IDE won’t be able to do everything that you need.
Over at the Emacs Elements Channel there’s another useful video up. This time it’s about the Emacs Help system. The majority of experienced Emacs users will already be familiar with most of the material but if you’re a learn-as-you-go user, there may be some information new to you.
The first thing is that Ctrl+hCtrl+h will show you a list of all the help commands. If you’re like me, you know this but always forget it when you’re trying to remember a help command. There are a lot more commands then the ones you use everyday so it’s worth your while to type Ctrl+hCtrl+h to see what’s available.
For example, I’d completely forgotten about Ctrl+Hw to discover the shortcut for a given command. My usual procedure is to bring up the documentation for the command and get the information there but I’m going to try to remember to use Ctrl+hw instead.
Another thing that I learned from the video is the difference between scrolling up and down with Space and Delete versus the <PgUp> and <PgDn> keys. I’ll let you watch the video to see what that difference is.
The video is 14 minutes 52 seconds long so it shouldn’t be too hard to find time but you may have to plan ahead.
I’ve written about Clojure’s threading macros and their implementation in Elisp before [1, 2, 3, 4, 5]. I like them but almost always use the traditional composition of functions instead. That’s probably because being a mathematician it seems natural to me. Still, the threading macros are easier to read and understand.
Most people who care about such things know about Magnar Sveen’s implementation of these macros in his Dash library. They have the advantage of using the same names, ->, ->>, etc. as clojure. Of course, you have to install Dash to use them. That’s not much of a problem because so many packages use Dash that it’s probably already installed.
But what if you don’t want the dependency? It turns out that Elisp has the most important of these macros built in and has since at least Emacs 25. The first, thread-first corresponds to -> and the second, thread-last, corresponds to ->>. They live in the sub-x.el file if you want to check out there definition.
Ruslan Bekenev has a page that explains all this and even gives a short explanation of how to use the macros. If you’re interested in the threading macros, take a look at his post.
I spent some time today doing a think that I have wanted to do for a
while, moving my "network topology" in to a data file which can be
ingested by the tools themselves rather than declaring them in code.
This starts with defining a hosts.toml
file whose topology maps more-or-less to the one that Morph uses; a
network is a deployment entity which can have any number of hosts in
it:
[endpoints]description="my laptops and desktop"enableRollback=trueconfig="../roles/endpoint"[endpoints.hosts.rose-quine]# target = "rose-quine"# stateVersion = "23.05"# user = "rrix"
There are reasonable defaults in the host configurations so that
adding a new host is a single-line operation in the hosts.toml file.
With that file in place, Deploying from my hosts.toml defines a function that ingests
the networks and spits out a Nix attrset in the shape that Morph wants
to execute:
and from there i could say morph build $file_defined_above and it would go
off and do that. then another invocation of morph deploy with a grab-bag of arguments would
actually roll the system out to the host.
Taking things a step further is fun though. Why not make a simple
wrapper that can make this easier? Morph Command Wrapper does that and
allows me to just type deploy to run a
change out to the host i'm sitting at, or deploy -b to just build it, or deploy --all to run it out everywhere.
Invoking deploy-targets will print out
a list of all the hosts that the system knows about, which can then be
conveniently fed in to completing-read
(->> (shell-command-to-string "deploy-targets") (s-split "\n") (append '("--all")) (completing-read "Which host do you want to deploy to? "))
And that can be used by the interactive emacs
function arroyo-flood to
automatically tangle the systems' org-mode role files, dynamically
extracting a list of server, laptop, desktop, etc, modules
from a sqlite cache along the way, and then deploying those! I'm pretty
happy with this.
I just published the latest stable release of the Modus
themes. The change log
entry is reproduced further below. It is a long read. For any
questions, feel welcome to contact me.
I will soon install the changes in emacs.git so please wait a little
longer for the updates to trickle down to you.
Package name (GNU ELPA): modus-themes (also built into Emacs 28+)
This is not a “change” per se, but it is worth documenting here. It
shows how important accessibility can be in empowering people to use
their computer and, in our case, to exercise their software freedoms.
The Modus themes tend to one aspect of accessibility. They do not
exhaust the topic, though they should at least raise awareness about
the significance of tending to the usability needs of everyone. The
effort I put into documenting the themes (and my other packages)
should be understood in this light as a means of helping people enjoy
their software freedom by learning how to use and extend the program
in question.
New tritanopia-optimised themes
I have created a pair of light and dark themes that are intended for
people with blue-yellow colour deficiency (tritanopia). These are
modus-operandi-tritanopia (light) and modus-vivendi-tritanopia
(dark). Screenshots of all the Modus themes are available on my
website: https://protesilaos.com/emacs/modus-themes-pictures.
The entire collection is now described in the manual as follows:
The Modus themes consist of eight themes, divided into four subgroups.
Main themes:modus-operandi is the project’s main light theme,
while modus-vivendi is its dark counterpart. These two themes are
part of the project since its inception. They are designed to cover
a broad range of needs and are, in the opinion of the author, the
reference for what a highly legible “default” theme should look
like.
Tinted themes:modus-operandi-tinted and modus-vivendi-tinted
are variants of the two main themes. They slightly tone down the
intensity of the background and provide a bit more color variety.
modus-operandi-tinted has a set of base tones that are shades of
light ochre (earthly colors), while modus-vivendi-tinted gives a
night sky impression.
Deuteranopia themes:modus-operandi-deuteranopia and its
companion modus-vivendi-deuteranopia are optimized for users with
red-green color deficiency. This means that they do not use red and
green hues for color-coding purposes, such as for diff removed and
added lines. Instead, they implement colors that are discernible by
users with deueteranopia or deuteranomaly (mostly yellow and blue
hues).
Tritanopia themes:modus-operandi-tritanopia and its counterpart
modus-vivendi-tritanopia are optimized for users with blue-yellow
color deficiency. The idea is the same as with the deuteranopia
variants: color coding relies only on hues that are accessible to
people with tritanopia or tritanomaly, namely, shades of red and
cyan.
Recalibrated the “graph” colours in all themes
The new palette subset improves the contrast of all the relevant
colours when presented side-by-side. These are most notably used by
the org-habit consistency graph, which is displayed in the Org
agenda. The deuteranopia and tritanopia themes have their own bespoke
colours for this purpose, due to their specific requirements for
colour coding (e.g. they cannot use green).
Faces or face groups
Introduced a subtle 3D effect for clickable buttons, replacing the
previous 2D design. I realised the flat style creates ambiguity
between the button and the text fields. This happens, for example,
with M-x customize-variable for org-capture-templates which has
lots of button and text field combinations. The added sense of
depth helps with the usability of these buttons because it makes
them unambiguous. Personally, I prefer the 2D approach, but here we
have a trade-off between usability and aesthetics. According to
what I state in the manual:
If there arises an inescapable trade-off between usability and
stylistic considerations, we will always opt for the former.
Refashioned the whitespace-mode to be much more subtle and added
the concomitant semantic colour mappings.
The previous style involved the use of a dim grey background for
each invisible character. While this is was good to spot invisible
characters quickly, it was a major hindrance for users who want to
run whitespace-mode at all times (e.g. for the Python programming
language which is space-sensitive).
We thus remove the backgrounds by default but provide the option to
reinstate them via palette overrides (as documented at length in the
manual). To this end, we have two new semantic colour mappings for
ordinary space, its invisible characters, as well as space errors.
Applied a more subtle background for faces menu-bar-mode,
tool-bar-mode, scroll-bar-mode. They do not need to stand out
so much because the toolkit already takes care of that. Also, we do
not want to dillute the semantic value of either bg-tab-bar or
fringe palette colour mappings that I was wrongly using before in
this context. Note that those faces may not apply, depending on the
underlying tool kit. For example, I encounter them with the Lucid
build of Emacs, though not with the GTK one.
Fix the critical typo of ‘widget-buton’, which prevented the actual
widget-button face from being affected by the themes. Thanks to
Steve Downey for pointing it out in issue 73 on the GitHub mirror:
https://github.com/protesilaos/modus-themes/issues/73.
Added support for the disk-usage package. It is made to look like
Dired, to the extent possible. Thanks to Nacho Barrientos for the
patch: https://lists.sr.ht/~protesilaos/modus-themes/patches/39822.
The change is small and does not require copyright assignment to the
Free Software Foundation.
Made the eglot-diagnostic-tag-unnecessary-face look like a
warning. By default it inherits the shadow face, which makes it
counter-intuitive as it dims the text instead of bringing it to our
attention. The intent of eglot-diagnostic-tag-unnecessary-face is
to highlight unused symbols, so this is better presented as a
warning.
Thanks to Augusto Stoffel for bringing this matter to my attention.
This was done via a private channel and the information is shared
with permission.
Changed the smerge-markers to inherit from diff-header instead
of diff-heading. Thanks to Steve Downey for the contribution.
This was done in pull request 74 on the GitHub mirror:
https://github.com/protesilaos/modus-themes/pull/74. The change
is small and does not require copyright assignment to the Free
Software Foundation.
Added support for the jinx package. This was originally done by
Tomasz Hołubowicz in pull request 71 on the GitHub mirror:
https://github.com/protesilaos/modus-themes/pull/71. The change
is small and does not require copyright assignment to the Free
Software Foundation. I then modified it to make the underlines look
like warnings instead of errors. This is because of how the package
works: it automatically highlights misspellings in the visible
portion of the buffer. There are cases where this results in a very
intense presentation, which can be distracting. We want to reduce
the overall intensity and not draw too much attention to those
highlights.
Extended coverage of Org to the new org-agenda-calendar-daterange
face (part of Org version 9.7). Thanks to Gautier Ponsinet for the
patch, which I received via a private channel. The change is small
and does not require copyright assignment to the Free Software
Foundation. In addition to this, I introduced a new semantic colour
mapping in the themes’ palette called date-range. This can be
used with the palette overrides, which are documented at length in
the manual (there are lots of copy-pastable examples as well).
Supported all of the new faces of the built-in proced package.
These are part of Emacs 29 and make the proced buffers more
colourful, subject to the user option proced-enable-color-flag.
As always, the themes strive to avoid exaggerations, meaning that I
apply colour with restraint: not all faces need to stand out.
Included the rst-mode in the list of explicitly supported
packages, making its heading look like those of Org, Markdown, etc.
Thanks to David Edmondson for the patch:
https://lists.sr.ht/~protesilaos/modus-themes/patches/40625. I
believe David has already assigned copyright to the Free Software
Foundation, though this patch is small anyway.
Covered all the new faces of the built-in flymake package. These
concern the inline feedback messages (Emacs 30) as well as those
that appear in the echo area (Emacs 29). The former are subject to
the user option flymake-show-diagnostics-at-end-of-line.
Reduced the intensity of the which-key prefix descriptions. Those
are the keymaps that displayed by which-key to hint that typing
the given key will open a new which-key page with more keys.
Configured new vundo-saved and vundo-last-saved faces of the
vundo package. They are designed to be easy to read, without
going over-the-top. Thanks to Nicolas Semrau for bringing this
matter to my attention in issue 79 on the GitHub mirror:
https://github.com/protesilaos/modus-themes/issues/79.
Instructed the shr-selected-link face of the built-in shr
package to use a “mark selection” style instead of the semantically
incorrect “intense red” it had before. This change is helpful for
those who override the palette of their Modus theme of choice, while
it also allows us to have varied colours depending on the
requirements of each theme (e.g. deuteranopia/tritanopia compared to
the defaults).
Did the same as above, mutatis mutandis, for the faces
transient-disabled-suffix, web-mode-error-face,
erc-dangerous-host-face, aw-minibuffer-leading-char-face,
binder-sidebar-highlight, binder-sidebar-missing,
image-dired-thumb-flagged, image-dired-thumb-mark,
info-menu-star, rainbow-delimiters-mismatched-face,
evil-ex-substitute-matches, iedit-occurrence,
iedit-read-only-occurrence, pgtk-im-0, dired-narrow-blink.
Enhanced the image-dired mark faces with a box border, as the use
of a background alone can be obscured by the underlying image
thumbnail, depending on its figures/colours.
Removed the backgrounds from the powerline-evil faces and
simplified their overral presentation in the interest of
maintainability. The old styles were hard to predict and test.
There could easily be conflicts, such as if the user would override
the colours of the mode line.
Ensured that diary and holiday colours are distinct and legible,
without being too intense.
Changes to the manual or other documentation
Updated the doc string of the primary customisation group defined by
the themes to reflect the support for the case of tritanopia.
Included links to the web page of the manual and the one with the
sample pictures in the customisation groups. Those links appear in
the various Custom UI buffers.
Introduced an annotation function for all commands that involve
minibuffer completion. The annotations display the one-line
description of each theme, making it easier for a user to pick their
preferred choice (e.g. when using the modus-themes-select
command).
Defined semantic colour mappings for “marks”. These are used by
dired, trashed, proced, and others. These is no change to the
default appearance of what users are already familiar with, though
it is now possible to override those styles.
Complemented the subset of semantic colour mappings for
errors/warnings with “prominent” variants. Those employ a
background and foreground combination. They are used in all sorts
of contexts, such as for fringe errors (flymake, flycheck, …),
query-replace, isearch-fail, and others.
Wrote sample code on how to add “padding” to the Emacs frame and the
space between the Emacs windows. This makes for a presentation that
some users find easier to work with.
Corrected the sample code for git-gutter to use the appropriate
symbols from the theme palette. Thanks to Christian Tietze for the
patch: https://lists.sr.ht/~protesilaos/modus-themes/patches/40354.
The change is small and does not require copyright assignment to the
Free Software Foundation.
Removed moody from the list of packages explicitly supported by
the themes. We stopped supporting it since version 4 that removed
the relevant user option for the mode line. The idea is that the
mode line is better handled by the user without interference from
the theme, due to the number of options available (and how brittle
those can be when interacting with unpredictable face definitions).
Thanks to Nicolas De Jaeghere for reminding me to remove moody
from the manual:
https://lists.sr.ht/~protesilaos/modus-themes/%3Cypi9jzyclqxy.fsf%40gmail.com%3E#%3C87jzybdgg1.fsf@dejaeghe.re%3E.
Miscellaneous
Added two new preset palette overrides to make the overall
presentation “warmer” or “cooler”. Those are called
modus-themes-preset-overrides-warmer and
modus-themes-preset-overrides-cooler, respectively. The manual
explains how those presets can be used. I suggest the user does
not add such overrides if they intend to load any of the
deuteranopia or tritanopia themes, due to the specific
requirements of their design.
Refined the deuteranopia yellows for warnings, errors, and comments.
These otherwise slight adjustments make it considerably easier to
tell apart distinct elements that may be positioned close together.
Tweaked the deuteranopia semantic colour mappings for emails. The
subject line use a more appropriate colour value, while level 3
quotes stand out a bit more than they did before, without being
needlessly intense.
Arranged for the modus-themes-load-theme function return the
value of the THEME argument it accepts. The intent is to allow
other functions that call this one to capture the return value for
their purposes (such as with a let binding). Thank to Oliver
Epper for the feedback in issue 78 on the GitHub mirror:
https://github.com/protesilaos/modus-themes/issues/78.
The other day I wrote about installing elfeed-webkit to render my RSS feed as proper HTML. I was pretty impressed with it when I first tried it and now I’m even more of a fan. Before elfeed-webkit, I spent a lot of time switching between Elfeed and Safari so that I could read interesting posts that came up in the feed. It doesn’t seem like it would take that much time but since the change, my RSS workflow seems faster and easier.
A secondary advantage is that Emacs has more functionality now that I have XWidgets enabled. At first I wondered if I could get eww to do a better job rendering sites by using Webkit. That turned out to be a bust but I did discover xwidget-webkit-broswse-url that will render a site in decent HTML but it’s not a proper Browser so it’s pretty much restricted to viewing a specific URL. You can follow links and control videos but there are no bookmarks, content filtering, or other Browser amenities. Still, it does help keep me in Emacs and a lot of times I just want to visit a page from Emacs and it works perfectly for that.
In my original post, I noted a couple of problems. The first was the possibility of being inundated with ads because of the lack of content filtering. That’s basically a nonissue for the sites I read although occasionally a feed item will send me off to a “commercial” site that does have a lot of intrusive pop-up adds but it doesn’t happen often.
The second problem was that I couldn’t get t to toggle elfeed-webkit on and off. I thought maybe something else was grabbing the t binding to I changed it to w but that didn’t work either. I solved that by binding a global key to toggle elfeed-webkit and that worked fine (but see below).
Finally, I recently upgraded my email client mu/mu4e and a helper function I wrote to display the post in eww stopped working. While investigating that, I discovered that mu4e will display an email with webkit, which is what I really want so I’m now using that instead of eww.
While investigating the email issue I discovered that the XWidget library does indeed capture the t key as well as the w key. The t doesn’t appear to do anything useful as its definition
shows. I don’t know how it was working for Grabo; perhaps he’s using the Emacs 29 pretest and it has removed the useless binding. In any event, I simple changed my toggle key to x and now it works perfectly.
That leaves only one small problem. One of the sites I follow, Daring Fireball, has the unusual property that its RSS URL is not the site itself but the site it’s linking to. That means that I miss the Daring Fireball commentary and go straight to the linked site. I’m considering adding code to implement a tag that inhibits rather than enableselfeed-webkit. In the meantime, I’m simply toggling elfeed-webkit off when I get to a Daring Fireball post.
All in all, I’m really happy with elfeed-webkit and recommend it wholeheartedly.
I had tried to implement a debugging logging/print method myself using macros but hadn’t really achieved the level of elegance outlined in https://xenodium.com/sprinkle-me-logs/
I added a couple of programming modes to the function defined in the post above and have now incorporated it into my workflow:
For some reason I always seem to tend to ribald statements within my code, something like poop or some other unsavoury variant, I just need to remember to tidy these up later on!
Oh and I added an old fashioned emacs badge to the top of this blog just for fun! as technically it is kinda true as in this web page and of course as in me as a human 😀
I am working towards the next major release of denote. There
already are lots of goodies in the works. A new one among them is the
global minor mode denote-rename-buffer-mode. It automatically
renames the buffer of a Denote file upon visiting the file. A buffer
is renamed only when visiting the underlying file. This means that
existing buffers are not renamed until they are visited again in a new
buffer (files are visited with the command find-file or related).
For example, I enable the mode and then visit a file whose name is
20230507T084817--software-freedom-and-accessibility__linux_politics.txt.
Normally, that would also be the name of the buffer. Whereas now the
buffer is called Software freedom and accessibility.
[ If you are unfamiliar with Denote, consult the comprehensive manual
or at least watch the video demo I did of its original version.
Links below. ]
Customize the user option denote-rename-buffer-function to affect
how buffers are renamed. Its value must be the symbol of a function.
The default is the denote-rename-buffer-with-title, with an
alternative of denote-rename-buffer-with-identifier.
The user option also accepts an arbitrary function. Refer to the
implementation details of denote-rename-buffer-with-title or
denote-rename-buffer-with-identifier for guidance on how to write a
custom function.
Note that renaming a buffer is not the same as renaming a file
(Denote can do both). The former is just for ease-of-use inside of
Emacs. Whereas the latter is for writing changes to disk, making them
available to all programs.
I don’t know when I will be able to release version 2.0.0.
Hopefully soon.
Denote is a simple note-taking tool for Emacs. 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.
Denote’s file-naming scheme is not limited to “notes”. It can be used
for all types of file, including those that are not editable in Emacs,
such as videos. Naming files in a consistent way makes their
filtering and retrieval considerably easier. Denote provides relevant
facilities to rename files, regardless of file type.
Just a quickie. I stumbled across a post from Andrea that describes his package Org Blk URI. It’s pretty simple: it’s just a way of extracting the content at a URL into an Org source block.
That’s handy for capturing Web content that is apt to be ephemeral. The example Andrea gives is a job ad and, of course, we’ve all run across Web pages that might not remain available but that we’d like to retain. This package is a nice way of capturing them into an Org file that we control.
I haven’t installed yet but it seems like a handy tool to have.
Surprisingly for me I just discovered that Emacs Lisp has equivalent
of Clojure’s -> and ->> macros.
And I’m not talking about dash.el. I’m talking about built-in thread-first and thread-last.
What are these
If you’re not familiar with these beautiful macros, the main goal is to pipe a value through multiple functions
and return the result.
-> passes a value as first argument of next function, then takes the result and passes it as first argument to next function, etc. ->> does the same except that it passes the result as next function’s last argument
Example
Instead of having this:
(+(-(/(+520)25))40)
we can have this:
(->5(+20)(/25)-(+40))
It’s way easier to modify and which is even more important - to read.
Emacs lisp equivalent
There is dash.el library that provides us with similar macros (and many more) but emacs has built-in thread-first and thread-last.
(thread-first5(+20)(/25)-(+40))
will work for you if you’re on Emacs 25 or newer.
I don’t write much elisp but every time I do I feel like I miss those ->/->>.
The next version of Emacs is around the corner, so I think it’s time to talk about how you can start using one of the more impressive additions to Emacs 29: tree-sitter. Briefly, tree-sitter is a library that transforms source code – or any other structured text, like Markdown – into a concrete syntax tree. I’ve written about tree sitter and the complications of parsing languages and why it’s a big deal: correct syntax highlighting; cleverer editing and movement; and better indentation are just some of the benefits of tree-sitter.
And in Emacs 29, support for tree-sitter is built in. Sort of. It’s an optional extra, so you must compile Emacs from source, or hope that someone else will do it for you. In my experience, unless you’re using a bleeding-edge Linux distribution, you’re in for quite a wait. So I’ve compiled a guide on how to get started with tree-sitter in Emacs: not just the compilation, but how to get started using it. You see, getting everything to work properly is a bit more involved than just compiling Emacs with tree-sitter support.
My package, Combobulate, adds advanced editing and movement using tree-sitter. This is Combobulate's expand region feature, bound to M-h.
Despite the high activation cost of getting tree-sitter up and running, I firmly believe it’s worth it. Here’s what you’ll need to do to get it set up.
Building Emacs with Tree-Sitter Support
Note that these compilation instructions cover Linux, and use Ubuntu/Debian as the example distribution. Tree-sitter will also work on other platforms, like Microsoft Windows. For compiling or installing the grammars on more platforms than just Linux, see below.
Grab the latest Emacs sources from Savannah, Emacs’s official git repo. Once Emacs 29 is out you can use the official tarballs instead, but for now I recommend you check out the emacs-29 branch, or just master if you’re OK with living life on the bleeding edge. I always use master:
Next, you’ll need to install the prerequisites required for Emacs to compile. With Debian/Ubuntu-based systems, that is easy, as you can rely on apt-get build-deps to do the heavy lifting by having it install the dependencies for one of the Emacs versions it your distro does support.
Building Emacs is not hard, and the simplest way to do this is to follow my existing guide where I detail how to do all of this, step-by-step, to get native compilation working:
If you’ve never bothered with native compilation, you should: it provides a significant speed boost. You may as well build Emacs with it also.
I would urge you to get this step working first: we’ll amend it slightly to add tree-sitter support (and other optional goodies) next. The approach outlined in that article is the barebones version of Emacs, but once you get it building on your system, you can easily recompile Emacs from scratch with additional features, as needed.
Next, you’ll need to check out tree-sitter’s source code:
I, once again, stick to the master branch, but you can use a tagged release if you prefer a stable release.
Your distro may already include tree-sitter as a package, as in the case of Debian:
$ sudo apt-get install libtree-sitter-dev
That is occasionally enough to install tree-sitter so it works with Emacs. However, given how easy tree-sitter is to install, having no real depencies of its own, and it being a rather fast-moving project, I recommend you just build it from source also.
Time to build tree-sitter. Provided your Emacs builds, so should tree-sitter:
$ cd tree-sitter/
$ make
$ make install
That is all it takes. Note that make install normally requires root. It’ll install a shared library to (usually) /usr/local/lib.
In theory, that’s all it takes for Emacs to compile with tree-sitter support. However, if Emacs complains during the build that it can’t find the shared library libtree-sitter.so, try this:
$ export LD_LIBRARY_PATH=/usr/local/lib/
And retry building Emacs.
Now you can start building Emacs with tree-sitter. I’ll assume you followed my other tutorial and you’re now at a point where Emacs builds (without) tree-sitter. Now all you need to do is add --with-tree-sitter (technically, it should detect tree-sitter automatically, but I prefer being explicit) to the call to ./configure:
Now run make then make install. Everything should build and link and you’ll wind up with your own build of Emacs.
That takes care of Emacs. Unfortunately, that is not enough to reap the benefits of tree-sitter. We’ll have to install some language grammars also.
Installing the Language Grammars
Neither tree-sitter nor Emacs come installed with language grammars. Just like kids’ toys and batteries, they’re sold separately. So you’re required to download and compile the sources for each language grammar you want to use.
You must compile each language into a shared library and put in a place where tree-sitter can find them. It is not especially hard to do so, but it can be a frustrating experience as it’ll depend on: your platform; your choice of compilers; whether the grammar author chose C++ or just C, and so on. Furthermore, there is often no Makefile, so you have to tell the compiler yourself to build a shared library.
Luckily, there are two simpler ways than the manual way: the builtin method in Emacs, or relying on the kindness of strangers.
Before I explain both methods, I must point out that, at the end of the day, regardless of the method you choose – and especially if you’re compiling the grammars yourself – that you must put them in a directory where Emacs and tree-sitter can find them:
Emacs will look in treesit-extra-load-path if you have it set;
Then, in a subdirectory called tree-sitter under user-emacs-directory — e.g., ~/.emacs.d/tree-sitter/.
And finally it’ll look in all the usual /lib locations scattered around your filesystem.
I prefer the Emacs directory approach myself. The grammars are small and, unless you make it a habit to swap between wildly different system architectures, you can safely commit the shared libraries to git and lug ’em around with you.
Anyway. Let’s install the grammar libraries. Onwards!
Compiling and Installing with the builtin method in Emacs
This is perhaps the simplest, but it’ll only work if you don’t have an exceptional setup (so it won’t work well unless you have GCC and run some flavor of Linux.) But if your Linux installation’s plain as day, expect this method to work fine if you successfully compiled Emacs and tree-sitter from scratch.
The command M-x treesit-install-language-grammar installs a language grammar by first cloning the git repo hosting it and then compiling it and storing the shared library in your .emacs.d directory.
In order to determine where – and what – it can install, you must first tell Emacs where to find the language grammars. The variable treesit-language-source-alist is a simple alist that expects a form in the format of (LANG . (URL REVISION SOURCE-DIR CC C++)). Where only LANG and URL are mandatory. Leave out the rest and Emacs will try to do the right thing. It is not customizable using the Customize interface, unfortunately, so you must set and edit it manually.
As you can see, there’s not much to it. A couple of the languages require a little path and branch fiddling as their directory structure differ from the accepted standard.
Once you’ve found the languages you like, you’ll need to install them. Call the command M-x treesit-install-language-grammar for each language and that’s usually all there is to it.
If that’s too much manual work, just bulk install all of ’em in one go. Evaluate this elisp form to do so:
It can happen that LANGUAGE is named differently than the shared library. In the unlikely event that happens you can use treesit-load-name-override-list. You’re more likely to encounter this if you’re using competing grammars for the same language, or if the name does not match the shared library name.
Every language has a function entry point named tree_sitter_<LANGUAGE> in the library, and if the <LANGUAGE> does not match up with the filename (usually libtree-sitter-<LANGUAGE>.so), Emacs won’t load the module. This is not the case with the example I gave above, but you may run into it if you’re using niche language grammars or if you want multiple ones serving the same language (for some reason.)
Before Emacs 29 added tree-sitter support, Tuấn-Anh Nguyễn created a third-party tree-sitter package that adds tree-sitter based font locking and support for tree-sitter in all modern versions of Emacs. It’s excellent, though it has a number of limitations (mostly due to Emacs’s dynamic module system more than anything else.) But if you want tree-sitter support in older Emacsen, you should check it out. It’s a MELPA package install away and it pretty much works out of the box.
Nevertheless, Tuấn-Anh also took the time to build a CI release system that tracks a large portion of the most common language grammars — complete with builds for Windows, Mac and various Linux architectures. Really superb work.
So if you’re on Windows or if you find the idea of building the grammars cumbersome, you should give his precompiled packages a shot.
You can find them on his Github releases page. You can also download the tree-sitter-langs package from MELPA, but I recommend you just download the shared libs directly instead, as you’ll in any event have to rename them and place the grammar libraries somewhere else.
The names of the files are <LANGUAGE>.so (or with your platform’s equivalent extension) which is not in keeping with the expected naming style in Emacs. You must first rename them so they’re named libtree-sitter-<LANGUAGE>.so. This is as good a time as any to learn how to bulk rename them with Emacs’s M-x dired and the editable dired buffers feature.
Once they’re named appropriately, put them in the directory called tree-sitter in user-emacs-directory. Or pick another place for them, as per the search path order I wrote about earlier. But for most of us, putting them in ~/.emacs.d/tree-sitter is good enough.
Check if a grammar is working
Determining if a grammar is available is not intuitive nor obvious unless you use elisp. You must call the treesit-language-available-p function to check:
ELISP> (treesit-language-available-p 'python)
t
ELISP> (treesit-language-available-p 'klingon)
nil
Emacs will return t if it’s a known language and nil otherwise. Use this to check if you’ve compiled, installed or copied (all depending on the method you chose) the grammars correctly.
The other thing to keep in mind with the grammars is that they are not versioned! There is no version tags beyond the git commit hash to help you determine which version of the grammar you have. That’s mostly of interest to major mode developers or people like me that build structured editing and movement packages on top of tree-sitter. I recommend you reinstall the grammars every now again to keep up with changes, for package authors have no easy way of checking.
How to use Tree-Sitter
Yep. This part needs a tutorial introduction also. Emacs now implements a very different way of font locking (syntax highlighting) than most – though not all! – major modes in Emacs, as most of them use regular expressions to feed Emacs’s font lock engine with syntactic information. Now that it’s using an actual syntax tree to extract information, Emacs is a lot more accurate.
Because of the complete 180-degree turn in, well, almost everything, the Emacs developers decided against wedging tree-sitter support into the existing modes. Instead it’s relegated to its own, “TS”-powered, major modes. I understand why – some of the major modes are complex and naively cramming tree-sitter-powered features into them will require more longer-term engineering effort to sort out than they can currently muster – but it’s still, well, they’re different modes, with all the drawbacks and benefits that bring.
Modes that use tree-sitter are all named <major-mode>-ts-mode. That’s the naming standard and it does mean you can quickly check if Emacs supports your pet major mode out of the box: typing C-h a -ts-mode$ should do the trick. The apropos window will list all known tree-sitter major modes.
Note that, just because you have installed a grammar, does not mean Emacs supports it. Someone still has to write the – admittedly, way easier – syntax and indentation logic and all that good stuff.
One interesting outcome of tree-sitter support is that Emacs has now gained new major modes it did not have before. Like dockerfile-ts-mode.
So to use tree-sitter you must activate the new major mode manually. Emacs will, by default, use the existing major modes, even if you have everything set up correctly.
To coax Emacs into using the new major modes by default, you’ll have to either:
Edit auto-mode-alist, interpreter-mode-alist, etc. and change over all the references you care about to use new <LANGUAGE>-ts-mode major modes; or…
Use major-mode-remap-alist, an icky hack that maps one major mode symbol to another behind-the-scenes. That feature, rather conveniently, debuted in Emacs 29 also.
Hacky though I think it is, I’d pick the major-mode-remap-alist for now: it’s easy to get started with, and you can always migrate everything to the harder, and more explicit, way once you’re happy with your new tree-sitter-enabled major modes.
Here’s an example, and this time you can instead use M-x customize-option to customize it to your liking, if you prefer the customize interface.
As you can see there’s not much to it. Whenever Emacs is asked to activate css-mode, it’ll instead call css-ts-mode.
Despite the major mode switcheroo gimmick, it does not remove most of the obstacles and annoyances of having a new major mode.
At this point, I’d try out some of the major modes you want to use. Annoyingly, there’s no easy way to see if you’re using the normal or the TS-powered major mode: you can look at the lighter in the mode line, but it’s often the same text as the normal mode. The quickest way to tell is to type M-: major-mode and you’ll see which major mode you’re using.
I’ve heard tales of the TS-powered major modes being “temporary”, but… there’s nothing so permanent like a temporary solution. I understand why the distinction has to exist (for now), but it’s still awkward, and this approach does leave a number of unsolved problems you’ll still have to solve yourself:
You must duplicate and/or change your mode hooks. python-mode-hook is distinct from python-ts-mode-hook, and you should ensure you copy over your settings.
Your indentation customizations (if you have them) may not work. Indeed, any customizations you’ve applied to one mode won’t necessarily apply. They might, but there’s no guarantee they will. It comes down to the mode and the feature.
Font lock faces are now more detailed and expressive than ever before. This is one area you probably definitely will and want to customize, if only to take advantage of better syntax highlighting.
Third-party packages will blithely assume you’re using the default major mode and not your turbo-charged tree-sitter equivalent, and so they may not activate or work at all in the TS-powered one. It’ll take a while for this distinction to percolate, and for packages to check for one or the other.
Most TS-powered modes ‘derive’ from the original major mode, with varying levels of overlapping customizations and features. The best way to see what your new major mode can (or cannot) do is, uh, well.. to read the source. Sorry.
Nevertheless, it’s worth the pain, as you’ll only have to do it once.
Tweaking the Font Locking
One of the benefits of having a concrete syntax tree is precision. Emacs is now capable of precisely highlighting things it couldn’t before: it can distinguish function calls from keywords or identifiers. To better support that, there’s now a host of new font lock faces.
Due to the large array of things you can color, Emacs now separates its font locking into font lock features. This feature’s akin to the long-existing font-lock-maximum-decoration that the chromatically averse can tweak to disable some or all of Emacs’s coloring if it’s too ostentatious. If you belong to that cohort – most of whom refer to this as “angry fruit salad” – then you’re in for a technicolor razzle-dazzle.
Every TS-enabled major mode will decide on its own list of features. The features are buffer-local and set in treesit-font-lock-feature-list, with each sub-list representing a level of highlighting. If you want to change it, you’ll need a mode hook to alter it properly.
For most, it’s enough to change the font lock feature level. To do so, customize treesit-font-lock-level. Every incrementation of the level will color more and more things: one you reach the higher echelons, it does become a bit much, even for me. But it’s great to have that flexibility and the power to decide which things should, and which things should not, be highlighted.
NOTE: treesit-font-lock-level has a special setter attached to it, so as to automatically recompute the font lock features in all your buffers when you change the level. If you use Customize, then you don’t have to do anything, but if you normally use setq, you’ll have to use customize-set-variable instead to ensure the setter is called properly.
It’s worth experimenting with the font lock level: the default is conservative and in line with what Emacs normally font locks. This is one of the capstone features of tree-sitter, and you should absolutely tweak it to your liking. To go along with each feature is an equivalent font-lock-<feature>-face. You can list all the pertinent faces with M-x customize-apropos-faces RET ^font-lock-. It’s very likely your theme (or your own face customizations if you maintain your own faces, like I do) is missing these customizations, so be sure to check, as their defaults make everything look rather samey.
The general intent behind the level is that you set it once and you get – approximately – the same general style of font locking in all TS-powered modes. I think that intent holds up rather well, even though what gets font locked, and how, is up to each major mode author.
Inspecting the Tree-sitter tree
One benefit of tree-sitter is access to the live concrete syntax tree of your source code. You can inspect the tree in a buffer with M-x treesit-explore-mode and M-x treesit-inspect-mode. There’s a lot more you can do with it, so I recommend you consult the manual, or stay tuned for more in-depth articles on this topic here!
“Fixing” the S-Expression Commands
Emacs has had s-expression-based commands for decades. They’re bound to keys like C-M-f, C-M-SPC, and C-M-k.
They work well in a wide range of languages because they’re delightfully dumb: they look for structured expressions – such as ( and ), " and ", and so forth – and treat them as cohesive, syntactic ‘unit’. In the absence of such structured units, they fall back and behave much like word-based movement and editing.
Not so in tree-sitter major modes. They’ve been “upgraded” to try and guess the syntactic units you probably want to move over or edit.
That sounds like a great idea until you realize that it is not possible to make one-size-fits all commands that do this. Believe me: I’ve tried. Every language is different, and even a modest language grammar will have hundreds of node types and millions of combinations. Whereas before you could predict where point would end up after calling these commands, now you probably can’t. Worse, the commands do not mirror the old behavior at all: they’re erratic and unpredictable.
If you already use these commands, and you also dislike this unwanted and unasked for change in behavior, then you can use this snippet to revert to the old way:
Combobulate can insert multiple cursors (if you use it); move around your code structurally; insert syntax-aware code templates; and much, much more.
One of the tantalizing things that a library like tree-sitter offers is better and more correct editing and movement that understands the syntax of your code. That’s one of the things my package Combobulate sets out to do: to provide advanced editing and movement across a swathe of languages.
Now that you’ve gotten tree-sitter working, why not take my Combobulate package for a spin? It’s a work-in-progress still, so expect bugs, but it’s got a host of useful features that’ll speed up your day-to-day coding.
I got a new laptop: Lenovo ThinkPad X470 (EDIT 2023-05-27 11:39 +0300:
it’s T470, not X470). This is a gift from Anush V, to whom I am
thankful. I will be using this device to experiment with Guix, a
distro I have been following since ~2017 but never had the hardware to
test it on. These will be my first impressions.
The video is recorded and can be viewed at any time. No worries if
you cannot make it. I am posting this on 09:08 +0300.
Emacs consists of a massive set of tools with a long history. Therefore, whatever the problem is, someone likely has already created a package for it. In many cases, this package is already baked in Emacs. This is great for veterans but very confusing to newcomers - like me.
The three modes Emacs comes with three modes for input completion: Icomplete, IDO, and FIDO. Input completion works with whatever you select in the Minibuffer section.
Adding hooks and setting variables is core to customizing Emacs. Take a major mode like
emacs-lisp-mode as an example. To customize its behaviour, one may add a hook function to emacs-lisp-mode-hook, or if you're a little lazy while experimenting, you may even use a lambda.
The lambda can be removed too, but you ought to be careful in using the same lambda body.
(remove-hook 'emacs-lisp-mode-hook
(lambda ()
(message "I woz tere")))
There are other ways to remove the lambdas, but we're digressing here… We typically have to write these throwaway snippets to undo our experiments. What if we just had a handy helper always available to remove items from sequences (edit: we do, remove-hook is already interactive, see Update 2 below)? After all, hooks are just lists (sequences).
While the interactive command can likely be simplified further, I tried to optimize for ergonomic usage. For example, completing-read gives us a way narrow down whichever variable we'd like to modify as well as the item we'd like to remove. seqp is also handy, as we filter out noise by automatically removing any variable that's not a sequence.
Hooks are just an example of lists we can delete from. I recently used the same command on display-buffer-alist.
While this has been a fun exercise, I can't help but think that I'm likely re-inventing the wheel here. Is there something already built-in that I'm missing?
Update 1
alphapapa suggested some generalizations that would provide an editing buffer of sorts. This is a neat idea, using familiar key bindigs C-c C-c to save and C-c C-k to bail.
Beware, I haven't tested the code with a diverse set of list items, so there's a chance of corrupting the variable content. Improvements to the code are totally welcome.
"While this has been a fun exercise, I can't help but think that I'm likely re-inventing the wheel here. Is there something already built-in that I'm missing?"
I just stumbled across a post by Fritz Grabo about his package elfeed-webkit. When I first saw it, I thought it was interesting and worth a look. After reading more about it, I knew I had to install it. That wasn’t entirely easy because I had to recompile my Emacs to support xwidgets. But I liked the idea of the package enough to press on and add xwidgets to my Emacs.
After that, it was simply a matter of installing elfeed-webkit from MELPA. When I toggled it on with Meta+xelfeed-webkit-toggle all my elfeed results were rendered directly in the Elfeed buffer. Sometimes—for example, when I want to save a page for an Irreal post—I need to go to the browser and rerender the page. That’s simply done by pressing the v key.
You’re supposed to be able to toggle elfeed-webkit on and off with a t after you configure it in your init.el but I can only get it to toggle on, not off. Doubtless, I have some misconfiguration but that’s research for another day. You can also add a tag to individual feeds to turn it on but I haven’t tested that yet (I installed it just before I started this post).
So far, I really like this package. It (mostly) keeps me in Emacs and renders the pages perfectly. A comment in the original reddit post complained that Webkit was going to deluge my feeds with dozens of ads but I didn’t notice that with my admittedly limited testing. The nice thing is that you’re not really committed. It’s easy to turn it off or even uninstall it if you don’t like it. The worst that happens is that you end up with support of xwidgets in your Emacs.
Please note that planet.emacslife.com aggregates blogs, and blog authors might mention or link to nonfree things. To add a feed to this page, please e-mail the RSS or ATOM feed URL to sacha@sachachua.com . Thank you!