I came from jEdit which has folding. I have one report that uses folding that I still have to run in jEdit. I’m now so entrenched in Kakoune that jEdit is painful to run so I finally hacked some code to implement rudimentary “folding” in Kakoune. The jEdit folding was static in that it only folded and unfolded lines without modifying the underlying folded lines. The folded lines index the non-folded portion of the file and I had written jEdit macros to jump from the index to the non-folded portion of the file.
To simulate this in Kakoune I created a scratch buffer and wrote a number of short awk scripts to populate the scratch buffer with the initial fully folded view and to get additional lines where I want to drill down. The awk scripts directly read the report file not a Kakoune buffer. I ended up modifying the underlying report to add line numbers into the text of the file to be folded to link lines in the scratch buffer with the underlying file. It’s not a slick as jEdit, but it should get me off jEdit. Kakoune is so programmable I expect to be able to eventually improve the solution beyond jEdit.
This triggered some more generic thoughts on the Kakoune folding problem. I used a scratch buffer for folding, I didn’t attempt to do it in the buffer for the report file itself. How about a new type of buffer in Kakoune explicitly designed to support folding? The folding buffer would be linked to a normal file buffer. The user would write a script to populate the folding buffer with a subset of the lines in the underlying file buffer, but Kakoune would retain the line numbers of the underlying file buffer without having to hack line numbers into the file contents. Also it would be nice if Kakoune could automatically track the folded lines. It would be nice if Kakoune would reflect edits in the folded buffer back into the file buffer. I think it could be done vice versa as well. I admit that inserting a new line in the folded buffer might be difficult to define - i.e. where exactly does one insert a new line in or beside other folded lines. Folded (hidden) lines - would simply not be present in the folded buffer unless explicitly pulled in and not subject to change through global selection.
As best I understand Mawww’s main issue with folding is the tight coupling between the buffer and the file. Just maybe an additional type of buffer will break through this barrier or at least trigger some thoughts to enable folding. This could be implemented in stages. I.e. starting with no updates/synchronization either direction between the folding buffer and underlying file buffers, adding synchronization from the folding to the file buffer etc.
In the spirit of orthogonality perhaps folding could/should be done in front of Kakoune in a folding file system. It would give the user the ultimate fine grained control over folding. I’m not an expert on Linux virtual filesystems so I don’t know if it would require reopening the virtual file to change a fold…
I believe I have a proof of concept solution to folding as long as you can live with the folded (hidden) lines NOT present in the folded buffer. Sample code: code folding · Issue #453 · mawww/kakoune · GitHub
You could try using the same approach kakoune focus and use replace-ranges. I’m not an expert, however I believe you could use it to visually replace the folded region with whatever header you wish to use instead. I do however not know how well this will play with navigating over the fold.
Anyways, I’d be happy to have a try at writing such a plugin after Christmas.
When the command update-option is used on an option of this type,
its ranges get updated according to all the buffer modifications
that happened since its timestamp.
This demonstrates navigating over the fold behaviour - if any cursor is on the fold it will expand which I guess I can live with…
I can’t figure out any simple keystrokes to select the face text to tell my script how to drill further, but a script could use %val{selections_desc} to find out where it is. The best I can find to get the range specs is :debug options which dumps the ranges along with all sorts of other info to the debug buffer. The script should be able to check the range specs for the line it is on and use that to drill further, i.e. to further unfold lines if folded. GitHub - caksoylar/kakoune-focus: Focus on your selections, remove distractions may have some guidance. Perhaps there is an %opt{} that gives ranges…
I did manage to somehow get the face text into the actual buffer - I think I inserted a line then deleted a line containing range-replace text, so it may be a bit fragile. colouring the fold lines might help. Removing the highlighter removes the folding which is an important part of the solution.
Hello again! I finally got around to doing this, so here is my implementation. Most of it is just ideas taken from kakoune-focus.
# user config options
declare-option str fold_marker
set-option global fold_marker "{Whitespace} -- fold --"
declare-option range-specs fold_range # formated for replace-ranges
declare-option str-list fold_selection # all fold selections
define-command fold %{
execute-keys <">fZ
set-option buffer fold_selection %reg{f}
# loop over all selections and add them
# code from kakoune-focus / focus.kak, thanks <3
set-option buffer fold_range %val{timestamp} "%val{selection_desc}|%opt{fold_marker}"
try %{
execute-keys <a-,>
evaluate-commands -itersel %{
set-option -add buffer fold_range "%val{selection_desc}|%opt{fold_marker}"
}
}
# there might be somthing like update-highlighter?
remove-highlighter buffer/replace-ranges_fold_range
add-highlighter buffer/ replace-ranges fold_range
}
define-command fold_extend %{
try %{
execute-keys <">fZ # save current selection
set-register p %opt{fold_selection} # move other folds to p
execute-keys <">pz # load p
execute-keys <">f<a-z>a <a-_> # unite
# this code ↑ was also from kakoune-focus :)
}
# fold the new selection
fold
}
define-command unfold %{
# remove the fold highlighter, simple
remove-highlighter buffer/replace-ranges_fold_range
}
in addition to this i have the following in my kakrc
set-option global fold_marker "{Whitespace} --- fold --- "
declare-user-mode fold
map global user F ":enter-user-mode fold<ret>" -docstring "fold"
map global fold l "xH:fold_extend<ret>" -docstring "fold line"
map global fold L "xH:fold<ret>" -docstring "replace folds with line"
map global fold f ":fold_extend<ret>" -docstring "fold"
map global fold F ":fold<ret>" -docstring "replace folds"
map global fold d ":unfold<ret>" -docstring "unfold"
This works quite well, the only thing that bothers me is that it can’t handle nested folds. I think it’s because it at one point selects all folds, which eliminates any nested folds. But even if we could circumvent that I don’t know if kakoune can handle nested replace-ranges. If not it would be quite a hassle to support that.
Have a great day!
EDIT: Just after I posted the above and started using the thing i quickly got tiered of selecting blocks and folding them. So I added the following two bindings for { blocks } and js functions.
map global fold j "Z%%sfunction<ret>j<a-i>}:fold_extend<ret>z" -docstring "fold all js functions"
map global fold } "Z%%s\}<ret><a-i>}:fold_extend<ret>z" -docstring "fold top level blocks"