├── LICENSE ├── README.md ├── animation.gif └── plugin └── split-navigate.vim /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Rob Hoelz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Split Navigate 2 | 3 | An experimental Vim plugin for navigating to lines visible on screen. 4 | 5 | The idea is that you often see which line you want to go to, but you then need 6 | to read the number of that line (whether absolute or relative), move your fingers 7 | off of the home row to reach the numbers, key them in, and hit `g` or `j/k` to 8 | move the cursor there. While this is pretty fast, I couldn't hit but wonder 9 | if there were a faster way. 10 | 11 | I thought that maybe a navigation plugin based on binary search could be really 12 | fast once you got used to it. First of all, here's what it looks like: 13 | 14 | ![Animation](animation.gif) 15 | 16 | # Installation 17 | 18 | To install the plugin, you just need to copy `plugin/split-navigate.vim` to your 19 | Vim's runtime path, whether directly or using your preferred package manager. 20 | 21 | # Usage 22 | 23 | To use this plugin, hit `Space` in normal mode. This will highlight the screen 24 | in two halves - blue for the top, red for the bottom. If the line you want 25 | to go to is in the top (blue) section, hit `k`; otherwise, hit `j`. This will 26 | refine your search area to that half; the top half of the half you selected will 27 | now be blue, and the bottom half of the half you selected will now be red. Continue 28 | pressing `j`/`k` until you're reached the line you want. 29 | 30 | You can press `Escape` at any time to cancel split navigation. 31 | 32 | # Changing key bindings 33 | 34 | The default keys (`` for start, `k` for up, `j` for down and `` for abort) can be overridden on a per-key basis. 35 | 36 | The keybindings for up, down and abort are only mapped while search is active (buffer-local). These are `unmap`ped when search is aborted 37 | 38 | Any `{lhs}` should be valid. (see `:help map-which-keys`, though this was not thoroughly tested) 39 | 40 | You can use the following example to get started: 41 | ```vimL 42 | 43 | " start search with `leader+s` 44 | let g:splitnavigate_start_key = "s" 45 | " choose upper half with `u` 46 | let g:splitnavigate_up_key = "u" 47 | " choose lower half with `d` 48 | let g:splitnavigate_down_key = "d" 49 | " stop searching with `q` 50 | let g:splitnavigate_abort_key = "q" 51 | ``` 52 | 53 | # Custom Highlight Colors 54 | 55 | These are the default colors used: 56 | ```vimL 57 | "default white on blue 58 | highlight default TopHighlight term=bold ctermfg=252 ctermbg=18 guifg=fg guibg=#000080 59 | " default yellow on red 60 | highlight default BottomHighlight term=standout ctermfg=186 ctermbg=88 guifg=#d0d090 guibg=#800000 61 | ``` 62 | 63 | Use the following color groups to set custom colors: 64 | ```vimL 65 | " custom blue on white (terminal only) 66 | highlight TopHighlight term=bold ctermfg=18 ctermbg=252 67 | " custom red on white (terminal only) 68 | highlight BottomHighlight term=bold ctermfg=88 ctermbg=252 69 | ``` 70 | 71 | # Caveats 72 | 73 | Here are some of the compromises I made while writing this plugin; I will address 74 | them in the future if it takes off. 75 | 76 | - This plugin doesn't currently play well with folds. It *can*, but it would take some effort and I want to make sure it's useful before I add that. 77 | -------------------------------------------------------------------------------- /animation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hoelzro/vim-split-navigate/2a18e8dcee3184dacd9686b5ee17bdd4ba78b32f/animation.gif -------------------------------------------------------------------------------- /plugin/split-navigate.vim: -------------------------------------------------------------------------------- 1 | " set default values if unset 2 | if ! exists("g:splitnavigate_start_key") 3 | let g:splitnavigate_start_key = "" 4 | endif 5 | if ! exists("g:splitnavigate_up_key") 6 | let g:splitnavigate_up_key = "k" 7 | endif 8 | if ! exists("g:splitnavigate_down_key") 9 | let g:splitnavigate_down_key = "j" 10 | endif 11 | if ! exists("g:splitnavigate_abort_key") 12 | let g:splitnavigate_abort_key = "" 13 | endif 14 | 15 | function! s:SelectLower() 16 | let middle = GetMiddle() 17 | let b:binary_top = middle + 1 18 | call Refresh() 19 | endfunction 20 | 21 | function! s:SelectUpper() 22 | let middle = GetMiddle() 23 | let b:binary_bottom = middle 24 | call Refresh() 25 | endfunction 26 | 27 | function! s:SetupSeekBindings() 28 | execute "map ". g:splitnavigate_down_key ." :call SelectLower()" 29 | execute "map ". g:splitnavigate_up_key ." :call SelectUpper()" 30 | execute "map ". g:splitnavigate_abort_key ." :call AbortSearch()" 31 | endfunction 32 | 33 | function! s:AbortSearch() 34 | call matchdelete(b:binary_matches[0]) 35 | call matchdelete(b:binary_matches[1]) 36 | unlet b:binary_matches 37 | 38 | call ResetSeekBindings() 39 | endfunction 40 | 41 | function! s:ResetSeekBindings() 42 | execute "unmap " . g:splitnavigate_up_key 43 | execute "unmap " . g:splitnavigate_down_key 44 | execute "unmap " . g:splitnavigate_abort_key 45 | endfunction 46 | 47 | function! s:GetMiddle() 48 | return (b:binary_bottom - b:binary_top) / 2 + b:binary_top 49 | endfunction 50 | 51 | function! s:HighlightLinesBetween(start, finish) 52 | return '\%>' . (a:start - 1) . 'l\%<' . (a:finish + 1) . 'l' 53 | endfunction 54 | 55 | function! s:Refresh() 56 | if b:binary_top == b:binary_bottom 57 | call cursor(b:binary_top, 1) 58 | call AbortSearch() 59 | 60 | return 61 | endif 62 | 63 | if has_key(b:, 'binary_middle') 64 | let middle = b:binary_middle 65 | unlet b:binary_middle 66 | else 67 | let middle = GetMiddle() 68 | endif 69 | call cursor(middle, 1) 70 | 71 | let match_top = HighlightLinesBetween(b:binary_top, middle) 72 | let match_bottom = HighlightLinesBetween(middle + 1, b:binary_bottom) 73 | 74 | if has_key(b:, 'binary_matches') 75 | call matchdelete(b:binary_matches[0]) 76 | call matchdelete(b:binary_matches[1]) 77 | endif 78 | 79 | let b:binary_matches = [0, 0] 80 | let b:binary_matches[0] = matchadd('TopHighlight', match_top) 81 | let b:binary_matches[1] = matchadd('BottomHighlight', match_bottom) 82 | endfunction 83 | 84 | function! BinarySeek() 85 | let current_line = line('.') 86 | let b:binary_top = current_line - winline() + 1 87 | let b:binary_bottom = min([b:binary_top + winheight(0) - 1, line('$')]) 88 | if get(g:, 'splitnavigate_start_current', 0) 89 | let b:binary_middle = current_line 90 | endif 91 | 92 | call SetupSeekBindings() 93 | call Refresh() 94 | endfunction 95 | 96 | 97 | execute "try | unmap ". g:splitnavigate_start_key . " | catch | endtry" 98 | 99 | execute "nnoremap ". g:splitnavigate_start_key ." :call BinarySeek()" 100 | 101 | highlight default TopHighlight term=bold ctermfg=252 ctermbg=18 guifg=fg guibg=#000080 102 | highlight default BottomHighlight term=standout ctermfg=186 ctermbg=88 guifg=#d0d090 guibg=#800000 103 | 104 | " XXX Caveats: 105 | " - Doesn't really work with folds 106 | --------------------------------------------------------------------------------