Skip to content

Commit

Permalink
Merge branch 'feature-keeppos'
Browse files Browse the repository at this point in the history
  • Loading branch information
haya14busa committed Apr 3, 2015
2 parents 6e6c8ba + dc082a0 commit 7f41f76
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 22 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@ asterisk.vim provides improved * motions.
### 1. stay star motions (z prefixed mappings)
z star motions doesn't move your cursor.

![](https://github.com/haya14busa/i/raw/master/vim-asterisk/asterisk_z_star.gif)
![](https://raw.githubusercontent.com/haya14busa/i/master/vim-asterisk/asterisk_z_star.gif)

### 2. visual star motions
Search selected text.

![](https://github.com/haya14busa/i/raw/master/vim-asterisk/asterisk_visual_star.gif)
![](https://raw.githubusercontent.com/haya14busa/i/master/vim-asterisk/asterisk_visual_star.gif)

### 3. Use smartcase unlike default one
Default behavior, which see ignorecase and not smartcase, is not intuitive.

### 4. Keep cursor position across matches
Keeping cursor position while itering over matches is handy for refactoring.

![](https://raw.githubusercontent.com/haya14busa/i/master/vim-asterisk/asterisk_keeppos.gif)

Tips: `nmap § ` will allow you to use asterisk as multiple cursors in a vim way

Installation
------------

Expand Down Expand Up @@ -66,6 +73,11 @@ map g* <Plug>(asterisk-gz*)
map g# <Plug>(asterisk-gz#)
```

To enable keepCursor feature:
```vim
let g:asterisk#keeppos = 1
```

Special thanks
--------------
|asterisk.vim| uses the code from vim-visualstar for visual star feature.
Expand Down
85 changes: 67 additions & 18 deletions autoload/asterisk.vim
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,19 @@ let s:FALSE = 0
let s:INT = { 'MAX': 2147483647 }
let s:DIRECTION = { 'forward': 1, 'backward': 0 } " see :h v:searchforward

let g:asterisk#keeppos = get(g:, 'asterisk#keeppos', s:FALSE)

" do_jump: do not move cursor
" is_whole: is_whole word. false if `g` flag given (e.g. * -> true, g* -> false)
let s:_config = {
\ 'direction' : s:DIRECTION.forward,
\ 'do_jump' : s:TRUE,
\ 'is_whole' : s:TRUE
\ 'is_whole' : s:TRUE,
\ 'keeppos': s:FALSE
\ }

function! s:default_config() abort
return deepcopy(s:_config)
return extend(deepcopy(s:_config), {'keeppos': g:asterisk#keeppos})
endfunction

" @return command: String
Expand All @@ -61,15 +64,43 @@ function! asterisk#do(mode, config) abort
" Including \<\> if necessary
let pattern = (is_visual ?
\ s:convert_2_word_pattern_4_visual(cword, config) : s:cword_pattern(cword, config))
let key = (config.direction is s:DIRECTION.forward ? '/' : '?')
" Get offset in current word
let offset = config.keeppos ? s:get_pos_in_cword(cword, a:mode) : 0
let pattern_offseted = pattern . (offset is 0 ? '' : key . 's+' . offset)
let search_cmd = pre . key . pattern_offseted
if config.do_jump
let key = (config.direction is s:DIRECTION.forward ? '/' : '?')
return pre . key . pattern . "\<CR>"
else
return search_cmd . "\<CR>"
elseif config.keeppos && offset isnot 0
" Do not jump with keeppos feature
let echo = printf('echo "%s"', pattern_offseted)
let restore = s:restore_pos_cmd()
"" *premove* & *aftermove* : not to cause flickr as mush as possible
" flick corner case: `#` with under cursor word at the top of window
" and the cursor is at the end of the word.
let premove = 'm`' . (config.direction is s:DIRECTION.forward ? '0' : '$')
let aftermove = "\<C-o>"
return printf("%s%s\<CR>%s:%s | %s\<CR>", premove, search_cmd, aftermove, restore, echo)
else " Do not jump: Just handle search related
call s:set_search(pattern)
return s:generate_set_search_cmd(pattern, pre, config)
endif
endfunction

"" For keeppos feature
function! asterisk#restore() abort
call winrestview(s:w)
endfunction

function! s:set_view(view) abort
let s:w = a:view
endfunction

function! s:restore_pos_cmd() abort
call s:set_view(winsaveview())
return 'call asterisk#restore()'
endfunction

" @return \<cword\>: String
function! s:cword_pattern(cword, config) abort
return printf((a:config.is_whole ? '\<%s\>' : '%s'), a:cword)
Expand Down Expand Up @@ -148,14 +179,13 @@ function! s:should_plus_one_count(cword, config, mode) abort
" cword
return s:is_visual(a:mode) ? s:FALSE
\ : a:config.direction is# s:DIRECTION.backward
\ ? s:get_pos_char() =~# '\k' && ! s:is_head_of_cword(a:cword)
\ ? s:get_pos_char() =~# '\k' && ! s:is_head_of_cword(a:cword) && ! a:config.keeppos
\ : s:get_pos_char() !~# '\k'
endfunction

" @return boolean
function! s:is_head_of_cword(cword) abort
let c = col('.')
return a:cword is# getline(line('.'))[c - 1 : c + strlen(a:cword) - 2]
return 0 == s:get_pos_in_cword(a:cword)
endfunction

" Assume the current mode is middle of visual mode.
Expand Down Expand Up @@ -196,6 +226,11 @@ function! s:get_multibyte_aware_col(pos) abort
return c + d
endfunction

function! s:get_multi_col(pos) abort
let c = col(a:pos)
return c + len(matchstr(getline(a:pos), '.', c - 1)) - 1
endfunction

" Helper:

function! s:is_visual(mode) abort
Expand All @@ -206,20 +241,33 @@ function! s:get_pos_char() abort
return getline('.')[col('.')-1]
endfunction

function! s:sort_num(xs) abort
" 7.4.341
" http://ftp.vim.org/vim/patches/7.4/7.4.341
if v:version > 704 || v:version == 704 && has('patch341')
return sort(a:xs, 'n')
else
return sort(a:xs, 's:_sort_num_func')
endif
" @return int index of cursor in cword
function! s:get_pos_in_cword(cword, ...) abort
return (s:is_visual(get(a:, 1, mode(1))) || s:get_pos_char() !~# '\k') ? 0
\ : s:count_char(searchpos(a:cword, 'bcn')[1], s:get_multi_col('.'))
endfunction

function! s:_sort_num_func(x, y) abort
return a:x - a:y
" multibyte aware
function! s:count_char(from, to) abort
let chars = getline('.')[a:from-1:a:to-1]
return len(split(chars, '\zs')) - 1
endfunction

" 7.4.341
" http://ftp.vim.org/vim/patches/7.4/7.4.341
if v:version > 704 || v:version == 704 && has('patch341')
function! s:sort_num(xs) abort
return sort(a:xs, 'n')
endfunction
else
function! s:_sort_num_func(x, y) abort
return a:x - a:y
endfunction
function! s:sort_num(xs) abort
return sort(a:xs, 's:_sort_num_func')
endfunction
endif

function! s:sort_pos(pos_list) abort
" pos_list: [ [x1, y1], [x2, y2] ]
return sort(a:pos_list, 's:compare_pos')
Expand All @@ -237,3 +285,4 @@ unlet s:save_cpo
" vim: expandtab softtabstop=4 shiftwidth=4
" vim: foldmethod=marker
" }}}

22 changes: 20 additions & 2 deletions doc/asterisk.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ CONTENTS *asterisk-contents*
Introduction |asterisk-introduction|
Install |asterisk-install|
Usage |asterisk-usage|
Key Mappings |asterisk-key-mappings|
Variables |asterisk-variables|
Known Issues |asterisk-known-issues|
ChangeLog |asterisk-changelog|

Expand Down Expand Up @@ -65,7 +67,10 @@ INSTALL *asterisk-install*


==============================================================================
USAGE *asterisk-usage*
USAGE *asterisk-usage*

------------------------------------------------------------------------------
KEY MAPPINGS *asterisk-key-mappings*

<Plug>(asterisk-*) *<Plug>(asterisk-star)*
<Plug>(asterisk-#) *<Plug>(asterisk-#)*
Expand Down Expand Up @@ -104,6 +109,15 @@ USAGE *asterisk-usage*
map g* <Plug>(asterisk-gz*)
map g# <Plug>(asterisk-gz#)
<
------------------------------------------------------------------------------
VARIABLES *asterisk-variables*

g:asterisk#keeppos *g:asterisk#keeppos*
You can keep cursor position while moving across matches.
By default this feature is disabeled but you can activate
it by adding to your vimrc:
>
let g:asterisk#keeppos = 1
==============================================================================
KNOWN ISSUES *asterisk-issues*
Expand All @@ -113,7 +127,7 @@ KNOWN ISSUES *asterisk-issues*


==============================================================================
CREDITS *asterisk-credits*
CREDITS *asterisk-credits*

|asterisk.vim| uses the code from vim-visualstar for visual star feature.

Expand All @@ -123,6 +137,10 @@ CREDITS *asterisk-credits*
==============================================================================
CHANGELOG *asterisk-changelog*


0.9.4 2015-02-05
- Add keepCursor option

0.9.3 2014-12-10
- Fix multybite handling for visual-star feature.
- Fix |v| selection over multi lines.
Expand Down
106 changes: 106 additions & 0 deletions test/keeppos.vimspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
scriptencoding utf-8
Describe basic_asterisk

Before all
let lines = [
\ '1.asterisk 2.asterisk 3.asterisk'
\ , '4.Asterisk 5.AsteRisK 6.Asterisk'
\ , ''
\ , '7.アスタリスク 8.アスタリスクです 9.アスタリスク?'
\ ]
call g:Add_lines(lines)
let g:asterisk#keeppos = 1
End

Before each
:1
normal! 2l
End

After all
:1,$ delete
let g:asterisk#keeppos = 0
End

Describe keeppos *
It search forward with \<\> keeping cursor position
normal! 3l
normal *
Assert Equals(histget('/', -1), '\<asterisk\>/s+3')
End
It keep cursor position without offset
normal *
Assert Equals(histget('/', -1), '\<asterisk\>')
End
It doesn't keep cursor position if the char under cursor is not keyword
normal 1h
normal *
Assert Equals(histget('/', -1), '\<asterisk\>')
End
It handles multibyte
normal! 3j2l
normal *
Assert Equals(histget('/', -1), '\<アスタリスク\>/s+2')
End
End

Describe keeppos g*
It search forward keeping cursor position
normal! 3l
normal g*
Assert Equals(histget('/', -1), 'asterisk/s+3')
End
It keep cursor position without offset
normal g*
Assert Equals(histget('/', -1), 'asterisk')
End
It doesn't keep cursor position if the char under cursor is not keyword
normal 1h
normal g*
Assert Equals(histget('/', -1), 'asterisk')
End
End

Describe keeppos #
It search backward with \<\> keeping cursor position
normal! 3l
normal #
Assert Equals(histget('/', -1), '\<asterisk\>?s+3')
End
It search backward and correct count at the end of word
normal! $
normal #
Assert Equals(histget('/', -1), '\<asterisk\>?s+7')
normal! 9h
Assert Equals(g:Get_pos_char(), '2')
End
It keep cursor position without offset
normal #
Assert Equals(histget('/', -1), '\<asterisk\>')
End
It doesn't keep cursor position if the char under cursor is not keyword
normal 1h
normal #
Assert Equals(histget('/', -1), '\<asterisk\>')
End
End

Describe keeppos g#
It search forward keeping cursor position
normal! 3l
normal g#
Assert Equals(histget('/', -1), 'asterisk?s+3')
End
It keep cursor position without offset
normal g#
Assert Equals(histget('/', -1), 'asterisk')
End
It doesn't keep cursor position if the char under cursor is not keyword
normal 1h
normal g#
Assert Equals(histget('/', -1), 'asterisk')
End
End


End

0 comments on commit 7f41f76

Please sign in to comment.