Buffer order

At times I want to stack buffers in one kakoune window instead of opening multiple instances of kakoune in multiple windows. files a,b,c,d,e,f for example, but in some arbitrary order such as f, e, d, c, b, a
kak f e d c b a
opens at file “f”
however :bn advances to file “a” not “e”
another :bn advances to file “b” not “d”
:arrange-buffers f e d c b a
gives the desired :bn behaviour
even after :arrange-buffers :b still shows and tabs through the buffers in alpha order (including any leading directories)…

In my real case the files are in multiple directories with filenames that are not selected with alphabetical order in mind so there is no best way to sort them. I would like to sort them by last modified time or last accessed time instead of alphabetical. I might also want to sort alphabetically by filename ignoring leading directories. With kakoune being close to infinitely programmable, I’m pretty sure I can send the :arrange-buffers to kakoune from a script when starting the session, but is there any reason that kakoune is not respecting the order of buffers from the command parameters? As for ordering :b display/tabbing, I skimmed the hooks documentation page but pointers and sample code would be appreciated.

I suppose I could create a buffer with a name that sorts first in the alpha collation, populate it with b commands in my preferred order x e.g.
b f
b e
b d
b c
b b
b a
and then select the line then :c-r. to paste into the command window. This is a brute force replacement of :b There must be a better way…

I think :bn should work the way you want. If I launch the current trunk version of Kakoune with:

kak -n f e d c b a

…then it starts with the file f, and :bn takes me to file e. If your Kakoune behaves differently, you might be using an older version, or you might have some plugin that re-orders buffers?

As for the completions for :b, Kakoune’s completion engine sorts the available completions according to how closely they match the given input. So, given completions “buggy”, “ginseng” and “go-getter”, and the input “gg”, then the highest-ranked match is “go-getter” (letters at the beginning of words are ranked highly), then “buggy” (substrings are a medium rank) then “ginseng” (non-contiguous letters have a low rank). Alphabetical ordering is only used as a tie-breaker. Of course, when the input is empty (immediately after typing :b), that’s exactly what happens, so you see the results in alphabetical order.

As far as I know, there’s no way to re-order the initial completion results. Making your own “buffer switcher” buffer would work, although it would be convenient to add a <ret> hook to switch to the buffer under the cursor, instead of having to select the line and :<c-r>. every time.

Thanks! Yes :bn does work as expected - after :arrange-buffers.

I guess I have to once again concede that kakoune is probably correct to architect a ruthless separation between loading buffers - which can happen on the command line and manually during a session and switching between them. I.e. it’s probably good architecture for :b to ignore the order of command line file parameters. However, perhaps :b should heed :arrange-buffers.

I looked through the hooks again. Were you thinking of NormalKey/RawKey? I think that could work but I would probably have to restrict it to “buffer switcher” buffers to avoid unintended consequences. I may have a number of buffer switchers for various projects or *stdin* if I pipe it to kak at strartup so I’m not sure I want to track those names. Perhaps a hook into completion ordering?

Meanwhile I’ve created a global macro
map global user e ‘:.’ -docstring ‘execute selection as Kakoune command(s) delimited by ;’
that gets it down to 3 keystrokes. If the whole line is the command
map global user e ‘x:.’ -docstring ‘execute selection as Kakoune command(s) delimited by ;’
that’s 2 keystrokes

The macro will execute any command sequence. I’ve found it’s better to use e (for edit) which loads the file if not present and switches to it if present. Separating with ; allows for multiple commands. echo/nop allow for adding comments such as file description, last modified date etc.

The motivating background is that the kitty terminal emulator to my knowledge only allows stacking [kak] windows that occupy the whole terminal frame. The switch buffer makes it more convenient to split the kitty terminal frame and stack buffers in one kak window, leaving other kittty windows free.

p.s. Kakoune help via the :doc command already implements buffer loading/switching on enter, but restricted to the doc directories. If I get time, I’ll try and read the C++ code to find out how it’s done. It seems possible the << >> file link notation could easily extend to full regular filenames… I wonder why it wasn’t done that way in the first place…

To be clear, there’s only two orders:

  • the order of buffers for :bn and :bp, which is initialised from the order of files on the commandline, and can be adjusted by :arrange-buffers
  • the order of items in the buffer completion list, which is based on “closeness” to a query string

Yes, the :grep and :make plugins use hook buffer NormalKey <ret> %{ whatever... } to set up a custom behaviour for <ret> in those buffers. I think it would be more natural to use map buffer normal <ret> whatever... to make a buffer-specfic mapping rather than a hook, so that the new behaviour occurs instead of whatever the default might be, rather than in addition to it. I’m not sure why :grep and :make don’t do that.

You could hook BufCreate and BufClose, and automatically keep your buffer-picker up-to-date with whatever buffers you have open, rather than trying to maintain a separate buffer-list for every project you work on.

The :doc command is a Kakoune plugin like any other, it does not have any privileged access to Kakoune internals. Unlike :grep and :make, it does use map buffer normal <ret> ... rather than hook buffer NormalKey <ret> ...

That’s the standard AsciiDoc syntax for cross-references, and is a bit complicated because it keeps the “hyperlink target” separate from the “hyperlink text”, making it overkill for just pointing to files.

You might also be interested in the gfnormal-mode command (that is, g in normal mode enters the “goto” sub-mode, and f is a command in that sub-mode), which takes the current selection as a filename and tries to open it. A sequence like <a-i><a-w>gf might be a useful thing to have a mapping to.

Outstanding! Thanks for demystifying doc.kak. Interesting sample plugin code.

The tip on map buffer normal <ret> works for me!
For my simple buffer switcher:
map buffer normal <ret> x:<c-r>.<ret>
coupled with lines that look like
e somefilename; nop description of somefilename last date modified
allows me to hit enter to switch to somefilename.

Selecting multiple lines, opens multiple files at once.
gf will also open multiple files at once if run against multiple selections containing file names but it feels like more work to select multiple filenames than selecting multiple whole lines…

p.s. in my Kakoune v2022.10.31 :bn and :bp don’t respect the order of the kak command parameter list e.g. kak f e d c b a will open at buffer f but :bn goes to a and :bp goes to e. explicit :arrange-buffers is required to make :bn follow reverse alpha order. Perhaps :b should also respect the :arrange-buffers order instead of completing alphabetically. And when :b does filter buffers it should retain the :arrange-buffers order. However, I’m typically only working on a few files at a time and having the switch buffer should allow me to delete buffers because I know I can easily reload them.

I continue to be amazed at how programmable Kakoune is!

Glad to help!

Ah, it looks like that was fixed in commit 933e4a from December 2022. If you’re able to upgrade Kakoune to a more recent version (note that statically-linked builds for Linux/x86_64 are available from the GitHub Releases page), it should behave as you expect.

Thanks for the tip on the statically linked executables. It was straightforward to install in parallel with my existing version, which is how I like to migrate.

:bn and :bp do respect the order of the parameter list in v2025.06.03
:b still displays buffers in alphabetical order.

I can see value in viewing the buffers in alpha order so how about an enhancing :bn to display a completion list in :bn order from the current buffer and :bp to display a completion list in :bp order from the current buffer, exactly like :b does in alpha order. This will not add any keystrokes if you just want to move to the next or previous buffer, but it would give the current buffer order and allow for tabbing multiple steps?

I tend to write recipe files for my projects with various handy command snippets.
When the command snippets are related to Kakoune being able to easily select lines and execute them means I don’t have to create a separate .kak file for each snippet - there is a quoting issue where I have to enclose command strings in " and double any " that appear in the string.

Thanks again for all your help.

I don’t know how easy it would be to teach Kakoune to make a special ordering just for that command, but it would probably be convenient, yeah.

That’s how Kakoune’s double-quoted strings work. You might also want to try Kakoune’s %{} strings, which don’t require escaping as long as there’s only balanced pairs of {} inside the string:

info "string with {} curly brackets"
info %{string with {} curly brackets}

Glad to help!

I’ve opened feature request [REQUEST] upwardly harmonize :b :bn :bp · Issue #5361 · mawww/kakoune · GitHub to continue the discussion.

1 Like