The problem

I'm trying to write a function that outputs a shell command in a terminal vertical split.

Vim's terminal, as any terminal, will break lines that are wider than the terminal window. As there's no working around this, I still would like to get the widest possible output (that is, the screen width).

After executing for example :terminal cat wide_file, moving the window to the right manually with ctrl-w_L does not change the break point.

I can't reproduce this behaviour from a function: the lines are broken to the new window width, even if moving the window after the shell command is executed in a wider window.

What I have

command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand(<q-args>)
function! s:RunShellCommand(cmdline) abort
    " wipe previous command output
    if bufexists('scratch_terminal_output')
        bw! scratch_terminal_output
    " execute the command in a wide window
    wincmd v
    wincmd J
    let current_window = win_getid()
    if has("nvim")
        exe 'terminal '. a:cmdline
        exe 'terminal ++curwin'. a:cmdline
    file scratch_terminal_output
    let term_window = win_getid()
    " moving the window to the right, assigning a new width
    wincmd L
    60 wincmd|
    " back to where we were before executing
    if win_getid() != current_window
        call win_gotoid(current_window)

What I tried so far

In this part, the "xxxxxx" section, which does not work as expected, is removed.

Using another function called at the end of the above

function! MoveTermToRight(term_window, current_window) abort
    call win_gotoid(term_window)
    wincmd L
    60 wincmd|
    call win_gotoid(current_window)

Using another function and running it in the command

command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand(<q-args>) | call MoveLastWindowToRight()
function! MoveLastWindowToRight()
    wincmd p
    wincmd L
    60 wincmd|
    wincmd p

Using an autocommand to move the window after leaving the buffer

au BufLeave scratch_terminal_output wincmd L | 60 wincmd |

Using a mapping

(Well, I've been experimenting.)

nnoremap \ls :Shell ls <cr><bar>:wincmd p<cr><bar>:wincmd L<cr><bar>:wincmd p<cr>

Vim breaks each line at the new width, whatever approach I tried.

Why not stick with the channels approach?

It's sluggish, especially when displaying large outputs (e.i. ~100MB file).


I guess dedowsdi gave the answer. Any workaround welcome.

  • 2
    My guessing is term ... is async, it's actually executed after all wincmd (which change terminal width).
    – dedowsdi
    May 26 '20 at 0:58
  • Well indeed, that's even the whole point... I feel silly...
    – Biggybi
    May 26 '20 at 1:06
  • 1
    Perhaps polling term_getstatus() and checking when it's finished? Though I think you're probably better off running the command using :! or systemlist() and using a scratch buffer to display the output... The :terminal is great if you want the user to interact with the terminal, but just showing command output, maybe not the best option.
    – filbranden
    May 26 '20 at 2:03
  • @filbranden I'll have a look at term_getstatus(), it sounds promising, thanks. Also, I indeed would like it to be interactive :) I'll check that tomorrow.
    – Biggybi
    May 26 '20 at 2:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.