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.
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
executeskak 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.
Wow, thanks for the in-depth answer! that was super helpful
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)
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.