re: ctags

This post is a reply of sorts to "ctags" by thrig.

ctags is a little program that makes a little regex powered database (a plaintext 'tags' file) in your project root so you can jump around between locations in a text file. Consider for example a large codebase. ctags lets you jump to a class definition or function definition regardless of where it is defined, across files. It does this automatically for a large number of supported languages when you run the ctags command.

ctags support is deeply baked into vim. Ctrl-[ and Ctrl-O for jumping away and back are how you navigate :help for example. And :help ctags has a bunch of info.

ctags was obsoleted by exuberant-ctags, which was obsoleted by universal-ctags. All of which were obsoleted by Language Server Protocol.

But ctags can still be fun and also useful! Especially when using it with user-defined languages.

I recently used ctags to define an ad-hoc "language" when I was writing a choose-your-own-adventure story. At a certain point, the source file, a recfile full of story nodes, got to be kind of long. And to speed up my editing, I wanted to be able to quickly jump from a reference to a story node to the place where that story node was actually created. Exactly the kind of thing ctags is good at! Especially since there is of course no LSP support for the tiny bit of syntax I created for this tiny little project.

Defining a language requires making use of the optlib capabilities of ctags.

One of the advantages of Exuberant Ctags is that it allows a user to define a new parser from the command line. Extending this capability is one of the major features of Universal Ctags. ctags-optlib(7) describes how the capability is extended.
src: man ctags

Here's a snippet of my file:

id: 0
name: beginning
text: You wake up in the comfort of your own bed, in your own room. You open
your eyes to see the golden sunlight come streaming in through your window.
Golden like ears of corn. You suddenly remember what day it is. It is the day
of the Harvest Festival! You throw back your favorite corn print bed covers and
leap out of bed. You've been looking forward to this day all year, and you
already know exactly what you're going to wear. If you wear a pretty corn
dress, goto {{corndress}}. If you wear rugged corn bib overalls, goto to
{{cornoveralls}}.

id: 1
name: continue
text: You start to sneak sneakily around the web, and do so successfully, the
spider none the wiser to your passage through its lair. Good job! You trek
deeper and deeper into the forest, losing track of the path behind you.
Eventually you come across a small clearing, in the middle of which is a small
cottage on tall wooden legs. Goto {{hut}}.

What I want to do is jump quickly e.g. from "{{hut}}" to the line that says "name: hut". I could use the * command to jump to the next occurance of the word hut, but that could get me any instance of the word. I need /^name: hut$/. And the ctags language options will do that!

ctags --langdef=game
  --map-game=+.rec
  --kinddef-game=n,name,names
  --regex-game=/^name:[ \t]*([a-zA-Z]+)$/\1/n/

  1. --langdef=<LANG> allows you to define a new language.

  1. --map-<LANG> will do stuff like let you associate a file extension with the language

  1. --kinddef-<LANG>=<letter>,<name>,<description> defines a kind, a language object. Like a function or a class or a name. You can be pretty arbitrary with this. I don't think it does a ton except for when you use the -x cross reference flag with ctags to print a reference doc. Then you can see all the kinds. Oh, and also you'll need to refer to the letter / kind-spec in the next part.

  1. --regex-<LANG>=/<line_pattern>/<name_pattern>/<kind-spec>/: don't think this is regex search and replace just because it has forward slashes and says the word "regex". The first bit defines the definition. The second bit defines the definition reference. And then you gotta put the kind letter for some reason.

And then it's done!

Pretty convenient. I put the above command in my makefile, and now I can generate a tags file after updating my source file, and jump around to definitions much more easily! Thanks ctags!

Links:

video of me talking about ctags (peertube):

=> https://tube.tchncs.de/w/hsiLFG8WqA7XxNr4tcW3LE?start=17m42s

Language definitions:

=>: https://docs.ctags.io/en/latest/optlib.html

ctags by thrig.me:

=> gemini://thrig.me/blog/2025/01/17/ctags.gmi

:wq

Thoughts? Comments? Let me know at dozens@tilde.team

Filed under:
=> tags/programming.gmi programming
=> tags/reply.gmi reply
=> tags/recutils.gmi recutils
=> tags/index.gmi All tags

title: re: ctags

author: dozens dozens@tilde.team

url: gemini://tilde.town/~dozens/gemlog/27.gmi

created: Sun, 19 Jan 2025 21:35:55 -0700

updated: 2025-01-19T22:11:09-07:00

tags: programming reply recutils

Proxy Information
Original URL
gemini://tilde.town/~dozens/gemlog/27.gmi
Status Code
Success (20)
Meta
text/gemini
Capsule Response Time
504.964976 milliseconds
Gemini-to-HTML Time
2.366261 milliseconds

This content has been proxied by September (3851b).