mirror of
https://github.com/amix/vimrc
synced 2025-07-18 09:35:00 +08:00
merge
This commit is contained in:
1
sources_non_forked/vim-multiple-cursors/.gitignore
vendored
Normal file
1
sources_non_forked/vim-multiple-cursors/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/doc/tags
|
@ -1,7 +1,11 @@
|
||||
sudo: false
|
||||
language: ruby
|
||||
rvm:
|
||||
- 1.9.3
|
||||
before_install: sudo apt-get install vim-gtk
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- vim-gtk
|
||||
|
||||
before_script:
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
|
23
sources_non_forked/vim-multiple-cursors/CONTRIBUTING.md
Normal file
23
sources_non_forked/vim-multiple-cursors/CONTRIBUTING.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Problems summary
|
||||
|
||||
## Expected
|
||||
|
||||
## Environment Information
|
||||
* OS:
|
||||
* Neovim/Vim/Gvim version:
|
||||
|
||||
## Provide a minimal .vimrc with less than 50 lines
|
||||
|
||||
" Your minimal.vimrc
|
||||
|
||||
## Generate a logfile if appropriate
|
||||
|
||||
1. export NVIM_PYTHON_LOG_FILE=/tmp/log
|
||||
2. export NVIM_PYTHON_LOG_LEVEL=DEBUG
|
||||
3. nvim -u minimal.vimrc
|
||||
4. recreate your issue
|
||||
5. cat /tmp/log_{PID}
|
||||
|
||||
## Screen shot (if possible)
|
||||
|
||||
## Upload the log file
|
@ -1,17 +1,22 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
diff-lcs (1.2.4)
|
||||
rake (10.0.4)
|
||||
rspec (2.13.0)
|
||||
rspec-core (~> 2.13.0)
|
||||
rspec-expectations (~> 2.13.0)
|
||||
rspec-mocks (~> 2.13.0)
|
||||
rspec-core (2.13.1)
|
||||
rspec-expectations (2.13.0)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
rspec-mocks (2.13.1)
|
||||
vimrunner (0.3.0)
|
||||
diff-lcs (1.2.5)
|
||||
rake (10.4.2)
|
||||
rspec (3.4.0)
|
||||
rspec-core (~> 3.4.0)
|
||||
rspec-expectations (~> 3.4.0)
|
||||
rspec-mocks (~> 3.4.0)
|
||||
rspec-core (3.4.1)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-expectations (3.4.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-mocks (3.4.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.4.0)
|
||||
rspec-support (3.4.1)
|
||||
vimrunner (0.3.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@ -20,3 +25,6 @@ DEPENDENCIES
|
||||
rake
|
||||
rspec
|
||||
vimrunner
|
||||
|
||||
BUNDLED WITH
|
||||
1.10.6
|
||||
|
@ -1,4 +1,28 @@
|
||||
# vim-multiple-cursors [](https://travis-ci.org/terryma/vim-multiple-cursors)
|
||||
# vim-multiple-cursors
|
||||
[](https://travis-ci.org/terryma/vim-multiple-cursors)
|
||||
[](http://issuestats.com/github/terryma/vim-multiple-cursors)
|
||||
[](http://issuestats.com/github/terryma/vim-multiple-cursors)
|
||||
## Contents
|
||||
- [About](#about)
|
||||
- [Features](#features)
|
||||
- [Installation](#installation)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Mapping](#mapping)
|
||||
- [Settings](#settings)
|
||||
- [Interactions with other plugins](#interactions-with-other-plugins)
|
||||
- [Highlight](#highlight)
|
||||
- *[FAQ](#faq)*
|
||||
- *[Known issues](#known-issues)*
|
||||
- *[Issue creation requirements](#issue-creation-requirements)*
|
||||
- [Changelog](#changelog)
|
||||
- [Contributing](#contributing)
|
||||
- [Credit](#credit)
|
||||
|
||||
###Contributors
|
||||
- [eapache](https://github.com/eapache)
|
||||
- [aschrab](https://github.com/aschrab)
|
||||
- [kristijanhusak](https://github.com/kristijanhusak)
|
||||
- [faceleg](https://github.com/faceleg)
|
||||
|
||||
## About
|
||||
[There](https://github.com/paradigm/vim-multicursor) [have](https://github.com/felixr/vim-multiedit) [been](https://github.com/hlissner/vim-multiedit) [many](https://github.com/adinapoli/vim-markmultiple) [attempts](https://github.com/AndrewRadev/multichange.vim) at bringing Sublime Text's awesome [multiple selection][sublime-multiple-selection] feature into Vim, but none so far have been in my opinion a faithful port that is simplistic to use, yet powerful and intuitive enough for an existing Vim user. [vim-multiple-cursors] is yet another attempt at that.
|
||||
@ -6,27 +30,36 @@
|
||||
### It's great for quick refactoring
|
||||

|
||||
|
||||
Vim command sequence: `2Gfp<C-n><C-n><C-n>cname`
|
||||
|
||||
### Add a cursor to each line of your visual selection
|
||||

|
||||
|
||||
Vim command sequence: `2Gvip<C-n>i"<Right><Right><Right>",<Esc>vipJ$r]Idays = [`
|
||||
|
||||
### Do it backwards too! This is not just a replay of the above gif :)
|
||||

|
||||
|
||||
Vim command sequence: `2Gdf[$r,0f,v<C-n>…<C-n>c<CR><Up><Del><Right><Right><Right><Del>`
|
||||
|
||||
### Add multiple cursors using regexes
|
||||

|
||||
|
||||
To see what keystrokes are used for the above example, see [this issue](https://github.com/terryma/vim-multiple-cursors/issues/39).
|
||||
To see what keystrokes are used for the above examples, see [the wiki page](https://github.com/terryma/vim-multiple-cursors/wiki/Keystrokes-for-example-gifs).
|
||||
|
||||
## Features
|
||||
- Live update in Insert mode
|
||||
- One key to rule it all! See [Quick Start](#quick-start) on what the key does in different scenarios
|
||||
- Works in Normal, Insert, and Visual mode for SINGLE key command
|
||||
- Works in Normal, Insert, and Visual mode for any commands (including
|
||||
multi-key commands, assuming you set `g:multicursor_insert_maps` and
|
||||
`g:multicursor_normal_maps`; see Settings below for details)
|
||||
|
||||
## Installation
|
||||
Install using [Pathogen], [Vundle], [Neobundle], or your favorite Vim package manager.
|
||||
Requires vim 7.4 or later for full functionality.
|
||||
|
||||
## Quick Start
|
||||
Out of the box, all you need to know is a single key `Ctrl-n`. Pressing the key in Normal mode highlights the current word under the cursor in Visual mode and places a virtual cursor at the end of it. Pressing it again finds the next ocurrence and places another virtual cursor at the end of the visual selection. If you select multiple lines in Visual mode, pressing the key puts a virtual cursor at every line and leaves you in Normal mode.
|
||||
Out of the box, all you need to know is a single key `Ctrl-n`. Pressing the key in Normal mode highlights the current word under the cursor in Visual mode and places a virtual cursor at the end of it. Pressing it again finds the next occurrence and places another virtual cursor at the end of the visual selection. If you select multiple lines in Visual mode, pressing the key puts a virtual cursor at every line and leaves you in Normal mode.
|
||||
|
||||
After you've marked all your locations with `Ctrl-n`, you can change the visual selection with normal Vim motion commands in Visual mode. You could go to Normal mode by pressing `v` and wield your motion commands there. Single key command to switch to Insert mode such as `c` or `s` from Visual mode or `i`, `a`, `I`, `A` in Normal mode should work without any issues.
|
||||
|
||||
@ -36,18 +69,18 @@ Two additional keys are also mapped:
|
||||
- `Ctrl-p` in Visual mode will remove the current virtual cursor and go back to the previous virtual cursor location. This is useful if you are trigger happy with `Ctrl-n` and accidentally went too far.
|
||||
- `Ctrl-x` in Visual mode will remove the current virtual cursor and skip to the next virtual cursor location. This is useful if you don't want the current selection to be a candidate to operate on later.
|
||||
|
||||
You can also add multiple cursors using a regular expression. The command `MultipleCursorsFind` accepts a range and a pattern, and it will create a virtual cursor at the end of every match within the range. If no range is passed in, then it defaults to the entire buffer.
|
||||
You can also add multiple cursors using a regular expression. The command `MultipleCursorsFind` accepts a range and a pattern, and it will create a virtual cursor at the end of every match within the range. If no range is passed in, then it defaults to the entire buffer.
|
||||
|
||||
**NOTE:** If at any time you have lingering cursors on screen, you can press `Ctrl-n` in Normal mode and it will remove all prior cursors before starting a new one.
|
||||
|
||||
## Mapping
|
||||
Out of the box, only the single key `Ctrl-n` is mapped in regular Vim's Normal mode and Visual mode to provide the functionality mentioned above. `Ctrl-n`, `Ctrl-p`, `Ctrl-x`, and `<Esc>` are mapped in the special multicursor mode once you've added at least one virtual cursor to the buffer. If you don't like the plugin taking over your favorite key bindings, you can turn off the default with
|
||||
```
|
||||
```viml
|
||||
let g:multi_cursor_use_default_mapping=0
|
||||
```
|
||||
|
||||
You can then map the 'next', 'previous', 'skip', and 'exit' keys like the following:
|
||||
```
|
||||
```viml
|
||||
" Default mapping
|
||||
let g:multi_cursor_next_key='<C-n>'
|
||||
let g:multi_cursor_prev_key='<C-p>'
|
||||
@ -56,48 +89,149 @@ let g:multi_cursor_quit_key='<Esc>'
|
||||
```
|
||||
|
||||
By default, the 'next' key is also used to enter multicursor mode. If you want to use a different key to start multicursor mode than for selecting the next location, do like the following:
|
||||
```
|
||||
```viml
|
||||
" Map start key separately from next key
|
||||
let g:multi_cursor_start_key='<F6>'
|
||||
```
|
||||
|
||||
**IMPORTANT:** Please note that currently only single keystrokes and special keys can be mapped. This contraint is also the reason why multikey commands such as `ciw` do not work and cause unexpected behavior in Normal mode. This means that a mapping like `<Leader>n` will NOT work correctly. For a list of special keys that are supported, see `help :key-notation`
|
||||
Note that when multicursor mode is started, it selects current word with boundaries, i.e. it behaves like `*`. If you want to avoid word boundaries in Normal mode (as `g*` does) but still have old behaviour up your sleeve, you can do the following:
|
||||
```viml
|
||||
let g:multi_cursor_start_key='<C-n>'
|
||||
let g:multi_cursor_start_word_key='g<C-n>'
|
||||
```
|
||||
In this configuration `<C-n>` will start multicursor mode without word boundaries (but only in Normal mode, as it does not make much sense to use it in Visual mode). Old behaviour with word boundaries is still available using `g<C-n>`.
|
||||
|
||||
**IMPORTANT:** Please note that currently only single keystrokes and special keys can be mapped. This means that a mapping like `<Leader>n` will NOT work correctly. For a list of special keys that are supported, see `help :key-notation`
|
||||
|
||||
**NOTE:** Please make sure to always map something to `g:multi_cursor_quit_key`, otherwise you'll have a tough time quitting from multicursor mode.
|
||||
|
||||
**NOTE:** Prior to version 1.3, the recommended way to map the keys is using the expressoin quote syntax in Vim, using something like `"\<C-n>"` or `"\<Esc>"` (see h: expr-quote). After 1.3, the recommended way is to use a raw string like above. If your key mappings don't appear to work, give the new syntax a try.
|
||||
**NOTE:** Prior to version 1.3, the recommended way to map the keys is using the expression quote syntax in Vim, using something like `"\<C-n>"` or `"\<Esc>"` (see h: expr-quote). After 1.3, the recommended way is to use a raw string like above. If your key mappings don't appear to work, give the new syntax a try.
|
||||
|
||||
You can also map your own keys to quit, if ``g:multi_cursor_quit_key`` won't work:
|
||||
|
||||
```
|
||||
let g:multi_cursor_quit_key='<C-c>'
|
||||
nnoremap <C-c> :call multiple_cursors#quit()<CR>
|
||||
```
|
||||
|
||||
## Settings
|
||||
Currently there are four additional global settings one can tweak:
|
||||
|
||||
## Setting
|
||||
Currently there're two additional global settings one can tweak:
|
||||
### ```g:multi_cursor_exit_from_visual_mode``` (Default: 1)
|
||||
|
||||
If set to 0, then pressing `g:multi_cursor_quit_key` in _Visual_ mode will not quit and delete all existing cursors. This is useful if you want to press Escape and go back to Normal mode, and still be able to operate on all the cursors.
|
||||
|
||||
### ```g:multi_cursor_exit_from_insert_mode``` (Default: 1)
|
||||
If set to 0, then pressing `g:multi_cursor_quit_key` in _Insert_ mode will not quit and delete all existing cursors. This is useful if you want to press Escape and go back to Normal mode, and still be able to operate on all the cursors.
|
||||
|
||||
### ```g:multi_cursor_insert_maps``` (Default: `{}`)
|
||||
Any key in this map (values are ignored) will cause multi-cursor _Insert_ mode
|
||||
to pause for `timeoutlen` waiting for map completion just like normal vim.
|
||||
Otherwise keys mapped in insert mode are ignored when multiple cursors are
|
||||
active. For example, setting it to `{'\':1}` will make insert-mode mappings
|
||||
beginning with the default leader key work in multi-cursor mode. You have to
|
||||
manually set this because vim doesn't provide a way to see which keys _start_
|
||||
mappings.
|
||||
|
||||
### ```g:multi_cursor_normal_maps``` (Default: see below)
|
||||
Default value: `{'!':1, '@':1, '=':1, 'q':1, 'r':1, 't':1, 'T':1, 'y':1, '[':1, ']':1, '\':1, 'd':1, 'f':1, 'F':1, 'g':1, '"':1, 'z':1, 'c':1, 'm':1, '<':1, '>':1}`
|
||||
|
||||
Any key in this map (values are ignored) will cause multi-cursor _Normal_ mode
|
||||
to pause for map completion just like normal vim. Otherwise keys mapped in
|
||||
normal mode will "fail to replay" when multiple cursors are active. For example,
|
||||
changing it from `{}` to `{'d':1}` makes normal-mode mappings beginning with `d`
|
||||
(such as `dw` to delete a word) work in multi-cursor mode.
|
||||
|
||||
### ```g:multi_cursor_visual_maps``` (Default: see below)
|
||||
Default value: `{'i':1, 'a':1, 'f':1, 'F':1, 't':1, 'T':1}`
|
||||
|
||||
Any key in this map (values are ignored) will cause multi-cursor _Visual_ mode
|
||||
to pause for map completion just like normal vim. Otherwise keys mapped in
|
||||
visual mode will "fail to replay" when multiple cursors are active. For example,
|
||||
changing it from `{}` to `{'i':1}` makes visual-mode mappings beginning with `i`
|
||||
(such as `it` to select an "inner tag block") work in multi-cursor mode.
|
||||
|
||||
The default list contents should work for anybody, unless they have remapped a
|
||||
key from an operator-pending command to a non-operator-pending command or
|
||||
vice versa.
|
||||
|
||||
These keys must be manually listed because vim doesn't provide a way to
|
||||
automatically see which keys _start_ mappings, and trying to run motion commands
|
||||
such as `j` as if they were operator-pending commands can break things.
|
||||
|
||||
### Interactions with other plugins
|
||||
|
||||
### ```Multiple_cursors_before/Multiple_cursors_after``` (Default: `nothing`)
|
||||
|
||||
Other plugins may trigger on keypresses when in insert mode. These plugins
|
||||
generally provide a means to toggle their active state. These hooks allow
|
||||
the user to provide functions in their .vimrc to do this when multiple-cursor-mode
|
||||
is entered.
|
||||
|
||||
For example, if you are using [Neocomplete](https://github.com/Shougo/neocomplete.vim),
|
||||
add this to your vimrc to prevent conflict:
|
||||
|
||||
```viml
|
||||
" Called once right before you start selecting multiple cursors
|
||||
function! Multiple_cursors_before()
|
||||
if exists(':NeoCompleteLock')==2
|
||||
exe 'NeoCompleteLock'
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Called once only when the multiple selection is canceled (default <Esc>)
|
||||
function! Multiple_cursors_after()
|
||||
if exists(':NeoCompleteUnlock')==2
|
||||
exe 'NeoCompleteUnlock'
|
||||
endif
|
||||
endfunction
|
||||
```
|
||||
|
||||
With this locking and unlocking we prevent neocomplete to trigger it's function calls until we are finished with multiple cursors editing.
|
||||
|
||||
### Highlight
|
||||
The plugin uses the highlight group `multiple_cursors_cursor` and `multiple_cursors_visual` to highlight the virtual cursors and their visual selections respectively. You can customize them by putting something similar like the following in your vimrc:
|
||||
|
||||
```
|
||||
```viml
|
||||
" Default highlighting (see help :highlight and help :highlight-link)
|
||||
highlight multiple_cursors_cursor term=reverse cterm=reverse gui=reverse
|
||||
highlight link multiple_cursors_visual Visual
|
||||
```
|
||||
|
||||
## Issues
|
||||
- Multi key commands like `ciw` do not work at the moment
|
||||
- All user input typed before Vim is able to fan out the last operation to all cursors is lost. This is a implementation decision to keep the input perfectly synced in all locations, at the cost of potentially losing user input.
|
||||
## FAQ
|
||||
|
||||
#### **Q** <kbd>CTRL</kbd>+<kbd>n</kbd> doesn't seem to work in gVIM?
|
||||
|
||||
**A** Try setting `set selection=inclusive` in your `~/.gvimrc`
|
||||
|
||||
#### **Q** How can I select `n` keywords with several keystrokes? I have tried `200<C-n>` which does not work.
|
||||
|
||||
**A** You can use :MultipleCursorsFind keyword. I have this binding in my vimrc:
|
||||
|
||||
```VimL
|
||||
nnoremap <silent> <M-j> :MultipleCursorsFind <C-R>/<CR>
|
||||
vnoremap <silent> <M-j> :MultipleCursorsFind <C-R>/<CR>
|
||||
```
|
||||
|
||||
This allows one to a) search for the keyword using `*` b) turn search results into cursors with `Alt-j`.
|
||||
|
||||
## Known Issues
|
||||
- Select mode is not implemented
|
||||
|
||||
## Issue Creation Requirements
|
||||
|
||||
This is a community supported project. Contributor's time is precious and limited. To ensure your issue is not closed out of hand, please ensure it meets the requirements outlined in [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
## Changelog
|
||||
See [CHANGELOG.md](CHANGELOG.md)
|
||||
|
||||
## Contributing
|
||||
As one can see, there're still many issues to be resolved, patches and suggestions are always welcome! A list of open feature requests can be found [here](../../issues?labels=enhancement&state=open).
|
||||
|
||||
Running the test suite requires ruby and rake as well as vim of course. On Mac
|
||||
OS, [MacVim](https://code.google.com/p/macvim/) is known to work.
|
||||
|
||||
## Credit
|
||||
Obviously inspired by Sublime Text's [multiple selection][sublime-multiple-selection] feature, also encouraged by Emac's [multiple cursors][emacs-multiple-cursors] implemetation by Magnar Sveen
|
||||
Obviously inspired by Sublime Text's [multiple selection][sublime-multiple-selection] feature, also encouraged by Emac's [multiple cursors][emacs-multiple-cursors] implementation by Magnar Sveen
|
||||
|
||||
[vim-multiple-cursors]:http://github.com/terryma/vim-multiple-cursors
|
||||
[sublime-multiple-selection]:http://www.sublimetext.com/docs/2/multiple_selection_with_the_keyboard.html
|
||||
@ -107,6 +241,4 @@ Obviously inspired by Sublime Text's [multiple selection][sublime-multiple-selec
|
||||
[emacs-multiple-cursors]:https://github.com/magnars/multiple-cursors.el
|
||||
|
||||
|
||||
|
||||
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
||||
|
@ -8,22 +8,23 @@
|
||||
" it to work the way we like. '<C-n>' is converted to '\<C-n>' by the end and
|
||||
" the global vars are replaced by their new value. This is ok since the mapping
|
||||
" using '<C-n>' should already have completed in the plugin file.
|
||||
for key in [ 'g:multi_cursor_next_key',
|
||||
for s:key in [ 'g:multi_cursor_next_key',
|
||||
\ 'g:multi_cursor_prev_key',
|
||||
\ 'g:multi_cursor_skip_key',
|
||||
\ 'g:multi_cursor_quit_key' ]
|
||||
if exists(key)
|
||||
if exists(s:key)
|
||||
" Translate raw strings like "<C-n>" into key code like "\<C-n>"
|
||||
exec 'let temp = '.key
|
||||
if temp =~ '^<.*>$'
|
||||
exec 'let '.key.' = "\'.temp.'"'
|
||||
exec 'let s:temp = '.s:key
|
||||
if s:temp =~ '^<.*>$'
|
||||
exec 'let '.s:key.' = "\'.s:temp.'"'
|
||||
endif
|
||||
else
|
||||
" If the user didn't define it, initialize it to an empty string so the
|
||||
" logic later don't break
|
||||
exec 'let '.key.' = ""'
|
||||
exec 'let '.s:key.' = ""'
|
||||
endif
|
||||
endfor
|
||||
unlet! s:key s:temp
|
||||
|
||||
" These keys will not be replicated at every cursor location. Make sure that
|
||||
" this assignment happens AFTER the key tweak setting above
|
||||
@ -38,6 +39,13 @@ let s:hi_group_cursor = 'multiple_cursors_cursor'
|
||||
" The highlight group we use for all the visual selection
|
||||
let s:hi_group_visual = 'multiple_cursors_visual'
|
||||
|
||||
" Used for preventing multiple calls on before function
|
||||
let s:before_function_called = 0
|
||||
|
||||
" Used for searching whole words (search pattern is wrapped with \< and \>)
|
||||
" Keep old behaviour by default (act like g*)
|
||||
let s:use_word_boundary = 1
|
||||
|
||||
" Set up highlighting
|
||||
if !hlexists(s:hi_group_cursor)
|
||||
exec "highlight ".s:hi_group_cursor." term=reverse cterm=reverse gui=reverse"
|
||||
@ -46,32 +54,38 @@ if !hlexists(s:hi_group_visual)
|
||||
exec "highlight link ".s:hi_group_visual." Visual"
|
||||
endif
|
||||
|
||||
" Temporary buffer that is used for individual paste buffer save/restore
|
||||
" operations
|
||||
let s:paste_buffer_temporary_text = ''
|
||||
let s:paste_buffer_temporary_type = ''
|
||||
|
||||
"===============================================================================
|
||||
" Internal Mappings
|
||||
"===============================================================================
|
||||
|
||||
inoremap <silent> <Plug>(i) <C-o>:call <SID>process_user_input()<CR>
|
||||
nnoremap <silent> <Plug>(i) :call <SID>process_user_input()<CR>
|
||||
xnoremap <silent> <Plug>(i) :<C-u>call <SID>process_user_input()<CR>
|
||||
inoremap <silent> <Plug>(multiple-cursors-input) <C-o>:call <SID>process_user_input()<CR>
|
||||
nnoremap <silent> <Plug>(multiple-cursors-input) :call <SID>process_user_input()<CR>
|
||||
xnoremap <silent> <Plug>(multiple-cursors-input) :<C-u>call <SID>process_user_input()<CR>
|
||||
|
||||
inoremap <silent> <Plug>(a) <C-o>:call <SID>apply_user_input_next('i')<CR>
|
||||
nnoremap <silent> <Plug>(a) :call <SID>apply_user_input_next('n')<CR>
|
||||
xnoremap <silent> <Plug>(a) :<C-u>call <SID>apply_user_input_next('v')<CR>
|
||||
inoremap <silent> <Plug>(multiple-cursors-apply) <C-o>:call <SID>apply_user_input_next('i')<CR>
|
||||
nnoremap <silent> <Plug>(multiple-cursors-apply) :call <SID>apply_user_input_next('n')<CR>
|
||||
xnoremap <silent> <Plug>(multiple-cursors-apply) :<C-u>call <SID>apply_user_input_next('v')<CR>
|
||||
|
||||
inoremap <silent> <Plug>(d) <C-o>:call <SID>detect_bad_input()<CR>
|
||||
nnoremap <silent> <Plug>(d) :call <SID>detect_bad_input()<CR>
|
||||
xnoremap <silent> <Plug>(d) :<C-u>call <SID>detect_bad_input()<CR>
|
||||
inoremap <silent> <Plug>(multiple-cursors-detect) <C-o>:call <SID>detect_bad_input()<CR>
|
||||
nnoremap <silent> <Plug>(multiple-cursors-detect) :call <SID>detect_bad_input()<CR>
|
||||
xnoremap <silent> <Plug>(multiple-cursors-detect) :<C-u>call <SID>detect_bad_input()<CR>
|
||||
|
||||
inoremap <silent> <Plug>(w) <C-o>:call <SID>wait_for_user_input('')<CR>
|
||||
nnoremap <silent> <Plug>(w) :call <SID>wait_for_user_input('')<CR>
|
||||
xnoremap <silent> <Plug>(w) :<C-u>call <SID>wait_for_user_input('')<CR>
|
||||
inoremap <silent> <Plug>(multiple-cursors-wait) <C-o>:call <SID>wait_for_user_input('')<CR>
|
||||
nnoremap <silent> <Plug>(multiple-cursors-wait) :call <SID>wait_for_user_input('')<CR>
|
||||
xnoremap <silent> <Plug>(multiple-cursors-wait) :<C-u>call <SID>wait_for_user_input('')<CR>
|
||||
|
||||
" Note that although these mappings are seemingly triggerd from Visual mode,
|
||||
" they are in fact triggered from Normal mode. We quit visual mode to allow the
|
||||
" virtual highlighting to take over
|
||||
nnoremap <silent> <Plug>(p) :<C-u>call multiple_cursors#prev()<CR>
|
||||
nnoremap <silent> <Plug>(s) :<C-u>call multiple_cursors#skip()<CR>
|
||||
nnoremap <silent> <Plug>(n) :<C-u>call multiple_cursors#new('v')<CR>
|
||||
nnoremap <silent> <Plug>(multiple-cursors-prev) :<C-u>call multiple_cursors#prev()<CR>
|
||||
nnoremap <silent> <Plug>(multiple-cursors-skip) :<C-u>call multiple_cursors#skip()<CR>
|
||||
nnoremap <silent> <Plug>(multiple-cursors-new) :<C-u>call multiple_cursors#new('v', 0)<CR>
|
||||
nnoremap <silent> <Plug>(multiple-cursors-new-word) :<C-u>call multiple_cursors#new('v', 1)<CR>
|
||||
|
||||
"===============================================================================
|
||||
" Public Functions
|
||||
@ -95,7 +109,13 @@ endfunction
|
||||
" 3. In visual mode, if the visual selection covers a single line, a new cursor
|
||||
" is created at the end of the visual selection. Another cursor will be
|
||||
" attempted to be created at the next occurrence of the visual selection
|
||||
function! multiple_cursors#new(mode)
|
||||
function! multiple_cursors#new(mode, word_boundary)
|
||||
" Call before function if exists only once until it is canceled (<Esc>)
|
||||
if exists('*Multiple_cursors_before') && !s:before_function_called
|
||||
exe "call Multiple_cursors_before()"
|
||||
let s:before_function_called = 1
|
||||
endif
|
||||
let s:use_word_boundary = a:word_boundary
|
||||
if a:mode ==# 'n'
|
||||
" Reset all existing cursors, don't restore view and setting
|
||||
call s:cm.reset(0, 0)
|
||||
@ -150,6 +170,11 @@ function! multiple_cursors#new(mode)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Quit out of multicursor mode, fixes #27.
|
||||
function! multiple_cursors#quit()
|
||||
call s:exit()
|
||||
endfunction
|
||||
|
||||
" Delete the current cursor. If there's no more cursors, stop the loop
|
||||
function! multiple_cursors#prev()
|
||||
call s:cm.delete_current()
|
||||
@ -193,9 +218,12 @@ function! multiple_cursors#find(start, end, pattern)
|
||||
let first = 1
|
||||
while 1
|
||||
if first
|
||||
" Set `virtualedit` to 'onemore' for the first search to consistently
|
||||
" match patterns like '$'
|
||||
let saved_virtualedit = &virtualedit
|
||||
let &virtualedit = "onemore"
|
||||
" First search starts from the current position
|
||||
let match = search(a:pattern, 'cW')
|
||||
let first = 0
|
||||
else
|
||||
let match = search(a:pattern, 'W')
|
||||
endif
|
||||
@ -203,9 +231,26 @@ function! multiple_cursors#find(start, end, pattern)
|
||||
break
|
||||
endif
|
||||
let left = s:pos('.')
|
||||
call search(a:pattern, 'ceW')
|
||||
" Perform an intermediate backward search to correctly match patterns like
|
||||
" '^' and '$'
|
||||
let match = search(a:pattern, 'bceW')
|
||||
let right = s:pos('.')
|
||||
" Reset the cursor and perform a normal search if the intermediate search
|
||||
" wasn't successful
|
||||
if !match || s:compare_pos(right, left) != 0
|
||||
call cursor(left)
|
||||
call search(a:pattern, 'ceW')
|
||||
let right = s:pos('.')
|
||||
endif
|
||||
if first
|
||||
let &virtualedit = saved_virtualedit
|
||||
let first = 0
|
||||
endif
|
||||
if s:compare_pos(right, pos2) > 0
|
||||
" Position the cursor at the end of the previous match so it'll be on a
|
||||
" virtual cursor when multicursor mode is started. The `winrestview()`
|
||||
" call below 'undoes' unnecessary repositionings
|
||||
call search(a:pattern, 'be')
|
||||
break
|
||||
endif
|
||||
call s:cm.add(right, [left, right])
|
||||
@ -221,6 +266,14 @@ function! multiple_cursors#find(start, end, pattern)
|
||||
return
|
||||
else
|
||||
echohl Normal | echo 'Added '.s:cm.size().' cursor'.(s:cm.size()>1?'s':'') | echohl None
|
||||
|
||||
" If we've created any cursors, we need to call the before function, end
|
||||
" function will be called via normal routes
|
||||
if exists('*Multiple_cursors_before') && !s:before_function_called
|
||||
exe "call Multiple_cursors_before()"
|
||||
let s:before_function_called = 1
|
||||
endif
|
||||
|
||||
call s:wait_for_user_input('v')
|
||||
endif
|
||||
endfunction
|
||||
@ -235,9 +288,16 @@ function! s:Cursor.new(position)
|
||||
let obj = copy(self)
|
||||
let obj.position = copy(a:position)
|
||||
let obj.visual = []
|
||||
let obj.saved_visual = []
|
||||
" Stores text that was yanked after any commands in Normal or Visual mode
|
||||
let obj.paste_buffer_text = getreg('"')
|
||||
let obj.paste_buffer_type = getregtype('"')
|
||||
let obj.cursor_hi_id = s:highlight_cursor(a:position)
|
||||
let obj.visual_hi_id = 0
|
||||
let obj.line_length = col([a:position[0], '$'])
|
||||
if has('folding')
|
||||
silent! execute a:position[0] . "foldopen!"
|
||||
endif
|
||||
return obj
|
||||
endfunction
|
||||
|
||||
@ -293,12 +353,24 @@ endfunction
|
||||
|
||||
" Remove the visual selection and its highlight
|
||||
function! s:Cursor.remove_visual_selection() dict
|
||||
let self.saved_visual = deepcopy(self.visual)
|
||||
let self.visual = []
|
||||
" TODO(terryma): Move functionality into separate class
|
||||
call s:cm.remove_highlight(self.visual_hi_id)
|
||||
let self.visual_hi_id = 0
|
||||
endfunction
|
||||
|
||||
" Restore unnamed register from paste buffer
|
||||
function! s:Cursor.restore_unnamed_register() dict
|
||||
call setreg('"', self.paste_buffer_text, self.paste_buffer_type)
|
||||
endfunction
|
||||
|
||||
" Save contents of the unnamed register into paste buffer
|
||||
function! s:Cursor.save_unnamed_register() dict
|
||||
let self.paste_buffer_text = getreg('"')
|
||||
let self.paste_buffer_type = getregtype('"')
|
||||
endfunction
|
||||
|
||||
"===============================================================================
|
||||
" CursorManager class
|
||||
"===============================================================================
|
||||
@ -319,6 +391,7 @@ function! s:CursorManager.new()
|
||||
\ 'cursorline': &cursorline,
|
||||
\ 'lazyredraw': &lazyredraw,
|
||||
\ 'paste': &paste,
|
||||
\ 'clipboard': &clipboard,
|
||||
\ }
|
||||
" We save the window view when multicursor mode is entered
|
||||
let obj.saved_winview = []
|
||||
@ -328,7 +401,7 @@ function! s:CursorManager.new()
|
||||
endfunction
|
||||
|
||||
" Clear all cursors and their highlights
|
||||
function! s:CursorManager.reset(restore_view, restore_setting) dict
|
||||
function! s:CursorManager.reset(restore_view, restore_setting, ...) dict
|
||||
if a:restore_view
|
||||
" Return the view back to the beginning
|
||||
if !empty(self.saved_winview)
|
||||
@ -358,9 +431,15 @@ function! s:CursorManager.reset(restore_view, restore_setting) dict
|
||||
let self.saved_winview = []
|
||||
let self.start_from_find = 0
|
||||
let s:char = ''
|
||||
let s:saved_char = ''
|
||||
if a:restore_setting
|
||||
call self.restore_user_settings()
|
||||
endif
|
||||
" Call after function if exists and only if action is canceled (<Esc>)
|
||||
if exists('*Multiple_cursors_after') && a:0 && s:before_function_called
|
||||
exe "call Multiple_cursors_after()"
|
||||
let s:before_function_called = 0
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Returns 0 if it's not managing any cursors at the moment
|
||||
@ -434,14 +513,24 @@ function! s:CursorManager.update_current() dict
|
||||
exec "normal! gv\<Esc>"
|
||||
call cur.update_visual_selection(s:get_visual_region(s:pos('.')))
|
||||
elseif s:from_mode ==# 'v' || s:from_mode ==# 'V'
|
||||
" Save contents of unnamed register after each operation in Visual mode.
|
||||
" This should be executed after user input is processed, when unnamed
|
||||
" register already contains the text.
|
||||
call cur.save_unnamed_register()
|
||||
|
||||
call cur.remove_visual_selection()
|
||||
elseif s:from_mode ==# 'i' && s:to_mode ==# 'n' && self.current_index != self.size() - 1
|
||||
normal! h
|
||||
elseif s:from_mode ==# 'n'
|
||||
" Save contents of unnamed register after each operation in Normal mode.
|
||||
call cur.save_unnamed_register()
|
||||
endif
|
||||
let vdelta = line('$') - s:saved_linecount
|
||||
" If the total number of lines changed in the buffer, we need to potentially
|
||||
" adjust other cursor locations
|
||||
if vdelta != 0
|
||||
if self.current_index != self.size() - 1
|
||||
let cur_line_length = len(getline(cur.line()))
|
||||
let cur_column_offset = (cur.column() - col('.')) * -1
|
||||
let new_line_length = len(getline('.'))
|
||||
for i in range(self.current_index+1, self.size()-1)
|
||||
let hdelta = 0
|
||||
@ -453,7 +542,7 @@ function! s:CursorManager.update_current() dict
|
||||
if cur.line() == c.line()
|
||||
if vdelta > 0
|
||||
" Added a line
|
||||
let hdelta = cur_line_length * -1
|
||||
let hdelta = cur_column_offset
|
||||
else
|
||||
" Removed a line
|
||||
let hdelta = new_line_length
|
||||
@ -518,19 +607,28 @@ endfunction
|
||||
" cursors on screen
|
||||
" paste mode needs to be switched off since it turns off a bunch of features
|
||||
" that's critical for the plugin to function
|
||||
" clipboard should not have unnamed and unnamedplus otherwise plugin cannot
|
||||
" reliably use unnamed register ('"')
|
||||
function! s:CursorManager.initialize() dict
|
||||
let self.saved_settings['virtualedit'] = &virtualedit
|
||||
let self.saved_settings['cursorline'] = &cursorline
|
||||
let self.saved_settings['lazyredraw'] = &lazyredraw
|
||||
let self.saved_settings['paste'] = &paste
|
||||
let self.saved_settings['clipboard'] = &clipboard
|
||||
let &virtualedit = "onemore"
|
||||
let &cursorline = 0
|
||||
let &lazyredraw = 1
|
||||
let &paste = 0
|
||||
set clipboard-=unnamed clipboard-=unnamedplus
|
||||
" We could have already saved the view from multiple_cursors#find
|
||||
if !self.start_from_find
|
||||
let self.saved_winview = winsaveview()
|
||||
endif
|
||||
|
||||
" Save contents and type of unnamed register upon entering multicursor mode
|
||||
" to restore it later when leaving mode
|
||||
let s:paste_buffer_temporary_text = getreg('"')
|
||||
let s:paste_buffer_temporary_type = getregtype('"')
|
||||
endfunction
|
||||
|
||||
" Restore user settings.
|
||||
@ -540,7 +638,22 @@ function! s:CursorManager.restore_user_settings() dict
|
||||
let &cursorline = self.saved_settings['cursorline']
|
||||
let &lazyredraw = self.saved_settings['lazyredraw']
|
||||
let &paste = self.saved_settings['paste']
|
||||
let &clipboard = self.saved_settings['clipboard']
|
||||
endif
|
||||
|
||||
" Restore original contents and type of unnamed register. This method is
|
||||
" called from reset, which calls us only when restore_setting argument is
|
||||
" true, which happens only when we leave multicursor mode. This should be
|
||||
" symmetrical to saving of unnamed register upon the start of multicursor
|
||||
" mode.
|
||||
call setreg('"', s:paste_buffer_temporary_text, s:paste_buffer_temporary_type)
|
||||
endfunction
|
||||
|
||||
" Reposition all cursors to the start or end of their region
|
||||
function! s:CursorManager.reposition_all_within_region(start) dict
|
||||
for c in self.cursors
|
||||
call c.update_position(c.saved_visual[a:start ? 0 : 1])
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Reselect the current cursor's region in visual mode
|
||||
@ -587,6 +700,9 @@ endfunction
|
||||
|
||||
" This is the last user input that we're going to replicate, in its string form
|
||||
let s:char = ''
|
||||
" This is either `I` or `A`, as input in Visual mode, that we're going to use
|
||||
" to make the appropriate transition into Insert mode
|
||||
let s:saved_char = ''
|
||||
" This is the mode the user is in before s:char
|
||||
let s:from_mode = ''
|
||||
" This is the mode the user is in after s:char
|
||||
@ -628,6 +744,12 @@ endfunction
|
||||
" visual selection ended
|
||||
function! s:exit_visual_mode()
|
||||
exec "normal! \<Esc>gv\<Esc>"
|
||||
|
||||
" Call before function if exists only once until it is canceled (<Esc>)
|
||||
if exists('*Multiple_cursors_before') && !s:before_function_called
|
||||
exe "call Multiple_cursors_before()"
|
||||
let s:before_function_called = 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Visually select input region, where region is an array containing the start
|
||||
@ -643,7 +765,7 @@ endfunction
|
||||
function! s:select_in_visual_mode(region)
|
||||
if a:region[0] == a:region[1]
|
||||
normal! v
|
||||
else
|
||||
else
|
||||
call cursor(a:region[1])
|
||||
normal! m`
|
||||
call cursor(a:region[0])
|
||||
@ -660,7 +782,7 @@ endfunction
|
||||
function! s:update_visual_markers(region)
|
||||
if a:region[0] == a:region[1]
|
||||
normal! v
|
||||
else
|
||||
else
|
||||
call cursor(a:region[1])
|
||||
normal! m`
|
||||
call cursor(a:region[0])
|
||||
@ -674,7 +796,11 @@ endfunction
|
||||
" Mode change: Normal -> Normal
|
||||
" Cursor change: Set to the end of the match
|
||||
function! s:find_next(text)
|
||||
let pattern = '\V\C'.substitute(escape(a:text, '\'), '\n', '\\n', 'g')
|
||||
let pattern = substitute(escape(a:text, '\'), '\n', '\\n', 'g')
|
||||
if s:use_word_boundary == 1
|
||||
let pattern = '\<'.pattern.'\>'
|
||||
endif
|
||||
let pattern = '\V\C'.pattern
|
||||
call search(pattern)
|
||||
let start = s:pos('.')
|
||||
call search(pattern, 'ce')
|
||||
@ -714,7 +840,7 @@ function! s:highlight_region(region)
|
||||
let pattern = s1.'\|'.s2
|
||||
" More than two lines
|
||||
if (s[1][0] - s[0][0] > 1)
|
||||
let pattern = pattern.'\|\%>'.s[0][0].'l\%<'.s[1][0].'l.*\ze.\_$'
|
||||
let pattern = pattern.'\|\%>'.s[0][0].'l\%<'.s[1][0].'l.*\ze.\_$'
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@ -725,28 +851,31 @@ endfunction
|
||||
function! s:revert_mode(from, to)
|
||||
if a:to ==# 'v'
|
||||
call s:cm.reapply_visual_selection()
|
||||
endif
|
||||
if a:to ==# 'V'
|
||||
elseif a:to ==# 'V'
|
||||
call s:cm.reapply_visual_selection()
|
||||
normal! V
|
||||
endif
|
||||
if a:to ==# 'n' && a:from ==# 'i'
|
||||
elseif a:to ==# 'n' && a:from ==# 'i'
|
||||
stopinsert
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Consume all the additional character the user typed between the last
|
||||
" getchar() and here, to avoid potential race condition.
|
||||
" TODO(terryma): This solves the problem of cursors getting out of sync, but
|
||||
" we're potentially losing user input. We COULD replay these characters as
|
||||
" well...
|
||||
let s:saved_keys = ""
|
||||
function! s:feedkeys(keys)
|
||||
while 1
|
||||
let c = getchar(0)
|
||||
let char_type = type(c)
|
||||
" Checking type is important, when strings are compared with integers,
|
||||
" strings are always converted to ints, and all strings are equal to 0
|
||||
if type(c) == 0 && c == 0
|
||||
break
|
||||
if char_type == 0
|
||||
if c == 0
|
||||
break
|
||||
else
|
||||
let s:saved_keys .= nr2char(c)
|
||||
endif
|
||||
elseif char_type == 1 " char with more than 8 bits (as string)
|
||||
let s:saved_keys .= c
|
||||
endif
|
||||
endwhile
|
||||
call feedkeys(a:keys)
|
||||
@ -757,7 +886,8 @@ function! s:process_user_input()
|
||||
" Grr this is frustrating. In Insert mode, between the feedkey call and here,
|
||||
" the current position could actually CHANGE for some odd reason. Forcing a
|
||||
" position reset here
|
||||
call cursor(s:cm.get_current().position)
|
||||
let cursor_position = s:cm.get_current()
|
||||
call cursor(cursor_position.position)
|
||||
|
||||
" Before applying the user input, we need to revert back to the mode the user
|
||||
" was in when the input was entered
|
||||
@ -765,13 +895,20 @@ function! s:process_user_input()
|
||||
|
||||
" Update the line length BEFORE applying any actions. TODO(terryma): Is there
|
||||
" a better place to do this?
|
||||
call s:cm.get_current().update_line_length()
|
||||
" let cursor_position = s:cm.get_current()
|
||||
call cursor_position.update_line_length()
|
||||
let s:saved_linecount = line('$')
|
||||
|
||||
" Restore unnamed register only in Normal mode. This should happen before user
|
||||
" input is processed.
|
||||
if s:from_mode ==# 'n' || s:from_mode ==# 'v' || s:from_mode ==# 'V'
|
||||
call cursor_position.restore_unnamed_register()
|
||||
endif
|
||||
|
||||
" Apply the user input. Note that the above could potentially change mode, we
|
||||
" use the mapping below to help us determine what the new mode is
|
||||
" Note that it's possible that \<Plug>(a) never gets called, we have a
|
||||
" detection mechanism using \<Plug>(d). See its documentation for more details
|
||||
" Note that it's possible that \<Plug>(multiple-cursors-apply) never gets called, we have a
|
||||
" detection mechanism using \<Plug>(multiple-cursors-detect). See its documentation for more details
|
||||
|
||||
" Assume that input is not valid
|
||||
let s:valid_input = 0
|
||||
@ -781,14 +918,14 @@ function! s:process_user_input()
|
||||
" FIXME(terryma): Undo always places the cursor at the beginning of the line.
|
||||
" Figure out why.
|
||||
if s:from_mode ==# 'i' || s:to_mode ==# 'i'
|
||||
silent! undojoin | call s:feedkeys(s:char."\<Plug>(a)")
|
||||
silent! undojoin | call s:feedkeys(s:char."\<Plug>(multiple-cursors-apply)")
|
||||
else
|
||||
call s:feedkeys(s:char."\<Plug>(a)")
|
||||
call s:feedkeys(s:char."\<Plug>(multiple-cursors-apply)")
|
||||
endif
|
||||
|
||||
|
||||
" Even when s:char produces invalid input, this method is always called. The
|
||||
" 't' here is important
|
||||
call feedkeys("\<Plug>(d)", 't')
|
||||
call feedkeys("\<Plug>(multiple-cursors-detect)", 't')
|
||||
endfunction
|
||||
|
||||
" This method is always called during fanout, even when a bad user input causes
|
||||
@ -796,12 +933,34 @@ endfunction
|
||||
" to be called to continue the fanout process
|
||||
function! s:detect_bad_input()
|
||||
if !s:valid_input
|
||||
" To invoke the appropriate `<Plug>(multiple-cursors-apply)` mapping, we
|
||||
" need to revert back to the mode the user was in when the input was entered
|
||||
call s:revert_mode(s:to_mode, s:from_mode)
|
||||
" We ignore the bad input and force invoke s:apply_user_input_next
|
||||
call feedkeys("\<Plug>(a)")
|
||||
call feedkeys("\<Plug>(multiple-cursors-apply)")
|
||||
let s:bad_input += 1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Complete transition into Insert mode when `I` or `A` is input in Visual mode
|
||||
function! s:handle_visual_IA_to_insert()
|
||||
if !empty(s:saved_char) && s:char =~# 'v\|V' && s:to_mode ==# 'n'
|
||||
if s:saved_char ==# 'I'
|
||||
call s:cm.reposition_all_within_region(1)
|
||||
endif
|
||||
call feedkeys(tolower(s:saved_char))
|
||||
let s:saved_char = ''
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Begin transition into Insert mode when `I` or `A` is input in Visual mode
|
||||
function! s:handle_visual_IA_to_normal()
|
||||
if s:char =~# 'I\|A' && s:from_mode =~# 'v\|V'
|
||||
let s:saved_char = s:char
|
||||
let s:char = s:from_mode " spoof a 'v' or 'V' input to transiton from Visual into Normal mode
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Apply the user input at the next cursor location
|
||||
function! s:apply_user_input_next(mode)
|
||||
let s:valid_input = 1
|
||||
@ -828,10 +987,11 @@ function! s:apply_user_input_next(mode)
|
||||
" This is necessary to set the "'<" and "'>" markers properly
|
||||
call s:update_visual_markers(s:cm.get_current().visual)
|
||||
endif
|
||||
call feedkeys("\<Plug>(w)")
|
||||
call feedkeys("\<Plug>(multiple-cursors-wait)")
|
||||
call s:handle_visual_IA_to_insert()
|
||||
else
|
||||
" Continue to next
|
||||
call feedkeys("\<Plug>(i)")
|
||||
call feedkeys("\<Plug>(multiple-cursors-input)")
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -873,7 +1033,7 @@ endfunction
|
||||
" Quits multicursor mode and clears all cursors. Return true if exited
|
||||
" successfully.
|
||||
function! s:exit()
|
||||
if s:char !=# g:multi_cursor_quit_key
|
||||
if s:last_char() !=# g:multi_cursor_quit_key
|
||||
return 0
|
||||
endif
|
||||
let exit = 0
|
||||
@ -887,7 +1047,7 @@ function! s:exit()
|
||||
let exit = 1
|
||||
endif
|
||||
if exit
|
||||
call s:cm.reset(1, 1)
|
||||
call s:cm.reset(1, 1, 1)
|
||||
return 1
|
||||
endif
|
||||
return 0
|
||||
@ -902,11 +1062,15 @@ function! s:handle_special_key(key, mode)
|
||||
" increasing the call stack, since feedkeys execute after the current call
|
||||
" finishes
|
||||
if a:key == g:multi_cursor_next_key
|
||||
call s:feedkeys("\<Plug>(n)")
|
||||
if s:use_word_boundary == 1
|
||||
call s:feedkeys("\<Plug>(multiple-cursors-new-word)")
|
||||
else
|
||||
call s:feedkeys("\<Plug>(multiple-cursors-new)")
|
||||
endif
|
||||
elseif a:key == g:multi_cursor_prev_key
|
||||
call s:feedkeys("\<Plug>(p)")
|
||||
call s:feedkeys("\<Plug>(multiple-cursors-prev)")
|
||||
elseif a:key == g:multi_cursor_skip_key
|
||||
call s:feedkeys("\<Plug>(s)")
|
||||
call s:feedkeys("\<Plug>(multiple-cursors-skip)")
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -941,12 +1105,22 @@ function! s:revert_highlight_fix()
|
||||
let s:saved_line = 0
|
||||
endfunction
|
||||
|
||||
let s:retry_keys = ""
|
||||
function! s:display_error()
|
||||
if s:bad_input > 0
|
||||
echohl ErrorMsg |
|
||||
\ echo "Key '".s:char."' cannot be replayed at ".
|
||||
\ s:bad_input." cursor location".(s:bad_input == 1 ? '' : 's') |
|
||||
\ echohl Normal
|
||||
if s:bad_input == s:cm.size()
|
||||
\ && ((s:from_mode ==# 'n' && has_key(g:multi_cursor_normal_maps, s:char[0]))
|
||||
\ || (s:from_mode =~# 'v\|V' && has_key(g:multi_cursor_visual_maps, s:char[0])))
|
||||
" we couldn't replay it anywhere but we're told it's the beginning of a
|
||||
" multi-character map like the `d` in `dw`
|
||||
let s:retry_keys = s:char
|
||||
else
|
||||
let s:retry_keys = ""
|
||||
if s:bad_input > 0
|
||||
echohl ErrorMsg |
|
||||
\ echo "Key '".s:char."' cannot be replayed at ".
|
||||
\ s:bad_input." cursor location".(s:bad_input == 1 ? '' : 's') |
|
||||
\ echohl Normal
|
||||
endif
|
||||
endif
|
||||
let s:bad_input = 0
|
||||
endfunction
|
||||
@ -982,15 +1156,19 @@ function! s:end_latency_measure()
|
||||
let s:skip_latency_measure = 0
|
||||
endfunction
|
||||
|
||||
function! s:last_char()
|
||||
return s:char[len(s:char)-1]
|
||||
endfunction
|
||||
|
||||
function! s:wait_for_user_input(mode)
|
||||
call s:display_error()
|
||||
|
||||
let s:from_mode = a:mode
|
||||
if empty(a:mode)
|
||||
let s:from_mode = s:to_mode
|
||||
endif
|
||||
let s:to_mode = ''
|
||||
|
||||
call s:display_error()
|
||||
|
||||
" Right before redraw, apply the highlighting bug fix
|
||||
call s:apply_highlight_fix()
|
||||
|
||||
@ -1001,7 +1179,39 @@ function! s:wait_for_user_input(mode)
|
||||
|
||||
call s:end_latency_measure()
|
||||
|
||||
let s:char = s:get_char()
|
||||
let s:char = s:retry_keys . s:saved_keys
|
||||
if len(s:saved_keys) == 0
|
||||
let s:char .= s:get_char()
|
||||
call s:handle_visual_IA_to_normal()
|
||||
else
|
||||
let s:saved_keys = ""
|
||||
endif
|
||||
|
||||
if s:from_mode ==# 'i' && has_key(g:multi_cursor_insert_maps, s:last_char())
|
||||
let c = getchar(0)
|
||||
let char_type = type(c)
|
||||
let poll_count = 0
|
||||
while char_type == 0 && c == 0 && poll_count < &timeoutlen
|
||||
sleep 1m
|
||||
let c = getchar(0)
|
||||
let char_type = type(c)
|
||||
let poll_count += 1
|
||||
endwhile
|
||||
|
||||
if char_type == 0 && c != 0
|
||||
let s:char .= nr2char(c)
|
||||
elseif char_type == 1 " char with more than 8 bits (as string)
|
||||
let s:char .= c
|
||||
endif
|
||||
elseif s:from_mode !=# 'i' && s:char[0] ==# ":"
|
||||
call feedkeys(s:char)
|
||||
call s:cm.reset(1, 1)
|
||||
return
|
||||
elseif s:from_mode ==# 'n'
|
||||
while match(s:last_char(), "\\d") == 0
|
||||
let s:char .= s:get_char()
|
||||
endwhile
|
||||
endif
|
||||
|
||||
call s:start_latency_measure()
|
||||
|
||||
@ -1013,11 +1223,11 @@ function! s:wait_for_user_input(mode)
|
||||
endif
|
||||
|
||||
" If the key is a special key and we're in the right mode, handle it
|
||||
if index(get(s:special_keys, s:from_mode, []), s:char) != -1
|
||||
call s:handle_special_key(s:char, s:from_mode)
|
||||
if index(get(s:special_keys, s:from_mode, []), s:last_char()) != -1
|
||||
call s:handle_special_key(s:last_char(), s:from_mode)
|
||||
call s:skip_latency_measure()
|
||||
else
|
||||
call s:cm.start_loop()
|
||||
call s:feedkeys("\<Plug>(i)")
|
||||
call s:feedkeys("\<Plug>(multiple-cursors-input)")
|
||||
endif
|
||||
endfunction
|
||||
|
@ -1,11 +1,11 @@
|
||||
*vim-multiple-cursors.txt* True Sublime Text multiple selection in Vim
|
||||
|
||||
____ _ __
|
||||
____ _ __
|
||||
____ ___ __ __/ / /_(_)___ / /__ _______ ________________ __________
|
||||
/ __ `__ \/ / / / / __/ / __ \/ / _ \ / ___/ / / / ___/ ___/ __ \/ ___/ ___/
|
||||
/ / / / / / /_/ / / /_/ / /_/ / / __/ / /__/ /_/ / / (__ ) /_/ / / (__ )
|
||||
/_/ /_/ /_/\__,_/_/\__/_/ .___/_/\___/ \___/\__,_/_/ /____/\____/_/ /____/
|
||||
/_/
|
||||
/ / / / / / /_/ / / /_/ / /_/ / / __/ / /__/ /_/ / / (__ ) /_/ / / (__ )
|
||||
/_/ /_/ /_/\__,_/_/\__/_/ .___/_/\___/ \___/\__,_/_/ /____/\____/_/ /____/
|
||||
/_/
|
||||
|
||||
|
||||
Reference Manual~
|
||||
@ -71,7 +71,7 @@ CTRL-N in Normal mode and it will remove all prior cursors before starting a
|
||||
new one.
|
||||
|
||||
==============================================================================
|
||||
3. Mappings *multiple-cursors-mappings*
|
||||
3. Mappings *multiple-cursors-mappings*
|
||||
|
||||
*g:multi_cursor_use_default_mapping* (Default: 1)
|
||||
|
||||
@ -108,7 +108,22 @@ mode than for selecting the next location, do like the following: >
|
||||
let g:multi_cursor_start_key='<F6>'
|
||||
<
|
||||
|
||||
IMPORTANT: Please note that currently only single keystroes and special
|
||||
*g:multi_cursor_start_word_key*
|
||||
When multicursor mode is started, it selects current word without
|
||||
boundaries, i.e. it behaves like `g*`. If you want to use word boundaries in
|
||||
Normal mode (as `*` does) but still have old behaviour up your sleeve, you can
|
||||
do the following: >
|
||||
|
||||
let g:multi_cursor_start_key='g<C-n>'
|
||||
let g:multi_cursor_start_word_key='<C-n>'
|
||||
<
|
||||
|
||||
In this configuration <C-n> will start multicursor mode using word boundaries
|
||||
(but only in Normal mode, as it does not make much sense to use it in Visual
|
||||
mode). Old behaviour without word boundaries is still available using
|
||||
g<C-n>.
|
||||
|
||||
IMPORTANT: Please note that currently only single keystrokes and special
|
||||
keys can be mapped. This contraint is also the reason why multikey commands
|
||||
such as `ciw` do not work and cause unexpected behavior in Normal mode. This
|
||||
means that a mapping like `<Leader>n` will NOT work correctly. For a list of
|
||||
@ -118,17 +133,17 @@ NOTE: Please make sure to always map something to |g:multi_cursor_quit_key|,
|
||||
otherwise you'll have a tough time quitting from multicursor mode.
|
||||
|
||||
NOTE: Prior to version 1.3, the recommended way to map the keys is using the
|
||||
expressoin quote syntax in Vim, using something like `"\<C-n>"` or `"\<Esc>"`
|
||||
expression quote syntax in Vim, using something like `"\<C-n>"` or `"\<Esc>"`
|
||||
(see h: expr-quote). After 1.3, the recommended way is to use a raw string
|
||||
like above. If your key mappings don't appear to work, give the new syntax a
|
||||
try.
|
||||
|
||||
==============================================================================
|
||||
4. Global Options *multiple-cursors-global-options*
|
||||
4. Global Options *multiple-cursors-global-options*
|
||||
|
||||
Currently there're two additional global settings one can tweak:
|
||||
Currently there are four additional global settings one can tweak:
|
||||
|
||||
*g:multi_cursor_exit_from_visual_mode* (Defaut: 1)
|
||||
*g:multi_cursor_exit_from_visual_mode* (Default: 1)
|
||||
|
||||
If set to 0, then pressing |g:multi_cursor_quit_key| in Visual mode will not
|
||||
quit and delete all existing cursors. This is useful if you want to press
|
||||
@ -142,6 +157,45 @@ quit and delete all existing cursors. This is useful if you want to press
|
||||
Escape and go back to Normal mode, and still be able to operate on all the
|
||||
cursors.
|
||||
|
||||
*g:multi_cursor_insert_maps* (Default: `{}`)
|
||||
|
||||
Any key in this map (values are ignored) will cause multi-cursor _Insert_ mode
|
||||
to pause for `timeoutlen` waiting for map completion just like normal vim.
|
||||
Otherwise keys mapped in insert mode are ignored when multiple cursors are
|
||||
active. For example, setting it to `{'\':1}` will make insert-mode mappings
|
||||
beginning with the default leader key work in multi-cursor mode. You have to
|
||||
manually set this because vim doesn't provide a way to see which keys _start_
|
||||
mappings.
|
||||
|
||||
*g:multi_cursor_normal_maps* (Default: see below)
|
||||
|
||||
Default value: `{'!':1, '@':1, '=':1, 'q':1, 'r':1, 't':1, 'T':1, 'y':1, '[':1, ']':1, '\':1, 'd':1, 'f':1, 'F':1, 'g':1, '"':1, 'z':1, 'c':1, 'm':1, '<':1, '>':1}`
|
||||
|
||||
Any key in this map (values are ignored) will cause multi-cursor _Normal_ mode
|
||||
to pause for map completion just like normal vim. Otherwise keys mapped in
|
||||
normal mode will "fail to replay" when multiple cursors are active. For example,
|
||||
changing it from `{}` to `{'d':1}` makes normal-mode mappings beginning with `d`
|
||||
(such as `dw` to delete a word) work in multi-cursor mode.
|
||||
|
||||
*g:multi_cursor_visual_maps* (Default: )
|
||||
|
||||
Default value: `{'i':1, 'a':1, 'f':1, 'F':1, 't':1, 'T':1}`
|
||||
|
||||
Any key in this map (values are ignored) will cause multi-cursor _Visual_ mode
|
||||
to pause for map completion just like normal vim. Otherwise keys mapped in
|
||||
visual mode will "fail to replay" when multiple cursors are active. For example,
|
||||
changing it from `{}` to `{'i':1}` makes visual-mode mappings beginning with `i`
|
||||
(such as `it` to select an "inner tag block") work in multi-cursor mode.
|
||||
|
||||
The default list contents should work for anybody, unless they have remapped a
|
||||
key from an operator-pending command to a non-operator-pending command or
|
||||
vice versa.
|
||||
|
||||
These keys must be manually listed because vim doesn't provide a way to
|
||||
automatically see which keys _start_ mappings, and trying to run motion commands
|
||||
such as `j` as if they were operator-pending commands can break things.
|
||||
|
||||
|
||||
The plugin uses the highlight group `multiple_cursors_cursor` and
|
||||
`multiple_cursors_visual` to highlight the virtual cursors and their visual
|
||||
selections respectively. You can customize them by putting something similar
|
||||
@ -150,10 +204,11 @@ like the following in your vimrc: >
|
||||
" Default highlighting (see help :highlight and help :highlight-link)
|
||||
highlight multiple_cursors_cursor term=reverse cterm=reverse gui=reverse
|
||||
highlight link multiple_cursors_visual Visual
|
||||
|
||||
<
|
||||
|
||||
==============================================================================
|
||||
5. Issues *multiple-cursors-issues*
|
||||
5. Issues *multiple-cursors-issues*
|
||||
|
||||
- Multi key commands like ciw do not work at the moment
|
||||
- All user input typed before Vim is able to fan out the last operation to all
|
||||
@ -163,7 +218,7 @@ like the following in your vimrc: >
|
||||
- Select mode is not implemented
|
||||
|
||||
==============================================================================
|
||||
6. Contributing *multiple-cursors-contributing*
|
||||
6. Contributing *multiple-cursors-contributing*
|
||||
|
||||
The project is hosted on Github. Patches, feature requests and suggestions are
|
||||
always welcome!
|
||||
@ -172,19 +227,19 @@ Find the latest version of the plugin here:
|
||||
http://github.com/terryma/vim-multiple-cursors
|
||||
|
||||
==============================================================================
|
||||
7. License *multiple-cursors-license*
|
||||
7. License *multiple-cursors-license*
|
||||
|
||||
The project is licensed under the MIT license [7]. Copyrigth 2013 Terry Ma
|
||||
|
||||
==============================================================================
|
||||
8. Credit *multiple-cursors-credit*
|
||||
8. Credit *multiple-cursors-credit*
|
||||
|
||||
The plugin is obviously inspired by Sublime Text's awesome multiple selection
|
||||
[6] feature. Some inspiration was also taken from Emac's multiple cursors [8]
|
||||
implementation.
|
||||
implementation.
|
||||
|
||||
==============================================================================
|
||||
9. References *multiple-cursors-references*
|
||||
9. References *multiple-cursors-references*
|
||||
|
||||
[1] https://github.com/paradigm/vim-multicursor
|
||||
[2] https://github.com/felixr/vim-multiedit
|
||||
|
@ -1,12 +1,16 @@
|
||||
MultipleCursorsFind multiple_cursors.txt /*MultipleCursorsFind*
|
||||
g:multi_cursor_exit_from_insert_mode multiple_cursors.txt /*g:multi_cursor_exit_from_insert_mode*
|
||||
g:multi_cursor_exit_from_visual_mode multiple_cursors.txt /*g:multi_cursor_exit_from_visual_mode*
|
||||
g:multi_cursor_insert_maps multiple_cursors.txt /*g:multi_cursor_insert_maps*
|
||||
g:multi_cursor_next_key multiple_cursors.txt /*g:multi_cursor_next_key*
|
||||
g:multi_cursor_normal_maps multiple_cursors.txt /*g:multi_cursor_normal_maps*
|
||||
g:multi_cursor_prev_key multiple_cursors.txt /*g:multi_cursor_prev_key*
|
||||
g:multi_cursor_quit_key multiple_cursors.txt /*g:multi_cursor_quit_key*
|
||||
g:multi_cursor_skip_key multiple_cursors.txt /*g:multi_cursor_skip_key*
|
||||
g:multi_cursor_start_key multiple_cursors.txt /*g:multi_cursor_start_key*
|
||||
g:multi_cursor_start_word_key multiple_cursors.txt /*g:multi_cursor_start_word_key*
|
||||
g:multi_cursor_use_default_mapping multiple_cursors.txt /*g:multi_cursor_use_default_mapping*
|
||||
g:multi_cursor_visual_maps multiple_cursors.txt /*g:multi_cursor_visual_maps*
|
||||
multiple-cursors-contents multiple_cursors.txt /*multiple-cursors-contents*
|
||||
multiple-cursors-contributing multiple_cursors.txt /*multiple-cursors-contributing*
|
||||
multiple-cursors-credit multiple_cursors.txt /*multiple-cursors-credit*
|
||||
|
@ -1,7 +1,7 @@
|
||||
"===============================================================================
|
||||
" File: multiple_cursors.vim
|
||||
" Author: Terry Ma
|
||||
" Description: Emulate Sublime Text's multi selection feature
|
||||
" Description: Emulate Sublime Text's multi selection feature
|
||||
" Potential Features:
|
||||
" - Create a blinking cursor effect? Good place to do it would be instead of
|
||||
" waiting for user input, cycle through the highlight
|
||||
@ -40,26 +40,49 @@ let s:settings_if_default = {
|
||||
\ 'skip_key': '<C-x>',
|
||||
\ }
|
||||
|
||||
let s:default_insert_maps = {}
|
||||
let s:default_normal_maps = {'!':1, '@':1, '=':1, 'q':1, 'r':1, 't':1, 'T':1, 'y':1, '[':1, ']':1, '\':1, 'd':1, 'f':1, 'F':1, 'g':1, '"':1, 'z':1, 'c':1, 'm':1, '<':1, '>':1}
|
||||
let s:default_visual_maps = {'i':1, 'a':1, 'f':1, 'F':1, 't':1, 'T':1}
|
||||
|
||||
let g:multi_cursor_insert_maps =
|
||||
\ get(g:, 'multi_cursor_insert_maps', s:default_insert_maps)
|
||||
let g:multi_cursor_normal_maps =
|
||||
\ get(g:, 'multi_cursor_normal_maps', s:default_normal_maps)
|
||||
let g:multi_cursor_visual_maps =
|
||||
\ get(g:, 'multi_cursor_visual_maps', s:default_visual_maps)
|
||||
|
||||
call s:init_settings(s:settings)
|
||||
|
||||
if g:multi_cursor_use_default_mapping
|
||||
call s:init_settings(s:settings_if_default)
|
||||
endif
|
||||
|
||||
if !exists('g:multi_cursor_start_key') && exists('g:multi_cursor_next_key')
|
||||
let g:multi_cursor_start_key = g:multi_cursor_next_key
|
||||
if !exists('g:multi_cursor_start_word_key')
|
||||
if exists('g:multi_cursor_start_key')
|
||||
let g:multi_cursor_start_word_key = g:multi_cursor_start_key
|
||||
elseif exists('g:multi_cursor_next_key')
|
||||
let g:multi_cursor_start_word_key = g:multi_cursor_next_key
|
||||
endif
|
||||
endif
|
||||
|
||||
" External mappings
|
||||
if exists('g:multi_cursor_start_key')
|
||||
exec 'nnoremap <silent> '.g:multi_cursor_start_key.
|
||||
\' :call multiple_cursors#new("n")<CR>'
|
||||
\' :call multiple_cursors#new("n", 0)<CR>'
|
||||
exec 'xnoremap <silent> '.g:multi_cursor_start_key.
|
||||
\' :<C-u>call multiple_cursors#new("v")<CR>'
|
||||
\' :<C-u>call multiple_cursors#new("v", 0)<CR>'
|
||||
endif
|
||||
|
||||
if exists('g:multi_cursor_start_word_key')
|
||||
exec 'nnoremap <silent> '.g:multi_cursor_start_word_key.
|
||||
\' :call multiple_cursors#new("n", 1)<CR>'
|
||||
" In Visual mode word boundary is not used
|
||||
exec 'xnoremap <silent> '.g:multi_cursor_start_word_key.
|
||||
\' :<C-u>call multiple_cursors#new("v", 0)<CR>'
|
||||
endif
|
||||
|
||||
" Commands
|
||||
command! -nargs=1 -range=% MultipleCursorsFind
|
||||
command! -nargs=1 -range=% MultipleCursorsFind
|
||||
\ call multiple_cursors#find(<line1>, <line2>, <q-args>)
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
|
@ -58,6 +58,7 @@ end
|
||||
|
||||
describe "Multiple Cursors" do
|
||||
let(:filename) { 'test.txt' }
|
||||
let(:options) { [] }
|
||||
|
||||
specify "#benchmark" do
|
||||
before <<-EOF
|
||||
|
@ -12,11 +12,12 @@ def get_file_content()
|
||||
end
|
||||
|
||||
def before(string)
|
||||
options.each { |x| vim.command(x) }
|
||||
set_file_content(string)
|
||||
end
|
||||
|
||||
def after(string)
|
||||
get_file_content().should eq normalize_string_indent(string)
|
||||
expect(get_file_content()).to eq normalize_string_indent(string)
|
||||
end
|
||||
|
||||
def type(string)
|
||||
@ -29,8 +30,251 @@ def type(string)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Multiple Cursors op pending & exit from insert|visual mode" do
|
||||
let(:filename) { 'test.txt' }
|
||||
let(:options) { ['let g:multi_cursor_exit_from_insert_mode = 0',
|
||||
'let g:multi_cursor_exit_from_visual_mode = 0'] }
|
||||
# the default value of g:multi_cursor_normal_maps already works
|
||||
# for testing operator-pending
|
||||
|
||||
specify "#paste from unnamed register to 3 cursors" do
|
||||
before <<-EOF
|
||||
yankme
|
||||
a b c
|
||||
a b c
|
||||
a b c
|
||||
EOF
|
||||
|
||||
type 'yiwj<C-n><C-n><C-n>vwwp<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
yankme
|
||||
a b cyankme
|
||||
a b cyankme
|
||||
a b cyankme
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer normal caw then p" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>vwcaw<Esc>bP<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
jan hello world
|
||||
feb hello world
|
||||
mar hello world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer normal C then ABC then p" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>vwCABC <Esc>p<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello ABC jan world
|
||||
hello ABC feb world
|
||||
hello ABC mar world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer normal daw then P" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>vwdawbP<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
jan hello world
|
||||
feb hello world
|
||||
mar hello world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer normal D then P" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>vwwhDbhP<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello world jan
|
||||
hello world feb
|
||||
hello world mar
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer normal s then p" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>vws1<Esc>p<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello 1jan world
|
||||
hello 1feb world
|
||||
hello 1mar world
|
||||
EOF
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "Multiple Cursors when normal_maps is empty" do
|
||||
let(:filename) { 'test.txt' }
|
||||
let(:options) { ['let g:multi_cursor_normal_maps = {}'] }
|
||||
|
||||
# Operator-pending commands are handled correctly thanks to their inclusion
|
||||
# in `g:multi_cursor_normal_maps`.
|
||||
#
|
||||
# When an operator-pending command like 'd' is missing from that setting's
|
||||
# value, then it should result in a no-op, but we should still remain in
|
||||
# multicursor mode.
|
||||
specify "#normal mode 'd'" do
|
||||
before <<-EOF
|
||||
hello
|
||||
hello
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n>vdx<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hell
|
||||
hell
|
||||
EOF
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "Multiple Cursors when visual_maps is empty" do
|
||||
let(:filename) { 'test.txt' }
|
||||
let(:options) { ['let g:multi_cursor_visual_maps = {}'] }
|
||||
|
||||
# Operator-pending commands are handled correctly thanks to their inclusion
|
||||
# in `g:multi_cursor_visual_maps`.
|
||||
#
|
||||
# When an operator-pending command like 'f' is missing from that setting's
|
||||
# value, then it should result in a no-op, but we should still remain in
|
||||
# multicursor mode.
|
||||
specify "#visual mode 'i'" do
|
||||
before <<-EOF
|
||||
hello world x
|
||||
hello world x
|
||||
EOF
|
||||
|
||||
type 'fw<C-n><C-n>fx<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello x
|
||||
hello x
|
||||
EOF
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "Multiple Cursors" do
|
||||
let(:filename) { 'test.txt' }
|
||||
let(:options) { ['set autoindent'] }
|
||||
|
||||
specify "#paste buffer normal x then p" do
|
||||
before <<-EOF
|
||||
jan
|
||||
feb
|
||||
mar
|
||||
EOF
|
||||
|
||||
type '<C-v>jj<C-n>xp<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
ajn
|
||||
efb
|
||||
amr
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer visual y then p" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>vwvelywhp<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello jan jan world
|
||||
hello feb feb world
|
||||
hello mar mar world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer initial visual y then P" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type 'wywb<C-n><C-n><C-n>p<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
jan jan world
|
||||
jan feb world
|
||||
jan mar world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer visual y then P" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>vwvely^P<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
jan hello jan world
|
||||
feb hello feb world
|
||||
mar hello mar world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#paste buffer visual Y then P" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>vwvY^P<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello jan world
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello feb world
|
||||
hello mar world
|
||||
hello mar world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#multiline replacement" do
|
||||
before <<-EOF
|
||||
@ -106,6 +350,38 @@ describe "Multiple Cursors" do
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#multiple new lines on one line in insert mode" do
|
||||
before <<-EOF
|
||||
'a','b','c','d','e'
|
||||
EOF
|
||||
|
||||
type 'f,v<C-n><C-n><C-n>c<CR><Esc>'
|
||||
|
||||
after <<-EOF
|
||||
'a'
|
||||
'b'
|
||||
'c'
|
||||
'd'
|
||||
'e'
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#multiple new lines on one line in insert mode with indents" do
|
||||
before <<-EOF
|
||||
'a','b','c','d','e'
|
||||
EOF
|
||||
|
||||
type '4i<Space><Esc>f,v<C-n><C-n><C-n>c<CR><Esc>:%s/^/^<CR>'
|
||||
|
||||
after <<-EOF
|
||||
^ 'a'
|
||||
^ 'b'
|
||||
^ 'c'
|
||||
^ 'd'
|
||||
^ 'e'
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#normal mode 'o'" do
|
||||
before <<-EOF
|
||||
hello
|
||||
@ -153,6 +429,48 @@ describe "Multiple Cursors" do
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#find command start-of-line" do
|
||||
before <<-EOF
|
||||
hello
|
||||
world
|
||||
|
||||
hello
|
||||
world
|
||||
EOF
|
||||
|
||||
vim.normal ':MultipleCursorsFind ^<CR>'
|
||||
type 'Ibegin<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
beginhello
|
||||
beginworld
|
||||
begin
|
||||
beginhello
|
||||
beginworld
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#find command end-of-line" do
|
||||
before <<-EOF
|
||||
hello
|
||||
world
|
||||
|
||||
hello
|
||||
world
|
||||
EOF
|
||||
|
||||
vim.normal ':MultipleCursorsFind $<CR>'
|
||||
type 'Iend<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
helloend
|
||||
worldend
|
||||
end
|
||||
helloend
|
||||
worldend
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual line mode replacement" do
|
||||
before <<-EOF
|
||||
hello world
|
||||
@ -199,6 +517,216 @@ describe "Multiple Cursors" do
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual mode 'i'" do
|
||||
before <<-EOF
|
||||
hi (hello world jan) bye
|
||||
hi (hello world feb) bye
|
||||
hi (hello world mar) bye
|
||||
EOF
|
||||
|
||||
type 'fw<C-n><C-n><C-n>ibcone<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hi (one) bye
|
||||
hi (one) bye
|
||||
hi (one) bye
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual mode 'a'" do
|
||||
before <<-EOF
|
||||
hi (hello world jan) bye
|
||||
hi (hello world feb) bye
|
||||
hi (hello world mar) bye
|
||||
EOF
|
||||
|
||||
type 'fw<C-n><C-n><C-n>abcone<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hi one bye
|
||||
hi one bye
|
||||
hi one bye
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual mode 'f'" do
|
||||
before <<-EOF
|
||||
hi (hello world jan) bye
|
||||
hi (hello world feb) bye
|
||||
hi (hello world mar) bye
|
||||
EOF
|
||||
|
||||
type 'fw<C-n><C-n><C-n>f)cone<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hi (hello one bye
|
||||
hi (hello one bye
|
||||
hi (hello one bye
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual mode 'F'" do
|
||||
before <<-EOF
|
||||
hi (hello world jan) bye
|
||||
hi (hello world feb) bye
|
||||
hi (hello world mar) bye
|
||||
EOF
|
||||
|
||||
type 'fw<C-n><C-n><C-n>F(cbefore<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hi beforeorld jan) bye
|
||||
hi beforeorld feb) bye
|
||||
hi beforeorld mar) bye
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual mode 't'" do
|
||||
before <<-EOF
|
||||
hello.jan
|
||||
hello hi.feb
|
||||
hello hi bye.mar
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>t.cone<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
one.jan
|
||||
one.feb
|
||||
one.mar
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual mode 'T'" do
|
||||
before <<-EOF
|
||||
jan.world
|
||||
feb.hi world
|
||||
mar.bye hi world
|
||||
EOF
|
||||
|
||||
type 'fw<C-n><C-n><C-n>T.cbefore<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
jan.beforeorld
|
||||
feb.beforeorld
|
||||
mar.beforeorld
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual line mode 'f'" do
|
||||
before <<-EOF
|
||||
hello jan world
|
||||
hello feb world
|
||||
hello mar world
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n><C-n>VfwvAafter<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello jan wafterorld
|
||||
hello feb wafterorld
|
||||
hello mar wafterorld
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual mode 'I'" do
|
||||
before <<-EOF
|
||||
hello world jan
|
||||
hello world feb
|
||||
hello world mar
|
||||
EOF
|
||||
|
||||
type 'w<C-n><C-n><C-n>Ibefore<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello beforeworld jan
|
||||
hello beforeworld feb
|
||||
hello beforeworld mar
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#visual mode 'A'" do
|
||||
before <<-EOF
|
||||
hello world jan
|
||||
hello world feb
|
||||
hello world mar
|
||||
EOF
|
||||
|
||||
type 'w<C-n><C-n><C-n>Aafter<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello worldafter jan
|
||||
hello worldafter feb
|
||||
hello worldafter mar
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#resize regions visual mode 'I'" do
|
||||
before <<-EOF
|
||||
hello world jan
|
||||
hello world feb
|
||||
hello world mar
|
||||
EOF
|
||||
|
||||
type 'w<C-n><C-n><C-n>hhhIbefore<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello beforeworld jan
|
||||
hello beforeworld feb
|
||||
hello beforeworld mar
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#resize regions visual mode 'A'" do
|
||||
before <<-EOF
|
||||
hello world jan
|
||||
hello world feb
|
||||
hello world mar
|
||||
EOF
|
||||
|
||||
type 'w<C-n><C-n><C-n>hhhAbefore<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello wobeforerld jan
|
||||
hello wobeforerld feb
|
||||
hello wobeforerld mar
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#no word boundries visual mode 'I'" do
|
||||
before <<-EOF
|
||||
hello hibye world
|
||||
hello hibye world
|
||||
hello hibye world
|
||||
EOF
|
||||
|
||||
vim.normal ':MultipleCursorsFind bye<CR>'
|
||||
type 'Ibefore<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello hibeforebye world
|
||||
hello hibeforebye world
|
||||
hello hibeforebye world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#variable-length regions visual mode 'I'" do
|
||||
before <<-EOF
|
||||
hello hii world
|
||||
hello hiiii world
|
||||
hello hiiiiii world
|
||||
EOF
|
||||
|
||||
vim.normal ':MultipleCursorsFind \<hi*\><CR>'
|
||||
type 'Ibefore<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hello beforehii world
|
||||
hello beforehiiii world
|
||||
hello beforehiiiiii world
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#normal mode 'I'" do
|
||||
before <<-EOF
|
||||
hello
|
||||
@ -241,22 +769,6 @@ describe "Multiple Cursors" do
|
||||
EOF
|
||||
end
|
||||
|
||||
# 'd' is an operator pending command, which are not supported at the moment.
|
||||
# This should result in a nop, but we should still remain in multicursor mode.
|
||||
specify "#normal mode 'd'" do
|
||||
before <<-EOF
|
||||
hello
|
||||
hello
|
||||
EOF
|
||||
|
||||
type '<C-n><C-n>vdx<Esc>'
|
||||
|
||||
after <<-EOF
|
||||
hell
|
||||
hell
|
||||
EOF
|
||||
end
|
||||
|
||||
specify "#multiline visual mode" do
|
||||
before <<-EOF
|
||||
hello
|
||||
|
@ -5,7 +5,7 @@ Vimrunner::RSpec.configure do |config|
|
||||
|
||||
# Use a single Vim instance for the test suite. Set to false to use an
|
||||
# instance per test (slower, but can be easier to manage).
|
||||
config.reuse_server = true
|
||||
config.reuse_server = false
|
||||
|
||||
# Decide how to start a Vim instance. In this block, an instance should be
|
||||
# spawned and set up with anything project-specific.
|
||||
|
Reference in New Issue
Block a user