├── .gitignore ├── .travis.yml ├── Gemfile ├── Rakefile ├── autoload └── submode.vim ├── doc └── submode.txt └── t ├── current.vim ├── expr.vim └── keep-leaving-key.vim /.gitignore: -------------------------------------------------------------------------------- 1 | .vim-flavor 2 | Gemfile.lock 3 | VimFlavor.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.0.0 4 | script: rake ci 5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'vim-flavor', '~> 1.1' 4 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | 3 | task :ci => [:dump, :test] 4 | 5 | task :dump do 6 | sh 'vim --version' 7 | end 8 | 9 | task :test do 10 | sh 'bundle exec vim-flavor test' 11 | end 12 | -------------------------------------------------------------------------------- /autoload/submode.vim: -------------------------------------------------------------------------------- 1 | " submode - Create your own submodes 2 | " Version: 0.3.1 3 | " Copyright (C) 2008-2014 kana 4 | " License: MIT license {{{ 5 | " Permission is hereby granted, free of charge, to any person obtaining 6 | " a copy of this software and associated documentation files (the 7 | " "Software"), to deal in the Software without restriction, including 8 | " without limitation the rights to use, copy, modify, merge, publish, 9 | " distribute, sublicense, and/or sell copies of the Software, and to 10 | " permit persons to whom the Software is furnished to do so, subject to 11 | " the following conditions: 12 | " 13 | " The above copyright notice and this permission notice shall be included 14 | " in all copies or substantial portions of the Software. 15 | " 16 | " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 | " OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | " IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | " CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | " TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | " SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | " }}} 24 | " Concept "{{{1 25 | " 26 | " In the following pseudo code, :MAP means :map or :noremap, and it depends on 27 | " user's specification. 28 | " 29 | " map {key-to-enter} 30 | " \ (submode-before-entering:{submode}:with:{key-to-enter}) 31 | " \(submode-before-entering:{submode}) 32 | " \(submode-enter:{submode}) 33 | " 34 | " MAP (submode-before-entering:{submode}:with:{key-to-enter}) 35 | " \ {anything} 36 | " noremap (submode-before-entering:{submode}) 37 | " \ {tweaking 'timeout' and others} 38 | " map (submode-enter:{submode}) 39 | " \ (submode-before-action:{submode}) 40 | " \(submode-prefix:{submode}) 41 | " 42 | " map (submode-prefix:{submode}) 43 | " \ (submode-leave:{submode}) 44 | " map (submode-prefix:{submode}){the first N keys in {lhs}} 45 | " \ (submode-leave:{submode}) 46 | " map (submode-prefix:{submode}){lhs} 47 | " \ (submode-rhs:{submode}:for:{lhs}) 48 | " \(submode-enter:{submode}) 49 | " MAP (submode-rhs:{submode}:for:{lhs}) 50 | " \ {rhs} 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | " Variables "{{{1 60 | 61 | if !exists('g:submode_always_show_submode') 62 | let g:submode_always_show_submode = 0 63 | endif 64 | 65 | if !exists('g:submode_keep_leaving_key') 66 | let g:submode_keep_leaving_key = 0 67 | endif 68 | 69 | if !exists('g:submode_keyseqs_to_leave') 70 | let g:submode_keyseqs_to_leave = [''] 71 | endif 72 | 73 | if !exists('g:submode_timeout') 74 | let g:submode_timeout = &timeout 75 | endif 76 | 77 | if !exists('g:submode_timeoutlen') 78 | let g:submode_timeoutlen = &timeoutlen 79 | endif 80 | 81 | 82 | 83 | 84 | "" See s:set_up_options() and s:restore_options(). 85 | " 86 | " let s:original_showcmd = &showcmd 87 | " let s:original_showmode = &showmode 88 | " let s:original_timeout = &timeout 89 | " let s:original_timeoutlen = &timeoutlen 90 | " let s:original_ttimeout = &ttimeout 91 | " let s:original_ttimeoutlen = &ttimeoutlen 92 | 93 | if !exists('s:options_overridden_p') 94 | let s:options_overridden_p = 0 95 | endif 96 | 97 | " A padding string to wipe out internal key mappings in 'showcmd' area. (gh-3) 98 | " 99 | " We use no-break spaces (U+00A0) or dots, depending of the current 'encoding'. 100 | " Because 101 | " 102 | " * A normal space (U+0020) is rendered as "<20>" since Vim 7.4.116. 103 | " * U+00A0 is rendered as an invisible glyph if 'encoding' is set to one of 104 | " Unicode encodings. Otherwise "| " is rendered instead. 105 | let s:STEALTH_TYPEAHEAD = 106 | \ &g:encoding =~# '^u' 107 | \ ? repeat("\", 5) 108 | \ : repeat('.', 10) 109 | 110 | let s:current_submode = '' 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | " Interface "{{{1 120 | " :SubmodeRestoreOptions "{{{2 121 | 122 | command! -bar -nargs=0 SubmodeRestoreOptions call submode#restore_options() 123 | 124 | 125 | 126 | 127 | function! submode#current() "{{{2 128 | return s:current_submode 129 | endfunction 130 | 131 | 132 | 133 | 134 | function! submode#enter_with(submode, modes, options, lhs, ...) "{{{2 135 | let rhs = 0 < a:0 ? a:1 : '' 136 | for mode in s:each_char(a:modes) 137 | call s:define_entering_mapping(a:submode, mode, a:options, a:lhs, rhs) 138 | endfor 139 | return 140 | endfunction 141 | 142 | 143 | 144 | 145 | function! submode#leave_with(submode, modes, options, lhs) "{{{2 146 | let options = substitute(a:modes, 'e', '', 'g') " is not expression. 147 | return submode#map(a:submode, a:modes, options . 'x', a:lhs, '') 148 | endfunction 149 | 150 | 151 | 152 | 153 | function! submode#map(submode, modes, options, lhs, rhs) "{{{2 154 | for mode in s:each_char(a:modes) 155 | call s:define_submode_mapping(a:submode, mode, a:options, a:lhs, a:rhs) 156 | endfor 157 | return 158 | endfunction 159 | 160 | 161 | 162 | 163 | function! submode#restore_options() "{{{2 164 | call s:restore_options() 165 | return 166 | endfunction 167 | 168 | 169 | 170 | 171 | function! submode#unmap(submode, modes, options, lhs) "{{{2 172 | for mode in s:each_char(a:modes) 173 | call s:undefine_submode_mapping(a:submode, mode, a:options, a:lhs) 174 | endfor 175 | return 176 | endfunction 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | " Core "{{{1 186 | function! s:define_entering_mapping(submode, mode, options, lhs, rhs) "{{{2 187 | execute s:map_command(a:mode, 'r') 188 | \ s:map_options(s:filter_flags(a:options, 'bu')) 189 | \ (a:lhs) 190 | \ (s:named_key_before_entering_with(a:submode, a:lhs) 191 | \ . s:named_key_before_entering(a:submode) 192 | \ . s:named_key_enter(a:submode)) 193 | 194 | if !s:mapping_exists_p(s:named_key_enter(a:submode), a:mode) 195 | " When the given submode is not defined yet - define the default key 196 | " mappings to leave the submode. 197 | for keyseq in g:submode_keyseqs_to_leave 198 | call submode#leave_with(a:submode, a:mode, a:options, keyseq) 199 | endfor 200 | endif 201 | 202 | execute s:map_command(a:mode, s:filter_flags(a:options, 'r')) 203 | \ s:map_options(s:filter_flags(a:options, 'besu')) 204 | \ s:named_key_before_entering_with(a:submode, a:lhs) 205 | \ a:rhs 206 | execute s:map_command(a:mode, '') 207 | \ s:map_options('e') 208 | \ s:named_key_before_entering(a:submode) 209 | \ printf('on_entering_submode(%s)', string(a:submode)) 210 | execute s:map_command(a:mode, 'r') 211 | \ s:map_options('') 212 | \ s:named_key_enter(a:submode) 213 | \ (s:named_key_before_action(a:submode) 214 | \ . s:named_key_prefix(a:submode)) 215 | 216 | execute s:map_command(a:mode, '') 217 | \ s:map_options('e') 218 | \ s:named_key_before_action(a:submode) 219 | \ printf('on_executing_action(%s)', string(a:submode)) 220 | execute s:map_command(a:mode, 'r') 221 | \ s:map_options('') 222 | \ s:named_key_prefix(a:submode) 223 | \ s:named_key_leave(a:submode) 224 | " NB: :map- cannot be used for s:on_leaving_submode(), 225 | " because it uses some commands not allowed in :map-. 226 | execute s:map_command(a:mode, '') 227 | \ s:map_options('s') 228 | \ s:named_key_leave(a:submode) 229 | \ printf('%son_leaving_submode(%s)', 230 | \ a:mode =~# '[ic]' ? '=' : '@=', 231 | \ string(a:submode)) 232 | 233 | return 234 | endfunction 235 | 236 | 237 | 238 | 239 | function! s:define_submode_mapping(submode, mode, options, lhs, rhs) "{{{2 240 | execute s:map_command(a:mode, 'r') 241 | \ s:map_options(s:filter_flags(a:options, 'bu')) 242 | \ (s:named_key_prefix(a:submode) . a:lhs) 243 | \ (s:named_key_rhs(a:submode, a:lhs) 244 | \ . (s:has_flag_p(a:options, 'x') 245 | \ ? s:named_key_leave(a:submode) 246 | \ : s:named_key_enter(a:submode))) 247 | execute s:map_command(a:mode, s:filter_flags(a:options, 'r')) 248 | \ s:map_options(s:filter_flags(a:options, 'besu')) 249 | \ s:named_key_rhs(a:submode, a:lhs) 250 | \ a:rhs 251 | 252 | let keys = s:split_keys(a:lhs) 253 | for n in range(1, len(keys) - 1) 254 | let first_n_keys = join(keys[:-(n+1)], '') 255 | silent! execute s:map_command(a:mode, 'r') 256 | \ s:map_options(s:filter_flags(a:options, 'bu')) 257 | \ (s:named_key_prefix(a:submode) . first_n_keys) 258 | \ s:named_key_leave(a:submode) 259 | endfor 260 | 261 | return 262 | endfunction 263 | 264 | 265 | 266 | 267 | function! s:undefine_submode_mapping(submode, mode, options, lhs) "{{{2 268 | execute s:map_command(a:mode, 'u') 269 | \ s:map_options(s:filter_flags(a:options, 'b')) 270 | \ s:named_key_rhs(a:submode, a:lhs) 271 | 272 | let keys = s:split_keys(a:lhs) 273 | for n in range(len(keys), 1, -1) 274 | let first_n_keys = join(keys[:n-1], '') 275 | execute s:map_command(a:mode, 'u') 276 | \ s:map_options(s:filter_flags(a:options, 'b')) 277 | \ s:named_key_prefix(a:submode) . first_n_keys 278 | if s:longer_mapping_exists_p(s:named_key_prefix(a:submode), first_n_keys) 279 | execute s:map_command(a:mode, 'r') 280 | \ s:map_options(s:filter_flags(a:options, 'b')) 281 | \ s:named_key_prefix(a:submode) . first_n_keys 282 | \ s:named_key_leave(a:submode) 283 | break 284 | endif 285 | endfor 286 | 287 | return 288 | endfunction 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | " Misc. "{{{1 298 | function! s:each_char(s) "{{{2 299 | return split(a:s, '.\zs') 300 | endfunction 301 | 302 | 303 | 304 | 305 | function! s:filter_flags(s, cs) "{{{2 306 | return join(map(s:each_char(a:cs), 's:has_flag_p(a:s, v:val) ? v:val : ""'), 307 | \ '') 308 | endfunction 309 | 310 | 311 | 312 | 313 | function! s:has_flag_p(s, c) "{{{2 314 | return 0 <= stridx(a:s, a:c) 315 | endfunction 316 | 317 | 318 | 319 | 320 | function! s:insert_mode_p(mode) "{{{2 321 | return a:mode =~# '^[iR]' 322 | endfunction 323 | 324 | 325 | 326 | 327 | function! s:longer_mapping_exists_p(submode, lhs) "{{{2 328 | " FIXME: Implement the proper calculation. 329 | " Note that mapcheck() can't be used for this purpose because it may 330 | " act as s:shorter_mapping_exists_p() if there is such a mapping. 331 | return !0 332 | endfunction 333 | 334 | 335 | 336 | 337 | function! s:map_command(mode, flags) "{{{2 338 | if s:has_flag_p(a:flags, 'u') 339 | return a:mode . 'unmap' 340 | else 341 | return a:mode . (s:has_flag_p(a:flags, 'r') ? 'map' : 'noremap') 342 | endif 343 | endfunction 344 | 345 | 346 | 347 | 348 | function! s:map_options(options) "{{{2 349 | let _ = { 350 | \ 'b': '', 351 | \ 'e': '', 352 | \ 's': '', 353 | \ 'u': '', 354 | \ } 355 | return join(map(s:each_char(a:options), 'get(_, v:val, "")')) 356 | endfunction 357 | 358 | 359 | 360 | 361 | function! s:mapping_exists_p(keyseq, mode) "{{{2 362 | return maparg(a:keyseq, a:mode) != '' 363 | endfunction 364 | 365 | 366 | 367 | 368 | function! s:may_override_showmode_p(mode) "{{{2 369 | " Normal mode / Visual mode (& its variants) / Insert mode (& its variants) 370 | return a:mode =~# "^[nvV\sS\]" || s:insert_mode_p(a:mode) 371 | endfunction 372 | 373 | 374 | 375 | 376 | function! s:named_key_before_action(submode) "{{{2 377 | return printf('(submode-before-action:%s)', a:submode) 378 | endfunction 379 | 380 | 381 | 382 | 383 | function! s:named_key_before_entering(submode) "{{{2 384 | return printf('(submode-before-entering:%s)', a:submode) 385 | endfunction 386 | 387 | 388 | 389 | 390 | function! s:named_key_before_entering_with(submode, lhs) "{{{2 391 | return printf('(submode-before-entering:%s:with:%s)', a:submode, a:lhs) 392 | endfunction 393 | 394 | 395 | 396 | 397 | function! s:named_key_enter(submode) "{{{2 398 | return printf('(submode-enter:%s)', a:submode) 399 | endfunction 400 | 401 | 402 | 403 | 404 | function! s:named_key_leave(submode) "{{{2 405 | return printf('(submode-leave:%s)', a:submode) 406 | endfunction 407 | 408 | 409 | 410 | 411 | function! s:named_key_prefix(submode) "{{{2 412 | return printf('(submode-prefix:%s)%s', a:submode, s:STEALTH_TYPEAHEAD) 413 | endfunction 414 | 415 | 416 | 417 | 418 | function! s:named_key_rhs(submode, lhs) "{{{2 419 | return printf('(submode-rhs:%s:for:%s)', a:submode, a:lhs) 420 | endfunction 421 | 422 | 423 | 424 | 425 | function! s:on_entering_submode(submode) "{{{2 426 | call s:set_up_options(a:submode) 427 | return '' 428 | endfunction 429 | 430 | 431 | 432 | 433 | function! s:on_executing_action(submode) "{{{2 434 | if (s:original_showmode || g:submode_always_show_submode) 435 | \ && s:may_override_showmode_p(mode()) 436 | echohl ModeMsg 437 | echo '-- Submode:' a:submode '--' 438 | echohl None 439 | endif 440 | return '' 441 | endfunction 442 | 443 | 444 | 445 | 446 | function! s:on_leaving_submode(submode) "{{{2 447 | if (s:original_showmode || g:submode_always_show_submode) 448 | \ && s:may_override_showmode_p(mode()) 449 | if s:insert_mode_p(mode()) 450 | let cursor_position = getpos('.') 451 | endif 452 | 453 | " BUGS: :redraw! doesn't redraw 'showmode'. 454 | execute "normal! \" 455 | 456 | if s:insert_mode_p(mode()) 457 | call setpos('.', cursor_position) 458 | endif 459 | endif 460 | if !g:submode_keep_leaving_key && getchar(1) isnot 0 461 | " To completely ignore unbound key sequences in a submode, 462 | " here we have to fetch and drop the last key in the key sequence. 463 | call getchar() 464 | endif 465 | call s:restore_options() 466 | return '' 467 | endfunction 468 | 469 | 470 | 471 | 472 | function! s:remove_flag(s, c) "{{{2 473 | " Assumption: a:c is not a meta character. 474 | return substitute(a:s, a:c, '', 'g') 475 | endfunction 476 | 477 | 478 | 479 | 480 | function! s:restore_options() "{{{2 481 | if !s:options_overridden_p 482 | return 483 | endif 484 | let s:options_overridden_p = 0 485 | 486 | let &showcmd = s:original_showcmd 487 | let &showmode = s:original_showmode 488 | let &timeout = s:original_timeout 489 | let &timeoutlen = s:original_timeoutlen 490 | let &ttimeout = s:original_ttimeout 491 | let &ttimeoutlen = s:original_ttimeoutlen 492 | 493 | let s:current_submode = '' 494 | 495 | return 496 | endfunction 497 | 498 | 499 | 500 | 501 | function! s:set_up_options(submode) "{{{2 502 | if s:options_overridden_p 503 | return 504 | endif 505 | let s:options_overridden_p = !0 506 | 507 | let s:original_showcmd = &showcmd 508 | let s:original_showmode = &showmode 509 | let s:original_timeout = &timeout 510 | let s:original_timeoutlen = &timeoutlen 511 | let s:original_ttimeout = &ttimeout 512 | let s:original_ttimeoutlen = &ttimeoutlen 513 | 514 | " NB: 'showcmd' must be enabled to render the cursor properly. 515 | " If 'showcmd' is disabled and the current submode message is rendered, the 516 | " cursor is rendered at the end of the message, not the actual position in 517 | " the current window. (gh-9) 518 | set showcmd 519 | set noshowmode 520 | let &timeout = g:submode_timeout 521 | let &ttimeout = s:original_timeout ? !0 : s:original_ttimeout 522 | let &timeoutlen = g:submode_timeoutlen 523 | let &ttimeoutlen = s:original_ttimeoutlen < 0 524 | \ ? s:original_timeoutlen 525 | \ : s:original_ttimeoutlen 526 | 527 | let s:current_submode = a:submode 528 | 529 | return 530 | endfunction 531 | 532 | 533 | 534 | 535 | function! s:split_keys(keyseq) "{{{2 536 | " Assumption: Special keys such as are escaped with < and >, i.e., 537 | " a:keyseq doesn't directly contain any escape sequences. 538 | return split(a:keyseq, '\(<[^<>]\+>\|.\)\zs') 539 | endfunction 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | " __END__ "{{{1 549 | " vim: foldmethod=marker 550 | -------------------------------------------------------------------------------- /doc/submode.txt: -------------------------------------------------------------------------------- 1 | *submode.txt* Create your own submodes 2 | 3 | Version 0.3.1 4 | Script ID: 2467 5 | Copyright (C) 2008-2014 kana 6 | License: MIT license {{{ 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included 16 | in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | }}} 26 | 27 | CONTENTS *submode-contents* 28 | 29 | Introduction |submode-introduction| 30 | Interface |submode-interface| 31 | Functions |submode-functions| 32 | Variables |submode-variables| 33 | Bugs |submode-bugs| 34 | Changelog |submode-changelog| 35 | 36 | 37 | 38 | 39 | ============================================================================== 40 | INTRODUCTION *submode-introduction* 41 | 42 | *submode* is a Vim plugin to provide the way to define "submodes" to the 43 | built-in |vim-modes|. For example, whenever you type |g-| and/or |g+| to 44 | undo/redo many times, don't you want to type "g++--++..." instead 45 | "g+g+g-g-g+g+..."? With this plugin, you can define such interface with the 46 | following settings: 47 | > 48 | call submode#enter_with('undo/redo', 'n', '', 'g-', 'g-') 49 | call submode#enter_with('undo/redo', 'n', '', 'g+', 'g+') 50 | call submode#leave_with('undo/redo', 'n', '', '') 51 | call submode#map('undo/redo', 'n', '', '-', 'g-') 52 | call submode#map('undo/redo', 'n', '', '+', 'g+') 53 | < 54 | The above settings mean: 55 | - Define a new submode named "undo/redo". 56 | - Define "g-" and "g+" as key sequences to enter the submode "undo/redo" from 57 | Normal mode. Additionally, they does undo/redo before entering the submode 58 | "undo/redo". 59 | - In the submode "undo/redo", "-" and "+" do undo/redo. 60 | - In the submode "undo/redo", "" leaves the submode. 61 | 62 | *submode-leaving* 63 | By default, is automatically defined as a key to leave any submode. 64 | So you don't have to explicitly define like the above example. 65 | There are also 2 ways to leave submodes: 66 | - Type any key sequence which is not mapped in the submode. 67 | See also |g:submode_keep_leaving_key|. 68 | - Don't type any key for a long time. 69 | See |submode-variables| to configure the details of this time out. 70 | 71 | 72 | Requirements: 73 | - Vim 7.2 or later 74 | 75 | Latest version: 76 | https://github.com/kana/vim-submode 77 | 78 | Document in HTML format: 79 | http://vim-doc.heroku.com/view?https://raw.github.com/kana/vim-submode/master/doc/submode.txt 80 | 81 | 82 | 83 | 84 | ============================================================================== 85 | INTERFACE *submode-interface* 86 | 87 | ------------------------------------------------------------------------------ 88 | COMMANDS *submode-commands* 89 | 90 | :SubmodeRestoreOptions *:SubmodeRestoreOptions* 91 | Ex command version of |submode#restore_options()|. 92 | 93 | 94 | 95 | 96 | ------------------------------------------------------------------------------ 97 | FUNCTIONS *submode-functions* 98 | 99 | *submode#current()* 100 | submode#current() 101 | Return the name of the current submode. If any 102 | submode is not currently active, return an empty 103 | string instead. 104 | 105 | *submode#enter_with()* 106 | submode#enter_with({submode}, {modes}, {options}, {lhs}, [{rhs}]) 107 | Define a key mapping to enter the {submode} from 108 | {modes}. If {rhs} is given, it will be executed 109 | whenever entering the {submode} by {lhs}. 110 | 111 | See |submode#map()| for the details of arguments. 112 | 113 | *submode#leave_with()* 114 | submode#leave_with({submode}, {modes}, {options}, {lhs}) 115 | Define a key mapping ({lhs}) to leave the {submode} in 116 | {modes}. 117 | 118 | See |submode#map()| for the details of arguments. 119 | 120 | *submode#map()* 121 | submode#map({submode}, {modes}, {options}, {lhs}, {rhs}) 122 | Define a key mapping ({lhs} to {rhs}) in the {submode} 123 | in {modes}. 124 | 125 | {submode} String 126 | The name of the submode. It is recommended to 127 | use only the following characters: 128 | 129 | Alphabets A-Z, a-z 130 | Digits 0-9 131 | Some symbols -, _, / 132 | 133 | Note that the submode name is used as parts of 134 | internal key mappings. Use a short name. 135 | 136 | {modes} String 137 | A sequence of letters which specifies the 138 | modes to define a key mapping. The meanings 139 | of letters are as follows: 140 | 141 | c Command-line mode 142 | i Insert mode 143 | n Normal mode 144 | s Select mode only 145 | v Visual mode and Select mode 146 | x Visual mode only 147 | 148 | Note that Operator-pending mode and 149 | |language-mapping| are not supported, because 150 | the both modes are always leaved by 1 key 151 | sequence, so that submdoes can't be built on 152 | the both modes. 153 | 154 | {options} String 155 | A sequence of letters which specifies some 156 | options for a key mapping to be defined. The 157 | meanings of letters are as follows: 158 | 159 | b Same as |:map-|. 160 | e Same as |:map-|. 161 | r {rhs} may be remapped. 162 | If this letter is not included, 163 | {rhs} will be never remapped. 164 | s Same as |:map-|. 165 | u Same as |:map-|. 166 | x After executing {rhs}, leave the 167 | submode. This matters only for 168 | |submode#map()|. 169 | 170 | {lhs} String 171 | A key sequence to type. 172 | 173 | To denote a special key such as , write 174 | it in <>-escaped form instead of the character 175 | as is. For example, use '' instead of 176 | "\". 177 | 178 | {rhs} String 179 | A key sequence to be executed by typing {lhs}. 180 | 181 | See also {lhs} for other notes. 182 | 183 | submode#restore_options() *submode#restore_options()* 184 | Restore options overriden by this plugin. 185 | 186 | This plugin overrides some options before entering 187 | a submode and restores the options after leaving 188 | a submode. can be used to leave a submode, but 189 | it disturbs to restore the options. Call this 190 | function if you do so. 191 | 192 | *submode#unmap()* 193 | submode#unmap({submode}, {modes}, {options}, {lhs}) 194 | Delete a key mapping ({lhs} to something) in the 195 | {submode} in {modes}. 196 | 197 | See |submode#map()| for the details of arguments. 198 | Note that only "b" matters for {options} and other 199 | letters are just ignored. 200 | 201 | ------------------------------------------------------------------------------ 202 | VARIABLES *submode-variables* 203 | 204 | *g:submode_always_show_submode* 205 | g:submode_always_show_submode boolean (default: false) 206 | Show always the current submode, even if 'showmode' is disabled. 207 | Use this option if you use vim-airline or vim-powerline. 208 | 209 | 'showmode' g:submode_always_show_submode the current submode ~ 210 | off off not shown 211 | on off shown 212 | off on shown 213 | on on shown 214 | 215 | *g:submode_keep_leaving_key* 216 | g:submode_keep_leaving_key boolean (default: false) 217 | Whenever you type any key which is not mapped in the current submode, 218 | it causes to leave from the submode. In this case, the key is 219 | consumed by default. If this variable is set to true, the key is not 220 | consumed and will be processed by Vim. 221 | 222 | For example, when you type an unmapped key "X" to leave from the 223 | current submode of Normal mode, the "X" will be consumed by default. 224 | If this variable is set to true, the "X" will be processed by Vim, so 225 | that a characer before the cursor will be deleted unless you map |X| 226 | to something. 227 | 228 | *g:submode_keyseqs_to_leave* 229 | g:submode_keyseqs_to_leave list of strings (default: ['']) 230 | The default key sequences to leave a submode. 231 | 232 | *g:submode_timeout* 233 | g:submode_timeout boolean (default: same as 'timeout') 234 | If this value is true, time out on submodes is enabled. Otherwise, 235 | time out is disabled. If time out is enabled, not typing any key in 236 | a submode for a long time causes to leave the submode. 237 | 238 | If this variable is not defined, the value of 'timeout' is used 239 | instead. 240 | 241 | *g:submode_timeoutlen* 242 | g:submode_timeoutlen number (default: same as 'timeoutlen') 243 | The time in milliseconds that is waited for typing keys in a submode. 244 | 245 | If this variable is not defined, the value of 'timeoutlen' is used 246 | instead. 247 | 248 | 249 | 250 | 251 | ============================================================================== 252 | BUGS *submode-bugs* 253 | 254 | LIMITATIONS ~ 255 | 256 | - The maximum length of {lhs} of normal key mappings is 50. Since submode key 257 | mappings are built on top of normal key mappings, the maximum length of 258 | a submode {lhs} is shorter than 50. Usually 10 or more characters are 259 | available, depending on a submode name. And it is enough length because you 260 | don't want to type 4 or more keys to execute a command. 261 | 262 | - In {rhs} of a key mapping for a submode, cannot be used. Because key 263 | mappings for a submode is defined by this plugin, not callers. 264 | 265 | - To behave the same as Normal mode and Visual mode, any unbound key sequence 266 | should be ignored in a submode, but it's impossible to implement. 267 | 268 | - 'showcmd' is always turned on a submode to render the cursor properly. 269 | 270 | - If 'showcmd' is turned on and 'encoding' is set to a non-Unicode encoding, 271 | ".........." is showed at the bottom right corner while a submode is active. 272 | This is to hide a part of internal key mappings for submode key mappings. 273 | 274 | 275 | PROBLEMS ~ 276 | 277 | - [count] is not supported in a submode. 278 | 279 | - |submode#unmap()| does not actually unmap key mappings. It just replaces 280 | rhs with , but it may cause some problems. 281 | 282 | - The current API to define submode key mappings is somewhat low-level. 283 | It might be useful to add |:map|-like commands for readability. 284 | 285 | 286 | 287 | 288 | ============================================================================== 289 | CHANGELOG *submode-changelog* 290 | 291 | 0.3.1 2014-02-16T18:59:21+09:00 *submode-changelog-0.3.1* 292 | - Fix to hide unintended messages which were shown in the command line 293 | whenever users leave from a submode. 294 | 295 | 0.3.0 2014-02-15T21:15:46+09:00 *submode-changelog-0.3.0* 296 | - Add |submode#current()|. 297 | - Tidy up the document a bit. 298 | 299 | 0.2.0 2014-02-05T23:56:14+09:00 *submode-changelog-0.2.0* 300 | - Add |g:submode_always_show_submode| for users preferring 301 | 'statusline' such as vim-airline and vim-powerline. 302 | - Fix a rendering problem on the cursor. The problem was happened if 303 | 'showcmd' is off and 'showmode' is on. 304 | - Fix not to show internal key mappings in 'showcmd' area. 305 | - Add a note about a limitation of {lhs} length. See |submode-bugs|. 306 | 307 | 0.1.0 2013-03-16T16:34:49+09:00 *submode-changelog-0.1.0* 308 | - Allow to keep a key to leave from the current mode. 309 | See also |g:submode_keep_leaving_key| for the details. 310 | - Improve the document a bit. 311 | 312 | 0.0.1 2012-03-24T14:32:30+09:00 *submode-changelog-0.0.1* 313 | - Refine the document a bit. 314 | - Refine the internal structure a bit. 315 | 316 | 0.0.0 2008-11-27T01:58:43+09:00 *submode-changelog-0.0.0* 317 | - Initial version. 318 | 319 | 320 | 321 | 322 | ============================================================================== 323 | vim:tw=78:ts=8:ft=help:norl:fen:fdl=0:fdm=marker: 324 | -------------------------------------------------------------------------------- /t/current.vim: -------------------------------------------------------------------------------- 1 | call submode#enter_with('foo', 'n', '', 'sa') 2 | call submode#enter_with('bar', 'n', '', 'sb') 3 | call submode#enter_with('baz', 'n', '', 'sc') 4 | call submode#map('foo', 'n', 'e', 'm', 'Stash()') 5 | call submode#map('bar', 'n', 'e', 'm', 'Stash()') 6 | call submode#map('baz', 'n', 'e', 'm', 'Stash()') 7 | 8 | let g:submode = '' 9 | function! Stash() 10 | let g:submode = submode#current() 11 | return '' 12 | endfunction 13 | 14 | describe 'submode#current' 15 | it 'returns an empty string if any submode is not active' 16 | Expect submode#current() ==# '' 17 | end 18 | 19 | it 'returns the name of the current submode' 20 | execute 'normal' "sa\" 21 | Expect g:submode ==# '' 22 | 23 | execute 'normal' "sam\" 24 | Expect g:submode ==# 'foo' 25 | 26 | execute 'normal' "sbm\" 27 | Expect g:submode ==# 'bar' 28 | 29 | execute 'normal' "scm\" 30 | Expect g:submode ==# 'baz' 31 | 32 | Expect submode#current() ==# '' 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /t/expr.vim: -------------------------------------------------------------------------------- 1 | function! Flip() 2 | let g:flipped = !g:flipped 3 | return g:flipped 4 | endfunction 5 | let g:flipped = 0 6 | 7 | call submode#enter_with('expr', 'n', 'e', 'j', 'Flip() ? "k" : "j"') 8 | 9 | describe ' mapping in a submode' 10 | before 11 | new 12 | put =range(1, 30) 13 | 1 delete _ 14 | end 15 | 16 | after 17 | quit! 18 | end 19 | 20 | it 'works' 21 | normal! 10G 22 | Expect line('.') == 10 23 | 24 | normal j 25 | Expect line('.') == 9 26 | 27 | normal j 28 | Expect line('.') == 10 29 | 30 | normal j 31 | Expect line('.') == 9 32 | 33 | normal j 34 | Expect line('.') == 10 35 | end 36 | 37 | it 'is not applied to the default key mapping to leave a submode' 38 | normal! 10G 39 | 40 | let v:errmsg = '' 41 | execute 'normal' "j\" 42 | Expect v:errmsg ==# '' 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /t/keep-leaving-key.vim: -------------------------------------------------------------------------------- 1 | call submode#enter_with('boost', 'n', '', 'j', 'j') 2 | call submode#enter_with('boost', 'n', '', 'k', 'k') 3 | call submode#map('boost', 'n', '', 'j', 'jjj') 4 | call submode#map('boost', 'n', '', 'k', 'kkk') 5 | 6 | describe 'g:submode_keep_leaving_key' 7 | before 8 | new 9 | put =range(1, 30) 10 | 1 delete _ 11 | end 12 | 13 | after 14 | quit! 15 | end 16 | 17 | it 'does not keep a leaving key by default' 18 | Expect line('.') == 1 19 | 20 | normal ggj 21 | Expect line('.') == 2 22 | 23 | normal ggjj 24 | Expect line('.') == 5 25 | 26 | normal ggjjj 27 | Expect line('.') == 8 28 | 29 | normal ggjjjx 30 | Expect line('.') == 8 31 | Expect getline('.') ==# '8' 32 | end 33 | 34 | it 'does not keep a leaving key if g:submode_keep_leaving_key is false' 35 | let g:submode_keep_leaving_key = 0 36 | 37 | Expect line('.') == 1 38 | 39 | normal ggj 40 | Expect line('.') == 2 41 | 42 | normal ggjj 43 | Expect line('.') == 5 44 | 45 | normal ggjjj 46 | Expect line('.') == 8 47 | 48 | normal ggjjjx 49 | Expect line('.') == 8 50 | Expect getline('.') ==# '8' 51 | end 52 | 53 | it 'keeps a leaving key if g:submode_keep_leaving_key is true' 54 | let g:submode_keep_leaving_key = 1 55 | 56 | Expect line('.') == 1 57 | 58 | normal ggj 59 | Expect line('.') == 2 60 | 61 | normal ggjj 62 | Expect line('.') == 5 63 | 64 | normal ggjjj 65 | Expect line('.') == 8 66 | 67 | normal ggjjjx 68 | Expect line('.') == 8 69 | Expect getline('.') ==# '' 70 | end 71 | end 72 | --------------------------------------------------------------------------------