mirror of
https://github.com/amix/vimrc
synced 2025-06-23 06:35:01 +08:00
Added two new plugins: vim-expand-region and vim-multiple-cursors.
They are both super useful. Read more on their GitHub pages for more info: https://github.com/terryma/vim-expand-region https://github.com/terryma/vim-multiple-cursors
This commit is contained in:
20
sources_non_forked/vim-multiple-cursors/MIT-LICENSE.txt
Executable file
20
sources_non_forked/vim-multiple-cursors/MIT-LICENSE.txt
Executable file
@ -0,0 +1,20 @@
|
||||
Copyright 2013 Terry Ma
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
90
sources_non_forked/vim-multiple-cursors/README.md
Executable file
90
sources_non_forked/vim-multiple-cursors/README.md
Executable file
@ -0,0 +1,90 @@
|
||||
# vim-multiple-cursors
|
||||
|
||||
## 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.
|
||||
|
||||
### It's great for quick refactoring
|
||||

|
||||
|
||||
### Add a cursor to each line of your visual selection
|
||||

|
||||
|
||||
### Do it backwards too! This is not just a replay of the above gif :)
|
||||

|
||||
|
||||
## 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
|
||||
|
||||
## Installation
|
||||
Install using [Pathogen], [Vundle], [Neobundle], or your favorite Vim package manager.
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
At any time, you can press `<Esc>` to exit back to regular Vim.
|
||||
|
||||
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.
|
||||
|
||||
**NOTE**: The plugin is still somewhat buggy, 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, `Ctrl-n`, `Ctrl-p`, and `Ctrl-x` are mapped by default. If you don't like the plugin taking over your favorite key bindings, then turn off the default with
|
||||
```
|
||||
let g:multi_cursor_use_default_mapping=0
|
||||
```
|
||||
|
||||
You can map the 'next', 'previous', 'skip', and 'exit' keys like the following:
|
||||
```
|
||||
" Default mapping
|
||||
let g:multi_cursor_next_key="\<C-n>"
|
||||
let g:multi_cursor_prev_key="\<C-p>"
|
||||
let g:multi_cursor_skip_key="\<C-x>"
|
||||
let g:multi_cursor_exit_key="\<Esc>"
|
||||
```
|
||||
|
||||
## Setting
|
||||
Currently there're two additional global settings one can tweak:
|
||||
### ```g:multi_cursor_exit_from_visual_mode``` (Defaut: 1)
|
||||
|
||||
If set to 0, then pressing `g:multi_cursor_exit_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_exit_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.
|
||||
|
||||
### 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:
|
||||
|
||||
```
|
||||
" 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.
|
||||
- Single key commands that do not terminate properly cause unexpected behavior. For example, if the cursor is on the first character in the buffer and 'b' is pressed.
|
||||
- Undo behavior is unpredictable
|
||||
- Performance in terminal vim degrades significantly with more cursors
|
||||
- Select mode is not implemented
|
||||
- Buggy when `wrap` is turned on
|
||||
- Cursor highlighting is off. The last column on the same row as Vim's cursor is not highlighted incorrectly. Setting virtualedit=all might help
|
||||
|
||||
## Contributing
|
||||
As one can see, there're still many issues to be resolved, patches and suggestions are always welcome!
|
||||
|
||||
## 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
|
||||
|
||||
[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
|
||||
[Pathogen]:http://github.com/tpope/vim-pathogen
|
||||
[Vundle]:http://github.com/gmarik/vundle
|
||||
[Neobundle]:http://github.com/Shougo/neobundle.vim
|
||||
[emacs-multiple-cursors]:https://github.com/magnars/multiple-cursors.el
|
BIN
sources_non_forked/vim-multiple-cursors/assets/example1.gif
Executable file
BIN
sources_non_forked/vim-multiple-cursors/assets/example1.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 101 KiB |
BIN
sources_non_forked/vim-multiple-cursors/assets/example2.gif
Executable file
BIN
sources_non_forked/vim-multiple-cursors/assets/example2.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 265 KiB |
BIN
sources_non_forked/vim-multiple-cursors/assets/example3.gif
Executable file
BIN
sources_non_forked/vim-multiple-cursors/assets/example3.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
689
sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim
Executable file
689
sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim
Executable file
@ -0,0 +1,689 @@
|
||||
"===============================================================================
|
||||
" Internal Mappings
|
||||
"===============================================================================
|
||||
|
||||
inoremap <silent> <Plug>(multi_cursor_process_user_input)
|
||||
\ <C-o>:call <SID>process_user_inut('i')<CR>
|
||||
nnoremap <silent> <Plug>(multi_cursor_process_user_input)
|
||||
\ :call <SID>process_user_inut('n')<CR>
|
||||
xnoremap <silent> <Plug>(multi_cursor_process_user_input)
|
||||
\ :<C-u>call <SID>process_user_inut('v')<CR>
|
||||
|
||||
inoremap <silent> <Plug>(multi_cursor_apply_user_input_next)
|
||||
\ <C-o>:call <SID>apply_user_input_next('i')<CR>
|
||||
nnoremap <silent> <Plug>(multi_cursor_apply_user_input_next)
|
||||
\ :call <SID>apply_user_input_next('n')<CR>
|
||||
xnoremap <silent> <Plug>(multi_cursor_apply_user_input_next)
|
||||
\ :<C-u>call <SID>apply_user_input_next('v')<CR>
|
||||
|
||||
"===============================================================================
|
||||
" Public Functions
|
||||
"===============================================================================
|
||||
|
||||
" Reset everything the plugin has done
|
||||
function! multiple_cursors#reset()
|
||||
call s:cm.reset()
|
||||
endfunction
|
||||
|
||||
" Creates a new cursor. Different logic applies depending on the mode the user
|
||||
" is in and the current state of the buffer.
|
||||
" 1. In normal mode, a new cursor is created at the end of the word under Vim's
|
||||
" normal cursor
|
||||
" 2. In visual mode, if the visual selection covers more than one line, a new
|
||||
" cursor is created at the beginning of each line
|
||||
" 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)
|
||||
if a:mode ==# 'n'
|
||||
" Reset all existing cursors
|
||||
call s:cm.reset()
|
||||
|
||||
" Select the word under cursor to set the '< and '> marks
|
||||
exec "normal! viw\<Esc>"
|
||||
normal! gv
|
||||
|
||||
call s:create_cursor_from_visual_selection()
|
||||
|
||||
call s:wait_for_user_input('v')
|
||||
elseif a:mode ==# 'v'
|
||||
" If the visual area covers the same line, then do a search for next
|
||||
" occurrence
|
||||
let start = line("'<")
|
||||
let finish = line("'>")
|
||||
if start != finish
|
||||
call s:cm.reset()
|
||||
for line in range(line("'<"), line("'>"))
|
||||
call cursor(line, col("'<"))
|
||||
call s:cm.add()
|
||||
endfor
|
||||
" Start in normal mode
|
||||
call s:wait_for_user_input('n')
|
||||
else
|
||||
" Came directly from visual mode
|
||||
if s:cm.is_empty()
|
||||
call s:create_cursor_from_visual_selection()
|
||||
call s:exit_visual_mode()
|
||||
endif
|
||||
" Select the next ocurrence
|
||||
call s:select_next_occurrence(s:get_visual_selection())
|
||||
" Try to place a cursor there, reselect old cursor if fails
|
||||
if !s:cm.add()
|
||||
call s:exit_visual_mode()
|
||||
" Adding cursor failed, this mean the new cursor is already added
|
||||
call s:cm.reapply_visual_selection()
|
||||
endif
|
||||
call s:wait_for_user_input('v')
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Delete the current cursor and move Vim's cursor back to the previous cursor
|
||||
function! multiple_cursors#prev()
|
||||
if s:cm.is_empty()
|
||||
normal! gv
|
||||
return
|
||||
endif
|
||||
call s:cm.delete_current()
|
||||
" If that was the last cursor, go back to normal mode
|
||||
if s:cm.is_empty()
|
||||
call s:cm.reset()
|
||||
else
|
||||
call s:cm.reapply_visual_selection()
|
||||
call s:wait_for_user_input('v')
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Skip the current cursor and move to the next cursor
|
||||
function! multiple_cursors#skip()
|
||||
if s:cm.is_empty()
|
||||
normal! gv
|
||||
return
|
||||
endif
|
||||
call s:cm.delete_current()
|
||||
call s:select_next_occurrence(s:get_visual_selection())
|
||||
call s:cm.add()
|
||||
call s:wait_for_user_input('v')
|
||||
endfunction
|
||||
|
||||
"===============================================================================
|
||||
" Cursor class
|
||||
"===============================================================================
|
||||
let s:Cursor = {}
|
||||
|
||||
" Create a new cursor. Highlight it and save the current line length
|
||||
function! s:Cursor.new(position)
|
||||
let obj = copy(self)
|
||||
let obj.position = a:position
|
||||
let obj.visual = []
|
||||
let obj.cursor_hi_id = s:highlight_cursor(a:position)
|
||||
let obj.visual_hi_id = 0
|
||||
let obj.line_length = col([a:position[1], '$'])
|
||||
return obj
|
||||
endfunction
|
||||
|
||||
" Return the line the cursor is on
|
||||
function! s:Cursor.line() dict
|
||||
return self.position[1]
|
||||
endfunction
|
||||
|
||||
" Return the column the cursor is on
|
||||
function! s:Cursor.column() dict
|
||||
return self.position[2]
|
||||
endfunction
|
||||
|
||||
" Move the cursor location by the number of lines and columns specified in the
|
||||
" input. The input can be negative.
|
||||
function! s:Cursor.move(line, column) dict
|
||||
let self.position[1] += a:line
|
||||
let self.position[2] += a:column
|
||||
if !empty(self.visual)
|
||||
let self.visual[0][1] += a:line
|
||||
let self.visual[0][2] += a:column
|
||||
let self.visual[1][1] += a:line
|
||||
let self.visual[1][2] += a:column
|
||||
endif
|
||||
call self.update_highlight()
|
||||
endfunction
|
||||
|
||||
" Update the current position of the cursor
|
||||
function! s:Cursor.update_position(pos) dict
|
||||
let self.position = a:pos
|
||||
call self.update_highlight()
|
||||
endfunction
|
||||
|
||||
" Reapply the highlight on the cursor
|
||||
function! s:Cursor.update_highlight() dict
|
||||
call s:cm.remove_highlight(self.cursor_hi_id)
|
||||
let self.cursor_hi_id = s:highlight_cursor(self.position)
|
||||
endfunction
|
||||
|
||||
" Refresh the length of the line the cursor is on. This could change from
|
||||
" underneath
|
||||
function! s:Cursor.update_line_length() dict
|
||||
let self.line_length = col([self.line(), '$'])
|
||||
endfunction
|
||||
|
||||
" Update the visual selection and its highlight
|
||||
function! s:Cursor.update_visual_selection(region) dict
|
||||
let self.visual = a:region
|
||||
call s:cm.remove_highlight(self.visual_hi_id)
|
||||
let self.visual_hi_id = s:highlight_region(a:region)
|
||||
endfunction
|
||||
|
||||
" Remove the visual selection and its highlight
|
||||
function! s:Cursor.remove_visual_selection() dict
|
||||
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
|
||||
|
||||
"===============================================================================
|
||||
" CursorManager class
|
||||
"===============================================================================
|
||||
let s:CursorManager = {}
|
||||
|
||||
" Constructor
|
||||
function! s:CursorManager.new()
|
||||
let obj = copy(self)
|
||||
let obj.cursors = []
|
||||
let obj.current_index = -1
|
||||
let obj.starting_index = -1
|
||||
let obj.saved_settings = {
|
||||
\ 'virtualedit': &virtualedit,
|
||||
\ 'cursorline': &cursorline,
|
||||
\ }
|
||||
return obj
|
||||
endfunction
|
||||
|
||||
" Clear all cursors and their highlights
|
||||
function! s:CursorManager.reset() dict
|
||||
call clearmatches()
|
||||
let self.cursors = []
|
||||
let self.current_index = -1
|
||||
let self.starting_index = -1
|
||||
call self.restore_user_settings()
|
||||
" FIXME(terryma): Doesn't belong here
|
||||
let s:from_mode = ''
|
||||
let s:to_mode = ''
|
||||
endfunction
|
||||
|
||||
" Returns 0 if it's not managing any cursors at the moment
|
||||
function! s:CursorManager.is_empty() dict
|
||||
return self.size() == 0
|
||||
endfunction
|
||||
|
||||
" Returns the number of cursors it's managing
|
||||
function! s:CursorManager.size() dict
|
||||
return len(self.cursors)
|
||||
endfunction
|
||||
|
||||
" Returns the current cursor
|
||||
function! s:CursorManager.get_current() dict
|
||||
return self.cursors[self.current_index]
|
||||
endfunction
|
||||
|
||||
" Returns the cursor at index i
|
||||
function! s:CursorManager.get(i) dict
|
||||
return self.cursors[a:i]
|
||||
endfunction
|
||||
|
||||
" Removes the current cursor and all its associated highlighting. Also update
|
||||
" the current index
|
||||
function! s:CursorManager.delete_current() dict
|
||||
call self.remove_highlight(self.get_current().cursor_hi_id)
|
||||
call self.remove_highlight(self.get_current().visual_hi_id)
|
||||
call remove(self.cursors, self.current_index)
|
||||
let self.current_index -= 1
|
||||
endfunction
|
||||
|
||||
" Remove the highlighting if it matchid exists
|
||||
function! s:CursorManager.remove_highlight(hi_id) dict
|
||||
if a:hi_id
|
||||
call matchdelete(a:hi_id)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:CursorManager.debug() dict
|
||||
let i = 0
|
||||
for c in self.cursors
|
||||
echom 'cursor #'.i.': '.string(c)
|
||||
let i+=1
|
||||
endfor
|
||||
echom 'last key = '.s:char
|
||||
echom 'current cursor = '.self.current_index
|
||||
echom 'current pos = '.string(getpos('.'))
|
||||
echom 'last visual begin = '.string(getpos("'<"))
|
||||
echom 'last visual end = '.string(getpos("'>"))
|
||||
echom 'current mode = '.mode()
|
||||
echom 'current mode custom = '.s:to_mode
|
||||
echom 'prev mode custom = '.s:from_mode
|
||||
echom ' '
|
||||
endfunction
|
||||
|
||||
" Sync the current cursor to the current Vim cursor. This includes updating its
|
||||
" location, its highlight, and potentially its visual region. Return true if the
|
||||
" position changed, false otherwise
|
||||
function! s:CursorManager.update_current() dict
|
||||
let cur = self.get_current()
|
||||
if s:to_mode ==# 'v'
|
||||
call cur.update_visual_selection(s:get_current_visual_selection())
|
||||
call s:exit_visual_mode()
|
||||
else
|
||||
call cur.remove_visual_selection()
|
||||
endif
|
||||
|
||||
let vdelta = line('$') - s:saved_linecount
|
||||
" If the cursor changed line, and the total number of lines changed
|
||||
if vdelta != 0 && cur.line() != line('.')
|
||||
if self.current_index != self.size() - 1
|
||||
let cur_line_length = len(getline(cur.line()))
|
||||
let new_line_length = len(getline('.'))
|
||||
for i in range(self.current_index+1, self.size()-1)
|
||||
let hdelta = 0
|
||||
" If there're other cursors on the same line, we need to adjust their
|
||||
" columns. This needs to happen before we adjust their line!
|
||||
if cur.line() == self.get(i).line()
|
||||
if vdelta > 0
|
||||
" Added a line
|
||||
let hdelta = cur_line_length * -1
|
||||
else
|
||||
" Removed a line
|
||||
let hdelta = new_line_length
|
||||
endif
|
||||
endif
|
||||
call self.get(i).move(vdelta, hdelta)
|
||||
endfor
|
||||
endif
|
||||
else
|
||||
" If the line length changes, for all the other cursors on the same line as
|
||||
" the current one, update their cursor location as well
|
||||
let hdelta = col('$') - cur.line_length
|
||||
" Only do this if we're still on the same line as before
|
||||
if hdelta != 0 && cur.line() == line('.')
|
||||
" Update all the cursor's positions that occur after the current cursor on
|
||||
" the same line
|
||||
if self.current_index != self.size() - 1
|
||||
for i in range(self.current_index+1, self.size()-1)
|
||||
" Only do it for cursors on the same line
|
||||
if cur.line() == self.get(i).line()
|
||||
call self.get(i).move(0, hdelta)
|
||||
else
|
||||
" Early exit, if we're not on the same line, neither will any cursor
|
||||
" that come after this
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
let pos = getpos('.')
|
||||
if cur.position == pos
|
||||
return 0
|
||||
endif
|
||||
call cur.update_position(pos)
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
" Advance to the next cursor
|
||||
function! s:CursorManager.next() dict
|
||||
let self.current_index = (self.current_index + 1) % self.size()
|
||||
endfunction
|
||||
|
||||
" Start tracking cursor updates
|
||||
function! s:CursorManager.start_loop() dict
|
||||
let self.starting_index = self.current_index
|
||||
endfunction
|
||||
|
||||
" Returns true if we're cycled through all the cursors
|
||||
function! s:CursorManager.loop_done() dict
|
||||
return self.current_index == self.starting_index
|
||||
endfunction
|
||||
|
||||
" Tweak some user settings. This is called every time multicursor mode is
|
||||
" entered.
|
||||
" virtualedit needs to be set to onemore for updates to work correctly
|
||||
" cursorline needs to be turned off for the cursor highlight to work on the line
|
||||
" where the real vim cursor is
|
||||
function! s:CursorManager.initialize() dict
|
||||
let &virtualedit = "onemore"
|
||||
let &cursorline = 0
|
||||
endfunction
|
||||
|
||||
" Restore user settings.
|
||||
function! s:CursorManager.restore_user_settings() dict
|
||||
if !empty(self.saved_settings)
|
||||
let &virtualedit = self.saved_settings['virtualedit']
|
||||
let &cursorline = self.saved_settings['cursorline']
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Reselect the current cursor's region in visual mode
|
||||
function! s:CursorManager.reapply_visual_selection() dict
|
||||
call s:select_in_visual_mode(self.get_current().visual)
|
||||
endfunction
|
||||
|
||||
" Creates a new multicursor at the current Vim cursor location. Return true if
|
||||
" the cursor has been successfully added, false otherwise
|
||||
function! s:CursorManager.add() dict
|
||||
" Lazy init
|
||||
if self.is_empty()
|
||||
call self.initialize()
|
||||
endif
|
||||
|
||||
let pos = getpos('.')
|
||||
|
||||
" Don't add duplicates
|
||||
let i = 0
|
||||
for c in self.cursors
|
||||
if c.position == pos
|
||||
return 0
|
||||
endif
|
||||
let i+=1
|
||||
endfor
|
||||
|
||||
let cursor = s:Cursor.new(pos)
|
||||
|
||||
" Save the visual selection
|
||||
if mode() ==# 'v'
|
||||
call cursor.update_visual_selection(s:get_current_visual_selection())
|
||||
endif
|
||||
|
||||
call add(self.cursors, cursor)
|
||||
let self.current_index += 1
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
"===============================================================================
|
||||
" Variables
|
||||
"===============================================================================
|
||||
|
||||
" This is the last user input that we're going to replicate, in its string form
|
||||
let s: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
|
||||
let s:to_mode=''
|
||||
" This is the total number of lines in the buffer before processing s:char
|
||||
let s:saved_linecount=-1
|
||||
" These keys will not be replcated at every cursor location
|
||||
let s:special_keys = [
|
||||
\ g:multi_cursor_next_key,
|
||||
\ g:multi_cursor_prev_key,
|
||||
\ g:multi_cursor_skip_key,
|
||||
\ ]
|
||||
" The highlight group we use for all the cursors
|
||||
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'
|
||||
|
||||
" Singleton cursor manager instance
|
||||
let s:cm = s:CursorManager.new()
|
||||
|
||||
"===============================================================================
|
||||
" Initialization
|
||||
"===============================================================================
|
||||
if !hlexists(s:hi_group_cursor)
|
||||
exec "highlight ".s:hi_group_cursor." term=reverse cterm=reverse gui=reverse"
|
||||
endif
|
||||
if !hlexists(s:hi_group_visual)
|
||||
exec "highlight link ".s:hi_group_visual." Visual"
|
||||
endif
|
||||
|
||||
"===============================================================================
|
||||
" Utility functions
|
||||
"===============================================================================
|
||||
|
||||
" Exit visual mode and go back to normal mode
|
||||
" Precondition: In visual mode
|
||||
" Postcondition: In normal mode, cursor in the same location as visual mode
|
||||
" The reason for the additional gv\<Esc> is that it allows the cursor to stay
|
||||
" on where it was before exiting
|
||||
function! s:exit_visual_mode()
|
||||
exec "normal! \<Esc>gv\<Esc>"
|
||||
endfunction
|
||||
|
||||
" Visually select input region, where region is an array containing the start
|
||||
" and end position. If start is after end, the selection simply goes backwards.
|
||||
" Typically m<, m>, and gv would be a simple way of accomplishing this, but on
|
||||
" some systems, the m< and m> marks are not supported. Note that v`` has random
|
||||
" behavior if `` is the same location as the cursor location.
|
||||
" Precondition: In normal mode
|
||||
" Postcondition: In visual mode, with the region selected
|
||||
function! s:select_in_visual_mode(region)
|
||||
call setpos('.', a:region[0])
|
||||
call setpos("'`", a:region[1])
|
||||
if getpos('.') == getpos("'`")
|
||||
normal! v
|
||||
else
|
||||
normal! v``
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Highlight the position using the cursor highlight group
|
||||
function! s:highlight_cursor(pos)
|
||||
" Give cursor highlight high priority, to overrule visual selection
|
||||
return matchadd(s:hi_group_cursor, '\%'.a:pos[1].'l\%'.a:pos[2].'v', 99999)
|
||||
endfunction
|
||||
|
||||
" Compare two position arrays. Each input is the result of getpos(). Return a
|
||||
" negative value if lhs occurs before rhs, positive value if after, and 0 if
|
||||
" they are the same.
|
||||
function! s:compare_pos(l, r)
|
||||
" If number lines are the same, compare columns
|
||||
return a:l[1] ==# a:r[1] ? a:l[2] - a:r[2] : a:l[1] - a:r[1]
|
||||
endfunction
|
||||
|
||||
" Highlight the area bounded by the input region. The logic here really stinks,
|
||||
" it's frustrating that Vim doesn't have a built in easier way to do this. None
|
||||
" of the \%V or \%'m solutions work because we need the highlighting to stay for
|
||||
" multiple places.
|
||||
function! s:highlight_region(region)
|
||||
let s = sort(copy(a:region), "s:compare_pos")
|
||||
if (s[0][1] == s[1][1])
|
||||
" Same line
|
||||
let pattern = '\%'.s[0][1].'l\%>'.(s[0][2]-1).'v.*\%<'.(s[1][2]+1).'v.'
|
||||
else
|
||||
" Two lines
|
||||
let s1 = '\%'.s[0][1].'l.\%>'.s[0][2].'v.*'
|
||||
let s2 = '\%'.s[1][1].'l.*\%<'.s[1][2].'v..'
|
||||
let pattern = s1.'\|'.s2
|
||||
if (s[1][1] - s[0][1] > 1)
|
||||
let pattern = pattern.'\|\%>'.s[0][1].'l\%<'.s[1][1].'l'
|
||||
endif
|
||||
endif
|
||||
return matchadd(s:hi_group_visual, pattern)
|
||||
endfunction
|
||||
|
||||
" Perform the operation that's necessary to revert us from one mode to another
|
||||
function! s:revert_mode(from, to)
|
||||
if a:to ==# 'v'
|
||||
call s:cm.reapply_visual_selection()
|
||||
endif
|
||||
if a:to ==# 'i'
|
||||
startinsert
|
||||
endif
|
||||
if a:to ==# 'n' && a:from ==# 'i'
|
||||
stopinsert
|
||||
endif
|
||||
if a:to ==# 'n' && a:from ==# 'v'
|
||||
" TODO(terryma): Hmm this would cause visual to normal mode to break.
|
||||
" Strange
|
||||
" call s:exit_visual_mode()
|
||||
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...
|
||||
function! s:feedkeys(keys)
|
||||
while 1
|
||||
let c = getchar(0)
|
||||
" 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
|
||||
endif
|
||||
endwhile
|
||||
call feedkeys(a:keys)
|
||||
endfunction
|
||||
|
||||
" Take the user input and apply it at every cursor
|
||||
function! s:process_user_inut(mode)
|
||||
" 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 setpos('.', s:cm.get_current().position)
|
||||
|
||||
" Before applying the user input, 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)
|
||||
|
||||
" 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 s:saved_linecount = line('$')
|
||||
|
||||
" 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
|
||||
call s:feedkeys(s:char."\<Plug>(multi_cursor_apply_user_input_next)")
|
||||
endfunction
|
||||
|
||||
" Apply the user input at the next cursor location
|
||||
function! s:apply_user_input_next(mode)
|
||||
" Save the current mode
|
||||
let s:to_mode = a:mode
|
||||
|
||||
" Update the current cursor's information
|
||||
let changed = s:cm.update_current()
|
||||
|
||||
" Advance the cursor index
|
||||
call s:cm.next()
|
||||
|
||||
" Update Vim's cursor
|
||||
call setpos('.', s:cm.get_current().position)
|
||||
|
||||
" We're done if we're made the full round
|
||||
if s:cm.loop_done()
|
||||
" If we stay in visual mode, we need to reselect the original cursor
|
||||
if s:to_mode ==# 'v'
|
||||
call s:cm.reapply_visual_selection()
|
||||
endif
|
||||
call s:wait_for_user_input(s:to_mode)
|
||||
else
|
||||
" Continue to next
|
||||
call s:process_user_inut(s:from_mode)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
" Precondition: In visual mode with selected text
|
||||
" Postcondition: A new cursor is placed at the end of the selected text
|
||||
function! s:create_cursor_from_visual_selection()
|
||||
" Get the text for the current visual selection
|
||||
let selection = s:get_visual_selection()
|
||||
|
||||
" Go to the end of the visual selection
|
||||
call cursor(line("'<"), col("'>"))
|
||||
|
||||
" Add the current at the new location
|
||||
call s:cm.add()
|
||||
endfunction
|
||||
|
||||
" Precondition: In visual mode
|
||||
" Postcondition: Remain in visual mode
|
||||
" Return array of start and end position of visual selection
|
||||
" This should be available from the '< and '> registers, but it fails to work
|
||||
" correctly on some systems until visual mode quits. So we force quitting in
|
||||
" visual mode and reselecting the region afterwards
|
||||
function! s:get_current_visual_selection()
|
||||
call s:exit_visual_mode()
|
||||
let left = getpos("'<")
|
||||
let right = getpos("'>")
|
||||
if getpos('.') == left
|
||||
let region = [right, left]
|
||||
else
|
||||
let region = [left, right]
|
||||
endif
|
||||
call s:select_in_visual_mode(region)
|
||||
return region
|
||||
endfunction
|
||||
|
||||
" Return the content of the current visual selection. This is used to find the
|
||||
" next match in the buffer
|
||||
function! s:get_visual_selection()
|
||||
normal! gv
|
||||
let start_pos = getpos("'<")
|
||||
let end_pos = getpos("'>")
|
||||
let [lnum1, col1] = start_pos[1:2]
|
||||
let [lnum2, col2] = end_pos[1:2]
|
||||
let lines = getline(lnum1, lnum2)
|
||||
let lines[-1] = lines[-1][: col2 - 1]
|
||||
let lines[0] = lines[0][col1 - 1:]
|
||||
return join(lines, "\n")
|
||||
endfunction
|
||||
|
||||
" Visually select the next occurrence of the input text in the buffer
|
||||
function! s:select_next_occurrence(text)
|
||||
call s:exit_visual_mode()
|
||||
let pattern = '\V\C'.substitute(escape(a:text, '\'), '\n', '\\n', 'g')
|
||||
call search(pattern)
|
||||
let start = getpos('.')
|
||||
call search(pattern, 'ce')
|
||||
let end = getpos('.')
|
||||
call s:select_in_visual_mode([start, end])
|
||||
endfunction
|
||||
|
||||
" Wrapper around getchar() that returns the string representation of the user
|
||||
" input
|
||||
function! s:get_char()
|
||||
let c = getchar()
|
||||
" If the character is a number, then it's not a special key
|
||||
if type(c) == 0
|
||||
let c = nr2char(c)
|
||||
endif
|
||||
return c
|
||||
endfunction
|
||||
|
||||
" Quits multicursor mode and clears all cursors. Return true if exited
|
||||
" successfully.
|
||||
function! s:exit()
|
||||
if s:char ==# g:multi_cursor_quit_key &&
|
||||
\ (s:from_mode ==# 'n' ||
|
||||
\ s:from_mode ==# 'v' && g:multi_cursor_exit_from_visual_mode ||
|
||||
\ s:from_mode ==# 'i' && g:multi_cursor_exit_from_insert_mode)
|
||||
if s:from_mode ==# 'i'
|
||||
stopinsert
|
||||
elseif s:from_mode ==# 'v'
|
||||
call s:exit_visual_mode()
|
||||
endif
|
||||
call s:cm.reset()
|
||||
return 1
|
||||
endif
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
" Take users input and figure out what to do with it
|
||||
function! s:wait_for_user_input(mode)
|
||||
let s:from_mode = a:mode
|
||||
let s:to_mode = ''
|
||||
redraw
|
||||
let s:char = s:get_char()
|
||||
redraw
|
||||
|
||||
if s:exit()
|
||||
return
|
||||
endif
|
||||
|
||||
let feedkeys = ''
|
||||
if index(s:special_keys, s:char) != -1
|
||||
let feedkeys = s:char
|
||||
else
|
||||
call s:cm.start_loop()
|
||||
let feedkeys = "\<Plug>(multi_cursor_process_user_input)"
|
||||
endif
|
||||
call s:feedkeys(feedkeys)
|
||||
endfunction
|
174
sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt
Executable file
174
sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt
Executable file
@ -0,0 +1,174 @@
|
||||
*vim-multiple-cursors.txt* True Sublime Text multiple selection in Vim
|
||||
|
||||
____ _ __
|
||||
____ ___ __ __/ / /_(_)___ / /__ _______ ________________ __________
|
||||
/ __ `__ \/ / / / / __/ / __ \/ / _ \ / ___/ / / / ___/ ___/ __ \/ ___/ ___/
|
||||
/ / / / / / /_/ / / /_/ / /_/ / / __/ / /__/ /_/ / / (__ ) /_/ / / (__ )
|
||||
/_/ /_/ /_/\__,_/_/\__/_/ .___/_/\___/ \___/\__,_/_/ /____/\____/_/ /____/
|
||||
/_/
|
||||
|
||||
|
||||
Reference Manual~
|
||||
|
||||
|
||||
==============================================================================
|
||||
|
||||
CONTENTS *multiple-cursors-contents*
|
||||
1.Intro...................................|multiple-cursors-intro|
|
||||
2.Usage...................................|multiple-cursors-usage|
|
||||
3.Mappings................................|multiple-cursors-mappings|
|
||||
4.Global Options..........................|multiple-cursors-global-options|
|
||||
5.Issues..................................|multiple-cursors-issues|
|
||||
6.Contributing............................|multiple-cursors-contributing|
|
||||
7.License.................................|multiple-cursors-license|
|
||||
8.Credit..................................|multiple-cursors-credit|
|
||||
9.References..............................|multiple-cursors-references|
|
||||
|
||||
==============================================================================
|
||||
1. Intro *multiple-cursors-intro*
|
||||
|
||||
There [1] have [2] been [3] many [4] attempts [5] at bringing Sublime Text's
|
||||
awesome multiple selection [6] 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.
|
||||
|
||||
==============================================================================
|
||||
2. Usage *multiple-cursors-usage*
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
At any time, you can press <Esc> to exit back to regular Vim.
|
||||
|
||||
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.
|
||||
|
||||
**NOTE**: The plugin is still somewhat buggy, 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.
|
||||
|
||||
==============================================================================
|
||||
3. Mappings *multiple-cursors-mappings*
|
||||
|
||||
*g:multi_cursor_use_default_mapping* (Default: 1)
|
||||
|
||||
Out of the box, CTRL-N, CTRL-P, and CTRL-X are mapped by default. If you don't
|
||||
like the plugin taking over your favorite key bindings, then turn off the
|
||||
default with >
|
||||
|
||||
let g:multi_cursor_use_default_mapping=0
|
||||
<
|
||||
|
||||
*g:multi_cursor_next_key* (Default: "\<C-n>")
|
||||
*g:multi_cursor_prev_key* (Default: "\<C-p>")
|
||||
*g:multi_cursor_skip_key* (Default: "\<C-x>")
|
||||
*g:multi_cursor_exit_key* (Default: "\<Esc>")
|
||||
You can map the 'next', 'previous', 'skip', and 'exit' keys like the
|
||||
following: >
|
||||
|
||||
" Default mapping
|
||||
let g:multi_cursor_next_key="\<C-n>"
|
||||
let g:multi_cursor_prev_key="\<C-p>"
|
||||
let g:multi_cursor_skip_key="\<C-x>"
|
||||
let g:multi_cursor_exit_key="\<Esc>"
|
||||
<
|
||||
|
||||
==============================================================================
|
||||
4. Global Options *multiple-cursors-global-options*
|
||||
|
||||
Currently there're two additional global settings one can tweak:
|
||||
|
||||
*g:multi_cursor_exit_from_visual_mode* (Defaut: 1)
|
||||
|
||||
If set to 0, then pressing |g:multi_cursor_exit_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_exit_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.
|
||||
|
||||
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: >
|
||||
|
||||
" 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*
|
||||
|
||||
- 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.
|
||||
- Single key commands that do not terminate properly cause unexpected
|
||||
behavior. For example, if the cursor is on the first character in the buffer
|
||||
and 'b' is pressed.
|
||||
- Undo behavior is unpredictable
|
||||
- Performance in terminal vim degrades significantly with more cursors
|
||||
- Select mode is not implemented
|
||||
- Buggy when wrap is turned on
|
||||
- Cursor highlighting is off. The last column on the same row as Vim's cursor
|
||||
is not highlighted incorrectly. Setting virtualedit=all might help
|
||||
|
||||
==============================================================================
|
||||
6. Contributing *multiple-cursors-contributing*
|
||||
|
||||
The project is hosted on Github. Patches, feature requests and suggestions are
|
||||
always welcome!
|
||||
|
||||
Find the latest version of the plugin here:
|
||||
http://github.com/terryma/vim-multiple-cursors
|
||||
|
||||
==============================================================================
|
||||
7. License *multiple-cursors-license*
|
||||
|
||||
The project is licensed under the MIT license [7]. Copyrigth 2013 Terry Ma
|
||||
|
||||
==============================================================================
|
||||
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.
|
||||
|
||||
==============================================================================
|
||||
9. References *multiple-cursors-references*
|
||||
|
||||
[1] https://github.com/paradigm/vim-multicursor
|
||||
[2] https://github.com/felixr/vim-multiedit
|
||||
[3] https://github.com/hlissner/vim-multiedit
|
||||
[4] https://github.com/adinapoli/vim-markmultiple
|
||||
[5] https://github.com/AndrewRadev/multichange.vim
|
||||
[6] http://www.sublimetext.com/docs/2/multiple_selection_with_the_keyboard.html
|
||||
[7] http://opensource.org/licenses/MIT
|
||||
[8] https://github.com/magnars/multiple-cursors.el
|
||||
|
||||
vim:tw=78:sw=4:ft=help:norl:
|
19
sources_non_forked/vim-multiple-cursors/doc/tags
Normal file
19
sources_non_forked/vim-multiple-cursors/doc/tags
Normal file
@ -0,0 +1,19 @@
|
||||
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_exit_key multiple_cursors.txt /*g:multi_cursor_exit_key*
|
||||
g:multi_cursor_next_key multiple_cursors.txt /*g:multi_cursor_next_key*
|
||||
g:multi_cursor_prev_key multiple_cursors.txt /*g:multi_cursor_prev_key*
|
||||
g:multi_cursor_skip_key multiple_cursors.txt /*g:multi_cursor_skip_key*
|
||||
g:multi_cursor_use_default_mapping multiple_cursors.txt /*g:multi_cursor_use_default_mapping*
|
||||
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*
|
||||
multiple-cursors-global-options multiple_cursors.txt /*multiple-cursors-global-options*
|
||||
multiple-cursors-intro multiple_cursors.txt /*multiple-cursors-intro*
|
||||
multiple-cursors-issues multiple_cursors.txt /*multiple-cursors-issues*
|
||||
multiple-cursors-license multiple_cursors.txt /*multiple-cursors-license*
|
||||
multiple-cursors-mappings multiple_cursors.txt /*multiple-cursors-mappings*
|
||||
multiple-cursors-references multiple_cursors.txt /*multiple-cursors-references*
|
||||
multiple-cursors-usage multiple_cursors.txt /*multiple-cursors-usage*
|
||||
vim-multiple-cursors multiple_cursors.txt /*vim-multiple-cursors*
|
||||
vim-multiple-cursors.txt multiple_cursors.txt /*vim-multiple-cursors.txt*
|
99
sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim
Executable file
99
sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim
Executable file
@ -0,0 +1,99 @@
|
||||
"===============================================================================
|
||||
" File: multiple_cursors.vim
|
||||
" Author: Terry Ma
|
||||
" Description: Emulate Sublime Text's multi selection feature
|
||||
" Issues:
|
||||
" - Performance in terminal vim degrades significantly with more cursors
|
||||
" - 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.
|
||||
" - Multi key commands is not supported
|
||||
" - Single key commands that do not terminate properly cause unexpected
|
||||
" behavior. For example, if the cursor is on the first character in the buffer
|
||||
" and 'b' is pressed.
|
||||
" - Undo behavior is unpredictable
|
||||
" - Select mode is not implemented
|
||||
" - There is a bug with selection and highlight when wrap is on
|
||||
"
|
||||
" Potential Features:
|
||||
" - Create a blinking cursor effect? Good place to do it would be instead of
|
||||
" waiting for user input, cycle through the highlight
|
||||
" - Integrate with the status line? Maybe show a special multicursor mode?
|
||||
" - Support mouse? Ctrl/Cmd click to set cursor?
|
||||
"
|
||||
" Features:
|
||||
" - Real time update of cursor locations
|
||||
" - In normal mode, pressing <C-n> will highlight the current word under cursor,
|
||||
" and places a 'multicursor' at the end of the word, and goes to visual mode
|
||||
" - In visual mode, right after the above operation, pressing <C-n> again will
|
||||
" search for the word forward, and places a new cursor at the end of the
|
||||
" resulting search, one can continue to do this in Visual mode, this resembles
|
||||
" the Cmd-D feature of Sublime
|
||||
" - In insert mode, insert operations are captures and replayed at all the
|
||||
" cursor locations
|
||||
" - Pressing <Esc> in Normal mode quits multicursor mode and clears all cursors
|
||||
" - Normal mode single keystroke commands work:
|
||||
" - Works: 'w,e,i,p,a,h,j,k,l,x,v,b'
|
||||
" - Does not work: ''
|
||||
" - Replace mode just seems to work
|
||||
" - Visual mode
|
||||
" - Works: 'w,e,b,h,j,k,l,o'
|
||||
" - Does not work: 'A, I', because <C-o> does not get it out of normal mode
|
||||
" for these commands. It takes two
|
||||
"===============================================================================
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
function! s:init_settings(settings)
|
||||
for [key, value] in items(a:settings)
|
||||
let sub = ''
|
||||
if type(value) == 0
|
||||
let sub = '%d'
|
||||
elseif type(value) == 1
|
||||
let sub = '"%s"'
|
||||
endif
|
||||
let fmt = printf("let g:multi_cursor_%%s=get(g:, 'multi_cursor_%%s', %s)",
|
||||
\ sub)
|
||||
exec printf(fmt, key, key, value)
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
" Settings
|
||||
let s:settings = {
|
||||
\ 'exit_from_visual_mode': 1,
|
||||
\ 'exit_from_insert_mode': 1,
|
||||
\ 'use_default_mapping': 1,
|
||||
\ }
|
||||
|
||||
let s:settings_if_default = {
|
||||
\ 'quit_key': "\<Esc>",
|
||||
\ 'next_key': "\<C-n>",
|
||||
\ 'prev_key': "\<C-p>",
|
||||
\ 'skip_key': "\<C-x>",
|
||||
\ }
|
||||
|
||||
call s:init_settings(s:settings)
|
||||
|
||||
if g:multi_cursor_use_default_mapping
|
||||
call s:init_settings(s:settings_if_default)
|
||||
endif
|
||||
|
||||
" External mappings
|
||||
if exists('g:multi_cursor_next_key')
|
||||
exec 'nnoremap <silent> '.g:multi_cursor_next_key.
|
||||
\' :call multiple_cursors#new("n")<CR>'
|
||||
exec 'xnoremap <silent> '.g:multi_cursor_next_key.
|
||||
\' :<C-u>call multiple_cursors#new("v")<CR>'
|
||||
endif
|
||||
if exists('g:multi_cursor_prev_key')
|
||||
exec 'xnoremap <silent> '.g:multi_cursor_prev_key.
|
||||
\' :<C-u>call multiple_cursors#prev()<CR>'
|
||||
endif
|
||||
if exists('g:multi_cursor_skip_key')
|
||||
exec 'xnoremap <silent> '.g:multi_cursor_skip_key.
|
||||
\' :<C-u>call multiple_cursors#skip()<CR>'
|
||||
endif
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
Reference in New Issue
Block a user