3

Is there way I can identify a window by a number in neovim and then jump to it with a macro ? Or better yet...Is there a way that I can identify which window is a terminal after calling the :term command and then jump to it ?

I know there's window number system in tmux that's similar to that.

The problem is I wrote me a shell script that calls cmake and make and I plan on binding it to a key like F5 that runs it in the terminal. The problem is I want it where I'm able to automatically jump to the terminal window I called with :term no matter which window I'm in or how my workspace looks like.

Is this possible ?

  • 1
    I don't use neovim but I seems that it sets a variable &buftype to 'terminal' so you could iterate through the buffer and switch to the one where &buftype == 'terminal' is true. – statox Nov 4 '16 at 11:53
2

statox's comment works, but for what you want, it's not the best solution. You can't simply check for &buftype == 'terminal. A terminal buffer could be created by a plugin such as fzf and you could end up in a weird state if you blindly try to send text into it.

Plugin

Probably the best option is to use the neoterm plugin:

nnoremap <f5> :T make<cr>

That will run make in the terminal buffer that's managed by neoterm.

Manual method

Although I think neoterm will be best for your situation, I'm adding this for the sake of completeness.

For you to be sure that a terminal is yours to do with as you please, you have a couple methods:

autocmd TermOpen *:$SHELL,*:\$SHELL let b:my_term = 1

This will set b:my_term in a buffer that's created by :term without arguments. This isn't always reliable, since a plugin could run :term.

command! -nargs=? MyTerm execute 'term <args>' | let b:my_term = 1

This gives you a command that you can be 100% certain is yours.

To find these buffers:

let terms = filter(range(1, bufnr('$')),
      \ 'bufexists(v:val) && getbufvar(v:val, "my_term", 0)')

This gives you a list of buffers that have the b:my_term variable set. Also note that there are other terminal-specific variables that available.

From :h terminal-emulator-status

Terminal buffers maintain some information about the terminal in buffer-local
variables:

- *b:term_title* The settable title of the terminal, typically displayed in
  the window title or tab title of a graphical terminal emulator. Programs
  running in the terminal can set this title via an escape sequence.
- *b:terminal_job_id* The nvim job ID of the job running in the terminal. See
  |job-control| for more information.
- *b:terminal_job_pid* The PID of the top-level process running in the
  terminal.
  • And this would go to a window with a neoterm already opened up without displaying an entire new buffer and window? – PrimRock Nov 4 '16 at 21:29
  • Yes. It will open a new terminal buffer if one doesn't exist first. Then it will send subsequent :T arguments into the same buffer. – Tommy A Nov 4 '16 at 21:36
  • Such an elegant solution! Thank you good sir! – PrimRock Nov 4 '16 at 22:13
1

You will need to write a function for that (taken from Reddit):

function! s:win_by_bufname(bufname)
    let bufmap = map(range(1, winnr('$')), '[bufname(winbufnr(v:val)), v:val]')
    let thewindow = filter(bufmap, 'v:val[0] =~ a:bufname')[0][1]
    execute thewindow 'wincmd w'
endfunction

command! -nargs=* WinGo call s:win_by_bufname(<q-args>)

The function in this script creates a list of [, ] entries by applying map() to the range of window numbers in the current tabpage. winnr('$') returns the number of windows in the tabpage. Then it finds the entry with the given buffer name, and extracts the associated window number. Then it jumps to that window.

You need to modify it so it compares against the terminal buffer name (see below). Your key here will be the PID in that string. That PID corresponds to the process started along the terminal buffer and that's why it's the same during the terminal window lifetime.

Original answer

Besides @statox's suggestion you also have the :b command plus the terminal buffer name which is in the form term://$CWD//$PID:$COMMAND (see :h terminal-emulator) so you could call :b {pid}.

  • This opens the buffer that I want in the current window, but how do I get it to jump/cycle to window that already has it open ? – PrimRock Nov 4 '16 at 14:47
  • @PrimRock ok! Now I understand. I edited the answer describing the approach that I think you should follow but I don't have time to test it by myself :( I hope it helps. – Tae Nov 4 '16 at 16:20
  • 1
    I was struggling trying to get the script to function properly. I'll probably return to this in the future when I get better at vimscript and vim in general. I'll definitely upvote this though and try it again in the future, but thank you so much! – PrimRock Nov 4 '16 at 22:12
  • 1
    Actually Tommy A solution is pretty clever! – Tae Nov 5 '16 at 13:58

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.