File Links in the Terminal

By Artem Avetisyan on January 10, 20205 min read

I am a web developer working with node and rails. I’ve been using command line as my development environment and terminal vim as the editor of choice for more than ten years. I often pair with other developers and I can compare my experience with that more of a conventional IDE. Some of the terminal ways are clearly better, others are… less better. But there was this one thing missing from my setup, the thing so essential that it had me questioning my choices more than once. Today, after years of searching, I am happy to report that this has been finally put to bed.

You might be expecting something flashy but it’s actually quite boring. The most useful tricks aren’t the spectacular ones, but rather those we use often. Here is what it is: the IDE guys can click on a line in a stack trace in a terminal and have their editor open that file on that line. Let’s put this into context. Big part of my day is to run tests and investigate their failures. Seamless navigation between tests and code not only saves time, but also encourages to run tests more often. I am not going to dwell on the importance of that - let’s just say it’s really important to me. With that in mind, on to the how this is now possible.

Tmux

First let’s talk about tmux - as it plays a key part in all this. Tmux - terminal multiplexer - has lots of useful features but one thing that makes it indispensable for me personally is that it keeps terminal windows in sessions and it allows to quickly switch between those sessions. This way I can have multiple projects opened at the same time - each with their own set of terminal windows for shell, vim, rails console, log tail, etc. - and I can switch between them without having to close old terminal windows and open new ones, cd’ing into project directories and so on.

Another cool thing about tmux is that it is scriptable. You can do basic things like create or attach to a named session. Or more advanced stuff like sending kestrokes to a particular tmux window. I’ve used that last one before to implement run test under cursor feature. It will also come handy in this case.

There is nothing new about tmux however. What was missing all that time was something that would allow me to choose an arbitrary text in the terminal, make sure it resolves to an existing file and then pass it into the vim window in the form of :e +123 /path/to/the/file.txt - that’s vim’s for opening file.txt on line 123 - followed by Enter.

Kitty

I’ve looked into various terminal emulators, but none of them had enough muscle for it (except for iTerm but only for absolute filenames). And then I found kitty. Kitty didn’t have what I wanted either, but what it did have was a maintainer who, as I was settling in for a long feature discussion on github, just went ahead and did the whole thing. To this day, I am still shocked. In a good way. Oh, and let me also add to this that kitty is an insanely fast modern terminal emulator. Give it a try.

With the final piece of the puzzle in place, all that was left to be done was to… write a little bit of python. You see, what the kitty maintainer did was to simply expose an interface to plug into the hints plugin (or “kitten” as they call it) - a vimperator/vimium like way to “act on arbitrary text snippets currently visible on the screen” (this isn’t techincally clicking links, but who wants to use mouse in the terminal anyway?).

This provided enough power to do things like checking for file existence before showing “hints” (thus reducing false positives to none). It also unlocked an interesting ability to show “hints” for things that look nothing like files but yet resolve to a file on the file system. For example, Admin::PostsController#index in rails log actually resolves to a particular line number in app/controllers/admin/posts_controller.rb.

Ultimately, any text can be mapped onto any action. So when a text looks like a url, the script feeds it to the system open and so the browser pops up navigating to that url. God knows what other interesting mappings can spring out of this. Dates to calendar? Git SHAs to github? Custom actions based on file type? You name it.

All together now

Anyway. This is how you can use it:

  • get kitty (if installing from OS package manager, make sure the version is 0.15 or greater)
  • wget -P ~/.config/kitty https://raw.githubusercontent.com/artemave/myrcs/master/.config/kitty/mega-hints.py
  • add the following line map kitty_mod+f kitten hints --customize-processing mega-hints.py tmux to ~/.config/kitty/kitty.conf

That’s it. Assuming your kitty_mod is Alt, pressing Alt-f will highlight all files (and web urls) currently displayed in the terminal. Files will be sent to window named vim in the current tmux session. Web urls will be sent to the web browser.

This is how it looks:

How it works

Bonus - no tmux, no vim

I showed this to a friend. He said: “sexy”. He also said: “how do I quit vim?” and “what the hell is tmux?“. This got me thinking. Kitty’s “hints” isn’t tied to tmux in any way. Similarly, vim is just a program that can open files. I could simply have “normalised” file paths sent to a user defined command. And so I made few modifications and as a result this is now also possible. Simply swap the tmux bit in the above mapping for your editor command - e.g. code -g for vscode - and voila.