diff --git a/README.md b/README.md index 04c86348..39efe3fc 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ I recommend reading the docs of these plugins to understand them better. Each of * [zencoding](https://github.com/mattn/zencoding-vim): Expanding abbreviation like zen-coding, very useful for editing XML, HTML. * [vim-indent-object](https://github.com/michaeljsmith/vim-indent-object): Defines a new text object representing lines of code at the same indent level. Useful for python/vim scripts * [taglist.vim](https://github.com/vim-scripts/taglist.vim): Source code browser (supports C/C++, java, perl, python, tcl, sql, php, etc) +* [vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors): Sublime Text style multiple selections for Vim, CTRL+N is remapped to CTRL+A (due to YankRing) +* [vim-expand-region](https://github.com/terryma/vim-expand-region): Allows you to visually select increasingly larger regions of text using the same key combination. ## What color schemes are included? @@ -134,6 +136,7 @@ Managing the [NERD Tree](https://github.com/scrooloose/nerdtree) plugin: map nf :NERDTreeFind ### Normal mode mappings + Fast saving of a buffer: nmap w :w! @@ -261,7 +264,7 @@ Bash like keys for the command line: cnoremap cnoremap -Write the file as sudo (only on Unix). [Vim tip](http://vim.wikia.com/wiki/Su-write): +Write the file as sudo (only on Unix). Super useful when you open a file and you don't have permissions to save your changes. [Vim tip](http://vim.wikia.com/wiki/Su-write): :W diff --git a/sources_non_forked/vim-expand-region/MIT-LICENSE.txt b/sources_non_forked/vim-expand-region/MIT-LICENSE.txt new file mode 100755 index 00000000..dade7aa4 --- /dev/null +++ b/sources_non_forked/vim-expand-region/MIT-LICENSE.txt @@ -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. diff --git a/sources_non_forked/vim-expand-region/README.md b/sources_non_forked/vim-expand-region/README.md new file mode 100755 index 00000000..0ba8efac --- /dev/null +++ b/sources_non_forked/vim-expand-region/README.md @@ -0,0 +1,92 @@ +# vim-expand-region + +## About +[vim-expand-region] is a Vim plugin that allows you to visually select increasingly larger regions of text using the same key combination. It is similar to features from other editors: + +- Emac's [expand region](https://github.com/magnars/expand-region.el) +- IntelliJ's [syntax aware selection](http://www.jetbrains.com/idea/documentation/tips/#tips_code_editing) +- Eclipse's [select enclosing element](http://stackoverflow.com/questions/4264047/intellij-ctrlw-equivalent-shortcut-in-eclipse) + +

+ vim-expand-region +

+ +## Installation +Install using [Pathogen], [Vundle], [Neobundle], or your favorite Vim package manager. + +## Quick Start +Press ```+``` to expand the visual selection and ```_``` to shrink it. + +## Mapping +Customize the key mapping if you don't like the default. + +``` +map K (expand_region_expand) +map J (expand_region_shrink) +``` + +## Setting +### Customize selected regions +The plugin uses __your own__ text objects to determine the expansion. You can customize the text objects the plugin knows about with ```g:expand_region_text_objects```. + +```vim +" Default settings. (NOTE: Remove comments in dictionary before sourcing) +let g:expand_region_text_objects = { + \ 'iw' :0, + \ 'iW' :0, + \ 'i"' :0, + \ 'i''' :0, + \ 'i]' :1, " Support nesting of square brackets + \ 'ib' :1, " Support nesting of parentheses + \ 'iB' :1, " Support nesting of braces + \ 'il' :0, " 'inside line'. Available through https://github.com/kana/vim-textobj-line + \ 'ip' :0, + \ 'ie' :0, " 'entire file'. Available through https://github.com/kana/vim-textobj-entire + \ } +``` + +You can extend the global default dictionary by calling ```expand_region#custom_text_objects```: + +```vim +" Extend the global default (NOTE: Remove comments in dictionary before sourcing) +call expand_region#custom_text_objects({ + \ "\/\\n\\n\": 1, " Motions are supported as well. Here's a search motion that finds a blank line + \ 'a]' :1, " Support nesting of 'around' brackets + \ 'ab' :1, " Support nesting of 'around' parentheses + \ 'aB' :1, " Support nesting of 'around' braces + \ 'ii' :0, " 'inside indent'. Available through https://github.com/kana/vim-textobj-indent + \ 'ai' :0, " 'around indent'. Available through https://github.com/kana/vim-textobj-indent + \ }) +``` + +You can further customize the text objects dictionary on a per filetype basis by defining global variables like ```g:expand_region_text_objects_{ft}```. + +```vim +" Use the following setting for ruby. (NOTE: Remove comments in dictionary before sourcing) +let g:expand_region_text_objects_ruby = { + \ 'im' :0, " 'inner method'. Available through https://github.com/vim-ruby/vim-ruby + \ 'am' :0, " 'around method'. Available through https://github.com/vim-ruby/vim-ruby + \ } +``` + +Note that this completely replaces the default dictionary. To extend the default on a per filetype basis, you can call ```expand_region#custom_text_objects``` by passing in the filetype in the first argument: + +```vim +" Use the global default + the following for ruby +call expand_region#custom_text_objects('ruby', { + \ 'im' :0, + \ 'am' :0, + \ }) +``` + +### Customize selection mode +By default, after an expansion, the plugin leaves you in visual mode. If your ```selectmode```(h:selectmode)) contains ```cmd```, then the plugin will respect that setting and leave you in select mode. If you don't have ```selectmode``` set, but would like to default the expansion in select mode, you can use the global setting below: + +```vim +let g:expand_region_use_select_mode = 1 +``` + +[vim-expand-region]:http://github.com/terryma/vim-expand-region +[Pathogen]:http://github.com/tpope/vim-pathogen +[Vundle]:http://github.com/gmarik/vundle +[Neobundle]:http://github.com/Shougo/neobundle.vim diff --git a/sources_non_forked/vim-expand-region/autoload/expand_region.vim b/sources_non_forked/vim-expand-region/autoload/expand_region.vim new file mode 100755 index 00000000..3bf2f70a --- /dev/null +++ b/sources_non_forked/vim-expand-region/autoload/expand_region.vim @@ -0,0 +1,350 @@ +" ============================================================================== +" File: expand_region.vim +" Author: Terry Ma +" Last Modified: March 30, 2013 +" ============================================================================== + +let s:save_cpo = &cpo +set cpo&vim + +" ============================================================================== +" Settings +" ============================================================================== + +" Init global vars +function! expand_region#init() + if exists('g:expand_region_init') && g:expand_region_init + return + endif + let g:expand_region_init = 1 + + " Dictionary of text objects that are supported by default. Note that some of + " the text objects are not available in vanilla vim. '1' indicates that the + " text object is recursive (think of nested parens or brackets) + let g:expand_region_text_objects = get(g:, 'expand_region_text_objects', { + \ 'iw' :0, + \ 'iW' :0, + \ 'i"' :0, + \ 'i''' :0, + \ 'i]' :1, + \ 'ib' :1, + \ 'iB' :1, + \ 'il' :0, + \ 'ip' :0, + \ 'ie' :0, + \}) + + " Option to default to the select mode when selecting a new region + let g:expand_region_use_select_mode = get(g:, 'expand_region_use_select_mode', 0) +endfunction +call expand_region#init() + +" ============================================================================== +" Global Functions +" ============================================================================== + +" Allow user to customize the global dictionary, or the per file type dictionary +function! expand_region#custom_text_objects(...) + if a:0 == 1 + call extend(g:expand_region_text_objects, a:1) + elseif a:0 == 2 + if !exists("g:expand_region_text_objects_".a:1) + let g:expand_region_text_objects_{a:1} = {} + call extend(g:expand_region_text_objects_{a:1}, g:expand_region_text_objects) + endif + call extend(g:expand_region_text_objects_{a:1}, a:2) + endif +endfunction + +" Returns whether we should perform the region highlighting use visual mode or +" select mode +function! expand_region#use_select_mode() + return g:expand_region_use_select_mode || index(split(s:saved_selectmode, ','), 'cmd') != -1 +endfunction + +" Main function +function! expand_region#next(mode, direction) + call s:expand_region(a:mode, a:direction) +endfunction + +" ============================================================================== +" Variables +" ============================================================================== + +" The saved cursor position when user initiates expand. This is the position we +" use to calcuate the region for all of our text objects. This is also used to +" restore the original cursor position when the region is completely shrinked. +let s:saved_pos = [] + +" Index into the list of filtered text objects(s:candidates), the text object +" this points to is the currently selected region. +let s:cur_index = -1 + +" The list of filtered text objects used to expand/shrink the visual selection. +" This is computed when expand-region is called the first time. +" Each item is a dictionary containing the following: +" text_object: The actual text object string +" start_pos: The result of getpos() on the starting position of the text object +" end_pos: The result of getpos() on the ending position of the text object +" length: The number of characters for the text object +let s:candidates = [] + +" This is used to save the user's selectmode setting. If the user's selectmode +" contains 'cmd', then our expansion should result in the region selected under +" select mode. +let s:saved_selectmode = &selectmode + +" ============================================================================== +" Functions +" ============================================================================== + +" Sort the text object by length in ascending order +function! s:sort_text_object(l, r) + return a:l.length - a:r.length +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 + +" Boundary check on the cursor position to make sure it's inside the text object +" region. Return 1 if the cursor is within range, 0 otherwise. +function! s:is_cursor_inside(pos, region) + if s:compare_pos(a:pos, a:region.start_pos) < 0 + return 0 + endif + if s:compare_pos(a:pos, a:region.end_pos) > 0 + return 0 + endif + return 1 +endfunction + +" Remove duplicates from the candidate list. Two candidates are duplicates if +" they cover the exact same region (same length and same starting position) +function! s:remove_duplicate(input) + let i = len(a:input) - 1 + while i >= 1 + if a:input[i].length ==# a:input[i-1].length && + \ a:input[i].start_pos ==# a:input[i-1].start_pos + call remove(a:input, i) + endif + let i-=1 + endwhile +endfunction + +" Return a single candidate dictionary. Each dictionary contains the following: +" text_object: The actual text object string +" start_pos: The result of getpos() on the starting position of the text object +" end_pos: The result of getpos() on the ending position of the text object +" length: The number of characters for the text object +function! s:get_candidate_dict(text_object) + " Store the current view so we can restore it at the end + let winview = winsaveview() + + " Use ! as much as possible + exec 'normal! v' + exec 'silent! normal '.a:text_object + " The double quote is important + exec "normal! \" + + let selection = s:get_visual_selection() + let ret = { + \ "text_object": a:text_object, + \ "start_pos": selection.start_pos, + \ "end_pos": selection.end_pos, + \ "length": selection.length, + \} + + " Restore peace + call winrestview(winview) + return ret +endfunction + + +" Return dictionary of text objects that are to be used for the current +" filetype. Filetype-specific dictionaries will be loaded if they exist +" and the global dictionary will be used as a fallback. +function! s:get_configuration() + let configuration = {} + for ft in split(&ft, '\.') + if exists("g:expand_region_text_objects_".ft) + call extend(configuration, g:expand_region_text_objects_{ft}) + endif + endfor + + if empty(configuration) + call extend(configuration, g:expand_region_text_objects) + endif + + return configuration +endfunction + +" Return list of candidate dictionary. Each dictionary contains the following: +" text_object: The actual text object string +" start_pos: The result of getpos() on the starting position of the text object +" length: The number of characters for the text object +function! s:get_candidate_list() + " Turn off wrap to allow recursive search to work without triggering errors + let save_wrapscan = &wrapscan + set nowrapscan + + let config = s:get_configuration() + + " Generate the candidate list for every defined text object + let candidates = keys(config) + call map(candidates, "s:get_candidate_dict(v:val)") + + " For the ones that are recursive, generate them until they no longer match + " any region + let recursive_candidates = [] + for i in candidates + " Continue if not recursive + if !config[i.text_object] + continue + endif + " If the first level is already empty, no point in going any further + if i.length ==# 0 + continue + endif + let l:count = 2 + let previous = i.length + while 1 + let test = l:count.i.text_object + let candidate = s:get_candidate_dict(test) + if candidate.length ==# 0 + break + endif + " If we're not producing larger regions, end early + if candidate.length ==# previous + break + endif + call add(recursive_candidates, candidate) + let l:count+=1 + let previous = candidate.length + endwhile + endfor + + " Restore wrapscan + let &wrapscan = save_wrapscan + + return extend(candidates, recursive_candidates) +endfunction + +" Return a dictionary containing the start position, end position and length of +" the current visual selection. +function! s:get_visual_selection() + 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 { + \ 'start_pos': start_pos, + \ 'end_pos': end_pos, + \ 'length': len(join(lines, "\n")) + \} +endfunction + +" Figure out whether we should compute the candidate text objects, or we're in +" the middle of an expand/shrink. +function! s:should_compute_candidates(mode) + if a:mode ==# 'v' + " Check that current visual selection is idential to our last expanded + " region + if s:cur_index >= 0 + let selection = s:get_visual_selection() + if s:candidates[s:cur_index].start_pos ==# selection.start_pos + \ && s:candidates[s:cur_index].length ==# selection.length + return 0 + endif + endif + endif + return 1 +endfunction + +" Computes the list of text object candidates to be used given the current +" cursor position. +function! s:compute_candidates(cursor_pos) + " Reset index into the candidates list + let s:cur_index = -1 + + " Save the current cursor position so we can restore it later + let s:saved_pos = a:cursor_pos + + " Compute a list of candidate regions + let s:candidates = s:get_candidate_list() + + " Sort them and remove the ones with 0 or 1 length + call filter(sort(s:candidates, "s:sort_text_object"), 'v:val.length > 1') + + " Filter out the ones where the cursor falls outside of its region. i" and i' + " can start after the cursor position, and ib can start before, so both checks + " are needed + call filter(s:candidates, 's:is_cursor_inside(s:saved_pos, v:val)') + + " Remove duplicates + call s:remove_duplicate(s:candidates) +endfunction + +" Perform the visual selection at the end. If the user wants to be left in +" select mode, do so +function! s:select_region() + exec 'normal! v' + exec 'normal '.s:candidates[s:cur_index].text_object + if expand_region#use_select_mode() + exec "normal! \" + endif +endfunction + +" Expand or shrink the visual selection to the next candidate in the text object +" list. +function! s:expand_region(mode, direction) + " Save the selectmode setting, and remove the setting so our 'v' command do + " not get interfered + let s:saved_selectmode = &selectmode + let &selectmode="" + + if s:should_compute_candidates(a:mode) + call s:compute_candidates(getpos('.')) + else + call setpos('.', s:saved_pos) + endif + + if a:direction ==# '+' + " Expanding + if s:cur_index ==# len(s:candidates) - 1 + normal! gv + else + let s:cur_index+=1 + " Associate the window view with the text object + let s:candidates[s:cur_index].prev_winview = winsaveview() + call s:select_region() + endif + else + "Shrinking + if s:cur_index <=# 0 + " In visual mode, doing nothing here will return us to normal mode. For + " select mode, the following is needed. + if expand_region#use_select_mode() + exec "normal! gV" + endif + else + " Restore the window view + call winrestview(s:candidates[s:cur_index].prev_winview) + let s:cur_index-=1 + call s:select_region() + endif + endif + + " Restore the selectmode setting + let &selectmode = s:saved_selectmode +endfunction + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/sources_non_forked/vim-expand-region/doc/expand_region.txt b/sources_non_forked/vim-expand-region/doc/expand_region.txt new file mode 100755 index 00000000..109dd721 --- /dev/null +++ b/sources_non_forked/vim-expand-region/doc/expand_region.txt @@ -0,0 +1,126 @@ +*vim-expand-region.txt* Incremental visual selection + + __ _ + ___ _ ______ ____ _____ ____/ / ________ ____ _(_)___ ____ + / _ \| |/_/ __ \/ __ `/ __ \/ __ / / ___/ _ \/ __ `/ / __ \/ __ \ + / __/> + + map K (expand_region_expand) + map J (expand_region_shrink) +< + +============================================================================== +4. Global Options *expand-region-global-options* + + *expand_region_text_objects* +Default: See below +Dictionary containing the text objects the plugin uses to search for the +available regions to expand/shrink to. The value corresponding to each plugin +indicates whether text object is recursive. A recursive text object is +continually expanded until the region no longer gets larger. > + + " Default settings. (NOTE: Remove comments in dictionary before sourcing) + let g:expand_region_text_objects = { + \ 'iw' :0, + \ 'iW' :0, + \ 'i"' :0, + \ 'i''' :0, + \ 'i]' :1, " Support nesting of square brackets + \ 'ib' :1, " Support nesting of parentheses + \ 'iB' :1, " Support nesting of braces + \ 'il' :0, " 'inside line'. Available through https://github.com/kana/vim-textobj-line + \ 'ip' :0, + \ 'ie' :0, " 'entire file'. Available through https://github.com/kana/vim-textobj-entire + \ } +< + +You can extend the global default dictionary by calling +'expand_region#custom_text_objects'. > + + " Extend the global default (NOTE: Remove comments in dictionary before sourcing) + call expand_region#custom_text_objects({ + \ "\/\\n\\n\": 1, " Motions are supported as well. Here's a search motion that finds a blank line + \ 'a]' :1, " Support nesting of 'around' brackets + \ 'ab' :1, " Support nesting of 'around' parentheses + \ 'aB' :1, " Support nesting of 'around' braces + \ 'ii' :0, " 'inside indent'. Available through https://github.com/kana/vim-textobj-indent + \ 'ai' :0, " 'around indent'. Available through https://github.com/kana/vim-textobj-indent + \ }) +< + +You can further customize the text objects dictionary on a per filetype basis +by defining global variables like 'g:expand_region_text_objects_{ft}'. > + + " Use the following setting for ruby. (NOTE: Remove comments in dictionary before sourcing) + let g:expand_region_text_objects_ruby = { + \ 'im' :0, " 'inner method'. Available through https://github.com/vim-ruby/vim-ruby + \ 'am' :0, " 'around method'. Available through https://github.com/vim-ruby/vim-ruby + \ } +< + +Note that this completely replaces the default dictionary. To extend the +default on a per filetype basis, you can call +'expand_region#custom_text_objects' by passing in the filetype in the first +argument: > + + " Use the global default + the following for ruby + call expand_region#custom_text_objects('ruby', { + \ 'im' :0, + \ 'am' :0, + \ }) +< + *expand_region_use_select_mode* +Default: 0 +By default, after an expansion, the plugin leaves you in visual mode. If your +'selectmode' contains "cmd", then the plugin will respect that setting and +leave you in select mode. If you don't have 'selectmode' set, but would +like to default the expansion in select mode, you can use the global setting +below: > + + let g:expand_region_use_select_mode = 1 +< + +============================================================================== +5. About *expand-region-about* +============================================================================== + +Find the latest version of the plugin here: + http://github.com/terryma/vim-expand-region + + vim:tw=78:sw=4:ft=help:norl: diff --git a/sources_non_forked/vim-expand-region/doc/tags b/sources_non_forked/vim-expand-region/doc/tags new file mode 100644 index 00000000..402a0c43 --- /dev/null +++ b/sources_non_forked/vim-expand-region/doc/tags @@ -0,0 +1,10 @@ +expand-region-about expand_region.txt /*expand-region-about* +expand-region-contents expand_region.txt /*expand-region-contents* +expand-region-global-options expand_region.txt /*expand-region-global-options* +expand-region-intro expand_region.txt /*expand-region-intro* +expand-region-mappings expand_region.txt /*expand-region-mappings* +expand-region-usage expand_region.txt /*expand-region-usage* +expand_region_text_objects expand_region.txt /*expand_region_text_objects* +expand_region_use_select_mode expand_region.txt /*expand_region_use_select_mode* +vim-expand-region.txt expand_region.txt /*vim-expand-region.txt* +vim-expand-regions expand_region.txt /*vim-expand-regions* diff --git a/sources_non_forked/vim-expand-region/expand-region.gif b/sources_non_forked/vim-expand-region/expand-region.gif new file mode 100755 index 00000000..00aa5b33 Binary files /dev/null and b/sources_non_forked/vim-expand-region/expand-region.gif differ diff --git a/sources_non_forked/vim-expand-region/plugin/expand_region.vim b/sources_non_forked/vim-expand-region/plugin/expand_region.vim new file mode 100755 index 00000000..18db51ae --- /dev/null +++ b/sources_non_forked/vim-expand-region/plugin/expand_region.vim @@ -0,0 +1,43 @@ +" ============================================================================== +" File: expand_region.vim +" Author: Terry Ma +" Description: Incrementally select larger regions of text in visual mode by +" repeating the same key combination +" Last Modified: March 30, 2013 +" ============================================================================== + +let s:save_cpo = &cpo +set cpo&vim + +" Init global vars +call expand_region#init() + +" ============================================================================== +" Mappings +" ============================================================================== +if !hasmapto('(expand_region_expand)') + nmap + (expand_region_expand) + vmap + (expand_region_expand) +endif +if !hasmapto('(expand_region_shrink)') + vmap _ (expand_region_shrink) + nmap _ (expand_region_shrink) +endif + +nnoremap (expand_region_expand) + \ :call expand_region#next('n', '+') +" Map keys differently depending on which mode is desired +if expand_region#use_select_mode() + snoremap (expand_region_expand) + \ :call expand_region#next('v', '+') + snoremap (expand_region_shrink) + \ :call expand_region#next('v', '-') +else + xnoremap (expand_region_expand) + \ :call expand_region#next('v', '+') + xnoremap (expand_region_shrink) + \ :call expand_region#next('v', '-') +endif + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/sources_non_forked/vim-multiple-cursors/MIT-LICENSE.txt b/sources_non_forked/vim-multiple-cursors/MIT-LICENSE.txt new file mode 100755 index 00000000..dade7aa4 --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/MIT-LICENSE.txt @@ -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. diff --git a/sources_non_forked/vim-multiple-cursors/README.md b/sources_non_forked/vim-multiple-cursors/README.md new file mode 100755 index 00000000..b38c311a --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/README.md @@ -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 +![Example1](assets/example1.gif?raw=true) + +### Add a cursor to each line of your visual selection +![Example2](assets/example2.gif?raw=true) + +### Do it backwards too! This is not just a replay of the above gif :) +![Example3](assets/example3.gif?raw=true) + +## 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 `` 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="\" +let g:multi_cursor_prev_key="\" +let g:multi_cursor_skip_key="\" +let g:multi_cursor_exit_key="\" +``` + +## 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 diff --git a/sources_non_forked/vim-multiple-cursors/assets/example1.gif b/sources_non_forked/vim-multiple-cursors/assets/example1.gif new file mode 100755 index 00000000..f191985a Binary files /dev/null and b/sources_non_forked/vim-multiple-cursors/assets/example1.gif differ diff --git a/sources_non_forked/vim-multiple-cursors/assets/example2.gif b/sources_non_forked/vim-multiple-cursors/assets/example2.gif new file mode 100755 index 00000000..df14aa3c Binary files /dev/null and b/sources_non_forked/vim-multiple-cursors/assets/example2.gif differ diff --git a/sources_non_forked/vim-multiple-cursors/assets/example3.gif b/sources_non_forked/vim-multiple-cursors/assets/example3.gif new file mode 100755 index 00000000..f4ab9876 Binary files /dev/null and b/sources_non_forked/vim-multiple-cursors/assets/example3.gif differ diff --git a/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim b/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim new file mode 100755 index 00000000..b38d3d8e --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim @@ -0,0 +1,689 @@ +"=============================================================================== +" Internal Mappings +"=============================================================================== + +inoremap (multi_cursor_process_user_input) + \ :call process_user_inut('i') +nnoremap (multi_cursor_process_user_input) + \ :call process_user_inut('n') +xnoremap (multi_cursor_process_user_input) + \ :call process_user_inut('v') + +inoremap (multi_cursor_apply_user_input_next) + \ :call apply_user_input_next('i') +nnoremap (multi_cursor_apply_user_input_next) + \ :call apply_user_input_next('n') +xnoremap (multi_cursor_apply_user_input_next) + \ :call apply_user_input_next('v') + +"=============================================================================== +" 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\" + 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\ is that it allows the cursor to stay +" on where it was before exiting +function! s:exit_visual_mode() + exec "normal! \gv\" +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."\(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 = "\(multi_cursor_process_user_input)" + endif + call s:feedkeys(feedkeys) +endfunction diff --git a/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt b/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt new file mode 100755 index 00000000..75af3d45 --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt @@ -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 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: "\") +*g:multi_cursor_prev_key* (Default: "\") +*g:multi_cursor_skip_key* (Default: "\") +*g:multi_cursor_exit_key* (Default: "\") +You can map the 'next', 'previous', 'skip', and 'exit' keys like the +following: > + + " Default mapping + let g:multi_cursor_next_key="\" + let g:multi_cursor_prev_key="\" + let g:multi_cursor_skip_key="\" + let g:multi_cursor_exit_key="\" +< + +============================================================================== +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: diff --git a/sources_non_forked/vim-multiple-cursors/doc/tags b/sources_non_forked/vim-multiple-cursors/doc/tags new file mode 100644 index 00000000..97741cb1 --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/doc/tags @@ -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* diff --git a/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim b/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim new file mode 100755 index 00000000..e2273862 --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim @@ -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 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 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 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 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': "\", + \ 'next_key': "\", + \ 'prev_key': "\", + \ 'skip_key': "\", + \ } + +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 '.g:multi_cursor_next_key. + \' :call multiple_cursors#new("n")' + exec 'xnoremap '.g:multi_cursor_next_key. + \' :call multiple_cursors#new("v")' +endif +if exists('g:multi_cursor_prev_key') + exec 'xnoremap '.g:multi_cursor_prev_key. + \' :call multiple_cursors#prev()' +endif +if exists('g:multi_cursor_skip_key') + exec 'xnoremap '.g:multi_cursor_skip_key. + \' :call multiple_cursors#skip()' +endif + +let &cpo = s:save_cpo +unlet s:save_cpo diff --git a/update_plugins.py b/update_plugins.py index ce4b8917..b93bde6b 100644 --- a/update_plugins.py +++ b/update_plugins.py @@ -29,6 +29,7 @@ vim-pyte https://github.com/therubymug/vim-pyte vim-snipmate https://github.com/garbas/vim-snipmate vim-snippets https://github.com/honza/vim-snippets vim-surround https://github.com/tpope/vim-surround +vim-expand-region https://github.com/terryma/vim-expand-region """.strip() GITHUB_ZIP = '%s/archive/master.zip' diff --git a/vimrcs/plugins_config.vim b/vimrcs/plugins_config.vim index 28f257f5..a2c09717 100644 --- a/vimrcs/plugins_config.vim +++ b/vimrcs/plugins_config.vim @@ -87,6 +87,12 @@ map nb :NERDTreeFromBookmark map nf :NERDTreeFind +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" => vim-multiple-cursors +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +let g:multi_cursor_next_key="\" + + """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " => surround.vim config " Annotate strings with gettext http://amix.dk/blog/post/19678