You should fork your favorite software

... and actually do something with it!

I'm always really happy when I see things get forked by lots of people, but then when I look into some of them, I rarely see anything being done. I think that's a massive missed opportunity: Messing around in the software you use is one of the most rewarding and productive things you can do.

I forked Oracle's GraalVM

Once upon a time, I was a java developer (ew, imagine that!). I wrote a minecraft modification called TTCp, which was basically a cheat for use on anarchy servers (ew, imagine that!), and I wanted to make a plugin system for it.

I first looked towards the JVM's builtin nashorn javascript engine: It provides everything I needed, so I tried it, only to notice that the thing was severely outdated in terms of what javascript things it supports. I tried using it anyway and it worked quite well. I had no issues beyond difficulty writing such old JS.

But I wanted to write newer JS. So I looked at oracle's new thing, GraalVM: That supports up-to-date JS and even all sorts of other languages. But quickly upon trying it, I noticed it would fire a mysterious exception telling me I can't be accessing the JS context from multiple threads.
This issue was absolutely horrible and I hope to never think of it ever again after I'm done writing this. I tried all sorts of things: Adding locks (which slowed the game down intensely because GraalVM was SO much slower than nashorn), having a separate JavaScript thread, just trying to avoid even accessing it from multiple threads in the first place by just returning when calling from not-the-main-thread. None of these were good solutions.

So I forked it. I cloned GraalVM to my PC and started hunting for this error message. Within about 20 minutes, I patched it away and tried the result. My GraalVM was now no longer "production-stable", according to the original developers, but it didn't experience any instability for the many many hours of playtime I accumulated with such plugins.

I was actually really quite lucky to have gotten the idea to fork Graal. The code was horrible, but now I could actually implement a competent way of doing name translation: You see, minecraft is not really made for modding. The entire code is obfuscated - you can't really know what any function or field does. But there are mappings available, such as those used for writing mods in Java.

My pull requests for both of these changes were denied due to stubbornness both on my part and on theirs. But that didn't really matter, because I now had a working plugin system for minecraft that had hot-reloading, hid the ugly obfuscation away, and worked with minecraft's multi-threaded nature.

I forked Helix

Really, I'm writing this because I recently forked Helix, and I am getting the feeling that I'll be doing this kind of thing significantly more often now.

Helix is quite an awesome editor, but unfortunately, having manpages open is basically a requirement for C development. I'm not usually much of a C person, but I saw my friend manually type `man n xyz` a bunch and realized my C code would probably also improve if I looked at more documentation. I decided to make helix open these manpages for me.

Where to start

When I first went into the helix project, it was a bit overwhelming to be honest. There really is a lot of code. I started by searching for the broad category of what I want to hook into: Movement and typing. Movement first.

By typing `gfmovement`, i simply asked helix to find any file with movement in the name. And it found three: Two of them tests, one of them in helix-core. I went into that, and asked helix for references to the first movement function I saw. That showed me a bunch more calls in the same file, but I wanted to get closer to wherever the movement actually happens, so I searched for things outside that file, leading me to commands.rs. Here, I found exactly what I was looking for: A function called move_impl, which then called doc.set_selection. And that's what I hooked into. Now whenever I select anything, move anywhere, click anything, I can do whatever I want with that.

Avoiding insanity

Remember, you are doing this JUST for you. If you want to contribute, you can go do that later. For now, you will do what works. Do not make my mistake of trying to bother with e.g. helix-events. helix-events is theoretically the intended way of hooking into that same function. And yet, it is the absolute worst way to do so. With it, you're looking through several more layers of abstraction that don't bring you any closer to your goal, but force you to write a dozen functions to get your events to come in correctly.

Dont. Bother.

Instead of hooking into this beast, you will write a single function call right inside of the set_selection function, where you actually want to be. You also make a new file or just go into some other file (in my case, I just went to the main file lib.rs), and you create a function there that will handle your new "event". Now you call that from wherever you want to add your custom actions, so in my case set_selection. Just call it directly, it's fine. The intended audience is you, not a reviewer. You are modifying this code so that you have a better time using it, not so that others admire how well you can hook into preexisting event distribution systems.

Now you do whatever

In my case, the handler function has a static TCP server running and sends all clients the currently selected word using some dirty word detection. But you can basically make it do whatever you'd like. Even if it goes completely against the original project's philosophy. If it aligns, great, but the most important thing is that it is useful to you. Integrating it with the rest of the project might be a good idea if it does fit in, but even then, don't waste your time. Make a dirty version first, then refine if you want.

The manpage viewer works like a charm, even though it could never ever be in the main repo. Indeed, I would probably be called a lunatic if I even suggested such an out-of-scope idea - a plugin system is already in the works after all. But writing a plugin is effort, and when you want to make a change just for yourself, don't feel pressured to make it into a plugin (but publish the patch anyway for others who might need it).

TL;DR

Fork your favorite thing and make whatever changes you feel might improve your workflow. Don't be afraid to break and sidestep things in the process. If it's hyperspecific, then so be it, because you're doing this for yourself. But if it does end up fitting in, making a pull request is of course also great.