How can I substitute line numbers?

In vim, it is

%s/xxx/=printf(“xxx-%02d”, line(‘.’))/

In kakoune, how do you do it?

what exactly this commands does? I understand that this acts on a whole buffer replacing xxx with, I believe, xxx appended with line numbers after dash?

If so, you don’t need to do replacement. First select all you want to replace with %sxxx<ret>, then you can do: :exec -itersel "a-%val{cursor_line}" which will append number line after dash to each selection.

I usually use vim for renaming files. ranger uses vim for bulk-renaming.
I often type

%s/.*/\=printf("2019-12-05|cool cat|%02d.jpg", line('.'))/

The vim snippet didn’t work for me in vanilla vim, but I assume this is the kakoune equivelent:

%sxxx<ret>|printf "%s-%02d" $kak_selection $kak_cursor_line<ret>

That’s the key sequence you’d input from normal mode.

if I understand correctly, you want to assign an incrementing number to your cursors. You can use the # register for this, which simply contains the index of each selection. For example if you do "#P in normal mode with multiple cursors, it will paste the index before each selection.

How specifically can I replace each arbitrary line with “xxxxxx-%02d.jpg”?

I want to replace

sdfsdgsdg.jpg

sdfsd098729038749082734.jpg
lkhsadl;gkhas;dlkghasd23452345.jpg

with

2019-12-06|cool cat|01.jpg
2019-12-06|cool cat|02.jpg
2019-12-06|cool cat|03.jpg
2019-12-06|cool cat|04.jpg

In vim,

:%s/.*/\=printf("2019-12-06|cool cat|%02d.jpg", line('.'))/

does this.

%<a-s>|printf "2019-12-06|cool cat|%02d.jpg\n" $kak_cursor_line<ret>

where:

  • % - select whole buffer
  • <a-s> (alt s) - split selection to individual lines
  • | - pipe
  • printf "2019-12-06|cool cat|%02d.jpg\n" $kak_cursor_line - shell command printf with arguments
  • <ret> - confirm

or even better:

%<a-s>|printf "%s|cool cat|%02d.jpg\n" "$(date)" "$kak_cursor_line"<ret>

That works…

  • Which shell does kak use? Does it use user shell? $(date) is not correct in some shells.
  • Where is $kak_cursor_line documented?

Kakoune uses the system’s POSIX-compatible shell (the first sh executable in the directories named in the confstr(CS_PATH) path), or the executable named in $KAKOUNE_POSIX_SHELL, not the user shell.

Environment variables named like $kak_* are described in :doc expansions shell-expansions. That expansion in particular is the shell version of %val{cursor_line}, which is described in :doc expansions value-expansions.

How do I use selection indices instead of %val{cursor_line}?

%<a-s>Hc2019-12-06|cool cat|0.jpg<esc><a-f>."#P

where:

  • %<a-s> as before
  • H moves the end of each selection left by one character, so it doesn’t include the newline at the end of the line
    • this doesn’t work if you have any blank lines in your input, but you shouldn’t have any files with empty filenames
  • c deletes the contents of each selection, and puts you into insert mode.
  • 2019-12-06|cool cat|0.jpg<esc> is just typing the skeleton filename that we want to modify, then leaving insert mode
  • <a-f>. moves the cursor backwards until it sits on a .
  • "#P pastes the selection number before each cursor

"#P doesn’t make anything zero-padded, that’s why the above instructions manually type a 0 in insert mode - there’s only 4 items in your example, so they’re all going to have a 0. If you have more than 9 items (i.e. some lines will have 1 digit, others will have 2), you can reformat the numbers with printf afterward:

%<a-s>Hc2019-12-06|cool cat|.jpg<esc><a-f>."#Pb|printf %02d $kak_selection

where:

  • %<a-s>Hc as before
  • 2019-12-06|cool cat|.jpg<esc> is just typing, but this time we don’t bother typing a 0.
  • <a-f>."#P as before
  • bmoves the cursor back one word (i.e., selecting the numbers we just inserted)
  • |printf %02d $kak_selection replaces the contents of each selection with the output of the given shell command
    • the contents of the selection is also available on stdin, but printf doesn’t read from stdin, so it’s provided as an environment variable too
    • If you really want to process stdin, you could say |awk '{ printf "%02d", $1 }' instead

In general, this is more verbose than the Vim “big ol’ search-and-replace”, but the advantage of Kakoune for me is that the whole thing above is an interactive process, not a complex one-shot command. Where I’ve written <a-f>. what I would probably do in practice is just hit left-arrow a bunch of times until the cursor was in the right place, since I find it a lot easier to “tweak until it looks right” than memorise the relationships between f, t, <a-f> and <a-t>. Plus, if I make a mistake in one of those steps, I can just undo and try it again, I don’t have to go all the way back to the beginning of the process and start from scratch.

Why doesn’t

%s<a-s>|printf "%02d.jpg\n" $kak_(main_)reg_hash

work? It’s simpler.
I had a success with

%s<a-s>|echo<ret>i2019-12-06|cool cat|.jpg<esc><a-f>."#Pb|printf "%02d" $kak_selection

Note that you want %<a-s>, not %s<a-s> — there’s no “search within selection” step, you want all the selections.

The reason you can’t use $kak_reg_hash inside a | command is that the command receives the selection content on standard input. You might have seven lines selected, but you can’t have seven standard inputs, so instead Kakoune runs the command for each selection individually - and an individual selection is always selection number 1, because there’s only one selection.

It’s like the -itersel flag for the :evaluate-commands and :execute-keys commands - see :doc execeval.

It is

%<a-s>|echo<ret>i2019-12-06|cool cat|.jpg<esc><a-f>."#Pb|printf "%02d" $kak_selection

Can you think of a more concise way with hash register?

30 days late but I have figured out a pretty big brained alternative (if I do say so myself) which is a shorter, arguably a little more complicated but works for any line count.

%<a-s>|echo<ret>i2019-12-06|cool cat|.jpg<esc><a-f>.Z"#PGl&<a-z>us r0

How it works:

  • Z saves the current selection to make it easy to go back to (note this overrides existing Z unless you select a different register)
  • "#P works as before, pasting selection count
  • Gl (that’s a lower case L) selects to the end of the line
  • & aligns all of your cursors.
  • <a-z>u basically joins your saved cursor positions with your current ones so now all the <space> characters created by & are selected. There might be a way to do this without using Z at all.
  • s r0 select all spaces and replace with zeroes.

optionally you can add a space in the filename cat| .jpg if you always want the extra 0. then do an <a-f> for space rather than .

Edit - Since this works for any line count you should be able to pretty easily define a function that takes one argument (the filename) and performs this operation. But I still haven’t gotten around to learning kak plugins.

1 Like

Actually I was thinking about this backwards. It’s a lot simpler to do something like:

%<a-s>Z"#PX&<a-x>s r0zI2019-12-06|cool cat|<esc>A.jpg

where you handle the numbers first then prepend/append the rest

1 Like

I added an arbitrary integer to cursor line number and selection index with

  • $(($kak_cursor_line + num))
  • $(($kak_selection + num))

It is POSIX shell syntax.

I finally found a versatile solution.

If I had

01 - product - .jpg
01 - product - .jpg
01 - product - .jpg
01 - product - .jpg
01 - product - .jpg
01 - product - .jpg
01 - product - .jpg
..

I could do

%<a-s><a-f>.hZ"#pe&zlEs <ret>r0

to get

01 - product - 001.jpg
01 - product - 002.jpg
01 - product - 003.jpg
01 - product - 004.jpg
01 - product - 005.jpg
01 - product - 006.jpg
01 - product - 007.jpg
01 - product - 008.jpg
01 - product - 009.jpg
01 - product - 010.jpg
01 - product - 011.jpg
01 - product - 012.jpg
01 - product - 013.jpg
01 - product - 014.jpg
01 - product - 015.jpg
01 - product - 016.jpg
01 - product - 017.jpg
01 - product - 018.jpg
01 - product - 019.jpg
01 - product - 020.jpg
01 - product - 021.jpg
01 - product - 022.jpg
01 - product - 023.jpg
01 - product - 024.jpg
01 - product - 025.jpg
01 - product - 026.jpg
01 - product - 027.jpg
01 - product - 028.jpg
01 - product - 029.jpg
01 - product - 030.jpg
01 - product - 031.jpg
01 - product - 032.jpg
01 - product - 033.jpg
01 - product - 034.jpg
01 - product - 035.jpg
01 - product - 036.jpg
01 - product - 037.jpg
01 - product - 038.jpg
01 - product - 039.jpg
01 - product - 040.jpg
01 - product - 041.jpg
01 - product - 042.jpg
01 - product - 043.jpg
01 - product - 044.jpg
01 - product - 045.jpg
01 - product - 046.jpg
01 - product - 047.jpg
01 - product - 048.jpg
01 - product - 049.jpg
01 - product - 050.jpg
01 - product - 051.jpg
01 - product - 052.jpg
01 - product - 053.jpg
01 - product - 054.jpg
01 - product - 055.jpg
01 - product - 056.jpg
01 - product - 057.jpg
01 - product - 058.jpg
01 - product - 059.jpg
01 - product - 060.jpg
01 - product - 061.jpg
01 - product - 062.jpg
01 - product - 063.jpg
01 - product - 064.jpg
01 - product - 065.jpg
01 - product - 066.jpg
01 - product - 067.jpg
01 - product - 068.jpg
01 - product - 069.jpg
01 - product - 070.jpg
01 - product - 071.jpg
01 - product - 072.jpg
01 - product - 073.jpg
01 - product - 074.jpg
01 - product - 075.jpg
01 - product - 076.jpg
01 - product - 077.jpg
01 - product - 078.jpg
01 - product - 079.jpg
01 - product - 080.jpg
01 - product - 081.jpg
01 - product - 082.jpg
01 - product - 083.jpg
01 - product - 084.jpg
01 - product - 085.jpg
01 - product - 086.jpg
01 - product - 087.jpg
01 - product - 088.jpg
01 - product - 089.jpg
01 - product - 090.jpg
01 - product - 091.jpg
01 - product - 092.jpg
01 - product - 093.jpg
01 - product - 094.jpg
01 - product - 095.jpg
01 - product - 096.jpg
01 - product - 097.jpg
01 - product - 098.jpg
01 - product - 099.jpg
01 - product - 100.jpg
01 - product - 101.jpg
01 - product - 102.jpg
01 - product - 103.jpg
01 - product - 104.jpg
01 - product - 105.jpg
01 - product - 106.jpg
01 - product - 107.jpg
01 - product - 108.jpg
01 - product - 109.jpg
01 - product - 110.jpg

Nice, although it fails if the number of items is less than 10 because s <ret> selects nothing, fails, and you end up r0 everything.

If the number of items is less than 10, I would use a different key sequence.