jktr / matplotlib-backend-kitty

show matplotlib plots directly in your kitty terminal
Creative Commons Zero v1.0 Universal
137 stars 16 forks source link

Make the backend work inside a Docker container #11

Open ayorgo opened 1 year ago

ayorgo commented 1 year ago

This addresses https://github.com/jktr/matplotlib-backend-kitty/issues/10 by using kitty's low level graphics protocol.

The main challenge was to get the window dimensions in pixels as described here which was solved with the help of this SO answer.

kovidgoyal commented 1 year ago

You dont need to use an escape code to get the size, use the example code from the graphics protocol docs:

import array, fcntl, sys, termios
buf = array.array('H', [0, 0, 0, 0])
fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)
print((
    'number of rows: {} number of columns: {}'
    'screen width: {} screen height: {}').format(*buf))

This code is what icat uses as well, so if icat worked so will this.

ayorgo commented 1 year ago

Thanks for the feedback and the amazing terminal emulator @kovidgoyal. The recipe didn't quite work for me inside a Docker container sadly. It manages to get rows and columns just right but the height and width in pixels are both zeros despite me having specified -e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix as well as -v /usr/lib/kitty/terminfo/x:/root/.terminfo/x although I'm not particularly happy with forcing people to install kitty itself inside containers. The escape code on the other hand works quite well both inside and outside of a container.

kovidgoyal commented 1 year ago

On Fri, Aug 25, 2023 at 01:26:39AM -0700, ayorgo wrote:

Thanks for the feedback @kovidgoyal. The recipe didn't quite work for me inside a Docker container sadly. It manages to get rows and columns just right but the height and width in pixels are both zeros despite me having specified -e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix as well as -v /usr/lib/kitty/terminfo/x:/root/.terminfo/x although I'm not particularly happy with forcing people to install kitty itself inside containers. The escape code on the other hand works quite well both inside and outside of a container.

SSH into your container and it will work. I am guessing that the container runtime's PTY implementation does not fill in the pixel fields of the wininfo struct.

Note you dont need to install kitty inside the container, all you need is the kitten standalone executable which is available as a statically compiled binary for all unix like operating systems. Again if you SSH into your container using the ssh kitten it will actually be automatically made available inside the container no need to even install that single binary file.

ayorgo commented 1 year ago

SSH into your container and it will work.

Fair enough although that requires some extra steps like opening the ssh port, having the ssh server installed and configured inside the container, a firewall properly setup, then running the ssh command itself with some parameters.

While technically viable I'd argue that it isn't the simplest solution for a lay person like e.g. myself (and some of my data science colleagues as well) whereas the proposed solution with the escape code while a bit cumbersome to implement works straight away without any extra steps.

kovidgoyal commented 1 year ago

Well, the correct solution is of course, to get docker to fill in the winsize struct properly in their pseudo terminal implementation. Then you wont have to jump through these hoops. In the meantime, I suggest using the ioctl first and falling back to the escape code only if it returns zero. That way people not running inside docker dont pay the price.

ayorgo commented 1 year ago

Well, the correct solution is of course, to get docker to fill in the winsize struct properly in their pseudo terminal implementation. Then you wont have to jump through these hoops. In the meantime, I suggest using the ioctl first and falling back to the escape code only if it returns zero. That way people not running inside docker dont pay the price.

Makes perfect sense. I'll look into how to pass pixel dimensions to a container.

Just curious, what do you mean by "pay the price"? Is the escape code method slower than the one with ioctl?

kovidgoyal commented 1 year ago

Yes, much slower. Escape code means the kernel has to send the escape code from your program to the terminal over a tty device, the terminal has to parse it and then the kernel has to send the terminals reply to your program again over a tty device, which then has to parse that reply. And say the user is running this program over SSH then there is basically unbounded latency depending on the speed and quality of the network link.

By contrast the ioctl() is a single context switch into the kernel which copies the cached winsize struct into your programs memory.