voldikss/vim-floaterm

github github
terminal-integration plugin
star 1469
stars
alert-circle 19
open issues
users 14
subscribers
git-branch 58
forks
CREATED

2019-08-03

UPDATED

5 days ago

packer

require('packer').startup(function()
  use 'voldikss/vim-floaterm'
end)

paq

require "paq" { 
  'voldikss/vim-floaterm'
}

Use (neo)vim terminal in the floating/popup window.

CI GitHub license Maintenance

Features

  • Support neovim floatwin and vim8 popupwin
  • Manage multiple terminal instances
  • Customizable terminal window style
  • Switch/preview floating terminal buffers using fuzzy-finder plugins such as denite.nvim or fzf, etc.
  • Use with other external command-line tools(ranger, fzf, ripgrep etc.)
  • Use as a custom task runner for asynctasks.vim or asyncrun.vim

Requirements

  • Vim or neovim with terminal feature

Installation

  • packer.nvim
use 'voldikss/vim-floaterm'
  • vim-plug
Plug 'voldikss/vim-floaterm'
  • dein.nvim
call dein#add('voldikss/vim-floaterm')

Get Started

Use :FloatermNew to open a terminal window, use :FloatermToggle to hide/reopen that. The filetype of the terminal buffer is floaterm.

If you've opened multiple floaterm instances, they will be attached to a double-circular-linkedlist. Then you can use :FloatermNext or : FloatermPrev to switch between them.

❗️Note: Long-running jobs (e.g. yarn watch) inside the builtin terminal would probably slowdown your operation. It's recommended to put them into the external terminals.

Commands

:FloatermNew[!] [options] [cmd] Open a floaterm window.

  • If ! is given, execute cmd in $SHELL. Try :FloatermNew python and : FloatermNew! python to learn about the difference.
  • If execute without cmd, open $SHELL.
  • The options is formed as --key[=value], it is used to specify local attributes of a specific floaterm instance. Note that in order to input space, you have to form it as \ followed by space, and \ must be typed as \\
    • cwd working directory that floaterm will be opened at. Accepts a path, the literal <root> which represents the project root directory, and the literal <buffer> which specifies the directory of the active buffer
    • name name of the floaterm
    • silent If --silent is given, spawn a floaterm but not open the window, you may toggle it afterwards
    • disposable If --disposable is given, the floaterm will be destroyed once it is hidden.
    • title see g:floaterm_title
    • width see g:floaterm_width
    • height see g:floaterm_height
    • opener see g:floaterm_opener
    • wintype see g:floaterm_wintype
    • position see g:floaterm_position
    • autoclose see g:floaterm_autoclose
    • borderchars see g:floaterm_borderchars
  • This command basically shares the consistent behaviors with the builtin :terminal:
    • The special characters(:help cmdline-special) such as % and <cfile> will be auto-expanded, to get standalone characters, use \ followed by the corresponding character(e.g., \%).
    • Note that <bar>(i.e., |) will be seen as an argument of the command, therefore it can not be followed by another Vim command.
  • If execute this command with a range, i.e., '<,'>:FloatermNew ..., the selected lines will be sent to the created floaterm. For example, see python repl use case below.
  • Use <TAB> to get completion.

For example, the command

:FloatermNew --height=0.6 --width=0.4 --wintype=float --name=floaterm1 --position=topleft --autoclose=2 ranger --cmd="cd ~"

will open a new floating/popup floaterm instance named floaterm1 running ranger --cmd="cd ~" in the topleft corner of the main window.

The following command allows you to compile and run your C code in the floaterm window:

:FloatermNew --autoclose=0 gcc % -o %< && ./%<

:FloatermPrev Switch to the previous floaterm instance

:FloatermNext Switch to the next floaterm instance

:FloatermFirst Switch to the first floaterm instance

:FloatermLast Switch to the last floaterm instance

:FloatermUpdate [options] Update floaterm window attributes(height, width, etc.).

  • The options is the same as in :FloatermNew (except --silent).
  • Use <TAB> to get completion.

:[N]FloatermToggle[!] [floaterm_name] Open or hide the floaterm window.

  • If N is given, toggle the floaterm whose buffer number is N
  • If floaterm_name is given, toggle the floaterm instance whose name attribute is floaterm_name. Otherwise create a new floaterm named floaterm_name.
  • Use <TAB> to get completion.
  • If ! is given, toggle all floaterms (:FloatermHide! or : FloatermShow!)

:[N]FloatermShow[!] [floaterm_name] Show the current floaterm window.

  • If N is given, show the floaterm whose buffer number is N
  • If floaterm_name is given, show the floaterm named floaterm_name.
  • If ! is given, show all floaterms (If multiple floaterms have the same position attribute, only one of them will be show)

:[N]FloatermHide[!] [floaterm_name] Hide the current floaterms window.

  • If N is given, hide the floaterm whose buffer number is N
  • If floaterm_name is given, show the floaterm named floaterm_name.
  • If ! is given, hide all floaterms

:[N]FloatermKill[!] [floaterm_name] Kill the current floaterm instance

  • If N is given, kill the floaterm whose buffer number is N
  • If floaterm_name is given, kill the floaterm instance named floaterm_name.
  • If ! is given, kill all floaterms

:FloatermSend[!] [--name=floaterm_name] [cmd] Send command to a job in floaterm.

  • If --name=floaterm_name is given, send lines to the floaterm instance whose name is floaterm_name. Otherwise use the current floaterm.
  • If cmd is given, it will be sent to floaterm and selected lines will be ignored.
  • This command can also be used with a range, i.e., '<,'>:FloatermSend [--name=floaterm_name] to send selected lines to a floaterm.
    • If cmd is given, the selected lines will be ignored.
    • If use this command with a !, i.e., '<,'>:FloatermSend! [--name=floaterm_name] the common white spaces in the beginning of lines will be trimmed while the relative indent between lines will still be kept.
  • Use <TAB> to get completion.
  • Examples
    :FloatermSend                        " Send current line to the current floaterm (execute the line in the terminal)
    :FloatermSend --name=ft1             " Send current line to the floaterm named ft1
    :FloatermSend ls -la                 " Send `ls -la` to the current floaterm
    :FloatermSend --name=ft1 ls -la      " Send `ls -la` to the floaterm named ft1
    :23FloatermSend ...                  " Send the line 23 to floaterm
    :1,23FloatermSend ...                " Send lines between line 1 and line 23 to floaterm
    :'<,'>FloatermSend ...               " Send lines selected to floaterm(visual block selection are supported)
    :%FloatermSend ...                   " Send the whole buffer to floaterm
    

Options

g:floaterm_shell

Type String. Default: &shell

g:floaterm_title

Type String. Show floaterm info(e.g., 'floaterm: 1/3' implies there are 3 floaterms in total and the current is the first one) at the top left corner of floaterm window.

Default: 'floaterm: $1/$2'($1 and $2 will be substituted by 'the index of the current floaterm' and 'the count of all floaterms' respectively)

Example: 'floaterm($1|$2)'

g:floaterm_wintype

Type String. 'float'(nvim's floating or vim's popup) by default. Set it to 'split' or 'vsplit' if you don't want to use floating or popup window.

g:floaterm_width

Type Number (number of columns) or Float (between 0 and 1). If Float, the width is relative to &columns.

Default: 0.6

g:floaterm_height

Type Number (number of lines) or Float (between 0 and 1). If Float, the height is relative to &lines.

Default: 0.6

g:floaterm_position

Type String. The position of the floating window. Available values:

  • If wintype is split/vsplit: 'leftabove', 'aboveleft', 'rightbelow', 'belowright', 'topleft', 'botright'. Default: 'botright'.

    It's recommended to have a look at those options meanings, e.g. :help :leftabove.

  • If wintype is float: 'top', 'bottom', 'left', 'right', 'topleft', 'topright', 'bottomleft', 'bottomright', 'center', 'auto'(at the cursor place). Default: 'center'

In addition, there is another option 'random' which allows to pick a random position from above when (re)opening a floaterm window.

g:floaterm_borderchars

Type String. 8 characters of the floating window border (top, right, bottom, left, topleft, topright, botright, botleft).

Default: ─│─│┌┐┘└

g:floaterm_rootmarkers

Type List of String. Markers used to detect the project root directory for --cwd=<root>

Default: ['.project', '.git', '.hg', '.svn', '.root']

g:floaterm_opener

Type String. Command used for opening a file in the outside nvim from within :terminal.

Available: 'edit', 'split', 'vsplit', 'tabe', 'drop' or user-defined commands

Default: 'split'

g:floaterm_autoclose

Type Number. Whether to close floaterm window once the job gets finished.

  • 0: Always do NOT close floaterm window
  • 1: Close window if the job exits normally, otherwise stay it with messages like [Process exited 101]
  • 2: Always close floaterm window

Default: 0.

g:floaterm_autohide

Type Number. Whether to hide previous floaterms before switching to or opening a another one.

  • 0: Always do NOT hide previous floaterm windows
  • 1: Only hide those whose position (b:floaterm_position) is identical to that of the floaterm which will be opened
  • 2: Always hide them

Default: 1.

g:floaterm_autoinsert

Type Boolean. Whether to enter Terminal-mode after opening a floaterm.

Default: v:true

Keymaps

This plugin doesn't supply any default mappings. Here are the configuration examples.

" Configuration example
let g:floaterm_keymap_new    = '<F7>'
let g:floaterm_keymap_prev   = '<F8>'
let g:floaterm_keymap_next   = '<F9>'
let g:floaterm_keymap_toggle = '<F12>'

You can also use other keys as shown below:

let g:floaterm_keymap_new = '<Leader>ft'

All options for the mappings are listed below:

  • g:floaterm_keymap_new
  • g:floaterm_keymap_prev
  • g:floaterm_keymap_next
  • g:floaterm_keymap_first
  • g:floaterm_keymap_last
  • g:floaterm_keymap_hide
  • g:floaterm_keymap_show
  • g:floaterm_keymap_kill
  • g:floaterm_keymap_toggle

Note that the key mappings are set from the plugin/floaterm.vim, so if you are using on-demand loading feature provided by some plugin-managers, the keymap above won't take effect(:help load-plugins). Then you have to define the key bindings by yourself. For example,

nnoremap   <silent>   <F7>    :FloatermNew<CR>
tnoremap   <silent>   <F7>    <C-\><C-n>:FloatermNew<CR>
nnoremap   <silent>   <F8>    :FloatermPrev<CR>
tnoremap   <silent>   <F8>    <C-\><C-n>:FloatermPrev<CR>
nnoremap   <silent>   <F9>    :FloatermNext<CR>
tnoremap   <silent>   <F9>    <C-\><C-n>:FloatermNext<CR>
nnoremap   <silent>   <F12>   :FloatermToggle<CR>
tnoremap   <silent>   <F12>   <C-\><C-n>:FloatermToggle<CR>

Highlights

There are two highlight-groups to specify the color of floaterm (also the border color if g: floaterm_wintype is 'float') window.

To customize, use hi command together with the colors you prefer.

" Configuration example

" Set floaterm window's background to black
hi Floaterm guibg=black
" Set floating window border line color to cyan, and background to orange
hi FloatermBorder guibg=orange guifg=cyan

Besides, there is a neovim only highlight group which can be used to configure no-current-focused window(:help NormalNC).

" Configuration example

" Set floaterm window background to gray once the cursor moves out from it
hi FloatermNC guibg=gray

Autocmd

autocmd User FloatermOpen        " triggered after opening a new/existed floaterm

Advanced Topics

Use with command line tools

The following cases should work both in Vim and NeoVim unless otherwise specifically noted.

floaterm

Normally if you run vim/nvim somefile.txt within the builtin terminal, you would get another nvim/vim instance running in the subprocess.

Floaterm, which is a builtin script in this plugin, allows you to open files from within : terminal without starting a nested nvim. To archive that, just literally replace vim/nvim with floaterm, e.g. floaterm somefile.txt

P.S.

  • #208 describes how to use gf in the floating terminal window.
  • floaterm is too long to type? set alias in your bashrc, e.g. alias f=floaterm
  • For configurable open action, refer to g:floaterm_opener

git

Execute git commit in the terminal window without starting a nested vim/nvim.

Refer to g:floaterm_opener for configurable open action

fzf

This plugin has implemented a wrapper for fzf command. So it can be used as a tiny fzf plugin.

Try :FloatermNew fzf or even wrap this to a new command like this:

command! FZF FloatermNew fzf

ripgrep

This plugin has implemented a wrapper for rg command.

Try :FloatermNew rg or create yourself a new command like this:

command! Rg FloatermNew --width=0.8 --height=0.8 rg

broot

This plugin has implemented a wrapper for broot.

Try :FloatermNew broot or create yourself a new command like this:

command! Broot FloatermNew --width=0.8 --height=0.8 broot

fff

There is also an fff wrapper

Try :FloatermNew fff or define a new command:

command! FFF FloatermNew fff

nnn

There is also an nnn wrapper

Try :FloatermNew nnn or define a new command:

command! NNN FloatermNew nnn

xplr

There is also an xplr wrapper

Try :FloatermNew xplr or define a new command:

command! XPLR FloatermNew xplr

lf

There is also an lf wrapper. It is recommened to use lf.vim which is an lf wrapper with more features (Overriding netrw, Lfcd, etc.).

Try :FloatermNew lf or define a new command:

command! LF FloatermNew lf

ranger

This plugin can also be a handy ranger plugin since it also has a ranger wrapper

Try :FloatermNew ranger or define a new command:

command! Ranger FloatermNew ranger

vifm

There is also a vifm wrapper

Try :FloatermNew vifm or define a new command:

command! Vifm FloatermNew vifm

lazygit

Furthermore, you can also use other command-line programs, such as lazygit, htop, ncdu, etc.

Use lazygit for instance:

python

Use :FloatermNew python to open a python shell. After that you can use : FloatermSend to send lines to the Python interactive shell.

Or you can just select lines and execute :'<,'>FloatermNew --wintype=split python, then the selected lines will be sent and executed once a python repl floaterm window is opened.

This can also work for other languages which have interactive shells, such as lua, node, etc.

Use with other plugins

vim-clap

Use vim-clap to switch/preview floating terminal buffers.

Install clap-floaterm and try :Clap floaterm

denite.nvim

Use denite to switch/preview/open floating terminal buffers.

Install denite-floaterm and try :Denial floaterm

coc.nvim

Use CocList to switch/preview/open floating terminal buffers.

Install coc-floaterm and try :CocList floaterm

fzf

Install fzf-floaterm and try :Floaterms

LeaderF

Install LeaderF-floaterm and try :Leaderf floaterm

asynctasks.vim | asyncrun.vim

This plugin can be a runner for asynctasks.vim or asyncrun.vim. See asyncrun.extra for the installation and usage.

How to define more wrappers

The wrapper script must be located in autoload/floaterm/wrapper/ directory, e.g., autoload/floaterm/wrapper/fzf.vim.

There are two ways for a command to be spawned:

  • To be executed after spawning $SHELL. Here is the old implementation of fzf wrapper

    function! floaterm#wrapper#fzf#(cmd, jobopts, config) abort
      return [v:true, 'floaterm $(fzf)']
    endfunction
    

    The code above returns a list. floaterm $(fzf) is the command to be executed. v:true means the command will be executed after the &shell startup.

  • To be executed through termopen()/term_start() function, in that case, a callback option can be provided. See fzf wrapper

    function! floaterm#wrapper#fzf#(cmd, jobopts, config) abort
      let s:fzf_tmpfile = tempname()
      let cmd = a:cmd . ' > ' . s:fzf_tmpfile
      let a:jobopts.on_exit = funcref('s:fzf_callback')
      return [v:false, cmd]
    endfunction
    
    function! s:fzf_callback(...) abort
      if filereadable(s:fzf_tmpfile)
        let filenames = readfile(s:fzf_tmpfile)
        if !empty(filenames)
          if has('nvim')
            call floaterm#window#hide(bufnr('%'))
          endif
          let locations = []
          for filename in filenames
            let dict = {'filename': fnamemodify(filename, ':p')}
            call add(locations, dict)
          endfor
          call floaterm#util#open(locations)
        endif
      endif
    endfunction
    

    In the example above, after executing :FloatermNew fzf, function floaterm#wrapper#fzf# will return

    [v:false, 'fzf > /tmp/atmpfilename'].
    

    Here v:false means cmd

    fzf > /tmp/atmpfilename
    

    will be passed through termopen()(neovim) or term_start()(vim). As the result, an fzf interactive will be opened in a floaterm window.

    When user picks a file using ENTER, fzf exits and the filepath will be written in /tmp/atmpfilename and s:fzf_callback() will be invoked to open the file. Note that the function s: fzf_callback() is registered by

    let a:jobopts.on_exit = funcref('s:fzf_callback')
    

    The variable a:jobopts in the above code will be eventually passed to termopen()(neovim) or term_start()(vim). For more info, see :help jobstart-options(neovim) or :help job-options(vim)

How to write sources for fuzzy finder plugins

Function floaterm#buflist#gather() returns a list contains all the floaterm buffers.

Function floaterm#terminal#open_existing({bufnr}) opens the floaterm whose buffer number is {bufnr}.

For reference, see floaterm source for LeaderF.

Contributing

  • Improve the documentation
  • Help resolve issues labeled as help wanted

FAQ

https://github.com/voldikss/vim-floaterm/issues?q=label%3AFAQ

Breaking Changes

https://github.com/voldikss/vim-floaterm/issues?q=label%3A%22breaking+change%22

Credits

License

MIT