unimpaired.vim 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  1. " unimpaired.vim - Pairs of handy bracket mappings
  2. " Maintainer: Tim Pope <http://tpo.pe/>
  3. " Version: 2.1
  4. " GetLatestVimScripts: 1590 1 :AutoInstall: unimpaired.vim
  5. if exists("g:loaded_unimpaired") || &cp || v:version < 700
  6. finish
  7. endif
  8. let g:loaded_unimpaired = 1
  9. function! s:Map(...) abort
  10. let [mode, head, rhs; rest] = a:000
  11. let flags = get(rest, 0, '') . (rhs =~# '^<Plug>' ? '' : '<script>')
  12. let tail = ''
  13. let keys = get(g:, mode.'remap', {})
  14. if type(keys) == type({}) && !empty(keys)
  15. while !empty(head) && len(keys)
  16. if has_key(keys, head)
  17. let head = keys[head]
  18. if empty(head)
  19. let head = '<skip>'
  20. endif
  21. break
  22. endif
  23. let tail = matchstr(head, '<[^<>]*>$\|.$') . tail
  24. let head = substitute(head, '<[^<>]*>$\|.$', '', '')
  25. endwhile
  26. endif
  27. if head !=# '<skip>' && empty(maparg(head.tail, mode))
  28. return mode.'map ' . flags . ' ' . head.tail . ' ' . rhs
  29. endif
  30. return ''
  31. endfunction
  32. " Section: Next and previous
  33. function! s:MapNextFamily(map, cmd, current) abort
  34. let prefix = '<Plug>(unimpaired-' . a:cmd
  35. let map = '<Plug>unimpaired'.toupper(a:map)
  36. let cmd = '".(v:count ? v:count : "")."'.a:cmd
  37. let zv = (a:cmd ==# 'l' || a:cmd ==# 'c' ? 'zv' : '')
  38. let end = '"<CR>'.zv
  39. execute 'nnoremap <silent> '.prefix.'previous) :<C-U>exe "'.cmd.'previous'.end
  40. execute 'nnoremap <silent> '.prefix.'next) :<C-U>exe "'.cmd.'next'.end
  41. execute 'nnoremap '.prefix.'first) :<C-U><C-R>=v:count ? v:count . "' . a:current . '" : "' . a:cmd . 'first"<CR><CR>' . zv
  42. execute 'nnoremap '.prefix.'last) :<C-U><C-R>=v:count ? v:count . "' . a:current . '" : "' . a:cmd . 'last"<CR><CR>' . zv
  43. execute 'nnoremap <silent> '.map.'Previous :<C-U>exe "'.cmd.'previous'.end
  44. execute 'nnoremap <silent> '.map.'Next :<C-U>exe "'.cmd.'next'.end
  45. execute 'nnoremap <silent> '.map.'First :<C-U>exe "'.cmd.'first'.end
  46. execute 'nnoremap <silent> '.map.'Last :<C-U>exe "'.cmd.'last'.end
  47. exe s:Map('n', '['. a:map , prefix.'previous)')
  48. exe s:Map('n', ']'. a:map , prefix.'next)')
  49. exe s:Map('n', '['.toupper(a:map), prefix.'first)')
  50. exe s:Map('n', ']'.toupper(a:map), prefix.'last)')
  51. if a:cmd ==# 'c' || a:cmd ==# 'l'
  52. execute 'nnoremap <silent> '.prefix.'pfile) :<C-U>exe "'.cmd.'pfile'.end
  53. execute 'nnoremap <silent> '.prefix.'nfile) :<C-U>exe "'.cmd.'nfile'.end
  54. execute 'nnoremap <silent> '.map.'PFile :<C-U>exe "'.cmd.'pfile'.end
  55. execute 'nnoremap <silent> '.map.'NFile :<C-U>exe "'.cmd.'nfile'.end
  56. exe s:Map('n', '[<C-'.toupper(a:map).'>', prefix.'pfile)')
  57. exe s:Map('n', ']<C-'.toupper(a:map).'>', prefix.'nfile)')
  58. elseif a:cmd ==# 't'
  59. nnoremap <silent> <Plug>(unimpaired-ptprevious) :<C-U>exe v:count1 . "ptprevious"<CR>
  60. nnoremap <silent> <Plug>(unimpaired-ptnext) :<C-U>exe v:count1 . "ptnext"<CR>
  61. execute 'nnoremap <silent> '.map.'PPrevious :<C-U>exe "p'.cmd.'previous'.end
  62. execute 'nnoremap <silent> '.map.'PNext :<C-U>exe "p'.cmd.'next'.end
  63. exe s:Map('n', '[<C-T>', '<Plug>(unimpaired-ptprevious)')
  64. exe s:Map('n', ']<C-T>', '<Plug>(unimpaired-ptnext)')
  65. endif
  66. endfunction
  67. call s:MapNextFamily('a', '' , 'argument')
  68. call s:MapNextFamily('b', 'b', 'buffer')
  69. call s:MapNextFamily('l', 'l', 'll')
  70. call s:MapNextFamily('q', 'c', 'cc')
  71. call s:MapNextFamily('t', 't', 'trewind')
  72. function! s:entries(path) abort
  73. let path = substitute(a:path,'[\\/]$','','')
  74. let path = substitute(path, '[[$*]', '[&]', 'g')
  75. let files = split(glob(path."/.*"),"\n")
  76. let files += split(glob(path."/*"),"\n")
  77. call map(files,'substitute(v:val,"[\\/]$","","")')
  78. call filter(files,'v:val !~# "[\\\\/]\\.\\.\\=$"')
  79. let filter_suffixes = substitute(escape(&suffixes, '~.*$^'), ',', '$\\|', 'g') .'$'
  80. call filter(files, 'v:val !~# filter_suffixes')
  81. return sort(files)
  82. endfunction
  83. function! s:FileByOffset(num) abort
  84. let file = expand('%:p')
  85. if empty(file)
  86. let file = getcwd() . '/'
  87. endif
  88. let num = a:num
  89. while num
  90. let files = s:entries(fnamemodify(file,':h'))
  91. if a:num < 0
  92. call reverse(filter(files,'v:val <# file'))
  93. else
  94. call filter(files,'v:val ># file')
  95. endif
  96. let temp = get(files,0,'')
  97. if empty(temp)
  98. let file = fnamemodify(file,':h')
  99. else
  100. let file = temp
  101. let found = 1
  102. while isdirectory(file)
  103. let files = s:entries(file)
  104. if empty(files)
  105. let found = 0
  106. break
  107. endif
  108. let file = files[num > 0 ? 0 : -1]
  109. endwhile
  110. let num += (num > 0 ? -1 : 1) * found
  111. endif
  112. endwhile
  113. return file
  114. endfunction
  115. function! s:fnameescape(file) abort
  116. if exists('*fnameescape')
  117. return fnameescape(a:file)
  118. else
  119. return escape(a:file," \t\n*?[{`$\\%#'\"|!<")
  120. endif
  121. endfunction
  122. function! s:GetWindow() abort
  123. if exists('*getwininfo') && exists('*win_getid')
  124. return get(getwininfo(win_getid()), 0, {})
  125. else
  126. return {}
  127. endif
  128. endfunction
  129. function! s:PreviousFileEntry(count) abort
  130. let window = s:GetWindow()
  131. if get(window, 'loclist')
  132. return 'lolder ' . a:count
  133. elseif get(window, 'quickfix')
  134. return 'colder ' . a:count
  135. else
  136. return 'edit ' . s:fnameescape(fnamemodify(s:FileByOffset(-v:count1), ':.'))
  137. endif
  138. endfunction
  139. function! s:NextFileEntry(count) abort
  140. let window = s:GetWindow()
  141. if get(window, 'loclist')
  142. return 'lnewer ' . a:count
  143. elseif get(window, 'quickfix')
  144. return 'cnewer ' . a:count
  145. else
  146. return 'edit ' . s:fnameescape(fnamemodify(s:FileByOffset(v:count1), ':.'))
  147. endif
  148. endfunction
  149. nnoremap <silent> <Plug>(unimpaired-directory-next) :<C-U>execute <SID>NextFileEntry(v:count1)<CR>
  150. nnoremap <silent> <Plug>(unimpaired-directory-previous) :<C-U>execute <SID>PreviousFileEntry(v:count1)<CR>
  151. nnoremap <silent> <Plug>unimpairedDirectoryNext :<C-U>execute <SID>NextFileEntry(v:count1)<CR>
  152. nnoremap <silent> <Plug>unimpairedDirectoryPrevious :<C-U>execute <SID>PreviousFileEntry(v:count1)<CR>
  153. exe s:Map('n', ']f', '<Plug>(unimpaired-directory-next)')
  154. exe s:Map('n', '[f', '<Plug>(unimpaired-directory-previous)')
  155. " Section: Diff
  156. nnoremap <silent> <Plug>(unimpaired-context-previous) :<C-U>call <SID>Context(1)<CR>
  157. nnoremap <silent> <Plug>(unimpaired-context-next) :<C-U>call <SID>Context(0)<CR>
  158. vnoremap <silent> <Plug>(unimpaired-context-previous) :<C-U>exe 'normal! gv'<Bar>call <SID>Context(1)<CR>
  159. vnoremap <silent> <Plug>(unimpaired-context-next) :<C-U>exe 'normal! gv'<Bar>call <SID>Context(0)<CR>
  160. onoremap <silent> <Plug>(unimpaired-context-previous) :<C-U>call <SID>ContextMotion(1)<CR>
  161. onoremap <silent> <Plug>(unimpaired-context-next) :<C-U>call <SID>ContextMotion(0)<CR>
  162. exe s:Map('n', '[n', '<Plug>(unimpaired-context-previous)')
  163. exe s:Map('n', ']n', '<Plug>(unimpaired-context-next)')
  164. exe s:Map('x', '[n', '<Plug>(unimpaired-context-previous)')
  165. exe s:Map('x', ']n', '<Plug>(unimpaired-context-next)')
  166. exe s:Map('o', '[n', '<Plug>(unimpaired-context-previous)')
  167. exe s:Map('o', ']n', '<Plug>(unimpaired-context-next)')
  168. nnoremap <silent> <Plug>unimpairedContextPrevious :<C-U>call <SID>Context(1)<CR>
  169. nnoremap <silent> <Plug>unimpairedContextNext :<C-U>call <SID>Context(0)<CR>
  170. xnoremap <silent> <Plug>unimpairedContextPrevious :<C-U>exe 'normal! gv'<Bar>call <SID>Context(1)<CR>
  171. xnoremap <silent> <Plug>unimpairedContextNext :<C-U>exe 'normal! gv'<Bar>call <SID>Context(0)<CR>
  172. onoremap <silent> <Plug>unimpairedContextPrevious :<C-U>call <SID>ContextMotion(1)<CR>
  173. onoremap <silent> <Plug>unimpairedContextNext :<C-U>call <SID>ContextMotion(0)<CR>
  174. function! s:Context(reverse) abort
  175. call search('^\(@@ .* @@\|[<=>|]\{7}[<=>|]\@!\)', a:reverse ? 'bW' : 'W')
  176. endfunction
  177. function! s:ContextMotion(reverse) abort
  178. if a:reverse
  179. -
  180. endif
  181. call search('^@@ .* @@\|^diff \|^[<=>|]\{7}[<=>|]\@!', 'bWc')
  182. if getline('.') =~# '^diff '
  183. let end = search('^diff ', 'Wn') - 1
  184. if end < 0
  185. let end = line('$')
  186. endif
  187. elseif getline('.') =~# '^@@ '
  188. let end = search('^@@ .* @@\|^diff ', 'Wn') - 1
  189. if end < 0
  190. let end = line('$')
  191. endif
  192. elseif getline('.') =~# '^=\{7\}'
  193. +
  194. let end = search('^>\{7}>\@!', 'Wnc')
  195. elseif getline('.') =~# '^[<=>|]\{7\}'
  196. let end = search('^[<=>|]\{7}[<=>|]\@!', 'Wn') - 1
  197. else
  198. return
  199. endif
  200. if end > line('.')
  201. execute 'normal! V'.(end - line('.')).'j'
  202. elseif end == line('.')
  203. normal! V
  204. endif
  205. endfunction
  206. " Section: Line operations
  207. function! s:BlankUp() abort
  208. let cmd = 'put!=repeat(nr2char(10), v:count1)|silent '']+'
  209. if &modifiable
  210. let cmd .= '|silent! call repeat#set("\<Plug>(unimpaired-blank-up)", v:count1)'
  211. endif
  212. return cmd
  213. endfunction
  214. function! s:BlankDown() abort
  215. let cmd = 'put =repeat(nr2char(10), v:count1)|silent ''[-'
  216. if &modifiable
  217. let cmd .= '|silent! call repeat#set("\<Plug>(unimpaired-blank-down)", v:count1)'
  218. endif
  219. return cmd
  220. endfunction
  221. nnoremap <silent> <Plug>(unimpaired-blank-up) :<C-U>exe <SID>BlankUp()<CR>
  222. nnoremap <silent> <Plug>(unimpaired-blank-down) :<C-U>exe <SID>BlankDown()<CR>
  223. nnoremap <silent> <Plug>unimpairedBlankUp :<C-U>exe <SID>BlankUp()<CR>
  224. nnoremap <silent> <Plug>unimpairedBlankDown :<C-U>exe <SID>BlankDown()<CR>
  225. exe s:Map('n', '[<Space>', '<Plug>(unimpaired-blank-up)')
  226. exe s:Map('n', ']<Space>', '<Plug>(unimpaired-blank-down)')
  227. function! s:ExecMove(cmd) abort
  228. let old_fdm = &foldmethod
  229. if old_fdm !=# 'manual'
  230. let &foldmethod = 'manual'
  231. endif
  232. normal! m`
  233. silent! exe a:cmd
  234. norm! ``
  235. if old_fdm !=# 'manual'
  236. let &foldmethod = old_fdm
  237. endif
  238. endfunction
  239. function! s:Move(cmd, count, map) abort
  240. call s:ExecMove('move'.a:cmd.a:count)
  241. silent! call repeat#set("\<Plug>(unimpaired-move-".a:map.")", a:count)
  242. endfunction
  243. function! s:MoveSelectionUp(count) abort
  244. call s:ExecMove("'<,'>move'<--".a:count)
  245. silent! call repeat#set("\<Plug>(unimpaired-move-selection-up)", a:count)
  246. endfunction
  247. function! s:MoveSelectionDown(count) abort
  248. call s:ExecMove("'<,'>move'>+".a:count)
  249. silent! call repeat#set("\<Plug>(unimpaired-move-selection-down)", a:count)
  250. endfunction
  251. nnoremap <silent> <Plug>(unimpaired-move-up) :<C-U>call <SID>Move('--',v:count1,'up')<CR>
  252. nnoremap <silent> <Plug>(unimpaired-move-down) :<C-U>call <SID>Move('+',v:count1,'down')<CR>
  253. noremap <silent> <Plug>(unimpaired-move-selection-up) :<C-U>call <SID>MoveSelectionUp(v:count1)<CR>
  254. noremap <silent> <Plug>(unimpaired-move-selection-down) :<C-U>call <SID>MoveSelectionDown(v:count1)<CR>
  255. nnoremap <silent> <Plug>unimpairedMoveUp :<C-U>call <SID>Move('--',v:count1,'up')<CR>
  256. nnoremap <silent> <Plug>unimpairedMoveDown :<C-U>call <SID>Move('+',v:count1,'down')<CR>
  257. noremap <silent> <Plug>unimpairedMoveSelectionUp :<C-U>call <SID>MoveSelectionUp(v:count1)<CR>
  258. noremap <silent> <Plug>unimpairedMoveSelectionDown :<C-U>call <SID>MoveSelectionDown(v:count1)<CR>
  259. exe s:Map('n', '[e', '<Plug>(unimpaired-move-up)')
  260. exe s:Map('n', ']e', '<Plug>(unimpaired-move-down)')
  261. exe s:Map('x', '[e', '<Plug>(unimpaired-move-selection-up)')
  262. exe s:Map('x', ']e', '<Plug>(unimpaired-move-selection-down)')
  263. " Section: Option toggling
  264. function! s:StatuslineRefresh() abort
  265. let &l:readonly = &l:readonly
  266. return ''
  267. endfunction
  268. function! s:Toggle(op) abort
  269. call s:StatuslineRefresh()
  270. return eval('&'.a:op) ? 'no'.a:op : a:op
  271. endfunction
  272. function! s:CursorOptions() abort
  273. return &cursorline && &cursorcolumn ? 'nocursorline nocursorcolumn' : 'cursorline cursorcolumn'
  274. endfunction
  275. function! s:option_map(letter, option, mode) abort
  276. exe 'nmap <script> <Plug>(unimpaired-enable)' .a:letter ':<C-U>'.a:mode.' '.a:option.'<C-R>=<SID>StatuslineRefresh()<CR><CR>'
  277. exe 'nmap <script> <Plug>(unimpaired-disable)'.a:letter ':<C-U>'.a:mode.' no'.a:option.'<C-R>=<SID>StatuslineRefresh()<CR><CR>'
  278. exe 'nmap <script> <Plug>(unimpaired-toggle)' .a:letter ':<C-U>'.a:mode.' <C-R>=<SID>Toggle("'.a:option.'")<CR><CR>'
  279. endfunction
  280. nmap <script> <Plug>(unimpaired-enable)b :<C-U>set background=light<CR>
  281. nmap <script> <Plug>(unimpaired-disable)b :<C-U>set background=dark<CR>
  282. nmap <script> <Plug>(unimpaired-toggle)b :<C-U>set background=<C-R>=&background == "dark" ? "light" : "dark"<CR><CR>
  283. call s:option_map('c', 'cursorline', 'setlocal')
  284. call s:option_map('-', 'cursorline', 'setlocal')
  285. call s:option_map('_', 'cursorline', 'setlocal')
  286. call s:option_map('u', 'cursorcolumn', 'setlocal')
  287. call s:option_map('<Bar>', 'cursorcolumn', 'setlocal')
  288. nmap <script> <Plug>(unimpaired-enable)d :<C-U>diffthis<CR>
  289. nmap <script> <Plug>(unimpaired-disable)d :<C-U>diffoff<CR>
  290. nmap <script> <Plug>(unimpaired-toggle)d :<C-U><C-R>=&diff ? "diffoff" : "diffthis"<CR><CR>
  291. call s:option_map('h', 'hlsearch', 'set')
  292. call s:option_map('i', 'ignorecase', 'set')
  293. call s:option_map('l', 'list', 'setlocal')
  294. call s:option_map('n', 'number', 'setlocal')
  295. call s:option_map('r', 'relativenumber', 'setlocal')
  296. call s:option_map('s', 'spell', 'setlocal')
  297. call s:option_map('w', 'wrap', 'setlocal')
  298. if empty(maparg('<Plug>(unimpaired-toggle)z', 'n'))
  299. call s:option_map('z', 'spell', 'setlocal')
  300. endif
  301. nmap <script> <Plug>(unimpaired-enable)v :<C-U>set virtualedit+=all<CR>
  302. nmap <script> <Plug>(unimpaired-disable)v :<C-U>set virtualedit-=all<CR>
  303. nmap <script> <Plug>(unimpaired-toggle)v :<C-U>set <C-R>=(&virtualedit =~# "all") ? "virtualedit-=all" : "virtualedit+=all"<CR><CR>
  304. nmap <script> <Plug>(unimpaired-enable)x :<C-U>set cursorline cursorcolumn<CR>
  305. nmap <script> <Plug>(unimpaired-disable)x :<C-U>set nocursorline nocursorcolumn<CR>
  306. nmap <script> <Plug>(unimpaired-toggle)x :<C-U>set <C-R>=<SID>CursorOptions()<CR><CR>
  307. nmap <script> <Plug>(unimpaired-enable)+ :<C-U>set cursorline cursorcolumn<CR>
  308. nmap <script> <Plug>(unimpaired-disable)+ :<C-U>set nocursorline nocursorcolumn<CR>
  309. nmap <script> <Plug>(unimpaired-toggle)+ :<C-U>set <C-R>=<SID>CursorOptions()<CR><CR>
  310. function! s:ColorColumn(should_clear) abort
  311. if !empty(&colorcolumn)
  312. let s:colorcolumn = &colorcolumn
  313. endif
  314. return a:should_clear ? '' : get(s:, 'colorcolumn', get(g:, 'unimpaired_colorcolumn', '+1'))
  315. endfunction
  316. nmap <script> <Plug>(unimpaired-enable)t :<C-U>set colorcolumn=<C-R>=<SID>ColorColumn(0)<CR><CR>
  317. nmap <script> <Plug>(unimpaired-disable)t :<C-U>set colorcolumn=<C-R>=<SID>ColorColumn(1)<CR><CR>
  318. nmap <script> <Plug>(unimpaired-toggle)t :<C-U>set colorcolumn=<C-R>=<SID>ColorColumn(!empty(&cc))<CR><CR>
  319. exe s:Map('n', 'yo', '<Plug>(unimpaired-toggle)')
  320. exe s:Map('n', '[o', '<Plug>(unimpaired-enable)')
  321. exe s:Map('n', ']o', '<Plug>(unimpaired-disable)')
  322. exe s:Map('n', 'yo<Esc>', '<Nop>')
  323. exe s:Map('n', '[o<Esc>', '<Nop>')
  324. exe s:Map('n', ']o<Esc>', '<Nop>')
  325. exe s:Map('n', '=s', '<Plug>(unimpaired-toggle)')
  326. exe s:Map('n', '<s', '<Plug>(unimpaired-enable)')
  327. exe s:Map('n', '>s', '<Plug>(unimpaired-disable)')
  328. exe s:Map('n', '=s<Esc>', '<Nop>')
  329. exe s:Map('n', '<s<Esc>', '<Nop>')
  330. exe s:Map('n', '>s<Esc>', '<Nop>')
  331. function! s:RestorePaste() abort
  332. if exists('s:paste')
  333. let &paste = s:paste
  334. let &mouse = s:mouse
  335. unlet s:paste
  336. unlet s:mouse
  337. endif
  338. autocmd! unimpaired_paste
  339. endfunction
  340. function! s:SetupPaste() abort
  341. let s:paste = &paste
  342. let s:mouse = &mouse
  343. set paste
  344. set mouse=
  345. augroup unimpaired_paste
  346. autocmd!
  347. autocmd InsertLeave * call s:RestorePaste()
  348. if exists('##ModeChanged')
  349. autocmd ModeChanged *:n call s:RestorePaste()
  350. else
  351. autocmd CursorHold,CursorMoved * call s:RestorePaste()
  352. endif
  353. augroup END
  354. endfunction
  355. nnoremap <silent> <Plug>unimpairedPaste :call <SID>SetupPaste()<CR>
  356. nmap <script><silent> <Plug>(unimpaired-paste) :<C-U>call <SID>SetupPaste()<CR>
  357. nmap <script><silent> <Plug>(unimpaired-enable)p :<C-U>call <SID>SetupPaste()<CR>O
  358. nmap <script><silent> <Plug>(unimpaired-disable)p :<C-U>call <SID>SetupPaste()<CR>o
  359. nmap <script><silent> <Plug>(unimpaired-toggle)p :<C-U>call <SID>SetupPaste()<CR>0C
  360. " Section: Put
  361. function! s:putline(how, map) abort
  362. let [body, type] = [getreg(v:register), getregtype(v:register)]
  363. if type ==# 'V'
  364. exe 'normal! "'.v:register.a:how
  365. else
  366. call setreg(v:register, body, 'l')
  367. exe 'normal! "'.v:register.a:how
  368. call setreg(v:register, body, type)
  369. endif
  370. silent! call repeat#set("\<Plug>(unimpaired-put-".a:map.")")
  371. endfunction
  372. nnoremap <silent> <Plug>(unimpaired-put-above) :call <SID>putline('[p', 'above')<CR>
  373. nnoremap <silent> <Plug>(unimpaired-put-below) :call <SID>putline(']p', 'below')<CR>
  374. nnoremap <silent> <Plug>(unimpaired-put-above-rightward) :<C-U>call <SID>putline(v:count1 . '[p', 'Above')<CR>>']
  375. nnoremap <silent> <Plug>(unimpaired-put-below-rightward) :<C-U>call <SID>putline(v:count1 . ']p', 'Below')<CR>>']
  376. nnoremap <silent> <Plug>(unimpaired-put-above-leftward) :<C-U>call <SID>putline(v:count1 . '[p', 'Above')<CR><']
  377. nnoremap <silent> <Plug>(unimpaired-put-below-leftward) :<C-U>call <SID>putline(v:count1 . ']p', 'Below')<CR><']
  378. nnoremap <silent> <Plug>(unimpaired-put-above-reformat) :<C-U>call <SID>putline(v:count1 . '[p', 'Above')<CR>=']
  379. nnoremap <silent> <Plug>(unimpaired-put-below-reformat) :<C-U>call <SID>putline(v:count1 . ']p', 'Below')<CR>=']
  380. nnoremap <silent> <Plug>unimpairedPutAbove :call <SID>putline('[p', 'above')<CR>
  381. nnoremap <silent> <Plug>unimpairedPutBelow :call <SID>putline(']p', 'below')<CR>
  382. exe s:Map('n', '[p', '<Plug>(unimpaired-put-above)')
  383. exe s:Map('n', ']p', '<Plug>(unimpaired-put-below)')
  384. exe s:Map('n', '[P', '<Plug>(unimpaired-put-above)')
  385. exe s:Map('n', ']P', '<Plug>(unimpaired-put-below)')
  386. exe s:Map('n', '>P', "<Plug>(unimpaired-put-above-rightward)")
  387. exe s:Map('n', '>p', "<Plug>(unimpaired-put-below-rightward)")
  388. exe s:Map('n', '<P', "<Plug>(unimpaired-put-above-leftward)")
  389. exe s:Map('n', '<p', "<Plug>(unimpaired-put-below-leftward)")
  390. exe s:Map('n', '=P', "<Plug>(unimpaired-put-above-reformat)")
  391. exe s:Map('n', '=p', "<Plug>(unimpaired-put-below-reformat)")
  392. " Section: Encoding and decoding
  393. function! s:string_encode(str) abort
  394. let map = {"\n": 'n', "\r": 'r', "\t": 't', "\b": 'b', "\f": '\f', '"': '"', '\': '\'}
  395. return substitute(a:str,"[\001-\033\\\\\"]",'\="\\".get(map,submatch(0),printf("%03o",char2nr(submatch(0))))','g')
  396. endfunction
  397. function! s:string_decode(str) abort
  398. let map = {'n': "\n", 'r': "\r", 't': "\t", 'b': "\b", 'f': "\f", 'e': "\e", 'a': "\001", 'v': "\013", "\n": ''}
  399. let str = a:str
  400. if str =~# '^\s*".\{-\}\\\@<!\%(\\\\\)*"\s*\n\=$'
  401. let str = substitute(substitute(str,'^\s*\zs"','',''),'"\ze\s*\n\=$','','')
  402. endif
  403. return substitute(str,'\\\(\o\{1,3\}\|x\x\{1,2\}\|u\x\{1,4\}\|.\)','\=get(map,submatch(1),submatch(1) =~? "^[0-9xu]" ? nr2char("0".substitute(submatch(1),"^[Uu]","x","")) : submatch(1))','g')
  404. endfunction
  405. function! s:url_encode(str) abort
  406. " iconv trick to convert utf-8 bytes to 8bits indiviual char.
  407. return substitute(iconv(a:str, 'latin1', 'utf-8'),'[^A-Za-z0-9_.~-]','\="%".printf("%02X",char2nr(submatch(0)))','g')
  408. endfunction
  409. function! s:url_decode(str) abort
  410. let str = substitute(substitute(substitute(a:str,'%0[Aa]\n$','%0A',''),'%0[Aa]','\n','g'),'+',' ','g')
  411. return iconv(substitute(str,'%\(\x\x\)','\=nr2char("0x".submatch(1))','g'), 'utf-8', 'latin1')
  412. endfunction
  413. " HTML entities {{{2
  414. let g:unimpaired_html_entities = {
  415. \ 'nbsp': 160, 'iexcl': 161, 'cent': 162, 'pound': 163,
  416. \ 'curren': 164, 'yen': 165, 'brvbar': 166, 'sect': 167,
  417. \ 'uml': 168, 'copy': 169, 'ordf': 170, 'laquo': 171,
  418. \ 'not': 172, 'shy': 173, 'reg': 174, 'macr': 175,
  419. \ 'deg': 176, 'plusmn': 177, 'sup2': 178, 'sup3': 179,
  420. \ 'acute': 180, 'micro': 181, 'para': 182, 'middot': 183,
  421. \ 'cedil': 184, 'sup1': 185, 'ordm': 186, 'raquo': 187,
  422. \ 'frac14': 188, 'frac12': 189, 'frac34': 190, 'iquest': 191,
  423. \ 'Agrave': 192, 'Aacute': 193, 'Acirc': 194, 'Atilde': 195,
  424. \ 'Auml': 196, 'Aring': 197, 'AElig': 198, 'Ccedil': 199,
  425. \ 'Egrave': 200, 'Eacute': 201, 'Ecirc': 202, 'Euml': 203,
  426. \ 'Igrave': 204, 'Iacute': 205, 'Icirc': 206, 'Iuml': 207,
  427. \ 'ETH': 208, 'Ntilde': 209, 'Ograve': 210, 'Oacute': 211,
  428. \ 'Ocirc': 212, 'Otilde': 213, 'Ouml': 214, 'times': 215,
  429. \ 'Oslash': 216, 'Ugrave': 217, 'Uacute': 218, 'Ucirc': 219,
  430. \ 'Uuml': 220, 'Yacute': 221, 'THORN': 222, 'szlig': 223,
  431. \ 'agrave': 224, 'aacute': 225, 'acirc': 226, 'atilde': 227,
  432. \ 'auml': 228, 'aring': 229, 'aelig': 230, 'ccedil': 231,
  433. \ 'egrave': 232, 'eacute': 233, 'ecirc': 234, 'euml': 235,
  434. \ 'igrave': 236, 'iacute': 237, 'icirc': 238, 'iuml': 239,
  435. \ 'eth': 240, 'ntilde': 241, 'ograve': 242, 'oacute': 243,
  436. \ 'ocirc': 244, 'otilde': 245, 'ouml': 246, 'divide': 247,
  437. \ 'oslash': 248, 'ugrave': 249, 'uacute': 250, 'ucirc': 251,
  438. \ 'uuml': 252, 'yacute': 253, 'thorn': 254, 'yuml': 255,
  439. \ 'OElig': 338, 'oelig': 339, 'Scaron': 352, 'scaron': 353,
  440. \ 'Yuml': 376, 'circ': 710, 'tilde': 732, 'ensp': 8194,
  441. \ 'emsp': 8195, 'thinsp': 8201, 'zwnj': 8204, 'zwj': 8205,
  442. \ 'lrm': 8206, 'rlm': 8207, 'ndash': 8211, 'mdash': 8212,
  443. \ 'lsquo': 8216, 'rsquo': 8217, 'sbquo': 8218, 'ldquo': 8220,
  444. \ 'rdquo': 8221, 'bdquo': 8222, 'dagger': 8224, 'Dagger': 8225,
  445. \ 'permil': 8240, 'lsaquo': 8249, 'rsaquo': 8250, 'euro': 8364,
  446. \ 'fnof': 402, 'Alpha': 913, 'Beta': 914, 'Gamma': 915,
  447. \ 'Delta': 916, 'Epsilon': 917, 'Zeta': 918, 'Eta': 919,
  448. \ 'Theta': 920, 'Iota': 921, 'Kappa': 922, 'Lambda': 923,
  449. \ 'Mu': 924, 'Nu': 925, 'Xi': 926, 'Omicron': 927,
  450. \ 'Pi': 928, 'Rho': 929, 'Sigma': 931, 'Tau': 932,
  451. \ 'Upsilon': 933, 'Phi': 934, 'Chi': 935, 'Psi': 936,
  452. \ 'Omega': 937, 'alpha': 945, 'beta': 946, 'gamma': 947,
  453. \ 'delta': 948, 'epsilon': 949, 'zeta': 950, 'eta': 951,
  454. \ 'theta': 952, 'iota': 953, 'kappa': 954, 'lambda': 955,
  455. \ 'mu': 956, 'nu': 957, 'xi': 958, 'omicron': 959,
  456. \ 'pi': 960, 'rho': 961, 'sigmaf': 962, 'sigma': 963,
  457. \ 'tau': 964, 'upsilon': 965, 'phi': 966, 'chi': 967,
  458. \ 'psi': 968, 'omega': 969, 'thetasym': 977, 'upsih': 978,
  459. \ 'piv': 982, 'bull': 8226, 'hellip': 8230, 'prime': 8242,
  460. \ 'Prime': 8243, 'oline': 8254, 'frasl': 8260, 'weierp': 8472,
  461. \ 'image': 8465, 'real': 8476, 'trade': 8482, 'alefsym': 8501,
  462. \ 'larr': 8592, 'uarr': 8593, 'rarr': 8594, 'darr': 8595,
  463. \ 'harr': 8596, 'crarr': 8629, 'lArr': 8656, 'uArr': 8657,
  464. \ 'rArr': 8658, 'dArr': 8659, 'hArr': 8660, 'forall': 8704,
  465. \ 'part': 8706, 'exist': 8707, 'empty': 8709, 'nabla': 8711,
  466. \ 'isin': 8712, 'notin': 8713, 'ni': 8715, 'prod': 8719,
  467. \ 'sum': 8721, 'minus': 8722, 'lowast': 8727, 'radic': 8730,
  468. \ 'prop': 8733, 'infin': 8734, 'ang': 8736, 'and': 8743,
  469. \ 'or': 8744, 'cap': 8745, 'cup': 8746, 'int': 8747,
  470. \ 'there4': 8756, 'sim': 8764, 'cong': 8773, 'asymp': 8776,
  471. \ 'ne': 8800, 'equiv': 8801, 'le': 8804, 'ge': 8805,
  472. \ 'sub': 8834, 'sup': 8835, 'nsub': 8836, 'sube': 8838,
  473. \ 'supe': 8839, 'oplus': 8853, 'otimes': 8855, 'perp': 8869,
  474. \ 'sdot': 8901, 'lceil': 8968, 'rceil': 8969, 'lfloor': 8970,
  475. \ 'rfloor': 8971, 'lang': 9001, 'rang': 9002, 'loz': 9674,
  476. \ 'spades': 9824, 'clubs': 9827, 'hearts': 9829, 'diams': 9830,
  477. \ 'apos': 39}
  478. " }}}2
  479. function! s:xml_encode(str) abort
  480. let str = a:str
  481. let str = substitute(str,'&','\&amp;','g')
  482. let str = substitute(str,'<','\&lt;','g')
  483. let str = substitute(str,'>','\&gt;','g')
  484. let str = substitute(str,'"','\&quot;','g')
  485. let str = substitute(str,"'",'\&apos;','g')
  486. return str
  487. endfunction
  488. function! s:xml_entity_decode(str) abort
  489. let str = substitute(a:str,'\c&#\%(0*38\|x0*26\);','&amp;','g')
  490. let str = substitute(str,'\c&#\(\d\+\);','\=nr2char(submatch(1))','g')
  491. let str = substitute(str,'\c&#\(x\x\+\);','\=nr2char("0".submatch(1))','g')
  492. let str = substitute(str,'\c&apos;',"'",'g')
  493. let str = substitute(str,'\c&quot;','"','g')
  494. let str = substitute(str,'\c&gt;','>','g')
  495. let str = substitute(str,'\c&lt;','<','g')
  496. let str = substitute(str,'\C&\(\%(amp;\)\@!\w*\);','\=nr2char(get(g:unimpaired_html_entities,submatch(1),63))','g')
  497. return substitute(str,'\c&amp;','\&','g')
  498. endfunction
  499. function! s:xml_decode(str) abort
  500. let str = substitute(a:str,'<\%([[:alnum:]-]\+=\%("[^"]*"\|''[^'']*''\)\|.\)\{-\}>','','g')
  501. return s:xml_entity_decode(str)
  502. endfunction
  503. function! s:Transform(algorithm,type) abort
  504. let sel_save = &selection
  505. let cb_save = &clipboard
  506. set selection=inclusive clipboard-=unnamed clipboard-=unnamedplus
  507. let reg_save = exists('*getreginfo') ? getreginfo('@') : getreg('@')
  508. if a:type ==# 'line'
  509. silent exe "normal! '[V']y"
  510. let @@ = substitute(@@, "\n$", '', '')
  511. elseif a:type ==# 'block'
  512. silent exe "normal! `[\<C-V>`]y"
  513. else
  514. silent exe "normal! `[v`]y"
  515. endif
  516. if a:algorithm =~# '^\u\|#'
  517. let @@ = {a:algorithm}(@@)
  518. else
  519. let @@ = s:{a:algorithm}(@@)
  520. endif
  521. norm! gvp
  522. call setreg('@', reg_save)
  523. let &selection = sel_save
  524. let &clipboard = cb_save
  525. endfunction
  526. function! s:TransformOpfunc(type) abort
  527. return s:Transform(s:encode_algorithm, a:type)
  528. endfunction
  529. function! s:TransformSetup(algorithm) abort
  530. let s:encode_algorithm = a:algorithm
  531. let &opfunc = matchstr(expand('<sfile>'), '<SNR>\d\+_').'TransformOpfunc'
  532. return 'g@'
  533. endfunction
  534. function! UnimpairedMapTransform(algorithm, key) abort
  535. let name = tr(a:algorithm, '_', '-')
  536. exe 'nnoremap <expr> <Plug>unimpaired_' .a:algorithm.' <SID>TransformSetup("'.a:algorithm.'")'
  537. exe 'xnoremap <expr> <Plug>unimpaired_' .a:algorithm.' <SID>TransformSetup("'.a:algorithm.'")'
  538. exe 'nnoremap <expr> <Plug>unimpaired_line_'.a:algorithm.' <SID>TransformSetup("'.a:algorithm.'")."_"'
  539. exe 'nnoremap <expr> <Plug>(unimpaired-' . name . ') <SID>TransformSetup("'.a:algorithm.'")'
  540. exe 'xnoremap <expr> <Plug>(unimpaired-' . name . ') <SID>TransformSetup("'.a:algorithm.'")'
  541. exe 'nnoremap <expr> <Plug>(unimpaired-' . name . '-line) <SID>TransformSetup("'.a:algorithm.'")."_"'
  542. exe s:Map('n', a:key, '<Plug>(unimpaired-' . name . ')')
  543. exe s:Map('x', a:key, '<Plug>(unimpaired-' . name . ')')
  544. exe s:Map('n', a:key.a:key[strlen(a:key)-1], '<Plug>(unimpaired-' . name . '-line)')
  545. return ''
  546. endfunction
  547. exe UnimpairedMapTransform('string_encode','[y')
  548. exe UnimpairedMapTransform('string_decode',']y')
  549. exe UnimpairedMapTransform('string_encode','[C')
  550. exe UnimpairedMapTransform('string_decode',']C')
  551. exe UnimpairedMapTransform('url_encode','[u')
  552. exe UnimpairedMapTransform('url_decode',']u')
  553. exe UnimpairedMapTransform('xml_encode','[x')
  554. exe UnimpairedMapTransform('xml_decode',']x')
  555. " vim:set sw=2 sts=2: