├── README.md ├── autoload └── filebeagle.vim ├── doc └── filebeagle.txt └── plugin └── filebeagle.vim /README.md: -------------------------------------------------------------------------------- 1 | # FileBeagle 2 | 3 | ![FileBeagle screen](http://jeetworks.org/wp-content/uploads/filebeagle2.png) 4 | 5 | ## Introduction 6 | 7 | FileBeagle is a utility to display a directory listing and select a file for 8 | editing. You can change directories and, if necessary, create new files. Files 9 | can be opened in new splits or tabs, and new directory catalogs can be spawned. 10 | 11 | And that is about it. 12 | 13 | FileBeagle is "VINE-spired": that is, inspired by the design principle of "Vim 14 | Is Not Emacs". 15 | 16 | Vim is a text editor, *not* an operating system that can edit text. FileBeagle 17 | respects this, and attempts to conform to this both in spirit and in practice. 18 | 19 | If you are looking for a plugin to serve as a filesystem manager from within 20 | Vim, FileBeagle is not it. FileBeagle does not support copying, deleting, 21 | moving/renaming, or any other filesystem operations. FileBeagle lists and opens 22 | files. 23 | 24 | If you are looking for a plugin to replicate an operating system shell in Vim, 25 | FileBeagle is not it. FileBeagle does not support `grep`-ing, `find`-ing, or 26 | any of other the other functionality provided by (the *excellent*) programs in 27 | your operating system environment dedicated to these tasks. FileBeagles lists 28 | and opens files. 29 | 30 | If you are looking for a plugin that makes Vim resemble some bloated 31 | bells-and-whistles IDE with a billion open "drawers", panels, toolbars, and 32 | windows, FileBeagle is not it. FileBeagle does not provide for fancy 33 | splits or project drawers. FileBeagle lists and opens files. 34 | 35 | ## Overview of Basic Usage 36 | 37 | Type `-` to open the FileBeagle directory viewer on the directory of the 38 | current buffer. Alternatively, you can use `f` to open the FileBeagle 39 | directory viewer on the current working directory. This latter key is mapped to 40 | the command `:FileBeagle`: if the command is used directly, it can actually 41 | take an optional argument which specifies the path of the directory to open 42 | instead of the current working directory. 43 | 44 | In either case, once a directory viewer is open, you can use any of your normal 45 | navigation keys/commands to move to a file or directory of your choice. Once 46 | you have selected a file or directory, you can type `` or `o` to open 47 | it for editing in the current window. Or you can type `CTRL-V` to edit it in a 48 | new vertical split, `CTRL-S` to edit it in a new horizontal split, or `CTRL-T` 49 | to edit it in a new tab. Even better, if you make sure that line numbers are 50 | enabled, you can simply type the line number followed by `o` or any of the 51 | other maps to instantly open the file or directory listed at the given line 52 | number. So, for example, `42o` will open the file or directory at line 42 in 53 | the same window, while `42v` will open it in a new 54 | vertical split, and `42t` will open it in a new tab, etc. 55 | 56 | You can navigate to a directory by selecting it using the same key maps that 57 | you use to select files. In addition, you can use `-` to go a parent 58 | directory or backspace (``) to go back to the previous directory. 59 | 60 | For each independent invocation of FileBeagle, it remembers the entry which you 61 | last selected in each directory as your enter or leave directories. Each time 62 | you return to a directory that you have visited before, the cursor is 63 | automatically placed at the entry which you selected the just before leaving 64 | that directory. This means that you can quickly traverse up and down a 65 | directory chain by typing `-` and/or ``. Use `-` to move up and 66 | up, until you get to the root, and then `` to drill seamlessly back 67 | down the same path you just traversed until you hit the file from which you 68 | came. Once you have tried it, you will not want to traverse directories in any 69 | other way (well, except for fuzzy-querying to "teleport" you directly where you 70 | want to go). 71 | 72 | The only file management functionality provided is to create a new file (`%` 73 | or `+`). For everything else, use the operating system. 74 | 75 | At any time, you can type `q` to close FileBeagle and restore the previous 76 | buffer. 77 | 78 | ## Acknowledgements 79 | 80 | FileBeagle is inspired by [Tim Pope](http://tpo.pe/)'s [Vinegar plugin for Vim](https://github.com/tpope/vim-vinegar.git), which, in turn, was inspired by [Drew Neil](http://drewneil.com/)'s assertion that ["project drawers" are unidiomatic in Vim](http://vimcasts.org/blog/2013/01/oil-and-vinegar-split-windows-and-project-drawer/). 81 | -------------------------------------------------------------------------------- /autoload/filebeagle.vim: -------------------------------------------------------------------------------- 1 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 2 | "" FileBeagle 3 | "" 4 | "" VINE (Vim Is Not Emacs) file system explorer. 5 | "" 6 | "" Copyright 2014 Jeet Sukumaran. 7 | "" 8 | "" This program is free software; you can redistribute it and/or modify 9 | "" it under the terms of the GNU General Public License as published by 10 | "" the Free Software Foundation; either version 3 of the License, or 11 | "" (at your option) any later version. 12 | "" 13 | "" This program is distributed in the hope that it will be useful, 14 | "" but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | "" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | "" GNU General Public License 17 | "" for more details. 18 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 19 | 20 | " Compatibility Guard {{{1 21 | " ============================================================================ 22 | let g:did_filebeagle = 1 23 | " avoid line continuation issues (see ':help user_41.txt') 24 | let s:save_cpo = &cpo 25 | set cpo&vim 26 | " }}}1 27 | 28 | " Script Globals {{{1 29 | " ============================================================================ 30 | if (has("win16") || has("win32") || has("win64")) && !&shellslash 31 | let s:sep = '\' 32 | let s:sep_as_pattern = '\\' 33 | else 34 | let s:sep = '/' 35 | let s:sep_as_pattern = '/' 36 | endif 37 | " }}}1 38 | 39 | " Utilities {{{1 40 | " ============================================================================== 41 | 42 | " Messaging {{{2 43 | " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 44 | 45 | function! s:NewMessenger(name) 46 | 47 | " allocate a new pseudo-object 48 | let messenger = {} 49 | let messenger["name"] = a:name 50 | if empty(a:name) 51 | let messenger["title"] = "FileBeagle" 52 | else 53 | let messenger["title"] = "FileBeagle (" . messenger["name"] . ")" 54 | endif 55 | 56 | function! messenger.format_message(leader, msg) dict 57 | return self.title . ": " . a:leader.a:msg 58 | endfunction 59 | 60 | function! messenger.format_exception( msg) dict 61 | return a:msg 62 | endfunction 63 | 64 | function! messenger.send_error(msg) dict 65 | redraw 66 | echohl ErrorMsg 67 | echomsg self.format_message("[ERROR] ", a:msg) 68 | echohl None 69 | endfunction 70 | 71 | function! messenger.send_warning(msg) dict 72 | redraw 73 | echohl WarningMsg 74 | echomsg self.format_message("[WARNING] ", a:msg) 75 | echohl None 76 | endfunction 77 | 78 | function! messenger.send_status(msg) dict 79 | redraw 80 | echohl None 81 | echomsg self.format_message("", a:msg) 82 | endfunction 83 | 84 | function! messenger.send_info(msg) dict 85 | redraw 86 | echohl None 87 | echo self.format_message("", a:msg) 88 | endfunction 89 | 90 | return messenger 91 | 92 | endfunction 93 | " }}}2 94 | 95 | " Path Discovery {{{2 96 | " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 97 | 98 | function! s:parent_dir(current_dir) 99 | let l:current_dir = fnamemodify(a:current_dir, ":p") 100 | if has("win16") || has("win32") || has("win64") 101 | let d = join(split(l:current_dir, s:sep_as_pattern)[:-2], s:sep) 102 | if empty(d) 103 | let d = a:current_dir 104 | endif 105 | if d =~ ":$" 106 | let d = d . s:sep 107 | endif 108 | else 109 | let d = s:sep . join(split(l:current_dir, s:sep_as_pattern)[:-2], s:sep) 110 | endif 111 | return d 112 | endfunction 113 | 114 | function! s:base_dirname(dirname) 115 | let l:dirname = fnamemodify(a:dirname, ":p") 116 | if l:dirname == s:sep 117 | return s:sep 118 | endif 119 | let d = split(l:dirname, s:sep_as_pattern)[-1] . s:sep 120 | return d 121 | endfunction 122 | 123 | function! s:is_path_exists(path) 124 | if filereadable(a:path) || !empty(glob(a:path)) 125 | return 1 126 | else 127 | return 0 128 | endif 129 | endfunction 130 | 131 | function! s:build_current_parent_dir_entry(current_dir) 132 | let parent = s:parent_dir(a:current_dir) 133 | let entry = { 134 | \ "full_path" : parent, 135 | \ "basename" : "..", 136 | \ "dirname" : fnamemodify(parent, ":h"), 137 | \ "is_dir" : 1 138 | \ } 139 | return entry 140 | endfunction 141 | 142 | function! s:discover_paths(current_dir, glob_pattern, is_include_hidden, is_include_ignored) 143 | let old_wildignore = &wildignore 144 | let old_suffixes = &suffixes 145 | if a:is_include_ignored 146 | let &wildignore = "" 147 | let &suffixes = "" 148 | endif 149 | 150 | let l:current_dir = substitute(a:current_dir, '{', '\\{', 'g') 151 | let l:current_dir = substitute(l:current_dir, '}', '\\}', 'g') 152 | 153 | if a:is_include_hidden 154 | let path_str = glob(l:current_dir.s:sep.'.[^.]'.a:glob_pattern)."\n".glob(l:current_dir.s:sep.a:glob_pattern) 155 | else 156 | let path_str = glob(l:current_dir.s:sep.a:glob_pattern) 157 | endif 158 | let paths = split(path_str, '\n') 159 | if g:filebeagle_check_gitignore && !a:is_include_ignored && executable('git') 160 | let l:gitignored_output = system( 161 | \ 'cd ' . l:current_dir . '; ' . 162 | \ 'git check-ignore ' . l:current_dir . s:sep . '*') 163 | let l:gitignored = split(l:gitignored_output, "\n") 164 | if !v:shell_error 165 | call filter(paths, 'index(l:gitignored, v:val) == -1') 166 | endif 167 | endif 168 | call sort(paths) 169 | let &wildignore = old_wildignore 170 | let &suffixes = old_suffixes 171 | let dir_paths = [] 172 | let file_paths = [] 173 | " call add(dir_paths, s:GetCurrentDirEntry(l:current_dir)) 174 | if g:filebeagle_show_parent 175 | call add(dir_paths, s:build_current_parent_dir_entry(l:current_dir)) 176 | endif 177 | for path_entry in paths 178 | let path_entry = substitute(path_entry, s:sep_as_pattern.'\+', s:sep, 'g') 179 | let path_entry = substitute(path_entry, s:sep_as_pattern.'$', '', 'g') 180 | let full_path = fnamemodify(path_entry, ":p") 181 | let basename = fnamemodify(path_entry, ":t") 182 | let dirname = fnamemodify(path_entry, ":h") 183 | let entry = { "full_path": full_path, "basename" : basename, "dirname" : dirname} 184 | if isdirectory(path_entry) 185 | let entry["is_dir"] = 1 186 | call add(dir_paths, entry) 187 | else 188 | let entry["is_dir"] = 0 189 | call add(file_paths, entry) 190 | endif 191 | endfor 192 | return [dir_paths, file_paths] 193 | endfunction 194 | " }}}2 195 | 196 | " FileBeagle Buffer Management {{{2 197 | " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 198 | function! s:get_filebeagle_buffer_name() 199 | let stemname = "filebeagle" 200 | let idx = 1 201 | let bname = stemname 202 | while bufnr(bname, 0) != -1 203 | let idx = idx + 1 204 | let bname = stemname . "-" . string(idx) 205 | endwhile 206 | return bname 207 | endfunction 208 | " }}}2 209 | 210 | " Global Support Functions {{{2 211 | " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 212 | function! FileBeagleCompleteNewFileName(A, L, P) 213 | if !exists("b:filebeagle_directory_viewer") 214 | return "" 215 | endif 216 | let basenames = [] 217 | for key in keys(b:filebeagle_directory_viewer.jump_map) 218 | let entry = b:filebeagle_directory_viewer.jump_map[key] 219 | if !entry.is_dir 220 | call add(basenames, entry.basename) 221 | endif 222 | endfor 223 | return join(basenames, "\n") 224 | endfunction 225 | " }}}2 226 | 227 | 228 | " }}}1 229 | 230 | " DirectoryViewer {{{1 231 | " ============================================================================== 232 | 233 | " Display the catalog. 234 | function! s:NewDirectoryViewer() 235 | 236 | " initialize 237 | let directory_viewer = {} 238 | 239 | " Initialize object state. 240 | if has("title") 241 | let directory_viewer["old_titlestring"] = &titlestring 242 | else 243 | let directory_viewer["old_titlestring"] = "" 244 | endif 245 | 246 | " filebeagle_buf_num, int 247 | " - The buffer number to use, or -1 if we should generate and use our 248 | " own buffer. 249 | " focus_dir, string 250 | " - The full path to the directory being listed/viewed 251 | " focus_file, string 252 | " - The full path to the file or directory that is should be the initial 253 | " target or focus 254 | " calling_buf_num, int 255 | " - The buffer number of the buffer from which FileBeagle was invoked. 256 | " If `filebeagle_buf_num` > -1, and `calling_buf_num` == 257 | " `filebeagle_buf_num`, generally it is because FileBeagle was 258 | " automagically invoked as a result of Vim being called upon to edit a 259 | " directory. 260 | " prev_focus_dirs, list of tuples, [ (string, string) ] 261 | " - The history stack, with the first element of the tuple being the 262 | " directory previously visited and the second element of the tuple being 263 | " the last selected entry in that directory 264 | " default_targets_for_directory, dictionary {string: string} 265 | " - Keys are directories and values are the correspondign default target 266 | " or selected item when that directory will be visited again. 267 | " is_filtered, boolean 268 | " - If 1, then entries will be filtered following `filter_exp` if 269 | " `filter_exp` is not empty; otherwise, entries will not be filtered 270 | " filter_exp, regular expression pattern string 271 | " - Regular expression pattern to be used to filter entries if 272 | " `is_filtered` is 1 273 | " is_include_hidden, boolean 274 | " - If 1, hidden files and directories (paths beginning with '.') will 275 | " be listed; otherwise, they will not be shown. 276 | " is_include_ignored, boolean 277 | " - If 1, files and directories matching patterns in ``wildignore`` 278 | " will be listed; otherwise, they will not be shown. 279 | function! directory_viewer.open_dir( 280 | \ filebeagle_buf_num, 281 | \ focus_dir, 282 | \ focus_file, 283 | \ calling_buf_num, 284 | \ prev_focus_dirs, 285 | \ default_targets_for_directory, 286 | \ is_filtered, 287 | \ filter_exp, 288 | \ is_include_hidden, 289 | \ is_include_ignored 290 | \) dict 291 | if !&hidden && &modified 292 | let l:windows = filter(range(1,winnr('$')), 'winbufnr(v:val) == a:calling_buf_num') 293 | if len(l:windows) < 2 294 | call s:_filebeagle_messenger.send_error("Cannot invoke FileBeagle from modified buffer if 'hidden' is not set") 295 | return 296 | endif 297 | endif 298 | " if !&hidden 299 | " let hidden_forced = 1 300 | " set hidden 301 | " else 302 | " let hidden_forced = 0 303 | " endif 304 | if a:filebeagle_buf_num == -1 305 | let self.buf_name = s:get_filebeagle_buffer_name() 306 | let self.buf_num = bufnr(self.buf_name, 1) 307 | else 308 | let self.buf_num = a:filebeagle_buf_num 309 | let self.buf_name = bufname(self.buf_num) 310 | endif 311 | let self.focus_dir = fnamemodify(a:focus_dir, ":p") 312 | let self.focus_file = fnamemodify(a:focus_file, ":p:t") 313 | if empty(a:calling_buf_num) 314 | let self.prev_buf_num = bufnr('%') 315 | else 316 | let self.prev_buf_num = a:calling_buf_num 317 | endif 318 | let self.prev_focus_dirs = deepcopy(a:prev_focus_dirs) 319 | let self.default_targets_for_directory = deepcopy(a:default_targets_for_directory) 320 | let self.is_include_hidden = a:is_include_hidden 321 | let self.is_include_ignored = a:is_include_ignored 322 | " get a new buf reference 323 | " get a viewport onto it 324 | execute "silent keepalt keepjumps buffer " . self.buf_num 325 | " if hidden_forced 326 | " set nohidden 327 | " endif 328 | let b:filebeagle_directory_viewer = self 329 | silent! doautocmd User FileBeagleBufNew 330 | " Sets up buffer environment. 331 | call self.setup_buffer_opts() 332 | call self.setup_buffer_syntax() 333 | call self.setup_buffer_commands() 334 | call self.setup_buffer_keymaps() 335 | call self.setup_buffer_statusline() 336 | " let self.prev_buf_num = prev_buf_num 337 | " set up filters 338 | let self.is_filtered = a:is_filtered 339 | let self.filter_exp = a:filter_exp 340 | " render it 341 | silent! doautocmd User FileBeagleReadPre 342 | call self.render_buffer() 343 | silent! doautocmd User FileBeagleReadPost 344 | endfunction 345 | 346 | " Sets buffer options. 347 | function! directory_viewer.setup_buffer_opts() dict 348 | 349 | if self.prev_buf_num != self.buf_num 350 | " Only set these if not directly editing a directory (i.e., 351 | " replacing netrw) 352 | set bufhidden=hide 353 | setlocal nobuflisted 354 | endif 355 | 356 | if g:filebeagle_show_line_numbers == 0 357 | setlocal nonumber 358 | elseif g:filebeagle_show_line_numbers == 1 359 | setlocal number 360 | endif 361 | if g:filebeagle_show_line_relativenumbers == 0 362 | setlocal nornu 363 | elseif g:filebeagle_show_line_relativenumbers == 1 364 | setlocal rnu 365 | endif 366 | 367 | setlocal buftype=nofile 368 | setlocal noswapfile 369 | setlocal nowrap 370 | setlocal nolist 371 | setlocal noinsertmode 372 | setlocal cursorline 373 | setlocal nospell 374 | set ft=filebeagle 375 | endfunction 376 | 377 | " Sets buffer syntax. 378 | function! directory_viewer.setup_buffer_syntax() dict 379 | if has("syntax") 380 | syntax clear 381 | syn match FileBeagleDirectoryEntry '^.*[/\\]$' 382 | highlight! link FileBeagleDirectoryEntry Directory 383 | endif 384 | endfunction 385 | 386 | " Sets buffer commands. 387 | function! directory_viewer.setup_buffer_commands() dict 388 | command! -buffer -nargs=0 ClipPathname :call b:filebeagle_directory_viewer.yank_target_name("full_path", "+") 389 | command! -buffer -nargs=0 ClipDirname :call b:filebeagle_directory_viewer.yank_current_dirname("+") 390 | command! -bang -range -buffer -nargs=1 -complete=command PreFill :,call b:filebeagle_directory_viewer.prefill_command(, "" == "!") 391 | endfunction 392 | 393 | " Sets buffer key maps. 394 | function! directory_viewer.setup_buffer_keymaps() dict 395 | 396 | """" Disabling of unused modification keys 397 | for key in [".", "p", "P", "C", "x", "X", "r", "R", "i", "I", "a", "A", "D", "S", "U"] 398 | try 399 | execute "nnoremap " . key . " " 400 | catch // 401 | endtry 402 | endfor 403 | 404 | """ Define these as we go along ... 405 | let l:default_normal_plug_map = {} 406 | let l:default_visual_plug_map = {} 407 | 408 | if !g:filebeagle_buffer_legacy_key_maps 409 | 410 | """ Directory listing splitting 411 | nnoremap :call b:filebeagle_directory_viewer.new_viewer("vert sp") 412 | nnoremap v :call b:filebeagle_directory_viewer.new_viewer("vert sp") 413 | nnoremap V :call b:filebeagle_directory_viewer.new_viewer("vert sp") 414 | nnoremap :call b:filebeagle_directory_viewer.new_viewer("sp") 415 | nnoremap s :call b:filebeagle_directory_viewer.new_viewer("sp") 416 | nnoremap S :call b:filebeagle_directory_viewer.new_viewer("sp") 417 | nnoremap :call b:filebeagle_directory_viewer.new_viewer("tabedit") 418 | nnoremap t :call b:filebeagle_directory_viewer.new_viewer("tabedit") 419 | nnoremap T :call b:filebeagle_directory_viewer.new_viewer("tabedit") 420 | 421 | """ Directory listing buffer management 422 | nnoremap (FileBeagleBufferRefresh) :call b:filebeagle_directory_viewer.refresh() 423 | let l:default_normal_plug_map['FileBeagleBufferRefresh'] = 'R' 424 | nnoremap (FileBeagleBufferSetFilter) :call b:filebeagle_directory_viewer.set_filter_exp() 425 | let l:default_normal_plug_map['FileBeagleBufferSetFilter'] = 'f' 426 | nnoremap (FileBeagleBufferToggleFilter) :call b:filebeagle_directory_viewer.toggle_filter() 427 | let l:default_normal_plug_map['FileBeagleBufferToggleFilter'] = 'F' 428 | nnoremap (FileBeagleBufferToggleHiddenAndIgnored) :call b:filebeagle_directory_viewer.toggle_hidden_and_ignored() 429 | let l:default_normal_plug_map['FileBeagleBufferToggleHiddenAndIgnored'] = 'gh' 430 | nnoremap (FileBeagleBufferQuit) :call b:filebeagle_directory_viewer.quit_buffer() 431 | let l:default_normal_plug_map['FileBeagleBufferQuit'] = 'q' 432 | nnoremap (FileBeagleBufferCloseWindow) :call b:filebeagle_directory_viewer.close_window() 433 | let l:default_normal_plug_map['FileBeagleBufferCloseWindow'] = '' 434 | 435 | """ Open selected file/directory 436 | nnoremap (FileBeagleBufferVisitTarget) :call b:filebeagle_directory_viewer.visit_target("edit", 0) 437 | let l:default_normal_plug_map['FileBeagleBufferVisitTarget'] = 'o' 438 | vnoremap (FileBeagleBufferVisitTarget) :call b:filebeagle_directory_viewer.visit_target("edit", 0) 439 | let l:default_visual_plug_map['FileBeagleBufferVisitTarget'] = 'o' 440 | nnoremap (FileBeagleBufferBgVisitTarget) :call b:filebeagle_directory_viewer.visit_target("edit", 1) 441 | let l:default_normal_plug_map['FileBeagleBufferBgVisitTarget'] = g:filebeagle_buffer_background_key_map_prefix . 'o' 442 | vnoremap (FileBeagleBufferBgVisitTarget) :call b:filebeagle_directory_viewer.visit_target("edit", 1) 443 | let l:default_visual_plug_map['FileBeagleBufferBgVisitTarget'] = g:filebeagle_buffer_background_key_map_prefix . 'o' 444 | 445 | """ Special case: 446 | nmap (FileBeagleBufferVisitTarget) 447 | vmap (FileBeagleBufferVisitTarget) 448 | execute "nmap " . g:filebeagle_buffer_background_key_map_prefix . " (FileBeagleBufferBgVisitTarget)" 449 | execute "vmap " . g:filebeagle_buffer_background_key_map_prefix . " (FileBeagleBufferBgVisitTarget)" 450 | 451 | nnoremap (FileBeagleBufferSplitVerticalVisitTarget) :call b:filebeagle_directory_viewer.visit_target("vert sp", 0) 452 | " let l:default_normal_plug_map['FileBeagleBufferSplitVerticalVisitTarget'] = 'v' 453 | let l:default_normal_plug_map['FileBeagleBufferSplitVerticalVisitTarget'] = '' 454 | vnoremap (FileBeagleBufferSplitVerticalVisitTarget) :call b:filebeagle_directory_viewer.visit_target("vert sp", 0) 455 | " let l:default_visual_plug_map['FileBeagleBufferSplitVerticalVisitTarget'] = 'v' 456 | let l:default_visual_plug_map['FileBeagleBufferSplitVerticalVisitTarget'] = '' 457 | nnoremap (FileBeagleBufferBgSplitVerticalVisitTarget) :call b:filebeagle_directory_viewer.visit_target("rightbelow vert sp", 1) 458 | let l:default_normal_plug_map['FileBeagleBufferBgSplitVerticalVisitTarget'] = g:filebeagle_buffer_background_key_map_prefix . 'v' 459 | vnoremap (FileBeagleBufferBgSplitVerticalVisitTarget) :call b:filebeagle_directory_viewer.visit_target("rightbelow vert sp", 1) 460 | let l:default_visual_plug_map['FileBeagleBufferBgSplitVerticalVisitTarget'] = g:filebeagle_buffer_background_key_map_prefix . 'v' 461 | 462 | nnoremap (FileBeagleBufferSplitVisitTarget) :call b:filebeagle_directory_viewer.visit_target("sp", 0) 463 | " let l:default_normal_plug_map['FileBeagleBufferSplitVisitTarget'] = 's' 464 | let l:default_normal_plug_map['FileBeagleBufferSplitVisitTarget'] = '' 465 | vnoremap (FileBeagleBufferSplitVisitTarget) :call b:filebeagle_directory_viewer.visit_target("sp", 0) 466 | " let l:default_visual_plug_map['FileBeagleBufferSplitVisitTarget'] = 's' 467 | let l:default_visual_plug_map['FileBeagleBufferSplitVisitTarget'] = '' 468 | nnoremap (FileBeagleBufferBgSplitVisitTarget) :call b:filebeagle_directory_viewer.visit_target("rightbelow sp", 1) 469 | let l:default_normal_plug_map['FileBeagleBufferBgSplitVisitTarget'] = g:filebeagle_buffer_background_key_map_prefix . 's' 470 | vnoremap (FileBeagleBufferBgSplitVisitTarget) :call b:filebeagle_directory_viewer.visit_target("rightbelow sp", 1) 471 | let l:default_visual_plug_map['FileBeagleBufferBgSplitVisitTarget'] = g:filebeagle_buffer_background_key_map_prefix . 's' 472 | 473 | nnoremap (FileBeagleBufferTabVisitTarget) :call b:filebeagle_directory_viewer.visit_target("tabedit", 0) 474 | " let l:default_normal_plug_map['FileBeagleBufferTabVisitTarget'] = 't' 475 | let l:default_normal_plug_map['FileBeagleBufferTabVisitTarget'] = '' 476 | vnoremap (FileBeagleBufferTabVisitTarget) :call b:filebeagle_directory_viewer.visit_target("tabedit", 0) 477 | " let l:default_visual_plug_map['FileBeagleBufferTabVisitTarget'] = 't' 478 | let l:default_visual_plug_map['FileBeagleBufferTabVisitTarget'] = '' 479 | nnoremap (FileBeagleBufferBgTabVisitTarget) :call b:filebeagle_directory_viewer.visit_target("tabedit", 1) 480 | let l:default_normal_plug_map['FileBeagleBufferBgTabVisitTarget'] = g:filebeagle_buffer_background_key_map_prefix . 't' 481 | vnoremap (FileBeagleBufferBgTabVisitTarget) :call b:filebeagle_directory_viewer.visit_target("tabedit", 1) 482 | let l:default_visual_plug_map['FileBeagleBufferBgTabVisitTarget'] = g:filebeagle_buffer_background_key_map_prefix . 't' 483 | 484 | """ Focal directory changing 485 | nnoremap (FileBeagleBufferFocusOnParent) :call b:filebeagle_directory_viewer.visit_parent_dir() 486 | let l:default_normal_plug_map['FileBeagleBufferFocusOnParent'] = '-' 487 | nnoremap (FileBeagleBufferFocusOnPrevious) :call b:filebeagle_directory_viewer.visit_prev_dir() 488 | let l:default_normal_plug_map['FileBeagleBufferFocusOnPrevious'] = 'b' 489 | nmap (FileBeagleBufferFocusOnPrevious) 490 | 491 | """ File operations 492 | nnoremap (FileBeagleBufferCreateNewFile) :call b:filebeagle_directory_viewer.new_file(b:filebeagle_directory_viewer.focus_dir, 1, 0) 493 | let l:default_normal_plug_map['FileBeagleBufferCreateNewFile'] = '+' 494 | nnoremap (FileBeagleBufferVisitNewFile) :call b:filebeagle_directory_viewer.new_file(b:filebeagle_directory_viewer.focus_dir, 0, 1) 495 | let l:default_normal_plug_map['FileBeagleBufferVisitNewFile'] = '%' 496 | nnoremap (FileBeagleBufferInsertTargetBelowCursor) :call b:filebeagle_directory_viewer.read_target("", 0) 497 | let l:default_normal_plug_map['FileBeagleBufferInsertTargetBelowCursor'] = 'r.' 498 | vnoremap (FileBeagleBufferInsertTargetBelowCursor) :call b:filebeagle_directory_viewer.read_target("", 0) 499 | let l:default_visual_plug_map['FileBeagleBufferInsertTargetBelowCursor'] = 'r.' 500 | nnoremap (FileBeagleBufferInsertTargetAtBeginning) :call b:filebeagle_directory_viewer.read_target("0", 0) 501 | let l:default_normal_plug_map['FileBeagleBufferInsertTargetAtBeginning'] = 'r0' 502 | vnoremap (FileBeagleBufferInsertTargetAtBeginning) :call b:filebeagle_directory_viewer.read_target("0", 0) 503 | let l:default_visual_plug_map['FileBeagleBufferInsertTargetAtBeginning'] = 'r0' 504 | nnoremap (FileBeagleBufferInsertTargetAtEnd) :call b:filebeagle_directory_viewer.read_target("$", 0) 505 | let l:default_normal_plug_map['FileBeagleBufferInsertTargetAtEnd'] = 'r$' 506 | vnoremap (FileBeagleBufferInsertTargetAtEnd) :call b:filebeagle_directory_viewer.read_target("$", 0) 507 | let l:default_visual_plug_map['FileBeagleBufferInsertTargetAtEnd'] = 'r$' 508 | nnoremap (FileBeagleBufferBgInsertTargetBelowCursor) :call b:filebeagle_directory_viewer.read_target("", 1) 509 | let l:default_normal_plug_map['FileBeagleBufferBgInsertTargetBelowCursor'] = g:filebeagle_buffer_background_key_map_prefix . 'r.' 510 | vnoremap (FileBeagleBufferBgInsertTargetBelowCursor) :call b:filebeagle_directory_viewer.read_target("", 1) 511 | let l:default_visual_plug_map['FileBeagleBufferBgInsertTargetBelowCursor'] = g:filebeagle_buffer_background_key_map_prefix . 'r.' 512 | nnoremap (FileBeagleBufferBgInsertTargetAtBeginning) :call b:filebeagle_directory_viewer.read_target("0", 1) 513 | let l:default_normal_plug_map['FileBeagleBufferBgInsertTargetAtBeginning'] = g:filebeagle_buffer_background_key_map_prefix . 'r0' 514 | vnoremap (FileBeagleBufferBgInsertTargetAtBeginning) :call b:filebeagle_directory_viewer.read_target("0", 1) 515 | let l:default_visual_plug_map['FileBeagleBufferBgInsertTargetAtBeginning'] = g:filebeagle_buffer_background_key_map_prefix . 'r0' 516 | nnoremap (FileBeagleBufferBgInsertTargetAtEnd) :call b:filebeagle_directory_viewer.read_target("$", 1) 517 | let l:default_normal_plug_map['FileBeagleBufferBgInsertTargetAtEnd'] = g:filebeagle_buffer_background_key_map_prefix . 'r$' 518 | vnoremap (FileBeagleBufferBgInsertTargetAtEnd) :call b:filebeagle_directory_viewer.read_target("$", 1) 519 | let l:default_visual_plug_map['FileBeagleBufferBgInsertTargetAtEnd'] = g:filebeagle_buffer_background_key_map_prefix . 'r$' 520 | 521 | """ Directory Operations 522 | nnoremap (FileBeagleBufferChangeVimWorkingDirectory) :call b:filebeagle_directory_viewer.change_vim_working_directory(0) 523 | let l:default_normal_plug_map['FileBeagleBufferChangeVimWorkingDirectory'] = 'cd' 524 | nnoremap (FileBeagleBufferChangeVimLocalDirectory) :call b:filebeagle_directory_viewer.change_vim_working_directory(1) 525 | let l:default_normal_plug_map['FileBeagleBufferChangeVimLocalDirectory'] = 'cl' 526 | nnoremap (FileBeagleBufferFocusHomeDirectory) :call b:filebeagle_directory_viewer.set_focus_dir(expand("~"), '', 0) 527 | let l:default_normal_plug_map['FileBeagleBufferFocusHomeDirectory'] = '~' 528 | 529 | if exists("g:filebeagle_buffer_normal_key_maps") 530 | call extend(l:default_normal_plug_map, g:filebeagle_buffer_normal_key_maps) 531 | endif 532 | 533 | for plug_name in keys(l:default_normal_plug_map) 534 | let plug_key = l:default_normal_plug_map[plug_name] 535 | if !empty(plug_key) 536 | execute "nmap " . plug_key . " (".plug_name.")" 537 | endif 538 | endfor 539 | 540 | if exists("g:filebeagle_buffer_visual_key_maps") 541 | call extend(l:default_visual_plug_map, g:filebeagle_buffer_visual_key_maps) 542 | endif 543 | 544 | for plug_name in keys(l:default_visual_plug_map) 545 | let plug_key = l:default_visual_plug_map[plug_name] 546 | if !empty(plug_key) 547 | execute "vmap " . plug_key . " (".plug_name.")" 548 | endif 549 | endfor 550 | 551 | else 552 | "" Legacy key maps 553 | 554 | """ Directory listing buffer management 555 | nnoremap r :call b:filebeagle_directory_viewer.refresh() 556 | nnoremap f :call b:filebeagle_directory_viewer.set_filter_exp() 557 | nnoremap F :call b:filebeagle_directory_viewer.toggle_filter() 558 | nnoremap gh :call b:filebeagle_directory_viewer.toggle_hidden_and_ignored() 559 | nnoremap q :call b:filebeagle_directory_viewer.quit_buffer() 560 | nnoremap c :call b:filebeagle_directory_viewer.close_window() 561 | nnoremap :call b:filebeagle_directory_viewer.close_window() 562 | 563 | """ Directory listing splitting 564 | nnoremap :call b:filebeagle_directory_viewer.new_viewer("vert sp") 565 | nnoremap v :call b:filebeagle_directory_viewer.new_viewer("vert sp") 566 | nnoremap V :call b:filebeagle_directory_viewer.new_viewer("vert sp") 567 | nnoremap :call b:filebeagle_directory_viewer.new_viewer("sp") 568 | nnoremap s :call b:filebeagle_directory_viewer.new_viewer("sp") 569 | nnoremap S :call b:filebeagle_directory_viewer.new_viewer("sp") 570 | nnoremap :call b:filebeagle_directory_viewer.new_viewer("tabedit") 571 | nnoremap t :call b:filebeagle_directory_viewer.new_viewer("tabedit") 572 | nnoremap T :call b:filebeagle_directory_viewer.new_viewer("tabedit") 573 | 574 | """ Open selected file/directory 575 | nnoremap :call b:filebeagle_directory_viewer.visit_target("edit", 0) 576 | vnoremap :call b:filebeagle_directory_viewer.visit_target("edit", 0) 577 | nnoremap o :call b:filebeagle_directory_viewer.visit_target("edit", 0) 578 | vnoremap o :call b:filebeagle_directory_viewer.visit_target("edit", 0) 579 | nnoremap g :call b:filebeagle_directory_viewer.visit_target("edit", 1) 580 | vnoremap g :call b:filebeagle_directory_viewer.visit_target("edit", 1) 581 | nnoremap go :call b:filebeagle_directory_viewer.visit_target("edit", 1) 582 | vnoremap go :call b:filebeagle_directory_viewer.visit_target("edit", 1) 583 | 584 | nnoremap v :call b:filebeagle_directory_viewer.visit_target("vert sp", 0) 585 | vnoremap v :call b:filebeagle_directory_viewer.visit_target("vert sp", 0) 586 | nnoremap :call b:filebeagle_directory_viewer.visit_target("vert sp", 0) 587 | vnoremap :call b:filebeagle_directory_viewer.visit_target("vert sp", 0) 588 | nnoremap gv :call b:filebeagle_directory_viewer.visit_target("rightbelow vert sp", 1) 589 | vnoremap gv :call b:filebeagle_directory_viewer.visit_target("rightbelow vert sp", 1) 590 | nnoremap g :call b:filebeagle_directory_viewer.visit_target("rightbelow vert sp", 1) 591 | vnoremap g :call b:filebeagle_directory_viewer.visit_target("rightbelow vert sp", 1) 592 | 593 | nnoremap s :call b:filebeagle_directory_viewer.visit_target("sp", 0) 594 | vnoremap s :call b:filebeagle_directory_viewer.visit_target("sp", 0) 595 | nnoremap :call b:filebeagle_directory_viewer.visit_target("sp", 0) 596 | vnoremap :call b:filebeagle_directory_viewer.visit_target("sp", 0) 597 | nnoremap gs :call b:filebeagle_directory_viewer.visit_target("rightbelow sp", 1) 598 | vnoremap gs :call b:filebeagle_directory_viewer.visit_target("rightbelow sp", 1) 599 | nnoremap g :call b:filebeagle_directory_viewer.visit_target("rightbelow sp", 1) 600 | vnoremap g :call b:filebeagle_directory_viewer.visit_target("rightbelow sp", 1) 601 | 602 | nnoremap t :call b:filebeagle_directory_viewer.visit_target("tabedit", 0) 603 | vnoremap t :call b:filebeagle_directory_viewer.visit_target("tabedit", 0) 604 | nnoremap :call b:filebeagle_directory_viewer.visit_target("tabedit", 0) 605 | vnoremap :call b:filebeagle_directory_viewer.visit_target("tabedit", 0) 606 | nnoremap g :call b:filebeagle_directory_viewer.visit_target("tabedit", 1) 607 | vnoremap g :call b:filebeagle_directory_viewer.visit_target("tabedit", 1) 608 | 609 | """ Focal directory changing 610 | nnoremap - :call b:filebeagle_directory_viewer.visit_parent_dir() 611 | nnoremap u :call b:filebeagle_directory_viewer.visit_parent_dir() 612 | nnoremap :call b:filebeagle_directory_viewer.visit_prev_dir() 613 | nnoremap b :call b:filebeagle_directory_viewer.visit_prev_dir() 614 | 615 | """ File operations 616 | nnoremap + :call b:filebeagle_directory_viewer.new_file(b:filebeagle_directory_viewer.focus_dir, 1, 0) 617 | nnoremap % :call b:filebeagle_directory_viewer.new_file(b:filebeagle_directory_viewer.focus_dir, 0, 1) 618 | nnoremap R :call b:filebeagle_directory_viewer.read_target("", 0) 619 | vnoremap R :call b:filebeagle_directory_viewer.read_target("", 0) 620 | nnoremap 0r :call b:filebeagle_directory_viewer.read_target("0", 0) 621 | vnoremap 0r :call b:filebeagle_directory_viewer.read_target("0", 0) 622 | nnoremap $r :call b:filebeagle_directory_viewer.read_target("$", 0) 623 | vnoremap $r :call b:filebeagle_directory_viewer.read_target("$", 0) 624 | nnoremap g0r :call b:filebeagle_directory_viewer.read_target("0", 1) 625 | vnoremap g0r :call b:filebeagle_directory_viewer.read_target("0", 1) 626 | nnoremap g$r :call b:filebeagle_directory_viewer.read_target("$", 1) 627 | vnoremap g$r :call b:filebeagle_directory_viewer.read_target("$", 1) 628 | nnoremap gr :call b:filebeagle_directory_viewer.read_target("", 1) 629 | vnoremap gr :call b:filebeagle_directory_viewer.read_target("", 1) 630 | 631 | """ Directory Operations 632 | nnoremap cd :call b:filebeagle_directory_viewer.change_vim_working_directory(0) 633 | nnoremap cl :call b:filebeagle_directory_viewer.change_vim_working_directory(1) 634 | 635 | endif 636 | 637 | """ Movement keys 638 | if g:filebeagle_buffer_map_movement_keys 639 | map h (FileBeagleBufferFocusOnParent) 640 | map l (FileBeagleBufferVisitTarget) 641 | endif 642 | 643 | 644 | endfunction 645 | 646 | " Sets buffer status line. 647 | function! directory_viewer.setup_buffer_statusline() dict 648 | if has("statusline") 649 | let self.old_statusline=&l:statusline 650 | let &l:statusline = g:filebeagle_statusline 651 | else 652 | let self.old_statusline="" 653 | endif 654 | endfunction 655 | 656 | " Populates the buffer with the catalog index. 657 | function! directory_viewer.render_buffer() dict 658 | setlocal modifiable 659 | call self.clear_buffer() 660 | let self.jump_map = {} 661 | call self.setup_buffer_syntax() 662 | let paths = s:discover_paths(self.focus_dir, "*", self.is_include_hidden, self.is_include_ignored) 663 | for path in paths[0] + paths[1] 664 | if !path.is_dir && self.is_filtered && !empty(self.filter_exp) && (path["basename"] !~# self.filter_exp) 665 | continue 666 | endif 667 | let l:line_map = { 668 | \ "full_path" : path["full_path"], 669 | \ "basename" : path["basename"], 670 | \ "dirname" : path["dirname"], 671 | \ "is_dir" : path["is_dir"] 672 | \ } 673 | let text = path["basename"] 674 | if path["is_dir"] 675 | let text .= s:sep 676 | endif 677 | let self.jump_map[line("$")] = l:line_map 678 | call append(line("$")-1, text) 679 | endfor 680 | let b:filebeagle_last_render_time = localtime() 681 | try 682 | " remove extra last line 683 | execute('normal! GV"_X') 684 | catch // 685 | endtry 686 | setlocal nomodifiable 687 | call cursor(1, 1) 688 | if has("title") 689 | let &titlestring = expand(self.focus_dir) 690 | endif 691 | let self.default_targets_for_directory[self.focus_dir] = self.focus_file 692 | call self.goto_pattern(self.focus_file) 693 | endfunction 694 | 695 | " Restore title and anything else changed 696 | function! directory_viewer.wipe_and_restore() dict 697 | try 698 | execute "bwipe! " . self.buf_num 699 | catch // " E517: No buffers were wiped out 700 | endtry 701 | if has("statusline") && exists("self['old_statusline']") 702 | try 703 | let &l:statusline=self.old_statusline 704 | catch // 705 | endtry 706 | endif 707 | if has("title") 708 | let &titlestring = self.old_titlestring 709 | endif 710 | endfunction 711 | 712 | " Close and quit the viewer. 713 | function! directory_viewer.quit_buffer() dict 714 | " if !isdirectory(bufname(self.prev_buf_num)) 715 | " if self.prev_buf_num == self.buf_num 716 | " " Avoid switching back to calling buffer if it is a (FileBeagle) directory 717 | " call s:_filebeagle_messenger.send_info("Directory buffer was created by Vim, not FileBeagle: type ':quit' to exit or ':bwipe' to delete") 718 | " else 719 | " execute "b " . self.prev_buf_num 720 | " endif 721 | if self.prev_buf_num != self.buf_num 722 | execute "silent keepalt keepjump b " . self.prev_buf_num 723 | endif 724 | call self.wipe_and_restore() 725 | endfunction 726 | 727 | " Close and quit the viewer. 728 | function! directory_viewer.close_window() dict 729 | execute "bwipe" 730 | " if self.prev_buf_num != self.buf_num 731 | " execute "b " . self.prev_buf_num 732 | " endif 733 | " call self.wipe_and_restore() 734 | " :close 735 | endfunction 736 | 737 | " Clears the buffer contents. 738 | function! directory_viewer.clear_buffer() dict 739 | call cursor(1, 1) 740 | exec 'silent! normal! "_dG' 741 | endfunction 742 | 743 | function! directory_viewer.read_target(pos, read_in_background) dict range 744 | if self.prev_buf_num == self.buf_num || isdirectory(bufname(self.prev_buf_num)) 745 | call s:_filebeagle_messenger.send_error("Cannot read into a directory buffer") 746 | return 0 747 | endif 748 | if v:count == 0 749 | let l:start_line = a:firstline 750 | let l:end_line = a:lastline 751 | else 752 | let l:start_line = v:count 753 | let l:end_line = v:count 754 | endif 755 | let l:selected_entries = [] 756 | for l:cur_line in range(l:start_line, l:end_line) 757 | if !has_key(self.jump_map, l:cur_line) 758 | call s:_filebeagle_messenger.send_info("Line " . l:cur_line . " is not a valid navigation entry") 759 | return 0 760 | endif 761 | if self.jump_map[l:cur_line].is_dir 762 | call s:_filebeagle_messenger.send_info("Reading directories into the current buffer is not supported at the current time") 763 | return 0 764 | endif 765 | call add(l:selected_entries, self.jump_map[l:cur_line]) 766 | endfor 767 | if a:pos == "0" 768 | call reverse(l:selected_entries) 769 | endif 770 | let old_lazyredraw = &lazyredraw 771 | set lazyredraw 772 | execute "silent keepalt keepjumps buffer " . self.prev_buf_num 773 | for l:entry in l:selected_entries 774 | let l:path_to_open = fnameescape(l:entry.full_path) 775 | execute a:pos . "r " . l:path_to_open 776 | endfor 777 | if a:read_in_background 778 | execute "silent keepalt keepjumps buffer " .self.buf_num 779 | else 780 | call self.wipe_and_restore() 781 | endif 782 | let &lazyredraw = l:old_lazyredraw 783 | endfunction 784 | 785 | function! directory_viewer.new_viewer(split_cmd) dict 786 | let l:cur_tab_num = tabpagenr() 787 | execute "silent keepalt keepjumps " . a:split_cmd . " " . bufname(self.prev_buf_num) 788 | let directory_viewer = s:NewDirectoryViewer() 789 | call directory_viewer.open_dir( 790 | \ -1, 791 | \ self.focus_dir, 792 | \ self.focus_file, 793 | \ self.prev_buf_num, 794 | \ self.prev_focus_dirs, 795 | \ self.default_targets_for_directory, 796 | \ self.is_filtered, 797 | \ self.filter_exp, 798 | \ self.is_include_hidden, 799 | \ self.is_include_ignored 800 | \ ) 801 | endfunction 802 | 803 | function! directory_viewer.visit_target(split_cmd, open_in_background) dict range 804 | if v:count == 0 805 | let l:start_line = a:firstline 806 | let l:end_line = a:lastline 807 | else 808 | let l:start_line = v:count 809 | let l:end_line = v:count 810 | endif 811 | 812 | let l:num_dir_targets = 0 813 | let l:selected_entries = [] 814 | for l:cur_line in range(l:start_line, l:end_line) 815 | if !has_key(self.jump_map, l:cur_line) 816 | call s:_filebeagle_messenger.send_info("Line " . l:cur_line . " is not a valid navigation entry") 817 | return 0 818 | endif 819 | if self.jump_map[l:cur_line].is_dir 820 | let l:num_dir_targets += 1 821 | endif 822 | call add(l:selected_entries, self.jump_map[l:cur_line]) 823 | endfor 824 | 825 | if l:num_dir_targets > 1 || (l:num_dir_targets == 1 && len(l:selected_entries) > 1) 826 | call s:_filebeagle_messenger.send_info("Cannot open multiple selections that include directories") 827 | return 0 828 | endif 829 | 830 | if l:num_dir_targets == 1 831 | let l:cur_tab_num = tabpagenr() 832 | let l:entry = l:selected_entries[0] 833 | let l:target = l:entry.full_path 834 | if !isdirectory(l:target) 835 | call s:_filebeagle_messenger.send_error("Cannot open directory: '" . l:target . "'") 836 | return 0 837 | endif 838 | if l:entry.basename == ".." 839 | let new_focus_file = s:base_dirname(self.focus_dir) 840 | elseif a:split_cmd == "edit" 841 | let new_focus_file = get(self.default_targets_for_directory, l:target, "") 842 | " echo "Current (" . l:target . "): " . new_focus_file 843 | " for key in keys(self.default_targets_for_directory) 844 | " echo "'".key."':'".self.default_targets_for_directory[key]."'" 845 | " endfor 846 | else 847 | let new_focus_file = l:target 848 | endif 849 | if a:split_cmd == "edit" 850 | call self.set_focus_dir(l:target, new_focus_file, 1) 851 | else 852 | if a:open_in_background 853 | if a:split_cmd == "tabedit" 854 | " execute "silent keepalt keepjumps " . a:split_cmd . " " . self.buf_name 855 | execute "silent keepalt keepjumps " . a:split_cmd . " " . bufname(self.prev_buf_num) 856 | else 857 | execute "silent keepalt keepjumps " . a:split_cmd 858 | endif 859 | else 860 | execute "silent keepalt keepjumps " . a:split_cmd . " " . bufname(self.prev_buf_num) 861 | endif 862 | let directory_viewer = s:NewDirectoryViewer() 863 | call directory_viewer.open_dir( 864 | \ -1, 865 | \ l:target, 866 | \ new_focus_file, 867 | \ self.prev_buf_num, 868 | \ self.prev_focus_dirs, 869 | \ self.default_targets_for_directory, 870 | \ self.is_filtered, 871 | \ self.filter_exp, 872 | \ self.is_include_hidden, 873 | \ self.is_include_ignored 874 | \ ) 875 | if a:open_in_background 876 | execute "tabnext " . l:cur_tab_num 877 | execute bufwinnr(self.buf_num) . "wincmd w" 878 | endif 879 | endif 880 | else 881 | call self.visit_files(l:selected_entries, a:split_cmd, a:open_in_background) 882 | endif 883 | endfunction 884 | 885 | function! directory_viewer.set_focus_dir(new_dir, focus_file, add_to_history) dict 886 | if a:add_to_history && exists("self['focus_dir']") 887 | if empty(self.prev_focus_dirs) || self.prev_focus_dirs[-1][0] != self.focus_dir 888 | call add(self.prev_focus_dirs, [self.focus_dir, self.focus_file]) 889 | endif 890 | endif 891 | let self.focus_dir = fnamemodify(a:new_dir, ":p") 892 | let self.focus_file = a:focus_file 893 | call self.refresh() 894 | endfunction 895 | 896 | function! directory_viewer.visit_files(selected_entries, split_cmd, open_in_background) 897 | if len(a:selected_entries) < 1 898 | return 899 | endif 900 | let l:cur_tab_num = tabpagenr() 901 | let old_lazyredraw = &lazyredraw 902 | set lazyredraw 903 | let l:split_cmd = a:split_cmd 904 | if !a:open_in_background 905 | execute "silent keepalt keepjumps buffer " . self.prev_buf_num 906 | endif 907 | let l:opened_basenames = [] 908 | for l:entry in a:selected_entries 909 | let l:path_to_open = fnameescape(l:entry.full_path) 910 | try 911 | execute l:split_cmd . " " . l:path_to_open 912 | catch /E37:/ 913 | " E37: No write since last change 914 | " skip opening file 915 | catch /E36:/ 916 | " E36: not enough room for any new splits: switch to 917 | " opening in-situ 918 | let l:split_cmd = "edit" 919 | try 920 | execute l:split_cmd . " " . l:path_to_open 921 | catch /E325:/ "swap file exists 922 | endtry 923 | catch /E325:/ "swap file exists 924 | endtry 925 | call add(l:opened_basenames, '"' . fnameescape(l:entry.basename) . '"') 926 | endfor 927 | if a:open_in_background 928 | execute "tabnext " . l:cur_tab_num 929 | execute bufwinnr(self.buf_num) . "wincmd w" 930 | if a:split_cmd == "edit" 931 | execute "silent keepalt keepjumps buffer " .self.buf_num 932 | endif 933 | redraw! 934 | if a:split_cmd == "edit" 935 | " It makes sense (to me, at least) to go to the last buffer 936 | " selected & opened upon closing FileBeagle when in this 937 | " combination of modes (i.e., split = 'edit' and in 938 | " background) 939 | let new_prev_buf_num = bufnr(a:selected_entries[-1].full_path) 940 | if new_prev_buf_num > 0 941 | let self.prev_buf_num = new_prev_buf_num 942 | endif 943 | if len(l:opened_basenames) > 1 944 | " Opening multiple in background of same window is a little 945 | " cryptic so in this special case, we issue some feedback 946 | echo join(l:opened_basenames, ", ") 947 | endif 948 | endif 949 | else 950 | call self.wipe_and_restore() 951 | redraw! 952 | endif 953 | let &lazyredraw = l:old_lazyredraw 954 | endfunction 955 | 956 | function! directory_viewer.visit_parent_dir() dict 957 | let pdir = s:parent_dir(self.focus_dir) 958 | if pdir != self.focus_dir 959 | let new_focus_file = s:base_dirname(self.focus_dir) 960 | call self.set_focus_dir(pdir, new_focus_file, 1) 961 | else 962 | call s:_filebeagle_messenger.send_info("No parent directory available") 963 | endif 964 | endfunction 965 | 966 | function! directory_viewer.visit_prev_dir() dict 967 | " if len(self.prev_focus_dirs) == 0 968 | if empty(self.prev_focus_dirs) 969 | call s:_filebeagle_messenger.send_info("No previous directory available") 970 | else 971 | let new_focus_dir = self.prev_focus_dirs[-1][0] 972 | let new_focus_file = self.prev_focus_dirs[-1][1] 973 | call remove(self.prev_focus_dirs, -1) 974 | call self.set_focus_dir(new_focus_dir, new_focus_file, 0) 975 | endif 976 | endfunction 977 | 978 | function! directory_viewer.yank_target_name(part, register) dict 979 | let l:cur_line = line(".") 980 | if !has_key(self.jump_map, l:cur_line) 981 | call s:_filebeagle_messenger.send_info("Not a valid path") 982 | return 0 983 | endif 984 | if a:part == "dirname" 985 | let l:target = self.jump_map[line(".")].dirname 986 | elseif a:part == "basename" 987 | let l:target = self.jump_map[line(".")].basename 988 | else 989 | let l:target = self.jump_map[line(".")].full_path 990 | endif 991 | execute "let @" . a:register . " = '" . fnameescape(l:target) . "'" 992 | endfunction 993 | 994 | function! directory_viewer.yank_current_dirname(register) dict 995 | execute "let @" . a:register . " = '" . fnameescape(self.focus_dir) . "'" 996 | endfunction 997 | 998 | function! directory_viewer.change_vim_working_directory(local) dict 999 | let l:target = self.focus_dir 1000 | if a:local 1001 | let l:cmd = "lcd" 1002 | else 1003 | let l:cmd = "cd" 1004 | endif 1005 | execute "b " . self.prev_buf_num 1006 | call self.wipe_and_restore() 1007 | execute l:cmd . " " . fnameescape(l:target) 1008 | echomsg l:target 1009 | endfunction 1010 | 1011 | function! directory_viewer.yank_current_dirname(register) dict 1012 | execute "let @" . a:register . " = '" . fnameescape(self.focus_dir) . "'" 1013 | endfunction 1014 | 1015 | function! directory_viewer.prefill_command(cmd, bang) dict range 1016 | if v:count == 0 1017 | let l:start_line = a:firstline 1018 | let l:end_line = a:lastline 1019 | else 1020 | let l:start_line = v:count 1021 | let l:end_line = v:count 1022 | endif 1023 | 1024 | let l:num_dir_targets = 0 1025 | let l:selected_entries = [] 1026 | for l:cur_line in range(l:start_line, l:end_line) 1027 | call add(l:selected_entries, self.jump_map[l:cur_line]) 1028 | endfor 1029 | 1030 | let l:filepaths = map(copy(l:selected_entries), 'v:val.full_path') 1031 | echo l:filepaths 1032 | 1033 | if a:bang 1034 | execute a:cmd join(l:filepaths) 1035 | else 1036 | call feedkeys(":" . a:cmd . " " . join(l:filepaths), "n") 1037 | endif 1038 | 1039 | endfunction 1040 | 1041 | function! directory_viewer.refresh() dict 1042 | silent! doautocmd User FileBeagleRefreshPre 1043 | call self.render_buffer() 1044 | silent! doautocmd User FileBeagleRefreshPost 1045 | endfunction 1046 | 1047 | function! directory_viewer.goto_pattern(pattern) dict 1048 | " call cursor(1, 0) 1049 | " let old_ignorecase = &ignorecase 1050 | " set noignorecase 1051 | let full_pattern = '^\V\C' . escape(a:pattern, '/\') . '\$' 1052 | call search(full_pattern, "cw") 1053 | " let &ignorecase = old_ignorecase 1054 | " call cursor(lnum, 0) 1055 | endfunction 1056 | 1057 | function! directory_viewer.new_file(parent_dir, create, open) dict 1058 | call inputsave() 1059 | let new_fname = input("Add file: ".a:parent_dir, "", "custom,FileBeagleCompleteNewFileName") 1060 | call inputrestore() 1061 | if !empty(new_fname) 1062 | let new_fpath = a:parent_dir . new_fname 1063 | if a:create 1064 | if isdirectory(new_fpath) 1065 | call s:_filebeagle_messenger.send_error("Directory already exists: '" . new_fpath . "'") 1066 | elseif s:is_path_exists(new_fpath) 1067 | call s:_filebeagle_messenger.send_error("File already exists: '" . new_fpath . "'") 1068 | else 1069 | if new_fpath[-1:] =~ '[/\\]' 1070 | call mkdir(new_fpath, 'p') 1071 | else 1072 | let l:path = fnamemodify(new_fpath, ":p:h") 1073 | if !isdirectory(l:path) 1074 | call mkdir(l:path, 'p') 1075 | endif 1076 | call writefile([], new_fpath) 1077 | endif 1078 | call self.refresh() 1079 | endif 1080 | endif 1081 | if a:open 1082 | let entry = { "full_path": new_fpath, "basename" : new_fname, "dirname" : a:parent_dir, "is_dir": 0} 1083 | call self.visit_files([entry], "edit", 0) 1084 | else 1085 | call self.goto_pattern(new_fname) 1086 | endif 1087 | endif 1088 | endfunction 1089 | 1090 | function! directory_viewer.set_filter_exp() dict 1091 | let self.filter_exp = input("Filter expression: ", self.filter_exp) 1092 | if empty(self.filter_exp) 1093 | let self.is_filtered = 0 1094 | call s:_filebeagle_messenger.send_info("Filter OFF") 1095 | else 1096 | let self.is_filtered = 1 1097 | call s:_filebeagle_messenger.send_info("Filter ON") 1098 | endif 1099 | call self.refresh() 1100 | endfunction 1101 | 1102 | function! directory_viewer.toggle_filter() dict 1103 | if self.is_filtered 1104 | let self.is_filtered = 0 1105 | call s:_filebeagle_messenger.send_info("Filter OFF") 1106 | call self.refresh() 1107 | else 1108 | if !empty(self.filter_exp) 1109 | let self.is_filtered = 1 1110 | call s:_filebeagle_messenger.send_info("Filter ON") 1111 | call self.refresh() 1112 | else 1113 | call self.set_filter_exp() 1114 | endif 1115 | endif 1116 | endfunction 1117 | 1118 | function! directory_viewer.toggle_hidden_and_ignored() dict 1119 | if self.is_include_hidden || self.is_include_ignored 1120 | let self.is_include_hidden = 0 1121 | let self.is_include_ignored = 0 1122 | call s:_filebeagle_messenger.send_info("Not showing hidden/ignored files") 1123 | else 1124 | let self.is_include_hidden = 1 1125 | let self.is_include_ignored = 1 1126 | call s:_filebeagle_messenger.send_info("Showing hidden/ignored files") 1127 | endif 1128 | call self.refresh() 1129 | endfunction 1130 | 1131 | " return object 1132 | return directory_viewer 1133 | 1134 | endfunction 1135 | 1136 | " }}}1 1137 | 1138 | " Status Line Functions {{{1 1139 | " ============================================================================== 1140 | 1141 | function! FileBeagleStatusLineCurrentDirInfo() 1142 | return exists("b:filebeagle_directory_viewer") ? b:filebeagle_directory_viewer.focus_dir : '' 1143 | endfunction 1144 | 1145 | function! FileBeagleStatusLineHiddenInfo(...) 1146 | if !exists('b:filebeagle_directory_viewer') 1147 | return '' 1148 | endif 1149 | let l:label_hidden_dotfiles = get(a:000, 0, 'dotfiles') 1150 | let l:label_hidden_wildignore = get(a:000, 1, 'wildignore') 1151 | let l:label_separator = get(a:000, 2, ', ') 1152 | let l:status_line = [] 1153 | if empty(b:filebeagle_directory_viewer.is_include_hidden) 1154 | call add(l:status_line, l:label_hidden_dotfiles) 1155 | endif 1156 | if empty(b:filebeagle_directory_viewer.is_include_ignored) && !empty(&wildignore) 1157 | call add(l:status_line, l:label_hidden_wildignore) 1158 | endif 1159 | return join(l:status_line, l:label_separator) 1160 | endfunction 1161 | 1162 | function! FileBeagleStatusLineFilterInfo() 1163 | return exists("b:filebeagle_directory_viewer") && b:filebeagle_directory_viewer.is_filtered && !empty(b:filebeagle_directory_viewer.filter_exp) 1164 | \ ? b:filebeagle_directory_viewer.filter_exp : '' 1165 | endfunction 1166 | 1167 | function! FileBeagleStatusLineFilterAndHiddenInfo() 1168 | if !exists("b:filebeagle_directory_viewer") 1169 | return "" 1170 | endif 1171 | let l:status_line = "" 1172 | if !empty(FileBeagleStatusLineHiddenInfo()) 1173 | let l:status_line .= "[+HIDE]" 1174 | endif 1175 | if !empty(FileBeagleStatusLineFilterInfo()) 1176 | let l:status_line .= "[+FILTER:" . FileBeagleStatusLineFilterInfo() . "]" 1177 | endif 1178 | return l:status_line 1179 | endfunction 1180 | " }}}1 1181 | 1182 | " Command Interface {{{1 1183 | " ============================================================================= 1184 | 1185 | function! filebeagle#FileBeagleOpen(focus_dir, filebeagle_buf_num) 1186 | if exists("b:filebeagle_directory_viewer") 1187 | call s:_filebeagle_messenger.send_info("Use 'CTRL-W CTRL-V' or 'CTRL-W CTRL-S' to spawn a new FileBeagle viewer on the current directory") 1188 | return 1189 | endif 1190 | let directory_viewer = s:NewDirectoryViewer() 1191 | if empty(a:focus_dir) 1192 | let focus_dir = getcwd() 1193 | else 1194 | let focus_dir = fnamemodify(a:focus_dir, ":p") 1195 | endif 1196 | if !isdirectory(focus_dir) 1197 | call s:_filebeagle_messenger.send_error("Not a valid directory: '" . focus_dir . "'") 1198 | else 1199 | call directory_viewer.open_dir( 1200 | \ a:filebeagle_buf_num, 1201 | \ focus_dir, 1202 | \ bufname("%"), 1203 | \ bufnr("%"), 1204 | \ [], 1205 | \ {}, 1206 | \ 0, 1207 | \ "", 1208 | \ g:filebeagle_show_hidden, 1209 | \ g:filebeagle_show_hidden 1210 | \) 1211 | endif 1212 | endfunction 1213 | 1214 | function! filebeagle#FileBeagleOpenCurrentBufferDir() 1215 | if exists("b:filebeagle_directory_viewer") 1216 | call s:_filebeagle_messenger.send_info("Use 'CTRL-W CTRL-V' or 'CTRL-W CTRL-S' to spawn a new FileBeagle viewer on the current directory") 1217 | return 1218 | endif 1219 | if empty(expand("%")) 1220 | call filebeagle#FileBeagleOpen(getcwd(), -1) 1221 | else 1222 | let directory_viewer = s:NewDirectoryViewer() 1223 | let focus_dir = expand('%:p:h') 1224 | call directory_viewer.open_dir( 1225 | \ -1, 1226 | \ focus_dir, 1227 | \ bufname("%"), 1228 | \ bufnr("%"), 1229 | \ [], 1230 | \ {}, 1231 | \ 0, 1232 | \ "", 1233 | \ g:filebeagle_show_hidden, 1234 | \ g:filebeagle_show_hidden 1235 | \) 1236 | endif 1237 | endfunction 1238 | 1239 | " }}}1 1240 | 1241 | " Global Initialization {{{1 1242 | " ============================================================================== 1243 | if exists("s:_filebeagle_messenger") 1244 | unlet s:_filebeagle_messenger 1245 | endif 1246 | let s:_filebeagle_messenger = s:NewMessenger("") 1247 | " }}}1 1248 | 1249 | " Restore State {{{1 1250 | " ============================================================================ 1251 | " restore options 1252 | let &cpo = s:save_cpo 1253 | " }}}1 1254 | 1255 | " vim:foldlevel=4: 1256 | -------------------------------------------------------------------------------- /doc/filebeagle.txt: -------------------------------------------------------------------------------- 1 | *filebeagle.txt* For Vim version 7.3 Last change: 2014 May 31 2 | 3 | =============================================================================== 4 | *filebeagle* *filebeagle-contents* 5 | CONTENTS~ 6 | 7 | 1. Invocation Commands ................... |filebeagle-invocation-commands| 8 | 2. Invocation Key Mappings ............... |filebeagle-invocation-key-maps| 9 | 3. Directory Buffer Key Mappings ......... |filebeagle-buffer-key-maps| 10 | 3.1 Directory Listing and View ........ |filebeagle-listing-view| 11 | 3.2 Opening Files and Directories ..... |filebeagle-opening-files| 12 | 3.3 Reading/Inserting Files ........... |filebeagle-inserting-files| 13 | 3.4 Setting the Vim Directories ....... |filebeagle-set-vim-directory| 14 | 4. Directory Buffer Commands ............. |filebeagle-buffer-commands| 15 | 5. Options and Settings .................. |filebeagle-options| 16 | 6. Custom Autocommands ................... |filebeagle-autocommands| 17 | 18 | =============================================================================== 19 | *filebeagle-invocation-commands* 20 | INVOCATION COMMANDS~ 21 | 22 | :FileBeagleBufferDir *:FileBeagleBufferDir* 23 | Open the FileBeagle directory buffer on the directory of the current 24 | buffer. 25 | 26 | :FileBeagle [{path}] *:FileBeagle* 27 | Open the FileBeagle directory buffer on {path} or current working directory 28 | if {path} is not given. 29 | 30 | =============================================================================== 31 | *filebeagle-invocation-key-maps* 32 | INVOCATION KEY MAPPINGS~ 33 | 34 | These are key mappings to invoke FileBeagle from a normal Vim Buffer. By 35 | default (unless |g:filebeagle_suppress_keymaps| is defined to be 1), the 36 | following key maps are provided: 37 | 38 | - Invokes ":FileBeagleBufferDir": open the directory buffer 39 | on the directory of the current buffer. 40 | 41 | f Invokes ":FileBeagle" with no arguments: open the directory buffer 42 | on the current working directory. 43 | 44 | If you want to define your own key mappings, then add something like the 45 | following to your '~/.vimrc': 46 | > 47 | let g:filebeagle_suppress_keymaps = 1 48 | map f FileBeagleOpenCurrentWorkingDir 49 | map - FileBeagleOpenCurrentBufferDir 50 | > 51 | The above replicate the default key mappings. You should, of course, 52 | substitute 'f' and '-' for whatever you prefer. 53 | 54 | =============================================================================== 55 | *filebeagle-buffer-key-maps* 56 | FILEBEAGLE BUFFER KEY MAPPINGS~ 57 | 58 | These are key mappings available from within the FileBeagle directory buffer. 59 | They provide ways to open files or directories, or change the current focal 60 | directory (i.e., the directory being viewed). 61 | 62 | ------------------------------------------------------------------------------- 63 | *filebeagle-listing-view* 64 | Directory Listing and View~ 65 | 66 | R Refresh the directory listing. 67 | f Define and apply a regular expression filter for the file 68 | entries. 69 | F Toggle application of the regular expression filter. 70 | gh Toggle showing of hidden/(wild-)ignored files. 71 | - Move up to the parent directory of the current focal 72 | directory. 73 | Go back to the previous directory in the directory history. 74 | q Quit and delete the FileBeagle buffer. 75 | ~ Goto home directory 76 | 77 | ------------------------------------------------------------------------------- 78 | *filebeagle-opening-files* 79 | Opening Files and Directories~ 80 | 81 | +---------------------------+------------+------------+ 82 | | Action* | Foreground | Background | 83 | +---------------------------+------------+------------+ 84 | | Open in Current Window | o | po | 85 | | Open in Horizontal Split | s | ps | 86 | | Open in Vertical Split | v | pv | 87 | | Open in Tab Page | t | pt | 88 | +---------------------------+------------+------------+ 89 | * If multiple files are selected in visual mode, the 90 | action will be carried out on all visually-selected 91 | files. The action can also take an optional {count}, 92 | which specifies that the action will be carried out on 93 | the file listed at line {count} of the FileBeagle 94 | buffer, regardless of where the cursor is. 95 | 96 | (NOTE: THE KEY MAPPINGS IN THE DIRECTORY BUFFER HAVE CHANGED RADICALLY 97 | FROM THE PREVIOUS VERSION. IF YOU PREFER THE OLD SCHEME THEN SEE 98 | |filebeagle_buffer_legacy_key_maps|.) 99 | 100 | The basic set of key maps allow for the the opening of the file or directory 101 | under the cursor, either in the current window or split, or a new horizontal 102 | split, vertical split, or tab page. 103 | 104 | If there is a visual selection active, then instead of the file currently 105 | under the cursor, all selected files will be targeted for the action invoked 106 | by the key mapping. For example, if there are four files highlighted in a 107 | visual selection, then '`v`' will result in four vertical splits being 108 | created, with each one of the selected files being opened in its own split. 109 | 110 | Alternatively, all key maps to open files or directory can take an optional 111 | {count}, which specifies the file or directory to open in terms of the line 112 | number in which it is listed. So, for example, while '`v`' will open the file 113 | or directory currently listed at the current cursor line in a new vertical 114 | split, '`42v`' will open the file or directory at line 42 in a new vertical 115 | split, regardless of where the cursor is. 116 | 117 | All actions can be carried out with FileBeagle in a "pinned mode" by 118 | initiating the key sequence with '`p`'. With FileBeagle in "pinned mode", the 119 | action is carried out in the background: i.e., the files are opened with the 120 | FileBeagle buffer remaining open and in focus. So, for example, '`pv`' will 121 | open the file under the cursor in a new vertical split, while keeping the 122 | FileBeagle buffer open and in focus. This can also be used with multiple files 123 | visually-selected to open all of them in the background in new vertical 124 | splits, or a {count} to open a file/directory at a specific line. 125 | 126 | 127 | o Open the file or directory under the cursor in the current 128 | window. Multiple files can be opened simultaneously by 129 | selecting them in visual mode. 130 | {count} 131 | {count}o Open the file or directory at line {count} in the current 132 | window. 133 | p 134 | po Open the file or directory under the cursor in the current 135 | window in the background. Multiple files can be opened 136 | simultaneously by selecting them in visual mode. 137 | {count}p 138 | {count}po Open the file or directory at line {count} in the current 139 | window in the background. 140 | 141 | 142 | v Open the currently selected file or directory in a new 143 | vertical split. Multiple files can be opened simultaneously by 144 | selecting them in visual mode. 145 | {count}v Open the file or directory at line {count} in a new 146 | pv Open the file or directory under the cursor in a new vertical 147 | split in the background. Multiple files can be opened 148 | simultaneously by selecting them in visual mode. 149 | {count}pv Open the file or directory at line {count} in a new 150 | vertical split in the background. 151 | vertical split. 152 | 153 | 154 | s Open the currently selected file or directory in a new 155 | horizontal split. Multiple files can be opened simultaneously 156 | by selecting them in visual mode. 157 | {count}s Open the file or directory at line {count} in a new horizontal 158 | split. 159 | ps Open the file or directory under the cursor in a new 160 | horizontal split in the background. Multiple files can be 161 | opened simultaneously by selecting them in visual mode. 162 | {count}ps Open the file or directory at line {count} in a new horizontal 163 | split in the background. 164 | 165 | 166 | t Open the currently selected file in a new tab. Multiple files 167 | can be opened simultaneously by selecting them in visual mode. 168 | {count}t Open the file or directory at line {count} in a new tab. 169 | pt Open the file or directory under the cursor in a new tab in 170 | the background. Multiple files can be opened simultaneously 171 | by selecting them in visual mode. 172 | {count}pt Open the file or directory at line {count} in a new tab in 173 | the background. 174 | 175 | ------------------------------------------------------------------------------- 176 | *filebeagle-inserting-files* 177 | Reading/Inserting Files~ 178 | 179 | +---------------------------+------------+------------+ 180 | | Action* | Foreground | Background | 181 | +---------------------------+------------+------------+ 182 | | Read/Insert Below Current | r. | pr. | 183 | | Read/Insert at Beginning | r0 | pr0 | 184 | | Read/Insert at End | r$ | pr$ | 185 | +---------------------------+------------+------------+ 186 | * If multiple files are selected in visual mode, the 187 | action will be carried out on all visually-selected 188 | files. The action can also take an optional {count}, 189 | which specifies that the action will be carried out on 190 | the file listed at line {count} of the FileBeagle 191 | buffer, regardless of where the cursor is. 192 | 193 | At the moment, only files can be read/inserted into the current (original) 194 | buffer. As above, the basic key maps ('`r.`', '`r0`', '`r$`', for insertion 195 | below current cursor line, at beginning of file, or end of file, respectively) 196 | can be modified by {count} to target a file at a specific line {count} in the 197 | FileBeagle buffer or prefixed by '`p`' to be carried out in "pinned" mode or 198 | the background. In addition, again as above, if a visual selection is active, 199 | the action will be carried out on all visually-selected files. 200 | 201 | 202 | r. Close FileBeagle and insert contents of the current or 203 | selected file(s) into original buffer at line below the 204 | current cursor position in the original buffer. 205 | {count}r. Close FileBeagle and insert contents of the file at line 206 | {count} into original buffer at line below the current cursor 207 | position in the original buffer. 208 | pr. Keep FileBeagle open and in focus, and insert contents of the 209 | current or selected file(s) into original buffer at line below 210 | the current cursor position in the original buffer. 211 | {count}pr. Keep FileBeagle open and in focus, and insert contents of the 212 | file at line {count} into original buffer at line below the 213 | current cursor position in the original buffer. 214 | 215 | r0 Close FileBeagle and insert contents of the current or 216 | selected file(s) into original buffer at the beginning of the 217 | buffer. 218 | {count}r0 Close FileBeagle and insert contents of the file at line 219 | {count} into original buffer at the beginning of the buffer. 220 | pr0 Keep FileBeagle open and in focus, and insert contents of the 221 | current or selected file(s) into original buffer the beginning. 222 | {count}pr0 Keep FileBeagle open and in focus, and insert contents of the 223 | file at line {count} into original buffer at the beginning of 224 | the buffer. 225 | 226 | r$ Close FileBeagle and insert contents of the current or 227 | selected file(s) into original buffer at the end of the buffer. 228 | {count}r$ Close FileBeagle and insert contents of the file at line 229 | {count} into original buffer at the end of the buffer. 230 | pr$ Keep FileBeagle open and in focus, and insert contents of the 231 | current or selected file(s) into original buffer at the end of 232 | the buffer. 233 | {count}pr$ Keep FileBeagle open and in focus, and insert contents of the 234 | file at line {count} into original buffer at the end of the 235 | buffer. 236 | 237 | ------------------------------------------------------------------------------- 238 | *filebeagle-adding-files* 239 | File Creation/Addition Operations~ 240 | 241 | + Add (create) a new file to FileBeagle's current focal 242 | directory. 243 | % Open a new empty buffer in FileBeagle's current focal 244 | directory. 245 | 246 | ------------------------------------------------------------------------------- 247 | *filebeagle-set-vim-directory* 248 | Setting the Vim Directories~ 249 | 250 | cd Change Vim working directory to FileBeagle's current focal 251 | directory. 252 | cl Change Vim local directory to FileBeagle's current focal 253 | directory. 254 | 255 | =============================================================================== 256 | *filebeagle-buffer-commands* 257 | FILEBEAGLE BUFFER COMMANDS~ 258 | 259 | The following commands are available from within the directory listing buffer: 260 | 261 | :ClipPathname 262 | Copy the full path of the currently selected file or directory to the system 263 | clipboard (i.e., the "+" register). 264 | 265 | :ClipDirname 266 | Copy the full path of the current focal directory (i.e., the directory 267 | currently listed) to the system clipboard (i.e., the "+" register). 268 | 269 | =============================================================================== 270 | *filebeagle-options* 271 | OPTIONS AND SETTINGS~ 272 | 273 | The list of file patterns to ignore can be controlled by setting 274 | |wildignore|. 275 | 276 | Other options are: 277 | 278 | g:filebeagle_suppress_keymaps~ *g:filebeagle_suppress_keymaps* 279 | Default: 0 280 | If specified as 1, then key-mappings to invoke FileBeagle will not be defined. 281 | 282 | g:filebeagle_buffer_legacy_key_maps~ *g:filebeagle_buffer_legacy_key_maps* 283 | Default: 0 284 | If specified as 1, then the key-mapping scheme from release 1.0.0 will be 285 | used in the FileBeagle buffer instead of the new ones. 286 | 287 | g:filebeagle_hijack_netrw~ *g:filebeagle_hijack_netrw* 288 | Default: 1 289 | If specified as 0, directories will be opened by |netrw| instead of 290 | FileBeagle. 291 | 292 | g:filebeagle_show_hidden~ *g:filebeagle_show_hidden* 293 | Default: 0 294 | Show hidden and (wild-)ignored files by default (can be toggled when 295 | viewing a directory using 'gh'). 296 | 297 | g:filebeagle_show_parent *g:filebeagle_show_parent* 298 | Default: 1 299 | If specified as 1, show entry to navigate to parent directory (../). 300 | 301 | g:filebeagle_show_line_numbers~ *g:filebeagle_show_line_numbers* 302 | Default: -1 303 | If 0, then line numbers (see |nu|) will be suppressed in the directory 304 | buffer (i.e, 'set nonumber' will be invoked). If 1, then line numbers will 305 | be explicitly activated (i.e, 'set number' will be invoked). If -1 306 | (default), then no number options will be explicitly set or unset. 307 | 308 | g:filebeagle_show_line_relativenumbers~ *g:filebeagle_show_line_relativenumbers* 309 | Default: -1 310 | If 0, then relative line numbers (see |rnu|) will be suppressed in the 311 | directory buffer (i.e, 'set rnu' will be invoked). If 1, then relative 312 | line numbers will be explicitly activated (i.e, 'set nornu' will be 313 | invoked). If -1 (default), then no relative number options will be 314 | explicitly set or unset. 315 | 316 | g:filebeagle_check_gitignore~ *g:filebeagle_check_gitignore* 317 | Default: 0 318 | If 1, filebeagle will attempt to exclude gitignored files. Requires 319 | external git binary on system path. 320 | 321 | g:filebeagle_statusline~ *g:filebeagle_statusline* 322 | Default: %( %{FileBeagleStatusLineCurrentDirInfo()} %)%=%( 323 | %{FileBeagleStatusLineFilterAndHiddenInfo()} %) 324 | Defines a statusbar used by filebeagle. See |statusline| for more 325 | information. 326 | 327 | =============================================================================== 328 | *filebeagle-autocommands* 329 | CUSTOM AUTOCOMMANDS~ 330 | 331 | FileBeagle exposes the following autocommand events, to allow you to hook in 332 | custom functionality: 333 | 334 | *FileBeagleBufNew* 335 | FileBeagleBufNew Immediately after creation of the FileBeagle 336 | directory buffer, and before any buffer-local 337 | options, key mappings, commands, etc. have been 338 | defined. The directory viewer object is available 339 | as the buffer variable 340 | `b:filebeagle_directory_viewer`. 341 | 342 | *FileBeagleReadPre* 343 | FileBeagleReadPre After creation and full setup (options, key 344 | mappings, commands, etc.) of the FileBeagle 345 | buffer, but before any directory information has 346 | been read. 347 | 348 | 349 | *FileBeagleReadPost* 350 | FileBeagleReadPost After creation, full setup (options, key mappings, 351 | commands, etc.) of the FileBeagle buffer, and 352 | after the directory information has been read, 353 | parsed, and rendered. 354 | 355 | FileBeagleRefreshPre Immediately before updating the content of the 356 | directory buffer. 357 | 358 | FileBeagleRefreshPost Immediately after updating the content of the 359 | directory buffer. 360 | 361 | vim:tw=78:ts=8:ft=help:norl: 362 | -------------------------------------------------------------------------------- /plugin/filebeagle.vim: -------------------------------------------------------------------------------- 1 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 2 | "" FileBeagle 3 | "" 4 | "" VINE (Vim Is Not Emacs) file system explorer. 5 | "" 6 | "" Copyright 2014 Jeet Sukumaran. 7 | "" 8 | "" This program is free software; you can redistribute it and/or modify 9 | "" it under the terms of the GNU General Public License as published by 10 | "" the Free Software Foundation; either version 3 of the License, or 11 | "" (at your option) any later version. 12 | "" 13 | "" This program is distributed in the hope that it will be useful, 14 | "" but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | "" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | "" GNU General Public License 17 | "" for more details. 18 | """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" 19 | 20 | " Reload and Compatibility Guard {{{1 21 | " ============================================================================ 22 | " Reload protection. 23 | if (exists('g:did_filebeagle') && g:did_filebeagle) || &cp || version < 700 24 | finish 25 | endif 26 | let g:did_filebeagle = 1 27 | " avoid line continuation issues (see ':help user_41.txt') 28 | let s:save_cpo = &cpo 29 | set cpo&vim 30 | " 1}}} 31 | 32 | " Options {{{1 33 | " ============================================================================== 34 | 35 | let g:filebeagle_hijack_netrw = get(g:, 'filebeagle_hijack_netrw', 1) 36 | let g:filebeagle_suppress_keymaps = get(g:, 'filebeagle_suppress_keymaps', 0) 37 | let g:filebeagle_show_hidden = get(g:, 'filebeagle_show_hidden', 0) 38 | let g:filebeagle_show_parent = get(g:, 'filebeagle_show_parent', 1) 39 | let g:filebeagle_show_line_numbers = get(g:, 'filebeagle_show_line_numbers', -1) 40 | let g:filebeagle_show_line_relativenumbers = get(g:, 'filebeagle_show_line_relativenumbers', -1) 41 | let g:filebeagle_buffer_legacy_key_maps = get(g:, 'filebeagle_buffer_legacy_key_maps', 0) 42 | let g:filebeagle_buffer_background_key_map_prefix = get(g:, 'filebeagle_buffer_background_key_map_prefix', 'p') 43 | let g:filebeagle_buffer_normal_key_maps = get(g:, 'filebeagle_buffer_normal_key_maps', {}) 44 | let g:filebeagle_buffer_visual_key_maps = get(g:, 'filebeagle_buffer_visual_key_maps', {}) 45 | let g:filebeagle_buffer_map_movement_keys = get(g:, 'filebeagle_buffer_map_movement_keys', 1) 46 | let g:filebeagle_check_gitignore = get(g:, 'filebeagle_check_gitignore', 0) 47 | let g:filebeagle_statusline = get(g:, 'filebeagle_statusline', '%( %{FileBeagleStatusLineCurrentDirInfo()} %)%=%( %{FileBeagleStatusLineFilterAndHiddenInfo()} %)') 48 | 49 | " 1}}} 50 | 51 | " Public Command and Key Maps {{{1 52 | " ============================================================================== 53 | command! -complete=dir -nargs=* FileBeagle :call filebeagle#FileBeagleOpen(, -1) 54 | command! -nargs=0 FileBeagleBufferDir :call filebeagle#FileBeagleOpenCurrentBufferDir() 55 | 56 | nnoremap FileBeagleOpenCurrentWorkingDir :FileBeagle 57 | nnoremap FileBeagleOpenCurrentBufferDir :FileBeagleBufferDir 58 | 59 | if !exists('g:filebeagle_suppress_keymaps') || !g:filebeagle_suppress_keymaps 60 | map f FileBeagleOpenCurrentWorkingDir 61 | map - FileBeagleOpenCurrentBufferDir 62 | endif 63 | " 1}}} 64 | 65 | " netrw hijacking {{{1 66 | " ============================================================================== 67 | " (from EasyTree by Dmitry "troydm" Geurkov ) 68 | function! s:OpenDirHere(dir) 69 | if isdirectory(a:dir) 70 | let l:focal_dir = a:dir 71 | let l:focal_file = bufnr("%") 72 | if (has("win16") || has("win32") || has("win64")) && !&shellslash 73 | let l:focal_dir = substitute(l:focal_dir, '/', '\\', 'g') 74 | let l:focal_file = substitute(l:focal_file, '/', '\\', 'g') 75 | endif 76 | call filebeagle#FileBeagleOpen(l:focal_dir, l:focal_file) 77 | endif 78 | endfunction 79 | 80 | function! s:DisableFileExplorer() 81 | if exists("#FileExplorer") 82 | au! FileExplorer 83 | endif 84 | endfunction 85 | 86 | augroup FileBeagle 87 | au! 88 | autocmd VimEnter * if g:filebeagle_hijack_netrw | call DisableFileExplorer() | endif 89 | autocmd BufEnter * if g:filebeagle_hijack_netrw | call OpenDirHere(expand('')) | endif 90 | augroup end 91 | " }}}1 92 | 93 | " Restore State {{{1 94 | " ============================================================================ 95 | " restore options 96 | let &cpo = s:save_cpo 97 | " 1}}} 98 | 99 | " vim:foldlevel=4: 100 | --------------------------------------------------------------------------------