kovidgoyal / kitty

Cross-platform, fast, feature-rich, GPU based terminal
https://sw.kovidgoyal.net/kitty/
GNU General Public License v3.0
23.85k stars 964 forks source link

can't figure out how to use --to/--listen-on #4825

Closed ckp95 closed 2 years ago

ckp95 commented 2 years ago

What I'm trying to do

Make a file searcher and launcher powered by kitty and fzf. It would launch a kitty window running a script that calls fzf, in which I search for a file, and then when I press enter, it launches the file using xdg-open. This would be invoked via a keyboard shortcut in my window manager, not from a pre-existing kitty window.

What I have so far

This works, when run from an existing kitty window:

#! /usr/bin/zsh

tmp=$(mktemp -d)
trap 'rm -rf $tmp' EXIT

mkdir "$tmp/done"

# the .{10} part in the sed filter is to ignore the ansi color escape codes
kitty @ launch --title "fzf-launcher" --type=os-window --no-response sh -c "fd --follow --color=always . $HOME/me/ | sed -E 's#^(.{10})$HOME#\1~#g' | fzf -e --layout=reverse --ansi | sed -E 's#^~#$HOME#g' >$tmp/stdout ; touch $tmp/done/1" > /dev/null 2> /tmp/kitty-error

inotifywait -q -e create "$tmp/done" >/dev/null
choice="$(< $tmp/stdout)"

if [[ ! -z "$choice" ]] then
  xdg-open "$choice"
fi

It is based on code found in issue #2440 .

The problem

However, when I try to bind this script to a shortcut in my window manager, it does not work. Nothing appears. When I inspect the error output sent to /tmp/kitty-error, it says:

Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/usr/bin/../lib/kitty/__main__.py", line 169, in <module>
    main()
  File "/usr/bin/../lib/kitty/__main__.py", line 165, in main
    func(sys.argv[1:])
  File "/usr/bin/../lib/kitty/__main__.py", line 22, in remote_control
    rc_main(args)
  File "/usr/bin/../lib/kitty/kitty/remote_control.py", line 242, in main
    response = do_io(global_opts.to, send, no_response, response_timeout)
  File "/usr/bin/../lib/kitty/kitty/remote_control.py", line 151, in do_io
    with io:
  File "/usr/bin/../lib/kitty/kitty/utils.py", line 463, in __enter__
    self.tty_fd, self.original_termios = open_tty(self.read_with_timeout)
OSError: Failed to open controlling terminal: /dev/tty (identified with ctermid()) with error: No such device or address

I searched for the error code and found this issue talking about something similar: #2426 . It says I need to:

Use the --to argument to kitty @ and a --listen-on to kitty to communicate via a dedicated socket instead.

But I don't understand how I'm meant to apply that to my problem. I only have a kitty @ invocation, there isn't a kitty on its own. I read the documentation at the end of here, which says:

Note that in the example’s above, kitty @ messaging works only when run inside a kitty window, not anywhere. But, within a kitty window it even works over SSH. If you want to control kitty from programs/scripts not running inside a kitty window, you have to implement a couple of extra steps. First start kitty as:

kitty -o allow_remote_control=yes --listen-on unix:/tmp/mykitty

The kitty --listen-on option tells kitty to listen for control messages at the specified path. See kitty --help for details. Now you can control this instance of kitty using the kitty @ --to command line argument to kitty @. For example:

kitty @ --to unix:/tmp/mykitty ls

Note that if all you want to do is run a single kitty “daemon” and have subsequent kitty invocations appear as new top-level windows, you can use the simpler kitty --single-instance option, see kitty --help for that.

So I tried to follow that and wrote this:

#! /usr/bin/zsh

tmp=$(mktemp -d)
trap 'rm -rf $tmp' EXIT

mkdir "$tmp/done"

kitty -o allow_remote_control=yes --listen-on "unix:$tmp/socket"

# the .{10} part in the sed filter is to ignore the ansi color escape codes
kitty @ --to "unix:$tmp/socket" launch --title "fzf-launcher" --type=os-window --no-response sh -c "fd --follow --color=always . $HOME/me/ | sed -E 's#^(.{10})$HOME#\1~#g' | fzf -e --layout=reverse --ansi | sed -E 's#^~#$HOME#g' >$tmp/stdout ; touch $tmp/done/1" > /dev/null 2> /tmp/kitty-error

inotifywait -q -e create "$tmp/done" >/dev/null
choice="$(< $tmp/stdout)"

if [[ ! -z "$choice" ]] then
  xdg-open "$choice"
fi

But this didn't work either. When launched from the keyboard shortcut, a kitty window appears but with nothing running in it. The error file reads:

Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/usr/bin/../lib/kitty/__main__.py", line 169, in <module>
    main()
  File "/usr/bin/../lib/kitty/__main__.py", line 165, in main
    func(sys.argv[1:])
  File "/usr/bin/../lib/kitty/__main__.py", line 22, in remote_control
    rc_main(args)
  File "/usr/bin/../lib/kitty/kitty/remote_control.py", line 242, in main
    response = do_io(global_opts.to, send, no_response, response_timeout)
  File "/usr/bin/../lib/kitty/kitty/remote_control.py", line 151, in do_io
    with io:
  File "/usr/bin/../lib/kitty/kitty/remote_control.py", line 98, in __enter__
    self.socket.connect(self.address)
FileNotFoundError: [Errno 2] No such file or directory

I don't understand what I'm supposed to do. What am I doing wrong?

page-down commented 2 years ago

Why not just run it through kitty? If window manager supports running GUI programs, then just run a new kitty process directly.

Write a script, fd to fzf, get the selected item and call xdg open.

keyboard shortcut -> kitty /path/to/my-launcher.zsh

ckp95 commented 2 years ago

That creates two windows, a blank one (I assume that's the "controlling" window?) and the one with fzf inside it. I just want the fzf window.

page-down commented 2 years ago

There is no such thing as a control window. For example, run kitty --config=NONE vim in the terminal and try it.

ckp95 commented 2 years ago

For example, run kitty --config=NONE vim in the terminal and try it.

I don't understand what point you're making.

page-down commented 2 years ago

https://sw.kovidgoyal.net/kitty/invocation/

When running the executable with kitty parameters, only a new process and an OS window will be opened. (No session configuration)

https://sw.kovidgoyal.net/kitty/remote-control/

If you want to use remote control. There has to be a kitty process already running, listening to the socket, and then sending commands to this already running process via remote commands.

In your script, the first kitty command will run at least one blank window and will not exit.

You need to make sure that kitty is running and that a unix socket exists when you use kitty @ --to to send remote commands .

ckp95 commented 2 years ago

I still don't get it. If kitty has to be already running, then that means there will be two windows opened when I run the keyboard shortcut. I don't want two windows, I just want one.

ckp95 commented 2 years ago

Okay it turns out I was overcomplicating this. I don't even need to use the remote control feature at all. All I have to do is bind a keyboard shortcut to:

#! /usr/bin/zsh

tmp=$(mktemp -d)
trap 'rm -rf $tmp' EXIT

kitty sh -c "fd --follow --color=always . $HOME/me/ | sed -E 's#^(.{10})$HOME#\1~#g' | fzf -e --layout=reverse --ansi | sed -E 's#^~#$HOME#g' >$tmp/stdout"

choice="$(< $tmp/stdout)"

if [[ ! -z $choice ]] then
  xdg-open $choice
fi

Is this what you meant before with your vim example?

page-down commented 2 years ago

Is this what you meant before with your vim example?

Yes, maybe it could be a bit simpler, without the need for temporary file.