Opening files with pipes

kak example.txt opens example.txt
but why doesn’t echo "example.txt" | xargs kak
do the same thing? I just get a window that says it’s reading the *stdin* buffer.

It does open it, but also creates a scratch buffer that is holding the input and shows it. I guess the reason may be that the input is not coming from a terminal.

1 Like

What useredsa says is correct, but here’s a bit more detail.

You can load a file into Kakoune:

kak example.txt

…but you can also pipe text into it:

cat example.txt | kak

When you pipe text into Kakoune, it doesn’t have a filename, so it calls the buffer *stdin*.

But a Unix process like Kakoune always has a stdin, how does it know whether to create a special buffer for it or not?

There’s a Unix standard library function called isatty() which tells you whether a particular file handle (in our case, stdin) “is a teletype” or other compatible brand of terminal. When Kakoune starts up, if stdin is not a terminal, it creates a new buffer named *stdin* and slurps the input into it.

There’s one final wrinkle: In the example you give, you’re trying to load files on the command-line (via xargs), you’re not trying to pipe data into Kakoune, so why is it reading stdin?

The command you wrote works like this:

  • your shell creates a pipe
  • the shell creates a new sub-process whose stdout is connected to the write-end of the pipe
  • in that sub-process, the shell executes echo example.txt
  • the shell creates a new sub-process whose stdin is connected to the read-end of the pipe
  • in that sub-process, the shell executes xargs kak
  • xargs runs and slurps all the data from stdin into memory
  • xargs creates a new sub-process, which (as is tradition) inherits its stdin from the parent process; that is, the stdin of the new sub-process is the (now empty) pipe
  • In that sub-process, xargs executes kak example.txt
  • kak runs and detects that its stdin is not a terminal, so it creates a *stdin* buffer
  • kak loads all the other files on the command-line into buffers
  • kak notices its stdin is empty, so it converts the *stdin* buffer from a FIFO buffer to a scratch buffer.

TL;DR: Running Kakoune inside xargs behaves differently because Kakoune inherits the now-empty stdin pipe that was used to feed xargs, and tries to read it again.

8 Likes

Wow, thanks for the in-depth answer! that was super helpful :slightly_smiling_face:

How do you recommend I open a file whose filename is the result of another command?

I can think of

filename=$(ls | fzf)
kak "${filename}"

But are there other ways? I’m particularly interested in one-line solutions like

ls | fzf | xargs kak

(if that one actually worked the way I expected it to)

You pretty much have it.

kak $(fzf)
1 Like

With fzf keybindings sourced for your shell (bash here) you can press <c-t> to open fzf, pick a file and the filename will be pasted at the readline cursor.