├── README.md ├── autoload └── gtfo │ └── open.vim ├── doc └── vim-gtfo.txt └── plugin └── gtfo.vim /README.md: -------------------------------------------------------------------------------- 1 | gtfo.vim :point_right: 2 | ====================== 3 | 4 | Opens the 5 | [file manager](http://en.wikipedia.org/wiki/File_manager#Examples) 6 | or [terminal](http://en.wikipedia.org/wiki/Terminal_emulator) at the 7 | directory of the current file in Vim. 8 | 9 | Features 10 | -------- 11 | 12 | ### Mappings 13 | 14 | * `gof`: **Go** to the directory of the current file in the **File manager** 15 | * `goF`: Go to the *working directory* (`:pwd`) 16 | * `got`: **Go** to the directory of the current file in the **Terminal** 17 | * `goT`: Go to the *working directory* (`:pwd`) 18 | 19 | ### Options 20 | 21 | * `g:gtfo#terminals` Optional dictionary with one or more of the following keys: `win`, `mac`, `unix` 22 | 23 | The `g:gtfo#terminals.` *value* is the name (or absolute path) of 24 | a terminal program followed by the necessary flags (`-e`, `/k`, etc.) for 25 | executing a command on startup. 26 | 27 | **Special case (OS X):** To use iTerm instead of Terminal.app, use the special value "iterm": 28 | ``` 29 | let g:gtfo#terminals = { 'mac': 'iterm' } 30 | ``` 31 | 32 | Platform Support 33 | ---------------- 34 | 35 | * **tmux:** `got` opens a new tmux pane. 36 | * **mintty ([Git-for-Windows](https://gitforwindows.org/), 37 | [Cygwin](http://www.cygwin.com/), etc.):** `got` opens a new mintty console. 38 | * **Windows** 39 | * `gof` opens Windows Explorer. 40 | * `got` opens `g:gtfo#terminals['win']` *or* the first terminal it can find: 41 | "Git bash", mintty, or cmd.exe. 42 | * To use pwsh: 43 | ``` 44 | let g:gtfo#terminals = { 'win': 'pwsh' } 45 | ``` 46 | * To use powershell: 47 | ``` 48 | let g:gtfo#terminals = { 'win': 'powershell -NoLogo -NoExit -Command' } 49 | ``` 50 | * To use ye olde cmd.exe: 51 | ``` 52 | let g:gtfo#terminals = { 'win': 'cmd.exe /k' } 53 | ``` 54 | * **Mac OS X** 55 | * `gof` opens Finder. 56 | * `got` opens Terminal.app *unless* Vim is running in iTerm or `g:gtfo#terminals['mac']` is set.
57 | To force iTerm (special case, see [above][#settings]): 58 | ``` 59 | let g:gtfo#terminals = { 'mac': 'iterm' } 60 | ``` 61 | * **Unix** 62 | * `gof` opens the file manager dictated by 63 | [`xdg-open`](https://portland.freedesktop.org/doc/xdg-open.html). 64 | * `got` opens `$SHELL` inside `gnome-terminal` unless `g:gtfo#terminals['unix']` is set. 65 | * To use termite: 66 | ``` 67 | let g:gtfo#terminals = { 'unix': 'termite -d' } 68 | ``` 69 | * To use rxvt-unicode: 70 | ``` 71 | let g:gtfo#terminals = { 'unix': 'urxvt -cd' } 72 | ``` 73 | 74 | Installation 75 | ------------ 76 | 77 | - [Pathogen](https://github.com/tpope/vim-pathogen) 78 | - `cd ~/.vim/bundle && git clone git://github.com/justinmk/vim-gtfo.git` 79 | - [vim-plug](https://github.com/junegunn/vim-plug) 80 | 1. Add `Plug 'justinmk/vim-gtfo'` to .vimrc 81 | 2. Run `:PlugInstall` 82 | 83 | FAQ 84 | --- 85 | 86 | > `got` (or `gof`) doesn't work 87 | 88 | Try `:verbose map gof` to see if some other plugin is using that mapping. 89 | 90 | > On Linux without a gui, `gof` does nothing, or launches w3m 91 | 92 | `xdg-open` defaults to w3m if no GUI is available (eg, in ssh or tty console). 93 | To change the default: `xdg-mime default application/x-directory foo` 94 | 95 | Credits 96 | ------- 97 | 98 | * Sangmin Ryu, [open-terminal-filemanager](http://www.vim.org/scripts/script.php?script_id=2896) 99 | * @tpope, for impeccable Vim plugin reference implementations 100 | * [EasyShell](http://marketplace.eclipse.org/node/974#.Ui1kc2R273E) 101 | * [junegunn](https://github.com/junegunn) for some readme copy 102 | 103 | License 104 | ------- 105 | 106 | Copyright © Justin M. Keyes. MIT license. 107 | -------------------------------------------------------------------------------- /autoload/gtfo/open.vim: -------------------------------------------------------------------------------- 1 | let s:iswin = has('win32') || has('win64') || has('win32unix') || has('win64unix') 2 | let s:ismac = has('gui_macvim') || has('mac') 3 | let s:istmux = !(empty($TMUX)) 4 | let s:iswezterm = $WEZTERM_PANE !=? '' 5 | let s:iskitty = $KITTY_LISTEN_ON !=? '' 6 | "GUI Vim 7 | let s:isgui = has('gui_running') || &term ==? 'builtin_gui' 8 | "non-GUI Vim running within a GUI environment 9 | let s:is_gui_available = s:ismac || s:iswin || (!empty($DISPLAY) && $TERM !=# 'linux') 10 | 11 | let s:termpath = '' 12 | let s:tmux_1_6 = 0 13 | 14 | func! s:beep(s) abort 15 | echohl ErrorMsg | echom 'gtfo: '.a:s | echohl None 16 | endf 17 | func! s:trimws(s) abort 18 | return substitute(a:s, '^\s*\(.\{-}\)\s*$', '\1', '') 19 | endf 20 | func! s:scrub(s) abort 21 | "replace \\ with \ (greedy) #21 22 | return substitute(a:s, '\\\\\+', '\', 'g') 23 | endf 24 | func! s:empty(s) abort 25 | return strlen(s:trimws(a:s)) == 0 26 | endf 27 | 28 | func! s:init() abort 29 | " initialize missing keys with empty strings. 30 | let g:gtfo#terminals = extend(get(g:, "gtfo#terminals", {}), 31 | \ { 'win' : '', 'mac' : '', 'unix': '' }, 'keep') 32 | 33 | if s:iswin 34 | let s:termpath = s:empty(g:gtfo#terminals.win) ? s:find_cygwin_bash() : g:gtfo#terminals.win 35 | elseif s:ismac 36 | let s:termpath = s:empty(g:gtfo#terminals.mac) ? '' : g:gtfo#terminals.mac 37 | else 38 | let s:termpath = s:empty(g:gtfo#terminals.unix) ? '' : g:gtfo#terminals.unix 39 | endif 40 | 41 | let s:termpath = s:trimws(s:termpath) 42 | 43 | if s:istmux 44 | call system('tmux -V') 45 | let s:tmux_1_6 = v:shell_error 46 | endif 47 | endf 48 | 49 | func! s:try_find_git_bin(binname) abort 50 | "try 'Program Files', else fall back to 'Program Files (x86)'. 51 | for programfiles_path in [$ProgramW6432, $ProgramFiles, $ProgramFiles.' (x86)', $SCOOP.'/apps'] 52 | let path = substitute(programfiles_path, '\', '/', 'g').'/'.a:binname 53 | if executable(path) 54 | return path 55 | endif 56 | endfor 57 | return '' 58 | endf 59 | 60 | func! s:find_cygwin_bash() abort 61 | let path = s:try_find_git_bin('Git/usr/bin/mintty.exe') 62 | let path = '' !=# path ? path : s:try_find_git_bin('Git/bin/bash.exe') 63 | let path = '' !=# path ? path : s:try_find_git_bin('git/current/usr/bin/mintty.exe') 64 | "return path or fallback to vanilla cygwin. 65 | return '' !=# path ? path : 66 | \ (executable($SystemDrive.'/cygwin/bin/bash') ? $SystemDrive.'/cygwin/bin/bash' : '') 67 | endf 68 | 69 | func! s:force_cmdexe() abort 70 | if &shell !~? "cmd" || &shellslash 71 | let s:shell=&shell | let s:shslash=&shellslash | let s:shcmdflag=&shellcmdflag 72 | let &shell=$COMSPEC 73 | set noshellslash shellcmdflag=/c 74 | endif 75 | endf 76 | func! s:restore_shell() abort 77 | if exists("s:shell") 78 | let &shell=s:shell | let &shellslash=s:shslash | let &shellcmdflag=s:shcmdflag 79 | endif 80 | endf 81 | 82 | func! s:cygwin_cmd(path, dir, validfile) abort 83 | let startcmd = executable('cygstart') ? 'cygstart' : 'start' 84 | return a:validfile 85 | \ ? startcmd.' explorer /select,$(cygpath -w '.shellescape(a:path).')' 86 | \ : startcmd.' explorer $(cygpath -w '.shellescape(a:dir).')' 87 | endf 88 | 89 | func! gtfo#open#file(path) abort "{{{ 90 | if exists('+shellslash') && &shellslash 91 | "Windows: force expand() to return `\` paths so explorer.exe won't choke. #11 92 | let l:shslash=1 | set noshellslash 93 | endif 94 | 95 | let l:path = s:scrub(expand(a:path, 1)) 96 | let l:dir = isdirectory(l:path) ? l:path : fnamemodify(l:path, ":h") 97 | let l:validfile = filereadable(l:path) 98 | 99 | if exists("l:shslash") 100 | set shellslash 101 | endif 102 | 103 | if !isdirectory(l:dir) "this happens if the directory was moved/deleted. 104 | echom 'gtfo: invalid/missing directory: '.l:dir 105 | return 106 | endif 107 | 108 | if has('win32unix') 109 | silent call system(s:cygwin_cmd(l:path, l:dir, l:validfile)) 110 | elseif s:iswin 111 | call s:force_cmdexe() 112 | silent exec '!start explorer '.(l:validfile ? '/select,'.shellescape(l:path, 1) : shellescape(l:dir, 1)) 113 | call s:restore_shell() 114 | elseif !s:is_gui_available && !executable('xdg-open') 115 | if s:istmux "fallback to 'got' 116 | call gtfo#open#term(l:dir, "") 117 | else 118 | call s:beep('failed to open file manager') 119 | endif 120 | elseif s:ismac 121 | if l:validfile 122 | silent call system('open --reveal '.shellescape(l:path)) 123 | else 124 | silent call system('open '.shellescape(l:dir)) 125 | endif 126 | elseif executable('xdg-open') 127 | silent call system("xdg-open ".shellescape(l:dir)." &") 128 | else 129 | call s:beep('xdg-open is not in your $PATH. Try "sudo apt-get install xdg-utils"') 130 | endif 131 | endf "}}} 132 | 133 | func! gtfo#open#term(dir, cmd) abort "{{{ 134 | let l:dir = s:scrub(expand(a:dir, 1)) 135 | if !isdirectory(l:dir) "this happens if a directory was deleted outside of vim. 136 | call s:beep('invalid/missing directory: '.l:dir) 137 | return 138 | endif 139 | 140 | if s:istmux 141 | if s:tmux_1_6 142 | silent call system('tmux split-window -h \; send-keys "cd ''' . l:dir . ''' && clear" C-m') 143 | else 144 | silent call system("tmux split-window -h -c '" . l:dir . "'") 145 | endif 146 | elseif s:iskitty 147 | let l:cwd = s:iswin ? shellescape(l:dir, 1) : "'" . l:dir . "'" 148 | silent call system("kitty @ --to=$KITTY_LISTEN_ON new-window --cwd=" . l:cwd) 149 | elseif s:iswezterm 150 | let l:cwd = s:iswin ? shellescape(l:dir, 1) : "'" . l:dir . "'" 151 | silent call system("wezterm cli split-pane --cwd=" . l:cwd) 152 | elseif &shell !~? "cmd" && executable('cygstart') && executable('mintty') 153 | " https://github.com/mintty/mintty/wiki/Tips 154 | silent exec '!cd '.shellescape(l:dir, 1).' && cygstart mintty /bin/env CHERE_INVOKING=1 /bin/bash' 155 | if !s:isgui | redraw! | endif 156 | elseif s:iswin && &shell !~? "cmd" && executable('mintty') 157 | silent call system('cd '.shellescape(l:dir).' && mintty - &') 158 | elseif s:iswin 159 | call s:force_cmdexe() 160 | if s:isgui 161 | " Prevent cygwin/msys from inheriting broken $VIMRUNTIME. 162 | " WEIRD BUT TRUE: This correctly unsets $VIMRUNTIME in the child shell, 163 | " without modifying $VIMRUNTIME in the running gvim. 164 | let $VIMRUNTIME='' 165 | endif 166 | let drive = matchstr(l:dir, '^\s*\S:') 167 | let cmdsep = (s:termpath =~? 'powershell') ? ' ; ' : ' & ' 168 | let cdcmd = ( '' ==# drive ? '' : drive.cmdsep ).'cd '.shellescape(l:dir, 1) 169 | 170 | if s:termpath =~? 'bash' && executable('bash') 171 | silent exe '!start '.$COMSPEC.' /c "'.cdcmd.' & "'.s:termpath.'" --login -i "' 172 | elseif s:termpath =~? 'mintty' && executable('mintty') 173 | silent exe '!start /min '.$COMSPEC.' /c "'.cdcmd.' & "'.s:termpath.'" - " & exit' 174 | elseif s:termpath =~? 'powershell' && executable('powershell') 175 | silent exe '!start '.s:termpath.' \"'.cdcmd.'\"' 176 | elseif s:termpath =~? 'pwsh' && executable('pwsh') 177 | silent exe '!start '.s:termpath.' -wd '.shellescape(l:dir,1) 178 | elseif s:termpath =~? 'wt' && executable('wt') 179 | silent exe '!start '.s:termpath.' -d '.shellescape(l:dir,1) 180 | else "Assume it is a path-plus-arguments. 181 | if s:empty(s:termpath) | let s:termpath = 'cmd.exe /k' | endif 182 | " This will nest quotes (""foo" "bar""), and yes, that is what cmd.exe expects. 183 | silent exe '!start '.s:termpath.' "'.cdcmd.'"' 184 | endif 185 | call s:restore_shell() 186 | elseif s:ismac 187 | if (s:empty(s:termpath) && $TERM_PROGRAM ==? 'iTerm.app') || s:termpath ==? "iterm" 188 | silent call system("open -a iTerm ".shellescape(l:dir)) 189 | else 190 | if s:empty(s:termpath) | let s:termpath = 'Terminal' | endif 191 | silent call system("open -a ".shellescape(s:termpath)." ".shellescape(l:dir)) 192 | endif 193 | elseif s:is_gui_available 194 | if !s:empty(s:termpath) 195 | silent call system(s:termpath." ".shellescape(l:dir)) 196 | elseif executable('gnome-terminal') 197 | silent call system('gnome-terminal --app-id=org.gnome.Terminal --window --working-directory '''. l:dir . '''') 198 | elseif executable('urxvt') 199 | silent call system('urxvt -cd '.shellescape(l:dir)) 200 | else 201 | call s:beep('failed to open terminal') 202 | endif 203 | if !s:isgui | redraw! | endif 204 | else 205 | call s:beep('failed to open terminal') 206 | endif 207 | endf "}}} 208 | 209 | call s:init() 210 | -------------------------------------------------------------------------------- /doc/vim-gtfo.txt: -------------------------------------------------------------------------------- 1 | gtfo.txt 2 | 3 | Opens the file manager (http://en.wikipedia.org/wiki/File_manager#Examples) 4 | or terminal (http://en.wikipedia.org/wiki/Terminal_emulator) at the 5 | directory of the current file in Vim. 6 | 7 | -------------------------------------------------------------------------------- 8 | FEATURES *gtfo-features* 9 | 10 | MAPPINGS *gtfo-mappings* 11 | 12 | * `gof`: Go to the directory of the current file in the File manager 13 | * `goF`: Go to the working directory (`:pwd`) 14 | * `got`: Go to the directory of the current file in the Terminal 15 | * `goT`: Go to the working directory (`:pwd`) 16 | 17 | OPTIONS *gtfo-options* 18 | 19 | * `g:gtfo#terminals` Optional dictionary with one or more of the following 20 | keys: `win`, `mac`, `unix` 21 | * The `g:gtfo#terminals.` value is the name (or absolute path) of 22 | a terminal program followed by the necessary flags (`-e`, `/k`, etc.) for 23 | executing a command on startup. 24 | Special case (OS X): To use iTerm instead of Terminal.app, use the special 25 | value "iterm": 26 | > 27 | let g:gtfo#terminals = { 'mac': 'iterm' } 28 | < 29 | 30 | -------------------------------------------------------------------------------- 31 | PLATFORM SUPPORT *gtfo-platform_support* 32 | 33 | * tmux: `got` opens a new tmux pane. 34 | * wezterm: `got` opens a new wezterm pane. 35 | * kitty: `got` opens a new kitty pane if `allow_remote_control` and `listen_on` 36 | are set to appropriate values in your kitty config. 37 | See https://sw.kovidgoyal.net/kitty/remote-control 38 | * mintty (Git-for-Windows (https://gitforwindows.org/), 39 | Cygwin (http://www.cygwin.com/), etc.): `got` opens a new mintty console. 40 | * Windows 41 | * `gof` opens Windows Explorer. 42 | * `got` opens `g:gtfo#terminals['win']` or the first terminal it can find: 43 | "Git bash", mintty, or cmd.exe. 44 | * To use powershell: 45 | > 46 | let g:gtfo#terminals = { 'win': 'powershell -NoLogo -NoExit -Command' } 47 | < 48 | * To use ye olde cmd.exe: 49 | > 50 | let g:gtfo#terminals = { 'win': 'cmd.exe /k' } 51 | < 52 | * Mac OS X 53 | * `gof` opens Finder. 54 | * `got` opens Terminal.app unless Vim is running in iTerm or 55 | `g:gtfo#terminals['mac']` is set. 56 | To force iTerm (special case, see [above][#settings]): 57 | < 58 | let g:gtfo#terminals = { 'mac': 'iterm' } 59 | > 60 | * Unix 61 | * `gof` opens the file manager dictated by 62 | `xdg-open` (https://portland.freedesktop.org/doc/xdg-open.html). 63 | * `got` opens `$SHELL` inside `gnome-terminal` unless 64 | `g:gtfo#terminals['unix']` is set. 65 | * To use termite: 66 | > 67 | let g:gtfo#terminals = { 'unix': 'termite -d' } 68 | < 69 | * To use rxvt-unicode: 70 | > 71 | let g:gtfo#terminals = { 'unix': 'urxvt -cd' } 72 | < 73 | 74 | 75 | -------------------------------------------------------------------------------- 76 | FAQ *gtfo-faq* 77 | > 78 | `got` (or `gof`) doesn't work 79 | < 80 | 81 | Try `:verbose map gof` to see if some other plugin is using that mapping. 82 | 83 | > 84 | On Linux without a gui, `gof` does nothing, or launches w3m 85 | < 86 | 87 | `xdg-open` defaults to w3m if no GUI is available (eg, in ssh or tty console). 88 | To change the default: `xdg-mime default application/x-directory foo` 89 | 90 | -------------------------------------------------------------------------------- 91 | CREDITS *gtfo-credits* 92 | 93 | * Sangmin Ryu, open-terminal-filemanager 94 | (http://www.vim.org/scripts/script.php?script_id=2896) 95 | * @tpope, for impeccable Vim plugin reference implementations 96 | * EasyShell (http://marketplace.eclipse.org/node/974#.Ui1kc2R273E) 97 | * junegunn (https://github.com/junegunn) for some readme copy 98 | 99 | -------------------------------------------------------------------------------- 100 | LICENSE *gtfo-license* 101 | 102 | Copyright © Justin M. Keyes. MIT license. 103 | 104 | vim:tw=78:ts=8:ft=help:norl: 105 | -------------------------------------------------------------------------------- /plugin/gtfo.vim: -------------------------------------------------------------------------------- 1 | " gtfo.vim - Go to Terminal or File manager 2 | " Author: Justin M. Keyes 3 | " Version: 2.0.0 4 | 5 | if exists('g:loaded_gtfo') || &compatible 6 | finish 7 | endif 8 | let g:loaded_gtfo = 1 9 | 10 | " Turn on support for line continuations when creating the script 11 | let s:cpo_save = &cpo 12 | set cpo&vim 13 | 14 | if maparg('gof', 'n') ==# '' 15 | nnoremap gof :call gtfo#open#file("%:p") 16 | endif 17 | if maparg('got', 'n') ==# '' 18 | nnoremap got :call gtfo#open#term("%:p:h", "") 19 | endif 20 | if maparg('goF', 'n') ==# '' 21 | nnoremap goF :call gtfo#open#file(getcwd()) 22 | endif 23 | if maparg('goT', 'n') ==# '' 24 | nnoremap goT :call gtfo#open#term(getcwd(), "") 25 | endif 26 | 27 | let &cpo = s:cpo_save 28 | unlet s:cpo_save 29 | 30 | --------------------------------------------------------------------------------