🏠 About Now Archive Tags RSS

Posts tagged "emacs":

The good side-window side

I want the content I am working on to be the centre of attention on my screen. I want as little scrolling as possible and most of the content I work with is taller than it is wide (code and org documents). On wide screens, buffers with shells, for version control, REPLs, help, info etc should therefore be on the side of the screen where it does not steal space from the main content. Since I read left to right, I like such windows to pop up on the right side where they do not disturb the flow of my reading of the main content. Emacs has the concept of side-windows that is useful for taming buffers that would otherwise pop up other places.

I set the width of my side-windows to 80 since man pages expect that and it works well for help and shells as well. To be able to have a (wo)man page and a shell, an info node and a REPL, or a shell, REPL and help buffer at the same time, I use slots to divide up the side-window if more than one special buffer is open. I have not included ansi-term in the buffer-list for side-windows since I use it only occasionally when I want more than one terminal, in which case I need to be able to manage its windows in the normal way. Usually, there is no need for a full terminal emulator, but I use Eshell a lot.

At home, my laptops and my external screen are 16:9 or 16:10 wide screens. At my desk at work, I have a 16:9 screen, a 16:10 screen and another 16:9 screen flipped 90 degrees to the portrait orientation. I usually use the tall screen for Emacs to minimise scrolling. Since the tall screen is slim (9:16), I would rather have side-windows in the bottom instead of overlapping the main window on the right side when I use that screen. Even with the side-windows at the bottom, the screen is a lot taller than the wide screens which is nice.

However, I spend most of my time at work not at my desk, but in two classrooms where I either use my laptop only with its built-in screen, duplicated to a large screen in front of the class or only with an external screen when sitting in the back (for ergonomics). And there are also meetings where I use the laptop's internal screen only. All of these screens are wider than they are tall, so I want my side-windows on the right again.

So I made a function that checks whether the height of the frame is larger than the width and if so, side-windows are put on the bottom of the screen where they belong on tall screens, but if the opposite is true, then they are put on the right where they make more sense on wide screens. I call this function when Emacs starts in my configuration to adapt the side-windows to the screen in use, but I also have a keybinding (C-z w) for it so after moving from a classroom or meeting to my desk or vise versa, I can get the side-windows where I want them without having to end my Emacs session. I often prepare a file at my desk that I am going to present in class with inter-present-mode or jot something in a file during class that I work on at my desk later, so it is useful to keep the session going.

Here is my function for deciding which side side-windows should be on:

(defun emo-side-window-side ()
  "Evaluates which side side-windows should be on based on whether the frame is in portrait or landscape orientation."
  (interactive)
  (let* ((side-window-side (if (> (frame-outer-height) (frame-outer-width))
                          'bottom 'right))
       (disp-buf-alist `(("\\*\\(Python\\|ielm\\|compilation\\).*\\*"
          (display-buffer-reuse-window display-buffer-in-side-window)
          (side . ,side-window-side)
          (slot . -1)
          (post-command-select-window . t)
          (window-width . 80))
("\\*\\(shell\\|.*eshell\\).*\\*"
          (display-buffer-reuse-window display-buffer-in-side-window)
          (side . ,side-window-side)
          (slot . 0)
          (post-command-select-window . t)
          (window-width . 80))
("\\*\\(help\\|info\\|man\\|woman\\|Agenda Commands\\|Org Agenda\\|Occur\\|Buffer.\\|xref\\).*\\*"
          (display-buffer-reuse-window display-buffer-in-side-window)
          (side . ,side-window-side)
          (slot . 1)
          (post-command-select-window . t)
          (window-width . 80)))))
  (setq display-buffer-alist disp-buf-alist)))

Inter-present-mode

A while ago, I wrote that I made a few functions to present from org mode to replace org-present which removes too many glyphs to be practical for my use. I thought it would be nice to use use-package to defer loading these functions until I need them, and I was curious about how to make a minor mode. So yesterday, I created a minor mode around those simple functions.

I made functions for starting the presentation, going forward, going backward and stopping the presentation, so turning it into a minor mode that is turned on and then have some functionality bound to a keymap, and which you then can turn off again was a very natural fit. I added the ability to customize a few things and have some ideas for more functionality to include and more things to customize.

Have a look at the Readme.org at Codeberg.org if you want to have a look or try it out. I might try to include it in a package archive in the future, but for now, you can install it with use-package's vc: keyword.

Presentation functions

I use Emacs at work to present in class. I teach basic IT technology, programming and development, so it is very useful to be able to run code blocks interactively and get them syntax highlighted. If I get questions from the students, I can change the code to explain other ways of doings things or show them how small changes can yield very different results. I also quite often add additional useful information from the students into the slides while presenting if they mention something worth noting. I have written about this before.

I have used org-present to present from Emacs Org files thus far. It has been good in many ways, but there have been a few annoyances as well. One thing that has bitten me many times is that it hides too many characters. This means that when I show things like == on screen (except in code blocks), it looks like =. This is very annoying when teaching programming. It also ruins org tables since it removes + which means that tables with vertical lines that are fully aligned normally show up misaligned. I have stopped using lines to separate headings and content in tables, but it is not ideal. I have used org-present for two years now, and there is no way to configure it to remove these annoyances, so I am ready to switch to something else.

Today, I found some time to look into this and made a few, simple functions that does exactly what I need and nothing more. It is just ten lines more than my previous configuration for org-present. And since it is part of my Emacs config, there is no need to install additional packages. I almost always start presentations from the the start with the title, so my emo-present-start function does that. There is a bit of a rough edge in that it shows metadata keywords like #+Title: and #+Options: toc: nil when I present the title. I might sandpaper that rough edge off in the future. Otherwise, it works better for me than org-present and with a lot fewer lines of code.

Fix popup windows in Emacs

Whenever you use a function that pops up a window in Emacs, it can be annoying and distracting. The buffer often take over one of the windows you already have on screen and that you are actively working in. For example, when using Python mode, I often felt that it was a bit random where the Python Shell buffer would show up when invoked with C-c C-p. The same problem occurs with help buffers, shell mode, eshell, ansi-term, async-shell-command, man, woman, occur etc. It isn't actually random, but the rules governing in which window new buffers show up, in the variable display-buffer-alist is quite opaque to a new user, so it seems random.

I lived with this seeming randomness for a while, but it annoyed me. Then I came across a video by David Wilson of SystemCrafters that showed me how I could use the concept of a side-window to not have popup windows take over my other windows. I also looked at his Emacs configuration and stole some of his settings. It solved the annoyance of popup windows taking over my other windows. He places his side-window in the bottom third of the screen. It makes sense when you want to pop up a shell or terminal, write a few commands and then close it again which you often see David do on his videos.

I also watched a video by Protesilaos Stavrou about side-windows where he explained the concept of slots. It solves the problem you have when you have more than one side-window from a popup buffer open at the same time. Maybe you have a help buffer and shell mode for instance. Prot also uses the lower part of his screen for his side-windows.

Since almost every screen is wider than it is tall, I think a better placement for user interface elements and extra information is on the left or right, not the top or bottom of the screen. Most content, except a few videos and pictures, are higher than they are tall. I want the content I am working on to take up as much as possible of the screen real estate to avoid unnecessary scrolling. This is why I always turn on the sidebar and off the toolbars in LibreOffice Writer and detest the Ribbon interface in MS365's Word.

Back to Emacs. I had a look at the Emacs manual which showed me how to tweak the settings David Wilson and Prot had taught me to get what I want. I think buffers with shells, for version control, REPLs, help, info etc should pop up on the side of the screen and leave the main buffer(s) alone. I want the content I am working on to always be the centre of attention. Since I read left to right, I like such windows to pop up on the right side of the screen where they disturb the other window(s) the least. (If I read right to left, I would have had them pop up on the left.) I set the width to 80 since man pages expect that and it works well for help and shells as well. (On smaller screens like the 1366 x 768 screen on the ThinkPad X230, this feels a bit large, but on larger screens like my 1440p external screen at home, it takes up less than a third of the screen. I could have used a ratio like 0.33 to have the side-window always take up one third of the screen, but that would mean it would be wider than necessary on large screens and too small for the content of [wo]man buffers on small screens, so after trying that for a while, I went with a fixed width in columns instead.)

To be able to have a man page and a shell, an info node and a REPL, or a shell, REPL and help buffer at the same time, I use slots to divide up the side-window if more than one special buffer is open. Slot -1 ends up at the top if there are more than one special window. Slot 0 ends up in the middle and slot 1 ends up at the bottom. I have REPLs at the top, shells in the middle and documentation in the bottom. I seldom use both a woman buffer and a help buffer at the same time, but I might use for example the Python REPL, Shell mode to launch and test out a python program and an info manual with Python documentation (yes, it is available in info format) at the same time, so it is useful to use different slots. If there is one buffer, the whole side of the screen is used and if there are two, the side is split in two if they occupy different slots.

Here is the code from my Emacs config for this:

(setq display-buffer-alist '(("\\*\\(Python\\|ielm\\|compilation\\).*\\*"
          (display-buffer-reuse-window display-buffer-in-side-window)
          (side . right)
          (slot . -1)
          (post-command-select-window . t)
          (window-width . 80))
("\\*\\(shell\\|.*eshell\\).*\\*"
          (display-buffer-reuse-window display-buffer-in-side-window)
          (side . right)
          (slot . 0)
          (post-command-select-window . t)
          (window-width . 80))
("\\*\\(help\\|info\\|man\\|woman\\|.*Ibuffer*\\|Agenda Commands\\|Org Agenda\\|Occur\\|xref\\).*\\*"
          (display-buffer-reuse-window display-buffer-in-side-window)
          (side . right)
          (slot . 1)
          (post-command-select-window . t)
          (window-width . 80))))

Rethink about the prefix for my Emacs keymap

I wrote a blog post about binding <menu> as the prefix key to my own Emacs keymap and swapping CapsLock for Menu on GNU/Linux and its closest equivalent, <apps> on Windows. (I have deleted that blog post since I realised doing that was dumb, and I don't want to steer others down that path.) It worked as long as I used Emacs in its GUI on Windows 11 or Wayland. However, when I installed Guix on my laptop and was trying to figure out how to get Sway running on Guix, I naturally used Emacs in the TTY where it works just as well as in a graphical session except some limitations around showing pictures, using multiple faces and keybindings. TTYs and graphical terminals doesn't send through every key to Emacs and one of the many newer keys they don't send to Emacs is <menu>. So I was left with none of my own keybindings. It made me realise that using any special key not usable in a TTY for my own keymap is not very smart.

There is always M-x, so I could do everything I wanted to do, but without using my own keymap. The advantage of having a keymap that works everywhere is that it makes using commonly used functions a lot faster than using M-x. If the keymap isn't available everywhere, the advantage of having a keymap at all is severely limited and you have to think about in which situations it is usable and in which it isn't. Training oneself to remember the keychords through muscle memory also make little sense if it is only available some of the time.

I had a quick think about which possible prefix keys I could use that would work everywhere and in theory, every combo with ctrl or meta is usable except a few that has special meaning in a terminal like C-i and C-m. However, it is important not to remove a keychord I already use a lot for its original functionality to use it as the prefix for my own keymap instead, and I don't want a situation where a keychord both has its own functionality that I sometimes use and also is the prefix key for my keymap. That would be confusing and annoying to work with. I don't use C-z to iconify GUI Emacs or stop TTY Emacs, so I thought it was a keychord I could unbind and then use as my prefix.

Below is the code from my Emacs config for my keymap. It has just a few functions I use often that doesn't have a keybinding by default and a few of my own functions. Using it makes me faster than using M-x.

(global-unset-key (kbd "C-z"))
(define-prefix-command 'emo-map)
(global-set-key (kbd "C-z") 'emo-map)
(define-key emo-map (kbd "a") 'tempo-complete-tag)
(define-key emo-map (kbd "b") 'tempo-backward-mark)
(define-key emo-map (kbd "c") 'org-insert-structure-template)
(define-key emo-map (kbd "d") 'org-display-inline-images)
(define-key emo-map (kbd "e") 'elfeed)
(define-key emo-map (kbd "C-e") 'eshell)
(define-key emo-map (kbd "f") 'tempo-forward-mark)
(define-key emo-map (kbd "h") 'emo-hjemmeside)
(define-key emo-map (kbd "i") 'emo-ispell-toggle)
(define-key emo-map (kbd "l") 'org-toggle-link-display)
(define-key emo-map (kbd "m") 'mu4e)
(define-key emo-map (kbd "o") 'emo-dired-convert-to-org)
(define-key emo-map (kbd "C-s") '(lambda () (interactive) (emo-present 'toggle)))
(define-key emo-map (kbd "s") 'shell)
(define-key emo-map (kbd "t") '(lambda () (interactive) (ansi-term "bash")))
(define-key emo-map (kbd "y") 'emo-systemcrafters)

Convert any file pandoc can read to org

I got an idea from an EmacsElements video by Raoul Comninos where he converts docx and odt files he finds with dired to org format with two separate functions. Doc-view mode is nice for viewing files from MS365 and LibreOffice and other programs that use Open Document Format with the help of unoconv (which comes with LibreOffice), but you cannot edit the files. So he made these two functions to convert it to Org markup which Emacs edits well in Org mode. After editing, he can export a .docx or .odt to send back to the people that sent him the original file.

Export of .docx is the reason my Emacs config installs ox-pandoc which exports to .docx through pandoc, so I have experienced the same need occasionally even though I am lucky that most of the documents I use at work are pure text files with either code or org markup I use for interactive presentations in class with org-present.

I thought that I could convert any file format to org by using its extension as the from format for pandoc instead of having separate functions for different file formats. It seems to work. My function will either convert the file if pandoc can use it as input or give an error. I had to open the async-shell-command buffer with switch-to-buffer because I normally hide this buffer from popping up to avoid unwanted distractions when using async-shell-command, but for most users, this is not needed.

I bound the function to C-z o in my own keymap to make it easy to open a file. The idea is to use this function in dired. I usually get .docx files for reading only through Teams at work which I usually read in the browser where I also use Teams, but occasionally, I need to edit one and I thought this function might save me an excursion outside my favourite text editor.

(defun emo-dired-convert-to-org ()
  "Converts files pandoc can convert to org files for easy editing. Use in dired."
  (interactive)
  (let ((endelse (file-name-extension (dired-get-file-for-visit)))
        (filnavn (dired-get-file-for-visit)))
    (async-shell-command (concat "pandoc -f " endelse " -t org --wrap=none " "\"" filnavn "\""))
    (switch-to-buffer "*Async Shell Command*")))

Emacs' built-in tempo mode for templates (snippets)

A reason to use LLMs that is often repeated is that they can write boilerplate which speeds up the programmer. Why not use templates or snippets instead? They use far less energy and do not contribute to climate change or nuclear waste unlike LLMs, they don't hallucinate, you don't have to give US$ 200 a month to Microsoft to get half-decent results, they don't ruin the internet with scraping, they don't ruin text based browsing, you know the output is correct since you wrote it yourself, you will never get sued for using your templates or snippets unlike LLM code whose legal status is questionable because of stolen, non-licensed and copyleft licensed training data, and you waste less time trying to "engineer" a prompt that will yield a usable result. There is some work up-front writing the templates or snippets, but you do that once and reap the benefit for as long as you use the same editor or IDE. I anticipate using GNU Emacs for the rest of my life since it has already been around for 40 years (or 52 if you count MIT Emacs) and is still developed for and by a vibrant free software community, unlike most IDEs and text editors which seldom survive more than a decade or two.

I have been thinking for a while that I would check out the snippet package Yasnippets which is recommended by a lot of Emacsers. I discovered tempo recently by stumbling upon Thomas Ingram's website. Tempo is a built-in template or snippets package in Emacs without any built-in documentation (unlike most Emacs packages). There is an info manual on David KÄgedal's homepage and some examples of its use and if you follow the link to Ingram's site, there is also some information there. The documentation is very readable when you find it. I tend to prefer built-in packages unless there is functionality only available in external ones that I want or need, and tempo looked like it had many interesting features, so I tried it.

There are two main ways of using tempo. Either you insert a template into a buffer and it can ask you interactively in the minibuffer for things to fill in into the template, like for instance names of function, type annotation or variables and the like. To use it this way, set tempo-interactive to t. The default way of using it will instead insert the template into a buffer and then use the command tempo-forward-mark to go to the next place in the template where you should fill in some value. There is also a tempo-backwards-mark to go back if you change your mind about something you already filled in.

There is also a third way where you mark a region, and use the universal argument before calling the function with the name of your template. You can use this whether tempo-interactive is t or nil. This includes the region in the part of the template with the r keyword and then either prompts you in the minibuffer for things to fill in or you do it with tempo-forward-mark and tempo-backward-mark depending on your setting of tempo-interactive. This may be useful if you want to wrap some code in a function definition, a class definition, a loop or an if-statement etc.

To me, the default "non-interactive" way of using it seems the fastest, so I set tempo-interactive to nil. Since I do not anticipate that I will switch to doing it that way in the future, I wrote my templates without prompts for the minibuffer. Whenever there is a p or an r, you can wrap them in parenthesis and add a string which will become the minibuffer prompt if you use tempo with tempo-interactive set to t, but this is optional and not needed if you, like me, use it the default way.

There are also different ways to insert a template into a buffer. Every template becomes a function you can run interactively with M-x with the name "tempo-template-" and the name you have given your template. The other way of invoking it is to write a tag and then run the function tempo-complete-tag which replaces the tag with the template. Thomas Ingram also writes that you can use abbrev mode to insert a template with the help of its function name, but since I have yet to learn abbrev mode, I thought using tags and binding the function to replace them with templates would be fastest for me. It also avoids having to configure tempo templates another place in the config, so even if/when I learn abbrev mode, I may continue to use it this way.

I have my own keymap using the menu key which I have rebound my CapsLock to on my GNU/Linux machines, and which I have as a separate key next to Alt gr on my Windows 11 work laptop. I could have bound Caps to Hyper on GNU/Linux, but then I would not be able to use that keymap on Windows without a lot of setup. I have set menu-n to tempo-forward-mark, menu-p to tempo-backward-mark and menu-a to tempo-complete-tag. To get a template inserted, I write the tag and hit menu-a. Then I hit menu-n to go to where the next p or r is in the template and fill it in.

This way of using tempo seems very efficient so far, as long as the tag names are short enough. I thought it was a good idea to start tags related to Python with py, Elisp with el, JavaScript with js, C with c etc to keep them short. The challenge is probably to remember the tags, but as with keybindings, the ones I use often will become second nature. Since every template becomes a function with a name starting with "tempo-template-", finding templates if you cannot remember their tags is easy through M-x and completions.

The first template I made was a template to create tempo templates with the name "definition" so the function name would be "tempo-template-definition" and with the tag tempo. This template makes it easier for me to create future templates. So far I have only made two for function definitions in Python and Elisp, but I will make more and more complex ones over time. I think tempo will increase my tempo when I have written enough templates to speed up writing boilerplate. And since I use Emacs for a lot more than programming, I may use tempo for boilerplate in other text as well.

In the code block below, you can see how I have configured tempo thus far. To not slow down Emacs start-up I don't ensure that it is loaded, but load it on demand when the function tempo-complete-tag is run (which I do with the keypress menu-a after writing a tag for a template).

(use-package tempo
  :ensure nil
  :commands tempo-complete-tag
  :config
  (setq tempo-interactive 'nil)
  (tempo-define-template "definition"
                         '("(tempo-define-template \"" p "\" '(\"" r "\") \"" p "\" \"" p "\")")
                         "tempo" "A tempo template to define tempo templates.")
  (tempo-define-template "python-def"
                         '("def " p " (" p ": " p ") -> " p ":\n"
                           "    \"\"\"\n    " p "\n    \"\"\"\n    " r)
                         "pydef" "Create a Python function definition.")
  (tempo-define-template "elisp-defun"
                       '("(defun " p " (" p ")" n> "\"" p "\"" n> r ")")
                       "eldefun" "Create an Elisp function definition.")
  )

LLMs ruin text based browsing

I am an Emacs user. I have recently started to do more of my browsing in Emacs' built-in EWW browser. It is a text-based browser that also shows images, but it does not run JavaScript. It's not for running webapps, but it is a great browser for web pages. It has a nice reader mode to focus in on the content of the page and get rid of clutter. It also integrates well with my RSS reader (elfeed) and makes it easy to open links I find in other documents within my text editor.

Large Languague Models ("AI") are making the lives of people hosting websites harder by scraping their content which add cost to the owners of the sites for data transfer or spinning up extra infrastructure to not go down with the extra load. The scrapers tend not to respect robots.txt files that tell them not to scrape the sites. The legality of this scraping under current copyright law is questionable. The LLMs' owners are especially interested in software source code since this is an area where companies and users are willing to pay serious money to use LLMs. Free software git forges like codeberg.org and sourcehut.org are scraped so hard that it almost constitutes DDOSing. One of the companies doing this is Microsoft, their market-leading, near monopoly competitor on git forges and owner of proprietary git forge GitHub, to improve their CoPilot LLM.

To combat LLM content scraping, many websites use a program called Anubis that runs some JavaScript in the browser of the user to check whether it is in fact a human with a browser and not an LLM scraper that has changed the user-agent string that identifies which browser is being used. This program demands that JavaScript is run before serving the content. This means that when I want to go to a site that uses Anubis with Eww, I get a message that I have to turn on Javascript, which I cannot do since I use a text based browser. So in effect, LLMs ruin text based browsing.

Emacs on Windows

Updated: November 23rd, 2025

I use Emacs as my text editor. At work, I use a laptop with Windows 11. After having tried a lot of different approaches, this school year, I just use Windows 11 on the laptop without any dual booting or additional desktop machines with GNU/Linux in classrooms or at my desk. When I need to show something in GNU/Linux to my students who use it on their desktops for parts of one of the subjects I teach, I will use Hyper-V on the laptop. This approach is simpler and more flexible than having multiple machines in different locations or dual-booting the laptop that I did in the past. There are also a few Windows-specific programs I need occasionally that are not available through Sharepoint on the web, and my students mostly use Windows 11 on their laptops so when showing them how to do something, it is better if I also use Windows, especially for things that happen in a non-cross-platform way, for example using Windows installers, Hyper-V or PowerShell in Windows-specific ways.

I use inter-present-mode in class for interactive presentations where I can run code blocks live, and write things into the presentation while presenting. Since I sometimes have pictures in my presentations and inter-present-mode changes face height, I need to use GUI Emacs. (Emacs is also available in the TTY and terminal emulators.) There are two ways to get GUI Emacs on Windows. The first is through WSL2 with the graphical features Microsoft calls WSLg.

Unfortunately, the Wayland stack is implemented in a non-standard way in WSLg that doesn't currently work properly. There are two bugs related to Wayland-native programs: the first bug makes Wayland native programs use XWayland instead of Wayland. The community found a fix for that bug in 2023 and told Microsoft about it in a GitHub Issues thread where a representative for Microsoft said they applied the fix to the codebase, but so far, Microsoft has not released that fix. You can fix it yourself if you like.

However, there is another bug that makes Wayland windows unresponsive after locking the screen and unlocking it again. This is the show-stopper for WSLg for me. (There is also a similar bug for X windows where the windows disappear after screen locking, but if you open a new X window, you can alt-tab to the original window and use it.)

Since I need GUI Emacs for presentations and thus cannot use Emacs in the Windows terminal through WSL2 without WSLg, and WSLg doesn't work properly, I have opted to instead use native Emacs on Windows. With WSL2, all the free software programs that integrate with Emacs is easily available, but I gradually discovered how to get the necessary external packages and how to configure Emacs on Windows to get as similar an experience as possible to the one I have on GNU/Linux. I wrote blog posts as I discovered these things, but I think it is more useful to have all the information in one post, rather than in separate posts, so I have deleted those older post and replaced them with this post instead.

I originally kept a separate Emacs configuration for Windows that I forked from my normal config, but since I always wanted to get things to work as similarly as possible on both OSes and I found it hard to keep the common parts in sync, I chose to integrate the two configs back into one with a few if and when-statements when needed. You can find it here.

People use Emacs in different ways, so you may find that you need something I don't, but I hope this blog post can give you a starting point. (It is also useful for me in case I need to set things up again.) Some other good starting points are Using Emacs on Windows 11: An Installation Guide by Dr. Peter Prevos and Properly Installing Emacs on Windows, Properly Setting up Emacsclient on Windows, Printing Directly from Emacs on Windows and Getting spelling to work in Emacs on Windows by Dr. Raoul Comninos on the EmacsElements website and YouTube channel. I have used their ideas in my setup, but tweaked things to my own liking.

Installation and basic use

I use the Windows installer from a nearby mirror of GNU.org as recommended on the Emacs website. Make sure to use runemacs.exe since it does not open an empty terminal before opening the Emacs GUI, unlike emacs.exe. It is a good idea to add runemacs.exe to your start menu and task bar to have it easily available. I have runemacs.exe as the leftmost icon in my task bar which means that I can launch it with Super-1.

You may also consider adding runemacs.exe as the default program to open .org, .md, .py, .js etc files. I find it easier to do so in File Explorer by right-cliking a file of that type and choosing Propteries… and setting the application to open that file type instead of using the Settings app which doesn't work by file type, but by program which always seems a bit backwards to me. The way I use Emacs, I tend to have a frame open at all times and visit files from inside Emacs, but when I use File Explorer, I often want files to open in other programs, usually because I want to show my students the files in the programs they use (Thonny, VSCode, Word, Excel, MySQL Workbench…) even if I usually would use the files of the same file types inside Emacs, so I have only set a few file types to open with runemacs.exe. Since I don't use emacsclientw.exe on Windows, I don't want to double click files in File Explorer or open them through the start menu since that opens a new Emacs frame if runemacs.exe is set to open those file types. I like to almost always work in just one Emacs frame.

I have stopped using Emacsclient on Windows since it doesn't work the same way as on GNU/Linux. It does not respect my settings for faces (fonts) or scroll bars from my config. If I open Emacsclientw on Windows directly, it complains that I haven't opened it with a file. On GNU/Linux, if I open Emacsclient without a file, it opens up with the scratch buffer. Since I want to have an Emacs frame open at all times and more frequently open files from inside Emacs than from the File Explorer, I quite often want to open emacsclientw without a file. Another weird thing is that when I kill the buffer with the file I opened emacsclientw with, Emacsclient quits. It doesn't do that on GNU/Linux. Since I want to keep the frame for further work through the day, this behaviour makes emacsclientw more or less unusable for me. The third annoyance is that if I forget to use M-x kill-emacs before restarting or turning off the Windows machine, it uses forever to turn off. Together, these annoyances were just too much, so I went back to open an Emacs frame after booting the machine and continue to use it until I turn the machine off.

Installation of tools that interact with Emacs

Emacs needs external programs for some of its functionality. Below is a table that shows useful programs I use on Windows to get the functionality I need or want from Emacs. More details can be found in the relevant sections below.

Package What it supplies Where to get it
chocolatey Package manager https://chocolatey.org/install Use Individual install.
Hack Free programming font https://github.com/source-foundry/Hack-windows-installer
Liberation Free variable pitch fonts Come with LibreOffice
imagemagick For showing pictures Install with Chocolatey
Pandoc Export org with ox-pandoc Install with Chocolatey
MikTex Export org via LaTex Install miktex.install with Chocolatey
Strawberry Perl MikTex needs Perl https://strawberryperl.com/
mupdf PDFs in doc-view-mode Install with Chocolatey
unoconv MS365 & ODF in doc-view-mode https://www.libreoffice.org/download/download-libreoffice/
git Version control https://git-scm.com/downloads
hunspell Spell checking program https://sourceforge.net/projects/ezwinports/hunspell-1.3.2-3-w32.bin.zip/download
nb_NO.aff, nb_NO.dic BokmÄl hunspell dictionary Come with Libreoffice
Node.js and npm NPM to install LSP servers https://nodejs.org/en/download
Python Pip to install LSP servers NPM installs Chocolatey and Python as well, otherwise Chocolatey
LSP servers Completions, errors, linting pip and/or npm
LibreOffice See above https://www.libreoffice.org/download/download-libreoffice/
Microsoft PowerToys Rebind keys (if needed) The Microsoft Store

Setup of environment variables

Emacs looks for a .emacs.d directory or a .config/emacs/ directory or a .emacs file in $HOME. To set $HOME, press the Windows key, write environment and you should see the Edit Environment Variables program (Rediger systemmiljÞvariabler if you use Norwegian BokmÄl). Set the User variables for HOME to wherever you want it. I also found that it was useful for git to set LANG and LC_ALL since git and other programs compiled with MSYS2 respects the text encoding from those. I did this as part of my trial and error process to find ways around git's default conversion of text encoding and line endings, but I am not certain it is necessary after setting the system locale to UTF-8 and/or setting Git Bash's text encoding in the GUI (see the dealing with text-encoding section for more on this).

windowsenv.jpg

Dealing with text-encoding

Windows uses UTF-16 under the hood, but on the surface it uses different text encodings depending on your locale. (GNU/Linux, BSD and MacOS use UTF-8 unless you configure them to use something else.) Windows uses CR and LF to end lines while GNU/Linux, BSD and MacOS X use LF. (Mac OS < 10 used CR.) There are different strategies to deal with this:

  1. Use the locale's encoding on Windows and have git convert line endings on clone, pull and push.
  2. Use UTF-8 and Unix line endings for every buffer and file inside Emacs, but configure Emacs to work with yanking (pasting) and killing (cutting) to and from the clipboard in Windows locale's text encoding. Tell git to not convert files and line endings.
  3. Set Windows 11 to use UTF-8, set Emacs to use UTF-8 and Unix line endings and tell git to use UTF-8 and not convert line endings.

If you do 1, then you don't have to configure git, because that is its default behaviour on Windows. This supposes that you use your text editor(s) with Windows line endings, and possible also your locale's text encoding which makes writing a lot of glyphs, like emojis, Hangul, Hiragana etc, impossible. Even VSCode defaults to UTF-8 and Unix line endings, even on Windows. I think there is absolutely no advantages to this approach unless you never use any other platform than Windows.

If you do 2, then you have files with only UTF-8 and Unix line ending in your repos, but you have to configure Emacs to convert text when yanking and killing to/from the system clipboard. You also have to configure git not to convert CRLF to LF. (See the below section on how to do this.) Below is how you configure yanking and killing to work to and from iso-latin-1 which is the common text encoding for Windows in Northern Europe and North America. I tried this approach for a while, but would rather avoid another if-statement in my config if I could avoid it to keep things as similar as possible between Windows and GNU/Linux.

(if (eq system-type 'windows-nt)
   (set-clipboard-coding-system 'iso-latin-1)
  (set-clipboard-coding-system 'utf-8))

My strategy

I use the third strategy now. Windows 11 has a beta feature where you can choose to use UTF-8. You can set it up by following the step-by-step instruction from geekrewind.com. You still have to configure git not to convert CR LF to LF and vise versa on push and pull, but you don't have to configure Emacs to do anything when yanking and killing. To configure git to use UTF, I set the user environment variables LANG and LC_ALL since git and other programs compiled with MSYS2 respects the text encoding from those. In addition, I opened Git Bash, right-clicked the window title, selected Options…, selected Text, chose nb_NO and UTF-8 (you may want something else than nb_NO which is Norwegian BokmĂ„l) since I read somewhere that git uses the settings set in Git Bash. I am not certain if you need to do both, but I did and it works. In my .gitconfig in my $HOME, I made a section called [core] and on the next line wrote autocrlf = false. This means that git will not convert line endings on push and pull from Unix (LF) to Windows (CRLF). Since all my files use Unix line endings anyway, this is no longer necessary.

I still have configuration to always use UTF-8 and Unix line endings inside Emacs and save every file as UTF-8 with Unix line endings. This is useful for getting rid of other encodings in previously made files. (In case I want that other encoding, for example for files I want to use under emulation of older systems, I can omit saving and they would still be in their original encoding.) I hope Microsoft will make UTF-8 and Unix line endings standard in Windows 12. The only small problem I have seen since switching to UTF-8 is that a few Norwegian glyphs in HP's notification about driver updates don't display properly. Otherwise, I have had no problems. Below is the configuration I use to set Emacs to use UTF-8 and Unix line endings and write every file with UTF-8 and Unix line endings.

(prefer-coding-system 'utf-8-unix)
(set-default-coding-systems 'utf-8-unix)
(set-language-environment 'utf-8)
(setq-default coding-system-for-write 'utf-8-unix)
(setq-default buffer-file-coding-system 'utf-8-unix)

Spell checking

I used to use aspell with aspell-en and aspell-nb (or -no) depending on whether the distro ships both Nynorsk and BokmÄl in the same package or have separate packages (nb = Norwegian BokmÄl, nn = Norwegian Nynorsk, no = both Nynorsk and BokmÄl). I did not find aspell-no or nb on chocolatey or msys2 and I had the same problem with the hunspell package available for Windows which comes with British and American English which I sometimes use, but not Norwegian BokmÄl.

For a while, I turned off spelling on Windows, but I recently looked into it again and found that I could copy over the .dic and .aff files I get with LibreOffice since it uses hunspell as well. The LO installer installs Norwegian dictionaries with a "typical install" if you downloaded the installer by browsing to the download page with a Norwegian IP address. To use the dictionaries from LibreOffice, go to C:\Program Files\LibreOffice\share\extensions\dict-no\ and copy the files nb_NO.aff and nb_NO.dic. If you use another language, have a look in the extensions folders to find the folder with your relevant dictionaries. Go to the share\hunspell directory under where you installed hunspell. I use C:\Program Files\Hunspell\share\hunspell\ and paste the files there.

In addition I have taken the settings suggested by Getting spelling to work in Emacs on Windows and modified them slightly for my use. I now also use hunspell on GNU/Linux. I have also made a convenient function in my Emacs config to toggle between Norwegian BokmÄl and British English, and bound it in my keymap to C-z i.

(use-package flyspell
  :hook ((prog-mode . flyspell-prog-mode)
         (text-mode . flyspell-mode))
  :init
  (when (eq system-type 'windows-nt)
    (setq ispell-program-name "C:/Program Files/Hunspell/bin/hunspell.exe"))
  (setq ispell-dictionary "nb_NO")
  (setq ispell-dictionary-alist
    '(("nb_NO" ":alpha" "[^[:alpha:]]" "[']" nil ("-d" "nb_NO") nil utf-8)))
  (setq hunspell-default-dict "nb_NO"))

Dictionary lookup

On my GNU/Linux systems, I install a dictd server and some dictionaries so I don't need to be connected to the internet to use dictionary-lookup-definition. Since there is no dictd server package for Windows, I first tried to use dict.org to look up words. When I tried dictionary-lookup-definition, Emacs just froze. It did not use a lot of CPU, but it just did not respond do anything, including C-g. I had to kill it with the three-finger salute (Ctrl-Alt-Delete). Maybe the relevant ports are blocked by my network at work, so it might work for you even if it did not for me. Below, you see my configuration for dictionary mode. I check if I am on GNU/Linux and otherwise, don't load it since I cannot get it to work at work.

(use-package dictionary
   :if (eq system-type 'gnu/linux)
   :config
   (setq dictionary-server "localhost"))

Viewing MS365 and Open Document Format documents

Emacs can show .xlsx, .docx, .pptx, .odt, .odp and other MS365 (Formerly Microsoft Office) and LibreOffice (Open Document Format) files in doc-view-mode. It is very practical to go directly from dired to doc-view-mode in stead of waiting for LibreOffice or MS365 to start. To show these files it needs a python script called unoconv that comes with LibreOffice. You also need to set the path to that script to get it to work. Since newer versions of LibreOffice stalls when you open them on Windows 11, either if you launch Writer or use unoconv from Emacs, I had to install version 24.2.0.3 to get this to work properly. You find it with the Archive link on the LibreOffice download page.

Pandoc and LaTex for export and import from Org mode

I use pandoc with Emacs and also ox-pandoc to be able to export from Org mode to .docx format. Upper Secondary schools in Norway use MS365, so it is useful to be able to write .docx documents occasionally. I use LaTex a lot for export of PDFs from org files I have used with inter-present-mode in class. Both pandoc and LaTex can be installed with Chocolatey, but when using LaTex to export PDFs on Windows 11, I always got an error that wrapfig.sty was not installed. It probably doesn't come with the LaTex package from Chocolatey. The solution is to use MikTex instead. Install the package miktex.install with chocolatey. MikTex needs Perl to function, so you also need to install Strawberry Perl from its website to get the export functionality to work. As with any external programs, you also need to set the exec paths (see further down this blog post) to get the actual functionality, unlike on GNU/Linux where it just works.

PowerShell in Shell mode

Since I like to have as few windows open as possible since Windows ironically is terrible at handling windows (at least compared to the tiling window manager Sway which I use on GNU/Linux), it makes more sense to use PowerShell in shell mode and stay within Emacs instead of launching a new PowerShell window. (Some people think window snapping solves the inefficiencies of a floating window manager or desktop environment, but it doesn't since you have to do it manually with a keyboard shortcut or even more inefficiently by mousing around and dragging the windows to the edges. A tiling WM tiles automatically without any need to mouse around or press keyboard combos, which saves time and interruptions.)

By default, you get cmd.exe in Shell mode on Windows. I had some trouble finding good documentation of how to set it up with PowerShell. Some people suggest just setting PowerShell to explicit-shell-file-name, but that only partially worked since it gave me an error that PowerShell was invoked with a wrong argument. A lot of people pointed to someone on the Microsoft blogs that set up PowerShell in Shell mode, but in a way that removed the prompt. He had made an Elisp workaround to get the prompt back, but it seemed like there should be an easier way. The trouble is that comint mode, the mode shell mode is built on, sends -i by default to the shells it interacts with as an argument. I tried a couple of things and it turns out the solution is really simple.

(use-package shell
  :config
  (add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
  (add-to-list 'comint-output-filter-functions 'ansi-color-process-output)
  (add-hook 'comint-output-filter-functions 'comint-osc-process-output)
  (add-hook 'shell-mode-hook (lambda() (company-mode 0)))
  (when (eq system-type 'windows-nt)
    (setq explicit-shell-file-name "C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe")
    (setq explicit-powershell.exe-args '("")))
  (when (eq system-type 'gnu/linux)
     (setq explicit-shell-file-name "/bin/bash")
     (setq system-uses-terminfo t)
     (setq comint-terminfo-terminal "xterm")))

In the code block above, if on Windows, I tell Emacs to run PowerShell and give it the arguments "" (ie, nothing) which remove the default -i argument, but adds nothing else. And now I have PowerShell in Shell mode. The rest of the configuration turns off company since the shells have their own tab-completion and turns on ansi-colours which both Bash and PowerShell can work with. If you prefer to use PowerShell 7 instead, use the path to it instead of the path to the built-in Windows PowerShell.

Language Server Protocol servers

LSP is a standard Microsoft made for adding language support to VSCode that is now also used by other editors like NeoVim and Emacs. In Emacs, you just have to have the LSP servers you want installed, the correct paths configured and eglot, company and eldoc, if turned on, makes use of them in the mode for the associated programming or markup language. I tend not to like documentation constantly popping up with eldoc-mode, but use completions and warnings from eglot and company. Below is a table of the LSP servers I use and how to install them on Windows.

Language LSP-server names install with Comment
Python python-lsp-server (pylsp) pip or npm i -g FOSS, flake8 is an optional dependency
Bash / Shell shellcheck, bash-language-server npm i -g FOSS
JavaScript, TS, JSX typescript-language-server, typescript npm i -g Microsoft, LSP depends on typescript
CSS vscode-css-languageserver-bin npm i -g Microsoft
HTML vscode-html-languageserver-bin npm i -g Microsoft
JSON vscode-json-languageserver npm i -g Microsoft

The Microsoft LSP servers give you the same completions, documentation and warnings as in VSCode. I would recommend against Microsoft's pyright which has given both me and my students errors that were not actual errors. For instance, it told me that I could not change data type for an element inside a list even if that is precisely what a dynamically typed language like python lets me do. I used the list internally in a function, so it was not like I was mutating a list I might use somewhere else in the file. Python-lsp-server, also called pylsp has never given me any errors that weren't actual errors. You may find more LSP servers at https://langserver.org/.

In addition, you have to turn eglot on in the relevant modes. I turn it on for all programming modes.

(use-package eglot
  :hook (prog-mode . eglot-ensure))  

Python Shell

Python mode in Emacs on GNU/Linux works out of the box with no setup if you have Python installed on your system. However, on Windows, Python mode does not work even if Python is installed. It does not help to add the directory Python is in to the exec-path or add it to the $PATH environment variable either. After trying those two things, I looked for a useful variable to set the path to the python executable and tried a couple of promising ones before finding the correct solution. In the code below, I set the docstring-style to Django which I prefer over the default pep-257 and then check if on Windows and if so, set the path to the shell to where I have python installed.

(setq python-fill-docstring-style 'django)
(when (eq system-type 'windows-nt)
  (setq python-shell-interpreter "c:/Python313/python.exe"))

Rebind keys

After realising that using a key only available in the Emacs GUI, but not when using Emacs in a TTY or a graphical terminal, was dumb, I changed my prefix key for my keymap to C-z and no longer rebind CapsLock to <apps/menu> on Windows with PowerToys and <menu> in my Sway config on GNU/Linux. I use Lenovo ThinkPads and keyboards at home, so I had to switch Fn and Ctrl on my HP work laptop with its BIOS to not confuse my muscle memory when at work. If you need to rebind keys on Windows, and cannot do it in the BIOS of your computer, try PowerToys. You can get it in The Microsoft Store.

Paths that need adding

For Emacs to integrate with external packages on Windows, the exec path needs to include the file path to those packages. Below is my extra configuration for adding exec-paths in Windows. You may have placed the programs you have installed manually, like Hunspell, in other places, so adjust accordingly. You may also do this with customize, but I want to have it as part of my config since sometimes I let the custom-vars file where I keep the changes from customize drift a little bit away from the upstream emacs_config repo on some machines.

(when (eq system-type 'windows-nt)
  (custom-set-variables
 '(exec-path
   '("C:/Program Files/MiKTeX" "C:/Program Files/ImageMagick-7.1.2-Q16-HDRI" "C:/Python313/"
     "C:/ProgramData/chocolatey/lib/findutils/tools/install/bin/" "C:/WINDOWS/system32"
     "C:/WINDOWS" "C:/WINDOWS/System32/Wbem" "C:/WINDOWS/System32/WindowsPowerShell/v1.0/"
     "C:/WINDOWS/System32/OpenSSH/" "C:/Program Files/dotnet/" "C:/Program Files/Git/cmd"
     "C:/Program Files/nodejs/" "C:/ProgramData/chocolatey/bin" "C:/ProgramData/chocolatey/lib/mpv/"
     "C:/ProgramData/chocolatey/lib/mupdf" "C:/Users/AFK01217/AppData/Local/Microsoft/WindowsApps"
     "C:/texlive/2025/bin/windows" "C:/Users/AFK01217/AppData/Local/Programs/Microsoft VS Code/bin"
     "C:/Users/AFK01217/AppData/Roaming/npm" "C:/Users/AFK01217/AppData/Local/Pandoc/" "."
     "C:/Program Files/Hunspell/bin" "c:/Strawberry/perl/bin/" "C:/Program Files/LibreOffice/program"))
 '(image-load-path
   '("c:/Program Files/Emacs/emacs-30.1/share/emacs/30.1/etc/images/" data-directory load-path "c:/python313/")))
)

Why I replace Bash scripts with Elisp functions

Lately, I have spent some time replacing my Bash scripts with Emacs Lisp functions inside my Emacs configuration. I like programming and I haven't really gotten deeper into Elisp, so one reason was just to learn more Elisp and have some fun. Another reason is that replacing the Bash Shell scripts with Elisp functions removes the need to clone down an extra repository when I install a new system to get things up and running. It simplifies my installscripts a little.

Another advantage of having useful functionality inside my Emacs config is that whatever window manager or maybe even operating system I use, I can still use my functions from inside Emacs. Bash Shell scripts only run on GNU/Linux and POSIX Shell scripts only run on POSIX systems. But Emacs functions can be run inside Emacs on every platform it is available for without any external configuration. I might have to change my settings for wallpaper-command and wallpaper-command-args if I use another window manger, desktop environment or operating system, but most things will just work no matter where I am. Having the functionality in Emacs makes it easier if I ever were to change window manager from Sway as well.

The scripts I was able to replace with Emacs functions this weekend was my radio stream script, my two tv scripts for watching the latest news or satire broadcast from NRK, and my two wallpaper setting scripts, one that goes to the next file in a folder and sets it as the wallpaper so I can cycle through (and also around again when I get to the end) and another one that picks a random wallpaper from within the same folder. During the weekdays I was able to make a script to update my homepage and copy a youtube RSS feed link from a yewtu.be URL in primary selection. It was a lot of fun to dive into Elisp even if it took a lot of time since I was constantly searching for functions I could use for my purposes, both within Emacs and online.

I can still launch my scripts with keyboard shortcuts from my Sway config with emacsclient -e '(functionname)'. I start an Emacs server when I launch Sway, so I can always rely on having Emacs running. For the scripts that need user interaction in an Emacs frame, I can add -r to either reuse an open frame or make a new one.

How I generate my blog from Org files

I have used org-static-blog to generate HTML from org files for a while, but I have changed how I get those files onto my website. Org files are markup files used in Emacs Org Mode. The syntax is more regular than Markdown, there is only one standard unlike Markdown and the facilities in Org Mode to write these files make it a really great format to work with for any Emacs user.

In the past, I would manually delete all files except robots.txt, style.css and my media folder from the folder I exported to with org-static-blog. The reason is that org-static-blog only creates html files from org files where the html file does not already exist and then updates index.html, archive.html and rss.xml to reflect the changes. However, I sometimes edit older blog posts or my about page or change the header or footer which applies to all html pages, so I want to generate all the files every time and to achieve this, I delete all the html files before generating the new ones with the function org-static-blog-publish from my posts folder full of org files. I would then either use scp or FileZilla to upload those to my web server.

What I do now is use Codeberg Pages to serve my website instead. I have forwarded https://mostad.eu/ to https://einar.codeberg.page/ so visitors to mostad.eu get to the URL where html files in my Codeberg repo called pages are served by Codeberg instead. I have also made a shell script (that I will replace with an Elisp function in the future) that removes the previously generated html files, generates the html files with Emacs, and once closed, adds, commits and pushes the files to the repository Codeberg Pages hosts my website from. This way, I can get out a new blog post a lot faster than I would in the past and most of the process is automated.

Interactive presentations

I often present new material for my students in class. I teach programming and information technology at a vocational school, so I often need to run code as examples of what I am presenting. When a student has a question about how the code works, I can show the answer by tweaking the code and rerun it. I might ask my students something and write down their answers in my presentation as well or I might hand out individual tasks, collect the answers and use the presentation to share the results with everyone on the screen. (We have large 4k touch screens that also have whiteboard functionality in every classroom.)

Emacs Org mode is a tool for outlining ideas (and a lot of other stuff like calendaring, todos and project planning) in a pure text markup format with support for inline images and code blocks in almost any programming language. You can run the code blocks when you want or tangle them out to a separate code file a la literate programming. Emacs is extendable and hackable enough that it can be made to work as presentation software. Ric Lister has made an Emacs package called org-present which I use. I make my presentation in org mode as an org file (org markup is similar to markdown), and add the images and code blocks directly within the text with the markup. When I am in class, I run the function org-present to start a presentation.

Each top level heading in my org document becomes a slide. I can write directly into the slides while I present them since they are just text files in org markup displayed with larger font sizes and nicer headlines etc, which makes it possible to do things like ask my students something and write down their answers. I can also run code blocks by hitting Ctrl-C Ctrl-C with the pointer above the code block and the results pop up underneath in a separate results block within the text of my presentation. Another advantage is that if I alt-tab into another program like Firefox or Thonny, my presentation within Emacs does not switch out of presentation mode like most presentation software like PowerPoint tends to do. I can come back to my presentation after showing a Youtube video with Firefox and continue where I left off.

After class, I export the presentation including code blocks, images and results of running the code to a PDF and put it on our learning platform to make it easy for students not present to see what was happening or for later review before a test or an exam. I have set up org-present to work the way I like with a bit of code in my Emacs config. I turn on display of inline images and set a standard width that usually works (that I can easily change with some metadata above an image if needed) and use org-present-big to make everything large. I then hook my configuration into the start of org-present and also have a function that resets my configuration that I hook in when org-present is quit. I highly recommend org-present if you want interactivity within your presentations, especially if you already use Emacs and Org mode. It lets me hold interactive presentations presentation software like PowerPoint, Prezi or Keynote cannot.

Setting the background wallpaper for Sway and managing music with Emacs

I just watched an old video by Luke Smith which gave me the idea that it would be cool to change background in Sway from Emacs. I thought I would use dired and either open an image to see how it looks directly or use image-dired to get a preview of all the images in a folder. I would probably have to make a shell script to do the work and launch it with async-shell-command from an elisp function. It turns out I don't have to do anything. The functionality is already built into Emacs and it even gets which window manager or desktop environment is in use and selects the correct command to change the background for that WM or DE. The documentation tells me this functionality came with Emacs 29.1, at the same time a lot of other improvements were made to image-dired and opening images in general. I used image-dired in 28.2 and the improvements with 29.1 were many and greatly appreciated!

Moon_blue.jpg

A few months ago I did the same type of discovery. I was looking for a way to interact with mpd, the music player daemon, possibly through the command line tool mpc from within Emacs. EMMS and Bongo are often mentioned by people in the Emacs community and I have tried both, but they are both unable to list albums with many artists and/or many recording years as one album. All other mpd players I have tried, both TUI and GUI-based have the same problem, so this is not a unique shortcoming in these packages. Until recently, I have relied on a shell script I wrote that lists all the albums in the mpd database with fzf and lets me select the one I want to play. However, sometimes I don't want to play a whole album, but I still want my music sorted by album since I have been carefully tagging my files so I can easily find music by album.

(I kind of had to make a system for album names since having 11 albums named "Bach cello suites" doesn't really help me find the one I like to listen to when I have six different recordings, they usually span two albums and two recordings are by the same artist at different times. Hence, I have made a system that is fine grained enough for me to find the right album without being too detailed to avoid too long album names. For instance, I don't include first name initials of the composer in the album name when I only have one composer with that last name in my database (even if more exist), and I don't list artist in the album name when I have only one recording of a work. Every time I ripped an album, I manually changed the tags to match my system even if MusicBraniz through Rhythmbox and earlier, iTunes, often gave me terrible album names for classical albums when I ripped them, otherwise I would not be able to find anything.)

A few months ago, I discovered a built-in mpc mode in Emacs that gave me exactly what I wanted. I could continue to use mpd and mpc to manage my music playback and use mpc mode which looks very much like Rhythmbox, but has the advantage of having all of Emacs' superior keyboard centricity and text handling. I can easily search with C-s for an album name, add it to the playlist and start playing it and then q to quit out of that mode with the music still playing and I am back at whatever I was doing in Emacs before, all without having to lift my hands from the keyboard. It is really convenient. In mpc mode, the albums are correctly listed even when there are many artist and/or years on the same album. Since I can sort my music by album, I can easily also find a single track if I am so inclined.

These kinds of discoveries make me love Emacs and the Emacs community. Emacs is hackable enough that if you want some functionality, you can get it. And since the project wasn't started yesterday, someone has often already thought of my use-cases and spent some of their spare time to code up that functionality and often also even gone to the trouble to include it in the editor itself. Thank you!

Offline dictionary lookups within Emacs

There is a dictionary-mode in Emacs. It used to be a separate package, but now comes as part of Emacs. The usual way to use it is to (setq dictionary-server "dict.org") in init.el (or equivalents) to tell Emacs to look up dictionary definitions from the internet when used. There are a lot of dictionaries in dict.org. The availability of the full text of the Webster 1913 dictionary within it has been much lauded in the Emacsphere by wordsmiths eager to vary their outpourings' formulations. However, I am not always online. I like to keep as much functionality as possible available to me offline to not become over-reliant on the internet or loose functionality when the internet is unavailable.

The solution is simply to install the dictd server and the dictionary packages you want on your computer. In Debian, these are available as dictd and a number of packages that supply dictd-dictionary for it. In Arch, dictd is an ordinary package in the community repo, but the dictionaries has to be added through the AUR. The dictd server and related dictionary files are however not available yet for GNU Guix. The Arch Wiki has an excellent page on dictd if you want more information on its usage. Once installed, you can just change the aforementioned dictionary-server variable from "dict.org" to "localhost" and Emacs will find your installed dictionaries. Depending on the distro, you may also have to systemctl enable dictd.service and systemctl start dictd.service to make certain dictd runs at every startup as well as immediately.

The selection of freely available Norwegian BokmĂ„l dictionaries is rather slim. I only found an English - Norwegian dictionary that seemed slightly useful to me. I wish there was as Norwegian BokmĂ„l - English dictionary as well since that would sometimes be useful for me even if I have a decent English vocabulary. There are some dictionaries from other European languages to Norwegian BokmĂ„l, but I seldom use other languages than English these days. (I used to play opera, cantatas and masses and then those would have been useful to me.) There is also a Norwegian Nynorsk - Norwegian BokmĂ„l dictionary by freedict. It could occasionally be useful when I read very old Nynorsk (Landsmaal). I wish there were a comprehensive Norwegian BokmĂ„l dictionary with word definitions, synonyms, IPA pronunciation, example of usage and expressions. I would use it especially for synonyms and spelling. Since I have lived and worked some years in Denmark and Sweden, my BokmĂ„l spelling isn't as good as it used to be, and ten years of using English as my working language after I returned to Norway did not really improve it either. I naturally blame the morons in the government of Denmark-Norway that decided to support Napoleon for all my current spelling troubles. Or maybe the Swedes that broke up the Kalmar Union should ultimately be to blame? Ok, maybe I need to take some responsibility myself as well…

American English is well covered by the GNU version of the Collaborative International Dictionary of English (dict-gcide) that includes the full text of the 1913 Webster's Unabridged Dictionary, the 1906 Century Dictionary and some other additions. I also installed WordNet (dict-wn) for synonyms. There are also some good computer term dictionaries like the Jargon File (dict-jargon), Virtual Entity of Relevant Acronyms (dict-vera) and the Free On Line Dictionary of Computing (dict-foldoc) available. I miss a dictionary with both British and American spelling and also IPA pronunciation since I try to stick with British spelling and RP. It is a pity that Oxford University Press do not release the Oxford English Dictionary or my favourite, the Oxford Advanced Learner's Dictionary, under a free culture license so it could be included as well. I have the Advanced Learner's Dictionary as a paperback in my bookshelf, and there is a website with it available gratis, but leaving Emacs breaks my flow when writing, the internet is not always available and my paperback is only available in my home. In my opinion, a university should use free culture and software licenses for everything they produce since when public money is used, it is only fair that the tax-payers get access to the works they funded. Also, the freedom to use, study, modify and share information should be the core values of any school or university.

I use both M-x dictionary-search and M-x dictionary-lookup-definition. The former lets you write in a search term while the latter looks up the word at point. The latter is obviously very useful while reading while the former may be more useful when writing, except if you want to find a synonym while revising your text where the latter becomes useful again. There is no need to change dictionary language for dictionary-mode unless you have installed too many dictionaries or dictionaries of languages with a lot of collision of vocabulary and spelling. Norwegian and English share a lot of vocabulary, but seldom collide in spelling, so I see no need to exclude any of the relevant dictionaries in either language. If you are overwhelmed with hits, it is possible to change dictionary inside the dictionary-mode buffer to limit the number of entries you get.

Combined with recently setting up flyspell-prog-mode for prog-mode and flyspell-mode for text-mode and (setq ispell-dictionary "british") in my init.el, I now feel more confident than before when writing text in Emacs, whether in code or not. (Dictionaries for lookup with dictionary mode and dictionaries for spell checking are separate and aspell or hunspell has to be installed with relevant dictionaries on your distro for ispell-dictionary to be set to the language you want for spell checking.) It's nice with spell checking for variable names and comments. Maybe I should add a toggle function with a keybinding for ispell-local-dictionary between "british" and "nb" to avoid having to use ispell-change-dictionary.

Elfeed with useful scripts

Elfeed is an RSS feed reader package for GNU Emacs. RSS is a standard for getting content like podcasts, video channels from LBRY and Youtube, Mastodon and Twitter, blog entries, news articles etc from the web without using a browser. Before I started using elfeed, I used Newsboat, a terminal program, as my RSS reader. I was inspired by Napoleon Wils0n to add scripts to Newsboat so I could launch videos from RSS feeds directly in mpv or download them with youtube-dl (and later yt-dlp). After I started using Emacs, I wanted to try to integrate most of my computing into it and I looked at the two built in feed readers before trying the highly recommended elfeed package. I liked it, so the next step was to find a way to get the same functionality I had in Newsboat in elfeed.

I don't know Elisp well enough to script this myself yet, so I looked online. I read up on the documentation for elfeed on GitHub and also found some inspiration on Reddit that I tweaked to make some elisp scripts to be able to hit m if I want to watch a video in mpv and M if I want to download it with yt-dlp to my "Nedlastinger" (Downloads in Norwegian) folder. I tried a couple of different solutions before I was able to get what I wanted. The suggestion from Reddit was to use start-process to launch an external process with the url from the entry as its argument. That worked well with mpv. For yt-dlp that was less successful and I also wanted to change directory to ~/Nedlastinger before launching the yt-dlp process so I read up on how to run shell-commands asyncronously and used that functionality instead. I also made certain that any shell command run asyncronously doesn't display a new window. (A "window" is a split within an Emacs "frame" (an X11 window) in Emacs parlance. Emacs is from before the Macintosh introduced the desktop metaphor's now common vocabulary (that Microsoft later copied in Windows), so it uses its own vocab for these concepts.) The reason why there are two scripts for each functionality is that I can use those keyboard shortucts both inside the view where you show the specific entry and in the view where you see all entries while one is selected.

;; Dette gjør at Async Shell Command ikke vises hver gang man kjører en shell kommando med & fra inne i Emacs 
(add-to-list 'display-buffer-alist
  (cons "\\*Async Shell Command\\*.*" (cons #'display-buffer-no-window nil)))

;; Gir meg muligheten til å bruke m i elfeed for å åpne en rss entry i mpv
(defun browse-url-mpv (url &optional single)
  (start-process "mpv" "*mpv*" "mpv" url))

(defun elfeed-show-mpv-open (&optional use-generic-p)
  "open with mpv"
  (interactive "P")
  (let ((browse-url-browser-function #'browse-url-mpv))
    (elfeed-show-visit use-generic-p)))

(defun elfeed-search-mpv-open (&optional use-generic-p)
  "open with mpv"
  (interactive "P")
  (let ((browse-url-browser-function #'browse-url-mpv))
    (elfeed-search-browse-url use-generic-p)))

(define-key elfeed-show-mode-map (kbd "m") 'elfeed-show-mpv-open)
(define-key elfeed-search-mode-map (kbd "m") 'elfeed-search-mpv-open)

;; Gir meg muligheten til å bruke M i elfeed for å åpne en rss entry i yt-dlp
(defun browse-url-ytdlp (url &optional single)
  (shell-command (concat "cd ~/Nedlastinger &&" "yt-dlp -f 'bestvideo[height<=720]+bestaudio/best' " url " &")))

(defun elfeed-show-ytdlp-open (&optional use-generic-p)
  "open with ytdlp"
  (interactive "P")
  (let ((browse-url-browser-function #'browse-url-ytdlp))
    (elfeed-show-visit use-generic-p)))

(defun elfeed-search-ytdlp-open (&optional use-generic-p)
  "open with ytdlp"
  (interactive "P")
  (let ((browse-url-browser-function #'browse-url-ytdlp))
    (elfeed-search-browse-url use-generic-p)))

(define-key elfeed-show-mode-map (kbd "M") 'elfeed-show-ytdlp-open)
(define-key elfeed-search-mode-map (kbd "M") 'elfeed-search-ytdlp-open)

Those scripts worked fine for video channels from LBRY and Youtube, but not for podcasts which use an enclosure url to give the url to the actual episode's video or audio while the general url field in the RSS entry is used for show notes. I tried searching for variables within elfeed with the built in self-documenting features of Emacs, but did not fully understand how to find the enclosure url. After some searching aorund the internet, I found a way to get the enclosure-url and recycled most of my previous code again with the new url to make two functions making it possible for me to listen/watch a podcast with mpv by hitting P and downloading it with yt-dlp with K. I only implemented this for one of the two views.

;; Gir meg muligheten til å bruke P i elfeed for å åpne en podcast (enclosure) i mpv
(defun elfeed-show-play-enclosure (enclosure-index)
  (interactive (list (elfeed--enclosure-maybe-prompt-index elfeed-show-entry)))
  (let ((url (car
              (elt
               (elfeed-entry-enclosures elfeed-show-entry)
               (- enclosure-index 1)))))
    (start-process "mpv" "*mpv*" "mpv" url)))

(define-key elfeed-show-mode-map (kbd "P") 'elfeed-show-play-enclosure)

;; Gir meg muligheten til å bruke K i elfeed for å laste ned en podcast (enclosure) med yt-dlp
(defun elfeed-show-dl-enclosure (enclosure-index)
  (interactive (list (elfeed--enclosure-maybe-prompt-index elfeed-show-entry)))
  (let ((url (car
              (elt
               (elfeed-entry-enclosures elfeed-show-entry)
               (- enclosure-index 1)))))
    (shell-command (concat "cd ~/Nedlastinger &&" "yt-dlp -f 'bestvideo[height<=720]+bestaudio/best' " url " &"))))

(define-key elfeed-show-mode-map (kbd "K") 'elfeed-show-dl-enclosure)

I have set my default browser with my environment variables to Firefox and even though I like Emacs' built in browser eww a lot for text-based content with the occasional picture, I want to keep Firefox as my default browser for now. However, when I read an RSS entry in elfeed and it does not supply the full blog post, it is nice to stay within Emacs and read the linked blog post with eww instead of launching a heavy external browser. So I had to make two functions for the two view modes for that as well. So for those RSS feeds that do not supply the full content, I just hit B and the content opens up in eww. There is built in functionality to open the linked content in the default browser by hitting b in elfeed, so whenever I want or need to open the content in Firefox, I just hit b. For some content that is dependent on JavaScript or is full of media, I sometimes use that built in function, but usually, I use B instead.

;; Gir meg muligheten til å bruk B i elfeed for å åpne en rss entry i eww
(defun elfeed-show-eww-open (&optional use-generic-p)
  "open with eww"
  (interactive "P")
  (let ((browse-url-browser-function #'eww-browse-url))
    (elfeed-show-visit use-generic-p)))

(defun elfeed-search-eww-open (&optional use-generic-p)
  "open with eww"
  (interactive "P")
  (let ((browse-url-browser-function #'eww-browse-url))
    (elfeed-search-browse-url use-generic-p)))

(define-key elfeed-show-mode-map (kbd "B") 'elfeed-show-eww-open)
(define-key elfeed-search-mode-map (kbd "B") 'elfeed-search-eww-open)

Comparing my present elfeed setup with my former Newsboat setup, one thing that is much nicer with these scripts and elfeed is that I don't have to use an external program for podcasts. Newsboat comes with podboat which is intended for use as a podcatcher after you have qued up the content within Newsboat. That process always felt cumbersome and I actually didn't use it because of that. With elfeed and a few scripts, I have all kinds of feeds within the one reader and use a few different keyboard shortcuts to get everything done that I want. Another nice thing with elfeed is its search functionality which is very powerful.

My Emacs journey is still in its infancy, but the more I delve into Emacs, the more I like it. It's powerful, personal and pleasant. Emacs extends the hackability of GNU/Linux further by allowing you to tweak not only your DE or WM through configuration and shell scripts, but also the program you do most of your tasks inside. Integrating more functionality into Emacs means less friction and context switching between different tasks. Thus far, I have only integrated RSS reader, email, pdf document creation (org mode with latex export to pdf), blogging (org mode and org-static-blog), some web browsing (Firefox is still my default browser, but I use eww more and more), note-taking in org mode (I used to use vim and markdown) and of course general text-editing.

It's interesting how much faster for instance navigating around my emails is in mu4e within Emacs than in Thunderbird which was my previous email program. I think the reason is that Emacs is both text and keybord-centric (while also allowing for mouse use if you are so inclined). Elfeed has also become more useful than Newsboat used to be for me since I now also use it for podcasts. The hackability of Emacs means you can add functionality you want or customize things to your own preferences easily. Emacs also uses less system resources than other programs while doing more. Fewer resources means less power use and longer battery life on laptops. You can save money and possibly also CO2 emissions if your electicity is produced in environmentally unfriendly ways.

I see Emacs as the ultimate step in my gradual move towards less resource usage for my computing that started when I switched from Mac OS X to GNU/Linux in 2011, moved to a light-weight desktop environment (LXDE and later LXQt), then to even lighter weight window managers, gradually switched some GUI programs with terminal programs and scripts and then in the end the gradual integration of many tasks into Emacs. (I did this mainly out of curiosity, but I have reaped other rewards like less resource usage and more freedom as well.) If you see Emacs as only a text editor, then it is more resource hungry than vim (but less than VSCode), but if you see it as what it is: an integrated, hackable computing environment, then it is less resource hungry than the combination of programs you would use to do the same tasks. It is also the ultimate expression of the FSF's ideal of empowering users through the use of free software. I am definitively going to delve deeper into Emacs in the months to come.

Vim vs Emacs for fast text editing

vimvsemacs.jpg

Introduction

I used vim for 2 years and got it into my muscle memory before my Emacs curiosity led me to try out GNU Emacs in the spring of 2022. Many people say vim is the faster text editor, but Emacs is wonderfully extensible. After having used both, I don't think vim is faster than Emacs, so I am going to show how many consecutive key presses you need to accomplish some common tasks in both and compare. Of course, you can use evil-mode in Emacs and edit text the vim way, but I am comparing the usual non-evil default keybindings of Emacs with the defaults in vim. There is also the common halftruth about crazy key chords in Emacs contra simple one-key presses in vim. This is true for many workflows, but not so much for actual text editing. For text editing, the keyboard shortcuts in Emacs are usually just a modifier key plus an alphanumeric key.

I believe that pressing two keys at once takes the same amount of time as pressing one key. I call both "a keypress". On the other hand, pressing three keys consecutively takes three times longer than pressing three keys at once because you have to depress one key, lift up your finger, then depress the next key, lift your finger and then depress the next key and lift your finger. Therefore the actual speed of editing is determined by the number of consecutive keypresses to get something done, not the total number of keys depressed. As an example, I often press C-c C-, s (Ctrl-C Ctrl-, s) to insert a code block in org mode which is three consecutive key presses and a total of four keys (I hold Ctrl down from the time I start pressing c until I have finished pressing ,). This could have been faster if it involved fewer consecutive keypresses even with the same amount of totalt keys, like for instance the keypress C-M-S-, (Ctrl-Alt-Shift-,) which is just one keypress, but also four total keys. My point is that when thinking about the speed of editing, it is the number of consecutive keypresses that matter, not how many keys you press at once (although fewer is less akward for the hand).

In this blog post, I will use Emacs symbols for keybindings in Emacs where C = Ctrl, M = Meta (Alt or press and release Esc), S = Shift and s = super (Windows/Tux/Purism/Apple Commmand Key/…). Emacs keybindings are generally written with a dash when pressed together and with a space in between when consecutive, for instance M-b C-p means Alt and b pressed at the same time and then Ctrl and p pressed at the same time. When the same modifier key is used for two consecutive key presses, it does not have to be released like the example above with C-c C-, s shows. When writing about Vim, I will use Esc for Escape and use no space between consecutive keypresses which is the usual vim way, for exampel 2gj for the three consecutive keypresses 2, g and j. All other glyphs just represent themselves.

Comparison of keypresses for common editing tasks

Before starting to write anything in vim, you have to press i (or a or o etc). In Emacs, you just start writing. That's one keypress for vim and zero for Emacs. After you have written a sentence, maybe you want to move back and do an edit. Let's say you want to move to the start of the sentence you just wrote and add something in front of the first sentence. In vim you would press Esc to get to normal mode and then 0 to move to the start of the line (not necessarily the line you see on screen, but the start of the chunk of text since the last newline character) and then you would have to press i. In Emacs, you would press C-a (or M-a if the sentence is longer than one visual line) and start to write. In vim, you would need three consecutive key presses and in Emacs one before you started to write your new first sentence. After you have written your new sentence, maybe you want to go to the end of your paragraph and add something. In vim, you would press Esc, then A and then start to write. In Emacs, you would press C-} and then start to write. Again, vim has two consecutive keypresses and Emacs has one before writing.

Maybe we want to move two visual lines up and correct the misspelling of the word "icnonsequently" next. The word is two visual lines up, but starts four columns (four letters) to the left of where we are now. In vim, you would press Esc to get to normal mode, then 2gk (that is not one keypress, but three consecutive key presses) and then 3h (two key presses), then d, l, i and c, which is 1 + 3 + 2 + 1 + 1 + 1 + 1 = 10 consecutive key presses. In Emacs, you would press C-2 C-p (or C-p C-p) (two consecutive key presses to move up two visual lines since Emacs works on those), then C-2 C-b, then C-t (to use the function transpose chars with the cursor at the third letter), ie 5 consecutive key presses.

I could probably think of more examples, but the point is that for most edits, Emacs demands fewer consecutive key presses than vim. You can check out Emacs Rocks' episode 3 and 4 where Emacs is faster than vim for a couple of Vim golf tasks. Protesilaos Stavrou has also made a video where he shows off Emacs Macros for solving Vim Golf tasks. I think most of these are faster than vim as well. There are probably more examples floating around the internet if you care to find them.

How can vim be slower than Emacs? Everyone think it is the opposite…

The reason why we get more consecutive key presses and spend more time to get from one point to another and start writing in vim is because of the modal editing. Since we constantly have to hit Esc to get to normal mode before moving around and then hit a, o, i, r, c, A, O, C or I before actually getting to start typing our text, we generally need two or at least one (when combining movement and getting into insert mode like with A) more consecutive keypresses for moving around and starting to write in vim than in Emacs. Even if you count the total number of keys depressed and disregard that it is faster to press two keys at once than to press the same two keys after each other, Emacs usually ends up with fewer total number of keys pressed for doing the same edits.

Modal editing, as shown above, is slower since you have to go in and out of modes. In addition, it is very unlike any workflow most of us have ever used before, which means that it takes more time to learn text editing in vim than to learn text editing in Emacs. As someone who has spent time learning both vim and Emacs, I found vim to have a much steeper learning curve for text editing. The people that say vim is intuitive on the internet are lying to seem leet. Emacs can also do everything else than text editing, so you can continue to learn Emacs after your muscle memory has adjusted to its text editing workflow and that is the reason why many people think Emacs is hard to learn, but for text editing, it is easier to learn than Vim. Most Emacs users were (Neo)Vim users in the past, but there are very few (Neo)Vim users that were Emacs users. I think this means that when Vim users try Emacs, they never go back.

Both vim and Emacs have good tutorials that you should spend some time with when trying them out for the first time, but for vim, I felt like I had to go back to the tutorial a lot of times before I really mastered the concepts of modal editing and the keyboard shortcuts for doing things. When I finally made my own vim cheat sheet for my Norwegian keyboard layout and hung it on the wall underneath my screen, I finally started to get its keyboard shortcuts into my muscle memory. With Emacs, I felt that the text editing keyboard shortcuts were more intuitive and easier to learn and remember since many of them are mnemonic.

Conclusion

The joke that Emacs is a good operating system that just lacks a good editor is just a joke. It is a slightly faster text editor than vim and it is easier to learn for text editing because of its non-modal nature. There are other reasons for choosing a text editor than text editing speed, like using the same tool as your colleagues or fellow students, having the possibility to do more things within a hyper-efficient text-centric interface or having a tool that is very minimal. I think both (Neo)vim and Emacs are good choices for investing some time into learning since they both have strong communities that will make sure they will be around for fitfy years more. Even if you use a GUI-centric editor as your main editor, you will probably be in a situation where you need to edit a configuration file from at tty and then vim and Emacs are readily available where the GUI-centric editors are unusable. Nano is an option, but it is very inefficient compared to vim and Emacs.

Both editors demand a bit of configuration and going through a tutorial to learn how to edit text in them which is a different approach than many of the newer GUI-centric editors with more of a one-size-fits-all approach with or without extensions that may tweak things a little, but not a lot. I think those editors are short term solutions that will disappear when the priorities of the companies or individuals who make them change, like Atom exemplified. Long term Emacs users remember other editors coming and going while Emacs and ed descendants (vi, vim, NeoVim…) where always there. In the end, you choose the tools that work the best for you. Just don't lie and say you use vim because it is faster if you haven't given Emacs with default keybindings the chance to convince you otherwise.

I now use org-static-blog to create this blog

I have moved from WordPress to Hugo to nothing and now on to org-static-blog to create this blog. One reason to move to org-static-blog is that I have switched from using vim to using GNU Emacs as my text editor. When I used Hugo, I wrote my blog posts in vim and Hugo made it into a bunch of static pages that I uploaded to my webserver. Hugo has many features, like themes, RSS feeds, tags etc and is very practical to use if you use markdown on a regular basis. Since I was a vim user, my idea was to use markdown for everything and use Hugo for my website and pandoc to convert my .md files into LaTex-styled PDFs, LaTex Beamer presentation PDFs, ODTs and the occasional .docx when needed. I converted most of my older documents to .md and worked like this for a while. Then my Emacs curiosity got the better of me, and this spring, I started dipping my feet into Emacs.

I soon realised the power of Org Mode and that it could replace my former markdown workflow with practical features like automatic tables, lots of easy to use keyboard shortcuts for creating the .org markup syntax and very easy exporting to all the aforementioned formats plus many more. Not to mention that it is also a calendaring and todo-system, that you can use for literate programming, that it can also be used for journaling, a personal note taking system with reverse-linking etc. Naturally, I have been looking for a way to write my blog posts in Org Mode as well. Many people use Hugo and just convert their .org files to .md files with the emacs package ox-hugo. To me, this seems to be one step more than what I would actually like to do and what is actually necessary. After the war in Ukraine started, I left my website with just a static HTML page, but I have recently wanted to get back into blogging. I had started to work on making a program to make a static site from a bunch of .org files when I discovered the Emacs package org-static-blog that did the same. My plan with my program was to make it first in Bash Shell since I am more familiar with that language and then move it to Elisp for easy integration with Emacs later. Org-static-blog made all that work unneccessary.

Org-static-blog makes a nice index page with a blog-roll of the newest pages, an archive page and an RSS feed. You may also add links to other static pages you would like to include. If you use the tags feature, you can also get RSS feeds for each tag. Personally, I want to just keep things simple for now and have opted out of that feature. To make a new post, you just write an .org file with a title and date and optionally also a description and file tags metadata on the top and then just write your content. Each .org-file becomes a blog post. You can also use org-static-blog-create-new-post to automatically make that document with the correct tags for you which is nice for people like me that have yet to start using metadata heavily in Org files and would enjoy a helping hand with that.

When you are ready to publish your blog, you just run org-static-blog-publish in Emacs, and org-static-blog spits out all the HTML-files you need in your chosen export folder. To make the site look nice, you should make a style.css file that you put into your export folder and link to it in your header as described in the README. There are no themes, but the author links to his own website's Git repo where you can grab his style.css and tweak it to your own liking. As a dark mode lover that also likes to keep things simple, I have opted for a simple black and white look with the occasional light blue for links. The CSS styling is set it and forget it, so after the initial tweak, you are good to go. Just org-static-blog-publish and upload your static files to your website and there you go.

org-static-blog.jpg

The advantage of using a static site generator over something dynamic is faster load times and easier access to content for non-JavaScript enabled users. Not having unecessary JavaScript running just to show some content that is easily accessible without it also saves power for the site visitors which is good both for the environment and their economy and especially important when Europe is going through an energy crisis caused by Putin's invasion of Ukraine and energy war with Europe.

© Einar Mostad 2010 - 2025. Content is licensed under the terms of CC BY SA except code which is GNU GPL v3 or later.
Made with GNU Emacs, Org-Static-Blog, and Codeberg Pages on GNU/Linux.