mirror of
				https://github.com/amix/vimrc
				synced 2025-11-01 07:33:34 +08:00 
			
		
		
		
	Added two new plugins: vim-expand-region and vim-multiple-cursors.
They are both super useful. Read more on their GitHub pages for more info: https://github.com/terryma/vim-expand-region https://github.com/terryma/vim-multiple-cursors
This commit is contained in:
		
							
								
								
									
										350
									
								
								sources_non_forked/vim-expand-region/autoload/expand_region.vim
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										350
									
								
								sources_non_forked/vim-expand-region/autoload/expand_region.vim
									
									
									
									
									
										Executable file
									
								
							| @ -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! \<Esc>" | ||||
|  | ||||
|   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! \<C-g>" | ||||
|   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 | ||||
		Reference in New Issue
	
	Block a user
	 amix
					amix