mirror of https://github.com/amix/vimrc.git
parent
f343b66088
commit
347b3bea0e
@ -0,0 +1,2 @@ |
||||
.rvmrc |
||||
doc/tags |
@ -0,0 +1,4 @@ |
||||
source 'https://rubygems.org' |
||||
|
||||
gem "vimbot", :git => "git@github.com:maxbrunsfeld/vimbot.git" |
||||
gem "rspec" |
@ -0,0 +1,25 @@ |
||||
GIT |
||||
remote: git@github.com:maxbrunsfeld/vimbot.git |
||||
revision: 489cb3283a89d3e7891d9d9765188179c764317b |
||||
specs: |
||||
vimbot (0.0.1) |
||||
|
||||
GEM |
||||
remote: https://rubygems.org/ |
||||
specs: |
||||
diff-lcs (1.1.3) |
||||
rspec (2.8.0) |
||||
rspec-core (~> 2.8.0) |
||||
rspec-expectations (~> 2.8.0) |
||||
rspec-mocks (~> 2.8.0) |
||||
rspec-core (2.8.0) |
||||
rspec-expectations (2.8.0) |
||||
diff-lcs (~> 1.1.2) |
||||
rspec-mocks (2.8.0) |
||||
|
||||
PLATFORMS |
||||
ruby |
||||
|
||||
DEPENDENCIES |
||||
rspec |
||||
vimbot! |
@ -0,0 +1,134 @@ |
||||
yankstack.vim |
||||
============= |
||||
|
||||
Author: Max Brunsfeld <http://www.github.com/maxbrunsfeld> |
||||
|
||||
[Yankstack.vim](https://github.com/maxbrunsfeld/vim-yankstack) is a |
||||
lightweight implementation of the Emacs 'kill ring' for Vim. It allows you to |
||||
yank and delete things without worrying about losing the text that you yanked |
||||
previously. It effectively turns your default register into a stack, and lets |
||||
you cycle through the items in the stack after doing a paste. |
||||
|
||||
This plugin is intended to be a simpler alternative to the |
||||
[yankring](https://github.com/chrismetcalf/vim-yankring) plugin. It has a fairly |
||||
complete [test suite](https://github.com/maxbrunsfeld/vim-yankstack/blob/master/spec/yankstack/yankstack_spec.rb) |
||||
based on [rspec](https://www.relishapp.com/rspec) |
||||
and [vimbot](https://github.com/maxbrunsfeld/vimbot). |
||||
|
||||
## Installation ## |
||||
|
||||
I recommend loading your plugins with |
||||
[vundle](https://github.com/gmarik/vundle) or |
||||
[pathogen](https://github.com/tpope/vim-pathogen). |
||||
|
||||
## Key Mappings ## |
||||
|
||||
By default, yankstack adds only 2 key bindings, in normal and visual modes: |
||||
|
||||
- ```meta-p``` - cycle *backward* through your history of yanks |
||||
- ```meta-shift-p``` - cycle *forwards* through your history of yanks |
||||
|
||||
After pasting some text using ```p``` or ```P```, you can cycle through your |
||||
yank history using these commands. Typing either of these keys *without* pasting first |
||||
will do a normal paste (the same as typing `p`). This also works in insert mode. |
||||
|
||||
### the 'meta' key |
||||
|
||||
If you're using MacVim, and you want to use |
||||
this plugin's default key bindings (or any bindings involving the `option` |
||||
key), you must ```:set macmeta```. On Linux, you may have issues with the meta key if your terminal is running in 7bit mode. |
||||
Instructions for dealing with this can be found on the [wiki](https://github.com/maxbrunsfeld/vim-yankstack/wiki/Linux-terminal-configurations-for-correct-meta-key-handling) |
||||
|
||||
## Commands ## |
||||
|
||||
You can see the contents of the yank-stack using the ```:Yanks``` command. |
||||
Its output is similar to the ```:registers``` command. |
||||
|
||||
## Configuration ## |
||||
|
||||
Yankstack defines two plugin mappings that you can map to keys of your choosing. |
||||
The same mappings work in normal and insert modes. |
||||
|
||||
- ```<Plug>yankstack_substitute_older_paste``` - cycle backwards through your history of yanks |
||||
- ```<Plug>yankstack_substitute_newer_paste``` - cycle forwards through your history of yanks |
||||
|
||||
For example, if you wanted to define some mappings based on your 'leader' key, |
||||
you could do this: |
||||
|
||||
``` |
||||
nmap <leader>p <Plug>yankstack_substitute_older_paste |
||||
nmap <leader>P <Plug>yankstack_substitute_newer_paste |
||||
``` |
||||
|
||||
Also, if you want to load yankstack without the default key mappings, just |
||||
``` let g:yankstack_map_keys = 0 ``` |
||||
in your .vimrc file. |
||||
|
||||
## Compatibility ## |
||||
|
||||
Yankstack works by mapping the yank and paste keys to functions that do some |
||||
book-keeping before calling through to the normal yank/paste keys. You may want |
||||
to define your own mappings of the yank and paste keys. For example, I like to |
||||
map the ```Y``` key to ```y$```, so that it behaves the same as ```D``` and |
||||
```C```. The yankstack mappings need to happen **before** you define any such |
||||
mappings of your own. To achieve this, just call ```yankstack#setup()``` in |
||||
your vimrc, before defining your mappings: |
||||
|
||||
``` |
||||
call yankstack#setup() |
||||
nmap Y y$ |
||||
" other mappings involving y, d, c, etc |
||||
``` |
||||
|
||||
You can also prevent certain keys from being remapped by setting the `g:yankstack_yank_keys` |
||||
to the keys of your choosing. For example, if you only want Yankstack to remap `y` and `d`: |
||||
|
||||
``` |
||||
let g:yankstack_yank_keys = ['y', 'd'] |
||||
``` |
||||
|
||||
## Contributing, Feedback ## |
||||
|
||||
I'd enjoy hearing anybody's feedback on yankstack, and welcome any contribution. |
||||
Check it out on [github](https://github.com/maxbrunsfeld/vim-yankstack)! |
||||
|
||||
## Changelog ## |
||||
|
||||
|
||||
### 1.0.6 (2014-08-04) |
||||
- Allow customization of the list of keys to be remapped. |
||||
|
||||
### 1.0.5 (2012-07-19) |
||||
- Fix bug where on certain versions of vim, the first time you tried |
||||
to cycle through your yanks after doing a normal paste, an extra |
||||
paste was created. |
||||
|
||||
### 1.0.4 (2012-07-01) |
||||
- Make it so that yankstack-cycling keys cause a normal paste if they are |
||||
used without pasting first. Fix stack-cycling in insert-mode. |
||||
|
||||
### 1.0.3 (2012-05-04): |
||||
- Fix bug when overwriting text in select mode. This was causing |
||||
problems for snipMate users. |
||||
|
||||
### 1.0.2 (2012-4-20): |
||||
- Add test coverage using rspec and [vimbot](https://github.com/maxbrunsfeld/vimbot)! |
||||
- Perfect the behavior of the yankstack when pasting over text in visual |
||||
mode |
||||
- Fix bug where 's' and 'S' didn't push to the yankstack |
||||
|
||||
### 1.0.1 (2012-2-11): |
||||
- Change default key bindings, update readme, add link to github page. |
||||
|
||||
### 1.0.1 (2011-12-08): |
||||
- Fix bug when displaying empty yanks. |
||||
|
||||
### 1.0.0 (2011-12-04): |
||||
- Remove unnecessary dependency on the undotree() function. Plugin should |
||||
now work on any recent version of vim. |
||||
|
||||
## License ## |
||||
Copyright (c) Max Brunsfeld. Distributed under the same terms as Vim itself. |
||||
See the vim license. |
||||
|
||||
vim:tw=78:ts=8:ft=help:norl: |
@ -0,0 +1,197 @@ |
||||
" yankstack.vim - keep track of your history of yanked/killed text |
||||
" |
||||
" Maintainer: Max Brunsfeld <https://github.com/maxbrunsfeld> |
||||
" Version: 1.0.6 |
||||
" Todo: |
||||
" |
||||
|
||||
let s:yankstack_tail = [] |
||||
let g:yankstack_size = 30 |
||||
let s:last_paste = { 'changedtick': -1, 'key': '', 'mode': 'n', 'count': 1, 'register': '' } |
||||
|
||||
if !exists('g:yankstack_yank_keys') |
||||
let g:yankstack_yank_keys = ['c', 'C', 'd', 'D', 's', 'S', 'x', 'X', 'y', 'Y'] |
||||
endif |
||||
|
||||
function! s:yank_with_key(key) |
||||
call s:before_yank() |
||||
return a:key |
||||
endfunction |
||||
|
||||
function! s:paste_with_key(key, mode, register, count) |
||||
return s:paste_from_yankstack(a:key, a:mode, a:register, a:count, 1) |
||||
endfunction |
||||
|
||||
function! s:paste_from_yankstack(key, mode, register, count, is_new) |
||||
let keys = a:count . a:key |
||||
let keys = (a:register == s:default_register()) ? keys : ('"' . a:register . keys) |
||||
let s:last_paste = { 'key': a:key, 'mode': a:mode, 'register': a:register, 'count': a:count, 'changedtick': -1 } |
||||
call feedkeys("\<Plug>yankstack_after_paste", "m") |
||||
|
||||
if a:mode == 'n' |
||||
exec 'normal!' keys |
||||
elseif a:mode == 'v' |
||||
if a:is_new |
||||
call s:before_yank() |
||||
call feedkeys("\<Plug>yankstack_substitute_older_paste", "t") |
||||
exec 'normal! gv' . keys |
||||
else |
||||
let head = s:get_yankstack_head() |
||||
exec 'normal! gv' . keys |
||||
call s:set_yankstack_head(head) |
||||
endif |
||||
|
||||
" In insert mode, this function's return value is used in an |
||||
" expression mapping. In other modes, it is called for its |
||||
" side effects only. |
||||
elseif a:mode == 'i' |
||||
return keys |
||||
endif |
||||
|
||||
silent! call repeat#setreg(a:register) |
||||
silent! call repeat#set(a:key, a:count) |
||||
endfunction |
||||
|
||||
function! s:substitute_paste(offset, current_mode) |
||||
if s:last_change_was_paste() |
||||
silent undo |
||||
call s:yankstack_rotate(a:offset) |
||||
return s:paste_from_yankstack(s:last_paste.key, s:last_paste.mode, s:last_paste.register, s:last_paste.count, 0) |
||||
else |
||||
return s:paste_from_yankstack(s:default_paste_key(a:current_mode), a:current_mode, v:register, '', 1) |
||||
endif |
||||
endfunction |
||||
|
||||
function! s:before_yank() |
||||
let head = s:get_yankstack_head() |
||||
if !empty(head.text) && (empty(s:yankstack_tail) || (head != s:yankstack_tail[0])) |
||||
call insert(s:yankstack_tail, head) |
||||
let s:yankstack_tail = s:yankstack_tail[: g:yankstack_size-1] |
||||
endif |
||||
endfunction |
||||
|
||||
function! s:yankstack_rotate(offset) |
||||
if empty(s:yankstack_tail) | return | endif |
||||
let offset_left = a:offset |
||||
while offset_left != 0 |
||||
let head = s:get_yankstack_head() |
||||
if offset_left > 0 |
||||
let entry = remove(s:yankstack_tail, 0) |
||||
call add(s:yankstack_tail, head) |
||||
let offset_left -= 1 |
||||
elseif offset_left < 0 |
||||
let entry = remove(s:yankstack_tail, -1) |
||||
call insert(s:yankstack_tail, head) |
||||
let offset_left += 1 |
||||
endif |
||||
call s:set_yankstack_head(entry) |
||||
endwhile |
||||
endfunction |
||||
|
||||
function! s:get_yankstack_head() |
||||
let reg = s:default_register() |
||||
return { 'text': getreg(reg), 'type': getregtype(reg) } |
||||
endfunction |
||||
|
||||
function! s:set_yankstack_head(entry) |
||||
let reg = s:default_register() |
||||
call setreg(reg, a:entry.text, a:entry.type) |
||||
endfunction |
||||
|
||||
function! s:after_paste() |
||||
let s:last_paste.changedtick = b:changedtick |
||||
endfunction |
||||
|
||||
function! s:last_change_was_paste() |
||||
return b:changedtick == s:last_paste.changedtick |
||||
endfunction |
||||
|
||||
function! s:default_register() |
||||
let clipboard_flags = split(&clipboard, ',') |
||||
if index(clipboard_flags, 'unnamedplus') >= 0 |
||||
return "+" |
||||
elseif index(clipboard_flags, 'unnamed') >= 0 |
||||
return "*" |
||||
else |
||||
return "\"" |
||||
endif |
||||
endfunction |
||||
|
||||
function! s:default_paste_key(mode) |
||||
if a:mode == 'i' |
||||
return "\<C-g>u\<C-r>" . s:default_register() |
||||
else |
||||
return "p" |
||||
endif |
||||
endfunction |
||||
|
||||
function! g:Yankstack() |
||||
return [s:get_yankstack_head()] + s:yankstack_tail |
||||
endfunction |
||||
|
||||
command! -nargs=0 Yanks call s:show_yanks() |
||||
function! s:show_yanks() |
||||
echohl WarningMsg | echo "--- Yanks ---" | echohl None |
||||
let i = 0 |
||||
for yank in g:Yankstack() |
||||
call s:show_yank(yank, i) |
||||
let i += 1 |
||||
endfor |
||||
endfunction |
||||
|
||||
function! s:show_yank(yank, index) |
||||
let index = printf("%-4d", a:index) |
||||
let lines = split(a:yank.text, '\n') |
||||
let line = empty(lines) ? '' : lines[0] |
||||
let line = substitute(line, '\t', repeat(' ', &tabstop), 'g') |
||||
if len(line) > 80 || len(lines) > 1 |
||||
let line = line[: 80] . '…' |
||||
endif |
||||
|
||||
echohl Directory | echo index |
||||
echohl None | echon line |
||||
echohl None |
||||
endfunction |
||||
|
||||
function! yankstack#setup() |
||||
if exists('g:yankstack_did_setup') | return | endif |
||||
let g:yankstack_did_setup = 1 |
||||
|
||||
let paste_keys = ['p', 'P', 'gp', 'gP'] |
||||
let word_characters = split("qwertyuiopasdfghjklzxcvbnm1234567890_", '\zs') |
||||
|
||||
for key in g:yankstack_yank_keys |
||||
exec 'nnoremap <silent> <expr>' key '<SID>yank_with_key("' . key . '")' |
||||
exec 'xnoremap <silent> <expr>' key '<SID>yank_with_key("' . key . '")' |
||||
endfor |
||||
|
||||
for key in paste_keys |
||||
exec 'nnoremap <silent>' key ':<C-u>call <SID>paste_with_key("' . key . '", "n", v:register, v:count1)<CR>' |
||||
exec 'xnoremap <silent>' key ':<C-u>call <SID>paste_with_key("' . key . '", "v", v:register, v:count1)<CR>' |
||||
endfor |
||||
|
||||
for key in word_characters |
||||
exec 'smap <expr>' key '<SID>yank_with_key("' . key . '")' |
||||
endfor |
||||
endfunction |
||||
|
||||
nnoremap <silent> <Plug>yankstack_substitute_older_paste :<C-u>call <SID>substitute_paste(v:count1, 'n')<CR> |
||||
nnoremap <silent> <Plug>yankstack_substitute_newer_paste :<C-u>call <SID>substitute_paste(-v:count1, 'n')<CR> |
||||
xnoremap <silent> <Plug>yankstack_substitute_older_paste :<C-u>call <SID>substitute_paste(v:count1, 'v')<CR> |
||||
xnoremap <silent> <Plug>yankstack_substitute_newer_paste :<C-u>call <SID>substitute_paste(-v:count1, 'v')<CR> |
||||
inoremap <silent> <Plug>yankstack_substitute_older_paste <C-r>=<SID>substitute_paste(v:count1, 'i')<CR> |
||||
inoremap <silent> <Plug>yankstack_substitute_newer_paste <C-r>=<SID>substitute_paste(-v:count1, 'i')<CR> |
||||
|
||||
nnoremap <silent> <Plug>yankstack_after_paste :call <SID>after_paste()<CR> |
||||
xnoremap <silent> <Plug>yankstack_after_paste :<C-u>call <SID>after_paste()<CR> |
||||
inoremap <silent> <Plug>yankstack_after_paste <C-o>:call <SID>after_paste()<CR> |
||||
|
||||
if !exists('g:yankstack_map_keys') || g:yankstack_map_keys |
||||
nmap <M-p> <Plug>yankstack_substitute_older_paste |
||||
xmap <M-p> <Plug>yankstack_substitute_older_paste |
||||
imap <M-p> <Plug>yankstack_substitute_older_paste |
||||
nmap <M-P> <Plug>yankstack_substitute_newer_paste |
||||
xmap <M-P> <Plug>yankstack_substitute_newer_paste |
||||
imap <M-P> <Plug>yankstack_substitute_newer_paste |
||||
endif |
||||
|
@ -0,0 +1,124 @@ |
||||
*yankstack.txt* Plugin for storing and cycling through yanked text strings. |
||||
|
||||
Author: Max Brunsfeld <http://www.github.com/maxbrunsfeld> |
||||
|
||||
|yankstack-introduction| Introduction |
||||
|yankstack-installation| Installation |
||||
|yankstack-initialization| Initialization |
||||
|yankstack-commands| Commands |
||||
|yankstack-configuration| Configuration |
||||
|yankstack-changelog| Changelog |
||||
|
||||
INTRODUCTION *yankstack-introduction* |
||||
|
||||
[Yankstack.vim](https://github.com/maxbrunsfeld/vim-yankstack) is a |
||||
lightweight implementation of the Emacs 'kill ring' for Vim. It allows you to |
||||
yank and delete things without worrying about losing the text that you yanked |
||||
previously. It effectively turns your default register into a stack, and lets |
||||
you cycle through the items in the stack after doing a paste. |
||||
|
||||
This plugin is intended to be a simpler alternative to the {Yankring} plugin |
||||
(https://github.com/chrismetcalf/vim-yankring). |
||||
|
||||
INSTALLATION *yankstack-installation* |
||||
|
||||
I recommend loading your plugins with {Pathogen} |
||||
(https://github.com/tpope/vim-pathogen), so you can just clone this repo into |
||||
your "bundle" directory. |
||||
|
||||
KEY MAPPINGS *yankstack-mappings* |
||||
|
||||
By default, yankstack adds only 2 key mappings, in normal and visual modes: |
||||
|
||||
Mapping Action ~ |
||||
meta-p cycle backward through your history of yanks |
||||
meta-shift-p cycle forwards through your history of yanks |
||||
|
||||
After pasting some text using |p| or |P|, you can cycle through your |
||||
yank history using these commands. |
||||
|
||||
Typing either of these keys without pasting first will do a normal paste |
||||
(the same as typing `p`). This also works in insert mode. |
||||
|
||||
A note about the meta key - if you're using MacVim, and you want to use |
||||
this plugin's default key bindings (or any bindings involving the `option` |
||||
key), you must :set |macmeta|. |
||||
|
||||
COMMANDS *yankstack-commands* |
||||
|
||||
You can see the contents of the yank-stack using the :Yanks command. |
||||
Its output is similar to the |registers| command. > |
||||
|
||||
:Yanks (lists the contents of the yank-stack) |
||||
|
||||
CONFIGURATION *yankstack-configuration* |
||||
|
||||
If you want to load yankstack without defining any of the default key |
||||
mappings, just add > |
||||
|
||||
let g:yankstack_map_keys = 0 |
||||
|
||||
to your |.vimrc| file. |
||||
|
||||
Yankstack defines three plugin mappings that you can map to keys of your |
||||
choosing. The same mappings work in normal and insert modes. |
||||
|
||||
Mapping Name Action ~ |
||||
<Plug>yankstack_substitute_older_paste cycle BACKWARDs through your history of yanks |
||||
<Plug>yankstack_substitute_newer_paste cycle FORWARDS through your history of yanks |
||||
|
||||
For example, if you wanted to define some mappings based on your |leader| key, you could do this: > |
||||
|
||||
nmap <leader>p <Plug>yankstack_substitute_older_paste |
||||
nmap <leader>P <Plug>yankstack_substitute_newer_paste |
||||
|
||||
|
||||
COMPATIBILITY *yankstack-compatibility* |
||||
|
||||
Yankstack works by mapping the yank and paste keys to functions that do some |
||||
book-keeping before calling through to the normal yank/paste keys. You may |
||||
want to define your own mappings of the yank and paste keys. For example, I |
||||
like to map the |Y| key to "y$", so that it behaves the same as |D| and |C|. |
||||
The yankstack mappings need to happen **BEFORE** you define any such |
||||
mappings of your own. To achieve this, just call 'yankstack#setup()'in your |
||||
|vimrc|, before defining your mappings: > |
||||
|
||||
call yankstack#setup() |
||||
nmap Y y$ |
||||
|
||||
CHANGELOG *yankstack-changelog* |
||||
|
||||
1.0.5 (2012-07-19) |
||||
- Fix bug where on certain versions of vim, the first time you tried |
||||
to cycle through your yanks after doing a normal paste, an extra |
||||
paste was created. |
||||
|
||||
1.0.4 (2012-07-01) |
||||
- Make it so that yankstack-cycling keys cause a normal paste if they are |
||||
used without pasting first. Fix stack-cycling in insert-mode. |
||||
|
||||
1.0.3 (2012-05-04): |
||||
- Fix bug when overwriting text in select mode. This was causing |
||||
problems for snipMate users. |
||||
|
||||
1.0.2 (2012-4-20): |
||||
- Add test coverage using rspec and [vimbot](https://github.com/maxbrunsfeld/vimbot)! |
||||
- Perfect the behavior of the yankstack when pasting over text in visual |
||||
mode |
||||
- Fix bug where 's' and 'S' didn't push to the yankstack |
||||
|
||||
1.0.1 (2012-02-11): |
||||
- Change default key bindings, update readme, add link to github page. |
||||
|
||||
1.0.1 (2011-12-08): |
||||
- Fix bug when displaying empty yanks. |
||||
|
||||
1.0 (2011-12-04): |
||||
- Remove unnecessary dependency on the undotree() function. Plugin should |
||||
now work on any recent version of vim. |
||||
|
||||
*yankstack-license* |
||||
Copyright (c) Max Brunsfeld. Distributed under the same terms as Vim itself. |
||||
See |license|. |
||||
|
||||
vim:tw=78:ts=8:ft=help:norl: |
@ -0,0 +1 @@ |
||||
call yankstack#setup() |
@ -0,0 +1,115 @@ |
||||
" repeat.vim - Let the repeat command repeat plugin maps |
||||
" Maintainer: Tim Pope |
||||
" Version: 1.1 |
||||
" GetLatestVimScripts: 2136 1 :AutoInstall: repeat.vim |
||||
|
||||
" Installation: |
||||
" Place in either ~/.vim/plugin/repeat.vim (to load at start up) or |
||||
" ~/.vim/autoload/repeat.vim (to load automatically as needed). |
||||
" |
||||
" License: |
||||
" Copyright (c) Tim Pope. Distributed under the same terms as Vim itself. |
||||
" See :help license |
||||
" |
||||
" Developers: |
||||
" Basic usage is as follows: |
||||
" |
||||
" silent! call repeat#set("\<Plug>MappingToRepeatCommand",3) |
||||
" |
||||
" The first argument is the mapping that will be invoked when the |.| key is |
||||
" pressed. Typically, it will be the same as the mapping the user invoked. |
||||
" This sequence will be stuffed into the input queue literally. Thus you must |
||||
" encode special keys by prefixing them with a backslash inside double quotes. |
||||
" |
||||
" The second argument is the default count. This is the number that will be |
||||
" prefixed to the mapping if no explicit numeric argument was given. The |
||||
" value of the v:count variable is usually correct and it will be used if the |
||||
" second parameter is omitted. If your mapping doesn't accept a numeric |
||||
" argument and you never want to receive one, pass a value of -1. |
||||
" |
||||
" Make sure to call the repeat#set function _after_ making changes to the |
||||
" file. |
||||
" |
||||
" For mappings that use a register and want the same register used on |
||||
" repetition, use: |
||||
" |
||||
" silent! call repeat#setreg("\<Plug>MappingToRepeatCommand", v:register) |
||||
" |
||||
" This function can (and probably needs to be) called before making changes to |
||||
" the file (as those typically clear v:register). Therefore, the call sequence |
||||
" in your mapping will look like this: |
||||
" |
||||
" nnoremap <silent> <Plug>MyMap |
||||
" \ :<C-U>execute 'silent! call repeat#setreg("\<lt>Plug>MyMap", v:register)'<Bar> |
||||
" \ call <SID>MyFunction(v:register, ...)<Bar> |
||||
" \ silent! call repeat#set("\<lt>Plug>MyMap")<CR> |
||||
|
||||
if exists("g:loaded_repeat") || &cp || v:version < 700 |
||||
finish |
||||
endif |
||||
let g:loaded_repeat = 1 |
||||
|
||||
let g:repeat_tick = -1 |
||||
let g:repeat_reg = ['', ''] |
||||
|
||||
" Special function to avoid spurious repeats in a related, naturally repeating |
||||
" mapping when your repeatable mapping doesn't increase b:changedtick. |
||||
function! repeat#invalidate() |
||||
let g:repeat_tick = -1 |
||||
endfunction |
||||
|
||||
function! repeat#set(sequence,...) |
||||
let g:repeat_sequence = a:sequence |
||||
let g:repeat_count = a:0 ? a:1 : v:count |
||||
let g:repeat_tick = b:changedtick |
||||
endfunction |
||||
|
||||
function! repeat#setreg(sequence,register) |
||||
let g:repeat_reg = [a:sequence, a:register] |
||||
endfunction |
||||
|
||||
function! repeat#run(count) |
||||
if g:repeat_tick == b:changedtick |
||||
let r = '' |
||||
if g:repeat_reg[0] ==# g:repeat_sequence && !empty(g:repeat_reg[1]) |
||||
if g:repeat_reg[1] ==# '=' |
||||
" This causes a re-evaluation of the expression on repeat, which |
||||
" is what we want. |
||||
let r = '"=' . getreg('=', 1) . "\<CR>" |
||||
else |
||||
let r = '"' . g:repeat_reg[1] |
||||
endif |
||||
endif |
||||
|
||||
let c = g:repeat_count |
||||
let s = g:repeat_sequence |
||||
let cnt = c == -1 ? "" : (a:count ? a:count : (c ? c : '')) |
||||
call feedkeys(r . cnt, 'n') |
||||
call feedkeys(s) |
||||
else |
||||
call feedkeys((a:count ? a:count : '') . '.', 'n') |
||||
endif |
||||
endfunction |
||||
|
||||
function! repeat#wrap(command,count) |
||||
let preserve = (g:repeat_tick == b:changedtick) |
||||
exe 'norm! '.(a:count ? a:count : '').a:command . (&foldopen =~# 'undo' ? 'zv' : '') |
||||
if preserve |
||||
let g:repeat_tick = b:changedtick |
||||
endif |
||||
endfunction |
||||
|
||||
nnoremap <silent> . :<C-U>call repeat#run(v:count)<CR> |
||||
nnoremap <silent> u :<C-U>call repeat#wrap('u',v:count)<CR> |
||||
if maparg('U','n') ==# '' |
||||
nnoremap <silent> U :<C-U>call repeat#wrap('U',v:count)<CR> |
||||
endif |
||||
nnoremap <silent> <C-R> :<C-U>call repeat#wrap("\<Lt>C-R>",v:count)<CR> |
||||
|
||||
augroup repeatPlugin |
||||
autocmd! |
||||
autocmd BufLeave,BufWritePre,BufReadPre * let g:repeat_tick = (g:repeat_tick == b:changedtick || g:repeat_tick == 0) ? 0 : -1 |
||||
autocmd BufEnter,BufWritePost * if g:repeat_tick == 0|let g:repeat_tick = b:changedtick|endif |
||||
augroup END |
||||
|
||||
" vim:set ft=vim et sw=4 sts=4: |
@ -0,0 +1,9 @@ |
||||
require "vimbot" |
||||
|
||||
PLUGIN_ROOT = File.expand_path("../..", __FILE__) |
||||
VIM_REPEAT_PATH = File.expand_path("spec/fixtures/repeat.vim", PLUGIN_ROOT) |
||||
|
||||
RSpec.configure do |c| |
||||
c.alias_it_should_behave_like_to :it_has_behavior, 'has behavior:' |
||||
end |
||||
|
@ -0,0 +1,343 @@ |
||||
require "spec_helper" |
||||
|
||||
describe "Yankstack" do |
||||
let(:vim) { Vimbot::Driver.new } |
||||
|
||||
before(:all) do |
||||
vim.start |
||||
|
||||
vim.set "visualbell" |
||||
vim.set "noerrorbells" |
||||
vim.set "macmeta" |
||||
|
||||
vim.set "runtimepath+=#{PLUGIN_ROOT}" |
||||
vim.runtime "plugin/yankstack.vim" |
||||
|
||||
vim.source VIM_REPEAT_PATH |
||||
end |
||||
|
||||
after(:all) { vim.stop } |
||||
before(:each) { vim.clear_buffer } |
||||
|
||||
shared_examples "yanking and pasting" do |
||||
let(:yank_keys) { "yw" } |
||||
|
||||
before do |
||||
vim.insert "first_line<CR>", "second_line<CR>", "third_line<CR>", "fourth_line" |
||||
vim.normal "gg" |
||||
vim.normal yank_keys, 'j', yank_keys, 'j', yank_keys, 'j', yank_keys |
||||
end |
||||
|
||||
it "pushes every yanked string to the :Yanks stack" do |
||||
yank_entries[0].should match /0\s+fourth_line/ |
||||
yank_entries[1].should match /1\s+third_line/ |
||||
yank_entries[2].should match /2\s+second_line/ |
||||
yank_entries[3].should match /3\s+first_line/ |
||||
end |
||||
|
||||
describe "yanking with different keys" do |
||||
before do |
||||
vim.normal "A", "<CR>", "line to delete", "<Esc>", "^" |
||||
end |
||||
|
||||
keys_that_change_register = [ |
||||
'cc', 'C', |
||||
'dd', 'D', |
||||
's', 'S', |
||||
'x', 'X', |
||||
'yy', 'Y' |
||||
] |
||||
|
||||
keys_that_change_register.each do |key| |
||||
it "pushes to the stack when deleting text with '#{key}'" do |
||||
vim.normal key |
||||
yank_entries[1].should match /1\s+fourth_line/ |
||||
end |
||||
end |
||||
|
||||
it "pushes to the stack when overwriting text in select mode" do |
||||
vim.type "V" |
||||
vim.type "<c-g>", "this overwrites the last line" |
||||
yank_entries[0].should include "line to delete" |
||||
yank_entries[1].should include "fourth_line" |
||||
end |
||||
end |
||||
|
||||
context "in normal mode" do |
||||
before { vim.normal "o", "<Esc>" } |
||||
|
||||
describe "pasting a string with 'p'" do |
||||
before { vim.normal "p" } |
||||
|
||||
it "pastes the most recently yanked string" do |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
|
||||
describe "pressing the repeat key with '.'" do |
||||
it "pastes again" do |
||||
pending unless File.exists?(VIM_REPEAT_PATH) |
||||
|
||||
vim.type "." |
||||
vim.line.should == "fourth_linefourth_line" |
||||
end |
||||
end |
||||
|
||||
describe "typing the 'cycle paste' key" do |
||||
before { vim.normal "<M-p>" } |
||||
|
||||
it "replaces the pasted string with the previously yanked text" do |
||||
vim.line.should == "third_line" |
||||
end |
||||
|
||||
it "rotates the previously yanked text to the top of the yank stack" do |
||||
yank_entries[0].should include 'third_line' |
||||
yank_entries[1].should include 'second_line' |
||||
yank_entries[2].should include 'first_line' |
||||
yank_entries[-1].should include 'fourth_line' |
||||
end |
||||
|
||||
it "rotates through the yanks when pressed multiple times" do |
||||
vim.normal "<M-p>" |
||||
vim.line.should == "second_line" |
||||
vim.normal "<M-p>" |
||||
vim.line.should == "first_line" |
||||
|
||||
vim.normal "<M-P>" |
||||
vim.line.should == "second_line" |
||||
vim.normal "<M-P>" |
||||
vim.line.should == "third_line" |
||||
vim.normal "<M-P>" |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe "typing the `substitute_older_paste` key without pasting first" do |
||||
before { vim.type "<M-p>" } |
||||
|
||||
it "pastes the most recently yanked string" do |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
|
||||
describe "typing the 'cycle paste' key" do |
||||
before { vim.normal "<M-p>" } |
||||
|
||||
it "replaces the pasted text with the previously yanked text" do |
||||
vim.line.should == "third_line" |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe "typing the `substitute_newer_paste` key without pasting first" do |
||||
before { vim.type "<M-P>" } |
||||
|
||||
it "pastes the most recently yanked string" do |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
|
||||
describe "typing the 'cycle paste' key" do |
||||
before { vim.normal "<M-p>" } |
||||
|
||||
it "replaces the pasted text with the previously yanked text" do |
||||
vim.line.should == "third_line" |
||||
end |
||||
end |
||||
end |
||||
|
||||
it "allows pasting from a non-default register" do |
||||
reg = 'a' |
||||
vim.normal "gg" |
||||
vim.normal %("#{reg}y$) |
||||
vim.normal "G" |
||||
|
||||
vim.normal %("#{reg}p) |
||||
vim.line.should == "first_line" |
||||
end |
||||
|
||||
it "allows pasting with a count" do |
||||
vim.normal "3p" |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "fourth_line" * 3 |
||||
end |
||||
end |
||||
|
||||
context "in visual mode, with text highlighted" do |
||||
before do |
||||
vim.normal "A<CR>", "line to overwrite" |
||||
vim.normal "V" |
||||
end |
||||
|
||||
describe "pasting a string with 'p'" do |
||||
before do |
||||
vim.type "p" |
||||
end |
||||
|
||||
it "overwrites the selection with the most recently yanked string" do |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
|
||||
it "moves the the overwritten text to the bottom of the stack" do |
||||
yank_entries[0].should include "fourth_line" |
||||
yank_entries[1].should include "third_line" |
||||
yank_entries[2].should include "second_line" |
||||
yank_entries[-1].should include "line to overwrite" |
||||
end |
||||
|
||||
describe "typing the 'cycle older paste' key" do |
||||
before { vim.normal "<M-p>" } |
||||
|
||||
it "replaces the pasted text with the previously yanked text" do |
||||
vim.line.should == "third_line" |
||||
end |
||||
|
||||
it "moves the previously yanked text to the top of the stack" do |
||||
yank_entries[0].should include "third_line" |
||||
yank_entries[1].should include "second_line" |
||||
yank_entries[2].should include "first_line" |
||||
yank_entries[-2].should include "line to overwrite" |
||||
yank_entries[-1].should include "fourth_line" |
||||
end |
||||
|
||||
describe "typing the 'cycle newer paste' key" do |
||||
before { vim.normal "<M-P>" } |
||||
|
||||
it "replaces the pasted text with the previously yanked text" do |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
|
||||
it "moves the previously yanked text to the top of the stack" do |
||||
yank_entries[0].should include "fourth_line" |
||||
yank_entries[1].should include "third_line" |
||||
yank_entries[2].should include "second_line" |
||||
yank_entries[3].should include "first_line" |
||||
yank_entries[-1].should include "line to overwrite" |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe "typing the `substitute_older_paste` key without pasting first" do |
||||
before { vim.type "<M-p>" } |
||||
|
||||
it "overwrites the selection with the most recently yanked string" do |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
end |
||||
|
||||
describe "typing the `substitute_newer_paste` key without pasting first" do |
||||
before { vim.type "<M-P>" } |
||||
|
||||
it "overwrites the selection with the most recently yanked string" do |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
end |
||||
|
||||
it "allows pasting with a count" do |
||||
vim.type "3p" |
||||
|
||||
vim.line_number.should == 5 |
||||
vim.line.should == "fourth_line" |
||||
|
||||
vim.normal 'j' |
||||
vim.line_number.should == 6 |
||||
vim.line.should == "fourth_line" |
||||
|
||||
vim.normal 'j' |
||||
vim.line_number.should == 7 |
||||
vim.line.should == "fourth_line" |
||||
end |
||||
end |
||||
|
||||
context "in insert mode" do |
||||
before do |
||||
vim.normal "A<Cr>", "()", "<Left>" |
||||
vim.type "<M-p>" |
||||
end |
||||
|
||||
describe "typing the `substitute_older_paste` after a character-wise yank" do |
||||
it "pastes the most recently yanked text after the cursor" do |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "(fourth_line)" |
||||
end |
||||
|
||||
it "stays in insert mode, with the cursor at the end of the pasted text" do |
||||
vim.should be_in_insert_mode |
||||
vim.column_number.should == "(fourth_line".length + 1 |
||||
end |
||||
|
||||
describe "typing the `substitute_older_paste` key again" do |
||||
before { vim.type "<M-p>" } |
||||
|
||||
it "replaces the pasted text with the previously yanked text" do |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "(third_line)" |
||||
end |
||||
|
||||
it "stays in insert mode, with the cursor at the end of the pasted text" do |
||||
vim.should be_in_insert_mode |
||||
vim.column_number.should == "(third_line".length+1 |
||||
end |
||||
|
||||
it "rotates the previously yanked text to the top of the yank stack" do |
||||
yank_entries[0].should include 'third_line' |
||||
yank_entries[1].should include 'second_line' |
||||
yank_entries[2].should include 'first_line' |
||||
yank_entries[-1].should include 'fourth_line' |
||||
end |
||||
|
||||
it "rotates through the yanks when pressed multiple times" do |
||||
vim.type "<M-p>" |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "(second_line)" |
||||
|
||||
vim.type "<M-p>" |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "(first_line)" |
||||
|
||||
vim.type "<M-P>" |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "(second_line)" |
||||
|
||||
vim.type "<M-P>" |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "(third_line)" |
||||
|
||||
vim.type "<M-P>" |
||||
vim.line_number.should == 5 |
||||
vim.line.should == "(fourth_line)" |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe "typing `substitute_older_paste` after a line-wise yank" do |
||||
let(:yank_keys) { "yy" } |
||||
|
||||
xit "pastes and puts the cursor after the pasted text" do |
||||
vim.line_number.should == 6 |
||||
vim.line.should == ")" |
||||
vim.type "<Up>" |
||||
vim.line.should == "(fourth_line" |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
describe "when using the normal default register" do |
||||
it_has_behavior "yanking and pasting" |
||||
end |
||||
|
||||
describe "when using the system clipboard as the default register" do |
||||
before { vim.set "clipboard", "unnamed" } |
||||
it_has_behavior "yanking and pasting" |
||||
end |
||||
|
||||
def yank_entries |
||||
@yank_entries ||= vim.command("Yanks").split("\n")[1..-1] |
||||
end |
||||
end |
||||
|
Loading…
Reference in new issue