I can easily see the output of a command in a split using vim's terminal

For example, I use :vertical terminal make re a lot.

This example is also stated in the help (h :terminal):

Or to run build command:

:term make myprogram

I even wrote a short function to easily launch shell commands in a vertical split:

command! -complete=shellcmd -nargs=+ Shell call s:RunShellCommand(<q-args>)
function! s:RunShellCommand(cmdline) abort
    exe 'vert terminal '. a:cmdline

However, if the output is larger than the terminal width, new lines will be inserted. This makes the output inconsistent (it will depend on the current splits layout, window and screen size, and so on).

enter image description here

In this state, it's difficult to make use of vim's magic moves, copy, paste, diff, and so on.

Is there any way to get the command output without breaking lines?

I tried using set nowrap, nolinebreak, tw=0 with no luck.

  • 2
    Is there any way to get the command output without breaking lines? Right in a Vim terminal buffer, and without a hack or patching Vim, I don't think so. If you want to grab the output from a command as it was sent to the terminal, you need to use another way. (source) – user938271 May 3 at 12:57
  • Oh, if Bram says so. Well, I'm open to ideas for 'another way'. – Biggybi May 3 at 13:00
  • 1
    @Biggybi "another way" Redirect to a file is the obvious one. Use tee if you want both to have it display in the terminal and preserve it for reuse inside Vim. – filbranden May 3 at 15:07
  • does it make a difference, if you set $COLUMNS to a smaller value? – Christian Brabandt May 3 at 17:13
  • @ChristianBrabandt you mean e.g. set columns=0? Well, it'll let more space for the output, but the same behavior will apply. @filbranden I've considered tee but would like to keep with builtins if possible. – Biggybi May 3 at 18:11

I came up with a solution using channels, an idea based on Bram's presentation in this video.

command! -complete=shellcmd -nargs=+ Shell call s:TmpShellOutput(<q-args>)
function! s:TmpShellOutput(cmdline) abort
    if bufexists('tmplog')
        " clear buffer content
        call deletebufline('tmplog', 1, '$')
        " create new buffer that will not be listed
        call bufadd('tmplog')
        call setbufvar('tmplog', "buftype", "nofile")
        call setbufvar('tmplog', "filetype", "nofile")
    " start a job with bash on the argument
    let logjob = job_start(["/bin/bash", "-c", a:cmdline],
                \ {'out_io': 'buffer', 'out_name': 'tmplog', 'out_msg': ''})
    " show the buffer as a panel on the far right-hand side, unwrapped
    vert sbuffer tmplog
    wincmd L
    30 wincmd |

Use the command like in this example :

:Shell make re

This function will use a buffer tmplog to output the result of a job. The buffer is cleared at each call, allowing successive uses without pilling up the buffer list.

Several caveats:

  • Ansi escape codes are printed as is, breaking colors and cluttering the output
  • Very long commands can struggle sometimes. I don't know exactly in which circumstance, but computing power seems to be a factor
  • <c-c> does not stop the job... :bw does when it does not hang vim

I could theoretically add a local mapping from the function:

nnoremap <buffer> <c-c> :call job_stop('logjob')<cr>

But is just hangs Vim. Maybe my laptop was to hot by the time I tested that.

| improve this answer | |

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.