diff --git a/sources_non_forked/nerdtree/autoload/nerdtree.vim b/sources_non_forked/nerdtree/autoload/nerdtree.vim index 3da55662..3a2d71a6 100644 --- a/sources_non_forked/nerdtree/autoload/nerdtree.vim +++ b/sources_non_forked/nerdtree/autoload/nerdtree.vim @@ -227,6 +227,19 @@ function! nerdtree#invokeKeyMap(key) call g:NERDTreeKeyMap.Invoke(a:key) endfunction +" FUNCTION: nerdtree#loadClassFiles() {{{2 +function! nerdtree#loadClassFiles() + runtime lib/nerdtree/path.vim + runtime lib/nerdtree/menu_controller.vim + runtime lib/nerdtree/menu_item.vim + runtime lib/nerdtree/key_map.vim + runtime lib/nerdtree/bookmark.vim + runtime lib/nerdtree/tree_file_node.vim + runtime lib/nerdtree/tree_dir_node.vim + runtime lib/nerdtree/opener.vim + runtime lib/nerdtree/creator.vim +endfunction + " FUNCTION: nerdtree#postSourceActions() {{{2 function! nerdtree#postSourceActions() call g:NERDTreeBookmark.CacheBookmarks(0) diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/bookmark.vim b/sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/bookmark.vim rename to sources_non_forked/nerdtree/lib/nerdtree/bookmark.vim diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/creator.vim b/sources_non_forked/nerdtree/lib/nerdtree/creator.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/creator.vim rename to sources_non_forked/nerdtree/lib/nerdtree/creator.vim diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/key_map.vim b/sources_non_forked/nerdtree/lib/nerdtree/key_map.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/key_map.vim rename to sources_non_forked/nerdtree/lib/nerdtree/key_map.vim diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/menu_controller.vim b/sources_non_forked/nerdtree/lib/nerdtree/menu_controller.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/menu_controller.vim rename to sources_non_forked/nerdtree/lib/nerdtree/menu_controller.vim diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/menu_item.vim b/sources_non_forked/nerdtree/lib/nerdtree/menu_item.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/menu_item.vim rename to sources_non_forked/nerdtree/lib/nerdtree/menu_item.vim diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/opener.vim b/sources_non_forked/nerdtree/lib/nerdtree/opener.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/opener.vim rename to sources_non_forked/nerdtree/lib/nerdtree/opener.vim diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/path.vim b/sources_non_forked/nerdtree/lib/nerdtree/path.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/path.vim rename to sources_non_forked/nerdtree/lib/nerdtree/path.vim diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/tree_dir_node.vim b/sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/tree_dir_node.vim rename to sources_non_forked/nerdtree/lib/nerdtree/tree_dir_node.vim diff --git a/sources_non_forked/nerdtree/plugin/nerdtree/tree_file_node.vim b/sources_non_forked/nerdtree/lib/nerdtree/tree_file_node.vim similarity index 100% rename from sources_non_forked/nerdtree/plugin/nerdtree/tree_file_node.vim rename to sources_non_forked/nerdtree/lib/nerdtree/tree_file_node.vim diff --git a/sources_non_forked/nerdtree/plugin/NERD_tree.vim b/sources_non_forked/nerdtree/plugin/NERD_tree.vim index 6c19a3fa..5bee03ad 100644 --- a/sources_non_forked/nerdtree/plugin/NERD_tree.vim +++ b/sources_non_forked/nerdtree/plugin/NERD_tree.vim @@ -136,15 +136,7 @@ call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U") call s:initVariable("g:NERDTreeMapCWD", "CD") "SECTION: Load class files{{{2 -runtime plugin/nerdtree/path.vim -runtime plugin/nerdtree/menu_controller.vim -runtime plugin/nerdtree/menu_item.vim -runtime plugin/nerdtree/key_map.vim -runtime plugin/nerdtree/bookmark.vim -runtime plugin/nerdtree/tree_file_node.vim -runtime plugin/nerdtree/tree_dir_node.vim -runtime plugin/nerdtree/opener.vim -runtime plugin/nerdtree/creator.vim +call nerdtree#loadClassFiles() " SECTION: Commands {{{1 "============================================================ diff --git a/sources_non_forked/vim-expand-region/MIT-LICENSE.txt b/sources_non_forked/vim-expand-region/MIT-LICENSE.txt old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-expand-region/README.md b/sources_non_forked/vim-expand-region/README.md old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-expand-region/autoload/expand_region.vim b/sources_non_forked/vim-expand-region/autoload/expand_region.vim old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-expand-region/doc/expand_region.txt b/sources_non_forked/vim-expand-region/doc/expand_region.txt old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-expand-region/expand-region.gif b/sources_non_forked/vim-expand-region/expand-region.gif old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-expand-region/plugin/expand_region.vim b/sources_non_forked/vim-expand-region/plugin/expand_region.vim old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-multiple-cursors/.rspec b/sources_non_forked/vim-multiple-cursors/.rspec new file mode 100644 index 00000000..397921fb --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/.rspec @@ -0,0 +1,2 @@ +--color +--format d diff --git a/sources_non_forked/vim-multiple-cursors/.travis.yml b/sources_non_forked/vim-multiple-cursors/.travis.yml new file mode 100644 index 00000000..e99037a9 --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/.travis.yml @@ -0,0 +1,7 @@ +language: ruby +rvm: + - 1.9.3 +before_install: sudo apt-get install vim-gtk +before_script: + - "export DISPLAY=:99.0" + - "sh -e /etc/init.d/xvfb start" diff --git a/sources_non_forked/vim-multiple-cursors/CHANGELOG.md b/sources_non_forked/vim-multiple-cursors/CHANGELOG.md new file mode 100644 index 00000000..aa8b644e --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/CHANGELOG.md @@ -0,0 +1,97 @@ +## 2.0 (04/24/2013) + +Bugfixes: + - Fix inconsistent undo behavior. Changes made in multicursor insert mode are now undone together. This fixes #22. + - Single key commands that do not terminate properly no longer cause ghostly cursors to linger on screen. An error message is now displayed informing the user the number of cursor locations that the input cannot be properly played back at. This fixes #28. + +## 1.16 (04/23/2013) + +Features: + - Add integration tests using vimrunner. Hook up travis-ci to run continous integration on commit. + +## 1.15 (04/22/2013) + +Bugfixes: + - Fix plugin causing error bell. This fixes #29. + +## 1.14 (04/22/2013) + +Features: + - Allow users to separate start key from next key. (credit: @xanderman) + +## 1.13 (04/22/2013) + +Bugfixes: + - Add support for switching to visual line mode from inside multicursor mode + - Fix highlight issue where extra character at end of line is highlighted for visual selections covering more than 2 lines. + +## 1.12 (04/19/2013) + +Bugfixes: + - Fix tab character causing highlight errors. This fixes #18 and fixes #32 + +## 1.11 (04/18/2013) + +Bugfixes: + - Fix regression where `C-n` doesn't exhibit correct behavior when all matches have been found + - Clear echo messages when a new input is received + +## 1.10 (04/17/2013) + +Bugfixes: + - `O` works now in normal mode. This fixes #24 + - Turn on `lazyredraw` during multicursor mode to prevent the sluggish screen redraws + +Features: + - Add command **MultipleCursorsFind** to add multiple virtual cursors using regexp. This closes #20 + +## 1.9 (04/17/2013) + +Bugfixes: + - Fix starting multicursor mode in visual line mode. This fixes #25 + - Major refactoring to avoid getting in and out of visual mode as much as possible + +## 1.8 (04/16/2013) + +Bugfixes: + - Fix regression that causes call stack to explode with too many cursors + +## 1.7 (04/15/2013) + +Bugfixes: + - Finally fix the annoying highlighting problem when the last virtual cursor is on the last character of the line. The solution is a hack, but it should be harmless + +## 1.6 (04/15/2013) + +Bugfixes: + - Stop chaining dictionary function calls. This fixes #10 and #11 + +## 1.5 (04/15/2013) + +Bugfixes: + - Exit Vim's visual mode before waiting for user's next input. This fixes #14 + +## 1.4 (04/14/2013) + +Bugfixes: + - Don't use clearmatches(). It clears highlighting from other plugins. This fixes #13 + +## 1.3 (04/14/2013) + +Bugfixes: + - Change mapping from using expression-quote syntax to using raw strings + +## 1.2 (04/14/2013) + +Bugfixes: + - Restore view when exiting from multicursor mode. This fixes #5 + - Remove the unnecessary user level mapping for 'prev' and 'skip' in visual mode, since we can purely detect those keys from multicursor mode + +## 1.1 (04/14/2013) + +Bugfixes: + - Stop hijacking escape key in normal mode. This fixes #1, #2, and #3 + +## 1.0 (04/13/2013) + +Initial release diff --git a/sources_non_forked/vim-multiple-cursors/Gemfile b/sources_non_forked/vim-multiple-cursors/Gemfile new file mode 100644 index 00000000..7658cb9d --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' +gem 'vimrunner' +gem 'rake' +gem 'rspec' diff --git a/sources_non_forked/vim-multiple-cursors/Gemfile.lock b/sources_non_forked/vim-multiple-cursors/Gemfile.lock new file mode 100644 index 00000000..12bf0d65 --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/Gemfile.lock @@ -0,0 +1,22 @@ +GEM + remote: https://rubygems.org/ + specs: + diff-lcs (1.2.4) + rake (10.0.4) + rspec (2.13.0) + rspec-core (~> 2.13.0) + rspec-expectations (~> 2.13.0) + rspec-mocks (~> 2.13.0) + rspec-core (2.13.1) + rspec-expectations (2.13.0) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.13.1) + vimrunner (0.3.0) + +PLATFORMS + ruby + +DEPENDENCIES + rake + rspec + vimrunner diff --git a/sources_non_forked/vim-multiple-cursors/MIT-LICENSE.txt b/sources_non_forked/vim-multiple-cursors/MIT-LICENSE.txt old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-multiple-cursors/README.md b/sources_non_forked/vim-multiple-cursors/README.md old mode 100755 new mode 100644 index b38c311a..5bf961f7 --- a/sources_non_forked/vim-multiple-cursors/README.md +++ b/sources_non_forked/vim-multiple-cursors/README.md @@ -1,4 +1,4 @@ -# vim-multiple-cursors +# vim-multiple-cursors [![Build Status](https://travis-ci.org/terryma/vim-multiple-cursors.png)](https://travis-ci.org/terryma/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. @@ -12,6 +12,11 @@ ### Do it backwards too! This is not just a replay of the above gif :) ![Example3](assets/example3.gif?raw=true) +### Add multiple cursors using regexes +![Example4](assets/example4.gif?raw=true) + +To see what keystrokes are used for the above example, see [this issue](https://github.com/terryma/vim-multiple-cursors/issues/39). + ## 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 @@ -31,31 +36,45 @@ 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. +You can also add multiple cursors using a regular expression. The command `MultipleCursorsFind` accepts a range and a pattern, and it will create a virtual cursor at the end of every match within the range. If no range is passed in, then it defaults to the entire buffer. + +**NOTE:** If at any time you have lingering cursors on screen, you can press `Ctrl-n` in Normal mode and it will remove all prior cursors before starting a new one. ## Mapping -Out of the box, `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 +Out of the box, only the single key `Ctrl-n` is mapped in regular Vim's Normal mode and Visual mode to provide the functionality mentioned above. `Ctrl-n`, `Ctrl-p`, `Ctrl-x`, and `` are mapped in the special multicursor mode once you've added at least one virtual cursor to the buffer. If you don't like the plugin taking over your favorite key bindings, you can turn off the default with ``` let g:multi_cursor_use_default_mapping=0 ``` -You can map the 'next', 'previous', 'skip', and 'exit' keys like the following: +You can then 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="\" +let g:multi_cursor_next_key='' +let g:multi_cursor_prev_key='' +let g:multi_cursor_skip_key='' +let g:multi_cursor_quit_key='' ``` +By default, the 'next' key is also used to enter multicursor mode. If you want to use a different key to start multicursor mode than for selecting the next location, do like the following: +``` +" Map start key separately from next key +let g:multi_cursor_start_key='' +``` + +**IMPORTANT:** Please note that currently only single keystrokes and special keys can be mapped. This contraint is also the reason why multikey commands such as `ciw` do not work and cause unexpected behavior in Normal mode. This means that a mapping like `n` will NOT work correctly. For a list of special keys that are supported, see `help :key-notation` + +**NOTE:** Please make sure to always map something to `g:multi_cursor_quit_key`, otherwise you'll have a tough time quitting from multicursor mode. + +**NOTE:** Prior to version 1.3, the recommended way to map the keys is using the expressoin quote syntax in Vim, using something like `"\"` or `"\"` (see h: expr-quote). After 1.3, the recommended way is to use a raw string like above. If your key mappings don't appear to work, give the new syntax a try. + ## 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. +If set to 0, then pressing `g:multi_cursor_quit_key` in _Visual_ mode will not quit and delete all existing cursors. This is useful if you want to press Escape and go back to Normal mode, and still be able to operate on all the cursors. ### ```g:multi_cursor_exit_from_insert_mode``` (Default: 1) -If set to 0, then pressing `g:multi_cursor_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. +If set to 0, then pressing `g:multi_cursor_quit_key` in _Insert_ mode will not quit and delete all existing cursors. This is useful if you want to press Escape and go back to Normal mode, and still be able to operate on all the cursors. ### 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: @@ -69,15 +88,14 @@ 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 + +## Changelog +See [CHANGELOG.md](CHANGELOG.md) ## Contributing -As one can see, there're still many issues to be resolved, patches and suggestions are always welcome! +As one can see, there're still many issues to be resolved, patches and suggestions are always welcome! A list of open feature requests can be found [here](../../issues?labels=enhancement&state=open). ## 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 @@ -88,3 +106,4 @@ Obviously inspired by Sublime Text's [multiple selection][sublime-multiple-selec [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/Rakefile b/sources_non_forked/vim-multiple-cursors/Rakefile new file mode 100644 index 00000000..70a846df --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/Rakefile @@ -0,0 +1,5 @@ +require 'rspec/core/rake_task' + +RSpec::Core::RakeTask.new(:spec) + +task :default => :spec diff --git a/sources_non_forked/vim-multiple-cursors/assets/example1.gif b/sources_non_forked/vim-multiple-cursors/assets/example1.gif old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-multiple-cursors/assets/example2.gif b/sources_non_forked/vim-multiple-cursors/assets/example2.gif old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-multiple-cursors/assets/example3.gif b/sources_non_forked/vim-multiple-cursors/assets/example3.gif old mode 100755 new mode 100644 diff --git a/sources_non_forked/vim-multiple-cursors/assets/example4.gif b/sources_non_forked/vim-multiple-cursors/assets/example4.gif new file mode 100644 index 00000000..062e0ca7 Binary files /dev/null and b/sources_non_forked/vim-multiple-cursors/assets/example4.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 old mode 100755 new mode 100644 index b38d3d8e..214ad65e --- a/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim +++ b/sources_non_forked/vim-multiple-cursors/autoload/multiple_cursors.vim @@ -1,28 +1,85 @@ +"=============================================================================== +" Initialization +"=============================================================================== + +" Tweak key settings. If the key is set using 'expr-quote' (h: expr-quote), then +" there's nothing that we need to do. If it's set using raw strings, then we +" need to convert it. We need to resort to such voodoo exec magic here to get +" it to work the way we like. '' is converted to '\' by the end and +" the global vars are replaced by their new value. This is ok since the mapping +" using '' should already have completed in the plugin file. +for key in [ 'g:multi_cursor_next_key', + \ 'g:multi_cursor_prev_key', + \ 'g:multi_cursor_skip_key', + \ 'g:multi_cursor_quit_key' ] + if exists(key) + " Translate raw strings like "" into key code like "\" + exec 'let temp = '.key + if temp =~ '^<.*>$' + exec 'let '.key.' = "\'.temp.'"' + endif + else + " If the user didn't define it, initialize it to an empty string so the + " logic later don't break + exec 'let '.key.' = ""' + endif +endfor + +" These keys will not be replicated at every cursor location. Make sure that +" this assignment happens AFTER the key tweak setting above +let s:special_keys = { + \ 'v': [ g:multi_cursor_next_key, g:multi_cursor_prev_key, g:multi_cursor_skip_key ], + \ 'n': [ g:multi_cursor_next_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' + +" Set up highlighting +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 + "=============================================================================== " 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 (i) :call process_user_inut() +nnoremap (i) :call process_user_inut() +xnoremap (i) :call process_user_inut() -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') +inoremap (a) :call apply_user_input_next('i') +nnoremap (a) :call apply_user_input_next('n') +xnoremap (a) :call apply_user_input_next('v') + +inoremap (d) :call detect_bad_input() +nnoremap (d) :call detect_bad_input() +xnoremap (d) :call detect_bad_input() + +inoremap (w) :call wait_for_user_input('') +nnoremap (w) :call wait_for_user_input('') +xnoremap (w) :call wait_for_user_input('') + +" Note that although these mappings are seemingly triggerd from Visual mode, +" they are in fact triggered from Normal mode. We quit visual mode to allow the +" virtual highlighting to take over +nnoremap (p) :call multiple_cursors#prev() +nnoremap (s) :call multiple_cursors#skip() +nnoremap (n) :call multiple_cursors#new('v') "=============================================================================== " Public Functions "=============================================================================== -" Reset everything the plugin has done -function! multiple_cursors#reset() - call s:cm.reset() +" Print some debugging info +function! multiple_cursors#debug() + call s:cm.debug() endfunction " Creates a new cursor. Different logic applies depending on the mode the user @@ -36,15 +93,15 @@ endfunction " 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() + " Reset all existing cursors, don't restore view + call s:cm.reset(0) " Select the word under cursor to set the '< and '> marks - exec "normal! viw\" - normal! gv - - call s:create_cursor_from_visual_selection() + exec "normal! viw" + call s:exit_visual_mode() + " Add cursor with the current visual selection + call s:cm.add(s:pos("'>"), s:region("'<", "'>")) 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 @@ -52,60 +109,118 @@ function! multiple_cursors#new(mode) let start = line("'<") let finish = line("'>") if start != finish - call s:cm.reset() + call s:cm.reset(0) + let col = col("'<") for line in range(line("'<"), line("'>")) - call cursor(line, col("'<")) - call s:cm.add() + let pos = [line, col] + call s:cm.add(pos) 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() + call s:cm.reset(0) + + if visualmode() ==# 'V' + let left = [line('.'), 1] + let right = [line('.'), col('$')-1] + if right[1] == 0 " empty line + return + endif + call s:cm.add(right, [left, right]) + else + call s:cm.add(s:pos("'>"), s:region("'<", "'>")) + endif 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() + let content = s:get_text(s:region("'<", "'>")) + let next = s:find_next(content) + if s:cm.add(next[1], next) + call s:update_visual_markers(next) + else + call cursor(s:cm.get_current().position) + echohl WarningMsg | echo 'No more matches' | echohl None 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 +" Delete the current cursor. If there's no more cursors, stop the loop 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() + if !s:cm.is_empty() + call s:update_visual_markers(s:cm.get_current().visual) + call cursor(s:cm.get_current().position) 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() + let content = s:get_text(s:region("'<", "'>")) + let next = s:find_next(content) + call s:cm.add(next[1], next) + call s:update_visual_markers(next) call s:wait_for_user_input('v') endfunction +" Search for pattern between the start and end line number. For each match, add +" a virtual cursor at the end and start multicursor mode +" This function is called from a command. User commands in Vim do not support +" passing in column ranges. If the user selects a block of text in visual mode, +" but not visual line mode, we only want to match patterns within the actual +" visual selection. We get around this by checking the last visual selection and +" see if its start and end lines match the input. If so, we assume that the user +" did a normal visual selection and we use the '< and '> marks to define the +" region instead of start and end from the method parameter. +function! multiple_cursors#find(start, end, pattern) + let s:cm.saved_winview = winsaveview() + let s:cm.start_from_find = 1 + if visualmode() ==# 'v' && a:start == line("'<") && a:end == line("'>") + let pos1 = s:pos("'<") + let pos2 = s:pos("'>") + else + let pos1 = [a:start, 1] + let pos2 = [a:end, col([a:end, '$'])] + endif + call cursor(pos1) + let first = 1 + while 1 + if first + " First search starts from the current position + let match = search(a:pattern, 'cW') + let first = 0 + else + let match = search(a:pattern, 'W') + endif + if !match + break + endif + let left = s:pos('.') + call search(a:pattern, 'ceW') + let right = s:pos('.') + if s:compare_pos(right, pos2) > 0 + break + endif + call s:cm.add(right, [left, right]) + " Redraw here forces the cursor movement to be updated. This prevents the + " jerky behavior when doing any action once the cursors are added. But it + " also slows down adding the cursors dramatically. We need to a better + " solution here + " redraw + endwhile + if s:cm.is_empty() + call winrestview(s:cm.saved_winview) + echohl ErrorMsg | echo 'No match found' | echohl None + return + else + echohl Normal | echo 'Added '.s:cm.size().' cursor'.(s:cm.size()>1?'s':'') | echohl None + call s:wait_for_user_input('v') + endif +endfunction + "=============================================================================== " Cursor class "=============================================================================== @@ -114,41 +229,42 @@ 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.position = copy(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], '$']) + let obj.line_length = col([a:position[0], '$']) return obj endfunction " Return the line the cursor is on function! s:Cursor.line() dict - return self.position[1] + return self.position[0] endfunction " Return the column the cursor is on function! s:Cursor.column() dict - return self.position[2] + return self.position[1] 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 + let self.position[0] += a:line + let self.position[1] += 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 + let self.visual[0][0] += a:line + let self.visual[0][1] += a:column + let self.visual[1][0] += a:line + let self.visual[1][1] += 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 + let self.position[0] = a:pos[0] + let self.position[1] = a:pos[1] call self.update_highlight() endfunction @@ -166,7 +282,7 @@ endfunction " Update the visual selection and its highlight function! s:Cursor.update_visual_selection(region) dict - let self.visual = a:region + let self.visual = deepcopy(a:region) call s:cm.remove_highlight(self.visual_hi_id) let self.visual_hi_id = s:highlight_region(a:region) endfunction @@ -187,26 +303,56 @@ let s:CursorManager = {} " Constructor function! s:CursorManager.new() let obj = copy(self) + " List of Cursors we're managing let obj.cursors = [] + " Current index into the s:cursors array let obj.current_index = -1 + " This marks the starting cursor index into the s:cursors array let obj.starting_index = -1 + " We save some user settings when the plugin loads initially let obj.saved_settings = { \ 'virtualedit': &virtualedit, \ 'cursorline': &cursorline, + \ 'lazyredraw': &lazyredraw, \ } + " We save the window view when multicursor mode is entered + let obj.saved_winview = [] + " Track whether we started multicursor mode from calling multiple_cursors#find + let obj.start_from_find = 0 return obj endfunction " Clear all cursors and their highlights -function! s:CursorManager.reset() dict - call clearmatches() +function! s:CursorManager.reset(restore_view) dict + if a:restore_view + " Return the view back to the beginning + if !empty(self.saved_winview) + call winrestview(self.saved_winview) + endif + + " If the cursor moved, just restoring the view could get confusing, let's + " put the cursor at where the user left it. Only do this if we didn't start + " from find mode + if !self.is_empty() && !self.start_from_find + call cursor(self.get(0).position) + endif + endif + + " Delete all cursors and clear their highlights. Don't do clearmatches() as + " that will potentially interfere with other plugins + if !self.is_empty() + for i in range(self.size()) + call self.remove_highlight(self.get(i).cursor_hi_id) + call self.remove_highlight(self.get(i).visual_hi_id) + endfor + endif + let self.cursors = [] let self.current_index = -1 let self.starting_index = -1 + let self.saved_winview = [] + let self.start_from_find = 0 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 @@ -238,27 +384,29 @@ function! s:CursorManager.delete_current() dict let self.current_index -= 1 endfunction -" Remove the highlighting if it matchid exists +" Remove the highlighting if its matchid exists function! s:CursorManager.remove_highlight(hi_id) dict if a:hi_id - call matchdelete(a:hi_id) + " If the user did a matchdelete or a clearmatches, we don't want to barf if + " the matchid is no longer valid + silent! 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) + echom 'cursor #'.i.': pos='.string(c.position).' visual='.string(c.visual) 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 'input = '.s:char + echom 'index = '.self.current_index + echom 'pos = '.string(s:pos('.')) + echom '''< = '.string(s:pos("'<")) + echom '''> = '.string(s:pos("'>")) + echom 'to mode = '.s:to_mode + echom 'from mode = '.s:from_mode + " echom 'special keys = '.string(s:special_keys) echom ' ' endfunction @@ -267,24 +415,34 @@ endfunction " 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() + if s:to_mode ==# 'v' || s:to_mode ==# 'V' + " If we're in visual line mode, we need to go to visual mode before we can + " update the visual region + if s:to_mode ==# 'V' + exec "normal! gvv\" + endif + + " Sets the cursor at the right place + exec "normal! gv\" + call cur.update_visual_selection(s:get_visual_region(s:pos('.'))) 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 the total number of lines changed in the buffer, we need to potentially + " adjust other cursor locations + if vdelta != 0 if self.current_index != self.size() - 1 let cur_line_length = len(getline(cur.line())) let new_line_length = len(getline('.')) for i in range(self.current_index+1, self.size()-1) let hdelta = 0 + " Note: some versions of Vim don't like chaining function calls like + " a.b().c(). For compatibility reasons, don't do it + let c = self.get(i) " 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 cur.line() == c.line() if vdelta > 0 " Added a line let hdelta = cur_line_length * -1 @@ -293,7 +451,7 @@ function! s:CursorManager.update_current() dict let hdelta = new_line_length endif endif - call self.get(i).move(vdelta, hdelta) + call c.move(vdelta, hdelta) endfor endif else @@ -306,9 +464,10 @@ function! s:CursorManager.update_current() dict " the same line if self.current_index != self.size() - 1 for i in range(self.current_index+1, self.size()-1) + let c = self.get(i) " Only do it for cursors on the same line - if cur.line() == self.get(i).line() - call self.get(i).move(0, hdelta) + if cur.line() == c.line() + call c.move(0, hdelta) else " Early exit, if we're not on the same line, neither will any cursor " that come after this @@ -319,7 +478,7 @@ function! s:CursorManager.update_current() dict endif endif - let pos = getpos('.') + let pos = s:pos('.') if cur.position == pos return 0 endif @@ -342,14 +501,21 @@ 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. +" Tweak some user settings, and save our current window view. 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 +" lazyredraw needs to be turned on to prevent jerky screen behavior with many +" cursors on screen function! s:CursorManager.initialize() dict let &virtualedit = "onemore" let &cursorline = 0 + let &lazyredraw = 1 + " We could have already saved the view from multiple_cursors#find + if !self.start_from_find + let self.saved_winview = winsaveview() + endif endfunction " Restore user settings. @@ -357,6 +523,7 @@ function! s:CursorManager.restore_user_settings() dict if !empty(self.saved_settings) let &virtualedit = self.saved_settings['virtualedit'] let &cursorline = self.saved_settings['cursorline'] + let &lazyredraw = self.saved_settings['lazyredraw'] endif endfunction @@ -365,30 +532,32 @@ 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 +" Creates a new virtual cursor as 'pos' +" Optionally a 'region' object can be passed in as second argument. If set, the +" visual region of the cursor will be set to it +" Return true if the cursor has been successfully added, false otherwise +" Mode change: Normal -> Normal +" Cursor change: None (TODO Should we set Vim's cursor to pos?) +function! s:CursorManager.add(pos, ...) 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 + if c.position == a:pos return 0 endif let i+=1 endfor - let cursor = s:Cursor.new(pos) + let cursor = s:Cursor.new(a:pos) " Save the visual selection - if mode() ==# 'v' - call cursor.update_visual_selection(s:get_current_visual_selection()) + if a:0 > 0 + call cursor.update_visual_selection(a:1) endif call add(self.cursors, cursor) @@ -403,44 +572,44 @@ endfunction " 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='' +let s:from_mode = '' " This is the mode the user is in after s:char -let s:to_mode='' +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' - +let s:saved_linecount = -1 +" This is used to apply the highlight fix. See s:apply_highight_fix() +let s:saved_line = 0 +" This is the number of cursor locations where we detected an input that we +" cannot play back +let s:bad_input = 0 " 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 "=============================================================================== +" Return the position of the input marker as a two element array. First element +" is the line number, second element is the column number +function! s:pos(mark) + let pos = getpos(a:mark) + return [pos[1], pos[2]] +endfunction + +" Return the region covered by the input markers as a two element array. First +" element is the position of the start marker, second element is the position of +" the end marker +function! s:region(start_mark, end_mark) + return [s:pos(a:start_mark), s:pos(a:end_mark)] +endfunction + " 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 +" Mode change: Normal -> Normal or Visual -> Normal +" Cursor change: If in visual mode, changed to exactly where it was on screen in +" visual mode. If in normal mode, changed to where the cursor was when the last +" visual selection ended function! s:exit_visual_mode() exec "normal! \gv\" endfunction @@ -450,30 +619,64 @@ endfunction " 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 +" Mode change: Normal -> Visual +" Cursor change: Set to end of region +" TODO: Refactor this and s:update_visual_markers +" FIXME: By using m` we're destroying the user's jumplist. We should use a +" different mark and use :keepjump function! s:select_in_visual_mode(region) - call setpos('.', a:region[0]) - call setpos("'`", a:region[1]) - if getpos('.') == getpos("'`") + if a:region[0] == a:region[1] normal! v - else + else + call cursor(a:region[1]) + normal! m` + call cursor(a:region[0]) normal! v`` endif + + " Unselect and reselect it again to properly set the '< and '> markers + exec "normal! \gv" +endfunction + +" Update '< and '> to the input region +" Mode change: Normal -> Normal +" Cursor change: Set to the end of the region +function! s:update_visual_markers(region) + if a:region[0] == a:region[1] + normal! v + else + call cursor(a:region[1]) + normal! m` + call cursor(a:region[0]) + normal! v`` + endif + call s:exit_visual_mode() +endfunction + +" Finds the next occurrence of the input text in the current buffer. +" Search is case sensitive +" Mode change: Normal -> Normal +" Cursor change: Set to the end of the match +function! s:find_next(text) + let pattern = '\V\C'.substitute(escape(a:text, '\'), '\n', '\\n', 'g') + call search(pattern) + let start = s:pos('.') + call search(pattern, 'ce') + let end = s:pos('.') + return [start, end] 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) + return matchadd(s:hi_group_cursor, '\%'.a:pos[0].'l\%'.a:pos[1].'c', 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. +" Compare two position arrays. 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] + return a:l[0] ==# a:r[0] ? a:l[1] - a:r[1] : a:l[0] - a:r[0] endfunction " Highlight the area bounded by the input region. The logic here really stinks, @@ -482,16 +685,21 @@ endfunction " 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.' + if s:to_mode ==# 'V' + let pattern = '\%>'.(s[0][0]-1).'l\%<'.(s[1][0]+1).'l.*\ze.\_$' 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' + if (s[0][0] == s[1][0]) + " Same line + let pattern = '\%'.s[0][0].'l\%>'.(s[0][1]-1).'c.*\%<'.(s[1][1]+1).'c.' + else + " Two lines + let s1 = '\%'.s[0][0].'l.\%>'.s[0][1].'c.*' + let s2 = '\%'.s[1][0].'l.*\%<'.s[1][1].'c..' + let pattern = s1.'\|'.s2 + " More than two lines + if (s[1][0] - s[0][0] > 1) + let pattern = pattern.'\|\%>'.s[0][0].'l\%<'.s[1][0].'l.*\ze.\_$' + endif endif endif return matchadd(s:hi_group_visual, pattern) @@ -502,17 +710,16 @@ function! s:revert_mode(from, to) if a:to ==# 'v' call s:cm.reapply_visual_selection() endif + if a:to ==# 'V' + call s:cm.reapply_visual_selection() + normal! V + 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 @@ -533,11 +740,11 @@ function! s:feedkeys(keys) endfunction " Take the user input and apply it at every cursor -function! s:process_user_inut(mode) +function! s:process_user_inut() " 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) + call cursor(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 @@ -550,13 +757,51 @@ function! s:process_user_inut(mode) " 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)") + " Note that it's possible that \(a) never gets called, we have a + " detection mechanism using \(d). See its documentation for more details + + " Assume that input is not valid + let s:valid_input = 0 + + " If we're coming from insert mode or going into insert mode, always chain the + " undos together. + " FIXME(terryma): Undo always places the cursor at the beginning of the line. + " Figure out why. + if s:from_mode ==# 'i' || s:to_mode ==# 'i' + silent! undojoin | call feedkeys(s:char."\(a)") + else + call feedkeys(s:char."\(a)") + endif + + " Even when s:char produces invalid input, this method is always called. The + " 't' here is important + call feedkeys("\(d)", 't') +endfunction + +" This method is always called during fanout, even when a bad user input causes +" s:apply_user_input_next to not be called. We detect that and force the method +" to be called to continue the fanout process +function! s:detect_bad_input() + if !s:valid_input + " We ignore the bad input and force invoke s:apply_user_input_next + call feedkeys("\(a)") + let s:bad_input += 1 + endif 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 + let s:valid_input = 1 + + " Save the current mode, only if we haven't already + if empty(s:to_mode) + let s:to_mode = a:mode + if s:to_mode ==# 'v' + if visualmode() ==# 'V' + let s:to_mode = 'V' + endif + endif + endif " Update the current cursor's information let changed = s:cm.update_current() @@ -565,78 +810,45 @@ function! s:apply_user_input_next(mode) call s:cm.next() " Update Vim's cursor - call setpos('.', s:cm.get_current().position) + call cursor(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() + if s:to_mode ==# 'v' || s:to_mode ==# 'V' + " This is necessary to set the "'<" and "'>" markers properly + call s:update_visual_markers(s:cm.get_current().visual) endif - call s:wait_for_user_input(s:to_mode) + call feedkeys("\(w)") else " Continue to next - call s:process_user_inut(s:from_mode) + call feedkeys("\(i)") 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 +" If pos is equal to the left side of the visual selection, the region start +" from end to start +function! s:get_visual_region(pos) + let left = s:pos("'<") + let right = s:pos("'>") + if a:pos == 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 the content of the buffer between the input region. This is used to +" find the next match in the buffer +" Mode change: Normal -> Normal +" Cursor change: None +function! s:get_text(region) + let lines = getline(a:region[0][0], a:region[1][0]) + let lines[-1] = lines[-1][:a:region[1][1] - 1] + let lines[0] = lines[0][a:region[0][1] - 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() @@ -651,39 +863,115 @@ 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() + if s:char !=# g:multi_cursor_quit_key + return 0 + endif + let exit = 0 + if s:from_mode ==# 'n' + let exit = 1 + elseif (s:from_mode ==# 'v' || s:from_mode ==# 'V') && + \ g:multi_cursor_exit_from_visual_mode + let exit = 1 + elseif s:from_mode ==# 'i' && g:multi_cursor_exit_from_insert_mode + stopinsert + let exit = 1 + endif + if exit + call s:cm.reset(1) return 1 endif return 0 endfunction -" Take users input and figure out what to do with it +" These keys don't get faned out to all cursor locations. Instead, they're used +" to add new / remove existing cursors +" Precondition: The function is only called when the keys and mode respect the +" setting in s:special_keys +function! s:handle_special_key(key, mode) + " Use feedkeys here instead of calling the function directly to prevent + " increasing the call stack, since feedkeys execute after the current call + " finishes + if a:key == g:multi_cursor_next_key + call s:feedkeys("\(n)") + elseif a:key == g:multi_cursor_prev_key + call s:feedkeys("\(p)") + elseif a:key == g:multi_cursor_skip_key + call s:feedkeys("\(s)") + endif +endfunction + +" The last line where the normal Vim cursor is always seems to highlighting +" issues if the cursor is on the last column. Vim's cursor seems to override the +" highlight of the virtual cursor. This won't happen if the virtual cursor isn't +" the last character on the line. This is a hack to add an empty space on the +" Vim cursor line right before we do the redraw, we'll revert the change +" immedidately after the redraw so the change should not be intrusive to the +" user's buffer content +function! s:apply_highlight_fix() + " Only do this if we're on the last character of the line + if col('.') == col('$') + let s:saved_line = getline('.') + if s:from_mode ==# 'i' + silent! undojoin | call setline('.', s:saved_line.' ') + else + call setline('.', s:saved_line.' ') + endif + endif +endfunction + +" Revert the fix if it was applied earlier +function! s:revert_highlight_fix() + if type(s:saved_line) == 1 + if s:from_mode ==# 'i' + silent! undojoin | call setline('.', s:saved_line) + else + call setline('.', s:saved_line) + endif + endif + let s:saved_line = 0 +endfunction + +function! s:display_error() + if s:bad_input > 0 + echohl ErrorMsg | + \ echo "Key '".s:char."' cannot be replayed at ". + \ s:bad_input." cursor location".(s:bad_input == 1 ? '' : 's') | + \ echohl Normal + endif + let s:bad_input = 0 +endfunction + function! s:wait_for_user_input(mode) let s:from_mode = a:mode + if empty(a:mode) + let s:from_mode = s:to_mode + endif let s:to_mode = '' + + call s:display_error() + + " Right before redraw, apply the highlighting bug fix + call s:apply_highlight_fix() + redraw + + " Immediately revert the change to leave the user's buffer unchanged + call s:revert_highlight_fix() + let s:char = s:get_char() - redraw + + " Clears any echoes we might've added + normal! : if s:exit() return endif - - let feedkeys = '' - if index(s:special_keys, s:char) != -1 - let feedkeys = s:char + + " If the key is a special key and we're in the right mode, handle it + if index(get(s:special_keys, s:from_mode, []), s:char) != -1 + call s:handle_special_key(s:char, s:from_mode) else call s:cm.start_loop() - let feedkeys = "\(multi_cursor_process_user_input)" + call s:feedkeys("\(i)") 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 old mode 100755 new mode 100644 index 75af3d45..dc6550bf --- a/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt +++ b/sources_non_forked/vim-multiple-cursors/doc/multiple_cursors.txt @@ -61,36 +61,68 @@ 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. +You can also add multiple cursors using a regular expression. The command +*MultipleCursorsFind* accepts a range and a pattern, and it will create a +virtual cursor at the end of every match within the range. If no range is +passed in, then it defaults to the entire buffer. + +NOTE: If at any time you have lingering cursors on screen, you can press +CTRL-N in Normal mode and it will remove all prior cursors before starting a +new one. ============================================================================== 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 > +Out of the box, only the single key CTRL-N is mapped in regular Vim's Normal +mode and Visual mode to provide the functionality mentioned above. CTRL-N, +CTRL-P, CTRL-X, and are mapped in the special multicursor mode once +you've added at least one virtual cursor to the buffer. If you don't like the +plugin taking over your favorite key bindings, you can turn off the default +with > 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: "\") +*g:multi_cursor_next_key* (Default: '') +*g:multi_cursor_prev_key* (Default: '') +*g:multi_cursor_skip_key* (Default: '') +*g:multi_cursor_quit_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="\" + let g:multi_cursor_next_key='' + let g:multi_cursor_prev_key='' + let g:multi_cursor_skip_key='' + let g:multi_cursor_quit_key='' < +*g:multi_cursor_start_key* (Default: 'g:multi_cursor_next_key') +By default, the same key is used to enter multicursor mode as to select the +next cursor location. If you want to use a different key to start multicursor +mode than for selecting the next location, do like the following: > + + " Map start key separately from next key + let g:multi_cursor_start_key='' +< + +IMPORTANT: Please note that currently only single keystroes and special +keys can be mapped. This contraint is also the reason why multikey commands +such as `ciw` do not work and cause unexpected behavior in Normal mode. This +means that a mapping like `n` will NOT work correctly. For a list of +special keys that are supported, see |key-notation| + +NOTE: Please make sure to always map something to |g:multi_cursor_quit_key|, +otherwise you'll have a tough time quitting from multicursor mode. + +NOTE: Prior to version 1.3, the recommended way to map the keys is using the +expressoin quote syntax in Vim, using something like `"\"` or `"\"` +(see h: expr-quote). After 1.3, the recommended way is to use a raw string +like above. If your key mappings don't appear to work, give the new syntax a +try. + ============================================================================== 4. Global Options *multiple-cursors-global-options* @@ -98,14 +130,14 @@ 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 +If set to 0, then pressing |g:multi_cursor_quit_key| in Visual mode will not quit and delete all existing cursors. This is useful if you want to press Escape and go back to Normal mode, and still be able to operate on all the cursors. *g:multi_cursor_exit_from_insert_mode* (Default: 1) -If set to 0, then pressing |g:multi_cursor_exit_key| in Insert mode will not +If set to 0, then pressing |g:multi_cursor_quit_key| in Insert mode will not quit and delete all existing cursors. This is useful if you want to press Escape and go back to Normal mode, and still be able to operate on all the cursors. @@ -128,15 +160,8 @@ like the following in your vimrc: > 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* diff --git a/sources_non_forked/vim-multiple-cursors/doc/tags b/sources_non_forked/vim-multiple-cursors/doc/tags index 97741cb1..5efd6085 100644 --- a/sources_non_forked/vim-multiple-cursors/doc/tags +++ b/sources_non_forked/vim-multiple-cursors/doc/tags @@ -1,9 +1,11 @@ +MultipleCursorsFind multiple_cursors.txt /*MultipleCursorsFind* g:multi_cursor_exit_from_insert_mode multiple_cursors.txt /*g:multi_cursor_exit_from_insert_mode* g:multi_cursor_exit_from_visual_mode multiple_cursors.txt /*g:multi_cursor_exit_from_visual_mode* -g:multi_cursor_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_quit_key multiple_cursors.txt /*g:multi_cursor_quit_key* g:multi_cursor_skip_key multiple_cursors.txt /*g:multi_cursor_skip_key* +g:multi_cursor_start_key multiple_cursors.txt /*g:multi_cursor_start_key* g:multi_cursor_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* diff --git a/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim b/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim old mode 100755 new mode 100644 index e2273862..7f6cfffb --- a/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim +++ b/sources_non_forked/vim-multiple-cursors/plugin/multiple_cursors.vim @@ -2,45 +2,11 @@ " 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 @@ -67,10 +33,10 @@ let s:settings = { \ } let s:settings_if_default = { - \ 'quit_key': "\", - \ 'next_key': "\", - \ 'prev_key': "\", - \ 'skip_key': "\", + \ 'quit_key': '', + \ 'next_key': '', + \ 'prev_key': '', + \ 'skip_key': '', \ } call s:init_settings(s:settings) @@ -79,21 +45,21 @@ if g:multi_cursor_use_default_mapping call s:init_settings(s:settings_if_default) endif +if !exists('g:multi_cursor_start_key') && exists('g:multi_cursor_next_key') + let g:multi_cursor_start_key = g:multi_cursor_next_key +endif + " External mappings -if exists('g:multi_cursor_next_key') - exec 'nnoremap '.g:multi_cursor_next_key. +if exists('g:multi_cursor_start_key') + exec 'nnoremap '.g:multi_cursor_start_key. \' :call multiple_cursors#new("n")' - exec 'xnoremap '.g:multi_cursor_next_key. + exec 'xnoremap '.g:multi_cursor_start_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 + +" Commands +command! -nargs=1 -range=% MultipleCursorsFind + \ call multiple_cursors#find(, , ) let &cpo = s:save_cpo unlet s:save_cpo diff --git a/sources_non_forked/vim-multiple-cursors/spec/multiple_cursors_spec.rb b/sources_non_forked/vim-multiple-cursors/spec/multiple_cursors_spec.rb new file mode 100644 index 00000000..4ea5a4f9 --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/spec/multiple_cursors_spec.rb @@ -0,0 +1,259 @@ +require 'spec_helper' + +def set_file_content(string) + string = normalize_string_indent(string) + File.open(filename, 'w'){ |f| f.write(string) } + vim.edit filename +end + +def get_file_content() + vim.write + IO.read(filename).strip +end + +def before(string) + set_file_content(string) +end + +def after(string) + get_file_content().should eq normalize_string_indent(string) +end + +def type(string) + string.scan(/<.*?>|./).each do |key| + if /<.*>/.match(key) + vim.feedkeys "\\#{key}" + else + vim.feedkeys key + end + end +end + +describe "Multiple Cursors" do + let(:filename) { 'test.txt' } + + specify "#multiline replacement" do + before <<-EOF + hello + hello + hello + EOF + + type 'cworld' + + after <<-EOF + world + world + world + EOF + end + + specify "#single line replacement" do + before <<-EOF + hello hello hello + EOF + + type 'cworld' + + after <<-EOF + world world world + EOF + end + + specify "#mixed line replacement" do + before <<-EOF + hello hello + hello + EOF + + type 'cworld' + + after <<-EOF + world world + world + EOF + end + + specify "#new line in insert mode" do + before <<-EOF + hello + hello + EOF + + type 'chelloworld' + + after <<-EOF + hello + world + hello + world + EOF + end + + specify "#new line in insert mode middle of line" do + before <<-EOF + hello world + hello world + EOF + + type 'vlxi' + + after <<-EOF + hello + world + hello + world + EOF + end + + specify "#normal mode 'o'" do + before <<-EOF + hello + hello + EOF + + type 'voworld' + + after <<-EOF + hello + world + hello + world + EOF + end + + specify "#normal mode 'O'" do + before <<-EOF + hello + hello + EOF + + type 'vOworld' + + after <<-EOF + world + hello + world + hello + EOF + end + + specify "#find command basic" do + before <<-EOF + hello + hello + EOF + + vim.normal ':MultipleCursorsFind hello' + type 'cworld' + + after <<-EOF + world + world + EOF + end + + specify "#visual line mode replacement" do + before <<-EOF + hello world + hello world + EOF + + type 'Vchi!' + + after <<-EOF + hi! + hi! + EOF + end + + specify "#skip key" do + before <<-EOF + hello + hello + hello + EOF + + type 'cworld' + + after <<-EOF + world + hello + world + EOF + end + + specify "#prev key" do + before <<-EOF + hello + hello + hello + EOF + + type 'cworld' + + after <<-EOF + world + world + hello + EOF + end + + specify "#normal mode 'I'" do + before <<-EOF + hello + hello + EOF + + type 'vIworld ' + + after <<-EOF + world hello + world hello + EOF + end + + specify "#normal mode 'A'" do + before <<-EOF + hello + hello + EOF + + type 'vA world' + + after <<-EOF + hello world + hello world + EOF + end + + specify "#undo" do + before <<-EOF + hello + hello + EOF + + type 'cworldu' + + after <<-EOF + hello + hello + EOF + end + + # 'd' is an operator pending command, which are not supported at the moment. + # This should result in a nop, but we should still remain in multicursor mode. + specify "#normal mode 'd'" do + before <<-EOF + hello + hello + EOF + + type 'vdx' + + after <<-EOF + hell + hell + EOF + end +end diff --git a/sources_non_forked/vim-multiple-cursors/spec/spec_helper.rb b/sources_non_forked/vim-multiple-cursors/spec/spec_helper.rb new file mode 100644 index 00000000..d5a4233c --- /dev/null +++ b/sources_non_forked/vim-multiple-cursors/spec/spec_helper.rb @@ -0,0 +1,25 @@ +require 'vimrunner' +require 'vimrunner/rspec' + +Vimrunner::RSpec.configure do |config| + + # Use a single Vim instance for the test suite. Set to false to use an + # instance per test (slower, but can be easier to manage). + config.reuse_server = true + + # Decide how to start a Vim instance. In this block, an instance should be + # spawned and set up with anything project-specific. + config.start_vim do + # vim = Vimrunner.start + + # Or, start a GUI instance: + vim = Vimrunner.start_gvim + + # Setup your plugin in the Vim instance + plugin_path = File.expand_path('../..', __FILE__) + vim.add_plugin(plugin_path, 'plugin/multiple_cursors.vim') + + # The returned value is the Client available in the tests. + vim + end +end diff --git a/sources_non_forked/vim-snipmate/README.rst b/sources_non_forked/vim-snipmate/README.rst index 26916e6e..e848fd25 100644 --- a/sources_non_forked/vim-snipmate/README.rst +++ b/sources_non_forked/vim-snipmate/README.rst @@ -14,7 +14,7 @@ In other words: upstream of snipmate is almost dead. (Better to say Marc Weber i :Author: `Michael Sanders`_ :Maintainer: `Adnan Zafar`_ & `Rok Garbas`_ & `Marc Weber`_ :Homepage: http://www.vim.org/scripts/script.php?script_id=2540 -:Contributors: `MarcWeber`_, `lilydjwg`_, `henrik`_, `steveno`_, `asymmetric`_, `jherdman`_, `ironcamel`_, `honza`_, `jb55`_, `robhudson`_, `kozo2`_, `MicahElliott`_, `darkwise`_, `redpill`_, `thisgeek`_, `sickill`_, `pose`_, `marutanm`_, `r00k`_, `jbernard`_, `holizz`_, `muffinresearch`_, `statik`_, `taq`_, `alderz`_, `pielgrzym`_ +:Contributors: `MarcWeber`_, `lilydjwg`_, `henrik`_, `steveno`_, `asymmetric`_, `jherdman`_, `ironcamel`_, `honza`_, `jb55`_, `robhudson`_, `kozo2`_, `MicahElliott`_, `darkwise`_, `redpill`_, `thisgeek`_, `sickill`_, `pose`_, `marutanm`_, `r00k`_, `jbernard`_, `holizz`_, `muffinresearch`_, `statik`_, `taq`_, `alderz`_, `radicalbit`_, `pielgrzym`_ .. contents:: @@ -254,3 +254,4 @@ TODO / Future .. _`taq`: https://github.com/taq .. _`vim.org`: http://www.vim.org/scripts/script.php?script_id=2540 .. _`GitHub`: http://github.com/msanders/snipmate.vim +.. _`radicalbit`: https://github.com/radicalbit diff --git a/sources_non_forked/vim-snipmate/after/plugin/snipMate.vim b/sources_non_forked/vim-snipmate/after/plugin/snipMate.vim index 76460826..668b2241 100644 --- a/sources_non_forked/vim-snipmate/after/plugin/snipMate.vim +++ b/sources_non_forked/vim-snipmate/after/plugin/snipMate.vim @@ -1,54 +1,51 @@ -" These are the mappings for snipMate.vim. Putting it here ensures that it -" will be mapped after other plugins such as supertab.vim. -if !exists('loaded_snips') || exists('s:did_snips_mappings') - finish -endif -let s:did_snips_mappings = 1 -" save and reset 'cpo' +" snipMate maps +" These maps are created here in order to make sure we can reliably create maps +" after SuperTab. + let s:save_cpo = &cpo set cpo&vim -" This is put here in the 'after' directory in order for snipMate to override -" other plugin mappings (e.g., supertab). -" -" To adjust the tirgger key see (:h snipMate-trigger) -" -if !exists('g:snips_trigger_key') - let g:snips_trigger_key = '' +function! s:map_if_not_mapped(lhs, rhs, mode) + let l:unique = s:overwrite ? '' : ' ' + if !hasmapto(a:rhs, a:mode) + silent! exe a:mode . 'map' . l:unique a:lhs a:rhs + endif +endfunction + +if !exists('g:snips_no_mappings') || !g:snips_no_mappings + if exists('g:snips_trigger_key') + echom 'g:snips_trigger_key is deprecated. See :h snipMate-mappings' + exec 'imap ' g:snips_trigger_key 'snipMateTrigger' + exec 'smap ' g:snips_trigger_key 'snipMateSNext' + exec 'xmap ' g:snips_trigger_key 'snipMateVisual' + else + " Remove SuperTab map if it exists + let s:overwrite = maparg('', 'i') ==? 'SuperTabForward' + call s:map_if_not_mapped('', 'snipMateNextOrTrigger', 'i') + call s:map_if_not_mapped('', 'snipMateNextOrTrigger', 's') + let s:overwrite = 0 + call s:map_if_not_mapped('', 'snipMateVisual', 'x') + endif + + if exists('g:snips_trigger_key_backwards') + echom 'g:snips_trigger_key_backwards is deprecated. See :h snipMate-mappings' + exec 'imap ' g:snips_trigger_key_backwards 'snipMateIBack' + exec 'smap ' g:snips_trigger_key_backwards 'snipMateSBack' + else + let s:overwrite = maparg('', 'i') ==? 'SuperTabBackward' + call s:map_if_not_mapped('', 'snipMateBack', 'i') + call s:map_if_not_mapped('', 'snipMateBack', 's') + let s:overwrite = 0 + endif + + call s:map_if_not_mapped('', 'snipMateShow', 'i') endif -if !exists('g:snips_trigger_key_backwards') - let g:snips_trigger_key_backwards = ']', '', 'g') . '>' -endif +" FIXME: Without this map, in select mode deletes the current selection and +" returns to normal mode. This doesn't update placeholders. Ideally there's some +" way to update the placeholders without this otherwise useless map. +silent! snoremap b -exec 'ino ' . g:snips_trigger_key . ' =snipMate#TriggerSnippet()' -exec 'snor ' . g:snips_trigger_key . ' i=snipMate#TriggerSnippet()' -exec 'ino ' . g:snips_trigger_key_backwards . ' =snipMate#BackwardsSnippet()' -exec 'snor ' . g:snips_trigger_key_backwards . ' i=snipMate#BackwardsSnippet()' -exec 'ino ' . g:snips_trigger_key . ' =snipMate#ShowAvailableSnips()' - -" maybe there is a better way without polluting registers ? -exec 'xnoremap ' . g:snips_trigger_key. ' s:letg:snipmate_content_visual=getreg('1')' - -" The default mappings for these are annoying & sometimes break snipMate. -" You can change them back if you want, I've put them here for convenience. -snor b -snor a -snor bi -snor ' b' -snor ` b` -snor % b% -snor U bU -snor ^ b^ -snor \ b\ -snor b - -" By default load snippets in snippets_dir -if empty(snippets_dir) - finish -endif - -" restore 'cpo' let &cpo = s:save_cpo -" vim:noet:sw=4:ts=4:ft=vim +" vim:noet: diff --git a/sources_non_forked/vim-snipmate/autoload/snipMate.vim b/sources_non_forked/vim-snipmate/autoload/snipMate.vim index db254c30..03329874 100644 --- a/sources_non_forked/vim-snipmate/autoload/snipMate.vim +++ b/sources_non_forked/vim-snipmate/autoload/snipMate.vim @@ -339,7 +339,6 @@ function! s:state_proto.update_vars(change) let newWord = strpart(getline('.'), self.start_col - 1, newWordLen) let changeLen = a:change let curLine = line('.') - let startCol = col('.') let oldStartSnip = self.start_col let updateTabStops = changeLen != 0 let i = 0 @@ -370,6 +369,12 @@ function! s:state_proto.update_vars(change) " subtract another -1 to exclude the col'th element call setline(lnum, theline[0:(col-2)] . newWord . theline[(col+self.end_col-self.start_col-a:change-1):]) endfor + + " Reposition the cursor in case a var updates on the same line but before + " the current tabstop + if oldStartSnip != self.start_col + call cursor(0, col('.') + self.start_col - oldStartSnip) + endif endfunction " should be moved to utils or such? diff --git a/sources_non_forked/vim-snipmate/doc/snipMate.txt b/sources_non_forked/vim-snipmate/doc/snipMate.txt index ced9d55f..c79e6679 100644 --- a/sources_non_forked/vim-snipmate/doc/snipMate.txt +++ b/sources_non_forked/vim-snipmate/doc/snipMate.txt @@ -356,18 +356,28 @@ If you would like your snippets to be expanded using spaces instead of tabs, just enable 'expandtab' and set 'softtabstop' to your preferred amount of spaces. If 'softtabstop' is not set, 'shiftwidth' is used instead. - *snipMate-trigger* -snipMate comes with a setting to configure the key that is used to trigger -snipMate. To configure the key set g:snips_trigger_key to something other than -,e.g. use: + *snipMate-mappings* +The mappings snipMate uses can be customized with the |:map| commands. For +example, to change the key that triggers snippets and moves to the next +tabstop, > - let g:snips_trigger_key='' + :imap snipMateNextOrTrigger + :smap snipMateNextOrTrigger +< +The list of possible mappings is as follows: -snipMate will try to automatically configure backwards trigger to prepend shift -key infront, e.g. or . You can manually configure backward -trigger using: +snipMateNextOrTrigger Jumps to the next tab stop or, if none exists, + try to expand a snippet. Use in both insert + and select modes. - let g:snips_trigger_key_backwards='' +snipMateBack Jump to the previous tab stop, if it exists. + Use in both insert and select modes. + +snipMateShow Show all available snippets (that start with + the previous text, if it exists). Use in + insert mode. + +snipMateVisual |snipMate-visual-selection-support| ============================================================================== FEATURES *snipMate-features* diff --git a/sources_non_forked/vim-snipmate/plugin/snipMate.vim b/sources_non_forked/vim-snipmate/plugin/snipMate.vim index 5dbe0cbc..0ae33584 100644 --- a/sources_non_forked/vim-snipmate/plugin/snipMate.vim +++ b/sources_non_forked/vim-snipmate/plugin/snipMate.vim @@ -14,6 +14,9 @@ if exists('loaded_snips') || &cp || version < 700 endif let loaded_snips = 1 if !exists('snips_author') | let snips_author = 'Me' | endif +" save and reset 'cpo' +let s:save_cpo = &cpo +set cpo&vim try call funcref#Function('') @@ -33,6 +36,14 @@ au FileType snippet setl noet nospell au BufRead,BufNewFile *.snippets set ft=snippets au FileType snippets setl noet nospell fdm=expr fde=getline(v:lnum)!~'^\\t\\\\|^$'?'>1':1 +inoremap snipMateNextOrTrigger =snipMate#TriggerSnippet() +snoremap snipMateNextOrTrigger a=snipMate#TriggerSnippet() +inoremap snipMateBack =snipMate#BackwardsSnippet() +snoremap snipMateBack a=snipMate#BackwardsSnippet() +inoremap snipMateShow =snipMate#ShowAvailableSnips() +" FIXME: snipMateVisual pollutes register(s) +xnoremap snipMateVisual s:let g:snipmate_content_visual=getreg('1') + " config which can be overridden (shared lines) if !exists('g:snipMate') let g:snipMate = {} @@ -80,4 +91,7 @@ fun! BackwardSnippet() return snipMate#BackwardsSnippet() endf +" restore 'cpo' +let &cpo = s:save_cpo + " vim:noet:sw=4:ts=4:ft=vim diff --git a/sources_non_forked/vim-snippets/README.md b/sources_non_forked/vim-snippets/README.md index 17a73739..6846edb2 100644 --- a/sources_non_forked/vim-snippets/README.md +++ b/sources_non_forked/vim-snippets/README.md @@ -5,8 +5,8 @@ Snipmate & UltiSnip Snippets This repository contains snippets files for various programming languages. -It is community-maintained and many people have contributed snippet files and other -improvements already. +It is community-maintained and many people have contributed snippet files and +other improvements already. Contents ======== @@ -82,6 +82,7 @@ to maintain snippets for a language, please get in touch. * Markdown - [honza](http://github.com/honza) * Ruby - [taq](http://github.com/taq) * PHP - [chrisyue](http://github.com/chrisyue) +* Scala - [gorodinskiy](https://github.com/gorodinskiy) Contributing notes ------------------ diff --git a/sources_non_forked/vim-snippets/UltiSnips/eruby.snippets b/sources_non_forked/vim-snippets/UltiSnips/eruby.snippets index 1fdcfc16..c6b201ea 100644 --- a/sources_non_forked/vim-snippets/UltiSnips/eruby.snippets +++ b/sources_non_forked/vim-snippets/UltiSnips/eruby.snippets @@ -14,9 +14,9 @@ def textmate_var(var, snip): lookup = dict( TM_RAILS_TEMPLATE_START_RUBY_EXPR = snip.opt('g:tm_rails_template_start_ruby_expr', '<%= '), TM_RAILS_TEMPLATE_END_RUBY_EXPR = snip.opt('g:tm_rails_template_end_ruby_expr', ' %>'), - TM_RAILS_TEMPLATE_START_RUBY_INLINE = snip.opt('g:tm_rails_template_start_ruby_inline', ' %>'), + TM_RAILS_TEMPLATE_START_RUBY_INLINE = snip.opt('g:tm_rails_template_start_ruby_inline', '<% '), TM_RAILS_TEMPLATE_END_RUBY_INLINE = snip.opt('g:tm_rails_template_end_ruby_inline', ' %>'), - TM_RAILS_TEMPLATE_END_RUBY_BLOCK = 'end' + TM_RAILS_TEMPLATE_END_RUBY_BLOCK = '<% end %>' ) snip.rv = lookup[var] diff --git a/sources_non_forked/vim-snippets/snippets/coffee.snippets b/sources_non_forked/vim-snippets/snippets/coffee.snippets index 83b77eba..11c82e7d 100644 --- a/sources_non_forked/vim-snippets/snippets/coffee.snippets +++ b/sources_non_forked/vim-snippets/snippets/coffee.snippets @@ -6,33 +6,33 @@ snippet forindo # Array comprehension snippet fora for ${1:name} in ${2:array} - ${3:// body...} + ${3:# body...} # Object comprehension snippet foro for ${1:key}, ${2:value} of ${3:object} - ${4:// body...} + ${4:# body...} # Range comprehension (inclusive) snippet forr for ${1:name} in [${2:start}..${3:finish}] - ${4:// body...} + ${4:# body...} snippet forrb for ${1:name} in [${2:start}..${3:finish}] by ${4:step} - ${5:// body...} + ${5:# body...} # Range comprehension (exclusive) snippet forrex for ${1:name} in [${2:start}...${3:finish}] - ${4:// body...} + ${4:# body...} snippet forrexb for ${1:name} in [${2:start}...${3:finish}] by ${4:step} - ${5:// body...} + ${5:# body...} # Function snippet fun (${1:args}) -> - ${2:// body...} + ${2:# body...} # Function (bound) snippet bfun (${1:args}) => - ${2:// body...} + ${2:# body...} # Class snippet cla class .. class ${1:`substitute(Filename(), '\(_\|^\)\(.\)', '\u\2', 'g')`} @@ -55,17 +55,17 @@ snippet cla class .. extends .. constructor: .. # If snippet if if ${1:condition} - ${2:// body...} + ${2:# body...} # If __ Else snippet ife if ${1:condition} - ${2:// body...} + ${2:# body...} else - ${3:// body...} + ${3:# body...} # Else if snippet elif else if ${1:condition} - ${2:// body...} + ${2:# body...} # Ternary If snippet ifte if ${1:condition} then ${2:value} else ${3:other} @@ -76,7 +76,7 @@ snippet unl snippet swi switch ${1:object} when ${2:value} - ${3:// body...} + ${3:# body...} # Log snippet log diff --git a/sources_non_forked/vim-snippets/snippets/eruby.snippets b/sources_non_forked/vim-snippets/snippets/eruby.snippets index f96ca846..592e490b 100644 --- a/sources_non_forked/vim-snippets/snippets/eruby.snippets +++ b/sources_non_forked/vim-snippets/snippets/eruby.snippets @@ -50,15 +50,15 @@ snippet cs snippet ct <%= content_tag '${1:DIV}', ${2:content}${3:,options} %> snippet ff - <% form_for @${1:model} do |f| %> + <%= form_for @${1:model} do |f| %> ${2} <% end %> snippet ffcb <%= ${1:f}.check_box :${2:attribute} %> snippet ffe <% error_messages_for :${1:model} %> - - <% form_for @${2:model} do |f| %> + + <%= form_for @${2:model} do |f| %> ${3} <% end %> snippet ffff @@ -78,7 +78,7 @@ snippet ffta snippet fftf <%= ${1:f}.text_field :${2:attribute} %> snippet fields - <% fields_for :${1:model}, @$1 do |${2:f}| %> + <%= fields_for :${1:model}, @$1 do |${2:f}| %> ${3} <% end %> snippet i18 diff --git a/sources_non_forked/vim-snippets/snippets/php.snippets b/sources_non_forked/vim-snippets/snippets/php.snippets index 513ee9b6..793c2a57 100644 --- a/sources_non_forked/vim-snippets/snippets/php.snippets +++ b/sources_non_forked/vim-snippets/snippets/php.snippets @@ -9,6 +9,18 @@ snippet +snippet ?= + +snippet ? + +snippet ?f + + ${3} + +snippet ?i + + ${2} + snippet ns namespace ${1:Foo\Bar\Baz}; ${2} @@ -16,9 +28,9 @@ snippet use use ${1:Foo\Bar\Baz}; ${2} snippet c - ${1:abstract }class ${2:`Filename()`} + class ${1:`Filename()`} { - ${3} + ${2} } snippet i interface ${1:`Filename()`} @@ -34,12 +46,12 @@ snippet f } # method snippet m - ${1:abstract }${2:protected}${3: static} function ${4:foo}(${5:array }${6:$bar}) + ${1:protected} function ${2:foo}() { - ${7} + ${3} } # setter method -snippet sm +snippet sm /** * Sets the value of ${1:foo} * @@ -92,7 +104,7 @@ snippet S $_SERVER['${1:variable}']${2} snippet SS $_SESSION['${1:variable}']${2} - + # the following are old ones snippet inc include '${1:file}';${2} @@ -193,7 +205,7 @@ snippet doc_h * @copyright ${4:$2}, `strftime('%d %B, %Y')` * @package ${5:default} */ - + # Interface snippet interface /** @@ -332,8 +344,8 @@ snippet vd snippet vdd var_dump(${1}); die(${2:}); snippet http_redirect - header ("HTTP/1.1 301 Moved Permanently"); - header ("Location: ".URL); + header ("HTTP/1.1 301 Moved Permanently"); + header ("Location: ".URL); exit(); # Getters & Setters snippet gs @@ -363,7 +375,7 @@ snippet gs snippet ags /** * ${1:description} - * + * * @${7} */ ${2:protected} $${3:foo}; @@ -382,3 +394,12 @@ snippet rett return true; snippet retf return false; +snippet am + $${1:foo} = array_map(function($${2:v}) { + ${3} + return $$2; + }, $$1); +snippet aw + array_walk($${1:foo}, function(&$${2:v}, $${3:k}) { + $$2 = ${4}; + });