Using gtags in neovim

Since LSPs are getting more and more common, the old way of indexing a whole codebase and saving that infomation in a file, then looking it up when needed is falling out of fashion.

Nevertheless, I still depend on it heavily. At work I can not use LSP for most projects, since they are (cross) compiled with a proprietary ARM compiler. LSP needs some info on where header files are and such, and it takes that usually from a compile_commands.json. Which can be generated using a program like Bear. Since there is no makefile, I could only write that compile_commands.json by hand. Which I obviously don’t want.

One of those things that does it the olde way is gtags, from GNU Global. It indexes the codebase and saves everything in a database instead of a textfile. This database can be updated incrementally, which makes subsequent generation much much faster. Also they say the lookup of tags is faster than ctags, but I never noticed.

I use gtags in Emacs all the time, using the excellent ggtags package. But in my recent endeavor getting to use neovim for coding (and mimicing Doom emacs with it as much as possbile) I learned that the gtags situation in the neovim world is a dire situation. There are almost no tutorials available, they contain outdated info etc.

So, here goes.

Installing GNU Global

First we need to get GNU Global. Install via your package manager. As usual this depends on your distro, I use Gentoo, so it is

sudo emerge -av dev-util/global

Tags are easily created, go to the project root directory use that command

gtags

That all, Global will index all subfolders and create GPATH, GRTAGS and GTAGS in that folder. There are ways to do that from vim, but using that in Emacs I found that I can get away with updating the tags very seldom. So doing it form the command line every once in a will is sufficient for me.

Neovim configuration

I use the two plugins gtags.vim and telescope-gtags from ivechan. Since I use Lazy as package manager for vim, they are installed using some simple declarations:

  {
    "ivechan/gtags.vim",
  },
  {
    "ivechan/telescope-gtags",
  },

Thats pretty much all there is to it. In order for Neovim to find the GTAGS file, its working directory must be where that GTAGS file is. (cd to that folder and then start vim in that folder or use :cd in vim)

But since I still have LSP running for some projects (mostly Rust) I have a keybinding conflict. When I am running a file with LSP attached, I want to look the definitions up with LSP, but when I am not running LSP, I wan’t to use gtags.
Emacs has the xref system for this, where you call an xref function to look up a definition and xref has a list of possibilities to resolve that request. It will then try each of the possibilities to get that tag until it has it.
For Neovim I just checked if a LSP server is attached to that buffer and if so (and if that LSP server is not copilot, because that is always running, I call LSP definitions, if not I call gtags definitions.


-- gtags
local xref_goto_definiton = function ()
    local clients = vim.lsp.get_clients( { bufnr = 0 } )
    for _, client in ipairs(clients) do
      print(client.name)
      if client.name ~= "copilot" then
        require('telescope.builtin').lsp_definitions()
        return
      end
    end
    require('telescope-gtags').showDefinition()
end
local xref_goto_references = function ()
    local clients = vim.lsp.get_clients( { bufnr = 0 } )
    for _, client in ipairs(clients) do
      print(client.name)
      if client.name ~= "copilot" then
        require('telescope.builtin').lsp_reference()
        return
      end
    end
    require('telescope-gtags').showReferences()
end
local xref_goto_definition_other_window = function ()
    local clients = vim.lsp.get_clients( { bufnr = 0 } )
    for _, client in ipairs(clients) do
      if client.name ~= "copilot" then
        require('telescope.builtin').lsp_definitions({jump_type="vsplit"})
        return
      end
    end
    require('telescope-gtags').showDefinition() -- there is no vsplit for this yet
end

vim.keymap.set('n', '<leader>cd', xref_goto_definiton, { desc = 'Goto [D]efinition' })
vim.keymap.set('n', '<leader>ch', xref_goto_definition_other_window, { desc = 'Goto [D]efinition other window' })
vim.keymap.set('n', '<leader>cD', xref_goto_references, { desc = 'Goto [R]eferences' })

(Doom) Emacs tags for obscure embedded stuff

Why?

Today, everything seems to revolve around Language Server Protocols (LSPs). Despite Emacs sometimes slowing down when LSPs are active, their utility is too immense to abandon, at least until they no longer serve our needs.

In my experience, LSPs shine in everyday projects, like a Linux-based program one might develop. However, they often feel overly flashy to me with their constant code linting pop-ups and such. Nevertheless, having an effortless way to reference variables and functions remains crucial. Even in the realm of C/C++, where projects vary greatly in setups—some even employing obscure, handcrafted Makefiles—tools like ‚bear make‘ come in handy to generate ‚compile_commands.json.‘ This file aids clangd, a C Language Server Protocol, in locating header files. The process becomes even smoother when using modern build systems like CMake.

But what happens when you cross-compile that project? What if you aren’t using GCC, clang, or even sensible tools like Make, CMake, or Meson? Instead, you might find yourself dealing with a proprietary ‚IDE‘ on Windows, using its own XML format to manage header files and running an ARM compiler vastly different from GCC. Creating a ‚compile_commands.json‘ for this scenario becomes an ordeal.

However, I still want the ability to reference tags in my programs without switching from Emacs to that peculiar proprietary ‚IDE.‘

This is where ‚gtags‘ come into play.

What are gtags?

In the days of yore (before LSPs), tags were looked up using a file. While this sounds archaic by today’s standards, ‚ctags‘ does precisely that. Nevertheless, for sizable projects, storing tags in plain text within a file can become sluggish. That’s where ‚GNU Global‘ steps in—it performs a similar task but utilizes a database. Unfortunately, GNU Global doesn’t operate on Windows. Thankfully, with Windows Subsystem for Linux (WSL) available, this limitation is mitigated.

The Setup

GNU Global primarily constructs the database. Using it within Emacs involves additional tools. With Emacs offering numerous packages, each slightly different yet serving the same purpose, I opted for ‚ggtags‘ due to its popularity.

Here’s the process:

  1. Create a tag database for each project.
  2. Access this database using ggtags.
  3. Navigate between tags, their definitions, and references using Emacs‘ Xref, with ggtags as the backend.

Installation

Install GNU Global through your package manager. For instance:

sudo emerge -av dev-util/global

The installation process might vary for other distros.

In Emacs, install ggtags. There are multiple ways to do this; for instance, in Doom, add:

(package! ggtags)

to your ‚packages.el.‘ Then, run ‚doom sync‘ from the command line to fetch the packages.

Configuration

For other projects, occasionally using Clangd might still be necessary. Since Doom integrates lsp-mode into ‚c-mode,‘ ‚c++-mode,‘ etc., we need to remove this integration:

(remove-hook! '(c-mode-local-vars-hook
c++-mode-local-vars-hook
objc-mode-local-vars-hook
cmake-mode-local-vars-hook)
#'lsp!)

(remove-hook! '(c-mode)
#'lsp!)

Instead, add ‚ggtags-mode‘ to the hook:

(add-hook 'c-mode-common-hook
(lambda ()
(when (derived-mode-p 'c-mode 'c++-mode 'java-mode)
(ggtags-mode 1))))

If there are library sources to include in your project’s tags, add them to the ‚GTAGSLIBPATH‘ environment variable:

(setenv "GTAGSLIBPATH" "path/to/some/library/source:/path/to/some/other/library/source")

Usage

After these steps, evaluate the changes and open a source file in your project. Execute ‚M-x ggtags-create-tags.‘ It prompts you to select the project’s root directory. Gtags will traverse subdirectories and generate three tag files in the project’s root. (Alternatively, navigate to that directory in the command line and run ‚gtags‘ command).

The process will also inquire if you wish to use the ctags backend. Gtags can only create tags files for specific languages; for others, it relies on ctags to create files that it then parses to build the database. For C-related languages, declining this option suffices. Accidentally accepting this setting can be rectified by deleting the ‚GTAGS,‘ ‚GRTAGS,‘ and ‚GPATH‘ files from the project directory; Ggtags will prompt this choice again.

Perform the same process in every folder within ‚GTAGSLIBPATH.‘

Now, with the cursor on a variable in Emacs, it will underline it. Running ‚M-x xref-find-definitions‘ will navigate you to that variable’s definitions. As an ‚evil‘ user, I can utilize ‚C-o‘ (evil-jump-backward) to return to that variable. The same applies to ‚xref-find-references‘ and ‚xref-find-definitions-other-window.‘

Getting screensavers to work on Wayland

So, Wayland is finally a major thing in the Linux Desktop world. And whether you like it or not, X11 is going to be phased out from all major distros sooner or later. (It will probably never die though.)

(Here comes some nostalgic bla bla, if you just want to know how to get screensavers from Xscreensaver in wayland, scroll down.)

I moved from xmonad to hyprland a few months back and after fiddling around a bit I felt right at home. (It is also nice to configure your window manager / wayland compositor in a language that can be understood without having a master in math)

But there is one thing bothering me: Screensavers. Or rather the lack of them.

I know, screensavers are a relic of the past, something from the 90s. Although there still are certain screens that can suffer from burn-in, we can just switch them off today. There is seldom a good technical reason to have them. But then again, even back in the day there always was just something artistic about them. Back when I was using X11 I used electric sheep, which I highly recommend. This is in fact art using tech, and there is no technical reason needed to have such a thing. Remember the pipes in windows? Everyone remembers that. Or the ant in the dark with the flash light? Or the flying toasters? I remember sitting in front of my parents Win 98 box just watching those mesmerizing pipes tangle.

Besides, the author of Xscreensaver, Jamie Zawinski, caused some really hilarious bug reports in the linux world. Mostly this one when he placed a warning inside Xscreensaver that it is outdated and that goes off only after some years to make Debian devs aware of how outdated the software of their stable branch is. Or this thread in the Gentoo Forums where Xscreensaver caused some poor guy trouble with his boss, when it showed some inappropriate things to the boss‘ niece and nephew. This ultimately led to the „offensive“ use flag of the Gentoo Xscreensaver package. That I am the proxy maintainer of, by the way. I also had my share of patching out offensive things from Xscreensaver. The source code is also full of weird and offensive comments. I love it.

But it seems there is only a few people thinking that screensavers have a right to exist in the modern world of lockscreens. Because on wayland there seems to be no such thing. And if you search online for it, you can only find a few questions on reddit asking for it.

Time to change that.

So a first I was thinking that can’t be that hard. We have swaylock on Wayland to lock the screen and does all the fancy things like blur. There is also gtklock, which also has plugin support and the dev from it has already written some for music player control and whatnot. Just play an animation in the background and you should be fine.

So I tried writing a plugin for gtklock, and halfway through understanding how this is done, it dawned on me that this is not what I am looking for. Screensavers are not just videos or gifs played in a loop. They are rendered animations. (I wonder why the 90s people decided to do that this way. Maybe rendered stuff was just cool and new back then. There was also a massive hype around the first Toy Story because of that.)

Also, it would be a shame to waste all the existing screensavers from Xscreensaver and not make them usable on Wayland.

So let’s see… maybe I could try using Xscreensavers existing screensavers and make them work on wayland somehow? Now, you can (sort of) run them on Wayland (they are compiled binaries in Xscreensavers /hacks folder) but they run through XWayland, the X-Server interfacing with Wayland to have support for legacy programs.

I have given that some thought, and I was looking into getting a Xscreensaver screensaver to run via XWayland in a GTK-Widget of Gtklock, which is a Wayland window. Or maybe try to build the screensavers for wayland using EGLX? This is though stuff.

But it turns out someone else is into screensavers as well: Wscreensaver by Manuel Stoeckl. So it turns out this guy has already (partly) done it and ported Xscreensaver screensavers to wayland.

And the best thing is, he already wrote a fork of swaylock to display those as screensavers!

Now let’s get this running.

I think it goes without saying that this is highly experimental software which should not be in a mission critical environment.

Wscreensaver

https://git.sr.ht/~mstoeckl/wscreensaver

Note: I wrote a package for wscreensaver and pushed it the Gentoos GURU. So if you have the GURU activated in your Gentoo system, just emerge gui-apps/wscreensaver from there. When using the package, the compiled screensavers will end up in the directory /usr/lib64/misc/wscreensaver/xscreensaver-antspotlight. You can then lock the screen using a screensaver and swaylock-plugin (see below) with a command like this for example:

swaylock-plugin --command /usr/lib64/misc/wscreensaver/xscreensaver-antspotlight

—-

We first need to install the dependencies (on gentoo you will have those anyway) and clone the wscreensaver repo. Also it helps to install Xscreensaver using emerge, so we already have all it’s build dependencies. Otherwise the ebuild file for Xscreensaver (or the ebuild from wscreensaver) can help figuring out he dependencies. (Look at COMMON_DEPEND and BDEPEND mostly)

sudo emerge dev-util/meson dev-util/ninja x11-misc/xscreensaver
git clone https://git.sr.ht/\~mstoeckl/wscreensaver

Then first build xscreensaver to generate some files we later need to compile the wayland screensavers:

cd wscreensaver
./configure
make

and cd into the wayland directory inside the source

cd wayland

Then compile the screensavers for Wayland

meson build
ninja -C build

That should result in some generated screensaver animations in the build directory. Many of those are not working (they will tell what is missing when they are run, though.) but the first one, xscreensaver-abstractile should work as an animated background in a wayland compositor. Awesome.

Random screensavers from a folder

A slight variation of the script provided by Manuel is the Readme of swaylock-plugin can get us random screensavers.

Save this script somewhere. For example as rotate_xscreensavers.sh

#!/usr/bin/env bash

folder=$1
file=`ls "${folder}" | shuf -n 1`
delay=60.
timeout $delay "${folder}/${file}"

And make it executeable

chmod +x rotate_xscreensavers.sh

Then run swaylock plugin with the script as the command:

swaylock-plugin --command '/home/pascal/.config/swaylock/rotate_xscreensavers.sh /usr/lib64/misc/wscreensaver'

Where you have to alter the path to the script and to the folders of screensavers from wscreensaver of course.

Swaylock-plugin

https://github.com/mstoeckl/swaylock-plugin

Note: I wrote a package for swaylock-plugin and pushed it the Gentoos GURU. So if you have the GURU activated in your Gentoo system, just emerge swaylock-plugin from there. You can then link /usr/bin/swaylock to /usr/bin/swaylock-plugin, to use swaylock-plugin like normal swaylock in other applications. !!! Also do symlink /etc/pam.d/swaylock to /etc/pam.d/swaylock-plugin like so, because otherwise swaylock-plugin starts but can not be unlocked anymore. (see also: https://github.com/mstoeckl/swaylock-plugin/issues/8)

sudo ln -s /etc/pam.d/swaylock-plugin /etc/pam.d/swaylock 

(In this case gui-apps/swaylock and gui-apps/swaylock-effects can not be installed obviously)

—-

Even though this is called swalock-plugin, this is a full fork of swaylock. So don’t confuse it with the swaylock inside the system repos.

Clone the repo again first and go into the directory. Again, emerge the package or install the dependencies manually with help of the ebuild.

sudo emerge gui-apps/swaylock
git clone https://github.com/mstoeckl/swaylock-plugin 
cd swaylock-plugin

And compile the code:

meson build
ninca -C build

The compiled binary should now be in the build directory.

Using that binary I can have a lock screen with a screensaver background:

./build/swaylock-plugin --command /home/pascal/dev/wscreensaver/wayland/build/xscreensaver-abstractile

(Note that swaylock-plugin seems to have some trouble relative paths for the command)

Random screensavers from a folder

A slight variation of the script provided by Manuel is the Readme of swaylock-plugin can get us random screensavers.

Save this script somewhere. For example as rotate_xscreensavers.sh

#!/usr/bin/env bash

folder=$1
file=`ls "${folder}" | shuf -n 1`
delay=60.
timeout $delay "${folder}/${file}"

And make it executeable

chmod +x rotate_xscreensavers.sh

Then run swaylock plugin with the script as the command:

swaylock-plugin --command '/home/pascal/.config/swaylock/rotate_xscreensavers.sh /usr/lib64/misc/wscreensaver'

Where you have to alter the path to the script and to the folders of screensavers from wscreensaver of course.

Conclusion

It can be done and I finally have screensavers back in wayland!

This is still somewhat rough around the edges. I think I am going to try to get some more screensavers from xscreensaver to work with wayland and contribute to Manuel Stoeckls repo if im successful. It would be great to have a version of Electric Sheep as well. But lets see what can be done.

Also a package in the guru for swaylock-plugin should be done.

Let’s see.

(Doom) Emacs as an IDE for ebuilds

Writing ebuilds is kind of an obscure task. It’s a thing that not many people do, and certainly not tech-illiterates and therefore tools that evolve around it are sparse and usually stick to the command line. What I use on a daily basis is pkgdev, pkgcheck, mgorny-dev-scripts and iwdevtools. All of them are text based shell tools, but that makes them perfect for Emacs-integration!

So, I am not the first one to have this idea of course. There is ebuild-mode and all the packages from Akater. What I think is lacking is proper instructions on how to integrate into Emacs and how to use them. Please note that I personlly use Doom Emacs now, so not everything here will work out of the box with vanilla GNU Emacs.

I will put this post also into a page on the Gentoo wiki and add things there.

ebuild-mode

Ebuild mode is the center package of ebuild development on Gentoo. It sits on top of sh mode. You can read its documentation with bzcat /usr/share/info/ebuild-mode.info.bz2.

Installation

Ebuild-mode is available on Gentoos main repository as app-misc/ebuild-mode, so install it like any other package with

emerge -a app-emacs/ebuild-mode

Ebuild mode package brings in several other modes apart from the ebuild-mode core, which are devbook-mode, gentoo-newsitem-mode and glep-mode. I don’t use them, and therefore this article will focus on ebuild-mode itself. Ebuild mode is then installed into /usr/share/emacs/site-lisp/ebuild-mode, so we have to tell emacs to load elisp from there:

(add-to-list 'load-path "/usr/share/emacs/site-lisp/ebuild-mode")

Put that into the config. There are several different ways how emacs loads configs. For Doom this is usually ~/.doom.d/config.el.

Configuration

To make emacs start ebuild-mode every time an .ebuild-File is opened, we should add this to the config as well:

(add-to-list 'load-path "/usr/share/emacs/site-lisp/ebuild-mode")
(autoload 'ebuild-mode "ebuild-mode"
  "Major mode for Portage .ebuild and .eclass files." t)
(autoload 'ebuild-repo-mode "ebuild-mode"
  "Minor mode for files in an ebuild repository." t)
(autoload 'ebuild-repo-mode-maybe-enable "ebuild-mode")
(autoload 'devbook-mode "devbook-mode"
  "Major mode for editing the Gentoo Devmanual." t)
(autoload 'gentoo-newsitem-mode "gentoo-newsitem-mode"
  "Major mode for Gentoo GLEP 42 news items." t)
(autoload 'glep-mode "glep-mode"
  "Major mode for Gentoo Linux Enhancement Proposals." t)
(add-to-list 'auto-mode-alist '("\\.\\(ebuild\\|eclass\\)\\'" . ebuild-mode))
(add-to-list 'auto-mode-alist '("*.ebuild" . ebuild-mode))
(add-to-list 'auto-mode-alist '("/devmanual.*\\.xml\\'" . devbook-mode))
(add-to-list 'auto-mode-alist
       '("/[0-9]\\{4\\}-[01][0-9]-[0-3][0-9]-.+\\.[a-z]\\{2\\}\\.txt\\'"
               . gentoo-newsitem-mode))
(add-to-list 'auto-mode-alist '("/glep.*\\.rst\\'" . glep-mode))
(add-to-list 'auto-mode-alist
       '("/\\(package\\.\\(mask\\|unmask\\|use\\|env\
\\|license\\|properties\\|accept_\\(keywords\\|restrict\\)\\)\
\\|\\(package\\.\\)?use.\\(stable\\.\\)?\\(force\\|mask\\)\\)\\'"
               . conf-space-mode))
(add-to-list 'auto-mode-alist
       '("/make\\.\\(conf\\|}defaults\\)\\'" . conf-unix-mode))
(add-to-list 'interpreter-mode-alist '("openrc-run" . sh-mode))
(add-to-list 'interpreter-mode-alist '("runscript" . sh-mode))
(add-hook 'find-file-hook #'ebuild-repo-mode-maybe-enable)
(modify-coding-system-alist 'file "\\.\\(ebuild\\|eclass\\)\\'" 'utf-8)

Keybinding

By default ebuild mode uses conventional emacs keybindings, you can look them up by pressing SPC h m while being in ebuild-mode.

key             binding
---             -------
C-c C-b         ebuild-mode-all-keywords-unstable
C-c C-e         ebuild-run-command
C-c C-k         ebuild-mode-keyword
C-c C-n         ebuild-mode-insert-skeleton
C-c C-y         ebuild-mode-ekeyword
C-c -           ebuild-mode-insert-tag-line

I remapped them so that they are more coherent with Doom Emacs:

(map! :localleader
      :map ebuild-mode-map
      "r" #'ebuild-run-command                ;; run a provided phase of the currently open ebuild
      "k" #'ebuild-mode-keyword               ;; change status of a single keyword e.g. from unstable to stable
      "s" #'ebuild-mode-insert-skeleton       ;; insert a skeleton of an ebuild to work from
      "u" #'ebuild-mode-all-keywords-unstable ;; mark all keywords unstable (~)
      "e" #'ebuild-mode-ekeyword              ;; run ekeyword on the current ebuild
      "t" #'ebuild-mode-insert-tag-line)      ;; inselt a tag with our name as the author

For the tag line ebuild mode uses the variables user-full-name and user-email-address. They are present in the default config of Doom Emacs.

ebuild-run-mode

Ebuild run mode provides the functionality to jump directly from an error in the output of ebuild-run-command to the location of the code snippet that produced the error.

Installation

ebuild-run-mode is available in akaters ebuild repository. So activate that using

eselect repository enable akater # if using eselect repository, or run the corresponding layman command
emaint sync -r akater
emerge -a app-emacs/ebuild-run-mode # then install ebuild-run-mode

Ebuild-run-mode is installed into /usr/share/emacs/site-lisp/ebuild-run-mode, so we need to tell emacs to load elisp from that path:

(add-to-list 'load-path "/usr/share/emacs/site-lisp/ebuild-run-mode")

Ebuild-run-mode sits on top of ebuild-mode, so only run that after ebuild-mode is loaded:

(eval-after-load 'ebuild-mode `(setq ebuild-log-buffer-mode 'ebuild-run-mode))

Now, when an ebuild was run using ebuild-run-command a buffer with the output will pop up. When there is an error, place the point (the cursor) on it and press return (bound to compile-goto-error) to jump to the line that produces the error in the packages code.

Little helpers

Put that in config.el/ init.el (for Doom that is ~/.doom.d/config.el).

Tabs instead of spaces in ebuild-mode

By convention ebuilds use Tabs, not spaces, for indentation. This is important, because pkgcheck will get upset when we use spaces or indentation. I usually use spaces in shell-Scripts, and since ebuilds are shell-scripts (for emacs at least they are), emacs would insert spaces when I press tab all the time. So I also put this into the config:

(after! ebuild-mode
  (setq indent-tabs-mode t))

Tag line everywhere

Because this is really useful even outside of ebuilds (in patches for example) I changed the ebuild-mode-insert-tag-line a little and bound it to a key that is always available instead of binding it to a key in ebuild-mode-map.

(defun ebuilds/insert-tag-line ()
  "Insert a tag line with the user's name, e-mail address and date.
Format is \"# Larry The Cow <larry@gentoo.org> (2019-07-01)\"."
  (interactive)
  (beginning-of-line)
  (insert (format "%s%s <%s> (%s)\n"
                  (if comment-start (concat comment-start " ") "")
                  ebuild-mode-full-name ebuild-mode-mail-address
                  (format-time-string "%F" nil t))))

This makes sure that a comment sign is only put into that tagline when a comment sign is known. Before when the line was inserted into a .patch-file, it would put nil at the start, because .patch-files do not have comment signs. (instead only lines with a space in front are not comments.) You could also use user-full-name and user-mail-address here instead of their ebuild-mode counterparts. For me those are the same so it does not really matter.

I bound that to SPC T.

(map! :leader
        :desc "Insert my tagline"           "T" #'ebuilds/insert-tag-line)#+end_src

Environment variables

To test ebuilds we often need to set environment variables like USE and CC for example. To set them in Emacs we use M-x setenv. To make things a little easier we can define little functions to set sets of environment variables and bind them to keys in ebuild-mode-map or call them with M-x. E.g. to change the compiler when testing Clang16 bugs I made this:

(defun ebuild-mode-set-CC-clang ()
    (interactive)
    (setenv "CC" "clang")
    (setenv "CXX" "clang++"))

(defun ebuild-mode-set-CC-gcc ()
    (interactive)
    (setenv "CC" "gcc")
    (setenv "CXX" "g++"))

Call scrub-patch from emacs

According to the Gentoo Dev Manual patches should meet certain QA conditions as well. Therefore we have a neat little program called scrub-patch which is part of app-portage/iwdevtools, so we should install that first using

emerge -a app-portage/iwdevtools

This thing scrubs the patch thoroughly and all we have to do is insert a short description what this patch is for, references to bugs and our tag. I wrote a function for Emacs to call scrub-patch on the current buffer or on the marked file(s) in dired, so we don’t have to go to the shell that often. In dired we mark files with m then call M-x ebuilds/scrub-patch. Or, if we have a patch-file open in the currently open buffer, just M-x ebuilds/scrub-patch.

(defun ebuilds/scrub-patch (&optional @fname)
"Call scrub-patch on marked file in dired or on current file.
 Needs app-portage/iwdevtools.
 Got this from xah lee, modified a bit
 URL `http://xahlee.info/emacs/emacs/emacs_dired_open_file_in_ext_apps.html'"
  (interactive)
  (let* (
         ($file-list
          (if @fname
              (progn (list @fname))
            (if (string-equal major-mode "dired-mode")
                (dired-get-marked-files)
              (list (buffer-file-name)))))
         ($do-it-p (if (<= (length $file-list) 5)
                       t
                     (y-or-n-p "Scrub more than 5 files? "))))
    (when $do-it-p
        (mapc
         (lambda ($fpath)
           (shell-command
            (concat "scrub-patch -c -i " (shell-quote-argument $fpath))))  $file-list)
        (when (not (string-equal major-mode "dired-mode"))
            (revert-buffer)))))

Go to build directory of the currently open ebuild

Sometimes I run into the problem that I want to go to the $WORKDIR of a build. Normally we would either need to type that long path to it (/var/tmp/portage...) or we could run the ebuild and produce an error somehow, than use ebuild-run-mode from above to go from that build error to the file. But what I the build has no error or we just want to run the prepare phase to begin writing patches for the package. Therefore I wrote this little function. When it is called with an ebuild in the current buffer, it will open helm-find-file (or ivy or vertico or whatever is used) in the $WORKDIR (/var/tmp/portage/$CATEGORY/$PACKAGENAME-VERSION/work) of that ebuild. Of course at least the unpack-phase must have ran before, otherwise there is no workdir. Be aware that this one only works in Doom, because we use the Doom specific function (doom/find-file-in-other-project) but if your Emacs has a similar function, tinker around with that function a bit. Also it is assumed that portages tempdir is /var/tmp/portage.

(defun ebuilds/goto-work-dir ()
"In a buffer with an open .ebuild file, go to the work dir of the build"
  (interactive)
  (let* '(currentpath (nreverse (split-string (buffer-file-name) "\/")))
    (if (string-match-p (regexp-quote ".ebuild") (car currentpath))
        (doom/find-file-in-other-project (concat
                                          "/var/tmp/portage/"
                                          (nth 2 currentpath)
                                          "/"
                                          (substring (car currentpath) 0 -7)))
      (print "Current file does not look like an ebuild"))))

I use that so often, I bound it to a key in ebuild mode:

(map! :localleader
      :map ebuild-mode-map
      "w" #'ebuilds/goto-work-dir)      ;; go to work dir of ebuild

Schievels software archeology 3 – wcd

app-misc/wcd is a utility program that should make changing directories on the command line more efficient. It was written by Erwin Waterlander in 1996 for HP-UX and was ported to many different operating systems, like DOS, Windows (95 to 10), MacOSX and, of course, Linux.

Because wcd indexes the filesystem on first run, and therefore can find the directories very fast. But what I also like is that this is coming from a time where mouse support was not really a big thing, so it has keyboard centric usage and is therefore very past to use.

When you type something like wcd org you get a list of files:

a /home/pascal/.emacs.d/.local/cache/org
b /home/pascal/.emacs.d/.local/straight/build-28.1/evil-collection/modes/org
c /home/pascal/.emacs.d/.local/straight/build-28.1/org
d /home/pascal/.emacs.d/.local/straight/repos/evil-collection/modes/org
e /home/pascal/.emacs.d/.local/straight/repos/org
f /home/pascal/.emacs.d/modules/lang/org
g /home/pascal/.emacs.old/.local/cache/org
h /home/pascal/.emacs.old/.local/straight/build-28.1/evil-collection/modes/org
i /home/pascal/.emacs.old/.local/straight/build-28.1/org
j /home/pascal/.emacs.old/.local/straight/repos/evil-collection/modes/org
k /home/pascal/.emacs.old/.local/straight/repos/org
l /home/pascal/.emacs.old/modules/lang/org
m /home/pascal/nextcloud/Uni/Theoretische Informatik/JFLAP7.1/org
n /home/pascal/nextcloud/org
o /home/pascal/org
                                                                                                                                                                                   w=up x=down ?=help  Page 1/1
Perfect match for 15 directories.
Please choose one (<Enter> to abort):

Typing a letter now will change the working directory to the given path.

On top of that wcd offers a very nice file browser for the terminal. I used to use lf for that (and only that, I know lf can do much more, but for I all the file operations I just stick to the normal shell commands), which is also a good program, but the default vim-like behaviour make things in wcd even a tad better for me. You activate the file browser with wcd -g and something like this will come up:

                        ├─ org2blog ─┬─<htmlize>─── .git ─┬─ hooks
                        │            │                    ├─ info
                        │            │                    ├─ logs ─── refs ─┬─ heads
                        │            │                    │                 └─ remotes ─── origin
                        │            │                    ├─ objects ─┬─ info
                        │            │                    │           └─ pack
                        │            │                    └─ refs ─┬─ heads
                        │            │                             ├─ remotes ─── origin
                        │            │                             └─ tags
                        │            ├─ hydra ─┬─ .git ─┬─ hooks
                        │            │         │        ├─ info
                        │            │         │        ├─ logs ─── refs ─┬─ heads
                        │            │         │        │                 └─ remotes ─── origin
                        │            │         │        ├─ objects ─┬─ info
                        │            │         │        │           └─ pack
                        │            │         │        └─ refs ─┬─ heads
                        │            │         │                 ├─ remotes ─── origin
                        │            │         │                 └─ tags
                        │            │         ├─ .github
                        │            │         ├─ doc
                        │            │         └─ targets
                        │            ├─ metaweblog ─┬─ .git ─┬─ hooks
                        │            │              │        ├─ info
                        │            │              │        ├─ logs ─── refs ─┬─ heads
                        │            │              │        │                 └─ remotes ─── origin
                        │            │              │        ├─ objects ─┬─ info
                        │            │              │        │           └─ pack
                        │            │              │        └─ refs ─┬─ heads
                        │            │              │                 ├─ remotes ─── origin
                        │            │              │                 └─ tags
                        │            │              ├─ .github ─── ISSUE_TEMPLATE
                        │            │              ├─ ci ─── vale ─── styles ─── Vocab ─── Base
                        │            │              ├─ docs
                        │            │              ├─ images
                        │            │              ├─ svg
                        │            │              └─ tests
                        │            ├─ org2blog ─┬─ .git ─┬─ hooks
                        │            │            │        ├─ info
                        │            │            │        ├─ logs ─── refs ─┬─ heads
                        │            │            │        │                 └─ remotes ─── origin

Now, you can go around the directory tree with arrow keys or HJKL. Additionally you can search similar to vim by typing /. To go to the next occurence of the searched term, type CTRL-n. Pressing enter will exit the tree view and change the working dir of the shell to the highlighted directory.

Schievels software archeology 2 – Levee

app-editors/levee is a vi clone by David Parsons. It is from a time where vi was still closed source. Last release it saw was in 2019, it has a Github repository and also a Webpage. I do not know why but levee is also called ’Captain Video’ by David.

Well, there is not that much to say about this technically other than this is a vi clone. It does what you expect from vi: Going around with HJKL and trapping users that do not know about :q!. What struck me is that this thing is really ancient, it is from 1981 or so and was originally written in some dialect of Pascal called USCD Pascal and was ported to C in the 80s. Yet it is still maintained actively by David, or Orc on GitHub. It is also really tiny, David writes about 54k on 64bit OSX. I am considering using this on an STM32 as an editor running on the display of my keyboard project. if I get this to compile for ATmega.

The changelog of version 4.0 reads fix a 39 year old bug where changing the last line in a file wouldn’t refresh properly.

David also has some other interesting projects, including his own version of autoconf, so check out his homepage.

Schievels software archeology 1 – Boxes

A series for ancient software pearls

I recently started with fixing bugs for clang16 in Gentoos packages. By default, Clang-16 will not allow implicit integer return types, implicit function declarations etc.

Eventually GCC-14 will follow, and instead of just changing the CFLAGS to make those errors into warnings again, we try to write patches for the packages. This is because this is not only cosmetic, implicit functions can lead to runtime failures on some architectures while the program runs fine on other architectures.

This is quite a task, here you can read up about it. Currently Gentoo has more than 500 open bugs because of this.

But this post should not be mainly about fixing clang16 bugs. When fixing those bugs I mainly aim for the packages in Gentoo that have no maintainer because these are the ones that are fixed the least likely so I feel my help is needed the most here. Many of those packages are abandoned by upstream as well, last release was 10+ years ago. But every now and then I come across an ancient software pearl which has a long standing history, is still maintained or does really interesting things. Things that are done in a different (supposedly more user friendly) way today, which makes using those packages and looking at them interesting as well.

Therefore I would like to start as small series here, where I present an ancient program in every post when I come across such a pearl.

Boxes

First software pearl I came across was app-misc/boxes by Thomas Jensen, they also have a GitHub repository and Webpage. This thing was founded some time around 1999 and saw it’s last release on Sep. 22, 2022!

What it does is generating ascii-art boxes, hence the name, around a given string. Like this:

/**************************/
/* Different all twisty a */
/* of in maze are you,    */
/* passages little.       */
/**************************/

or this:

          ,
      /\^/`\
     | \/   |
     | |    |               SPRING IS IN THE AIR!              jgs
     \ \    /                                                _ _
      '\\//'                                               _{ ' }_
        ||                      joan stark                { `.!.` }
        ||                  <spunk1111@juno.com>          ',_/Y\_,'
        ||  ,                                               {_,_}
    |\  ||  |\                                                |
    | | ||  | |              ASCII ART GALLERY:             (\|  /)
    | | || / /      <http://www.geocities.com/SoHo/7373/>    \| //
     \ \||/ /                                                 |//
      `\\//`   \\   \./    \\ /     //    \\./   \\   //   \\ |/ /
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

(The geocities link is sadly dead)
Boxes has a wide selection of ascii-art boxes to choose from. Now, the more artsy ones are nice, I have a nick for ascii-art, but not very useful to me. But the other ones are very good to split C-code into sections.
Boxes is especially great because it generates the box around an already existing string. So you don’t need to have the box in mind when writing comments, you can put them in afterwards. Secondly boxes not only generates those boxes, it also removes botched boxes and puts new ones around the string again. Say you have a nice box and you edit the text inside. The box will become broken. You can remove the broken box with boxes -r and put a new one in afterwards. This is a great feature, since removing such boxes manually is kind of tedious.

You can also integrate this into the editor of your choice. They have a dedicated page to that. There is also a boxes-modes for Emacs, of course, but I have not checked it out yet. I am quite happy with the two functions of adding a box and removing it again.

Armaturenbrett

In das originale Armaturenbrett passt leider das Kombiinstrument schon nichtmehr rein, so verbogen ist es. Deswegen haben wir uns dazu entschieden, es auszutauschen.

Ein Armaturenbrett war schnell ersteigert. Da wir es ohnehin neu lackieren wollten, waren unsere Ansprueche nur, dass es nicht verbogen ist und nicht zu viele selbstgebohrte Loecher aufweist.

Da Armaturenbrett haben wir abgeschliffen mit dem Akkubohrer mit Drahtbuerste. Wirklich keine schoene Arbeit. Das hat einen ganzen Tag gedauert, der originale Lack ist ziemlich dick und widerspenstig.

Dann haben wir das Armaturenbrett grundiert.

Und zu guter Letzt lackiert. Die Farbe hat sich die holde Weiblichkeit ausgesucht. Als Designerin muss die ja wissen ob das so passt. 🙂

Endergebnis und wie es vorher aussah:

 

 

Mit dem Ergebnis sind wir aber nicht ganz zufrieden. Auf den Bildern sieht man ja, dass die Oberflaeche nicht ganz glatt ist. Das liegt daran, dass die Grundierung mit dem Pinsel aufgetragen wurde. Also, naechstes mal spruehen. Und das Armaturenbrett wird vielleicht irgendwann nochmal lackiert.

Oben sieht man auch die Sonnenblenden und den neuen Rueckspiegel, den wir angebracht haben. Gurte hat er auch schon, allerdings brauchen wor laengere Gurtpeitschen. Die 30cm langen passen nicht, es muessen 45cm sein, sonst muss man sich total verrenken beim Anschnallen.

Da wir uns schon um solche Kosmetikdinge kuemmern, wird es wohl langsam Zeit, dass der Bus zum TUEV kommt. Zumindest mal die Abgasmessung beim Motor machen und dann einen Termin zum Erkenntnisgewinn, was noch alles gemacht werden muss. Zuerst aber mal Geld sparen, die Abgasmessung wird nicht billig.

 

Lichtmaschine kaputt?

Mal wieder ein Glanzstueck der Bastlerkunst…

Nachdem ich die Elektrik wieder zusammen hatte, habe ich mal den Motor gestartet und geschaut ob alles so geht wie es soll. Und wie es so spielt, habe ich mal an der Lichtmaschine gemessen, und gesehen: 12V!

Also Lichtmaschine kaputt? Aber ging doch frueher schonmal, da habe ich gemessen und es waren 14V!

Ok, kann ja sein, also Lichtmaschine ausgebaut. Das dauert gut und gerne 2 Stunden, natuerlich auf Knien, wenn man keine Ahnung hat wie es geht. Ich habe noch eine Lichtmaschine am alten Motor dran, die hat zwar weniger Ampers, aber vielleicht geht die ja…

Also Lichtmaschine vom alten Motor ab, in den Motor im Bus eingebaut, Keilriemen passt nicht, scheisse.

Die vermeintlich kaputte Lichtmaschine habe ich erstmal mitgenommen. Im Internet steht was Kohlen abgerieben, also neue Kohlen bestellt, eingeloetet. Man braucht fuer die LiMa vom Mexikokaefer uebrigens die hier:

https://www.ebay.de/itm/Kohleb%C3%BCrsten-Lichtmaschine-Bosch-Lima-Kohlen-8x5x15-5/273236094958?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649

in 8x5x15,5.

Da sind sie noch eingebaut: 

Dann lese ich schon ueber Reglertausch, und dass man dafuer die ganze Lima auseinandernehmen muss usw. usf.

Nebenbei lese ich aber noch folgendes: Die Erregerspule in der Lima ist in Reihe geschaltet mit dem Batteriewarnlaempchen im Armaturenbrett. Das macht auch theoretischen Sinn: Wenn die Lichtmaschine steht, also wenn man die Zuendung an macht aber den Motor noch nicht startet, fliesst durch die Erregerspule ein hoher Strom. (Oder wenn der Keilriemen kaputt ist.) Dieser Strom bringt auch die in Reihe geschaltete Lampe zum leuchten. Sobald die Lichtmaschine dann gedreht wird, hemmt das erzeugte Gegenfeld den Strom in der Erregerspule, und damit erlischt die Lampe.

Leider ist es aber so, dass die Lichtmaschine nichtmehr geht, sobald der Strompfad unterbrochen ist. Und das ist ja schon der Fall, wenn die Lampe durchbrennt. Deshalb empfiehlt es sich immer, wenn man Probleme mit der Lichtmaschine hat, erstmal zu schauen ob die Lampe brennt, wenn man die Zuendung anmacht.

Also, LiMa vom alten Motor wieder raus, Mexiko-LiMa wieder rein. Diesmal ging es etwas schneller, ich wusste ja schon wie es geht. Dann Verdrahtung vorne ueberprueft: Die Lampe fuer die Lichtmaschine ist an einer isolierten Platte im Gehaeuse des Kombinstruments angebracht. Das ruehrt daher, dass die normalen Lampen so funktionieren, dass am einen Kontakt der Birne 12V angeschaltet werden, wenn die Lampe leuchten soll. Der andere Kontakt der Birne hat durch die Fassung automatisch Kontakt mit dem Gehaeuse.

Die Lichtmaschinenlampe hat hingegen an dem Kontakt 12V, und der andere Kontakt wird durch die stehende Erregerspule auf Masse gelegt. Die isolierte Platte ist aber nur gegen das restliche Gehaeuse isoliert, d.h. ansonsten ist sie blank. So ganz geheuer war mir das nicht, dass da eine blanke Platte mir 12V im Armaturenbrett ist, natuerlich sind die 12V nicht abgesichert…

Daher habe ich die Lampenfassung so umgebaut, dass sie keinen elektrischen Kontakt mit dem Gehaeuse herstellt, und 12V von Klemme 15 an den (nun gegen die Platte isolierten) Kontakt angeschlossen.

Lichtmaschine geht wieder. Naja, zumindest hat sie jetzt auch neue Kohlen.

Elektrik, Elektrik, Elektrik

Zuerst habe ich ja mit dem Gedanken gespielt, die Elektrik komplett rauszureissen und neu zu verkabeln. Bei einem alten Auto, ist das weit weniger Aufwand als Heutzutage. Ist ja nichts dran. Ich habe mich aber dann doch dagegen entschieden, da ich dachte, dass ich das nie wieder so zusammenkriege, wie der Kabelbaum mal war.

Allerdings stoerte mich immer die Verdrahtung um den Sicherungskasten rum. Das ist so ein Kabelsalat, gleichzeitig sind die Sicherungshalter und Sammelschienen im vom Sicherungskasten komplett blank. Also kam es, wie es kommen musste, Batterie war angeschlossen und eine blanke Schienen vom Sicherungskasten kam an die Halterung vom Armaturenbrett. Die Schiene ist komplett ungesichert, deshalb hat ein Kabel sofort angefangen zu schmoren.

Das machte mit die Entscheidung etwas leichter, die Verdrahtung um den Sicherungskasten habe ich komplett neu gemacht. Den Sicherungskasten habe ich durch einen Modernen ersetzt. Mit der Verdrahtung bin ich nur halb zufrieden, das meinte ich oben mit nie wieder so zusammenkriegen: So ganz bin ich mir nie sicher, ob ich dann nicht doch irgendwann einen Wackelkontakt habe oder ein Draht mal gezogen wird und sich loest.

Erst alt, dann neu:

(Die Kabelschuhe habe ich noch mit Schrumpfschlauch isoliert)

Keine Ahnung ob der alte Sicherungskasten so original war und das so gedacht ist, dass die ungesicherten Schienen unisoliert sind.

Wenn man schonmal dabei ist, habe ich auch direkt eine Nebelschlussleuchte eingebaut. Opa hatte noch eine gute von Hama rumliegen. Der gelbe beleuchtete Schalter dafuer kommt ins Armaturenbrett

.