🏠 About Now Archive Tags RSS

Newest posts:

Speed improvement hack for dired with EWW

I have used EWW in Emacs for some of my browsing for a while and it does the job very well unless browsing single page applications or other sites that do not send HTML unless you run JavaScript. Thank you Lars Magne Ingebrigtsen for making EWW! Hitting R filters out all the noise for a really pleasant reading experience. It is good to browse within Emacs with no context switching in a keyboard-driven way.

(Apropos they joys of context switching: When I am a bit tired, I use Emacs keybindings everywhere. Tap-to-click is naturally off on my laptops to prevent insanity. I am often able to "help" my students a lot within just a few seconds of random keybindings and clicking everywhere on their laptops. It is really good for students to learn patience and tolerance towards people unable to handle computers. They need that for their user support class and future work in the IT industry.)

When Joshua Blaise wrote about his eww setup and use, I read it with interest and stole most of his ideas for my own config. The important one for this little hack is that I set up URLs with endings like .mp3, .mp4, .m4v, .mkv etc to launch in mpv when browsing to them. This makes watching videos and listening to audio content easy with EWW. EWW is also good for browsing local files where the URL is file:// and so forth.

In dired, I usually launch external programs for photo editing, media playback etc by pressing & with point on a file name. This brings up the completing-read interface in the minibuffer which asks me if I would like to use dired's guess as to which program to use (which I have set to guess xdg-open first) or something else. I press return and then mpv, gimp, darktable or whatever launches with the file.

I had an html file in my downloads folder which I launched with W to read it in EWW. I then, by mistake, hit W when on a .mp3 file, and it launched in mpv. Since W launches the file in EWW and EWW was configured to open .mp3 files in mpv, it did that without asking me which program to use. It is faster to hit W than to hit & RET, or in worst case write a program name and RET. So now I launch media files with W in dired in stead of using &. It speeds things up a bit.

(While writing this, I also remembered that I have functions for playing enclosure links and links in elfeed through mpv that I might replace or improve by shuffling the links to EWW or einar-browse-url-mpv. I wrote my configuration for elfeed very early in my Emacs journey, without really understanding any of it, by copying snippets from the Emacs wiki, blogs and Reddit so it is high time to look at it again anyway. I can probably simplify it.)

Here are the relevant parts of my configuration for EWW to get this working:

(defun einar-browse-url-mpv (url &rest _args)
  "Opens URL in mpv."
  (start-process "mpv" nil "mpv" url))

(use-package eww
  :config
  (setopt browse-url-handlers
          '(("\\(youtube\\.com\\|youtu\\.be\\|vimeo\\.com\\|twitch\\.tv\\)" . einar-browse-url-mpv)
            ("\\.mp3$" . einar-browse-url-mpv)
            ("\\.mp4$" . einar-browse-url-mpv)
            ("\\.webp$" . einar-browse-url-mpv)
            ("\\.m4v$" . einar-browse-url-mpv)
            ("\\.mkv$" . einar-browse-url-mpv)
            ("\\.pdf$" . einar-browse-url-pdf)
            ("." . eww-browse-url))))

Fix Emacs python-mode REPL and org code block with python evaluation problems

For a while now, the python shell in Python mode in Emacs has not worked properly on my work laptop. I get some strange glyphs in the top of the python shell buffer when opening it from a file with C-c C-p and when I tried importing a file with C-c C-c, I would get an error saying stringp was nil and every character in what I tried to import was written first once, then together with the next, then the next three and so on. It looked somewhat psychedelic and was more or less unusable.

I also had trouble evaluating python code blocks in org mode which has been annoying when presenting with inter-present-mode for my students or exporting from org files I used for presentations to PDF or docx to upload to our school's learning platform (it's learning). In org, I would get the same error saying stringp was nil when evaluating code blocks that I would get when trying to import files to the REPL in python mode.

I first thought the problem was related to my einar-python-virtualenv function which locally changes the python-shell-interpreter for a file if it is in a project with a virtual environment since I made that quite recently, but the strange thing was that it worked perfectly on GNU Guix on my main machine at home. I then thought maybe it was a Windows 11 problem since I only experienced it at work, so I tried on a Raspberry Pi 4 at work with the latest Raspberry Pi OS and I had the same problem.

I then tried launching Emacs with -q to see if the problem was related to my config or not. When I then launched the python shell from a file with C-c C-p, the REPL itself worked slightly better, but I still got some strange glyphs at the top. I then spent some time trying to figure out where in my config the problem appeared and removed first the einar-python-virtualenv and then my configuration for python-mode, but the problem persisted. I also looked into whether some setting for comint-mode might cause the problem.

After spending one and a half hour trying to troubleshoot this on Monday, I today realised I updated Python to 3.14 on my work Windows 11 laptop a while ago. I checked the python version on the Raspberry Pi and it was 3.13. I checked packages.guix.gnu.org and Guix uses version 3.11. I thought maybe something changed in one of the newer versions. I had a look at news for version 3.14 and did not find anything promising. I then checked out what was new in 3.13 and one of the first things was a new and improved python shell.

Luckily, you can get the old shell that python mode in Emacs works with by setting the environment variable PYTHON_BASIC_REPL to something. When I added this function call to my Emacs config for python mode, the python REPL works in python mode again and it is possible to evaluate org code blocks and export files that will evaluate them on export again:

(setenv "PYTHON_BASIC_REPL" "1")

I write this so others experiencing the same problem can find a solution. In the long term, python-mode, python-ts-mode and org mode needs to work with the new and improved python shell since the old shell will probably be removed at some point in the future, but for now, just setting the environment variable is enough to get both the REPL and org code blocks working again.

Use python shell from virtual environment if there is one in Emacs

About a week ago, I made a function to use python from a virtual environment if there existed a directory called venv within the project the file is inside. This works for me since I tend to call virtual environment directories venv. The point of the function is to get access to the packages within that virtual environment when using the python shell to evaluate code from a file or interact with its functions, classes and variables through the REPL. I usually write my code and then test it through the REPL and do the necessary adjustments when there are mistakes. (I probably do this since I learned basic programming principles by teaching myself HyperTalk by reading the Help stack and experimenting in the Message Box (a REPL) in HyperCard in the late 80s.) I think a lot of people overlook this great way of working in interpreted languages.

Today, I had a look at that function again. I thought it would be really nice if I could find the python executable within a virtual environment no matter what the virtual environment directory is called. I found that this would work:

(defun einar-python-virtualenv ()
  "Sets the python shell to python from a virtual environment if one exists."
  (when (project-current)
    (let ((pythonpath
           (nth 0 (directory-files-recursively
                   (nth 2 (project-current))
                   (if (eq system-type 'gnu/linux) "python$" "python.exe$")))))
      (when (file-exists-p pythonpath)
        (setq-local python-shell-interpreter pythonpath)))))

I need to run this function whenever I open a python file to set the correct path to the python shell for that file. This is done by adding the function to the python-mode hook like this since the mode hook is run every time you open a python file:

(add-hook 'python-mode-hook 'einar-python-virtualenv))

With this in place, whenever I open a python shell with C-c C-p from a python file, I get a python shell from within the virtual environment of that file's project, or I get the system python if there isn't a virtual environment within the project the file is part of.

Fix error with Cider Clojure REPL in Emacs on Guix

I am currently reading Clojure for the brave and true by Daniel Higginbotham and in Chapter 2 about how to use Emacs for Clojure, there are instructions on how to set up Emacs with Cider, a Clojure REPL. I tried installing the package with a use-package configuration with :ensure t and I got the package. However, when I tried using it as the book instructed, I just got an error. I then realised the need for OpenJDK and Clojure and installed those with my home-config.scm file in Guix. I tried again and I still got the same error. I then tried installing emacs-cider from Guix as well with the hope that maybe there was some kind of incompatibility between OpenJDK, Clojure and Cider that was ironed out in the guix package. It still did not work.

I tried looking up the error and found a blog post that suggested installing OpenJDK non-Guixily by downloading a binary and adding it to the $PATH which solved the problem for that user. I did not really want this, since I really like the idea of installing my whole system with a scheme file or two in a reproducible way. (I'm not there yet, but I hope to get there over time. I just started using Guix as my main distro a few weeks ago. For now, after installing Guix System or Guix on another distro, I do some manual work and then run a Shell script to set up a few folders and run the command that applies my home-config.)

Tonight, a day later, I DuckDuckWent again and found another blog post about Clojure that told me that since there are three outputs for the openjdk package, to get everything I would need for Clojure, I should install openjdk:jdk, not simply openjdk which would give me openjdk:out. In addition, I also added openjdk:doc since I am a fan of having as much documentation as possible available on my local machine. I saw a video where that documentation was read from inside Cider a couple of days ago, so I thought it might come in handy. Come to think of it, maybe that was accessed over the internet, not from the local machine. Anyway, it doesn't hurt to have some documentation.

And now, everything just works. Turns out the problem was just user error. Whenever there are multiple outputs of a package in Guix, it is important to know what you get with each output and choose accordingly. As someone who just recently switched my main machine to Guix, this is very useful information that I had not seen before. I thought I would write this up in a blog post so people out there trying to fix the same problem have a chance of finding a solution faster than I did, and for my own future reference.

Adventures in Guix

I have been interested in the Guix functional package manager and GNU distribution for a long time. It has some brilliant features like being able to roll-back to a previous generation of your system if an update fails, easy spinning up of development containers where you can functionally and reproducibly install the dependencies you need for your project and you can configure your whole system with Guile Scheme (a dialect of Lisp). I have tried Guix from time to time with varying results. Since I have been busy the last few years learning technologies I need at work, haven't had the time to learn Guix as well until now. However, I have found some time and energy lately to play with Guix and when I did, things seemed to work a lot better than my previous attempts. Spending the time to read up on the documentation helped, in addition to the many contributions by the Guix community to improve the distro / package manager since my previous attempts.

I have just started to use Guix on my main machine. As with anything new and different, there has been some hiccups along the way. For example, hunspell-nb which is the spell checker I use for Norwegian Bokmål isn't packaged for Guix. However, aspell-nb is and the only reason I switched from aspell to hunspell was that I also use Emacs on Windows at work (native Windows Emacs since WSLg doesn't work properly and I need GUI Emacs) and native aspell-nb is hard to get on Windows, but Hunspell-nb can be used if you install LibreOffice and copy some files after installing hunspell from chocolatey (where of course hunspell-nb is not packaged either). I prefer not having if-statements in my Emacs config if I can avoid it, so I switched to hunspell on GNU/Linux as well, but since it is not pacakged in Guix, I reverted the config back to when I used aspell on GNU/Linux and Hunspell on Windows.

However, that did not work. At every startup, Emacs complained that it could not read the nb dictionary from the address to the aspell-package in my current home-config. I tried everything, but it just didn't work. I then tried M-x ispell-change-dictionary and hit tab to have a look at the suggested dictionaries. Turns out that aspell-nb on Guix supplies a dictionary it calls no, unlike on every other distro, where it is called nb. This makes absolutely no sense since there are two Norwegian written languages, Norwegian Bokmål (nb) and Norwegian Nynorsk (nn), but no written language called just Norwegian (no). Packages that supply both tend to be called no, like hunspell-no which supplies nb_NO and nn_NO. It is easy to change my config to use the no dictionary and my emo-ispell-toggle function to toggle between no and british on GNU/Linux. I had a look at the package definition for aspell-nb, but it seemed to just supply the upstream package as far as I could tell as a very inexperienced Guix-user.

Another strange thing is that mpc mode in Emacs does not want to speak with mpd. It also took me a while to understand that mpd was packaged for Guix since I looked for mpd, but the package is called mpd-mpc in Guix. The strange thing is that my own emo-play-album function in Emacs that uses mpc shell commands work fine from the same Emacs that give me an error that it could not communicate with mpd when I try to show the songs in an album in mpc mode. I use the same mpd config file as on other distros where it does work. I tried changing some settings in the config file to see if I was able to fix it, but no luck thus far.

I also miss the frogr package for easy uploading of photos and adding of metadata to Flickr. When I get a bit more experienced, maybe I can contribute a package definition for it?

Another thing I have noticed is that Guix calls my locale in the LANG environment variable nb_NO.utf8, not nb_NO.UTF-8 like every other distro. I wonder if this might break localisation in programs that use the environment variable $LANG to choose which localisation to use, but I don't really know how this works so this might not be a problem at all. It seems strange and random, but maybe there are good reasons for it that I don't know.

Except for these new user problems, the experience is nice. After some tweaking and trial and error, I now have a very simple and basic system config that just installs the absolute minimum I need to have at the system level, and then I use Guix home to deploy my user packages and services. I have some Bash scripts in my installscripts repository as well as my Scheme config files that I can use to set up a system, either on Guix or on a "foreign distro" after an install with just basic system tools. Ideally, I would do that with Scheme in the system config, but I don't know Guix and Scheme well enough to do that yet. I'll get there over time. Using Guix as a package manager on top of another distro can be useful if I need to use Secureboot which Guix does not support, for example for a dual boot with Windows 11 which demands Secureboot. I really like that Guix adheres to the Free Software Foundation's Free System Distribution Guidelines, but when used on hardware I have not chosen myself, it can be useful to have another distro underneath that supplies non-free drivers for that hardware as well as support for Secureboot. I am slowly climbing up the freedom ladder in my personal computing and at every step, there is less lock-in, privacy invasion and enshittification, and more freedom and empowerment.

© Einar Mostad 2010 - 2026. 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.