Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to set size of terminal for job with PTY #11476

Open
cdelledonne opened this issue Oct 31, 2022 · 6 comments
Open

Unable to set size of terminal for job with PTY #11476

cdelledonne opened this issue Oct 31, 2022 · 6 comments
Labels

Comments

@cdelledonne
Copy link

Steps to reproduce

  1. For debugging purposes, create a C file called winsize.c, it will be used to get the size of the terminal. Then compile the above C file, e.g. gcc winsize.c -o winsize.out
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    int main() {
        struct winsize size;
        int err = ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);
        printf("Error: %d, Columns: %d, Rows: %d\n", err, size.ws_col, size.ws_row);
        return 0;
    }
  2. Launch Vim, run a job with PTY and width of 80 columns. The job uses winsize.out to obtain the PTY's size
    let g:out = []
    let opts = {'pty': 1, 'env': {'TERM': getenv('TERM'), 'COLUMNS': 80}, 'out_cb': {c, m -> add(g:out, m)}}
    let job = job_start(['./winsize.out'], opts)
    while ch_status(job) !=# 'closed' | execute 'sleep 5m' | endwhile
    echomsg g:out
  3. Observe the output. In my case, this is
    ['Error: 0, Columns: 0, Rows: 0']
    

Expected behaviour

I would expect the COLUMNS environment variable to set the job PTY's width, as suggested in :help terminal-unix. When I run ./winsize.out in a :terminal, I get something like

Error: 0, Columns: 238, Rows: 27

Version of Vim

9.0.720

Environment

  • Operating system: Fedora Linux, kernel 5.19.16-200
  • Terminal: Tmux
  • Value of $TERM: tmux-256color
  • Shell: ZSH

Logs and stack traces

No response

@brammool
Copy link
Contributor

You need a terminal to get the size of. A PTY is not a terminal, it's a way to connect sockets.
It would work when the "term" option of job_start() is used, but this is not implemented.
Thus you need to create a terminal and run the job in there.
The help for terminal-unix is about running a terminal, not a job.

You don't say why you are even trying to do this, perhaps if you say what you actually want to do someone can give you hints.
Otherwise I don't see anything that needs to change in Vim.

@cdelledonne
Copy link
Author

cdelledonne commented Nov 13, 2022

Whoops, I must have gotten some terminology wrong. That was based on Neovim's help regarding PTYs, where you can set width and height "of the pty terminal" (https://neovim.io/doc/user/builtin.html#jobstart()):

jobstart({cmd} [, {opts}])				*jobstart()*
		Spawns {cmd} as a job.
		...
							*jobstart-options*
		{opts} is a dictionary with these keys:
		  ...
		  height:     (number) Height of the `pty` terminal.
		  ...
		  pty:	      (boolean) Connect the job to a new pseudo
			      terminal, and its streams to the master file
			      descriptor. `on_stdout` receives all output,
			      `on_stderr` is ignored. |terminal-start|
		  ...
		  width:      (number) Width of the `pty` terminal.

Neovim seems to pull this off by calling ioctl() on the PTY slave: https://github.com/neovim/neovim/blob/0a96f18ed774ebc27db50eba4d8a4437e970a331/src/nvim/os/pty_process_unix.c#L95-L97.

Anyway, my goal is to be able to run a job in the background, save its output, and possibly write this output to a terminal buffer later on. Some commands (e.g. the Ninja build system) truncate lines of output depending on the width of the underlying terminal, and I was hoping to have such commands output lines that can fit in the terminal buffer I'm writing this output to.

@nyngwang
Copy link

nyngwang commented Feb 26, 2023

@cdelledonne So I think I just ran into exactly the same problem as you had described. So now both height, width seem to be ignored by Neovim, right? If so, this sounds like a bug on Neovim side, but I might be probably wrong since I saw an example script of an old issue Neovim side where the maintainer did set both of them.

@cdelledonne
Copy link
Author

@nyngwang that's not correct, at least with Neovim v0.8.2 the settings of height and width are respected. To reproduce on Neovim, change step 2 in my first post with

let g:out = []
let opts = {'pty': 1, 'on_stdout': {c, d, n -> add(g:out, d)}, 'width': 85, 'height': 25}
let job = jobstart(['./winsize.out'], opts)
call jobwait([job])
echomsg g:out

You should get

'Error: 0, Columns: 85, Rows: 25'

@nyngwang
Copy link

nyngwang commented Feb 27, 2023

that's not correct, at least with Neovim v0.8.2 the settings of height and width are respected.

@cdelledonne Yeah, I just confirmed it earlier today. But I tested it with API vim.fn.jobresize instead and I still saw some strange behaviors:

  • Say I create a terminal buffer to run my shell. If I hold my key say j in the interactive shell to create a string with growing length, then only width-wide is available for showing the string. (It's not wrapped but scrolled horizontally when the length of the string passed width.)
    • Each subsequent call of jobresize does change the available horizontal space of the interactive shell. As you can see in the image below. (the timestamp printed by zsh was moved to the middle of the window.)
  • But in the shrunk shell, when I called some basic terminal program (e.g. cat ./foobar.lua, ls -al, etc) the entire width of the window was still used, i.e. their outputs passed the right-end of the timestamp. (not shown in the image)

Some commands (e.g. the Ninja build system) truncate lines of output depending on the width of the underlying terminal, and I was hoping to have such commands output lines that can fit in the terminal buffer I'm writing this output to.

Did you find any new insights on this part (after months later)?

@cdelledonne
Copy link
Author

cdelledonne commented Feb 28, 2023

  • But in the shrunk shell, when I called some basic terminal program (e.g. cat ./foobar.lua, ls -al, etc) the entire width of the window was still used, i.e. their outputs passed the right-end of the timestamp. (not shown in the image)

I suspect that the PTY master, managed by the terminal emulator, resets the job's size again when running a new command. That's why, when I want to control the width of the output, I do not launch a terminal emulator.

Did you find any new insights on this part (after months later)?

No new insights unfortunately. As I said, some programs rely on the width of the terminal to output properly formatted lines (for instance, I guess your zsh uses the width information to print a properly formatted prompt with a right-aligned timestamp). For this to work, one should be able to set the width of the PTY terminal of a job launched using job_start() (using again Neovim's terminology).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants