4

I'm writing a terminal sharing web application using XTerm.js. The app uses WebSockets handled by a custom server written in PHP to send input from the browser to the host terminal. The input is received by curl and curl also sends the output back to the server which then pushes it to the browser. No SSH client library is involved, so the answer to this question unfortunately doesn't help me.

The issue is that applications that rely on knowing the terminal size aren't scaled properly and default to 24 rows by 80 columns. When I run some columns typically used to report terminal size I get the following results:

> stty size
0 0

> tput lines
24

> tput cols
80

I use xterm-addon-fit to resize the terminal, but it only works with the output of commands that don't rely on terminal size, for instance ls -l. Commands that do rely on it, for instance ls (no arguments) or more importantly vim only render their results assuming 24x80 terminal size.

I tried using the SIGWINCH signal from the previously mentioned question because I thought it might work when there's no SSH client in the middle. So I sent something like this in the browser:

echo -e "\e[8;30;120t"

but it didn't work.

I could try sending something like this as the first command:

stty rows 48 cols 160

but that can't be repeated in case the window size changes, so the terminal size will be fixed after starting it.

Is there a way to dynamically control the terminal size with XTerm.js? You can see the app in question here terminalmirror.com if you want to see the issue in action.

oguz ismail
  • 1
  • 16
  • 47
  • 69
Lukas
  • 1,246
  • 8
  • 15
  • 1
    You also need to resize the underlying pty device to the new col/row size. Only resizing the terminal output window is not enough. – jerch Aug 05 '21 at 14:23
  • I get that, the question is how can I do that? – Lukas Aug 06 '21 at 06:18
  • 1
    How do you access the pty? Either the pty binding would provide an interface for that, or you need to resort to ioctl with TIOCSWINSZ (linux) on the fd. – jerch Aug 06 '21 at 08:17
  • 1
    The javascript must send `SIGWINCH` (from javascript's window event) to terminal session, then react to ansi sequance (asking for window size). In your terminal session you had to trap `WINCH` then issue `stty` command. – F. Hauri - Give Up GitHub Aug 10 '21 at 22:45
  • I can't issue `stty` command automatically after resize. Someone might be running an editor or another command. – Lukas Aug 11 '21 at 07:30
  • 1
    Javascript/terminal does not create the SIGWINCH signal, never. It creates a resize request against the PTY, which then creates that signal. How you send the resize request to the PTY, depends on the way how you connect to the PTY. You can use `stty` as a work around on a second sub shell behind that PTY. – jerch Aug 11 '21 at 09:35
  • 1
    @Lukas *Javascript* must not issue `stty`, but have to send `SIGWINCH`. Then your session could *`trap WINCH`* to interact with ***terminal** (javascript)* to retrieve current condition (by [ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code) sequences), then issue `stty` command. – F. Hauri - Give Up GitHub Aug 12 '21 at 06:35
  • Here is a full example of the way I'm "connecting" https://terminalmirror.com/new-session . As you can see it's just "curl | script -q | curl". Any idea how would I send resize requests to script -q command? – Lukas Aug 12 '21 at 06:40
  • 1
    @Lukas: This application ***(terminalmirror)*** seem interesting! Where could we consult source code? – F. Hauri - Give Up GitHub Aug 12 '21 at 06:41
  • 1
    @Lukas Unfortunely, all links: https://terminalmirror.com/documentation, usage and operation lead to ***404***. – F. Hauri - Give Up GitHub Aug 12 '21 at 07:01
  • @F.Hauri not sure how this is going to help. I've shared the source code here: https://github.com/LukaszTlalka/TerminalMirror – Lukas Aug 12 '21 at 07:01
  • 1
    @Lukas Given what your name "terminalmirror" implicates, `script` does exactly that - it mirrors the real terminal. With `script` the resize should happen on the real terminal, and it would mirror that as well. If you want your own terminal with full control, use something that spawns its own pty instead of `script` (which is more like a terminal scraper). E.g. python has the `pty` module, nodejs has `node-pty`. Or write your own C helper. With `script` you are likely to run into more troubles around termios settings later on, it is not capable to work as a full own pty replacement. – jerch Aug 12 '21 at 07:59
  • > With script the resize should happen on the real terminal, and it would mirror that as well. I don't think this is correct. You can test by running: echo "tput cols" | script -q /dev/null No matter the size of the "real terminal", the script command defaults to 80 columns – Lukas Aug 13 '21 at 09:19
  • 1
    Well then this is already one of those limitations, where TTY properties are not correctly reflected by `script`. Looking at the code of `script` reveals, that it simply spawns a new PTY with default settings to re-route data. It never cares for SIGWINCH beside some logging. It is the wrong tool for your purpose. Spawn a PTY yourself, then you can handle resizes as well without weird subprocess juggling. – jerch Aug 13 '21 at 11:27
  • @jerch There are existing great projects like: https://tmate.io/ or https://tty-share.com/ that probably do what you suggest. With this project, I wanted to go a different route which is allowing users to share terminals with what is commonly available on their systems. – Lukas Aug 16 '21 at 08:20
  • Well - either stick with the initial pty size (users are not allowed to resize later on), or you need some additional logic on server side to handle resize requests. This additional logic can be done with another subprocess waiting for the resize requests and doing the stty col/row thing, or some script written in python which opens the pty to resize. Problem here - the terminal resizes are not in-band, you need another terminal channel to intercept those requests. Thats the point where your single script connection is not helpful, a dedicated server component can deal with that much easier. – jerch Aug 16 '21 at 09:09

0 Answers0