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.

Neue Scheibe

Da die alte Windschutzscheibe kein Verbundglas war, und zudem kein E-Pruefzeichen hatte, mussten wir diese auch ersetzen. Die Scheibe gibt es von Sekurit fuer ca. 170 Euro, ist also noch bezahlbar. Wichtig ist, dass es Verbundglas ist. Mit einer normalen Glasscheibe, die ja nochmal einiges guenstiger waere, wuerden wir wohl nicht durch den TUEV kommen. In den Brasilien Bulli  „T1,5“ passt die normale Scheibe vom deutschen T2.

Wenn man sowas noch nie gemacht hat, fragt man sich auch erstmal: Wie kiegt man denn so eine Autoscheibe in den Rahmen? Aber mit grossvaeterlicher Expertise, ging es doch ganz schnell.

Man drueckt zuerst die Scheibendichtung auf die Scheibe auf, dann legt man in die Nut, in die spaeter die Kante vom Rahmen soll, ein duennes Seil. Dann wird die Scheibe aufgelegt, und das Seil so rausgezogen, dass sich die Lippe der Scheibendichtung um die Kante im Rahmen legt. Klingt kompliziert, aber es gibt bestimmt auch genug Youtube-Video dazu.

Zwei Leute braucht man schon, wir waren zu Dritt.

Zugegebenermassen war ich etwas Schreibfaul. Aber nicht Arbeitsfaul, es ist einiges im letzten halben Jahr passiert an dem Bus! Der Blog hier ist eigentlich mehr als Erinnerungsstuetzte fuer mich Gedacht, damit ich in einiger Zeit mal wieder zurueck gehen kann und schauen kann was ich so alles gemacht habe und wie das war. Daher hole ich jetzt alles nach, was ich so gemacht habe.

 

Hinterachse

Heute war dann auch wie angekuendigt die Hinterachse dran.

Eine Antriebswelle hatte ja kaputte Manschetten, und da ich dachte, dass der Bus damit in Chile wahrscheinlich Ewig umhergefahren ist, bin ich davon ausgegangen, dass die Gelenke auch hinueber sind.

Nachdem ich ein Gelenk auseinandergebaut hatte, zeigte sich dieses Bild:

Ich wollte die erst austauschen, aber die Buscommunity ist sich da ziemlich einig, dass man die originalen Gelenke von VW so lange wie moeglich fahren sollte, da die Nachproduktionen nicht die gleiche Qualitaet erreichen. Das gilt uebrigens auch fuer die Manschetten, aber die war ja leider eh schon kaputt bei mir.

Also entschied ich mich nur die Manschetten auszutauschen. Da man mir ja schon sagte, dass die Nachproduktionen nicht so gut sind, habe ich mich fuer diese Universalmanschetten entschieden. Die sind auch einem vergleichsweise dicken Material, und ich hatte beim Lada Niva schon gute Erfahrungen mit den Dingern gemacht. Da reisst ja doch schon mal der ein oder andere Strauch an den Manschetten.

Also dann, gesagt getan. Die Gelenke hatte ich zuvor eine Woche in Petroleum eingelegt, damit das ganze alte Fett rauskommt. Heute musste ich sie nur noch abwischen, die eine Seite wieder zusammenbauen (natuerlich mit den neuen Manschetten vorher auf der Achse), fett rein, fertig. Wenn man ein Gelenk ab hat, geht das mit den Manschetten sehr viel einfacher, als mit so einem Kegel und sehr sehr viel Silikonspray.

Neue Daempfer gabs auch gleich fuer die Hinterachse:

In dem Bild sieht man auch einen Schlauch fuer die Heizung. Aus irgendeinem Grund hat sich VW irgendwann mal entschieden, die Stutzen fuer die Waermetauscher ein bisschen Groesser zu machen. Der Schlauch, der da zwischen Motor und Auto ist, hat einen Aussendurchmesser von 60mm, der Stutzen jetzt auch. Keine Ahnung warum man das gemacht hat, die Heizung vom Kaefer hat eigentlich sowieso nie richtig funktioniert. Ich habe einfach einen Kuehlerschlauch mit 60mm Innendurchmesser besorgt und da als Verbinder druebergezogen. Passt perfekt, so perfekt, dass ich auf eine Schelle verzichtet habe. Eigentlich kann der Heizungsschlauch aus nirgendwo hin.

Desweiteren hat der Bus jetzt neue Scheinwerfer. Die sehen genauso aus wie die Alten, haben aber E-Pruefzeichen. Und das Ruecklichtglas hinten Rechts ist auch neu und hat ein E-Pruefzeichen. (Das hinten links hatte schon eins.)

 

Ansonsten bin ich noch am Auspuff dran. Der ist ja auch vom 1600i Motor, und da geht das Rohr Kaeferstyle waagrecht nach hinten raus. Leider ist da beim Bus die Stossstange.

Motorumbau

Mittlerweile ist klargeworden, das wir an dem Bus den Motor austauschen muessen. Als einziger Motor kommt eigentlich nur der 1600i Motor aus dem Mexikokaefer in Frage, weil wir Euro 1 erreichen muessen.

Einen etwas laengeren neuen Text gibt es auf der Projektseite, mit einiges an Erklaerung, wie das alles von Statten geht. Der neue Motor ist mittlerweile auch drin und ready to fire, aber die Benzinpumpe geht nicht.

Insgesamt wird dieser Blog hier updates ueber den momentanen Zustand des Brullis geben, auf der Projektseite wird es tiefergehende Erklaerungen geben. Damit der Nachwelt auch ein bisschen was erhalten bleibt.

Projektseite

Ein neues Projekt

Ein etwas größeres Projekt ist unser Bulli. Letztes Jahr wurde der Bus aus Chile importiert, und nachdem er einen Winter hier in Deutschland in der Scheune verbracht hat, ist es in unsere Hände gefallen. So einen Brasilienbus, von Kennern liebevoll „Brulli“ gennant, ist genau das, was wir wollten. T2 Front, und daher noch einigermaßen Bezahlbar (für den T1 werden nur noch Mondpreise abgerufen) und T1 Heck. Das, was uns am T1 so gefällt, die Eckfenster hinten und die Flügeltüren statt Schiebetür an der Seite, hat der Brulli aber auch.

Ich sehe schon ziemlich eindeutig, dass da einiges auf uns zu kommen wird. Dabei geht es garnicht so sehr um die handwerkliche Arbeit, die mir Sorgen macht, sondern um die Bürokratie so einen Import in Deutschland zuzulassen.

Innen ist allerdings garnichts, wirklich garnichts, gemacht. Nach meiner Recherche liefen die Busse damals allerdings in Brasilien so vom Band: Keine Türverkleidungen hinten, kein Himmel. Also fehlt garnicht mal so viel.

Die Sitzbänke hinten sind auch hinüber, aber das ist halb so wild.

Unseren Brulli möchten wir zum Camper umbauen, daher kommen die ohnehin raus.