With header files don’t you have to write all your type signatures and type definitions twice? I hated them when I worked with OCaml.
It makes more sense to just implement the described feature in IDEs/editors, instead of making every programmer copy/paste their types/signatures to a separate file.
Dunno about OCaml, but in C public types go in the header, private types in the implementation, so all that gets duplicated is the function prototypes.
It might be nice to allow function definitions to be abbreviated, so the types don’t have to be repeated, but on the other hand it might be bad for the full prototype to be so far from the body. On the gripping hand, I usually have both files open so that I can make sure the implementation and documentation match.
But my prehensile tail points out that having the documentation, type signature, and body right next to each other in one file is a lot more convenient, and rustdoc does a fine job of pulling out and presenting just the public interface.
Yes, header files can totally serve this purpose. They provide a nice overview of what’s the public interface of a module.
And, in the spirit of improving UX (which is what this post is about), i think it would be crucial to have seamless integration between header files and implementation files. E.g., it should be trivial to toggle between them; if i “go to definition”, the definition on the implementation file should be open; if i edit the signature of a function in the implementation file, the change should be made in the header file automatically; etc.
But, if we had all this, then the header file would become almost a “projection” of the implementation file. In practical terms, it’d be almost a modified view of the same source code. Something that could be entirely derived, but for some reason still exists as a separate source file.
I.e., header files with good UX would be something very very similar to the feature this post is proposing; minus the need for duplicated information in two different files :)
As @fanf mentions, the article of which we’re talking touches on this. But, if this is a genuine question(*), i also commented on why the article’s proposal is IMO superior to an “outline” view elsewhere on this discussion :)
*: I initially read it as a kind of slight, “don’t you know this has been a common thing for decades?”, but you probably didn’t mean it that way. Or at least i hope so! hehe
I don’t understand, the post doesn’t mention at all the IDE’s existing “outline” feature which already does everything mentioned here. Like when I open a code file, I have a separate panel which tells me all the methods in a file with their parameters, etc. and this has worked pretty much in every IDE I’ve ever worked in. e.g. this : https://ibb.co/48nXwn4 ; this was already a thing in dev-c++ in 2005.
Header files have the documentation and the complete public types. That outline looks fine for navigating a source file, but it isn’t a substitute for a header or for Matklad’s folded view.
But, if we had all this, then the header file would become almost a “projection” of the implementation file. In practical terms, it’d be almost a modified view of the same source code. Something that could be entirely derived, but for some reason still exists as a separate source file.
Ideally, (part of) the implementation would be a projection of the header, because you really want the interface to be primary. And no, I have no idea how to implement that, at least not one that’s also in any way reasonable.
(One company that I worked at did automatic header generation as a matter of course. It worked. It was…hmm…let’s just say I adopted many of the habits and practices from there, but not that one)
Yes. It’s good that languages are less redundant nowadays, but we definitely lost some nice ergonomic and information-hiding aspects of headers.
When I was working in C# back in the 00s, I invented a “header file” format for C# (basically the public/protected class and function declarations with no bodies) and made a little tool that generated it from a DLL.
I think we did have Intellisense in Visual Studio back then, but that just shows one method at a time, whereas this let you see the full picture of a library (or your own code).
My main problem with header files is that any refactor that involves changing a function’s signature requires changing it in two places, which is annoying.
You are hereby challenged to explain exactly how to achieve folding of function bodies in vanilla vim. I am 0.7 sure that this isn’t actually possible without what amounts to writing your own regex-based mini parser, but I’d love to be proven wrong.
(Though, as with many things in the vast space of possibilities, it’s be useful if this incantation had a dedicated name such that people could start to even consider if they need it)
I’m not sure how precisely you want to fold function bodies vs other long noisy top-level constructs (structs, macro_rules), but if you’re satisfied with a 95% solution then vanilla vim has this:
Obviously the color scheme is quite a bit more Dwarf Fortress -ish than the nicely shaded screenshot in the blog, but that’s part of the charm of an ancient CLI tool.
No, level-based folding is not enough. It will incorrectly not fold any top-level functions, and it will incorrectly fold any inline modules, as far as I understand.
OTOH the jetbrains IDEs have both, you have an outline (the “structure” pane) and you can configure the IDE to auto-fold various constructs in the editor.
Another great feature, which has shown up in at least a few editors, addresses the reverse of the article’s problem: Given some code I’ve found, what is its context? I’m referring to sticky headers for the enclosing scopes of the topmost line. I’d like to see this feature available everywhere, and I’m curious where it first appeared. I first saw it in an Xcode beta. VS Code added it later that summer.
I love the audacity of writing “I will not try to motivate it. I think it is pretty obvious how awesome this actually is.”
And I agree – this is self-evidently useful. I like “automatically fold all imports”, which is now the default behavior in a lot of IDEs. I don’t necessarily think this mode should be the default, but if it were at least an OPTION that would be fantastic.
I really like the idea presented in this article. And i especially like how the author’s main argument is presented visually: it’s undeniable that the second screenshot has much more information condensed into it, and would be a much better default when navigating to modules/struct definitions.
I also think the arguments in favor of this feature over the “Outline” view are understated. Simply put: us programmers are used to reading source code in our editors, so presenting the outline of a module in the same format just makes sense. It has the same syntax highlighting we’re used to. We can do all the things we normally do, like using a shortcut when the cursor is over a type (e.g. a function argument) to go to it’s definition, or just edit something there right away, because it is the source code! Thinks that the separate and custom “Outline” view of IDEs usually don’t provide.
I also think the arguments in favor of this feature over the “Outline” view are understated.
Thanks for noticing this <3
Though, getting programmers to re-discover text files in between text streams and GUIs is not a mission I am quite ready to push right now. Can’t stop thinking about that it anyway:
I think I disagree with you on this. There’s nothing about the emacs model of text + ranges mapping to attributes that requires fixed width or a grid. Your posts hang together equally well if one assumes proportional fonts.
This is not a big deal (I don’t care that much about proportional fonts), just adds some noise to a nice mental model. But perhaps I’m missing something.
The 2D grid isn’t how the text looks on screen. Even if a line is wrapping across multiple screen lines it’s still conceptually a single line. The width of characters in pixels doesn’t matter.
TBH, I don’t care for it. I have been dealing with “big code” problems for the past few years and have long ditched relying on visual cues/anchors to navigate around. My workflow is either:
I have a stack trace with the exact line of code in a function. I can navigate there directly when opening a file.
Or I have some clue of what I am looking for and use some type of search to find references to that clue. Then I iterate through the references until I get to where I need to be. This could be regex search, or code intel (LSP, tree-sitter) searches, or ctags, etc..
This helped me narrow down the range of code I wanted to see much faster and better than relying on a folded function context. Historically, I have seen the folded functions to be misleading as well because their names could be out of date versus the actual implementation due to over-time scope creep.
Zed almost supports this functionality, i.e. you can have everything folded by default, and fold/unfold recursively to expand specific functions or whatever. But:
You can’t fold just function bodies, it’s basically fold everything by default or nothing by default. This is my biggest beef.
Go to definition doesn’t unfold, which is a bit surprising, but would be easy to add yourself via Zed’s key bindings (i.e. have your GTD binding perform both actions).
Folding everything recursively folds every block down to the smallest `if``, which I find to be useless, I almost always only want to fold top-level items, and if I want to fold a large block in a function, it’s always ad-hoc. I wish the feature was more discriminate with how it folds.
None of this is specific to Zed, but seems like getting to your proposed end state would actually be pretty straightforward since the “fold everything” infra is already there. Hopefully someone a bit more keen on implementing this than I takes a crack at it!
If I want to see the “structure of the source code file”, I use a necessary IDE option. Intellij/CLion has that, VSCode as well, not sure about RustRover. It basically shows the same thing as the “collapsed” version of author’s source code file. But it does it in a popup window, with fuzzy search. I click ‘enter’ on an interesting entry and it navigates me to the uncollapsed version of the function in the editor window.
The feature you describe is what the article meant by “the Outline, that special UI which shows a graphical, hierarchical table of contents of the file.” The IntelliJ family of IDEs calls it the Structure tool window.
So header files aren’t a bad idea after all?
Header files are the best thing ever! I wish so hard that Rust kept .crate files (the old ones, like .mli, not the Cargo tarballs).
With header files don’t you have to write all your type signatures and type definitions twice? I hated them when I worked with OCaml.
It makes more sense to just implement the described feature in IDEs/editors, instead of making every programmer copy/paste their types/signatures to a separate file.
Dunno about OCaml, but in C public types go in the header, private types in the implementation, so all that gets duplicated is the function prototypes.
It might be nice to allow function definitions to be abbreviated, so the types don’t have to be repeated, but on the other hand it might be bad for the full prototype to be so far from the body. On the gripping hand, I usually have both files open so that I can make sure the implementation and documentation match.
But my prehensile tail points out that having the documentation, type signature, and body right next to each other in one file is a lot more convenient, and rustdoc does a fine job of pulling out and presenting just the public interface.
I just went full-circle thinking about this.
Yes, header files can totally serve this purpose. They provide a nice overview of what’s the public interface of a module.
And, in the spirit of improving UX (which is what this post is about), i think it would be crucial to have seamless integration between header files and implementation files. E.g., it should be trivial to toggle between them; if i “go to definition”, the definition on the implementation file should be open; if i edit the signature of a function in the implementation file, the change should be made in the header file automatically; etc.
But, if we had all this, then the header file would become almost a “projection” of the implementation file. In practical terms, it’d be almost a modified view of the same source code. Something that could be entirely derived, but for some reason still exists as a separate source file.
I.e., header files with good UX would be something very very similar to the feature this post is proposing; minus the need for duplicated information in two different files :)
Why would you need header files when all the IDEs since 30 years have an “outline” feature?
As @fanf mentions, the article of which we’re talking touches on this. But, if this is a genuine question(*), i also commented on why the article’s proposal is IMO superior to an “outline” view elsewhere on this discussion :)
*: I initially read it as a kind of slight, “don’t you know this has been a common thing for decades?”, but you probably didn’t mean it that way. Or at least i hope so! hehe
I read a great blog post earlier which explains that IDEs lack the right kind of outlining.
I don’t understand, the post doesn’t mention at all the IDE’s existing “outline” feature which already does everything mentioned here. Like when I open a code file, I have a separate panel which tells me all the methods in a file with their parameters, etc. and this has worked pretty much in every IDE I’ve ever worked in. e.g. this : https://ibb.co/48nXwn4 ; this was already a thing in dev-c++ in 2005.
Header files have the documentation and the complete public types. That outline looks fine for navigating a source file, but it isn’t a substitute for a header or for Matklad’s folded view.
Ideally, (part of) the implementation would be a projection of the header, because you really want the interface to be primary. And no, I have no idea how to implement that, at least not one that’s also in any way reasonable.
(One company that I worked at did automatic header generation as a matter of course. It worked. It was…hmm…let’s just say I adopted many of the habits and practices from there, but not that one)
Yeah, I think that every modern language server/IDE has supported seamless navigation between header and source files like this for 10+ years 😅
Header files should be auto-generated. The painful thing about headers is having to make changes in two places.
For example, Xcode displays auto-generated “headers” of Swift system frameworks.
We used to generate ObjC headers all the time. It has upsides and downsides.
The upside is obviously less duplication.
However, the downsides are also significant, because you have the implementation driving the interface.
Yes. It’s good that languages are less redundant nowadays, but we definitely lost some nice ergonomic and information-hiding aspects of headers.
When I was working in C# back in the 00s, I invented a “header file” format for C# (basically the public/protected class and function declarations with no bodies) and made a little tool that generated it from a DLL.
I think we did have Intellisense in Visual Studio back then, but that just shows one method at a time, whereas this let you see the full picture of a library (or your own code).
My main problem with header files is that any refactor that involves changing a function’s signature requires changing it in two places, which is annoying.
Even better - Pascal’s interfaces ;)
Though it’s still tangential to what the author is asking for, i.e. overally easier file navigation, which I 100% agree with.
At least in VSCode I can fold only specific level, which works most of the time.
I always liked header files for this reason. It provides an overview of what you can do with a module.
[Comment removed by author]
The KDE editors Kwrite/Kate/Kdevelop have it.
When writing Go, I would often start a local Godoc server (https://pkg.go.dev/golang.org/x/tools/cmd/godoc) for very similar reasons. It only shows exported (public) symbols though
I’m curious to know if there’s a vim plugin that does this.
I don’t think it needs a plugin. The built-in folding configuration options should do it. See
:help fold-foldtext
. 🙂You are hereby challenged to explain exactly how to achieve folding of function bodies in vanilla vim. I am 0.7 sure that this isn’t actually possible without what amounts to writing your own regex-based mini parser, but I’d love to be proven wrong.
It is possible in neovim with tree sitter:
https://old.reddit.com/r/neovim/comments/1g41rjy/can_neovim_do_this_already_with_treesitter/ls0cf4b/
(Though, as with many things in the vast space of possibilities, it’s be useful if this incantation had a dedicated name such that people could start to even consider if they need it)
I’m not sure how precisely you want to fold function bodies vs other long noisy top-level constructs (structs, macro_rules), but if you’re satisfied with a 95% solution then vanilla vim has this:
Screenshot: https://i.imgur.com/Q5XwLJx.png
Obviously the color scheme is quite a bit more Dwarf Fortress -ish than the nicely shaded screenshot in the blog, but that’s part of the charm of an ancient CLI tool.
No, level-based folding is not enough. It will incorrectly not fold any top-level functions, and it will incorrectly fold any inline modules, as far as I understand.
VSCode (and many other editors/IDEs) usually have an Outline that serves this role: https://code.visualstudio.com/docs/getstarted/userinterface#_outline-view
I’m not against adding this feature directly to the code editors instead of a separate panel, but at least there’s this option in the mean time.
OTOH the jetbrains IDEs have both, you have an outline (the “structure” pane) and you can configure the IDE to auto-fold various constructs in the editor.
Would love to have this in helix! currently use
<space>s
as a substituteOh! Thanks for reminding me of this one. It actually is not half bad for getting an overview of a large file :)
Another great feature, which has shown up in at least a few editors, addresses the reverse of the article’s problem: Given some code I’ve found, what is its context? I’m referring to sticky headers for the enclosing scopes of the topmost line. I’d like to see this feature available everywhere, and I’m curious where it first appeared. I first saw it in an Xcode beta. VS Code added it later that summer.
There is an answer for this in neovim reddit here
Based on this same post itself.
I love the audacity of writing “I will not try to motivate it. I think it is pretty obvious how awesome this actually is.”
And I agree – this is self-evidently useful. I like “automatically fold all imports”, which is now the default behavior in a lot of IDEs. I don’t necessarily think this mode should be the default, but if it were at least an OPTION that would be fantastic.
I’d definitely use this if it was available in my editor.
I really like the idea presented in this article. And i especially like how the author’s main argument is presented visually: it’s undeniable that the second screenshot has much more information condensed into it, and would be a much better default when navigating to modules/struct definitions.
I also think the arguments in favor of this feature over the “Outline” view are understated. Simply put: us programmers are used to reading source code in our editors, so presenting the outline of a module in the same format just makes sense. It has the same syntax highlighting we’re used to. We can do all the things we normally do, like using a shortcut when the cursor is over a type (e.g. a function argument) to go to it’s definition, or just edit something there right away, because it is the source code! Thinks that the separate and custom “Outline” view of IDEs usually don’t provide.
Thanks for noticing this <3
Though, getting programmers to re-discover text files in between text streams and GUIs is not a mission I am quite ready to push right now. Can’t stop thinking about that it anyway:
Come check out BABLR!! You’re not the only one diving down into what it looks like to build a new narrow waist for code editors: https://github.com/bablr-lang/ https://discord.gg/NfMNyYN6cX
From the first link:
Do you care about proportional fonts, or do you mean ‘grid’ literally here?
Literally: y coordinate is a line, x coordinate is a visual character in the line.
This is mostly orthogonal to proportional fonts: eMacs is mostly monospaced, but can do proportional in a pinch.
I think I disagree with you on this. There’s nothing about the emacs model of text + ranges mapping to attributes that requires fixed width or a grid. Your posts hang together equally well if one assumes proportional fonts.
This is not a big deal (I don’t care that much about proportional fonts), just adds some noise to a nice mental model. But perhaps I’m missing something.
Oh I think I made sense of what you’re saying.
The 2D grid isn’t how the text looks on screen. Even if a line is wrapping across multiple screen lines it’s still conceptually a single line. The width of characters in pixels doesn’t matter.
I agree with this.
TBH, I don’t care for it. I have been dealing with “big code” problems for the past few years and have long ditched relying on visual cues/anchors to navigate around. My workflow is either:
I have a stack trace with the exact line of code in a function. I can navigate there directly when opening a file.
Or I have some clue of what I am looking for and use some type of search to find references to that clue. Then I iterate through the references until I get to where I need to be. This could be regex search, or code intel (LSP, tree-sitter) searches, or ctags, etc..
This helped me narrow down the range of code I wanted to see much faster and better than relying on a folded function context. Historically, I have seen the folded functions to be misleading as well because their names could be out of date versus the actual implementation due to over-time scope creep.
Zed almost supports this functionality, i.e. you can have everything folded by default, and fold/unfold recursively to expand specific functions or whatever. But:
None of this is specific to Zed, but seems like getting to your proposed end state would actually be pretty straightforward since the “fold everything” infra is already there. Hopefully someone a bit more keen on implementing this than I takes a crack at it!
Hmm, maybe this could work with Sublime’s RustEnhanced function.
[Comment removed by author]
I use
foldmethod=indent
andfoldnestmax=1
in vim, but it’s for C where the function bodies are at top-level and not nested in animpl
block.If I want to see the “structure of the source code file”, I use a necessary IDE option. Intellij/CLion has that, VSCode as well, not sure about RustRover. It basically shows the same thing as the “collapsed” version of author’s source code file. But it does it in a popup window, with fuzzy search. I click ‘enter’ on an interesting entry and it navigates me to the uncollapsed version of the function in the editor window.
The feature you describe is what the article meant by “the Outline, that special UI which shows a graphical, hierarchical table of contents of the file.” The IntelliJ family of IDEs calls it the Structure tool window.
Xcode used to do code folding, and I think you could choose what the default state was.
It seemed like it would be useful, but it turned out to be meh at best. In fact, it might still be available somewhere, I wouldn’t know.
The folding features are still there. I didn’t see a fold by default setting though.