├── README.md ├── autoload ├── signjk.vim ├── vital.vim └── vital │ ├── _signjk.vim │ ├── _signjk │ └── HitAHint │ │ └── Hint.vim │ └── signjk.vital └── plugin └── signjk.vim /README.md: -------------------------------------------------------------------------------- 1 | signjk-motion 2 | ============= 3 | 4 | `:sign` version of `(easymotion-j)` and `(easymotion-k)` in [easymotion/vim-easymotion](https://github.com/easymotion/vim-easymotion). 5 | 6 | ![](https://raw.githubusercontent.com/haya14busa/i/1a24362e8b9eaeb94ad3265da0e6d0cfedc00177/misc/signjk.gif) 7 | 8 | USAGE 9 | ----- 10 | 11 | ```vim 12 | map j (signjk-j) 13 | map k (signjk-k) 14 | ``` 15 | 16 | ADVANCED USAGE 17 | -------------- 18 | 19 | ![](https://raw.githubusercontent.com/haya14busa/i/7b6415c5d5a40b8b389eeadd3374956af7304fff/misc/signjk_textobj_lines.gif) 20 | 21 | ```vim 22 | omap L (textobj-signjk-lines) 23 | vmap L (textobj-signjk-lines) 24 | ``` 25 | -------------------------------------------------------------------------------- /autoload/signjk.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " FILE: autoload/signjk.vim 3 | " AUTHOR: haya14busa 4 | " License: MIT license 5 | "============================================================================= 6 | scriptencoding utf-8 7 | let s:save_cpo = &cpo 8 | set cpo&vim 9 | 10 | let s:ID_START = 1414141414 11 | 12 | let g:signjk#use_upper = get(g:, 'signjk#use_upper', 0) 13 | let g:signjk#keys = get(g:, 'signjk#keys', 'asdghklqwertyuiopzxcvbnmfj;') 14 | let g:signjk#dummysign = get(g:, 'signjk#dummysign', 1) 15 | 16 | let s:V = vital#of('signjk') 17 | let s:Hint = s:V.import('HitAHint.Hint') 18 | 19 | let s:DIRECTION = {'forward': 0, 'backward': 1, 'both': 2} 20 | 21 | function! s:init_hl() abort 22 | highlight default SignjkTarget term=standout ctermfg=81 gui=bold guifg=#66D9EF 23 | highlight default SignjkTarget2 ctermfg=229 guifg=#E6DB74 24 | endfunction 25 | 26 | function! s:init() abort 27 | call s:init_hl() 28 | sign define signjkdummy 29 | endfunction 30 | 31 | call s:init() 32 | 33 | augroup plugin-signjk-highlight 34 | autocmd! 35 | autocmd ColorScheme * call s:init_hl() 36 | augroup END 37 | 38 | function! signjk#keys() abort 39 | return g:signjk#keys 40 | endfunction 41 | 42 | function! signjk#dummysign() abort 43 | if g:signjk#dummysign 44 | execute printf('sign place %d line=%d name=signjkdummy buffer=%d', s:ID_START, 1, bufnr('%')) 45 | endif 46 | endfunction 47 | 48 | function! signjk#move(keys, direction) abort 49 | let b:signjk = { 50 | \ 'id_table': {}, 51 | \ 'bufnr': bufnr('%') 52 | \ } 53 | let lines = s:gather_lines(a:direction) 54 | let visible_lines = s:visible_lines(a:direction) 55 | if a:direction is# s:DIRECTION.backward 56 | call reverse(lines) 57 | call reverse(visible_lines) 58 | endif 59 | let target_lnum = s:select_line(lines, a:keys) 60 | if target_lnum is# -1 61 | let esc = v:count > 0 || mode(1) is# 'no' ? "\" : '' 62 | return esc 63 | else 64 | return s:generate_command(a:direction, target_lnum, visible_lines) 65 | endif 66 | endfunction 67 | 68 | function! s:generate_command(direction, target_lnum, lines) abort 69 | let dlnum = index(a:lines, a:target_lnum) - index(a:lines, line('.')) 70 | let key = a:direction is# s:DIRECTION.backward || dlnum < 0 ? 'k' : 'j' 71 | let move = dlnum is# 0 ? '' : abs(dlnum) . key 72 | let esc = v:count > 0 || !(mode(1) is# 'n') ? "\" : '' 73 | let op = mode(1) is# 'no' ? '"' . v:register . v:operator 74 | \ : s:is_visual(mode(1)) ? 'gv' 75 | \ : '' 76 | return esc . 'm`' . op . move 77 | endfunction 78 | 79 | function! s:select_line(lnums, keys) abort 80 | let lines_len = len(a:lnums) 81 | if lines_len is# 1 82 | return a:lnums[0] 83 | elseif lines_len < 1 84 | return -1 85 | else 86 | return s:choose_prompt(s:Hint.create(a:lnums, a:keys)) 87 | endif 88 | endfunction 89 | 90 | " @param Tree{string: (T|Tree)} hint_dict 91 | function! s:choose_prompt(hint_dict) abort 92 | try 93 | call s:place_sign(s:line_to_hint(a:hint_dict)) 94 | echo 'Type key: ' 95 | let c = s:getchar() 96 | redraw 97 | if g:signjk#use_upper 98 | let c = toupper(c) 99 | endif 100 | finally 101 | call s:remove_sign() 102 | endtry 103 | 104 | if has_key(a:hint_dict, c) 105 | let target = a:hint_dict[c] 106 | return type(target) is# type({}) ? s:choose_prompt(target) : target 107 | else 108 | echo 'Invalid target: ' . c 109 | return -1 110 | endif 111 | endfunction 112 | 113 | function! s:getchar(...) abort 114 | let mode = get(a:, 1, 0) 115 | call inputsave() 116 | while 1 117 | let char = call('getchar', a:000) 118 | " Workaround for the mappings 119 | if string(char) !~# "\x80\xfd`" 120 | break 121 | endif 122 | endwhile 123 | call inputrestore() 124 | return mode == 1 ? !!char 125 | \ : type(char) == type(0) ? nr2char(char) : char 126 | endfunction 127 | 128 | " @param {{lnum: list}} line_to_hint 129 | function! s:place_sign(line_to_hint) abort 130 | for [lnum, hint] in items(a:line_to_hint) 131 | let is_more_than_one_hint = len(hint) > 1 132 | let hl = is_more_than_one_hint ? 'SignjkTarget2' : 'SignjkTarget' 133 | call s:sign(str2nr(lnum), join(hint[:1], ''), hl) 134 | endfor 135 | endfunction 136 | 137 | function! s:sign(lnum, text, hl) abort 138 | let name = printf('signjk#%s', a:lnum) 139 | let id = s:ID_START + a:lnum 140 | let b:signjk.id_table[id] = { 141 | \ 'lnum': a:lnum, 142 | \ 'text': a:text 143 | \ } 144 | execute printf('sign define %s text=%s texthl=%s', name, a:text, a:hl) 145 | execute printf('sign place %d line=%d name=%s buffer=%d', id, a:lnum, name, b:signjk.bufnr) 146 | endfunction 147 | 148 | function! s:remove_sign(...) abort 149 | let bufnr = get(a:, 1, bufnr('%')) 150 | let signjk = getbufvar(bufnr, 'signjk', {}) 151 | for id in keys(get(signjk, 'id_table', {})) 152 | execute printf('sign unplace %d buffer=%d', id, bufnr) 153 | endfor 154 | endfunction 155 | 156 | 157 | " s:line_to_hint() returns dict whose key is line number and whose value is 158 | " the hints 159 | " e.g. {'1': ['a'], '2': ['b', 'a'], '3': ['b', 'b']} 160 | " @return {{lnum: list}} 161 | function! s:line_to_hint(hint_dict) abort 162 | return s:_line_to_hint({}, a:hint_dict) 163 | endfunction 164 | 165 | function! s:_line_to_hint(dict, hint_dict, ...) abort 166 | let prefix = get(a:, 1, []) 167 | for [hint, v] in items(a:hint_dict) 168 | if type(v) is# type(0) 169 | let a:dict[v] = prefix + [hint] 170 | else 171 | call s:_line_to_hint(a:dict, v, prefix + [hint]) 172 | endif 173 | unlet v 174 | endfor 175 | return a:dict 176 | endfunction 177 | 178 | function! s:gather_lines(direction) abort 179 | return filter(s:_win_lines(a:direction), '!s:is_in_folded(v:val)') 180 | endfunction 181 | 182 | function! s:is_in_folded(lnum) abort 183 | return foldclosed(a:lnum) != -1 184 | endfunction 185 | 186 | function! s:visible_lines(direction) abort 187 | return filter(s:_win_lines(a:direction), '!s:is_in_folded(v:val) || foldclosed(v:val) is# v:val') 188 | endfunction 189 | 190 | function! s:_win_lines(direction) abort 191 | if a:direction is# s:DIRECTION.forward 192 | return range(line('.') + 1, line('w$')) 193 | elseif a:direction is# s:DIRECTION.backward 194 | return range(line('w0'), line('.') - 1) 195 | else 196 | return range(line('w0'), line('w$')) 197 | endif 198 | endfunction 199 | 200 | function! s:is_visual(mode) abort 201 | return a:mode =~# "[vV\]" 202 | endfunction 203 | 204 | let &cpo = s:save_cpo 205 | unlet s:save_cpo 206 | " __END__ 207 | " vim: expandtab softtabstop=2 shiftwidth=2 foldmethod=marker 208 | -------------------------------------------------------------------------------- /autoload/vital.vim: -------------------------------------------------------------------------------- 1 | function! vital#of(name) abort 2 | let files = globpath(&runtimepath, 'autoload/vital/' . a:name . '.vital') 3 | let file = split(files, "\n") 4 | if empty(file) 5 | throw 'vital: version file not found: ' . a:name 6 | endif 7 | let ver = readfile(file[0], 'b') 8 | if empty(ver) 9 | throw 'vital: invalid version file: ' . a:name 10 | endif 11 | return vital#_{substitute(ver[0], '\W', '', 'g')}#new() 12 | endfunction 13 | -------------------------------------------------------------------------------- /autoload/vital/_signjk.vim: -------------------------------------------------------------------------------- 1 | let s:self_version = expand(':t:r') 2 | let s:self_file = expand('') 3 | 4 | " Note: The extra argument to globpath() was added in Patch 7.2.051. 5 | let s:globpath_third_arg = v:version > 702 || v:version == 702 && has('patch51') 6 | 7 | let s:loaded = {} 8 | let s:cache_module_path = {} 9 | let s:cache_sid = {} 10 | 11 | let s:_vital_files_cache_runtimepath = '' 12 | let s:_vital_files_cache = [] 13 | let s:_unify_path_cache = {} 14 | 15 | function! s:import(name, ...) abort 16 | let target = {} 17 | let functions = [] 18 | for a in a:000 19 | if type(a) == type({}) 20 | let target = a 21 | elseif type(a) == type([]) 22 | let functions = a 23 | endif 24 | unlet a 25 | endfor 26 | let module = s:_import(a:name) 27 | if empty(functions) 28 | call extend(target, module, 'keep') 29 | else 30 | for f in functions 31 | if has_key(module, f) && !has_key(target, f) 32 | let target[f] = module[f] 33 | endif 34 | endfor 35 | endif 36 | return target 37 | endfunction 38 | 39 | function! s:load(...) dict abort 40 | for arg in a:000 41 | let [name; as] = type(arg) == type([]) ? arg[: 1] : [arg, arg] 42 | let target = split(join(as, ''), '\W\+') 43 | let dict = self 44 | let dict_type = type({}) 45 | while !empty(target) 46 | let ns = remove(target, 0) 47 | if !has_key(dict, ns) 48 | let dict[ns] = {} 49 | endif 50 | if type(dict[ns]) == dict_type 51 | let dict = dict[ns] 52 | else 53 | unlet dict 54 | break 55 | endif 56 | endwhile 57 | 58 | if exists('dict') 59 | call extend(dict, s:_import(name)) 60 | endif 61 | unlet arg 62 | endfor 63 | return self 64 | endfunction 65 | 66 | function! s:unload() abort 67 | let s:loaded = {} 68 | let s:cache_sid = {} 69 | let s:cache_module_path = {} 70 | endfunction 71 | 72 | function! s:exists(name) abort 73 | return s:_get_module_path(a:name) !=# '' 74 | endfunction 75 | 76 | function! s:search(pattern) abort 77 | let paths = s:_vital_files(a:pattern) 78 | let modules = sort(map(paths, 's:_file2module(v:val)')) 79 | return s:_uniq(modules) 80 | endfunction 81 | 82 | function! s:expand_modules(entry, all) abort 83 | if type(a:entry) == type([]) 84 | let candidates = s:_concat(map(copy(a:entry), 's:search(v:val)')) 85 | if empty(candidates) 86 | throw printf('vital: Any of module %s is not found', string(a:entry)) 87 | endif 88 | if eval(join(map(copy(candidates), 'has_key(a:all, v:val)'), '+')) 89 | let modules = [] 90 | else 91 | let modules = [candidates[0]] 92 | endif 93 | else 94 | let modules = s:search(a:entry) 95 | if empty(modules) 96 | throw printf('vital: Module %s is not found', a:entry) 97 | endif 98 | endif 99 | call filter(modules, '!has_key(a:all, v:val)') 100 | for module in modules 101 | let a:all[module] = 1 102 | endfor 103 | return modules 104 | endfunction 105 | 106 | function! s:_import(name) abort 107 | if type(a:name) == type(0) 108 | return s:_build_module(a:name) 109 | endif 110 | let path = s:_get_module_path(a:name) 111 | if path ==# '' 112 | throw 'vital: module not found: ' . a:name 113 | endif 114 | let sid = s:_get_sid_by_script(path) 115 | if !sid 116 | try 117 | execute 'source' fnameescape(path) 118 | catch /^Vim\%((\a\+)\)\?:E484/ 119 | throw 'vital: module not found: ' . a:name 120 | catch /^Vim\%((\a\+)\)\?:E127/ 121 | " Ignore. 122 | endtry 123 | 124 | let sid = s:_get_sid_by_script(path) 125 | endif 126 | return s:_build_module(sid) 127 | endfunction 128 | 129 | function! s:_get_module_path(name) abort 130 | let key = a:name . '_' 131 | if has_key(s:cache_module_path, key) 132 | return s:cache_module_path[key] 133 | endif 134 | if s:_is_absolute_path(a:name) && filereadable(a:name) 135 | return a:name 136 | endif 137 | if a:name ==# '' 138 | let paths = [s:self_file] 139 | elseif a:name =~# '\v^\u\w*%(\.\u\w*)*$' 140 | let paths = s:_vital_files(a:name) 141 | else 142 | throw 'vital: Invalid module name: ' . a:name 143 | endif 144 | 145 | call filter(paths, 'filereadable(expand(v:val, 1))') 146 | let path = get(paths, 0, '') 147 | let s:cache_module_path[key] = path 148 | return path 149 | endfunction 150 | 151 | function! s:_get_sid_by_script(path) abort 152 | if has_key(s:cache_sid, a:path) 153 | return s:cache_sid[a:path] 154 | endif 155 | 156 | let path = s:_unify_path(a:path) 157 | for line in filter(split(s:_redir('scriptnames'), "\n"), 158 | \ 'stridx(v:val, s:self_version) > 0') 159 | let list = matchlist(line, '^\s*\(\d\+\):\s\+\(.\+\)\s*$') 160 | if !empty(list) && s:_unify_path(list[2]) ==# path 161 | let s:cache_sid[a:path] = list[1] - 0 162 | return s:cache_sid[a:path] 163 | endif 164 | endfor 165 | return 0 166 | endfunction 167 | 168 | function! s:_file2module(file) abort 169 | let filename = fnamemodify(a:file, ':p:gs?[\\/]?/?') 170 | let tail = matchstr(filename, 'autoload/vital/_\w\+/\zs.*\ze\.vim$') 171 | return join(split(tail, '[\\/]\+'), '.') 172 | endfunction 173 | 174 | if filereadable(expand(':r') . '.VIM') 175 | " resolve() is slow, so we cache results. 176 | " Note: On windows, vim can't expand path names from 8.3 formats. 177 | " So if getting full path via and $HOME was set as 8.3 format, 178 | " vital load duplicated scripts. Below's :~ avoid this issue. 179 | function! s:_unify_path(path) abort 180 | if has_key(s:_unify_path_cache, a:path) 181 | return s:_unify_path_cache[a:path] 182 | endif 183 | let value = tolower(fnamemodify(resolve(fnamemodify( 184 | \ a:path, ':p')), ':~:gs?[\\/]?/?')) 185 | let s:_unify_path_cache[a:path] = value 186 | return value 187 | endfunction 188 | else 189 | function! s:_unify_path(path) abort 190 | return resolve(fnamemodify(a:path, ':p:gs?[\\/]?/?')) 191 | endfunction 192 | endif 193 | 194 | if s:globpath_third_arg 195 | function! s:_runtime_files(path) abort 196 | return split(globpath(&runtimepath, a:path, 1), "\n") 197 | endfunction 198 | else 199 | function! s:_runtime_files(path) abort 200 | return split(globpath(&runtimepath, a:path), "\n") 201 | endfunction 202 | endif 203 | 204 | function! s:_vital_files(pattern) abort 205 | if s:_vital_files_cache_runtimepath !=# &runtimepath 206 | let path = printf('autoload/vital/%s/**/*.vim', s:self_version) 207 | let s:_vital_files_cache = s:_runtime_files(path) 208 | let mod = ':p:gs?[\\/]\+?/?' 209 | call map(s:_vital_files_cache, 'fnamemodify(v:val, mod)') 210 | let s:_vital_files_cache_runtimepath = &runtimepath 211 | endif 212 | let target = substitute(a:pattern, '\.', '/', 'g') 213 | let target = substitute(target, '\*', '[^/]*', 'g') 214 | let regexp = printf('autoload/vital/%s/%s.vim', s:self_version, target) 215 | return filter(copy(s:_vital_files_cache), 'v:val =~# regexp') 216 | endfunction 217 | 218 | " Copy from System.Filepath 219 | if has('win16') || has('win32') || has('win64') 220 | function! s:_is_absolute_path(path) abort 221 | return a:path =~? '^[a-z]:[/\\]' 222 | endfunction 223 | else 224 | function! s:_is_absolute_path(path) abort 225 | return a:path[0] ==# '/' 226 | endfunction 227 | endif 228 | 229 | function! s:_build_module(sid) abort 230 | if has_key(s:loaded, a:sid) 231 | return copy(s:loaded[a:sid]) 232 | endif 233 | let functions = s:_get_functions(a:sid) 234 | 235 | let prefix = '' . a:sid . '_' 236 | let module = {} 237 | for func in functions 238 | let module[func] = function(prefix . func) 239 | endfor 240 | if has_key(module, '_vital_created') 241 | call module._vital_created(module) 242 | endif 243 | let export_module = filter(copy(module), 'v:key =~# "^\\a"') 244 | let s:loaded[a:sid] = get(g:, 'vital_debug', 0) ? module : export_module 245 | if has_key(module, '_vital_loaded') 246 | let V = vital#{s:self_version}#new() 247 | call module._vital_loaded(V) 248 | endif 249 | return copy(s:loaded[a:sid]) 250 | endfunction 251 | 252 | if exists('+regexpengine') 253 | function! s:_get_functions(sid) abort 254 | let funcs = s:_redir(printf("function /\\%%#=2^\%d_", a:sid)) 255 | let map_pat = '' . a:sid . '_\zs\w\+' 256 | return map(split(funcs, "\n"), 'matchstr(v:val, map_pat)') 257 | endfunction 258 | else 259 | function! s:_get_functions(sid) abort 260 | let prefix = '' . a:sid . '_' 261 | let funcs = s:_redir('function') 262 | let filter_pat = '^\s*function ' . prefix 263 | let map_pat = prefix . '\zs\w\+' 264 | return map(filter(split(funcs, "\n"), 265 | \ 'stridx(v:val, prefix) > 0 && v:val =~# filter_pat'), 266 | \ 'matchstr(v:val, map_pat)') 267 | endfunction 268 | endif 269 | 270 | if exists('*uniq') 271 | function! s:_uniq(list) abort 272 | return uniq(a:list) 273 | endfunction 274 | else 275 | function! s:_uniq(list) abort 276 | let i = len(a:list) - 1 277 | while 0 < i 278 | if a:list[i] ==# a:list[i - 1] 279 | call remove(a:list, i) 280 | let i -= 2 281 | else 282 | let i -= 1 283 | endif 284 | endwhile 285 | return a:list 286 | endfunction 287 | endif 288 | 289 | function! s:_concat(lists) abort 290 | let result_list = [] 291 | for list in a:lists 292 | let result_list += list 293 | endfor 294 | return result_list 295 | endfunction 296 | 297 | function! s:_redir(cmd) abort 298 | let [save_verbose, save_verbosefile] = [&verbose, &verbosefile] 299 | set verbose=0 verbosefile= 300 | redir => res 301 | silent! execute a:cmd 302 | redir END 303 | let [&verbose, &verbosefile] = [save_verbose, save_verbosefile] 304 | return res 305 | endfunction 306 | 307 | function! vital#{s:self_version}#new() abort 308 | return s:_import('') 309 | endfunction 310 | -------------------------------------------------------------------------------- /autoload/vital/_signjk/HitAHint/Hint.vim: -------------------------------------------------------------------------------- 1 | " function() wrapper 2 | if v:version > 703 || v:version == 703 && has('patch1170') 3 | let s:_function = function('function') 4 | else 5 | function! s:_SID() abort 6 | return matchstr(expand(''), '\zs\d\+\ze__SID$') 7 | endfunction 8 | let s:_s = '' . s:_SID() . '_' 9 | function! s:_function(fstr) abort 10 | return function(substitute(a:fstr, 's:', s:_s, 'g')) 11 | endfunction 12 | endif 13 | 14 | function! s:_assert(...) abort 15 | return '' 16 | endfunction 17 | 18 | function! s:_vital_loaded(V) abort 19 | if a:V.exists('Vim.PowerAssert') 20 | let s:assert = a:V.import('Vim.PowerAssert').assert 21 | else 22 | let s:assert = s:_function('s:_assert') 23 | endif 24 | endfunction 25 | 26 | " TERMS: 27 | " key: A character to generate hint. e.g. a,b,c,d,e,f,... 28 | " hint: A hint is a combination of keys. e.g. a,b,ab,abc,.. 29 | 30 | " s:create() assigns keys to each targets and generate hint dict. 31 | " Example: 32 | " let targets = [1, 2, 3, 4, 5, 6] 33 | " echo s:label(targets, ['a', 'b', 'c']) 34 | " " => { 35 | " 'a': 1, 36 | " 'b': { 37 | " 'a': 2, 38 | " 'b': 3 39 | " }, 40 | " 'c': { 41 | " 'a': 4, 42 | " 'b': 5, 43 | " 'c': 6 44 | " } 45 | " } 46 | " Hint-to-target: 47 | " a -> 1 48 | " ba -> 2 49 | " bb -> 3 50 | " ca -> 4 51 | " cb -> 5 52 | " cc -> 6 53 | " @param {list} targets 54 | " @param {list} keys each key should be uniq 55 | " @return Tree{string: (T|Tree)} 56 | function! s:create(targets, keys) abort 57 | exe s:assert('len(a:keys) > 1') 58 | let groups = {} 59 | let keys_count = reverse(s:_keys_count(len(a:targets), len(a:keys))) 60 | 61 | let target_idx = 0 62 | let key_idx = 0 63 | for key_count in keys_count 64 | if key_count > 1 65 | " We need to create a subgroup 66 | " Recurse one level deeper 67 | let sub_targets = a:targets[target_idx : target_idx + key_count - 1] 68 | let groups[a:keys[key_idx]] = s:create(sub_targets, a:keys) 69 | elseif key_count == 1 70 | " Assign single target key_idx 71 | let groups[a:keys[key_idx]] = a:targets[target_idx] 72 | else 73 | " No target 74 | continue 75 | endif 76 | let key_idx += 1 77 | let target_idx += key_count 78 | endfor 79 | return groups 80 | endfunction 81 | 82 | " s:_keys_count() generates list which represents how many targets to be 83 | " assigned to the key. 84 | " If the count > 1, use tree recursively. 85 | " Example: 86 | " echo s:_keys_count(5, 3) 87 | " " => [3, 1, 1] 88 | " echo s:_keys_count(8, 3) 89 | " " => [3, 3, 2] 90 | " @param {number} target_len 91 | " @param {number} keys_len 92 | function! s:_keys_count(targets_len, keys_len) abort 93 | exe s:assert('a:keys_len > 1') 94 | let _keys_count = repeat([0], a:keys_len) 95 | let is_first_level = 1 96 | let targets_left_cnt = a:targets_len 97 | while targets_left_cnt > 0 98 | let cnt_to_add = is_first_level ? 1 : a:keys_len - 1 99 | for i in range(a:keys_len) 100 | let _keys_count[i] += cnt_to_add 101 | let targets_left_cnt -= cnt_to_add 102 | if targets_left_cnt <= 0 103 | let _keys_count[i] += targets_left_cnt 104 | break 105 | endif 106 | endfor 107 | let is_first_level = 0 108 | endwhile 109 | exe s:assert('len(_keys_count) is# a:keys_len') 110 | return _keys_count 111 | endfunction 112 | -------------------------------------------------------------------------------- /autoload/vital/signjk.vital: -------------------------------------------------------------------------------- 1 | signjk 2 | 55e399bc11fc1b45bd42dd2542f3906d1a44d5e3 3 | 4 | HitAHint.Hint 5 | -------------------------------------------------------------------------------- /plugin/signjk.vim: -------------------------------------------------------------------------------- 1 | "============================================================================= 2 | " FILE: plugin/signjk.vim 3 | " AUTHOR: haya14busa 4 | " License: MIT license 5 | "============================================================================= 6 | scriptencoding utf-8 7 | if expand('%:p') ==# expand(':p') 8 | unlet! g:loaded_signjk 9 | endif 10 | if exists('g:loaded_signjk') 11 | finish 12 | endif 13 | let g:loaded_signjk = 1 14 | let s:save_cpo = &cpo 15 | set cpo&vim 16 | 17 | noremap (signjk-j) signjk#move(signjk#keys(), 0) 18 | noremap (signjk-k) signjk#move(signjk#keys(), 1) 19 | noremap (signjk-jk) signjk#move(signjk#keys(), 2) 20 | 21 | omap (textobj-signjk-lines) operatorlines(0) 22 | vmap (textobj-signjk-lines) operatorlines(1) 23 | 24 | onoremap (_signjk-Esc) 25 | vnoremap (_signjk-Esc) 26 | nnoremap (_signjk-V) V 27 | nnoremap (_signjk-C-o) 28 | inoremap (_signjk-C-o) 29 | 30 | function! s:operatorlines(is_visual) abort 31 | let cmds = [ 32 | \ "\(_signjk-Esc)", 33 | \ "\(signjk-jk)", 34 | \ "\(_signjk-V)", 35 | \ "\(signjk-jk)", 36 | \ ] 37 | let ops = a:is_visual ? [] : [ 38 | \ '"' . v:register . v:operator, 39 | \ "\(_signjk-C-o)\(_signjk-C-o)" 40 | \ ] 41 | return join(cmds + ops, '') 42 | endfunction 43 | 44 | augroup plugin-signjk-dummy-sign 45 | autocmd! 46 | autocmd BufWinEnter * call signjk#dummysign() 47 | augroup END 48 | 49 | let &cpo = s:save_cpo 50 | unlet s:save_cpo 51 | " __END__ 52 | " vim: expandtab softtabstop=2 shiftwidth=2 foldmethod=marker 53 | --------------------------------------------------------------------------------