A Missing IDE Feature

Slightly unusual genre with this article, I want to try to enact a change in the world. I believe that there is a missing IDE feature which is:

The target audience here is anyone who can land a PR in Zed, VS Code, Helix, Neovim, Emacs, Kakoune, or any other editor or any language server. The blog post would be a success if one of you feels sufficiently inspired to do the thing!

The Feature

Suppose you are casually reading the source code of rust-analyzer, and are curious about handling of method bodies. Theres a Body struct in the code base, and you want to understand how it is used.

Would you rather look at this?

Or this?

(The screenshots are from IntelliJ/RustRover, because of course it gets this right)

The second option is clearly superior it conveys significantly more useful information in the same amount of pixels. Function names, argument lists and return types are so much more valuable than a body of any particular function. Especially if the function is a page-full of boilerplate code!

And this is the feature I am asking for make the code look like the second image. Or, specifically, Fold Method Bodies by Default.

There are two components here. First, only method bodies are folded. This is a syntactic check we are not folding the second level. For code like

fn f() { ... }

impl S {
    fn g(&self) { ... }
}

Both f and g are folded, but impl S is not. Similarly, function parameters and function body are actually on the same level of folding hierarchy, but it is imperative that parameters are not folded. This is the part that was hard ten years ago but is easy today. what is function body is a non-trivial question, which requires proper parsing of the code. These days, either an LSP server or Tree-sitter can answer this question quickly and reliably.

The second component of the feature is that folded is a default state. It is not a fold method bodies action. It is a setting that ensures that, whenever you visit a new file, bodies are folded by default. To make this work, the editor should be smart to seamlessly unfold specific function when appropriate. For example, if you go to definition to a function, that function should get unfolded, while the surrounding code should remail folded.

Now that I have explained how the feature works, I will not try to motivate it. I think it is pretty obvious how awesome this actually is. Code is read more often than written, and this is one of the best multipliers for readability. Most of the code is in method bodies, but most important code is in function signatures. Folding bodies auto-magically hide the 80% of boring code, leaving the most important 20%. It was in 2018 when I last the IDE (IntelliJ) which has this implemented properly, and Ive been missing this function ever since!

You might also be wondering whether it is the same feature as the Outline, that special UI which shows a graphical, hierarchical table of contents of the file. It is true that outline and fold-bodies-by-default attack the same issue. But Id argue that folding solves it better. This is an instance of a common pattern. In a smart editor, it is often possible to implement any given feature either by lowering it to plain text, or by creating a dedicated GUI. And the lowering approach almost always wins, because it gets to re-use all existing functionality for free. For example, the folding approach trivially gives you an ability to move a bunch of functions from one impl block to the other by selecting them with Shift + Down, cutting with Ctrl + X and pasting with Ctrl + V.

Call to Action

So, if you are a committer to one of the editors, please consider adding a fold function bodies by default mode. It probably should be off by default, as it can easily scare new users away, but it should be there for power users to enable, and it should be prominently documented, so that people can learn that they want it. After the checkbox is in place, see if you can implement the actual logic! If your editor uses Tree-sitter, this should be relatively easy its syntax tree contains all the information you need. Just make sure that:

  • bodies are folded when the new file is opened,
  • the editor unfolds them when appropriate (generally, when navigated to a function from elsewhere).

If your editor is not based on Tree-sitter, youll have a harder time. In theory, the information should be readily available from the language server, but LSP currently doesnt expose it. Heres the problem:

https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#foldingRangeKind

Theres no body kind there! Adding it should be trivially technically, but it always is a pain to get something into the protocol if you are not VS Code.

My Role

What is my job here, besides sitting there and writing blog posts? I actually think that writing this down is quite valuable!

I suppose the feature is still commonly missing due to a two-sided market failure the feature doesnt exist, so prospective users dont realize that it is possible, and dont ask editors authors to implement it. Without users asking, editor authors themselves dont realize this feature could exist, and dont rush implementing it. This is exacerbated by the fact that it was a hard feature to implement ten years ago, when we didnt have Tree-sitter/LSP, so there are poor workarounds in place actions to fold a certain level. These workarounds the prevent the proper feature from gaining momentum.

So here I hope to maybe tip the equilibriums scale a bit, and start a feedback loop where more people realize that they want this feature, such that it is implemented in some of the more experimental editors, which hopefully would expose the feature to more users, popularizing it until it gets implemented everywhere!

Still, just talking isnt everything I did here! Six years ago, I implemented the language-server side of this in rust-analyzer:

https://github.com/rust-lang/rust-analyzer/commit/23b040962ff299feeef1f967bc2d5ba92b01c2bc

This currently isnt exposed to LSP, because it doesnt allow flagging a folding range as method body. To fix that I opened this VS Code issue (LSP generally avoids doing something before VS Code):

https://github.com/microsoft/vscode/issues/128912

And since then I have been quietly waiting for some editor (not necessary VS Code) to pick this up. This hasnt happened yet, hence this article!

Thanks for reading!