Skip to content

Commit a21fe53

Browse files
committed
Add support for switching to Visual line mode in multicursor mode
This fixes #26. Also fix a highlighting issue where extra character at end of line is highlighted for visual selections covering more than 2 lines.
1 parent d5efed7 commit a21fe53

File tree

2 files changed

+62
-38
lines changed

2 files changed

+62
-38
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 1.13 (04/22/2013)
2+
3+
Bugfixes:
4+
- Add support for switching to visual line mode from inside multicursor mode
5+
- Fix highlight issue where extra character at end of line is highlighted for visual selections covering more than 2 lines.
6+
17
## 1.12 (04/19/2013)
28

39
Bugfixes:

autoload/multiple_cursors.vim

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ endif
5050
" Internal Mappings
5151
"===============================================================================
5252

53-
inoremap <silent> <Plug>(i) <C-o>:call <SID>process_user_inut('i')<CR>
54-
nnoremap <silent> <Plug>(i) :call <SID>process_user_inut('n')<CR>
55-
xnoremap <silent> <Plug>(i) :<C-u>call <SID>process_user_inut('v')<CR>
53+
inoremap <silent> <Plug>(i) <C-o>:call <SID>process_user_inut()<CR>
54+
nnoremap <silent> <Plug>(i) :call <SID>process_user_inut()<CR>
55+
xnoremap <silent> <Plug>(i) :<C-u>call <SID>process_user_inut()<CR>
5656
5757
inoremap <silent> <Plug>(a) <C-o>:call <SID>apply_user_input_next('i')<CR>
5858
nnoremap <silent> <Plug>(a) :call <SID>apply_user_input_next('n')<CR>
@@ -347,11 +347,6 @@ function! s:CursorManager.reset(restore_view) dict
347347
let self.saved_winview = []
348348
let self.start_from_find = 0
349349
call self.restore_user_settings()
350-
351-
" FIXME(terryma): Doesn't belong here
352-
let s:from_mode = ''
353-
let s:to_mode = ''
354-
let s:visualmode = ''
355350
endfunction
356351

357352
" Returns 0 if it's not managing any cursors at the moment
@@ -405,7 +400,6 @@ function! s:CursorManager.debug() dict
405400
echom '''> = '.string(s:pos("'>"))
406401
echom 'to mode = '.s:to_mode
407402
echom 'from mode = '.s:from_mode
408-
echom 'visual mode = '.s:visualmode
409403
" echom 'special keys = '.string(s:special_keys)
410404
echom ' '
411405
endfunction
@@ -415,7 +409,13 @@ endfunction
415409
" position changed, false otherwise
416410
function! s:CursorManager.update_current() dict
417411
let cur = self.get_current()
418-
if s:to_mode ==# 'v'
412+
if s:to_mode ==# 'v' || s:to_mode ==# 'V'
413+
" If we're in visual line mode, we need to go to visual mode before we can
414+
" update the visual region
415+
if s:to_mode ==# 'V'
416+
normal! gvv
417+
endif
418+
419419
" Sets the cursor at the right place
420420
call s:exit_visual_mode()
421421
call cur.update_visual_selection(s:get_visual_region(s:pos('.')))
@@ -569,8 +569,6 @@ let s:char = ''
569569
let s:from_mode = ''
570570
" This is the mode the user is in after s:char
571571
let s:to_mode = ''
572-
" If s:to_mode is 'v', this tells us what kind of visual mode the user was in
573-
let s:visualmode = ''
574572
" This is the total number of lines in the buffer before processing s:char
575573
let s:saved_linecount = -1
576574
" This is used to apply the highlight fix. See s:apply_highight_fix()
@@ -678,17 +676,21 @@ endfunction
678676
" multiple places.
679677
function! s:highlight_region(region)
680678
let s = sort(copy(a:region), "s:compare_pos")
681-
if (s[0][0] == s[1][0])
682-
" Same line
683-
let pattern = '\%'.s[0][0].'l\%>'.(s[0][1]-1).'c.*\%<'.(s[1][1]+1).'c.'
679+
if s:to_mode ==# 'V'
680+
let pattern = '\%>'.(s[0][0]-1).'l\%<'.(s[1][0]+1).'l.*\ze.\_$'
684681
else
685-
" Two lines
686-
let s1 = '\%'.s[0][0].'l.\%>'.s[0][1].'c.*'
687-
let s2 = '\%'.s[1][0].'l.*\%<'.s[1][1].'c..'
688-
let pattern = s1.'\|'.s2
689-
" More than two lines
690-
if (s[1][0] - s[0][0] > 1)
691-
let pattern = pattern.'\|\%>'.s[0][0].'l\%<'.s[1][0].'l'
682+
if (s[0][0] == s[1][0])
683+
" Same line
684+
let pattern = '\%'.s[0][0].'l\%>'.(s[0][1]-1).'c.*\%<'.(s[1][1]+1).'c.'
685+
else
686+
" Two lines
687+
let s1 = '\%'.s[0][0].'l.\%>'.s[0][1].'c.*'
688+
let s2 = '\%'.s[1][0].'l.*\%<'.s[1][1].'c..'
689+
let pattern = s1.'\|'.s2
690+
" More than two lines
691+
if (s[1][0] - s[0][0] > 1)
692+
let pattern = pattern.'\|\%>'.s[0][0].'l\%<'.s[1][0].'l.*\ze.\_$'
693+
endif
692694
endif
693695
endif
694696
return matchadd(s:hi_group_visual, pattern)
@@ -699,6 +701,10 @@ function! s:revert_mode(from, to)
699701
if a:to ==# 'v'
700702
call s:cm.reapply_visual_selection()
701703
endif
704+
if a:to ==# 'V'
705+
call s:cm.reapply_visual_selection()
706+
normal! V
707+
endif
702708
if a:to ==# 'i'
703709
startinsert
704710
endif
@@ -725,7 +731,7 @@ function! s:feedkeys(keys)
725731
endfunction
726732

727733
" Take the user input and apply it at every cursor
728-
function! s:process_user_inut(mode)
734+
function! s:process_user_inut()
729735
" Grr this is frustrating. In Insert mode, between the feedkey call and here,
730736
" the current position could actually CHANGE for some odd reason. Forcing a
731737
" position reset here
@@ -748,10 +754,15 @@ endfunction
748754

749755
" Apply the user input at the next cursor location
750756
function! s:apply_user_input_next(mode)
751-
" Save the current mode
752-
let s:to_mode = a:mode
753-
754-
let s:visualmode = visualmode()
757+
" Save the current mode, only if we haven't already
758+
if empty(s:to_mode)
759+
let s:to_mode = a:mode
760+
if s:to_mode ==# 'v'
761+
if visualmode() ==# 'V'
762+
let s:to_mode = 'V'
763+
endif
764+
endif
765+
endif
755766

756767
" Update the current cursor's information
757768
let changed = s:cm.update_current()
@@ -764,14 +775,14 @@ function! s:apply_user_input_next(mode)
764775

765776
" We're done if we're made the full round
766777
if s:cm.loop_done()
767-
if s:to_mode ==# 'v'
778+
if s:to_mode ==# 'v' || s:to_mode ==# 'V'
768779
" This is necessary to set the "'<" and "'>" markers properly
769780
call s:update_visual_markers(s:cm.get_current().visual)
770781
endif
771782
call s:wait_for_user_input(s:to_mode)
772783
else
773784
" Continue to next
774-
call s:process_user_inut(s:from_mode)
785+
call s:process_user_inut()
775786
endif
776787
endfunction
777788

@@ -813,15 +824,22 @@ endfunction
813824
" Quits multicursor mode and clears all cursors. Return true if exited
814825
" successfully.
815826
function! s:exit()
816-
if s:char ==# g:multi_cursor_quit_key &&
817-
\ (s:from_mode ==# 'n' ||
818-
\ s:from_mode ==# 'v' && g:multi_cursor_exit_from_visual_mode ||
819-
\ s:from_mode ==# 'i' && g:multi_cursor_exit_from_insert_mode)
820-
if s:from_mode ==# 'i'
821-
stopinsert
822-
elseif s:from_mode ==# 'v'
823-
call s:exit_visual_mode()
824-
endif
827+
if s:char !=# g:multi_cursor_quit_key
828+
return 0
829+
endif
830+
let exit = 0
831+
if s:from_mode ==# 'n'
832+
let exit = 1
833+
elseif (s:from_mode ==# 'v' || s:from_mode ==# 'V') &&
834+
\ g:multi_cursor_exit_from_visual_mode
835+
" This isn't strictly necessary, but good to do nonetheless
836+
call s:exit_visual_mode()
837+
let exit = 1
838+
elseif s:from_mode ==# 'i' && g:multi_cursor_exit_from_insert_mode
839+
stopinsert
840+
let exit = 1
841+
endif
842+
if exit
825843
call s:cm.reset(1)
826844
return 1
827845
endif

0 commit comments

Comments
 (0)