0

I'm trying to write a function to open a split terminal in Vim and then run the current file in that terminal. A non-working example trying to explain what I'm trying to do is

function! Foo()
    :bel term
    %
endfunction

This just opens up the terminal. I tried with another command, dir, and it seems it's fails because dir is not a Vim command, so it's still trying to run things in Vim rather than the terminal. I also tried putting the command on the same line e.g. :bel term % but I get an error:

Error detected while processing function Foo:
line 2:
CreateProcess failed

And the terminal doesn't even open.

I also tried

function! Foo()
    :bel term
    !dir
endfunction

though that had the expected result of essentially running !dir and then returning me to a split window with nothing in the terminal there.

I've also tried to use the feedkeys() function but I can't find a way to automatically pass the file name in.

I can't see anything relevant on :help terminal. I've also found two relevant posts (post 1, post 2) but both seem to use Linux/bash and I'm on Windows, and those solutions aren't working.

How could I achieve this? If it's relevant I'm running Vim on Windows through cmd.

1

Each line in vimscript is a vim command, not a series of keystrokes. Running :terminal doesn't automatically mean any following commands will be sent to the terminal buffer.

In order to send keystrokes to a terminal, we need its buffer number and term_sendkeys(). The easiest way to get a terminal's buffer number programatically is to start it with term_start():

function Foo() abort
  " replace with let if your vim is old
  const term_buf = term_start(&shell)
  call term_sendkeys(term_buf, expand('#')."\<CR>")
endfunction

You can also use method syntax in this case:

call term_start(&shell)->term_sendkeys(expand('#')."\<CR>")
  • expand('#') gets the previous files name (term_start() has already switched to the terminal buffer)
  • ."\<CR>" embeds a carriage-return (enter) keypress, too
  • term_start() takes a fair number of options, so you can use, e.g., #{vertical: v:true} for a vertical split.

When you do :terminal %, it tries to run the file expanded to by % as a program; it's possible the file isn't found (e.g., if the file is in the current directory and that directory is not in PATH). Using :terminal %:p might work around that.

7
  • That function you posted does open a terminal, but returns the file path of cmd rather than the file name. However, I managed to fix it by with const file_name = expand('%') and then call term_start(&shell)->term_sendkeys(file_name)! So thank you for that. A couple more questions: (1) how do I send an Enter keypress afterwards? Currently it fills the filename in the terminal but doesn't run it. (2) Is there a way to make the terminal split to be below or alongside the code, rather than above it, similar to :bel term and :vert term?
    – Alira
    Jul 28 at 15:35
  • Also, :terminal %:p sadly does not work, and gives the same error as the similar attempts mentioned in the question.
    – Alira
    Jul 28 at 15:37
  • Ick, good call on the file-name—term_start() switches windows, so the old one is lost. I'll use # here for the alternate file. For an enter keypress, you need a string with "\<cr>" in it probably. Have a look at term_start()s options and see if there's a splitting option.
    – D. Ben Knoble
    Jul 28 at 16:38
  • Hadn't seen # before, good to know! Much cleaner. As for the term_start() options: I'd already found them so I knew there was an option for a vertical split called vertical, but being new to Vim/Vimscript I couldn't figure out the syntax. After an embarassing amount of time I've finally got it: term_start(&shell, {'vertical' : 1}). Thanks for all the help!
    – Alira
    Jul 28 at 17:02
  • 1
    @D.BenKnoble Actually, that's probably why I haven't spent much time with it...99% of the time that I'm in (terminal) Vim it's in tmux and my custom stuff involving "shell from Vim" mostly predates :term and/or is easier to do with :!.
    – B Layer
    Jul 29 at 0:18

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.