The pages where I write about Emacs. It doesn’t happen very often. I think you’re probably best off following Planet Emacsen, the ultimate Emacs related blog aggregator.

2020-10-23 The finger memory of incremental search, or switching to swiper

I’ve used C-s and C-r to search in Emacs for ages. One of the most used combos was to move somewhere, start incremenental search, and yank some words from the current position in the buffer: M-b M-b C-s C-w C-w C-s. Now I’m trying to give Swiper a fair try. I’ve been using Yvy Mode until now but I never went all the way.

Recently, however, I stumbled upon the Swiper repository, which comes with a README that has a sample rebinding of keys for all the Ivy, Counsel and Swiper stuff. One of them was to use C-s for swiper-isearch instead of isearch-forward. OK! I’m going to try it.

Note that swiper-isearch is not line-based like swiper is. That is, <down> goes to the next match, even if the next match is on the same line.

But… my fingers are all confused, now. I need to switch modifier keys: M-b M-b C-s M-j M-j <down>. Perhaps I should start using M-s instead. But then again, that prefix hides a ton of functionality. But then again, I never use it.

This is what Emacs Paralysis looks like, I’m telling you!

Anyway, once you started your search for the current word using C-s M-j you can use C-c C-o to switch to Yvy Occur mode. From there, you can use w or C-c C-p to switch to Wgrep mode, which allows you to make changes to the buffer and to write them back to the files using C-x C-s. Strangely enough this doesn’t work if you’re using it in a buffer that has no file associated with it! How strange. This must be an unintended consequence of the grep heritage.

In any case, I’m still trying to get used to this. And I’ll give iedit a try as well. I’m hoping for some sort of refactoring support in Emacs.

All of these idea are from @takeonrules’s blog post:

Add Comment

2020-08-26 Emacs without the bling

On Mastodon, @pet84rik posted a link to Emacs, naked., by @bzg. I compared it to my own setup and found that I use many of the same things.

;; deactivate some bling
(dolist (mode '(tool-bar-mode
  (when (fboundp mode)
    (funcall mode -1)))

You can find code like this and similar stuff in my Emacs config, which is a lot better organized than it used to be.


When I scrolled down, however, I noticed something else: Bastien hides the mode-line completely. I’m using @algernon’s Brutalist Dark theme, which has visible mode-lines but the inactive mode-line is not readable (foreground and background colour are the same). It’s less distracting. Still, I started wondering.

With minor tweaks, I added the following:

(defvar-local hide-mode-line nil)

(define-minor-mode hidden-mode-line-mode
  "Minor mode to hide the mode-line in the current buffer."
  :init-value nil
  :global nil
  :group 'editing-basics
  (if hidden-mode-line-mode
      (setq hide-mode-line mode-line-format
            mode-line-format nil)
    (setq mode-line-format hide-mode-line
          hide-mode-line nil))
  ;; Apparently force-mode-line-update is not always enough to
  ;; redisplay the mode-line
  (when (and (called-interactively-p 'interactive)
     0 nil 'message
     (concat "Hidden Mode Line Mode enabled.  "
             "Use M-x hidden-mode-line-mode to make the mode-line appear."))))

;; Activate hidden-mode-line-mode
(hidden-mode-line-mode 1)

;; Hide the mode-line in all new buffers
(add-hook 'after-change-major-mode-hook 'hidden-mode-line-mode)

;; Use F12 to toggle modelines
(global-set-key (kbd "<f12>") 'hidden-mode-line-mode)

I’m liking it! And when I occasionally want to see something – mostly the column I’m at while I’m writing the first line of a git commit message – I can quickly use F12 to see it.

I remember in the old days I needed the mode-line to track IRC activity. These days, however, with me being connected to a bunch of Discord channels that I never read, and a bunch of Mastodon accounts, all via Bitlbee, the actual mode-line is far less useful than it used to be.


I continued scrolling down on Bastien’s page and saw the centred Emacs window (using the fringes). This would actually work very well for me, since I always use Emacs in full-screen mode. I recommend it! But if you’re not a big user of C-x 3 to split the window into two side-by-side windows, then all your text is going to on the left side of your monitor. Not good! Not good.

So here we go:

;; center the window by adding a very wide fringe
(define-minor-mode center-window-mode
  "Minor mode to center the window using wide fringes."
  :init-value nil
  :global t
  :group 'editing-basics
  (if (not center-window-mode)
      (set-fringe-style nil);; default
     (/ (- (frame-pixel-width)
           (* (+ fill-column 4)

(center-window-mode 1)

;; Use F9 to toggle centering
(global-set-key (kbd "<f9>") 'center-window-mode)

This uses the fill-column to calculate the width of the fringes. If you’re suddenly in a buffer with a different fill-column, just use F9 F9 to toggle it off and on again, and the new fill-column value is taken into account.

I’m sure this could be smarter, but it basically works for me. When I’m programming, I often use up to 120 characters per line; the fill-column only affects comments. I therefore leave it where it is and just toggle the centring of the window. The font-size I prefer to use and the width of my laptop screen give me about 125 characters per line max. Those two or three characters don’t make a big difference in the left margin, so I don’t really need code to do <f9> C-u 120 C-x f <f9> – I tried it and it wasn’t worth it.

So here we are.


Actually, let me get back to the window splitting issue again. I started talking with @ckeen and I think my main problem with Emacs is that it’s hard to keep the window configuration stable. As soon as you start using help, man pages, IRC, and the like, you’re going to mess up your window config. I use Winner Mode to get back to stuff I’ve set up but it’s mind numbing and so I most often just use C-x 0, C-x 1, and C-x 2. C-x 3 is reserved for the rare occasions where I need to compare something side by side and it’s not an ediff situation.

Back when I was interested in this (2012), I tried to write code to force all activities to stay inside one window and failed. What I wanted was “what happens in a window, stays in a window” – and I guess I’d still be interested in working code. It’s just that I gave up on it.

Comments on 2020-08-26 Emacs without the bling

Hi, Alex, You can either prevent specific buffers from splitting the window with

(push (cons "\\*shell\\*" display-buffer--same-window-action) display-buffer-alist)
(push (cons "\\*scheme\\*" display-buffer--same-window-action) display-buffer-alist)
(push (cons "\\*Help\\*" display-buffer--same-window-action) display-buffer-alist)
(push (cons "\\*Buffer List\\*" display-buffer--same-window-action) display-buffer-alist)

That’s what I do. Those are the ones that pop up all the time and mess things up, and that I especially want and expect to just work like normal windows.

Or, instead of doing that, you can make the frame “unsplittable”, which, weird name for it, because you can still use C-x 3 and C-x 2 etc.

(add-to-list 'default-frame-alist '(unsplittable . t))

I don’t do that (I tried it but some things got weird) but I might if I was using a ton of weird new modes. But the take above, selecting a couple of favorite modes to just behave like normal windows and not pop up all the time, works fine.

The “unsplittable” doesn’t prevent you from doing C-x 2 and the like manually at all.

TL;DR display-buffer-alist is awesome and secondarily and kind of unrelated frames can be made unsplittable now.

Sandra 2020-08-29 21:01 UTC

Oh, that sounds very doable! Thanks!

– Alex Schroeder 2020-08-29 22:54 UTC

I should add ligatures and better emoji support one day. See Unicode, Ligatures and Color Emoji by Mickey Petersen.

– Alex Schroeder 2020-09-08 05:29 UTC

Add Comment

2020-08-14 Uses this

Somebody asked me for a “uses this” page… The short answer is: I use Emacs.

But here’s the long version. Because I’m vain. 😆

Alex Schroeder

Who are you, and what do you do?

I’m a code monkey for a Swiss and German company. We do business software using Java and databases. It used to be mostly Oracle, these days it’s mostly PostgreSQL. This is still my first job. I’ve been doing it for more than twenty years. That is to say, the programming is boring, the tech isn’t exciting, and I’m old. But the part I love is switching projects, again and again. New team members, new project managers, new clients, new faces, new industries, I love that. I mean, it’s also a bit devoid of meaning, of course. In the grand scheme of things, who cares for car leasing, investment banking, furniture, call centers and credit cards? Nobody I love, that’s for sure.

And yet: I love to program. The world of programming is where I can make things. Like people tinkering with their cars, woodworking, knitting, sewing, playing music, baking, cooking, painting, I want to make things. Making things online comes easy to me and so I do it a lot. I only work a 60% job so that I have long weekends and long summer breaks, allowing me to follow my whim. One year it’s a local IRC server that acts as a gateway to Mastodon, the next year it’s a wiki using the Gemini protocol and markup as much as possible. I fall into projects in summer.

What hardware do you use?

I use a Purism Librem 13v2.

I have a bunch of external keyboards (Atreus, Keyboardio Model 01, Touchstream, Ergo Kinesis) but I don’t use them. I got used to laptop keyboards. And if my hands hurt, I know that I should just stop, not switch keyboards.

I also don’t use a mouse. I use the trackpad. When I’m drawing, I use an Apple Pencil and the iPad Pro. I rarely draw.

When I make music, I use various emulators on the iPad Pro, or the OP-1 or PO-33 K.O! by teenage engineering. I rarely make music.

For my podcasting I started recording voice memos with my phone; later I bought a second hand Snowball by Blue.

When I’m in the office, I use a regular Sennheiser Momentum for headphones. No wireless. No noise cancelling. I tried some noise cancelling headphones earlier and felt like it surpressed the background noise but not the voices and what I hate about the open plan office is the voices of my coworkers. A long time ago I had Shure in-ears. True plugs. Maybe I should get some in-ears again.

And what software?

The laptop runs PureOS, a Debian derivative. I picked a laptop that came with a Debian preinstalled. I hate installing software. I also dislike how out of date Debian can be, and I don’t like how they think the GNU manuals are not free, but overall, I still like package managers. Thank you so much!

In general, though, I’m not a operating system or distro hopping nerd. I used Slackware in the very old days and would not mind going back. I like to use Debian because I also use Debian on my server. My wife has an Apple laptop that I used for a long time, with Homebrew. Over the years I got angry about all the complications with iMovie, iTunes, iPhotos… it was difficult to get the stuff out again. The iTunes interface degraded over the years. Importing pictures into iPhotos led to crashes. It all started to feel like a thin veneer of sugar that was made to entrap me, and still didn’t deliver the stability I wanted. Instead I got mental models that didn’t fit the underlying models, if you know what I mean. The “events” and “playlists” cannot be found in the folders on disk, but the “rolls” are “importing events” and the “albums” are “folders” except when they’re “compilations”… Eventually I decided that I wanted to just use the filesystem again. Have files in folders. This I can understand. And on this level, Emacs can be used for practically everything.

Actual music playback is a command line tool like mpg321. When I look at PDFs, I use Evince because I find that Emacs’ document viewer mode is too slow. Or perhaps I just haven’t gotten used to it? Or is it the missing links? I don’t know. Maybe soon I’ll do without an external PDF viewer. 😁

When importing images from the iPhone, “Files” (is it still Nautilus? I have no idea) and whatever it invokes (gThumbs?) just work. It’s amazing that I don’t even know what this software is. Gnome something. It just works. This makes me happy.

When I’m organizing my images, I need a quick, keyboard driven user interface. Sadly, Emacs isn’t quick in this regard. I use Geeqie instead. The ability to use the ten digits for quick tagging is perfect. Go through the images and use 1 for album, 2 for delete, 3 for review, 4 for family, whatever, and then when you’re done, move the images around based on those temporary tags. ♥

When I’m editing my podcast, I use Audacity. I tried other programs, but most of the time their user interfaces are all tiny. I use a small laptop and I like big fonts and big icons. Audacity is the limit.

For graphics, I use Inkscape and Gimp (I hope to see Gimp replaced by Glimpse, soon!) – what a name. Yuck! It reminds me of that Quentin Tarantino movie and I hate Quentin Tarantino movies. On the iPad, the only app that I actually like using is Zen Brush 2. I somehow can’t get used to Procreate or Art Set or any of the other apps.

For making music, I use the iPad. The apps I like to use are PixiTracker (which is also available for other platforms), the iVCS3 emulator, the Model D emulator, the Animoog emulator, Synth One, and GarageBand (mostly for instruments like the Pipa, Erhu, Koto and Guzheng). I’d love to know more about music and must resist the temptation to buy more music making hardware without having taken full advantage of the things I already have. The temptations of capitalism…

The projects I work on in my spare time often use Perl 5. I sometimes try other languages: Python, Raku, Go, Scheme… but I always come back to Perl. Perhaps people just like to stick to their first language because that’s where their experience lies. You have made all the mistakes in the distant past and now everything comes naturally.

All the Perl projects I work on use the web as the universal user interface. I know, I know. I hate the web. It’s big and bloatet. And yet, the browser is the universal client. Huge, and bloated, and requiring a thousand engineers, I know. But none of the alternatives are great, either. I still haven’t written a GTK or Qt application, let alone something using X11, wxWidgets, or Tk. HTML and SVG it is, for me.

What would be your dream setup?

I have no idea. I want everything to just work, with no installation, and I love Emacs.

I’m fascinated by the Plan 9 concept of everything being a file, but at the same time, why can’t we have a system where everything is a file, and Emacs? Plan 9 has no Emacs. Emacs is like a universal Lisp machine: it provides a universal user interface to the underlying operating system and thus to the machine. It’s not perfect, yet. It often relies on tools that aren’t immediately available on Windows, for example – grep, find, sed – and you need external tools to play MP3 files and to edit their metadata.

Now that I use the Apple Pencil on the iPad Pro, I imagine how hard it is to draw on a traditional computer, even with a good tablet. And how would all of that work within Emacs? I would love to see all the Gimp stuff gobbled up by Emacs.

Comments on 2020-08-14 Uses this

I am really digging the love for EMACS that everyone is pouring out at the moment!! It’s probably because of its new release. I really enjoyed this gemini post 🙂 ~VIDAK

– elpherwVSLR9 2020-08-14 14:10 UTC

Haha, yeah! Emacs is great. I love it, too. And Elpher and Emacs together... my favourite way to comment on my wiki!

Karl Voit sent me a message on Mastodon about the naming and tagging he does using Geeqie with the addition of a small number of nifty scripts. An interesting workflow! And I totally agree with him: file names and folder structure is the kind of metadata that lasts a lifetime. Everything else is tricky.

– Alex

Add Comment

2020-08-14 How to comment using Elpher

If you visit this site using Elpher, you can leave a comment using Gemini. The comment can’t be too long. I think the total URL should be limited to about a thousand bytes, some of that is the URL without the query, and the query itself is going to be encoded… Who knows. Perhaps this server doesn’t actually check URL size? I have no idea and I have never tried. Ooops!

Here’s a video demonstrating it:

(Emacs using the Brutalist Dark theme…)

The video was recorded using Peek. It was edited and the audio was added using Pitivi. The audio was made on a tiny toy, the PO-35 speak. Basic recording was done using Audacity.

Comments on 2020-08-14 How to comment using Elpher

dogs are good

– elpherGiUS7i 2020-08-15 04:42 UTC

very cool, nice! great wiki 🙂

– elpherbqnGZw 2020-08-15 15:14 UTC

Hi from a patched Elpher! ~ michel

– 2020-08-15 23:24 UTC

Hah, I think most people don’t use the certificate’s Common Name to identify themselves but to identify the site they intend to use it for. Perhaps that’s some sort of usability issue: you want to create a new permanent certificate with your nickname as the Common Name, and save it using a filename identifying the site (or sites) you want to use it for. 😀

– Alex 2020-08-16 12:12 UTC

Nice. 🙂

– elpherzbK550 2020-08-16 12:30 UTC

Add Comment

2020-07-16 Emacs everything

These days I mostly use Emacs on my laptop. Sure, there’s all that stuff in the background. But in terms of applications I actually launch, I’d say I mostly use just Emacs.

I use Firefox for some websites, but I don’t actually do a lot of surfing. I spend a lot of time using Mastodon but with Bitlbee and the Mastodon plugin, I get the gist of things on IRC, and my IRC client is rcirc, in Emacs.

My Gemini client is Elpher, in Emacs. When I follow links in Elpher or IRC, they open in my default web browser, and my web browser is EWW, in Emacs.

(set browse-url-browser-function 'eww-browse-url)

Actually, there’s a little more customizing I do. First, I don’t need cookies:

(setq url-cookie-trusted-urls '()
      url-cookie-untrusted-urls '(".*"))

Cookies were invented for shopping carts and that’s where they should remain.

And I like to follow Gemini and Gopher links from my browser, so here’s how to handle them:

(advice-add 'eww-browse-url :around 'asc:eww-browse-url)

(defun asc:eww-browse-url (original url &optional new-window)
  "Handle gemini links."
  (cond ((string-match-p "\\`\\(gemini\\|gopher\\)://" url)
	 (require 'elpher)
	 (elpher-go url))
	(t (funcall original url new-window))))

Did you know about Readability in EWW? Use R. 😀

I work a lot on the command line, but a lot of my work on the command line is actually just making directories, using git, and running tests, and all of that is better done in Emacs. Dired is my file manager, Magit is my git interface most of the time, Eshell is my shell.

I remember the days thirty years ago when I used Norton Commander on a 286. It was so much better than MS DOS 3.3 or whatever I used back then. But when I try to use Midnight Commander in a terminal, or Sunrise Commander in Emacs, soon enough I end up back in Dired.

I think there are some important things you need to do for Dired, though:

(eval-after-load "dired"
  '(require 'dired-x))

(setq dired-recursive-deletes 'always
      dired-recursive-copies 'always
      dired-deletion-confirmer 'y-or-n-p
      dired-clean-up-buffers-too nil
      delete-by-moving-to-trash t
      ;; trash-directory "~/.Trash/emacs"
      dired-dwim-target t
      	  '(("\\.pdf\\'" "evince")
	    ("\\.jpg\\'" "feh"))
      dired-listing-switches "-alv")

Let’s go through them:

  • Some of the stuff I’m going to customise is actually part of the Dired extensions, so make sure those get loaded as well (but only when actually using Dired)
  • When deleting or copying directories, I always want to do this recursively.
  • When confirming things, I hate typing y e s and hitting the Return key. A simple y should be enough.
  • The buffer cleanup is another annoying question it likes to ask.
  • Very important: switching from rm to trash on the command line has been good for me a few times and so I was happy to see that Dired can also use the system trash.
  • Do-what-I-mean (DWIM) target means that whenever you have two dired buffers, the other buffer is suggested as a destination for commands that require one. Instant Norton Commander feelings: C-x 2 to split the window, change the directory in the current window, then copy or rename from one to the other.
  • When using ! on a file, Dired will suggest a command, but for JPG files the suggested command is xloadimage (where as for PNG files it is display), and for PDF files the suggested command is xpdf. I was interested in learning more about feh and my PDF reader is Evince, so that’s where these two settings come from.
  • The switches use -v in addition to the default switches, and that stands for natural numbers. Thus, foo-10 comes after foo-9, finally.

But there’s more:

(add-hook 'dired-mode-hook
	  (lambda ()
	    (local-set-key "E" 'emms-play-dired)
	    (local-set-key (kbd "C-c w") 'wdired-change-to-wdired-mode)))

Writable Dired (WDired) mode is cool because you can edit the buffer and rename a bunch of files all at the same time, using Emacs commands. In these situations using the rectangle commands come in super handy: C-x r k to kill a rectangle, and C-x r t to insert text on every line are my favourites.

EMMS is my music player, in Emacs. At home I don’t use it often, but at work I often need to listen to music. Fuck those open office plans. Project managers love it because they love to hear the buzz, get a feel for what the team is working on. For the team itself, however, it’s hell. We get to wear headphones almost the entire time because we can’t focus if we don’t. What a shitty way to program.

Back to EMMS... I usually use Dired to navigate to my music collection and then just hit E on a folder to play all of it. Perfect.

As loading EMMS can take a while because of the cache, I try to delay doing it. It’s only when nothing happens for a few seconds that I proceed. As you can see, my music player setup is super simple: I just use mpg321 or mpg123 or ogg123... As I said, it’s not fancy, can’t hit pause, don’t get lyrics, but it’s good enough for what I need: playing some music while I try to avoid the endless chatter of the people around me in the open plan office, GAAAAAAH!

 10 nil
 (lambda ()
   (require 'emms-setup)
   (if (executable-find "mpg321")
       (setq emms-player-list '(emms-player-mpg321))
     (define-emms-simple-player mpg123 '(file url)
       (emms-player-simple-regexp "mp3" "mp2")
     (setq emms-player-list '(emms-player-mpg123)))
   (when (executable-find "ogg123")
     (add-to-list 'emms-player-list 'emms-player-ogg123))))

Anyway, a small window into my Emacs life.

As you can see in the screenshot below, I use a big font, run Emacs maximised. I use them all maximised: Emacs, Tilix, Firefox, Evince... I don’t have time for tiling.

(cond ((find-font (font-spec :name "Iosevka"))
       ;; on windows, this defaults to a different font?
       (dolist (face '(default fixed-pitch))
	  face nil
	  :family "Iosevka"
	  :height (if (eq (window-system) 'w32) 180 220))))
      ((find-font (font-spec :name "Noto Mono"))
       (set-face-attribute 'default nil :family "Noto Mono" :height 200)))

In the mode-line you can see my IRC setup. The theme I use is brutalist-dark. Thanks, @algernon.

I also deactivate the blinking cursor, the tool-bar, the menu-bar, and the scroll-bar...

;; deactivate some bling
(dolist (mode '(blink-cursor-mode
  (when (fboundp mode)
    (funcall mode -1)))

And some stuff I need:

Matching parenthesis are important for programming languages with lots of parenthesis, hehe.

Winner mode lets me go back to particular window configurations. Let’s say I have used a bunch of C-x 2 and C-x 3 and C-x + to get a few buffers to show in just the right way, and then a few uses of C-h i or C-h f or C-h v or M-x man to get help and it gets all messed up? Use C-c <left> to get back to that old layout.

Windmove allows me to use shift and the arrow keys to move from window to window Which is important if you have more than one in Emacs. If you have just two, C-x o is probably good enough.

Showing the column is sometimes important, I guess? Now I can’t remember when it ever was important. Something to be removed soon, I guess.

I also like my Emacs to not beep. I like completion to ignore case, and I don’t use double space to end sentences. When this is really important I use non-breaking spaces after abbreviations. I’ve changed my Caps Lock key to be the Compose Key. Very useful!

;; active some other bling
(show-paren-mode 1)
(winner-mode 1)
(column-number-mode 1)

(setq visible-bell t
      completion-ignore-case t
      read-buffer-completion-ignore-case t)
(setq sentence-end-double-space nil)

And here’s the screenshot...



Comments on 2020-07-16 Emacs everything

My config files are online... see my Emacs setup.

– Alex Schroeder 2020-08-14 10:07 UTC

Add Comment

2020-07-02 An overview over my Gemini projects

A while ago I started writing lots of stuff for Gemini. Time for an overview, both for myself and for you, the hypothetical reader. 😀

I’m not going to link to the various blog posts where I’ve talked about the various projects before. If you want to find them, take a look at the Gemini tag.

Gemini Server is a server that serves an existing Oddmuse wiki via Gemini protocol. It also tries translate the wiki text from a typical Markdown + Wiki mess like the one I’m using on this wiki here into Gemini format. I think it works and you can look at it using your favourite Gemini Client. It’s at alexschroeder.ch:1965.

Gemini & Titan for Bash are two functions for bash. I use them all the time to debug stuff. The gemini function uses the Gemini protocol to fetch stuff from the Internet and dumps it. No formatting, header and all. The titan function uses the Titan protocol to write text and files to a Titan-enabled Gemini server, such as the ones I run.

Titan is where I’ve written down a few words on the protocol I use to upload files to my wiki. There hasn’t been much talk about the Titan protocol, partly because I felt pretty much alone in my interest for wikis. On the Gemini mailing list, people were talking about using SFTP or mail to upload or comment, or about how they disliked commenting, and so on. I figured I’ll just have to implement some stuff and then maybe other people might get interested, once it’s shown its utility, even if we then change small aspects of the protocol. If you want to talk about Titan, feel free to contact me, or comment or edit that Titan page. It’s also hosted on a wiki!

Community Wiki, where the Titan page is being hosted, is also reachable via Gemini and editable via Titan. The quality of the translation from wiki text to Gemini format isn’t all that great because it never switched to Markdown. It’s mostly Wiki Creole and a bunch of specific extensions. It’s available at communitywiki.org:1966.

Next, I wanted to see how to translate a dense hypertext like Wikipedia to the Gemini format and I wrote Gemini Wikipedia, a Wikipedia proxy strips most of the links in order to provide you with a nice reading experience; it also tries its best to translate tables to text (probably not a good way to read those tables if you’re blind, sadly). If you really want to, you can always get the HTML including all the links, and depending on your browser, it might work.

I later rewrote that code and now it’s part of the Gemini Wiki config file I’m using at The Transjovian Council. It’s available at The Vault. I recommend starting with the Project Gemini page. It’s the page I used to check my code as I was developing it. 😀

Gemini Wiki, finally, is my wiki for everybody. It builds on the Gemini Server I used for this site. It uses a Gemini format internally. It allows you to add pages and files to the wiki directly. It even has a very simple, read-only web interface! It has “spaces” so you can host multiple wikis for different people. I’ve been using my installation to write about it. It’s at The Transjovian Council, and as I said, you can also access it via a web browser on the same port.

Oh, and if you’re an Emacs person, there’s more...

Gemini Write is an extension to Elpher, the Emacs Gopher and Gemini client, which allows you to edit pages right there, in Emacs. I also started working on a “multiple buffers” branch for Elpher. You can find it in The Lambda Lab’s git repository, via Gopher!

Ah, and before I forget: here’s a video of me editing Gemini Wiki, from Emacs! You might have to right-click the preview image and choose “Play” from the context menu. It depends on your browser and your settings, I guess.

So happy. 😀


Comments on 2020-07-02 An overview over my Gemini projects

Hello, I notice I can’t play the video as my browser (Chrome) doesn’t show the video controls by default. After inspecting the source code, I think you mistyped the HTML attribute “controls”, you wrote “control”, that is, a “s” was missed.

Xu Chunyang(徐春阳) 2020-07-11 13:57 UTC

Thank you so much! That was indeed the problem. And now it works for Firefox as well.

– Alex Schroeder 2020-07-11 14:36 UTC

Add Comment

2020-06-11 Demonstrating Gemini Wiki

This wiki is also served via the Gemini protocol (something between Gopher and the Web as we know it). I’ve written an extension that allows me to write back to the wiki (and not just leave a single line of comments).

In case you’re curious, today I made a short 50s video!

Made using Emacs, Elpher, Gemini, Oddmuse, Peek, and Garage Band. 😀

If you’re interested in how this works, I think the two two bash functions I wrote make two good examples: gemini allows you to read and titan allows you to write.


Comments on 2020-06-11 Demonstrating Gemini Wiki

Let’s see how this works with a gemini client.

– Anonymous 2020-06-11 22:52 UTC

If you want to be non-anonymous, I guess you need Gemini Write support. If you have it, just edit the page and there you go.

Or I could add another back and forth to ask your name every time you comment. Do you think that would be worth it?

– Alex Schroeder 2020-06-12 18:05 UTC

Starting a series of wiki pages on how to set up your own Gemini Wiki using Oddmuse.

– Alex Schroeder 2020-06-13 20:25 UTC

Add Comment

2020-06-05 Gemini Write

My new package gemini-write can be used to edit this site via my Gemini Write proposal.

In order to browse Gemini sites, I use Elpher.

In order to get Gemini highlighting, I use Gemini Mode.

Once you have all three packages installed, visit this site, find a page you want to edit, follow the link to the “Raw text” at the bottom and then use e to edit it. The raw pages are the only pages that can be edited. Use C-c C-c to save, use C-c C-k to cancel. Customize elpher-gemini-tokens to set passwords, tokens, or whatever you need in order to edit sites.

Currently this only works on this site, I guess.

And I currently don’t have a markup rule to render Gemini links, but I’ll add that as soon as somebody posts one. 😀

Test it here: Gemini Test.


Comments on 2020-06-05 Gemini Write

I wonder if you also plan to support search functionality at some point?

deshipu 2020-06-05 13:57 UTC

Yes. I did that just now.

– Alex Schroeder 2020-06-05 21:21 UTC

There is still some sort of bug where saving doesn’t always work and if it does not, then whatever you wrote is lost. That is definitely disappointing. I’m suspecting that it depends on the page name.

– Alex Schroeder 2020-06-07 09:32 UTC

I’m starting to see the difficulties of rendering the raw wiki text to Gemini using regular expressions. That part is definitely trickier than I thought.

– Alex 2020-06-08 15:54 UTC

Video! 😀

– Alex Schroeder 2020-06-11 18:12 UTC

Add Comment

2020-05-30 XP, Gold, and Emacs

There are those rare occasions where my love for an editor that can be extended while you’re using it – Emacs! – and my love for role-playing games come together.

I use big tables like the following on the status pages of my various campaign wikis:

|= Character    |= Share |=     XP |=   Gold |=      Level |= XP next |= Home / final rest |= Health |= Player |
|[[Vangelis]]        | 1 |    12367|    10033|      thief 5| 20'001|[[Greyheim]] | |Sam |
|[[Maram]]           | ½ |    11793|     5324|   halfling 4| 16’251|[[Greyheim]] | |Sam |
|[[Magdalena]]       | ½ |    13203|     1816| magic-user 4| 20'001|[[Greyheim]] | |Sam |
|[[Delina]]          | ½ |     6781|     4095|      thief 3|  5'001|[[Greyheim]] | |Sam |
|[[Eldakkar]]        | 1 |    48013|     9938| magic-user 5| 40'001|[[Greyheim]] | |Flavio |
|[[Ernst Ormott]]    | ½ |    18158|     2626|    fighter 4|  16250|[[Greyheim]] | |Flavio |
|[[Mia]]             | ½ |     6843|      108|  Assistant 4| 10'001|[[Greyheim]] | |Flavio |
|[[Anouk]]           | 1 |    35001|        0|      dwarf 6| 70'001|[[Stormhold]] | |Ben |
|[[Strahl]]          | ½ |    40001|       95| magic-user 6| 80'001|[[Stormhold]] | |Ben |
|[[Kristina]]        | ½ |    11188|     2740|    fighter 4| 16'250|[[Stormhold]] | |Ben |
|[[John Greene]]     | ½ |    20001|        0| magic-user 5| 40'001|[[Stormhold]] | |Ben |
|[[Dorn Ironfoot]]   | ½ |     5501|        0|      dwarf 3|  8'751|[[Stormhold]] | |Ben |
|[[Yifan]]           | 1 |    34219|    16450|        elf 5| 65’001|[[Deathwatch Keep]] | |Grisha |
|[[Annica]]          | ½ |    18670|     8671|      dwarf 5| 35’001|[[Greyheim]] | |Grisha |
|[[Joana]]           | ½ |     2643|      300|    fighter 2|  4'065|[[Greyheim]] | |Grisha |
|[[Lila-Marie]]      | ½ |       52|     1792|        elf 1|  4'065|[[Greyheim]] | |Grisha |
|[[Sugo]]            | 1 |    19895|     7073|    fighter 5| 32'501|[[Greyheim]] | |Petr |
|[[Slui]]            | ½ |     5264|     1965|   halfling 3|  8,125|[[Greyheim]] | |Petr |
|[[Maxim]]           | ½ |     6033|      243|    fighter 3|  8'125|[[Greyheim]] | |Petr |
|[[Saray]]           | 1 |     1878|     2537| aquamancer 1|  2'501|[[Greyheim]] | |Natalie |
|[[Pringles]]        | 1 |    16468|     7577|    fighter 5| 32'501|[[Greyheim]] | |Petr's wife |
|[[Maximo]]          | 1 |     2042|      885|      thief 2|  2'501|[[Greyheim]] | |Giorgio |
|[[Adrijana]]        |   |     4560|     1743|  geomancer 2|  5'001|killed by bugbears | ☠ |Flavio |
|[[Tugra]]           |   |     5272|     -262|    fighter 2|  4'065|petriefied by a basilisk | ⌛ |Adrian |
|[[Sascha]]          | 1 |    13554|     1704|     cleric 5| 25'001|retired and runs a church | 💜 |Flavio |
|[[Lothar]]          |   |      750|       41|      dwarf 1|  2'187|[[Greyheim]] | 💜 |Chris |
|[[Tiana]]           |   |       45|      118|   halfling 1|  2'035|killed by a giant bat | ☠ |Sam |
|[[Arbogast]]        |   |      260|      682|    fighter 1|  2'035|ambushed by jackalweres | ☠ |Sam |
|[[Marika]]          |   |     1953|     2119| magic-user 2|  5’001|[[Greyheim]] | ⌛ |Sam |
|[[Simed]]           |   |      805|     1699|      dwarf 1|  2'187|[[Greyheim]] | 💜 |Sam |
|[[Neid]]            |   |       58|      694|        elf 1|  4'065|shot by hobgoblins | ☠ |Sam |
|[[Devd]]            |   |      694|      413|    fighter 1|  2'035|shot by hobgoblins | ☠ |Sam |
|[[Pietro]]          |   |       77|       11| pyromancer 1|  2'501|shared space whit a spear  | ☠ |Andre |
|[[Kim]]             |   |     3261|     1835|        elf 1|  4'065|killed by ear seekers | ☠ |Sam |
|[[Tristan]]         |   |        0|        0|   halfling 1|     - |killed by boring beatles | ☠ |Flavio |
|[[Aiza]]            |   |      997|      113|   halfling 1|     - |fell into a concealed pit | ☠ |Luca |
|[[Hiad]]            |   |       17|        1|      dwarf 1|     - |eaten by beatles | ☠ |Miae |
|[[Honey]]           |   |        0|        0|   halfling 1|     - |eaten by kobolds | ☠ |Miae |
|[[Sivan]]           |   |        0|        0|     cleric 1|     - |eaten by kobolds | ☠ |Sam |
|[[Desi]]            |   |     3474|     1908|    fighter 2|  4'065|held under the Freya temple | 🐺 💜 |Flavio |

I used Emacs to distribute gold and experience points because I’m not a big user of spreadsheets. For the longest time, I used a set of functions that created a form within Emacs, made up of widgets.

The code I had turned this into a form like the following:

XP total:   0            
Gold zu XP: 0            
Gold total: 0            
[ ] [[Vangelis]]        Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Maram]]           Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Magdalena]]       Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Delina]]          Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Eldakkar]]        Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Ernst Ormott]]    Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Mia]]             Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Anouk]]           Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Strahl]]          Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Kristina]]        Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[John Greene]]     Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Dorn Ironfoot]]   Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Yifan]]           Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Annica]]          Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Joana]]           Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Lila-Marie]]      Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Sugo]]            Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Slui]]            Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Maxim]]           Share: [ ] 1 [X] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Saray]]           Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Pringles]]        Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Maximo]]          Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      
[ ] [[Sascha]]          Share: [X] 1 [ ] ½ [ ] ⅓   Gold spent: 0       Transfer: 0      


You could check those boxes, arrange for money transfers, arrange for gold to be spent (turning it into experience points), you could distribute gold found (distributed according to shares, one share per main player character, half a share for retainers), or experience points gained (based on monsters defeated and distributed equally among characters).

Sadly, there interface was clumsy. Checking the necessary boxes took more time than I was willing to spend.

Later, I tried to write something like a chat interface. I basically wanted a special RPG shell with which to interact. I imagined myself typing parse <url> to read the data from the campaign wiki, filter Flavio Sam Ben to tell the system who was present, distribute 500 gold and distribute 200 xp to distribute gold and experience points, and save to save the result back to the wiki.

I spent a lot of time writing code and did very little distributing of gold and experience points. I was also a bit frustrated. Why was I using rules that required me to use software again? That question remains unanswered.

My latest attempt at writing code involves simply marking numbers using C-=, distribute a certain amount among all the marked numbers using M-C-=, add a certain amount among all the markednumbers using M-C-=, and remembering that C-+ already exists to increment the number at point.

It needs a bunch of convenience functions to quickly mark all the numbers at a particular column for lines matching a particular regular expression, and then we should be good to go!


Add Comment

2019-12-14 Gnus IMAP issues

I’ve started using Gnus again in recent weeks and months. One problem I have is that I enter the INBOX group using C-u RET or issue / o inside the group to see all the mail in my INBOX, read and unread, but all I get are 17 mails. I know some are missing.

When I use the Server Buffer via ^ and enter the INBOX, I get 50 mails. This includes all the missing mails.

I sometimes suspect that it has to do with me reading mails on the phone, too.

Do you understand what’s going on? Many years ago I had decided that the Gnus Agent was a problem and disable it setting gnus-agent to nil. (My entire Gnus config is available online.)

I removed the newsrc files (.newsrc.eld, .newsrc-dribble, their backup files), started Gnus again, and all I seem to have lost was the read marks. As I had all groups “read” that wasn’t a problem, a quick “catch-up” on the groups in questions solved that; then I went into my INBOX and all the mails were there. Let’s see whether it degenerates again.


Comments on 2019-12-14 Gnus IMAP issues

/ w runs the command gnus-summary-pop-limit

– gijs 2019-12-15 08:37 UTC

I don’t think this is a question of limits. When entering a group, read mail is not shown by default. When I then press / w, nothing happens. When I press / o, read mail is shown in the buffer. My problem is that not all read mail is shown in the buffer.

– Alex Schroeder 2019-12-15 10:04 UTC

I find Gnus nnimap is great,it practically runs itself, when imap is used as intended - keep it on the server. There is really no need to download everything. This is great for work email.

The .newsrc* files are not really needed, everything is on the imap server. They just make reading email faster. One can just delete them and start where the left, it will just take longer to sync.

I have a few comments on your gnus config:

  1. For nnimap gnus-secondary-select-methods the group names are formatted as “nnimap+server:Groupname”. The “server” part should be the method label and not the nnimap-address. So for your archive, spam or trash groups, should use for example “nnimap+notifications:Archive”. To my understanding, the “server” string is more of the method label to distinguish from the other methods.
  2. You must have your reasons for setting both the gnus-select-method and the gnus-secondary-select-method “notifications” to the same imap server (imap.migadu.com). This may be a source of confusion to gnus. The issues you are experiencing may come from a bad interaction between the two methods. From your config, it is not clear what distinguishes the two methods. May I suggest keeping only one and see if the issues persist ? I find gnus-select-method to be archaic, as it no longer makes any sense to treat any method as special. Setting gnus-select-method to ’(nnnil nil) and moving all method definition to gnus-secondary-select-methods gives the best experience IMV.

Btw, I’m a big fan of your work. Thank you for all the code contributions, post and of ourse the emacswiki work !! Amazing.

– DEUS MAX 2019-12-15 10:50 UTC

The reason I had done this was that for a while I had two mail accounts on the same server (alex@alexschroeder.ch and notifications@alexschroeder.ch). How do you set that up correctly, without delivering all the mails to a single account?

– Alex Schroeder 2019-12-15 12:07 UTC

No idea why Gnus is so popular! It’s OK for NNTP but not for e-mail. Ditch Gnus and user Wanderlust! 🙂

– zapata 2019-12-15 12:23 UTC

But I’ve been using Gnus for twenty years! I’ve got code in Gnus. I got the mug!

But yeah, perhaps one day I’ll do it.

– Alex Schroeder 2019-12-15 14:40 UTC

Setting up some stuff... starting M-x wl...

condition-case: Wrong type argument: arrayp, nil

This is not a good omen. 😐🔥🔥

M-x toggle-debug-on-error and then:

Debugger entered--Lisp error: (wrong-type-argument arrayp nil)
  signal(wrong-type-argument (arrayp nil))
  (condition-case obj (progn (if check (progn (message "Checking environment...") (wl-check-environment arg) (message "Checking environment...done") (message "Checking type of variables...") (wl-check-variables) (wl-check-variables-2) (message "Checking type of variables...done"))) (let ((inhibit-quit t)) (wl-plugged-init (wl-folder))) (if arg nil (run-hooks 'wl-auto-check-folder-pre-hook) (wl-folder-auto-check) (run-hooks 'wl-auto-check-folder-hook))) (error (if (buffer-live-p demo-buf) (kill-buffer demo-buf)) (signal (car obj) (cdr obj))) (quit))
  (let (demo-buf check) (if wl-init nil (if wl-demo (setq demo-buf (wl-demo))) (setq check t)) (wl-init) (condition-case obj (progn (if check (progn (message "Checking environment...") (wl-check-environment arg) (message "Checking environment...done") (message "Checking type of variables...") (wl-check-variables) (wl-check-variables-2) (message "Checking type of variables...done"))) (let ((inhibit-quit t)) (wl-plugged-init (wl-folder))) (if arg nil (run-hooks 'wl-auto-check-folder-pre-hook) (wl-folder-auto-check) (run-hooks 'wl-auto-check-folder-hook))) (error (if (buffer-live-p demo-buf) (kill-buffer demo-buf)) (signal (car obj) (cdr obj))) (quit)) (if wl-biff-check-folder-list (progn (if arg nil (wl-biff-check-folders)) (wl-biff-start))) (if (buffer-live-p demo-buf) (kill-buffer demo-buf)))

The problem appears to be this, when running edebug on wl-check-environment:

(wl-folder-get-elmo-folder "+draft")

And that’s even though (wl-folder-get-elmo-folder "+queue") returns nil, no error.

That’s because (wl-folder-make-elmo-folder wl-draft-folder) returns nil in wl-draft-get-folder.

I was debugging somewhere in the depths of elmo-make-folder when I decided to give and return to Gnus.

– Alex Schroeder 2019-12-15 19:39 UTC

As DEUX MAX said, you definitely shouldn’t configure the same email account several times.

I’ve switched to setting gnus-select-method to nnnil, and configuring everything in gnus-secondary-select-methods, to avoid confusing myself with the special status of the single account configured in gnus-select-method. I recommend that for everybody.

You can name methods in Gnus, so you can easily have multiple accounts on the same mail server:

(setq gnus-select-method '(nnnil))
(setq gnus-secondary-select-methods
        (nnimap "one" (nnimap-address "your.mailserver.example.org"))
        (nnimap "two" (nnimap-address "your.mailserver.example.org"))

and then in your .authinfo.gpg you’d have something like:

machine one login yourlogin1 password ***** force yes port imaps
machine two login yourlogin2 password ***** force yes port imaps

Or something to that effect.

Your groups will then show up as nnimap+one:blabla, nnimap+two:INBOX etc.

Adam 2019-12-18 19:58 UTC

Thanks! Will try that.

– Alex Schroeder 2019-12-18 21:44 UTC

I agree with Adam. It is best to ditch the gnus-select-method and move everything (configuration wise) in gnus-secondary-select-methods.
Treating an arbitrary method as special (primary) is bad holdover.
So yes, do use the The Empty backend :

(setq gnus-select-method '(nnnil ""))

Alternative configuration, for using two accounts on the same imap server, can be:

(setq gnus-secondary-select-methods
  '((nnimap "one" (nnimap-address "imap.mailserver.org")(nnimap-user "user1")...) 
    (nnimap "two" (nnimap-address "imap.mailserver.org")(nnimap-user "user2")...) 

and the .authinfo.gpg file:

machine imap.mailserver.org login user1 password user1secret ....
machine imap.mailserver.org login user2 password user2secret ....

This way, accounts get selected by the different user-names.
The strings “one” and “two” become just server labels, that can be conveniently chosen to provide for good looking gnus group names (nnimap+serverlabel:Groupname) that display nicely in the Group Buffer.

– DEUS MAX 2019-12-20 01:04 UTC

Thank you both.

– Alex Schroeder 2019-12-20 10:05 UTC

When you’re in the 17-mail inbox, what does C-h v gnus-newsgroup-name say? What does M-: (length gnus-newsgroup-headers) say?

When you’re in the 50-mail inbox, same questions.

– dickmao 2019-12-20 14:28 UTC

Somebody convinced me to simply go ahead and delete the ~/.newsrc* files. As my setup was simple and I didn’t have much marked, it was no problem at all ­– and currently the two look alike again.

I’ll remember to do that, next time this happens though.

– Alex Schroeder 2019-12-20 20:20 UTC

Yes, ~/.newsrc* state more than occasionally gets corrupted when gnus gets confused. Glad you’re back on track.

– dickmao 2019-12-21 16:02 UTC

The problem hast reappeared.

Here are the two last emails in my inbox:

... (16 other mails)
O    2020-02-18 [   7: xxxxxxxxx      ] über amazon data
O    2020-02-19 [   5: xxxxxxxxx      ] BBC - Travel - Japan’s perfectly imperfect garden


(length gnus-newsgroup-headers) → 18 (which is what I see)

When I got to the server buffer, I see the IMAP server:

     {nnimap:migadu} (opened)

When I browse it, it looks just fine:

      89: Archive
       7: Drafts
    1317: INBOX
    9954: Junk
       4: Notes
      75: Sent
    1162: Trash

When I try to enter the INBOX, however (using both RET and C-u RET):

Group nnimap+migadu:INBOX contains no messages
gnus-browse-read-group: Couldn’t enter nnimap+migadu:INBOX

And on the iPhone, the last four messages are:

  • über amazon data
  • Update Februar 2020 – Geheimdienst, E-Voting, E-ID, Julian Assange, Privacy Camp, Jahresbericht, Zmittag
  • BBC - Travel - Japan’s perfectly imperfect garden
  • Re: “Permanent Record”: Ein Hörbuch für Dich!

So, I can see two emails on the phone that Gnus isn’t showing, and this time around the server setup is broken in some way.


Am I going to delete the ~/.newsrc* files again? Probably.

Is this making me distrust Gnus? Definitely.

– Alex Schroeder 2020-02-23 10:45 UTC

Actually, a new development. I entered the group and used Z G to rescan the group, then / o to show the old messages – and now I have more messages in the summary buffer!

– Alex Schroeder 2020-02-24 00:16 CET

Dear Alex, I had the same problem for a long time – also trying to reuse Gnus after having stopped for 3, 4 years now.

Your solution Z G does work for me. Thanks a lot!!!

Side questions:

  • Is there a better way to display HTML mails thank K H?
  • Is there a way not to put hard line feed characters in our mails (they’re not properly displayed on phones)

– Fab Rice 2020-11-15 17:16 UTC

Sadly, I don’t know the answers to your questions... and I have since stopped using Gnus again! 😭 These days I use aerc in the terminal and Evolution when I need to look at fancy stuff.

– 2020-11-15 19:25 UTC

Sad ! You have code, you have the mug...

– Deus Max 2020-11-16 22:02 UTC

Yeah, I just stopped trusting it and that’s the end for a mail client. 😟

– Alex Schroeder 2020-11-16 22:18 UTC

Add Comment



Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Just say HELLO