diff --git a/.bin/ksh-update-completions b/.bin/ksh-update-completions
index f9da901..a1123d5 100755
--- a/.bin/ksh-update-completions
+++ b/.bin/ksh-update-completions
@@ -1,6 +1,6 @@
#!/bin/ksh
-rm -f "${HOME}/.ksh-complete"
+rm -f "${HOME}/.ksh/complete.ksh"
add() { ( printf '%s %s' "$1" "$2" | tr '\n' ' '; printf '\n') >> "${HOME}/.ksh-complete"; }
diff --git a/.config/spectrwm/spectrwm.conf b/.config/spectrwm/spectrwm.conf
index f4c6efe..80f45b7 100644
--- a/.config/spectrwm/spectrwm.conf
+++ b/.config/spectrwm/spectrwm.conf
@@ -10,15 +10,15 @@
# | WINDOW DECORATION
# +--------------------------------------------------
-border_width = 2
+border_width = 1
color_focus = rgb:AF/5F/00
color_focus_maximized = rgb:AF/5F/00
color_focus_maximized_free = rgb:AF/5F/00
color_focus_free = rgb:AF/5F/00
color_unfocus = rgb:44/44/44
color_unfocus_free = rgb:55/35/00
-tile_gap = 16
-region_padding = 16
+tile_gap = 8
+region_padding = 8
disable_border = 0
maximize_hide_bar = 0
@@ -152,8 +152,8 @@ bind[mcorner] = MOD+Shift+X
program[mixer] = texec cmixer
bind[mixer] = MOD+Shift+M
-program[vim] = texec vim
-bind[vim] = Control+o
+program[vim] = texec "vim -c ':History'"
+bind[vim] = MOD+Shift+o
program[vpn] = dexec_vpn
bind[vpn] = MOD+V
@@ -161,8 +161,8 @@ bind[vpn] = MOD+V
program[exec] = dexec
bind[exec] = MOD+D
-program[cexec] = dexec_command
-bind[cexec] = MOD+C
+program[cexec] = dexec_command
+bind[cexec] = MOD+C
program[texec] = dexec_term
bind[texec] = MOD+Shift+D
@@ -173,8 +173,8 @@ bind[ssh] = MOD+S
program[ssh] = dexec_ssh
bind[ssh] = MOD+S
-program[edit] = dexec_edit
-bind[edit] = MOD+numbersign
+program[edit] = dexec_edit
+bind[edit] = MOD+numbersign
program[scratchpad] = sp
bind[scratchpad] = MOD+minus
diff --git a/.ksh/aliases.ksh b/.ksh/aliases.ksh
index f001bac..a47fb16 100644
--- a/.ksh/aliases.ksh
+++ b/.ksh/aliases.ksh
@@ -13,10 +13,6 @@ alias sxhkdrc="vim ~/.config/bspwm/sxhkdrc"
alias vimbrc="vim ~/.config/vimb/config"
alias exrc="vim ~/.exrc"
-alias web-ebay="chrome https://www.kleinanzeigen.de/m-nachrichten.html &"
-alias web-scottsbasslessons="chrome https://scottsbasslessons.com &"
-
-alias vmctl="doas /usr/sbin/vmctl"
# translation
alias trans-en="trans -l de -s en -t de --no-ansi"
diff --git a/.ksh/porttools.ksh b/.ksh/porttools.ksh
index 64dbfe0..54bac52 100644
--- a/.ksh/porttools.ksh
+++ b/.ksh/porttools.ksh
@@ -17,6 +17,10 @@ case $(hostname -s) in
openbsd) PKGOPT="-Dsnap"; ;;
esac
+alias pkg_add="doas \pkg_add ${PKGOPT}"
+alias pkg_delete="doas \pkg_delete ${PKGOPT}"
+alias pkg_info="\pkg_info ${PKGOPT}"
+
#
# SUPER LAZY ALIASES FOR THE ALIASES
#
diff --git a/.kshrc b/.kshrc
index a6a65c9..5484eed 100644
--- a/.kshrc
+++ b/.kshrc
@@ -47,12 +47,6 @@ export PRINTER
# MANDATORY ENVIRONMENT
########################################################################
-# hack for more colors in cool-retro-term
-if [ ! -z $COLORFGBG ]
-then
- TERM=xterm-256color
-fi
-
### HISTORY
HISTCONTROL=ignoredups:ignorespace:erasedups
HISTFILE=$HOME/.ksh-history
@@ -65,10 +59,14 @@ LESSHISTFILE="$HOME/.less-history"
export LESS LESSHISTFILE
########################################################################
-# PROMPT (SIMPLE)
+# PROMPT
########################################################################
-PS1="\h|\${?}\w\\$ "
+C1="\[$(tput setaf 240)\]" # gray
+C2="\[$(tput setaf 208)\]" # orange
+C0="\[$(tput op)\]" # reset
+x=$(print \\001) # hack from ksh(1)
+PS1="$x\${C1}[\${C2}\h\${C1}](\${C2}\${?}\${C1})(\${C2}\W\${C1})\\$ \${C0}$x"
########################################################################
# SHELL SETTINGS
@@ -95,102 +93,31 @@ load ytdl.ksh
load amused.ksh
load gnupg.ksh
load fzf.ksh
+load dotfiles.ksh
load localstuff.ksh
+load complete.ksh
+
########################################################################
# ALIASES (MISC)
########################################################################
-alias sudo="doas"
-alias su="doas su"
-
-# packages
-alias pkg_add="doas \pkg_add ${PKGOPT}"
-alias pkg_delete="doas \pkg_delete ${PKGOPT}"
-alias pkg_info="\pkg_info ${PKGOPT}"
-
# mount
alias mount_msdos="doas \mount_msdos -o nodev,nosuid,noatime -u 1000 -g 1000"
-mount_tank() { awk '$3=="nfs"{print $2}' /etc/fstab | xargs -n1 doas mount; }
-umount_tank() { awk '$3=="nfs"{print $2}' /etc/fstab | xargs -n1 doas umount; }
+mount_tank() { awk '$3=="nfs"{print $2}' /etc/fstab | xargs -n1 doas mount -v | cut -d" " -f-3; }
+umount_tank() { awk '$3=="nfs"{print $2}' /etc/fstab | xargs -n1 doas umount -v | cut -d" " -f-3; }
pw() { pwgen -1 -y --remove-chars=\~\`\"\'{}\(\)\[\]\*.\;\|,\<\> 22; }
-########################################################################
-# KERNEL STUFF
-########################################################################
-
-alias update-ksh="cd /usr/src/bin/ksh \
- && doas make clean \
- && doas make obj \
- && doas make -j $MAKE_JOBS \
- && doas make install"
-
########################################################################
# TWITCH FROM CLI
########################################################################
-alias twitch-play="mpv https://www.twitch.tv/c0dev0id"
-twitch-stream() {
+alias twitch_play="mpv https://www.twitch.tv/c0dev0id"
+twitch_stream() {
local API_KEY=$(pass Internet/Twitch | head -1)
local RES=$(xrandr | grep "*+" | awk '{print $1}')
local FAUX_OPTS="-d snd/default -m -vmic 5.0 -vmon 0.2 -r $RES -f 20 -b 4000"
fauxstream $FAUX_OPTS rtmp://live-ams.twitch.tv/app/$API_KEY
}
-########################################################################
-# DOTFILES WITH GIT
-########################################################################
-
-alias config='git --git-dir=${HOME}/.cfg/ --work-tree=${HOME}'
-
-dotfiles_autoupdate() {
- config add -u && \
- config commit -m "Update $(date +"%Y-%m-%d %H:%M") \
- $(uname -s)/$(uname -m)-$(hostname -s)" && config push
-}
-
-dotfiles_init() {
- git --no-replace-objects clone --bare --depth 1 \
- _gitea@git.uugrn.org:sdk/dotfiles.git $HOME/.cfg;
- config config --local status.showUntrackedFiles no;
- config checkout -f
-}
-
-########################################################################
-# FILE SHARING
-########################################################################
-
-doupload-http() {
- [ ! -f "$1" ] && return 2
- chmod ugo+r "$1"
- _name=$(basename "$1");
- scp -r "$1" codevoid.de:/tmp
- ssh codevoid.de "doas mv /tmp/$_name /home/www/htdocs/http/$_name"
- echo "https://codevoid.de/h/$_name";
-}
-
-doupload-gopher() {
- [ ! -f "$1" ] && return 2
- chmod ugo+r "$1"
- _name=$(basename "$1");
- scp -r "$1" codevoid.de:/tmp
- ssh codevoid.de "doas mv /tmp/$_name /home/www/htdocs/gopher/p/$_name"
- case "$(file --mime-type -b "$1")" in
- image/*) S="I";;
- text/*) S="0";;
- message/*) S="0";;
- */x-shellscript) S="0";;
- */pgp-keys) S="0";;
- application/*) S="9";;
- esac
- echo "https://codevoid.de/$S/p/$_name";
- echo "gopher://codevoid.de/$S/p/$_name";
-}
-
-########################################################################
-# KSH COMPLETIONS
-########################################################################
-
-[ -f $HOME/.ksh-complete ] && . $HOME/.ksh-complete
-
diff --git a/.vim/autoload/pathogen.vim b/.vim/autoload/pathogen.vim
deleted file mode 100644
index 3582fbf..0000000
--- a/.vim/autoload/pathogen.vim
+++ /dev/null
@@ -1,264 +0,0 @@
-" pathogen.vim - path option manipulation
-" Maintainer: Tim Pope
-" Version: 2.4
-
-" Install in ~/.vim/autoload (or ~\vimfiles\autoload).
-"
-" For management of individually installed plugins in ~/.vim/bundle (or
-" ~\vimfiles\bundle), adding `execute pathogen#infect()` to the top of your
-" .vimrc is the only other setup necessary.
-"
-" The API is documented inline below.
-
-if exists("g:loaded_pathogen") || &cp
- finish
-endif
-let g:loaded_pathogen = 1
-
-" Point of entry for basic default usage. Give a relative path to invoke
-" pathogen#interpose() or an absolute path to invoke pathogen#surround().
-" Curly braces are expanded with pathogen#expand(): "bundle/{}" finds all
-" subdirectories inside "bundle" inside all directories in the runtime path.
-" If no arguments are given, defaults "bundle/{}", and also "pack/{}/start/{}"
-" on versions of Vim without native package support.
-function! pathogen#infect(...) abort
- if a:0
- let paths = filter(reverse(copy(a:000)), 'type(v:val) == type("")')
- else
- let paths = ['bundle/{}', 'pack/{}/start/{}']
- endif
- if has('packages')
- call filter(paths, 'v:val !~# "^pack/[^/]*/start/[^/]*$"')
- endif
- let static = '^\%([$~\\/]\|\w:[\\/]\)[^{}*]*$'
- for path in filter(copy(paths), 'v:val =~# static')
- call pathogen#surround(path)
- endfor
- for path in filter(copy(paths), 'v:val !~# static')
- if path =~# '^\%([$~\\/]\|\w:[\\/]\)'
- call pathogen#surround(path)
- else
- call pathogen#interpose(path)
- endif
- endfor
- call pathogen#cycle_filetype()
- if pathogen#is_disabled($MYVIMRC)
- return 'finish'
- endif
- return ''
-endfunction
-
-" Split a path into a list.
-function! pathogen#split(path) abort
- if type(a:path) == type([]) | return a:path | endif
- if empty(a:path) | return [] | endif
- let split = split(a:path,'\\\@]','\\&','')
- endif
-endfunction
-
-" Like findfile(), but hardcoded to use the runtimepath.
-function! pathogen#runtime_findfile(file,count) abort
- let rtp = pathogen#join(1,pathogen#split(&rtp))
- let file = findfile(a:file,rtp,a:count)
- if file ==# ''
- return ''
- else
- return fnamemodify(file,':p')
- endif
-endfunction
-
-" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=':
diff --git a/.vim/bundle/vim-cool/LICENSE b/.vim/bundle/vim-cool/LICENSE
deleted file mode 100644
index 0d48cca..0000000
--- a/.vim/bundle/vim-cool/LICENSE
+++ /dev/null
@@ -1,22 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016 Romain Lafourcade
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
diff --git a/.vim/bundle/vim-cool/README.md b/.vim/bundle/vim-cool/README.md
deleted file mode 100644
index 8d6ef04..0000000
--- a/.vim/bundle/vim-cool/README.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# vim-cool
-
-Vim-cool disables search highlighting when you are done searching and re-enables it when you search again. That's it. No more `:noh`, no more `/sytdstdrsid`, and no more dodgy `` mappings.
-
-Vim-cool is cool.
-
-Vim-cool is *experimental*.
-
-![cool](https://user-images.githubusercontent.com/344335/226825463-4ff5e352-ac2e-4f4d-94c7-a8109da7b6db.gif)
-
-## Requirements
-
-Vim-cool is intended to be used with Vim, **and only Vim**, 7.4.2008 or later. It may or may not work in other editors but they are not and will not be officially supported.
-
-## Installation
-
-Follow your favorite plugin/runtimepath manager's instructions.
-
-If you choose manual installation, just put `plugin/cool.vim` where it belongs:
-
- $HOME/.vim/plugin/cool.vim on Unix-like systems
- $HOME\vimfiles\plugin\cool.vim on Windows
-
-In Vim 8.0 and above, see `:help package`.
-
-## Setup
-
-The whole assumption behind Vim-cool is that the user enabled search highlighting but they don't want the highlighting to linger on when they are done searching. This implies that the user has the following line in their `vimrc`:
-
- set hlsearch
-
-That's it. Nothing else to do.
-
-## Experimental features
-
-* Show number of matches in the command-line:
-
- let g:cool_total_matches = 1
-
- ![demo](https://user-images.githubusercontent.com/344335/226825418-12931cf3-5f89-4375-89be-c98a57e177df.png)
-
-* Do something when we are doing `nnnNNnn`, do something else or do nothing when we are not:
-
- set statusline+=%{get(g:,'cool_is_searching',0)?'Yep':''}
-
-## Background
-
-I wrote the first iteration of vim-cool in about twenty minutes, mostly to test a few ideas I had after a short discussion about `'hlsearch'` and `:nohlsearch` on #vim.
-
-Because it relied almost exclusively on mappings, that first iteration was way too brittle to be of any use and actually messed with a bunch of my own mappings.
-
-Then came [@purpleP](https://github.com/purpleP) and [the game-changing approach](https://github.com/romainl/vim-cool/issues/9) he put together with the help of [@chrisbra](https://github.com/chrisbra), [@justinmk](https://github.com/justinmk), [@jamessan](https://github.com/jamessan), and [@ZyX-I](https://github.com/ZyX-I).
-
-The current version, essentially a weaponized version of @purpleP's code, doesn't rely on mappings anymore and thus should be devoid of nasty side-effects.
-
-Many thanks to [@bounceme](https://github.com/bounceme) for his help.
-
-## What they say about vim-cool
-
-- **puremourning**, in #vim:
-
- > vim-cool is by far my favourite plugin
- >
- > it's just so... cool.
diff --git a/.vim/bundle/vim-cool/plugin/cool.vim b/.vim/bundle/vim-cool/plugin/cool.vim
deleted file mode 100644
index 1c40b45..0000000
--- a/.vim/bundle/vim-cool/plugin/cool.vim
+++ /dev/null
@@ -1,136 +0,0 @@
-" vim-cool - Disable hlsearch when you are done searching.
-" Maintainer: romainl
-" Version: 0.0.2
-" License: MIT License
-" Location: plugin/cool.vim
-" Website: https://github.com/romainl/vim-cool
-
-if exists("g:loaded_cool") || v:version < 704 || &compatible
- finish
-endif
-let g:loaded_cool = 1
-
-let s:save_cpo = &cpo
-set cpo&vim
-
-augroup Cool
- autocmd!
-augroup END
-
-if exists('##OptionSet')
- if !exists('*execute')
- autocmd Cool OptionSet highlight let saveh = &highlight
- endif
- " toggle coolness when hlsearch is toggled
- autocmd Cool OptionSet hlsearch call PlayItCool(v:option_old, v:option_new)
-endif
-
-function! s:StartHL()
- if !v:hlsearch || mode() isnot 'n'
- return
- endif
- let g:cool_is_searching = 1
- let [pos, rpos] = [winsaveview(), getpos('.')]
- silent! exe "keepjumps go".(line2byte('.')+col('.')-(v:searchforward ? 2 : 0))
- try
- silent keepjumps norm! n
- if getpos('.') != rpos
- throw 0
- endif
- catch /^\%(0$\|Vim\%(\w\|:Interrupt$\)\@!\)/
- call StopHL()
- return
- finally
- call winrestview(pos)
- endtry
- if !get(g:,'cool_total_matches') || !exists('*reltimestr')
- return
- endif
- exe "silent! norm! :let g:cool_char=nr2char(screenchar(screenrow(),1))\"
- let cool_char = remove(g:,'cool_char')
- if cool_char !~ '[/?]'
- return
- endif
- let [f, ws, now, noOf] = [0, &wrapscan, reltime(), [0,0]]
- set nowrapscan
- try
- while f < 2
- if reltimestr(reltime(now))[:-6] =~ '[1-9]'
- " time >= 100ms
- return
- endif
- let noOf[v:searchforward ? f : !f] += 1
- try
- silent exe "keepjumps norm! ".(f ? 'n' : 'N')
- catch /^Vim[^)]\+):E38[45]\D/
- call setpos('.',rpos)
- let f += 1
- endtry
- endwhile
- finally
- call winrestview(pos)
- let &wrapscan = ws
- endtry
- redraw|echo cool_char.@/ 'match' noOf[0] 'of' noOf[0] + noOf[1] - 1
-endfunction
-
-function! s:StopHL()
- if !v:hlsearch || mode() isnot 'n'
- return
- else
- let g:cool_is_searching = 0
- silent call feedkeys("\(StopHL)", 'm')
- endif
-endfunction
-
-if !exists('*execute')
- let s:saveh = &highlight
- " toggle highlighting, a workaround for :nohlsearch in autocmds
- function! s:AuNohlsearch()
- noautocmd set highlight+=l:-
- autocmd Cool Insertleave *
- \ noautocmd let &highlight = s:saveh | autocmd! Cool InsertLeave *
- return ''
- endfunction
-endif
-
-function! s:PlayItCool(old, new)
- if a:old == 0 && a:new == 1
- " nohls --> hls
- " set up coolness
- noremap (StopHL) :nohlsearch
- if !exists('*execute')
- noremap! (StopHL) AuNohlsearch()
-
- " If no "execute()", ":tnoremap" isn't probably implemented too.
- else
- noremap! (StopHL) execute('nohlsearch')[-1]
- if exists(':tnoremap')
- tnoremap (StopHL) execute('nohlsearch')[-1]
- endif
- endif
-
- autocmd Cool CursorMoved * call StartHL()
- autocmd Cool InsertEnter * call StopHL()
- elseif a:old == 1 && a:new == 0
- " hls --> nohls
- " tear down coolness
- nunmap (StopHL)
- unmap! (StopHL)
- if exists(':tunmap')
- tunmap (StopHL)
- endif
-
- autocmd! Cool CursorMoved
- autocmd! Cool InsertEnter
- else
- " nohls --> nohls
- " do nothing
- return
- endif
-endfunction
-
-" play it cool
-call PlayItCool(0, &hlsearch)
-
-let &cpo = s:save_cpo
diff --git a/.vim/bundle/vim-easy-align/autoload/easy_align.vim b/.vim/bundle/vim-easy-align/autoload/easy_align.vim
deleted file mode 100644
index 795ea31..0000000
--- a/.vim/bundle/vim-easy-align/autoload/easy_align.vim
+++ /dev/null
@@ -1,1148 +0,0 @@
-" Copyright (c) 2014 Junegunn Choi
-"
-" MIT License
-"
-" Permission is hereby granted, free of charge, to any person obtaining
-" a copy of this software and associated documentation files (the
-" "Software"), to deal in the Software without restriction, including
-" without limitation the rights to use, copy, modify, merge, publish,
-" distribute, sublicense, and/or sell copies of the Software, and to
-" permit persons to whom the Software is furnished to do so, subject to
-" the following conditions:
-"
-" The above copyright notice and this permission notice shall be
-" included in all copies or substantial portions of the Software.
-"
-" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-if exists("g:loaded_easy_align")
- finish
-endif
-let g:loaded_easy_align = 1
-
-let s:cpo_save = &cpo
-set cpo&vim
-
-let s:easy_align_delimiters_default = {
-\ ' ': { 'pattern': ' ', 'left_margin': 0, 'right_margin': 0, 'stick_to_left': 0 },
-\ '=': { 'pattern': '===\|<=>\|\(&&\|||\|<<\|>>\)=\|=\~[#?]\?\|=>\|[:+/*!%^=><&|.?-]\?=[#?]\?',
-\ 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 },
-\ ':': { 'pattern': ':', 'left_margin': 0, 'right_margin': 1, 'stick_to_left': 1 },
-\ ',': { 'pattern': ',', 'left_margin': 0, 'right_margin': 1, 'stick_to_left': 1 },
-\ '|': { 'pattern': '|', 'left_margin': 1, 'right_margin': 1, 'stick_to_left': 0 },
-\ '.': { 'pattern': '\.', 'left_margin': 0, 'right_margin': 0, 'stick_to_left': 0 },
-\ '#': { 'pattern': '#\+', 'delimiter_align': 'l', 'ignore_groups': ['!Comment'] },
-\ '"': { 'pattern': '"\+', 'delimiter_align': 'l', 'ignore_groups': ['!Comment'] },
-\ '&': { 'pattern': '\\\@ winlen ? '..' : ''
-
- echon "\r"
- let yet = 0
- for [hl, msg] in a:tokens
- if empty(msg) | continue | endif
- execute "echohl ". hl
- let yet += len(msg)
- if yet > winlen - len(ellipsis)
- echon msg[ 0 : (winlen - len(ellipsis) - yet - 1) ] . ellipsis
- break
- else
- echon msg
- endif
- endfor
- finally
- echohl None
- let [&ruler, &showcmd] = xy
- endtry
-endfunction
-
-function! s:echon(l, n, r, d, o, warn)
- let tokens = [
- \ ['Function', s:live ? ':LiveEasyAlign' : ':EasyAlign'],
- \ ['ModeMsg', get(s:mode_labels, a:l, a:l)],
- \ ['None', ' ']]
-
- if a:r == -1 | call add(tokens, ['Comment', '(']) | endif
- call add(tokens, [a:n =~ '*' ? 'Repeat' : 'Number', a:n])
- call extend(tokens, a:r == 1 ?
- \ [['Delimiter', '/'], ['String', a:d], ['Delimiter', '/']] :
- \ [['Identifier', a:d == ' ' ? '\ ' : (a:d == '\' ? '\\' : a:d)]])
- if a:r == -1 | call extend(tokens, [['Normal', '_'], ['Comment', ')']]) | endif
- call add(tokens, ['Statement', empty(a:o) ? '' : ' '.string(a:o)])
- if !empty(a:warn)
- call add(tokens, ['WarningMsg', ' ('.a:warn.')'])
- endif
-
- call s:echon_(tokens)
- return join(map(tokens, 'v:val[1]'), '')
-endfunction
-
-function! s:exit(msg)
- call s:echon_([['ErrorMsg', a:msg]])
- throw 'exit'
-endfunction
-
-function! s:ltrim(str)
- return substitute(a:str, '^\s\+', '', '')
-endfunction
-
-function! s:rtrim(str)
- return substitute(a:str, '\s\+$', '', '')
-endfunction
-
-function! s:trim(str)
- return substitute(a:str, '^\s*\(.\{-}\)\s*$', '\1', '')
-endfunction
-
-function! s:fuzzy_lu(key)
- if has_key(s:known_options, a:key)
- return a:key
- endif
- let key = tolower(a:key)
-
- " stl -> ^s.*_t.*_l.*
- let regexp1 = '^' .key[0]. '.*' .substitute(key[1 : -1], '\(.\)', '_\1.*', 'g')
- let matches = filter(keys(s:known_options), 'v:val =~ regexp1')
- if len(matches) == 1
- return matches[0]
- endif
-
- " stl -> ^s.*t.*l.*
- let regexp2 = '^' . substitute(substitute(key, '-', '_', 'g'), '\(.\)', '\1.*', 'g')
- let matches = filter(keys(s:known_options), 'v:val =~ regexp2')
-
- if empty(matches)
- call s:exit("Unknown option key: ". a:key)
- elseif len(matches) == 1
- return matches[0]
- else
- " Avoid ambiguity introduced by deprecated margin_left and margin_right
- if sort(matches) == ['margin_left', 'margin_right', 'mode_sequence']
- return 'mode_sequence'
- endif
- if sort(matches) == ['ignore_groups', 'ignores']
- return 'ignore_groups'
- endif
- call s:exit("Ambiguous option key: ". a:key ." (" .join(matches, ', '). ")")
- endif
-endfunction
-
-function! s:shift(modes, cycle)
- let item = remove(a:modes, 0)
- if a:cycle || empty(a:modes)
- call add(a:modes, item)
- endif
- return item
-endfunction
-
-function! s:normalize_options(opts)
- let ret = {}
- for k in keys(a:opts)
- let v = a:opts[k]
- let k = s:fuzzy_lu(k)
- " Backward-compatibility
- if k == 'margin_left' | let k = 'left_margin' | endif
- if k == 'margin_right' | let k = 'right_margin' | endif
- if k == 'mode_sequence' | let k = 'align' | endif
- let ret[k] = v
- unlet v
- endfor
- return s:validate_options(ret)
-endfunction
-
-function! s:compact_options(opts)
- let ret = {}
- for k in keys(a:opts)
- let ret[s:shorthand[k]] = a:opts[k]
- endfor
- return ret
-endfunction
-
-function! s:validate_options(opts)
- for k in keys(a:opts)
- let v = a:opts[k]
- if index(s:known_options[k], type(v)) == -1
- call s:exit("Invalid type for option: ". k)
- endif
- unlet v
- endfor
- return a:opts
-endfunction
-
-function! s:split_line(line, nth, modes, cycle, fc, lc, pattern, stick_to_left, ignore_unmatched, ignore_groups)
- let mode = ''
-
- let string = a:lc ?
- \ strpart(getline(a:line), a:fc - 1, a:lc - a:fc + 1) :
- \ strpart(getline(a:line), a:fc - 1)
- let idx = 0
- let nomagic = match(a:pattern, '\\v') > match(a:pattern, '\C\\[mMV]')
- let pattern = '^.\{-}\s*\zs\('.a:pattern.(nomagic ? ')' : '\)')
- let tokens = []
- let delims = []
-
- " Phase 1: split
- let ignorable = 0
- let token = ''
- let phantom = 0
- while 1
- let matchidx = match(string, pattern, idx)
- " No match
- if matchidx < 0 | break | endif
- let matchend = matchend(string, pattern, idx)
- let spaces = matchstr(string, '\s'.(a:stick_to_left ? '*' : '\{-}'), matchend + (matchidx == matchend))
-
- " Match, but empty
- if len(spaces) + matchend - idx == 0
- let char = strpart(string, idx, 1)
- if empty(char) | break | endif
- let [match, part, delim] = [char, char, '']
- " Match
- else
- let match = strpart(string, idx, matchend - idx + len(spaces))
- let part = strpart(string, idx, matchidx - idx)
- let delim = strpart(string, matchidx, matchend - matchidx)
- endif
-
- let ignorable = s:highlighted_as(a:line, idx + len(part) + a:fc, a:ignore_groups)
- if ignorable
- let token .= match
- else
- let [pmode, mode] = [mode, s:shift(a:modes, a:cycle)]
- call add(tokens, token . match)
- call add(delims, delim)
- let token = ''
- endif
-
- let idx += len(match)
-
- " If the string is non-empty and ends with the delimiter,
- " append an empty token to the list
- if idx == len(string)
- let phantom = 1
- break
- endif
- endwhile
-
- let leftover = token . strpart(string, idx)
- if !empty(leftover)
- let ignorable = s:highlighted_as(a:line, len(string) + a:fc - 1, a:ignore_groups)
- call add(tokens, leftover)
- call add(delims, '')
- elseif phantom
- call add(tokens, '')
- call add(delims, '')
- endif
- let [pmode, mode] = [mode, s:shift(a:modes, a:cycle)]
-
- " Preserve indentation - merge first two tokens
- if len(tokens) > 1 && empty(s:rtrim(tokens[0]))
- let tokens[1] = tokens[0] . tokens[1]
- call remove(tokens, 0)
- call remove(delims, 0)
- let mode = pmode
- endif
-
- " Skip comment line
- if ignorable && len(tokens) == 1 && a:ignore_unmatched
- let tokens = []
- let delims = []
- " Append an empty item to enable right/center alignment of the last token
- " - if the last token is not ignorable or ignorable but not the only token
- elseif a:ignore_unmatched != 1 &&
- \ (mode ==? 'r' || mode ==? 'c') &&
- \ (!ignorable || len(tokens) > 1) &&
- \ a:nth >= 0 " includes -0
- call add(tokens, '')
- call add(delims, '')
- endif
-
- return [tokens, delims]
-endfunction
-
-function! s:do_align(todo, modes, all_tokens, all_delims, fl, ll, fc, lc, nth, recur, dict)
- let mode = a:modes[0]
- let lines = {}
- let min_indent = -1
- let max = { 'pivot_len2': 0, 'token_len': 0, 'just_len': 0, 'delim_len': 0,
- \ 'indent': 0, 'tokens': 0, 'strip_len': 0 }
- let d = a:dict
- let [f, fx] = s:parse_filter(d.filter)
-
- " Phase 1
- for line in range(a:fl, a:ll)
- let snip = a:lc > 0 ? getline(line)[a:fc-1 : a:lc-1] : getline(line)
- if f == 1 && snip !~ fx
- continue
- elseif f == -1 && snip =~ fx
- continue
- endif
-
- if !has_key(a:all_tokens, line)
- " Split line into the tokens by the delimiters
- let [tokens, delims] = s:split_line(
- \ line, a:nth, copy(a:modes), a:recur == 2,
- \ a:fc, a:lc, d.pattern,
- \ d.stick_to_left, d.ignore_unmatched, d.ignore_groups)
-
- " Remember tokens for subsequent recursive calls
- let a:all_tokens[line] = tokens
- let a:all_delims[line] = delims
- else
- let tokens = a:all_tokens[line]
- let delims = a:all_delims[line]
- endif
-
- " Skip empty lines
- if empty(tokens)
- continue
- endif
-
- " Calculate the maximum number of tokens for a line within the range
- let max.tokens = max([max.tokens, len(tokens)])
-
- if a:nth > 0 " Positive N-th
- if len(tokens) < a:nth
- continue
- endif
- let nth = a:nth - 1 " make it 0-based
- else " -0 or Negative N-th
- if a:nth == 0 && mode !=? 'l'
- let nth = len(tokens) - 1
- else
- let nth = len(tokens) + a:nth
- endif
- if empty(delims[len(delims) - 1])
- let nth -= 1
- endif
-
- if nth < 0 || nth == len(tokens)
- continue
- endif
- endif
-
- let prefix = nth > 0 ? join(tokens[0 : nth - 1], '') : ''
- let delim = delims[nth]
- let token = s:rtrim( tokens[nth] )
- let token = s:rtrim( strpart(token, 0, len(token) - len(s:rtrim(delim))) )
- if empty(delim) && !exists('tokens[nth + 1]') && d.ignore_unmatched
- continue
- endif
-
- let indent = s:strwidth(matchstr(tokens[0], '^\s*'))
- if min_indent < 0 || indent < min_indent
- let min_indent = indent
- endif
- if mode ==? 'c'
- let token .= substitute(matchstr(token, '^\s*'), '\t', repeat(' ', &tabstop), 'g')
- endif
- let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
- let max.indent = max([max.indent, indent])
- let max.token_len = max([max.token_len, tw])
- let max.just_len = max([max.just_len, pw + tw])
- let max.delim_len = max([max.delim_len, s:strwidth(delim)])
-
- if mode ==? 'c'
- let pivot_len2 = pw * 2 + tw
- if max.pivot_len2 < pivot_len2
- let max.pivot_len2 = pivot_len2
- endif
- let max.strip_len = max([max.strip_len, s:strwidth(s:trim(token))])
- endif
- let lines[line] = [nth, prefix, token, delim]
- endfor
-
- " Phase 1-5: indentation handling (only on a:nth == 1)
- if a:nth == 1
- let idt = d.indentation
- if idt ==? 'd'
- let indent = max.indent
- elseif idt ==? 's'
- let indent = min_indent
- elseif idt ==? 'n'
- let indent = 0
- elseif idt !=? 'k'
- call s:exit('Invalid indentation: ' . idt)
- end
-
- if idt !=? 'k'
- let max.just_len = 0
- let max.token_len = 0
- let max.pivot_len2 = 0
-
- for [line, elems] in items(lines)
- let [nth, prefix, token, delim] = elems
-
- let tindent = matchstr(token, '^\s*')
- while 1
- let len = s:strwidth(tindent)
- if len < indent
- let tindent .= repeat(' ', indent - len)
- break
- elseif len > indent
- let tindent = tindent[0 : -2]
- else
- break
- endif
- endwhile
-
- let token = tindent . s:ltrim(token)
- if mode ==? 'c'
- let token = substitute(token, '\s*$', repeat(' ', indent), '')
- endif
- let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
- let max.token_len = max([max.token_len, tw])
- let max.just_len = max([max.just_len, pw + tw])
- if mode ==? 'c'
- let pivot_len2 = pw * 2 + tw
- if max.pivot_len2 < pivot_len2
- let max.pivot_len2 = pivot_len2
- endif
- endif
-
- let lines[line][2] = token
- endfor
- endif
- endif
-
- " Phase 2
- for [line, elems] in items(lines)
- let tokens = a:all_tokens[line]
- let delims = a:all_delims[line]
- let [nth, prefix, token, delim] = elems
-
- " Remove the leading whitespaces of the next token
- if len(tokens) > nth + 1
- let tokens[nth + 1] = s:ltrim(tokens[nth + 1])
- endif
-
- " Pad the token with spaces
- let [pw, tw] = [s:strwidth(prefix), s:strwidth(token)]
- let rpad = ''
- if mode ==? 'l'
- let pad = repeat(' ', max.just_len - pw - tw)
- if d.stick_to_left
- let rpad = pad
- else
- let token = token . pad
- endif
- elseif mode ==? 'r'
- let pad = repeat(' ', max.just_len - pw - tw)
- let indent = matchstr(token, '^\s*')
- let token = indent . pad . s:ltrim(token)
- elseif mode ==? 'c'
- let p1 = max.pivot_len2 - (pw * 2 + tw)
- let p2 = max.token_len - tw
- let pf1 = s:floor2(p1)
- if pf1 < p1 | let p2 = s:ceil2(p2)
- else | let p2 = s:floor2(p2)
- endif
- let strip = s:ceil2(max.token_len - max.strip_len) / 2
- let indent = matchstr(token, '^\s*')
- let token = indent. repeat(' ', pf1 / 2) .s:ltrim(token). repeat(' ', p2 / 2)
- let token = substitute(token, repeat(' ', strip) . '$', '', '')
-
- if d.stick_to_left
- if empty(s:rtrim(token))
- let center = len(token) / 2
- let [token, rpad] = [strpart(token, 0, center), strpart(token, center)]
- else
- let [token, rpad] = [s:rtrim(token), matchstr(token, '\s*$')]
- endif
- endif
- endif
- let tokens[nth] = token
-
- " Pad the delimiter
- let dpadl = max.delim_len - s:strwidth(delim)
- let da = d.delimiter_align
- if da ==? 'l'
- let [dl, dr] = ['', repeat(' ', dpadl)]
- elseif da ==? 'c'
- let dl = repeat(' ', dpadl / 2)
- let dr = repeat(' ', dpadl - dpadl / 2)
- elseif da ==? 'r'
- let [dl, dr] = [repeat(' ', dpadl), '']
- else
- call s:exit('Invalid delimiter_align: ' . da)
- endif
-
- " Before and after the range (for blockwise visual mode)
- let cline = getline(line)
- let before = strpart(cline, 0, a:fc - 1)
- let after = a:lc ? strpart(cline, a:lc) : ''
-
- " Determine the left and right margin around the delimiter
- let rest = join(tokens[nth + 1 : -1], '')
- let nomore = empty(rest.after)
- let ml = (empty(prefix . token) || empty(delim) && nomore) ? '' : d.ml
- let mr = nomore ? '' : d.mr
-
- " Adjust indentation of the lines starting with a delimiter
- let lpad = ''
- if nth == 0
- let ipad = repeat(' ', min_indent - s:strwidth(token.ml))
- if mode ==? 'l'
- let token = ipad . token
- else
- let lpad = ipad
- endif
- endif
-
- " Align the token
- let aligned = join([lpad, token, ml, dl, delim, dr, mr, rpad], '')
- let tokens[nth] = aligned
-
- " Update the line
- let a:todo[line] = before.join(tokens, '').after
- endfor
-
- if a:nth < max.tokens && (a:recur || len(a:modes) > 1)
- call s:shift(a:modes, a:recur == 2)
- return [a:todo, a:modes, a:all_tokens, a:all_delims,
- \ a:fl, a:ll, a:fc, a:lc, a:nth + 1, a:recur, a:dict]
- endif
- return [a:todo]
-endfunction
-
-function! s:input(str, default, vis)
- if a:vis
- normal! gv
- redraw
- execute "normal! \"
- else
- " EasyAlign command can be called without visual selection
- redraw
- endif
- let got = input(a:str, a:default)
- return got
-endfunction
-
-function! s:atoi(str)
- return (a:str =~ '^[0-9]\+$') ? str2nr(a:str) : a:str
-endfunction
-
-function! s:shift_opts(opts, key, vals)
- let val = s:shift(a:vals, 1)
- if type(val) == 0 && val == -1
- call remove(a:opts, a:key)
- else
- let a:opts[a:key] = val
- endif
-endfunction
-
-function! s:interactive(range, modes, n, d, opts, rules, vis, bvis)
- let mode = s:shift(a:modes, 1)
- let n = a:n
- let d = a:d
- let ch = ''
- let opts = s:compact_options(a:opts)
- let vals = deepcopy(s:option_values)
- let regx = 0
- let warn = ''
- let undo = 0
-
- while 1
- " Live preview
- let rdrw = 0
- if undo
- silent! undo
- let undo = 0
- let rdrw = 1
- endif
- if s:live && !empty(d)
- let output = s:process(a:range, mode, n, d, s:normalize_options(opts), regx, a:rules, a:bvis)
- let &undolevels = &undolevels " Break undo block
- call s:update_lines(output.todo)
- let undo = !empty(output.todo)
- let rdrw = 1
- endif
- if rdrw
- if a:vis
- normal! gv
- endif
- redraw
- if a:vis | execute "normal! \" | endif
- endif
- call s:echon(mode, n, -1, regx ? '/'.d.'/' : d, opts, warn)
-
- let check = 0
- let warn = ''
-
- try
- let c = getchar()
- catch /^Vim:Interrupt$/
- let c = 27
- endtry
- let ch = nr2char(c)
- if c == 3 || c == 27 " CTRL-C / ESC
- if undo
- silent! undo
- endif
- throw 'exit'
- elseif c == "\"
- if !empty(d)
- let d = ''
- let regx = 0
- elseif len(n) > 0
- let n = strpart(n, 0, len(n) - 1)
- endif
- elseif c == 13 " Enter key
- let mode = s:shift(a:modes, 1)
- if has_key(opts, 'a')
- let opts.a = mode . strpart(opts.a, 1)
- endif
- elseif ch == '-'
- if empty(n) | let n = '-'
- elseif n == '-' | let n = ''
- else | let check = 1
- endif
- elseif ch == '*'
- if empty(n) | let n = '*'
- elseif n == '*' | let n = '**'
- elseif n == '**' | let n = ''
- else | let check = 1
- endif
- elseif empty(d) && ((c == 48 && len(n) > 0) || c > 48 && c <= 57) " Numbers
- if n[0] == '*' | let check = 1
- else | let n = n . ch
- end
- elseif ch == "\"
- call s:shift_opts(opts, 'da', vals['delimiter_align'])
- elseif ch == "\"
- call s:shift_opts(opts, 'idt', vals['indentation'])
- elseif ch == "\"
- let lm = s:input("Left margin: ", get(opts, 'lm', ''), a:vis)
- if empty(lm)
- let warn = 'Set to default. Input 0 to remove it'
- silent! call remove(opts, 'lm')
- else
- let opts['lm'] = s:atoi(lm)
- endif
- elseif ch == "\"
- let rm = s:input("Right margin: ", get(opts, 'rm', ''), a:vis)
- if empty(rm)
- let warn = 'Set to default. Input 0 to remove it'
- silent! call remove(opts, 'rm')
- else
- let opts['rm'] = s:atoi(rm)
- endif
- elseif ch == "\"
- call s:shift_opts(opts, 'iu', vals['ignore_unmatched'])
- elseif ch == "\"
- call s:shift_opts(opts, 'ig', vals['ignore_groups'])
- elseif ch == "\"
- if s:live
- if !empty(d)
- let ch = d
- break
- else
- let s:live = 0
- endif
- else
- let s:live = 1
- endif
- elseif c == "\"
- let opts['stl'] = 1
- let opts['lm'] = 0
- elseif c == "\"
- let opts['stl'] = 0
- let opts['lm'] = 1
- elseif c == "\"
- let opts['lm'] = 0
- let opts['rm'] = 0
- elseif c == "\"
- silent! call remove(opts, 'stl')
- silent! call remove(opts, 'lm')
- silent! call remove(opts, 'rm')
- elseif ch == "\" || ch == "\"
- let modes = tolower(s:input("Alignment ([lrc...][[*]*]): ", get(opts, 'a', mode), a:vis))
- if match(modes, '^[lrc]\+\*\{0,2}$') != -1
- let opts['a'] = modes
- let mode = modes[0]
- while mode != s:shift(a:modes, 1)
- endwhile
- else
- silent! call remove(opts, 'a')
- endif
- elseif ch == "\" || ch == "\"
- if s:live && regx && !empty(d)
- break
- endif
-
- let prompt = 'Regular expression: '
- let ch = s:input(prompt, '', a:vis)
- if !empty(ch) && s:valid_regexp(ch)
- let regx = 1
- let d = ch
- if !s:live | break | endif
- else
- let warn = 'Invalid regular expression: '.ch
- endif
- elseif ch == "\"
- let f = s:input("Filter (g/../ or v/../): ", get(opts, 'f', ''), a:vis)
- let m = matchlist(f, '^[gv]/\(.\{-}\)/\?$')
- if empty(f)
- silent! call remove(opts, 'f')
- elseif !empty(m) && s:valid_regexp(m[1])
- let opts['f'] = f
- else
- let warn = 'Invalid filter expression'
- endif
- elseif ch =~ '[[:print:]]'
- let check = 1
- else
- let warn = 'Invalid character'
- endif
-
- if check
- if empty(d)
- if has_key(a:rules, ch)
- let d = ch
- if !s:live
- if a:vis
- execute "normal! gv\"
- endif
- break
- endif
- else
- let warn = 'Unknown delimiter key: '.ch
- endif
- else
- if regx
- let warn = 'Press to finish'
- else
- if d == ch
- break
- else
- let warn = 'Press '''.d.''' again to finish'
- endif
- end
- endif
- endif
- endwhile
- if s:live
- let copts = call('s:summarize', output.summarize)
- let s:live = 0
- let g:easy_align_last_command = s:echon('', n, regx, d, copts, '')
- let s:live = 1
- end
- return [mode, n, ch, opts, regx]
-endfunction
-
-function! s:valid_regexp(regexp)
- try
- call matchlist('', a:regexp)
- catch
- return 0
- endtry
- return 1
-endfunction
-
-function! s:test_regexp(regexp)
- let regexp = empty(a:regexp) ? @/ : a:regexp
- if !s:valid_regexp(regexp)
- call s:exit('Invalid regular expression: '. regexp)
- endif
- return regexp
-endfunction
-
-let s:shorthand_regex =
- \ '\s*\%('
- \ .'\(lm\?[0-9]\+\)\|\(rm\?[0-9]\+\)\|\(iu[01]\)\|\(\%(s\%(tl\)\?[01]\)\|[<>]\)\|'
- \ .'\(da\?[clr]\)\|\(\%(ms\?\|a\)[lrc*]\+\)\|\(i\%(dt\)\?[kdsn]\)\|\([gv]/.*/\)\|\(ig\[.*\]\)'
- \ .'\)\+\s*$'
-
-function! s:parse_shorthand_opts(expr)
- let opts = {}
- let expr = substitute(a:expr, '\s', '', 'g')
- let regex = '^'. s:shorthand_regex
-
- if empty(expr)
- return opts
- elseif expr !~ regex
- call s:exit("Invalid expression: ". a:expr)
- else
- let match = matchlist(expr, regex)
- for m in filter(match[ 1 : -1 ], '!empty(v:val)')
- for key in ['lm', 'rm', 'l', 'r', 'stl', 's', '<', '>', 'iu', 'da', 'd', 'ms', 'm', 'ig', 'i', 'g', 'v', 'a']
- if stridx(tolower(m), key) == 0
- let rest = strpart(m, len(key))
- if key == 'i' | let key = 'idt' | endif
- if key == 'g' || key == 'v'
- let rest = key.rest
- let key = 'f'
- endif
-
- if key == 'idt' || index(['d', 'f', 'm', 'a'], key[0]) >= 0
- let opts[key] = rest
- elseif key == 'ig'
- try
- let arr = eval(rest)
- if type(arr) == 3
- let opts[key] = arr
- else
- throw 'Not an array'
- endif
- catch
- call s:exit("Invalid ignore_groups: ". a:expr)
- endtry
- elseif key =~ '[<>]'
- let opts['stl'] = key == '<'
- else
- let opts[key] = str2nr(rest)
- endif
- break
- endif
- endfor
- endfor
- endif
- return s:normalize_options(opts)
-endfunction
-
-function! s:parse_args(args)
- if empty(a:args)
- return ['', '', {}, 0]
- endif
- let n = ''
- let ch = ''
- let args = a:args
- let cand = ''
- let opts = {}
-
- " Poor man's option parser
- let idx = 0
- while 1
- let midx = match(args, '\s*{.*}\s*$', idx)
- if midx == -1 | break | endif
-
- let cand = strpart(args, midx)
- try
- let [l, r, c, k, s, d, n] = ['l', 'r', 'c', 'k', 's', 'd', 'n']
- let [L, R, C, K, S, D, N] = ['l', 'r', 'c', 'k', 's', 'd', 'n']
- let o = eval(cand)
- if type(o) == 4
- let opts = o
- if args[midx - 1 : midx] == '\ '
- let midx += 1
- endif
- let args = strpart(args, 0, midx)
- break
- endif
- catch
- " Ignore
- endtry
- let idx = midx + 1
- endwhile
-
- " Invalid option dictionary
- if len(substitute(cand, '\s', '', 'g')) > 2 && empty(opts)
- call s:exit("Invalid option: ". cand)
- else
- let opts = s:normalize_options(opts)
- endif
-
- " Shorthand option notation
- let sopts = matchstr(args, s:shorthand_regex)
- if !empty(sopts)
- let args = strpart(args, 0, len(args) - len(sopts))
- let opts = extend(s:parse_shorthand_opts(sopts), opts)
- endif
-
- " Has /Regexp/?
- let matches = matchlist(args, '^\(.\{-}\)\s*/\(.*\)/\s*$')
-
- " Found regexp
- if !empty(matches)
- return [matches[1], s:test_regexp(matches[2]), opts, 1]
- else
- let tokens = matchlist(args, '^\([1-9][0-9]*\|-[0-9]*\|\*\*\?\)\?\s*\(.\{-}\)\?$')
- " Try swapping n and ch
- let [n, ch] = empty(tokens[2]) ? reverse(tokens[1:2]) : tokens[1:2]
-
- " Resolving command-line ambiguity
- " '\ ' => ' '
- " '\' => ' '
- if ch =~ '^\\\s*$'
- let ch = ' '
- " '\\' => '\'
- elseif ch =~ '^\\\\\s*$'
- let ch = '\'
- endif
-
- return [n, ch, opts, 0]
- endif
-endfunction
-
-function! s:parse_filter(f)
- let m = matchlist(a:f, '^\([gv]\)/\(.\{-}\)/\?$')
- if empty(m)
- return [0, '']
- else
- return [m[1] == 'g' ? 1 : -1, m[2]]
- endif
-endfunction
-
-function! s:interactive_modes(bang)
- return get(g:,
- \ (a:bang ? 'easy_align_bang_interactive_modes' : 'easy_align_interactive_modes'),
- \ (a:bang ? ['r', 'l', 'c'] : ['l', 'r', 'c']))
-endfunction
-
-function! s:alternating_modes(mode)
- return a:mode ==? 'r' ? 'rl' : 'lr'
-endfunction
-
-function! s:update_lines(todo)
- for [line, content] in items(a:todo)
- call setline(line, s:rtrim(content))
- endfor
-endfunction
-
-function! s:parse_nth(n)
- let n = a:n
- let recur = 0
- if n == '*' | let [nth, recur] = [1, 1]
- elseif n == '**' | let [nth, recur] = [1, 2]
- elseif n == '-' | let nth = -1
- elseif empty(n) | let nth = 1
- elseif n == '0' || ( n != '-0' && n != string(str2nr(n)) )
- call s:exit('Invalid N-th parameter: '. n)
- else
- let nth = n
- endif
- return [nth, recur]
-endfunction
-
-function! s:build_dict(delimiters, ch, regexp, opts)
- if a:regexp
- let dict = { 'pattern': a:ch }
- else
- if !has_key(a:delimiters, a:ch)
- call s:exit('Unknown delimiter key: '. a:ch)
- endif
- let dict = copy(a:delimiters[a:ch])
- endif
- call extend(dict, a:opts)
-
- let ml = get(dict, 'left_margin', ' ')
- let mr = get(dict, 'right_margin', ' ')
- if type(ml) == 0 | let ml = repeat(' ', ml) | endif
- if type(mr) == 0 | let mr = repeat(' ', mr) | endif
- call extend(dict, { 'ml': ml, 'mr': mr })
-
- let dict.pattern = get(dict, 'pattern', a:ch)
- let dict.delimiter_align =
- \ get(dict, 'delimiter_align', get(g:, 'easy_align_delimiter_align', 'r'))[0]
- let dict.indentation =
- \ get(dict, 'indentation', get(g:, 'easy_align_indentation', 'k'))[0]
- let dict.stick_to_left =
- \ get(dict, 'stick_to_left', 0)
- let dict.ignore_unmatched =
- \ get(dict, 'ignore_unmatched', get(g:, 'easy_align_ignore_unmatched', 2))
- let dict.ignore_groups =
- \ get(dict, 'ignore_groups', get(dict, 'ignores', s:ignored_syntax()))
- let dict.filter =
- \ get(dict, 'filter', '')
- return dict
-endfunction
-
-function! s:build_mode_sequence(expr, recur)
- let [expr, recur] = [a:expr, a:recur]
- let suffix = matchstr(a:expr, '\*\+$')
- if suffix == '*'
- let expr = expr[0 : -2]
- let recur = 1
- elseif suffix == '**'
- let expr = expr[0 : -3]
- let recur = 2
- endif
- return [tolower(expr), recur]
-endfunction
-
-function! s:process(range, mode, n, ch, opts, regexp, rules, bvis)
- let [nth, recur] = s:parse_nth((empty(a:n) && exists('g:easy_align_nth')) ? g:easy_align_nth : a:n)
- let dict = s:build_dict(a:rules, a:ch, a:regexp, a:opts)
- let [mode_sequence, recur] = s:build_mode_sequence(
- \ get(dict, 'align', recur == 2 ? s:alternating_modes(a:mode) : a:mode),
- \ recur)
-
- let ve = &virtualedit
- set ve=all
- let args = [
- \ {}, split(mode_sequence, '\zs'),
- \ {}, {}, a:range[0], a:range[1],
- \ a:bvis ? min([virtcol("'<"), virtcol("'>")]) : 1,
- \ (!recur && a:bvis) ? max([virtcol("'<"), virtcol("'>")]) : 0,
- \ nth, recur, dict ]
- let &ve = ve
- while len(args) > 1
- let args = call('s:do_align', args)
- endwhile
-
- " todo: lines to update
- " summarize: arguments to s:summarize
- return { 'todo': args[0], 'summarize': [ a:opts, recur, mode_sequence ] }
-endfunction
-
-function s:summarize(opts, recur, mode_sequence)
- let copts = s:compact_options(a:opts)
- let nbmode = s:interactive_modes(0)[0]
- if !has_key(copts, 'a') && (
- \ (a:recur == 2 && s:alternating_modes(nbmode) != a:mode_sequence) ||
- \ (a:recur != 2 && (a:mode_sequence[0] != nbmode || len(a:mode_sequence) > 1))
- \ )
- call extend(copts, { 'a': a:mode_sequence })
- endif
- return copts
-endfunction
-
-function! s:align(bang, live, visualmode, first_line, last_line, expr)
- " Heuristically determine if the user was in visual mode
- if a:visualmode == 'command'
- let vis = a:first_line == line("'<") && a:last_line == line("'>")
- let bvis = vis && visualmode() == "\"
- elseif empty(a:visualmode)
- let vis = 0
- let bvis = 0
- else
- let vis = 1
- let bvis = a:visualmode == "\"
- end
- let range = [a:first_line, a:last_line]
- let modes = s:interactive_modes(a:bang)
- let mode = modes[0]
- let s:live = a:live
-
- let rules = s:easy_align_delimiters_default
- if exists('g:easy_align_delimiters')
- let rules = extend(copy(rules), g:easy_align_delimiters)
- endif
-
- let [n, ch, opts, regexp] = s:parse_args(a:expr)
-
- let bypass_fold = get(g:, 'easy_align_bypass_fold', 0)
- let ofm = &l:foldmethod
- try
- if bypass_fold | let &l:foldmethod = 'manual' | endif
-
- if empty(n) && empty(ch) || s:live
- let [mode, n, ch, opts, regexp] = s:interactive(range, copy(modes), n, ch, opts, rules, vis, bvis)
- endif
-
- if !s:live
- let output = s:process(range, mode, n, ch, s:normalize_options(opts), regexp, rules, bvis)
- call s:update_lines(output.todo)
- let copts = call('s:summarize', output.summarize)
- let g:easy_align_last_command = s:echon('', n, regexp, ch, copts, '')
- endif
- finally
- if bypass_fold | let &l:foldmethod = ofm | endif
- endtry
-endfunction
-
-function! easy_align#align(bang, live, visualmode, expr) range
- try
- call s:align(a:bang, a:live, a:visualmode, a:firstline, a:lastline, a:expr)
- catch /^\%(Vim:Interrupt\|exit\)$/
- if empty(a:visualmode)
- echon "\r"
- echon "\r"
- else
- normal! gv
- endif
- endtry
-endfunction
-
-let &cpo = s:cpo_save
-unlet s:cpo_save
-
diff --git a/.vim/bundle/vim-easy-align/doc/easy_align.txt b/.vim/bundle/vim-easy-align/doc/easy_align.txt
deleted file mode 100644
index 5a82e5e..0000000
--- a/.vim/bundle/vim-easy-align/doc/easy_align.txt
+++ /dev/null
@@ -1,891 +0,0 @@
-easy-align.txt easy-align Last change: December 14 2014
-EASY-ALIGN - TABLE OF CONTENTS *easyalign* *easy-align* *easy-align-toc*
-==============================================================================
-
- vim-easy-align
- Demo |easy-align-1|
- Features |easy-align-2|
- Installation |easy-align-3|
- TLDR - One-minute guide |easy-align-4|
- Usage |easy-align-5|
- Concept of alignment rule |easy-align-5-1|
- Execution models |easy-align-5-2|
- 1. Using mappings |easy-align-5-2-1|
- 2. Using :EasyAlign command |easy-align-5-2-2|
- Interactive mode |easy-align-5-3|
- Predefined alignment rules |easy-align-5-3-1|
- Examples |easy-align-5-3-2|
- Using regular expressions |easy-align-5-3-3|
- Alignment options in interactive mode |easy-align-5-3-4|
- Live interactive mode |easy-align-5-4|
- Non-interactive mode |easy-align-5-5|
- Partial alignment in blockwise-visual mode |easy-align-5-6|
- Alignment options |easy-align-6|
- List of options |easy-align-6-1|
- Filtering lines |easy-align-6-2|
- Examples |easy-align-6-2-1|
- Ignoring delimiters in comments or strings |easy-align-6-3|
- Ignoring unmatched lines |easy-align-6-4|
- Aligning delimiters of different lengths |easy-align-6-5|
- Adjusting indentation |easy-align-6-6|
- Alignments over multiple occurrences of delimiters |easy-align-6-7|
- Extending alignment rules |easy-align-6-8|
- Examples |easy-align-6-8-1|
- Other options |easy-align-7|
- Disabling &foldmethod during alignment |easy-align-7-1|
- Left/right/center mode switch in interactive mode |easy-align-7-2|
- Advanced examples and use cases |easy-align-8|
- Related work |easy-align-9|
- Author |easy-align-10|
- License |easy-align-11|
-
-
-VIM-EASY-ALIGN *vim-easy-align*
-==============================================================================
-
-A simple, easy-to-use Vim alignment plugin.
-
-
- *easy-align-1*
-DEMO *easy-align-demo*
-==============================================================================
-
-Screencast:
-https://raw.githubusercontent.com/junegunn/i/master/vim-easy-align.gif
-
-(Too fast? Slower GIF is {here}{1})
-
-{1} https://raw.githubusercontent.com/junegunn/i/master/vim-easy-align-slow.gif
-
-
- *easy-align-2*
-FEATURES *easy-align-features*
-==============================================================================
-
- - Easy to use
- - Comes with a predefined set of alignment rules
- - Provides a fast and intuitive interface
- - Extensible
- - You can define your own rules
- - Supports arbitrary regular expressions
- - Optimized for code editing
- - Takes advantage of syntax highlighting feature to avoid unwanted
- alignments
-
-
- *easy-align-3*
-INSTALLATION *easy-align-installation*
-==============================================================================
-
-Use your favorite plugin manager.
-
-Using {vim-plug}{2}:
->
- Plug 'junegunn/vim-easy-align'
-<
- {2} https://github.com/junegunn/vim-plug
-
-
- *easy-align-4*
-TLDR - ONE-MINUTE GUIDE *easy-align-tldr-one-minute-guide*
-==============================================================================
-
-Add the following mappings to your .vimrc.
-
- *(EasyAlign)*
->
- " Start interactive EasyAlign in visual mode (e.g. vip)
- vmap (EasyAlign)
-
- " Start interactive EasyAlign for a motion/text object (e.g. gaip)
- nmap ga (EasyAlign)
-<
-And with the following lines of text,
->
- apple =red
- grass+=green
- sky-= blue
-<
-try these commands:
-
- - vip=
- - `v`isual-select `i`nner `p`aragraph
- - Start EasyAlign command ()
- - Align around `=`
- - `gaip=`
- - Start EasyAlign command (`ga`) for `i`nner `p`aragraph
- - Align around `=`
-
-Notice that the commands are repeatable with `.` key if you have installed
-{repeat.vim}{3}. Install {visualrepeat}{4} as well if you want to repeat in
-visual mode.
-
- {3} https://github.com/tpope/vim-repeat
- {4} https://github.com/vim-scripts/visualrepeat
-
-
- *easy-align-5*
-USAGE *easy-align-usage*
-==============================================================================
-
-
-< Concept of alignment rule >_________________________________________________~
- *easy-align-concept-of-alignment-rule*
- *easy-align-5-1*
-
-Though easy-align can align lines of text around any delimiter, it provides
-shortcuts for the most common use cases with the concept of "alignment rule".
-
-An alignment rule is a predefined set of options for common alignment tasks,
-which is identified by a single character, DELIMITER KEY, such as ,
-`=`, `:`, `.`, `|`, `&`, `#`, and `,`.
-
-Think of it as a shortcut. Instead of writing regular expression and setting
-several options, you can just type in a single character.
-
-
-< Execution models >__________________________________________________________~
- *easy-align-execution-models*
- *easy-align-5-2*
-
-There are two ways to use easy-align.
-
-
-1. Using mappings~
- *easy-align-1-using-plug-mappings*
- *easy-align-5-2-1*
-
-The recommended method is to use mappings as described earlier.
-
- *(LiveEasyAlign)*
-
- ----------------------+--------+-----------------------------------------------------
- Mapping | Mode | Description ~
- ----------------------+--------+-----------------------------------------------------
- (EasyAlign) | normal | Start interactive mode for a motion/text object
- (EasyAlign) | visual | Start interactive mode for the selection
- (LiveEasyAlign) | normal | Start live-interactive mode for a motion/text object
- (LiveEasyAlign) | visual | Start live-interactive mode for the selection
- ----------------------+--------+-----------------------------------------------------
-
-
-2. Using :EasyAlign command~
- *easy-align-2-using-easyalign-command*
- *easy-align-5-2-2*
-
- *:EasyAlign*
-
-If you prefer command-line or do not want to start interactive mode, you can
-use `:EasyAlign` command instead.
-
- *:LiveEasyAlign*
-
- -------------------------------------------+-----------------------------------------------
- Mode | Command ~
- -------------------------------------------+-----------------------------------------------
- Interactive mode | `:EasyAlign[!] [OPTIONS]`
- Live interactive mode | `:LiveEasyAlign[!] [...]`
- Non-interactive mode (predefined rules) | `:EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]`
- Non-interactive mode (regular expressions) | `:EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]`
- -------------------------------------------+-----------------------------------------------
-
-
-< Interactive mode >__________________________________________________________~
- *easy-align-interactive-mode*
- *easy-align-5-3*
-
-The following sections will assume that you have (EasyAlign) mappings in
-your .vimrc as below:
->
- " Start interactive EasyAlign in visual mode (e.g. vip)
- vmap (EasyAlign)
-
- " Start interactive EasyAlign for a motion/text object (e.g. gaip)
- nmap ga (EasyAlign)
-<
-With these mappings, you can align text with only a few keystrokes.
-
- 1. key in visual mode, or `ga` followed by a motion or a text object to
- start interactive mode
- 2. Optional: Enter keys to select alignment mode (left, right, or center)
- 3. Optional: N-th delimiter (default: 1)
- - `1` Around the 1st occurrences of delimiters
- - `2` Around the 2nd occurrences of delimiters
- - ...
- - `*` Around all occurrences of delimiters
- - `**` Left-right alternating alignment around all delimiters
- - `-` Around the last occurrences of delimiters (`-1`)
- - `-2` Around the second to last occurrences of delimiters
- - ...
- 4. Delimiter key (a single keystroke; , `=`, `:`, `.`, `|`, `&`, `#`, `,`)
-
-
-Predefined alignment rules~
- *easy-align-predefined-alignment-rules*
- *easy-align-5-3-1*
-
- --------------+--------------------------------------------------------------------
- Delimiter key | Description/Use cases ~
- --------------+--------------------------------------------------------------------
- | General alignment around whitespaces
- `=` | Operators containing equals sign ( `=` , `==,` `!=` , `+=` , `&&=` , ...)
- `:` | Suitable for formatting JSON or YAML
- `.` | Multi-line method chaining
- `,` | Multi-line method arguments
- `&` | LaTeX tables (matches `&` and `\\` )
- `#` | Ruby/Python comments
- `"` | Vim comments
- | Table markdown
- --------------+--------------------------------------------------------------------
-
- *g:easy_align_delimiters*
-
-You can override these default rules or define your own rules with
-`g:easy_align_delimiters`, which will be described in {the later section}{5}.
-
- {5} https://github.com/junegunn/vim-easy-align#extending-alignment-rules
-
-
-Examples~
- *easy-align-examples*
- *easy-align-5-3-2*
-
- ------------------+------------------------------------+--------------------
- With visual map | Description | Equivalent command ~
- ------------------+------------------------------------+--------------------
- | Around 1st whitespaces | :'<,'>EasyAlign\
- 2 | Around 2nd whitespaces | :'<,'>EasyAlign2\
- - | Around the last whitespaces | :'<,'>EasyAlign-\
- -2 | Around the 2nd to last whitespaces | :'<,'>EasyAlign-2\
- : | Around 1st colon ( `key: value` ) | :'<,'>EasyAlign:
- : | Around 1st colon ( `key : value` ) | :'<,'>EasyAlign:= | Around 1st operators with = | :'<,'>EasyAlign=
- 3= | Around 3rd operators with = | :'<,'>EasyAlign3=
- *= | Around all operators with = | :'<,'>EasyAlign*=
- **= | Left-right alternating around = | :'<,'>EasyAlign**=
- = | Right alignment around 1st = | :'<,'>EasyAlign!=
- **= | Right-left alternating around = | :'<,'>EasyAlign!**=
- ------------------+------------------------------------+--------------------
-
-
-Using regular expressions~
- *easy-align-using-regular-expressions*
- *easy-align-5-3-3*
-
-Instead of finishing the command with a predefined delimiter key, you can type
-in a regular expression after CTRL-/ or CTRL-X key. For example, if you want
-to align text around all occurrences of numbers:
-
- -
- - `*`
- - CTRL-X
- - `[0-9]\+`
-
-
-Alignment options in interactive mode~
- *easy-align-alignment-options-in-interactive-mode*
- *easy-align-5-3-4*
-
-While in interactive mode, you can set alignment options using special
-shortcut keys listed below. The meaning of each option will be described in
-{the following sections}{6}.
-
- --------+--------------------+---------------------------------------------------
- Key | Option | Values ~
- --------+--------------------+---------------------------------------------------
- CTRL-F | `filter` | Input string ( `[gv]/.*/?` )
- CTRL-I | `indentation` | shallow, deep, none, keep
- CTRL-L | `left_margin` | Input number or string
- CTRL-R | `right_margin` | Input number or string
- CTRL-D | `delimiter_align` | left, center, right
- CTRL-U | `ignore_unmatched` | 0, 1
- CTRL-G | `ignore_groups` | [], ["String'], ["Comment'], ["String', "Comment']
- CTRL-A | `align` | Input string ( `/[lrc]+\*{0,2}/` )
- | `stick_to_left` | `{ 'stick_to_left': 1, 'left_margin': 0 }`
- | `stick_to_left` | `{ 'stick_to_left': 0, 'left_margin': 1 }`
- | `*_margin` | `{ 'left_margin': 0, 'right_margin': 0 }`
- --------+--------------------+---------------------------------------------------
-
- {6} https://github.com/junegunn/vim-easy-align#alignment-options
-
-
-< Live interactive mode >_____________________________________________________~
- *easy-align-live-interactive-mode*
- *easy-align-5-4*
-
-If you're performing a complex alignment where multiple options should be
-carefully adjusted, try "live interactive mode" where you can preview the
-result of the alignment on-the-fly as you type in.
-
-Live interactive mode can be started with either (LiveEasyAlign) map or
-`:LiveEasyAlign` command. Or you can switch to live interactive mode while in
-ordinary interactive mode by pressing CTRL-P. (P for Preview)
-
-In live interactive mode, you have to type in the same delimiter (or CTRL-X on
-regular expression) again to finalize the alignment. This allows you to
-preview the result of the alignment and freely change the delimiter using
-backspace key without leaving the interactive mode.
-
-
-< Non-interactive mode >______________________________________________________~
- *easy-align-non-interactive-mode*
- *easy-align-5-5*
-
-Instead of starting interactive mode, you can use declarative, non-interactive
-`:EasyAlign` command.
->
- " Using predefined alignment rules
- " :EasyAlign[!] [N-th] DELIMITER_KEY [OPTIONS]
- :EasyAlign :
- :EasyAlign =
- :EasyAlign *=
- :EasyAlign 3\
-
- " Using arbitrary regular expressions
- " :EasyAlign[!] [N-th] /REGEXP/ [OPTIONS]
- :EasyAlign /[:;]\+/
- :EasyAlign 2/[:;]\+/
- :EasyAlign */[:;]\+/
- :EasyAlign **/[:;]\+/
-<
-A command can end with alignment options, {each of which will be discussed in
-detail later}{6}, in Vim dictionary format.
-
- - `:EasyAlign * /[:;]\+/ { 'stick_to_left': 1, 'left_margin': 0 }`
-
-`stick_to_left` of 1 means that the matched delimiter should be positioned
-right next to the preceding token, and `left_margin` of 0 removes the margin
-on the left. So we get:
->
- apple;: banana:: cake
- data;; exchange:; format
-<
-Option names are fuzzy-matched, so you can write as follows:
-
- - `:EasyAlign * /[:;]\+/ { 'stl': 1, 'l': 0 }`
-
-You can even omit spaces between the arguments, so concisely (or cryptically):
-
- - `:EasyAlign*/[:;]\+/{'s':1,'l':0}`
-
-Nice. But let's make it even shorter. Option values can be written in
-shorthand notation.
-
- - `:EasyAlign*/[:;]\+/`
- `ignore_unmatched` | `iu[01]`
- `ignore_groups` | `ig\[.*\]`
- `align` | `a[lrc*]*`
- `delimiter_align` | `d[lrc]`
- `indentation` | `i[ksdn]`
- -------------------+-----------
-
-For your information, the same operation can be done in interactive mode as
-follows:
-
- -
- - `*`
- -
- - CTRL-X
- - `[:;]\+`
-
- {6} https://github.com/junegunn/vim-easy-align#alignment-options
-
-
-< Partial alignment in blockwise-visual mode >________________________________~
- *easy-align-partial-alignment-in-blockwise-visual-mode*
- *easy-align-5-6*
-
-In blockwise-visual mode (CTRL-V), EasyAlign command aligns only the selected
-text in the block, instead of the whole lines in the range.
-
-Consider the following case where you want to align text around `=>`
-operators.
->
- my_hash = { :a => 1,
- :aa => 2,
- :aaa => 3 }
-<
-In non-blockwise visual mode (`v` / `V`), = won't work since the
-assignment operator in the first line gets in the way. So we instead enter
-blockwise-visual mode (CTRL-V), and select the text around`=>` operators, then
-press =.
->
- my_hash = { :a => 1,
- :aa => 2,
- :aaa => 3 }
-<
-However, in this case, we don't really need blockwise visual mode since the
-same can be easily done using the negative N-th parameter: -=
-
-
- *easy-align-6*
-ALIGNMENT OPTIONS *easy-align-alignment-options*
-==============================================================================
-
-
-< List of options >___________________________________________________________~
- *easy-align-list-of-options*
- *easy-align-6-1*
-
- -------------------+---------+-----------------------+--------------------------------------------------------
- Option | Type | Default | Description ~
- -------------------+---------+-----------------------+--------------------------------------------------------
- `filter` | string | | Line filtering expression: `g/../` or `v/../`
- `left_margin` | number | 1 | Number of spaces to attach before delimiter
- `left_margin` | string | `' '` | String to attach before delimiter
- `right_margin` | number | 1 | Number of spaces to attach after delimiter
- `right_margin` | string | `' '` | String to attach after delimiter
- `stick_to_left` | boolean | 0 | Whether to position delimiter on the left-side
- `ignore_groups` | list | ["String', "Comment'] | Delimiters in these syntax highlight groups are ignored
- `ignore_unmatched` | boolean | 1 | Whether to ignore lines without matching delimiter
- `indentation` | string | `k` | Indentation method (keep, deep, shallow, none)
- `delimiter_align` | string | `r` | Determines how to align delimiters of different lengths
- `align` | string | `l` | Alignment modes for multiple occurrences of delimiters
- -------------------+---------+-----------------------+--------------------------------------------------------
-
-There are 4 ways to set alignment options (from lowest precedence to highest):
-
- 1. Some option values can be set with corresponding global variables
- 2. Option values can be specified in the definition of each alignment rule
- 3. Option values can be given as arguments to `:EasyAlign` command
- 4. Option values can be set in interactive mode using special shortcut keys
-
- *g:easy_align_ignore_groups* *g:easy_align_ignore_unmatched*
- *g:easy_align_indentation* *g:easy_align_delimiter_align*
-
- -------------------+-----------------+-------------+--------------------------------
- Option name | Shortcut key | Abbreviated | Global variable ~
- -------------------+-----------------+-------------+--------------------------------
- `filter` | CTRL-F | `[gv]/.*/` |
- `left_margin` | CTRL-L | `l[0-9]+` |
- `right_margin` | CTRL-R | `r[0-9]+` |
- `stick_to_left` | , | `<` or `>` |
- `ignore_groups` | CTRL-G | `ig\[.*\]` | `g:easy_align_ignore_groups`
- `ignore_unmatched` | CTRL-U | `iu[01]` | `g:easy_align_ignore_unmatched`
- `indentation` | CTRL-I | `i[ksdn]` | `g:easy_align_indentation`
- `delimiter_align` | CTRL-D | `d[lrc]` | `g:easy_align_delimiter_align`
- `align` | CTRL-A | `a[lrc*]*` |
- -------------------+-----------------+-------------+--------------------------------
-
-
-< Filtering lines >___________________________________________________________~
- *easy-align-filtering-lines*
- *easy-align-6-2*
-
-With `filter` option, you can align lines that only match or do not match a
-given pattern. There are several ways to set the pattern.
-
- 1. Press CTRL-F in interactive mode and type in `g/pat/` or `v/pat/`
- 2. In command-line, it can be written in dictionary format: `{'filter':
- 'g/pat/'}`
- 3. Or in shorthand notation: `g/pat/` or `v/pat/`
-
-(You don't need to escape "/'s in the regular expression)
-
-
-Examples~
-
- *easy-align-6-2-1*
->
- " Start interactive mode with filter option set to g/hello/
- EasyAlign g/hello/
-
- " Start live interactive mode with filter option set to v/goodbye/
- LiveEasyAlign v/goodbye/
-
- " Align the lines with 'hi' around the first colons
- EasyAlign:g/hi/
-<
-
-< Ignoring delimiters in comments or strings >________________________________~
- *easy-align-ignoring-delimiters-in-comments-or-strings*
- *easy-align-6-3*
-
-EasyAlign can be configured to ignore delimiters in certain syntax highlight
-groups, such as code comments or strings. By default, delimiters that are
-highlighted as code comments or strings are ignored.
->
- " Default:
- " If a delimiter is in a highlight group whose name matches
- " any of the followings, it will be ignored.
- let g:easy_align_ignore_groups = ['Comment', 'String']
-<
-For example, the following paragraph
->
- {
- # Quantity of apples: 1
- apple: 1,
- # Quantity of bananas: 2
- bananas: 2,
- # Quantity of grape:fruits: 3
- 'grape:fruits': 3
- }
-<
-becomes as follows on : (or `:EasyAlign:`)
->
- {
- # Quantity of apples: 1
- apple: 1,
- # Quantity of bananas: 2
- bananas: 2,
- # Quantity of grape:fruits: 3
- 'grape:fruits': 3
- }
-<
-Naturally, this feature only works when syntax highlighting is enabled.
-
-You can change the default rule by using one of these 4 methods.
-
- 1. Press CTRL-G in interactive mode to switch groups
- 2. Define global `g:easy_align_ignore_groups` list
- 3. Define a custom rule in `g:easy_align_delimiters` with `ignore_groups` option
- 4. Provide `ignore_groups` option to `:EasyAlign` command. e.g. `:EasyAlign:ig[]`
-
-For example if you set `ignore_groups` option to be an empty list, you get
->
- {
- # Quantity of apples: 1
- apple: 1,
- # Quantity of bananas: 2
- bananas: 2,
- # Quantity of grape: fruits: 3
- 'grape: fruits': 3
- }
-<
-If a pattern in `ignore_groups` is prepended by a `!`, it will have the
-opposite meaning. For instance, if `ignore_groups` is given as `['!Comment']`,
-delimiters that are not highlighted as Comment will be ignored during the
-alignment.
-
-
-< Ignoring unmatched lines >__________________________________________________~
- *easy-align-ignoring-unmatched-lines*
- *easy-align-6-4*
-
-`ignore_unmatched` option determines how EasyAlign command processes lines
-that do not have N-th delimiter.
-
- 1. In left-alignment mode, they are ignored
- 2. In right or center-alignment mode, they are not ignored, and the last tokens
- from those lines are aligned as well as if there is an invisible trailing
- delimiter at the end of each line
- 3. If `ignore_unmatched` is 1, they are ignored regardless of the alignment mode
- 4. If `ignore_unmatched` is 0, they are not ignored regardless of the mode
-
-Let's take an example. When we align the following code block around the (1st)
-colons,
->
- {
- apple: proc {
- this_line_does_not_have_a_colon
- },
- bananas: 2,
- grapefruits: 3
- }
-<
-this is usually what we want.
->
- {
- apple: proc {
- this_line_does_not_have_a_colon
- },
- bananas: 2,
- grapefruits: 3
- }
-<
-However, we can override this default behavior by setting `ignore_unmatched`
-option to zero using one of the following methods.
-
- 1. Press CTRL-U in interactive mode to toggle `ignore_unmatched` option
- 2. Set the global `g:easy_align_ignore_unmatched` variable to 0
- 3. Define a custom alignment rule with `ignore_unmatched` option set to 0
- 4. Provide `ignore_unmatched` option to `:EasyAlign` command. e.g.
- `:EasyAlign:iu0`
-
-Then we get,
->
- {
- apple: proc {
- this_line_does_not_have_a_colon
- },
- bananas: 2,
- grapefruits: 3
- }
-<
-
-< Aligning delimiters of different lengths >__________________________________~
- *easy-align-aligning-delimiters-of-different-lengths*
- *easy-align-6-5*
-
-Global `g:easy_align_delimiter_align` option and rule-wise/command-wise
-`delimiter_align` option determines how matched delimiters of different
-lengths are aligned.
->
- apple = 1
- banana += apple
- cake ||= banana
-<
-By default, delimiters are right-aligned as follows.
->
- apple = 1
- banana += apple
- cake ||= banana
-<
-However, with `:EasyAlign=dl`, delimiters are left-aligned.
->
- apple = 1
- banana += apple
- cake ||= banana
-<
-And on `:EasyAlign=dc`, center-aligned.
->
- apple = 1
- banana += apple
- cake ||= banana
-<
-In interactive mode, you can change the option value with CTRL-D key.
-
-
-< Adjusting indentation >_____________________________________________________~
- *easy-align-adjusting-indentation*
- *easy-align-6-6*
-
-By default :EasyAlign command keeps the original indentation of the lines. But
-then again we have `indentation` option. See the following example.
->
- # Lines with different indentation
- apple = 1
- banana = 2
- cake = 3
- daisy = 4
- eggplant = 5
-
- # Default: _k_eep the original indentation
- # :EasyAlign=
- apple = 1
- banana = 2
- cake = 3
- daisy = 4
- eggplant = 5
-
- # Use the _s_hallowest indentation among the lines
- # :EasyAlign=is
- apple = 1
- banana = 2
- cake = 3
- daisy = 4
- eggplant = 5
-
- # Use the _d_eepest indentation among the lines
- # :EasyAlign=id
- apple = 1
- banana = 2
- cake = 3
- daisy = 4
- eggplant = 5
-
- # Indentation: _n_one
- # :EasyAlign=in
- apple = 1
- banana = 2
- cake = 3
- daisy = 4
- eggplant = 5
-<
-In interactive mode, you can change the option value with CTRL-I key.
-
-
-< Alignments over multiple occurrences of delimiters >________________________~
- *easy-align-alignments-over-multiple-occurrences-of-delimiters*
- *easy-align-6-7*
-
-As stated above, "N-th" parameter is used to target specific occurrences of
-the delimiter when it appears multiple times in each line.
-
-To recap:
->
- " Left-alignment around the FIRST occurrences of delimiters
- :EasyAlign =
-
- " Left-alignment around the SECOND occurrences of delimiters
- :EasyAlign 2=
-
- " Left-alignment around the LAST occurrences of delimiters
- :EasyAlign -=
-
- " Left-alignment around ALL occurrences of delimiters
- :EasyAlign *=
-
- " Left-right ALTERNATING alignment around all occurrences of delimiters
- :EasyAlign **=
-
- " Right-left ALTERNATING alignment around all occurrences of delimiters
- :EasyAlign! **=
-<
-In addition to these, you can fine-tune alignments over multiple occurrences
-of the delimiters with "align' option. (The option can also be set in
-interactive mode with the special key CTRL-A)
->
- " Left alignment over the first two occurrences of delimiters
- :EasyAlign = { 'align': 'll' }
-
- " Right, left, center alignment over the 1st to 3rd occurrences of delimiters
- :EasyAlign = { 'a': 'rlc' }
-
- " Using shorthand notation
- :EasyAlign = arlc
-
- " Right, left, center alignment over the 2nd to 4th occurrences of delimiters
- :EasyAlign 2=arlc
-
- " (*) Repeating alignments (default: l, r, or c)
- " Right, left, center, center, center, center, ...
- :EasyAlign *=arlc
-
- " (**) Alternating alignments (default: lr or rl)
- " Right, left, center, right, left, center, ...
- :EasyAlign **=arlc
-
- " Right, left, center, center, center, ... repeating alignment
- " over the 3rd to the last occurrences of delimiters
- :EasyAlign 3=arlc*
-
- " Right, left, center, right, left, center, ... alternating alignment
- " over the 3rd to the last occurrences of delimiters
- :EasyAlign 3=arlc**
-<
-
-< Extending alignment rules >_________________________________________________~
- *easy-align-extending-alignment-rules*
- *easy-align-6-8*
-
-Although the default rules should cover the most of the use cases, you can
-extend the rules by setting a dictionary named `g:easy_align_delimiters`.
-
-You may refer to the definitions of the default alignment rules {here}{7}.
-
-{7} https://github.com/junegunn/vim-easy-align/blob/2.9.6/autoload/easy_align.vim#L32-L46
-
-
-Examples~
-
- *easy-align-6-8-1*
->
- let g:easy_align_delimiters = {
- \ '>': { 'pattern': '>>\|=>\|>' },
- \ '/': {
- \ 'pattern': '//\+\|/\*\|\*/',
- \ 'delimiter_align': 'l',
- \ 'ignore_groups': ['!Comment'] },
- \ ']': {
- \ 'pattern': '[[\]]',
- \ 'left_margin': 0,
- \ 'right_margin': 0,
- \ 'stick_to_left': 0
- \ },
- \ ')': {
- \ 'pattern': '[()]',
- \ 'left_margin': 0,
- \ 'right_margin': 0,
- \ 'stick_to_left': 0
- \ },
- \ 'd': {
- \ 'pattern': ' \(\S\+\s*[;=]\)\@=',
- \ 'left_margin': 0,
- \ 'right_margin': 0
- \ }
- \ }
-<
-
- *easy-align-7*
-OTHER OPTIONS *easy-align-other-options*
-==============================================================================
-
-
-< Disabling &foldmethod during alignment >____________________________________~
- *easy-align-disabling-foldmethod-during-alignment*
- *easy-align-7-1*
-
- *g:easy_align_bypass_fold*
-
-{It is reported}{8} that 'foldmethod' value of `expr` or `syntax` can
-significantly slow down the alignment when editing a large, complex file with
-many folds. To alleviate this issue, EasyAlign provides an option to
-temporarily set 'foldmethod' to `manual` during the alignment task. In order
-to enable this feature, set `g:easy_align_bypass_fold` switch to 1.
->
- let g:easy_align_bypass_fold = 1
-<
- {8} https://github.com/junegunn/vim-easy-align/issues/14
-
-
-< Left/right/center mode switch in interactive mode >_________________________~
- *easy-align-left-right-center-mode-switch-in-interactive-mode*
- *easy-align-7-2*
-
-In interactive mode, you can choose the alignment mode you want by pressing
-enter keys. The non-bang command, `:EasyAlign` starts in left-alignment mode
-and changes to right and center mode as you press enter keys, while the bang
-version first starts in right-alignment mode.
-
- - `:EasyAlign`
- - Left, Right, Center
- - `:EasyAlign!`
- - Right, Left, Center
-
-If you do not prefer this default mode transition, you can define your own
-settings as follows.
-
- *g:easy_align_interactive_modes* *g:easy_align_bang_interactive_modes*
->
- let g:easy_align_interactive_modes = ['l', 'r']
- let g:easy_align_bang_interactive_modes = ['c', 'r']
-<
-
- *easy-align-8*
-ADVANCED EXAMPLES AND USE CASES *easy-align-advanced-examples-and-use-cases*
-==============================================================================
-
-See {EXAMPLES.md}{9} for more examples.
-
- {9} https://github.com/junegunn/vim-easy-align/blob/master/EXAMPLES.md
-
-
- *easy-align-9*
-RELATED WORK *easy-align-related-work*
-==============================================================================
-
- - {DrChip's Alignment Tool for Vim}{10}
- - {Tabular}{11}
-
- {10} http://www.drchip.org/astronaut/vim/align.html
- {11} https://github.com/godlygeek/tabular
-
-
- *easy-align-10*
-AUTHOR *easy-align-author*
-==============================================================================
-
-{Junegunn Choi}{12}
-
- {12} https://github.com/junegunn
-
-
- *easy-align-11*
-LICENSE *easy-align-license*
-==============================================================================
-
-MIT
-
-==============================================================================
-vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap:
diff --git a/.vim/bundle/vim-easy-align/doc/tags b/.vim/bundle/vim-easy-align/doc/tags
deleted file mode 100644
index 0411c5f..0000000
--- a/.vim/bundle/vim-easy-align/doc/tags
+++ /dev/null
@@ -1,84 +0,0 @@
-:EasyAlign easy_align.txt /*:EasyAlign*
-:LiveEasyAlign easy_align.txt /*:LiveEasyAlign*
-(EasyAlign) easy_align.txt /*(EasyAlign)*
-(LiveEasyAlign) easy_align.txt /*(LiveEasyAlign)*
-easy-align easy_align.txt /*easy-align*
-easy-align-1 easy_align.txt /*easy-align-1*
-easy-align-1-using-plug-mappings easy_align.txt /*easy-align-1-using-plug-mappings*
-easy-align-10 easy_align.txt /*easy-align-10*
-easy-align-11 easy_align.txt /*easy-align-11*
-easy-align-2 easy_align.txt /*easy-align-2*
-easy-align-2-using-easyalign-command easy_align.txt /*easy-align-2-using-easyalign-command*
-easy-align-3 easy_align.txt /*easy-align-3*
-easy-align-4 easy_align.txt /*easy-align-4*
-easy-align-5 easy_align.txt /*easy-align-5*
-easy-align-5-1 easy_align.txt /*easy-align-5-1*
-easy-align-5-2 easy_align.txt /*easy-align-5-2*
-easy-align-5-2-1 easy_align.txt /*easy-align-5-2-1*
-easy-align-5-2-2 easy_align.txt /*easy-align-5-2-2*
-easy-align-5-3 easy_align.txt /*easy-align-5-3*
-easy-align-5-3-1 easy_align.txt /*easy-align-5-3-1*
-easy-align-5-3-2 easy_align.txt /*easy-align-5-3-2*
-easy-align-5-3-3 easy_align.txt /*easy-align-5-3-3*
-easy-align-5-3-4 easy_align.txt /*easy-align-5-3-4*
-easy-align-5-4 easy_align.txt /*easy-align-5-4*
-easy-align-5-5 easy_align.txt /*easy-align-5-5*
-easy-align-5-6 easy_align.txt /*easy-align-5-6*
-easy-align-6 easy_align.txt /*easy-align-6*
-easy-align-6-1 easy_align.txt /*easy-align-6-1*
-easy-align-6-2 easy_align.txt /*easy-align-6-2*
-easy-align-6-2-1 easy_align.txt /*easy-align-6-2-1*
-easy-align-6-3 easy_align.txt /*easy-align-6-3*
-easy-align-6-4 easy_align.txt /*easy-align-6-4*
-easy-align-6-5 easy_align.txt /*easy-align-6-5*
-easy-align-6-6 easy_align.txt /*easy-align-6-6*
-easy-align-6-7 easy_align.txt /*easy-align-6-7*
-easy-align-6-8 easy_align.txt /*easy-align-6-8*
-easy-align-6-8-1 easy_align.txt /*easy-align-6-8-1*
-easy-align-7 easy_align.txt /*easy-align-7*
-easy-align-7-1 easy_align.txt /*easy-align-7-1*
-easy-align-7-2 easy_align.txt /*easy-align-7-2*
-easy-align-8 easy_align.txt /*easy-align-8*
-easy-align-9 easy_align.txt /*easy-align-9*
-easy-align-adjusting-indentation easy_align.txt /*easy-align-adjusting-indentation*
-easy-align-advanced-examples-and-use-cases easy_align.txt /*easy-align-advanced-examples-and-use-cases*
-easy-align-aligning-delimiters-of-different-lengths easy_align.txt /*easy-align-aligning-delimiters-of-different-lengths*
-easy-align-alignment-options easy_align.txt /*easy-align-alignment-options*
-easy-align-alignment-options-in-interactive-mode easy_align.txt /*easy-align-alignment-options-in-interactive-mode*
-easy-align-alignments-over-multiple-occurrences-of-delimiters easy_align.txt /*easy-align-alignments-over-multiple-occurrences-of-delimiters*
-easy-align-author easy_align.txt /*easy-align-author*
-easy-align-concept-of-alignment-rule easy_align.txt /*easy-align-concept-of-alignment-rule*
-easy-align-demo easy_align.txt /*easy-align-demo*
-easy-align-disabling-foldmethod-during-alignment easy_align.txt /*easy-align-disabling-foldmethod-during-alignment*
-easy-align-examples easy_align.txt /*easy-align-examples*
-easy-align-execution-models easy_align.txt /*easy-align-execution-models*
-easy-align-extending-alignment-rules easy_align.txt /*easy-align-extending-alignment-rules*
-easy-align-features easy_align.txt /*easy-align-features*
-easy-align-filtering-lines easy_align.txt /*easy-align-filtering-lines*
-easy-align-ignoring-delimiters-in-comments-or-strings easy_align.txt /*easy-align-ignoring-delimiters-in-comments-or-strings*
-easy-align-ignoring-unmatched-lines easy_align.txt /*easy-align-ignoring-unmatched-lines*
-easy-align-installation easy_align.txt /*easy-align-installation*
-easy-align-interactive-mode easy_align.txt /*easy-align-interactive-mode*
-easy-align-left-right-center-mode-switch-in-interactive-mode easy_align.txt /*easy-align-left-right-center-mode-switch-in-interactive-mode*
-easy-align-license easy_align.txt /*easy-align-license*
-easy-align-list-of-options easy_align.txt /*easy-align-list-of-options*
-easy-align-live-interactive-mode easy_align.txt /*easy-align-live-interactive-mode*
-easy-align-non-interactive-mode easy_align.txt /*easy-align-non-interactive-mode*
-easy-align-other-options easy_align.txt /*easy-align-other-options*
-easy-align-partial-alignment-in-blockwise-visual-mode easy_align.txt /*easy-align-partial-alignment-in-blockwise-visual-mode*
-easy-align-predefined-alignment-rules easy_align.txt /*easy-align-predefined-alignment-rules*
-easy-align-related-work easy_align.txt /*easy-align-related-work*
-easy-align-tldr-one-minute-guide easy_align.txt /*easy-align-tldr-one-minute-guide*
-easy-align-toc easy_align.txt /*easy-align-toc*
-easy-align-usage easy_align.txt /*easy-align-usage*
-easy-align-using-regular-expressions easy_align.txt /*easy-align-using-regular-expressions*
-easyalign easy_align.txt /*easyalign*
-g:easy_align_bang_interactive_modes easy_align.txt /*g:easy_align_bang_interactive_modes*
-g:easy_align_bypass_fold easy_align.txt /*g:easy_align_bypass_fold*
-g:easy_align_delimiter_align easy_align.txt /*g:easy_align_delimiter_align*
-g:easy_align_delimiters easy_align.txt /*g:easy_align_delimiters*
-g:easy_align_ignore_groups easy_align.txt /*g:easy_align_ignore_groups*
-g:easy_align_ignore_unmatched easy_align.txt /*g:easy_align_ignore_unmatched*
-g:easy_align_indentation easy_align.txt /*g:easy_align_indentation*
-g:easy_align_interactive_modes easy_align.txt /*g:easy_align_interactive_modes*
-vim-easy-align easy_align.txt /*vim-easy-align*
diff --git a/.vim/bundle/vim-easy-align/plugin/easy_align.vim b/.vim/bundle/vim-easy-align/plugin/easy_align.vim
deleted file mode 100644
index c71af4e..0000000
--- a/.vim/bundle/vim-easy-align/plugin/easy_align.vim
+++ /dev/null
@@ -1,142 +0,0 @@
-" Copyright (c) 2014 Junegunn Choi
-"
-" MIT License
-"
-" Permission is hereby granted, free of charge, to any person obtaining
-" a copy of this software and associated documentation files (the
-" "Software"), to deal in the Software without restriction, including
-" without limitation the rights to use, copy, modify, merge, publish,
-" distribute, sublicense, and/or sell copies of the Software, and to
-" permit persons to whom the Software is furnished to do so, subject to
-" the following conditions:
-"
-" The above copyright notice and this permission notice shall be
-" included in all copies or substantial portions of the Software.
-"
-" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-if exists("g:loaded_easy_align_plugin")
- finish
-endif
-let g:loaded_easy_align_plugin = 1
-
-command! -nargs=* -range -bang EasyAlign ,call easy_align#align(0, 0, 'command', )
-command! -nargs=* -range -bang LiveEasyAlign ,call easy_align#align(0, 1, 'command', )
-
-let s:last_command = 'EasyAlign'
-
-function! s:abs(v)
- return a:v >= 0 ? a:v : - a:v
-endfunction
-
-function! s:remember_visual(mode)
- let s:last_visual = [a:mode, s:abs(line("'>") - line("'<")), s:abs(col("'>") - col("'<"))]
-endfunction
-
-function! s:repeat_visual()
- let [mode, ldiff, cdiff] = s:last_visual
- let cmd = 'normal! '.mode
- if ldiff > 0
- let cmd .= ldiff . 'j'
- endif
-
- let ve_save = &virtualedit
- try
- if mode == "\"
- if cdiff > 0
- let cmd .= cdiff . 'l'
- endif
- set virtualedit+=block
- endif
- execute cmd.":\=g:easy_align_last_command\\"
- call s:set_repeat()
- finally
- if ve_save != &virtualedit
- let &virtualedit = ve_save
- endif
- endtry
-endfunction
-
-function! s:repeat_in_visual()
- if exists('g:easy_align_last_command')
- call s:remember_visual(visualmode())
- call s:repeat_visual()
- endif
-endfunction
-
-function! s:set_repeat()
- silent! call repeat#set("\(EasyAlignRepeat)")
-endfunction
-
-function! s:generic_easy_align_op(type, vmode, live)
- if !&modifiable
- if a:vmode
- normal! gv
- endif
- return
- endif
- let sel_save = &selection
- let &selection = "inclusive"
-
- if a:vmode
- let vmode = a:type
- let [l1, l2] = ["'<", "'>"]
- call s:remember_visual(vmode)
- else
- let vmode = ''
- let [l1, l2] = [line("'["), line("']")]
- unlet! s:last_visual
- endif
-
- try
- let range = l1.','.l2
- if get(g:, 'easy_align_need_repeat', 0)
- execute range . g:easy_align_last_command
- else
- execute range . "call easy_align#align(0, a:live, vmode, '')"
- end
- call s:set_repeat()
- finally
- let &selection = sel_save
- endtry
-endfunction
-
-function! s:easy_align_op(type, ...)
- call s:generic_easy_align_op(a:type, a:0, 0)
-endfunction
-
-function! s:live_easy_align_op(type, ...)
- call s:generic_easy_align_op(a:type, a:0, 1)
-endfunction
-
-function! s:easy_align_repeat()
- if exists('s:last_visual')
- call s:repeat_visual()
- else
- try
- let g:easy_align_need_repeat = 1
- normal! .
- finally
- unlet! g:easy_align_need_repeat
- endtry
- endif
-endfunction
-
-nnoremap (EasyAlign) :set opfunc=easy_align_opg@
-vnoremap (EasyAlign) :call easy_align_op(visualmode(), 1)
-nnoremap (LiveEasyAlign) :set opfunc=live_easy_align_opg@
-vnoremap (LiveEasyAlign) :call live_easy_align_op(visualmode(), 1)
-
-" vim-repeat support
-nnoremap (EasyAlignRepeat) :call easy_align_repeat()
-vnoremap (EasyAlignRepeat) :call repeat_in_visual()
-
-" Backward-compatibility (deprecated)
-nnoremap (EasyAlignOperator) :set opfunc=easy_align_opg@
-
diff --git a/.vim/bundle/vim-fzf/LICENSE b/.vim/bundle/vim-fzf/LICENSE
deleted file mode 100644
index 8087dea..0000000
--- a/.vim/bundle/vim-fzf/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2021 Junegunn Choi
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/.vim/bundle/vim-fzf/README.md b/.vim/bundle/vim-fzf/README.md
deleted file mode 100644
index 6fc2d18..0000000
--- a/.vim/bundle/vim-fzf/README.md
+++ /dev/null
@@ -1,443 +0,0 @@
-fzf :heart: vim
-===============
-
-Things you can do with [fzf][fzf] and Vim.
-
-Rationale
----------
-
-[fzf][fzf] itself is not a Vim plugin, and the official repository only
-provides the [basic wrapper function][run] for Vim. It's up to the users to
-write their own Vim commands with it. However, I've learned that many users of
-fzf are not familiar with Vimscript and are looking for the "default"
-implementation of the features they can find in the alternative Vim plugins.
-
-Why you should use fzf on Vim
------------------------------
-
-Because you can and you love fzf.
-
-fzf runs asynchronously and can be orders of magnitude faster than similar Vim
-plugins. However, the benefit may not be noticeable if the size of the input
-is small, which is the case for many of the commands provided here.
-Nevertheless I wrote them anyway since it's really easy to implement custom
-selector with fzf.
-
-Installation
-------------
-
-fzf.vim depends on the basic Vim plugin of [the main fzf
-repository][fzf-main], which means you need to **set up both "fzf" and
-"fzf.vim" on Vim**. To learn more about fzf/Vim integration, see
-[README-VIM][README-VIM].
-
-[fzf-main]: https://github.com/junegunn/fzf
-[README-VIM]: https://github.com/junegunn/fzf/blob/master/README-VIM.md
-
-### Using [vim-plug](https://github.com/junegunn/vim-plug)
-
-```vim
-Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
-Plug 'junegunn/fzf.vim'
-```
-
-`fzf#install()` makes sure that you have the latest binary, but it's optional,
-so you can omit it if you use a plugin manager that doesn't support hooks.
-
-### Dependencies
-
-- [fzf][fzf-main] 0.41.1 or above
-- For syntax-highlighted preview, install [bat](https://github.com/sharkdp/bat)
-- If [delta](https://github.com/dandavison/delta) is available, `GF?`,
- `Commits` and `BCommits` will use it to format `git diff` output.
-- `Ag` requires [The Silver Searcher (ag)][ag]
-- `Rg` requires [ripgrep (rg)][rg]
-- `Tags` and `Helptags` require Perl
-
-Commands
---------
-
-| Command | List |
-| --- | --- |
-| `:Files [PATH]` | Files (runs `$FZF_DEFAULT_COMMAND` if defined) |
-| `:GFiles [OPTS]` | Git files (`git ls-files`) |
-| `:GFiles?` | Git files (`git status`) |
-| `:Buffers` | Open buffers |
-| `:Colors` | Color schemes |
-| `:Ag [PATTERN]` | [ag][ag] search result (`ALT-A` to select all, `ALT-D` to deselect all) |
-| `:Rg [PATTERN]` | [rg][rg] search result (`ALT-A` to select all, `ALT-D` to deselect all) |
-| `:RG [PATTERN]` | [rg][rg] search result; relaunch ripgrep on every keystroke |
-| `:Lines [QUERY]` | Lines in loaded buffers |
-| `:BLines [QUERY]` | Lines in the current buffer |
-| `:Tags [QUERY]` | Tags in the project (`ctags -R`) |
-| `:BTags [QUERY]` | Tags in the current buffer |
-| `:Changes` | Changelist across all open buffers |
-| `:Marks` | Marks |
-| `:Jumps` | Jumps |
-| `:Windows` | Windows |
-| `:Locate PATTERN` | `locate` command output |
-| `:History` | `v:oldfiles` and open buffers |
-| `:History:` | Command history |
-| `:History/` | Search history |
-| `:Snippets` | Snippets ([UltiSnips][us]) |
-| `:Commits [LOG_OPTS]` | Git commits (requires [fugitive.vim][f]) |
-| `:BCommits [LOG_OPTS]` | Git commits for the current buffer; visual-select lines to track changes in the range |
-| `:Commands` | Commands |
-| `:Maps` | Normal mode mappings |
-| `:Helptags` | Help tags [1](#helptags) |
-| `:Filetypes` | File types
-
-- Most commands support `CTRL-T` / `CTRL-X` / `CTRL-V` key
- bindings to open in a new tab, a new split, or in a new vertical split
-- Bang-versions of the commands (e.g. `Ag!`) will open fzf in fullscreen
-- You can set `g:fzf_vim.command_prefix` to give the same prefix to the commands
- - e.g. `let g:fzf_vim.command_prefix = 'Fzf'` and you have `FzfFiles`, etc.
-
-(1: `Helptags` will shadow the command of the same name
-from [pathogen][pat]. But its functionality is still available via `call
-pathogen#helptags()`. [↩](#a1))
-
-[pat]: https://github.com/tpope/vim-pathogen
-[f]: https://github.com/tpope/vim-fugitive
-
-Customization
--------------
-
-### Configuration options of the base plugin
-
-Every command in fzf.vim internally calls `fzf#wrap` function of the main
-repository which supports a set of global option variables. So please read
-through [README-VIM][README-VIM] to learn more about them.
-
-### Configuration options for fzf.vim
-
-All configuration values for this plugin are stored in `g:fzf_vim` dictionary,
-so **make sure to initialize it before assigning any configuration values to
-it**.
-
-```vim
-" Initialize configuration dictionary
-let g:fzf_vim = {}
-```
-
-#### Preview window
-
-Some commands will show the preview window on the right. You can customize the
-behavior with `g:fzf_vim.preview_window`. Here are some examples:
-
-```vim
-" This is the default option:
-" - Preview window on the right with 50% width
-" - CTRL-/ will toggle preview window.
-" - Note that this array is passed as arguments to fzf#vim#with_preview function.
-" - To learn more about preview window options, see `--preview-window` section of `man fzf`.
-let g:fzf_vim.preview_window = ['right,50%', 'ctrl-/']
-
-" Preview window is hidden by default. You can toggle it with ctrl-/.
-" It will show on the right with 50% width, but if the width is smaller
-" than 70 columns, it will show above the candidate list
-let g:fzf_vim.preview_window = ['hidden,right,50%,<70(up,40%)', 'ctrl-/']
-
-" Empty value to disable preview window altogether
-let g:fzf_vim.preview_window = []
-
-" fzf.vim needs bash to display the preview window.
-" On Windows, fzf.vim will first see if bash is in $PATH, then if
-" Git bash (C:\Program Files\Git\bin\bash.exe) is available.
-" If you want it to use a different bash, set this variable.
-" let g:fzf_vim = {}
-" let g:fzf_vim.preview_bash = 'C:\Git\bin\bash.exe'
-```
-
-#### Command-level options
-
-```vim
-" [Buffers] Jump to the existing window if possible
-let g:fzf_vim.buffers_jump = 1
-
-" [[B]Commits] Customize the options used by 'git log':
-let g:fzf_vim.commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'
-
-" [Tags] Command to generate tags file
-let g:fzf_vim.tags_command = 'ctags -R'
-
-" [Commands] --expect expression for directly executing the command
-let g:fzf_vim.commands_expect = 'alt-enter,ctrl-x'
-```
-
-#### List type to handle multiple selections
-
-The following commands will fill the quickfix list when multiple entries are
-selected.
-
-* `Ag`
-* `Rg` / `RG`
-* `Lines` / `BLines`
-* `Tags` / `BTags`
-
-By setting `g:fzf_vim.listproc`, you can make them use location list instead.
-
-```vim
-" Default: Use quickfix list
-let g:fzf_vim.listproc = { list -> fzf#vim#listproc#quickfix(list) }
-
-" Use location list instead of quickfix list
-let g:fzf_vim.listproc = { list -> fzf#vim#listproc#location(list) }
-```
-
-You can customize the list type per command by defining variables named
-`g:fzf_vim.listproc_{command_name_in_lowercase}`.
-
-```vim
-" Command-wise customization
-let g:fzf_vim.listproc_ag = { list -> fzf#vim#listproc#quickfix(list) }
-let g:fzf_vim.listproc_rg = { list -> fzf#vim#listproc#location(list) }
-```
-
-You can further customize the behavior by providing a custom function to
-process the list instead of using the predefined `fzf#vim#listproc#quickfix`
-or `fzf#vim#listproc#location`.
-
-```vim
-" A customized version of fzf#vim#listproc#quickfix.
-" The last two lines are commented out not to move to the first entry.
-function! g:fzf_vim.listproc(list)
- call setqflist(a:list)
- copen
- wincmd p
- " cfirst
- " normal! zvzz
-endfunction
-```
-
-### Advanced customization
-
-#### Vim functions
-
-Each command in fzf.vim is backed by a Vim function. You can override
-a command or define a variation of it by calling its corresponding function.
-
-| Command | Vim function |
-| --- | --- |
-| `Files` | `fzf#vim#files(dir, [spec dict], [fullscreen bool])` |
-| `GFiles` | `fzf#vim#gitfiles(git_options, [spec dict], [fullscreen bool])` |
-| `GFiles?` | `fzf#vim#gitfiles('?', [spec dict], [fullscreen bool])` |
-| `Buffers` | `fzf#vim#buffers([query string], [bufnrs list], [spec dict], [fullscreen bool])` |
-| `Colors` | `fzf#vim#colors([spec dict], [fullscreen bool])` |
-| `Rg` | `fzf#vim#grep(command, [spec dict], [fullscreen bool])` |
-| `RG` | `fzf#vim#grep2(command_prefix, query, [spec dict], [fullscreen bool])` |
-| ... | ... |
-
-(We can see that the last two optional arguments of each function are
-identical. They are directly passed to `fzf#wrap` function. If you haven't
-read [README-VIM][README-VIM] already, please read it before proceeding.)
-
-#### Example: Customizing `Files` command
-
-This is the default definition of `Files` command:
-
-```vim
-command! -bang -nargs=? -complete=dir Files call fzf#vim#files(, 0)
-```
-
-Let's say you want to a variation of it called `ProjectFiles` that only
-searches inside `~/projects` directory. Then you can do it like this:
-
-```vim
-command! -bang ProjectFiles call fzf#vim#files('~/projects', 0)
-```
-
-Or, if you want to override the command with different fzf options, just pass
-a custom spec to the function.
-
-```vim
-command! -bang -nargs=? -complete=dir Files
- \ call fzf#vim#files(, {'options': ['--layout=reverse', '--info=inline']}, 0)
-```
-
-Want a preview window?
-
-```vim
-command! -bang -nargs=? -complete=dir Files
- \ call fzf#vim#files(, {'options': ['--layout=reverse', '--info=inline', '--preview', 'cat {}']}, 0)
-```
-
-It kind of works, but you probably want a nicer previewer program than `cat`.
-fzf.vim ships [a versatile preview script](bin/preview.sh) you can readily
-use. It internally executes [bat](https://github.com/sharkdp/bat) for syntax
-highlighting, so make sure to install it.
-
-```vim
-command! -bang -nargs=? -complete=dir Files
- \ call fzf#vim#files(, {'options': ['--layout=reverse', '--info=inline', '--preview', '~/.vim/plugged/fzf.vim/bin/preview.sh {}']}, 0)
-```
-
-However, it's not ideal to hard-code the path to the script which can be
-different in different circumstances. So in order to make it easier to set up
-the previewer, fzf.vim provides `fzf#vim#with_preview` helper function.
-Similarly to `fzf#wrap`, it takes a spec dictionary and returns a copy of it
-with additional preview options.
-
-```vim
-command! -bang -nargs=? -complete=dir Files
- \ call fzf#vim#files(, fzf#vim#with_preview({'options': ['--layout=reverse', '--info=inline']}), 0)
-```
-
-You can just omit the spec argument if you only want the previewer.
-
-```vim
-command! -bang -nargs=? -complete=dir Files
- \ call fzf#vim#files(, fzf#vim#with_preview(), 0)
-```
-
-#### Example: `git grep` wrapper
-
-The following example implements `GGrep` command that works similarly to
-predefined `Ag` or `Rg` using `fzf#vim#grep`.
-
-- We set the base directory to git root by setting `dir` attribute in spec
- dictionary.
-- [The preview script](bin/preview.sh) supports `grep` format
- (`FILE_PATH:LINE_NO:...`), so we can just wrap the spec with
- `fzf#vim#with_preview` as before to enable previewer.
-
-```vim
-command! -bang -nargs=* GGrep
- \ call fzf#vim#grep(
- \ 'git grep --line-number -- '.fzf#shellescape(),
- \ fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), 0)
-```
-
-Mappings
---------
-
-| Mapping | Description |
-| --- | --- |
-| `(fzf-maps-n)` | Normal mode mappings |
-| `(fzf-maps-i)` | Insert mode mappings |
-| `(fzf-maps-x)` | Visual mode mappings |
-| `(fzf-maps-o)` | Operator-pending mappings |
-| `(fzf-complete-word)` | `cat /usr/share/dict/words` |
-| `(fzf-complete-path)` | Path completion using `find` (file + dir) |
-| `(fzf-complete-file)` | File completion using `find` |
-| `(fzf-complete-line)` | Line completion (all open buffers) |
-| `(fzf-complete-buffer-line)` | Line completion (current buffer only) |
-
-```vim
-" Mapping selecting mappings
-nmap (fzf-maps-n)
-xmap (fzf-maps-x)
-omap (fzf-maps-o)
-
-" Insert mode completion
-imap (fzf-complete-word)
-imap (fzf-complete-path)
-imap (fzf-complete-line)
-```
-
-Completion functions
---------------------
-
-| Function | Description |
-| --- | --- |
-| `fzf#vim#complete#path(command, [spec])` | Path completion |
-| `fzf#vim#complete#word([spec])` | Word completion |
-| `fzf#vim#complete#line([spec])` | Line completion (all open buffers) |
-| `fzf#vim#complete#buffer_line([spec])` | Line completion (current buffer only) |
-
-```vim
-" Path completion with custom source command
-inoremap fzf#vim#complete#path('fd')
-inoremap fzf#vim#complete#path('rg --files')
-
-" Word completion with custom spec with popup layout option
-inoremap fzf#vim#complete#word({'window': { 'width': 0.2, 'height': 0.9, 'xoffset': 1 }})
-```
-
-Custom completion
------------------
-
-`fzf#vim#complete` is a helper function for creating custom fuzzy completion
-using fzf. If the first parameter is a command string or a Vim list, it will
-be used as the source.
-
-```vim
-" Replace the default dictionary completion with fzf-based fuzzy completion
-inoremap fzf#vim#complete('cat /usr/share/dict/words')
-```
-
-For advanced uses, you can pass an options dictionary to the function. The set
-of options is pretty much identical to that for `fzf#run` only with the
-following exceptions:
-
-- `reducer` (funcref)
- - Reducer transforms the output lines of fzf into a single string value
-- `prefix` (string or funcref; default: `\k*$`)
- - Regular expression pattern to extract the completion prefix
- - Or a function to extract completion prefix
-- Both `source` and `options` can be given as funcrefs that take the
- completion prefix as the argument and return the final value
-- `sink` or `sink*` are ignored
-
-```vim
-" Global line completion (not just open buffers. ripgrep required.)
-inoremap fzf#vim#complete(fzf#wrap({
- \ 'prefix': '^.*$',
- \ 'source': 'rg -n ^ --color always',
- \ 'options': '--ansi --delimiter : --nth 3..',
- \ 'reducer': { lines -> join(split(lines[0], ':\zs')[2:], '') }}))
-```
-
-### Reducer example
-
-```vim
-function! s:make_sentence(lines)
- return substitute(join(a:lines), '^.', '\=toupper(submatch(0))', '').'.'
-endfunction
-
-inoremap fzf#vim#complete({
- \ 'source': 'cat /usr/share/dict/words',
- \ 'reducer': function('make_sentence'),
- \ 'options': '--multi --reverse --margin 15%,0',
- \ 'left': 20})
-```
-
-Status line of terminal buffer
-------------------------------
-
-When fzf starts in a terminal buffer (see [fzf/README-VIM.md][termbuf]), you
-may want to customize the statusline of the containing buffer.
-
-[termbuf]: https://github.com/junegunn/fzf/blob/master/README-VIM.md#fzf-inside-terminal-buffer
-
-### Hide statusline
-
-```vim
-autocmd! FileType fzf set laststatus=0 noshowmode noruler
- \| autocmd BufLeave set laststatus=2 showmode ruler
-```
-
-### Custom statusline
-
-```vim
-function! s:fzf_statusline()
- " Override statusline as you like
- highlight fzf1 ctermfg=161 ctermbg=251
- highlight fzf2 ctermfg=23 ctermbg=251
- highlight fzf3 ctermfg=237 ctermbg=251
- setlocal statusline=%#fzf1#\ >\ %#fzf2#fz%#fzf3#f
-endfunction
-
-autocmd! User FzfStatusLine call fzf_statusline()
-```
-
-License
--------
-
-MIT
-
-[fzf]: https://github.com/junegunn/fzf
-[run]: https://github.com/junegunn/fzf/blob/master/README-VIM.md#fzfrun
-[ag]: https://github.com/ggreer/the_silver_searcher
-[rg]: https://github.com/BurntSushi/ripgrep
-[us]: https://github.com/SirVer/ultisnips
diff --git a/.vim/bundle/vim-fzf/autoload/fzf/vim.vim b/.vim/bundle/vim-fzf/autoload/fzf/vim.vim
deleted file mode 100755
index 61f70a0..0000000
--- a/.vim/bundle/vim-fzf/autoload/fzf/vim.vim
+++ /dev/null
@@ -1,1718 +0,0 @@
-" Copyright (c) 2023 Junegunn Choi
-"
-" MIT License
-"
-" Permission is hereby granted, free of charge, to any person obtaining
-" a copy of this software and associated documentation files (the
-" "Software"), to deal in the Software without restriction, including
-" without limitation the rights to use, copy, modify, merge, publish,
-" distribute, sublicense, and/or sell copies of the Software, and to
-" permit persons to whom the Software is furnished to do so, subject to
-" the following conditions:
-"
-" The above copyright notice and this permission notice shall be
-" included in all copies or substantial portions of the Software.
-"
-" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-let s:cpo_save = &cpo
-set cpo&vim
-
-" ------------------------------------------------------------------
-" Common
-" ------------------------------------------------------------------
-
-function! s:conf(name, default)
- let conf = get(g:, 'fzf_vim', {})
- return get(conf, a:name, get(g:, 'fzf_' . a:name, a:default))
-endfunction
-
-let s:winpath = {}
-function! s:winpath(path)
- if has_key(s:winpath, a:path)
- return s:winpath[a:path]
- endif
-
- let winpath = split(system('for %A in ("'.a:path.'") do @echo %~sA'), "\n")[0]
- let s:winpath[a:path] = winpath
-
- return winpath
-endfunction
-
-let s:warned = 0
-function! s:bash()
- if exists('s:bash')
- return s:bash
- endif
-
- let custom_bash = s:conf('preview_bash', '')
- let git_bash = 'C:\Program Files\Git\bin\bash.exe'
- let candidates = filter(s:is_win ? [custom_bash, 'bash', git_bash] : [custom_bash, 'bash'], 'len(v:val)')
-
- let found = filter(map(copy(candidates), 'exepath(v:val)'), 'len(v:val)')
- if empty(found)
- if !s:warned
- call s:warn(printf('Preview window not supported (%s not found)', join(candidates, ', ')))
- let s:warned = 1
- endif
- let s:bash = ''
- return s:bash
- endif
-
- let s:bash = found[0]
-
- " Make 8.3 filename via cmd.exe
- if s:is_win
- let s:bash = s:winpath(s:bash)
- endif
-
- return s:bash
-endfunction
-
-function! s:escape_for_bash(path)
- if !s:is_win
- return fzf#shellescape(a:path)
- endif
-
- if !exists('s:is_linux_like_bash')
- call system(s:bash . ' -c "ls /mnt/[A-Za-z]"')
- let s:is_linux_like_bash = v:shell_error == 0
- endif
-
- let path = substitute(a:path, '\', '/', 'g')
- if s:is_linux_like_bash
- let path = substitute(path, '^\([A-Z]\):', '/mnt/\L\1', '')
- endif
-
- return escape(path, ' ')
-endfunction
-
-let s:min_version = '0.23.0'
-let s:is_win = has('win32') || has('win64')
-let s:is_wsl_bash = s:is_win && (exepath('bash') =~? 'Windows[/\\]system32[/\\]bash.exe$')
-let s:layout_keys = ['window', 'up', 'down', 'left', 'right']
-let s:bin_dir = expand(':p:h:h:h').'/bin/'
-let s:bin = {
-\ 'preview': s:bin_dir.'preview.sh',
-\ 'tags': s:bin_dir.'tags.pl' }
-let s:TYPE = {'bool': type(0), 'dict': type({}), 'funcref': type(function('call')), 'string': type(''), 'list': type([])}
-
-let s:wide = 120
-let s:checked = 0
-
-function! s:check_requirements()
- if s:checked
- return
- endif
-
- if !exists('*fzf#run')
- throw "fzf#run function not found. You also need Vim plugin from the main fzf repository (i.e. junegunn/fzf *and* junegunn/fzf.vim)"
- endif
- if !exists('*fzf#exec')
- throw "fzf#exec function not found. You need to upgrade Vim plugin from the main fzf repository ('junegunn/fzf')"
- endif
- let s:checked = !empty(fzf#exec(s:min_version))
-endfunction
-
-function! s:extend_opts(dict, eopts, prepend)
- if empty(a:eopts)
- return
- endif
- if has_key(a:dict, 'options')
- if type(a:dict.options) == s:TYPE.list && type(a:eopts) == s:TYPE.list
- if a:prepend
- let a:dict.options = extend(copy(a:eopts), a:dict.options)
- else
- call extend(a:dict.options, a:eopts)
- endif
- else
- let all_opts = a:prepend ? [a:eopts, a:dict.options] : [a:dict.options, a:eopts]
- let a:dict.options = join(map(all_opts, 'type(v:val) == s:TYPE.list ? join(map(copy(v:val), "fzf#shellescape(v:val)")) : v:val'))
- endif
- else
- let a:dict.options = a:eopts
- endif
-endfunction
-
-function! s:merge_opts(dict, eopts)
- return s:extend_opts(a:dict, a:eopts, 0)
-endfunction
-
-function! s:prepend_opts(dict, eopts)
- return s:extend_opts(a:dict, a:eopts, 1)
-endfunction
-
-" [spec to wrap], [preview window expression], [toggle-preview keys...]
-function! fzf#vim#with_preview(...)
- " Default spec
- let spec = {}
- let window = ''
-
- let args = copy(a:000)
-
- " Spec to wrap
- if len(args) && type(args[0]) == s:TYPE.dict
- let spec = copy(args[0])
- call remove(args, 0)
- endif
-
- if !executable(s:bash())
- return spec
- endif
-
- " Placeholder expression (TODO/TBD: undocumented)
- let placeholder = get(spec, 'placeholder', '{}')
-
- " g:fzf_preview_window
- if empty(args)
- let preview_args = s:conf('preview_window', ['', 'ctrl-/'])
- if empty(preview_args)
- let args = ['hidden']
- else
- " For backward-compatiblity
- let args = type(preview_args) == type('') ? [preview_args] : copy(preview_args)
- endif
- endif
-
- if len(args) && type(args[0]) == s:TYPE.string
- if len(args[0]) && args[0] !~# '^\(up\|down\|left\|right\|hidden\)'
- throw 'invalid preview window: '.args[0]
- endif
- let window = args[0]
- call remove(args, 0)
- endif
-
- let preview = []
- if len(window)
- let preview += ['--preview-window', window]
- endif
- if s:is_win
- if empty($MSWINHOME)
- let $MSWINHOME = $HOME
- endif
- if s:is_wsl_bash && $WSLENV !~# '[:]\?MSWINHOME\(\/[^:]*\)\?\(:\|$\)'
- let $WSLENV = 'MSWINHOME/u:'.$WSLENV
- endif
- endif
- let preview_cmd = s:bash() . ' ' . s:escape_for_bash(s:bin.preview)
- if len(placeholder)
- let preview += ['--preview', preview_cmd.' '.placeholder]
- end
- if &ambiwidth ==# 'double'
- let preview += ['--no-unicode']
- end
-
- if len(args)
- call extend(preview, ['--bind', join(map(args, 'v:val.":toggle-preview"'), ',')])
- endif
- call s:merge_opts(spec, preview)
- return spec
-endfunction
-
-function! s:remove_layout(opts)
- for key in s:layout_keys
- if has_key(a:opts, key)
- call remove(a:opts, key)
- endif
- endfor
- return a:opts
-endfunction
-
-function! s:reverse_list(opts)
- let tokens = map(split($FZF_DEFAULT_OPTS, '[^a-z-]'), 'substitute(v:val, "^--", "", "")')
- if index(tokens, 'reverse') < 0
- return extend(['--layout=reverse-list'], a:opts)
- endif
- return a:opts
-endfunction
-
-function! s:wrap(name, opts, bang)
- " fzf#wrap does not append --expect if sink or sink* is found
- let opts = copy(a:opts)
- let options = ''
- if has_key(opts, 'options')
- let options = type(opts.options) == s:TYPE.list ? join(opts.options) : opts.options
- endif
- if options !~ '--expect' && has_key(opts, 'sink*')
- let Sink = remove(opts, 'sink*')
- let wrapped = fzf#wrap(a:name, opts, a:bang)
- let wrapped['sink*'] = Sink
- else
- let wrapped = fzf#wrap(a:name, opts, a:bang)
- endif
- return wrapped
-endfunction
-
-function! s:strip(str)
- return substitute(a:str, '^\s*\|\s*$', '', 'g')
-endfunction
-
-function! s:rstrip(str)
- return substitute(a:str, '\s*$', '', 'g')
-endfunction
-
-function! s:chomp(str)
- return substitute(a:str, '\n*$', '', 'g')
-endfunction
-
-function! s:escape(path)
- let path = fnameescape(a:path)
- return s:is_win ? escape(path, '$') : path
-endfunction
-
-if v:version >= 704
- function! s:function(name)
- return function(a:name)
- endfunction
-else
- function! s:function(name)
- " By Ingo Karkat
- return function(substitute(a:name, '^s:', matchstr(expand(''), '\d\+_\zefunction$'), ''))
- endfunction
-endif
-
-function! s:get_color(attr, ...)
- let gui = has('termguicolors') && &termguicolors
- let fam = gui ? 'gui' : 'cterm'
- let pat = gui ? '^#[a-f0-9]\+' : '^[0-9]\+$'
- for group in a:000
- let code = synIDattr(synIDtrans(hlID(group)), a:attr, fam)
- if code =~? pat
- return code
- endif
- endfor
- return ''
-endfunction
-
-let s:ansi = {'black': 30, 'red': 31, 'green': 32, 'yellow': 33, 'blue': 34, 'magenta': 35, 'cyan': 36}
-
-function! s:csi(color, fg)
- let prefix = a:fg ? '38;' : '48;'
- if a:color[0] == '#'
- return prefix.'2;'.join(map([a:color[1:2], a:color[3:4], a:color[5:6]], 'str2nr(v:val, 16)'), ';')
- endif
- return prefix.'5;'.a:color
-endfunction
-
-function! s:ansi(str, group, default, ...)
- let fg = s:get_color('fg', a:group)
- let bg = s:get_color('bg', a:group)
- let color = (empty(fg) ? s:ansi[a:default] : s:csi(fg, 1)) .
- \ (empty(bg) ? '' : ';'.s:csi(bg, 0))
- return printf("\x1b[%s%sm%s\x1b[m", color, a:0 ? ';1' : '', a:str)
-endfunction
-
-for s:color_name in keys(s:ansi)
- execute "function! s:".s:color_name."(str, ...)\n"
- \ " return s:ansi(a:str, get(a:, 1, ''), '".s:color_name."')\n"
- \ "endfunction"
-endfor
-
-function! s:buflisted()
- return filter(range(1, bufnr('$')), 'buflisted(v:val) && getbufvar(v:val, "&filetype") != "qf"')
-endfunction
-
-function! s:fzf(name, opts, extra)
- call s:check_requirements()
-
- let [extra, bang] = [{}, 0]
- if len(a:extra) <= 1
- let first = get(a:extra, 0, 0)
- if type(first) == s:TYPE.dict
- let extra = first
- else
- let bang = first
- endif
- elseif len(a:extra) == 2
- let [extra, bang] = a:extra
- else
- throw 'invalid number of arguments'
- endif
-
- let extra = copy(extra)
- let eopts = has_key(extra, 'options') ? remove(extra, 'options') : ''
- let merged = extend(copy(a:opts), extra)
- call s:merge_opts(merged, eopts)
- return fzf#run(s:wrap(a:name, merged, bang))
-endfunction
-
-let s:default_action = {
- \ 'ctrl-t': 'tab split',
- \ 'ctrl-x': 'split',
- \ 'ctrl-v': 'vsplit' }
-
-function! s:execute_silent(cmd)
- silent keepjumps keepalt execute a:cmd
-endfunction
-
-" [key, [filename, [stay_on_edit: 0]]]
-function! s:action_for(key, ...)
- let Cmd = get(get(g:, 'fzf_action', s:default_action), a:key, '')
- let cmd = type(Cmd) == s:TYPE.string ? Cmd : ''
-
- " See If the command is the default action that opens the selected file in
- " the current window. i.e. :edit
- let edit = stridx('edit', cmd) == 0 " empty, e, ed, ..
-
- " If no extra argument is given, we just execute the command and ignore
- " errors. e.g. E471: Argument required: tab drop
- if !a:0
- if !edit
- normal! m'
- silent! call s:execute_silent(cmd)
- endif
- else
- " For the default edit action, we don't execute the action if the
- " selected file is already opened in the current window, or we are
- " instructed to stay on the current buffer.
- let stay = edit && (a:0 > 1 && a:2 || fnamemodify(a:1, ':p') ==# expand('%:p'))
- if !stay
- normal! m'
- call s:execute_silent((len(cmd) ? cmd : 'edit').' '.s:escape(a:1))
- endif
- endif
-endfunction
-
-function! s:open(target)
- if fnamemodify(a:target, ':p') ==# expand('%:p')
- return
- endif
- execute 'edit' s:escape(a:target)
-endfunction
-
-function! s:align_lists(lists)
- let maxes = {}
- for list in a:lists
- let i = 0
- while i < len(list)
- let maxes[i] = max([get(maxes, i, 0), len(list[i])])
- let i += 1
- endwhile
- endfor
- for list in a:lists
- call map(list, "printf('%-'.maxes[v:key].'s', v:val)")
- endfor
- return a:lists
-endfunction
-
-function! s:warn(message)
- echohl WarningMsg
- echom a:message
- echohl None
- return 0
-endfunction
-
-function! s:fill_quickfix(name, list)
- if len(a:list) > 1
- let Handler = s:conf('listproc_'.a:name, s:conf('listproc', function('fzf#vim#listproc#quickfix')))
- call call(Handler, [a:list], {})
- return 1
- endif
- return 0
-endfunction
-
-function! fzf#vim#_uniq(list)
- let visited = {}
- let ret = []
- for l in a:list
- if !empty(l) && !has_key(visited, l)
- call add(ret, l)
- let visited[l] = 1
- endif
- endfor
- return ret
-endfunction
-
-" ------------------------------------------------------------------
-" Files
-" ------------------------------------------------------------------
-function! s:shortpath()
- let short = fnamemodify(getcwd(), ':~:.')
- if !has('win32unix')
- let short = pathshorten(short)
- endif
- let slash = (s:is_win && !&shellslash) ? '\' : '/'
- return empty(short) ? '~'.slash : short . (short =~ escape(slash, '\').'$' ? '' : slash)
-endfunction
-
-function! fzf#vim#files(dir, ...)
- let args = {}
- if !empty(a:dir)
- if !isdirectory(expand(a:dir))
- return s:warn('Invalid directory')
- endif
- let slash = (s:is_win && !&shellslash) ? '\\' : '/'
- let dir = substitute(a:dir, '[/\\]*$', slash, '')
- let args.dir = dir
- else
- let dir = s:shortpath()
- endif
-
- let args.options = ['-m', '--prompt', strwidth(dir) < &columns / 2 - 20 ? dir : '> ']
- call s:merge_opts(args, s:conf('files_options', []))
- return s:fzf('files', args, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Lines
-" ------------------------------------------------------------------
-function! s:line_handler(lines)
- if len(a:lines) < 2
- return
- endif
-
- let qfl = []
- for line in a:lines[1:]
- let chunks = split(line, "\t", 1)
- call add(qfl, {'bufnr': str2nr(chunks[0]), 'lnum': str2nr(chunks[2]), 'text': join(chunks[3:], "\t")})
- endfor
-
- call s:action_for(a:lines[0])
- if !s:fill_quickfix('lines', qfl)
- let chunks = split(a:lines[1], '\t')
- execute 'buffer' chunks[0]
- execute chunks[2]
- endif
- normal! ^zvzz
-endfunction
-
-function! fzf#vim#_lines(all)
- let cur = []
- let rest = []
- let buf = bufnr('')
- let longest_name = 0
- let display_bufnames = &columns > s:wide
- if display_bufnames
- let bufnames = {}
- for b in s:buflisted()
- let bufnames[b] = pathshorten(fnamemodify(bufname(b), ":~:."))
- let longest_name = max([longest_name, len(bufnames[b])])
- endfor
- endif
- let len_bufnames = min([15, longest_name])
- for b in s:buflisted()
- let lines = getbufline(b, 1, "$")
- if empty(lines)
- let path = fnamemodify(bufname(b), ':p')
- let lines = filereadable(path) ? readfile(path) : []
- endif
- if display_bufnames
- let bufname = bufnames[b]
- if len(bufname) > len_bufnames + 1
- let bufname = '…' . bufname[-len_bufnames+1:]
- endif
- let bufname = printf(s:green("%".len_bufnames."s", "Directory"), bufname)
- else
- let bufname = ''
- endif
- let linefmt = s:blue("%2d\t", "TabLine")."%s".s:yellow("\t%4d ", "LineNr")."\t%s"
- call extend(b == buf ? cur : rest,
- \ filter(
- \ map(lines,
- \ '(!a:all && empty(v:val)) ? "" : printf(linefmt, b, bufname, v:key + 1, v:val)'),
- \ 'a:all || !empty(v:val)'))
- endfor
- return [display_bufnames, extend(cur, rest)]
-endfunction
-
-function! fzf#vim#lines(...)
- let [display_bufnames, lines] = fzf#vim#_lines(1)
- let nth = display_bufnames ? 3 : 2
- let [query, args] = (a:0 && type(a:1) == type('')) ?
- \ [a:1, a:000[1:]] : ['', a:000]
- return s:fzf('lines', {
- \ 'source': lines,
- \ 'sink*': s:function('s:line_handler'),
- \ 'options': s:reverse_list(['--tiebreak=index', '--prompt', 'Lines> ', '--ansi', '--extended', '--nth='.nth.'..', '--tabstop=1', '--query', query, '--multi'])
- \}, args)
-endfunction
-
-" ------------------------------------------------------------------
-" BLines
-" ------------------------------------------------------------------
-function! s:buffer_line_handler(lines)
- if len(a:lines) < 2
- return
- endif
- let qfl = []
- for line in a:lines[1:]
- let chunks = split(line, "\t", 1)
- let ln = chunks[0]
- let ltxt = join(chunks[1:], "\t")
- call add(qfl, {'filename': expand('%'), 'lnum': str2nr(ln), 'text': ltxt})
- endfor
- call s:action_for(a:lines[0])
- if !s:fill_quickfix('blines', qfl)
- execute split(a:lines[1], '\t')[0]
- endif
- normal! ^zvzz
-endfunction
-
-function! s:buffer_lines(query)
- let linefmt = s:yellow(" %4d ", "LineNr")."\t%s"
- let fmtexpr = 'printf(linefmt, v:key + 1, v:val)'
- let lines = getline(1, '$')
- if empty(a:query)
- return map(lines, fmtexpr)
- end
- return filter(map(lines, 'v:val =~ a:query ? '.fmtexpr.' : ""'), 'len(v:val)')
-endfunction
-
-function! fzf#vim#buffer_lines(...)
- let [query, args] = (a:0 && type(a:1) == type('')) ?
- \ [a:1, a:000[1:]] : ['', a:000]
- return s:fzf('blines', {
- \ 'source': s:buffer_lines(query),
- \ 'sink*': s:function('s:buffer_line_handler'),
- \ 'options': s:reverse_list(['+m', '--tiebreak=index', '--multi', '--prompt', 'BLines> ', '--ansi', '--extended', '--nth=2..', '--tabstop=1'])
- \}, args)
-endfunction
-
-" ------------------------------------------------------------------
-" Colors
-" ------------------------------------------------------------------
-function! fzf#vim#colors(...)
- let colors = split(globpath(&rtp, "colors/*.vim"), "\n")
- if has('packages')
- let colors += split(globpath(&packpath, "pack/*/opt/*/colors/*.vim"), "\n")
- endif
- return s:fzf('colors', {
- \ 'source': fzf#vim#_uniq(map(colors, "substitute(fnamemodify(v:val, ':t'), '\\..\\{-}$', '', '')")),
- \ 'sink': 'colo',
- \ 'options': '+m --prompt="Colors> "'
- \}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Locate
-" ------------------------------------------------------------------
-function! fzf#vim#locate(query, ...)
- return s:fzf('locate', {
- \ 'source': 'locate '.a:query,
- \ 'options': '-m --prompt "Locate> "'
- \}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" History[:/]
-" ------------------------------------------------------------------
-function! fzf#vim#_recent_files()
- return fzf#vim#_uniq(map(
- \ filter([expand('%')], 'len(v:val)')
- \ + filter(map(fzf#vim#_buflisted_sorted(), 'bufname(v:val)'), 'len(v:val)')
- \ + filter(copy(v:oldfiles), "filereadable(fnamemodify(v:val, ':p'))"),
- \ 'fnamemodify(v:val, ":~:.")'))
-endfunction
-
-function! s:history_source(type)
- let max = histnr(a:type)
- if max <= 0
- return ['No entries']
- endif
- let fmt = s:yellow(' %'.len(string(max)).'d ', 'Number')
- let list = filter(map(range(1, max), 'histget(a:type, - v:val)'), '!empty(v:val)')
- return extend([' :: Press '.s:magenta('CTRL-E', 'Special').' to edit'],
- \ map(list, 'printf(fmt, len(list) - v:key)." ".v:val'))
-endfunction
-
-nnoremap (-fzf-vim-do) :execute g:__fzf_command
-nnoremap (-fzf-/) /
-nnoremap (-fzf-:) :
-
-function! s:history_sink(type, lines)
- if len(a:lines) < 2
- return
- endif
-
- let prefix = "\(-fzf-".a:type.')'
- let key = a:lines[0]
- let item = matchstr(a:lines[1], ' *[0-9]\+ *\zs.*')
- if key == 'ctrl-e'
- call histadd(a:type, item)
- redraw
- call feedkeys(a:type."\", 'n')
- else
- if a:type == ':'
- call histadd(a:type, item)
- endif
- let g:__fzf_command = "normal ".prefix.item."\"
- call feedkeys("\(-fzf-vim-do)")
- endif
-endfunction
-
-function! s:cmd_history_sink(lines)
- call s:history_sink(':', a:lines)
-endfunction
-
-function! fzf#vim#command_history(...)
- return s:fzf('history-command', {
- \ 'source': s:history_source(':'),
- \ 'sink*': s:function('s:cmd_history_sink'),
- \ 'options': '+m --ansi --prompt="Hist:> " --header-lines=1 --expect=ctrl-e --tiebreak=index'}, a:000)
-endfunction
-
-function! s:search_history_sink(lines)
- call s:history_sink('/', a:lines)
-endfunction
-
-function! fzf#vim#search_history(...)
- return s:fzf('history-search', {
- \ 'source': s:history_source('/'),
- \ 'sink*': s:function('s:search_history_sink'),
- \ 'options': '+m --ansi --prompt="Hist/> " --header-lines=1 --expect=ctrl-e --tiebreak=index'}, a:000)
-endfunction
-
-function! fzf#vim#history(...)
- return s:fzf('history-files', {
- \ 'source': fzf#vim#_recent_files(),
- \ 'options': ['-m', '--header-lines', !empty(expand('%')), '--prompt', 'Hist> ']
- \}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" GFiles[?]
-" ------------------------------------------------------------------
-
-function! s:get_git_root(dir)
- let dir = len(a:dir) ? a:dir : substitute(split(expand('%:p:h'), '[/\\]\.git\([/\\]\|$\)')[0], '^fugitive://', '', '')
- let root = systemlist('git -C ' . fzf#shellescape(dir) . ' rev-parse --show-toplevel')[0]
- return v:shell_error ? '' : (len(a:dir) ? fnamemodify(a:dir, ':p') : root)
-endfunction
-
-function! s:version_requirement(val, min)
- for idx in range(0, len(a:min) - 1)
- let v = get(a:val, idx, 0)
- if v < a:min[idx] | return 0
- elseif v > a:min[idx] | return 1
- endif
- endfor
- return 1
-endfunction
-
-function! s:git_version_requirement(...)
- if !exists('s:git_version')
- let s:git_version = map(split(split(system('git --version'))[2], '\.'), 'str2nr(v:val)')
- endif
- return s:version_requirement(s:git_version, a:000)
-endfunction
-
-function! fzf#vim#gitfiles(args, ...)
- let dir = get(get(a:, 1, {}), 'dir', '')
- let root = s:get_git_root(dir)
- if empty(root)
- return s:warn('Not in git repo')
- endif
- let prefix = 'git -C ' . fzf#shellescape(root) . ' '
- if a:args != '?'
- let source = prefix . 'ls-files -z ' . a:args
- if s:git_version_requirement(2, 31)
- let source .= ' --deduplicate'
- endif
- return s:fzf('gfiles', {
- \ 'source': source,
- \ 'dir': root,
- \ 'options': '-m --read0 --prompt "GitFiles> "'
- \}, a:000)
- endif
-
- " Here be dragons!
- " We're trying to access the common sink function that fzf#wrap injects to
- " the options dictionary.
- let bar = s:is_win ? '^|' : '|'
- let diff_prefix = 'git -C ' . s:escape_for_bash(root) . ' '
- let preview = printf(
- \ s:bash() . ' -c "if [[ {1} =~ M ]]; then %s; else %s {-1}; fi"',
- \ executable('delta')
- \ ? diff_prefix . 'diff -- {-1} ' . bar . ' delta --width $FZF_PREVIEW_COLUMNS --file-style=omit ' . bar . ' sed 1d'
- \ : diff_prefix . 'diff --color=always -- {-1} ' . bar . ' sed 1,4d',
- \ s:escape_for_bash(s:bin.preview))
- let wrapped = fzf#wrap({
- \ 'source': prefix . '-c color.status=always status --short --untracked-files=all',
- \ 'dir': root,
- \ 'options': ['--ansi', '--multi', '--nth', '2..,..', '--tiebreak=index', '--prompt', 'GitFiles?> ', '--preview', preview]
- \})
- call s:remove_layout(wrapped)
- let wrapped.common_sink = remove(wrapped, 'sink*')
- function! wrapped.newsink(lines)
- let lines = extend(a:lines[0:0], map(a:lines[1:], 'substitute(v:val[3:], ".* -> ", "", "")'))
- return self.common_sink(lines)
- endfunction
- let wrapped['sink*'] = remove(wrapped, 'newsink')
- return s:fzf('gfiles-diff', wrapped, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Buffers
-" ------------------------------------------------------------------
-function! s:find_open_window(b)
- let [tcur, tcnt] = [tabpagenr() - 1, tabpagenr('$')]
- for toff in range(0, tabpagenr('$') - 1)
- let t = (tcur + toff) % tcnt + 1
- let buffers = tabpagebuflist(t)
- for w in range(1, len(buffers))
- let b = buffers[w - 1]
- if b == a:b
- return [t, w]
- endif
- endfor
- endfor
- return [0, 0]
-endfunction
-
-function! s:jump(t, w)
- execute a:t.'tabnext'
- execute a:w.'wincmd w'
-endfunction
-
-function! s:bufopen(lines)
- if len(a:lines) < 2
- return
- endif
- let b = matchstr(a:lines[1], '\[\zs[0-9]*\ze\]')
- if empty(a:lines[0]) && s:conf('buffers_jump', 0)
- let [t, w] = s:find_open_window(b)
- if t
- call s:jump(t, w)
- return
- endif
- endif
- call s:action_for(a:lines[0])
- execute 'buffer' b
-endfunction
-
-function! fzf#vim#_format_buffer(b)
- let name = bufname(a:b)
- let line = exists('*getbufinfo') ? getbufinfo(a:b)[0]['lnum'] : 0
- let fullname = empty(name) ? '' : fnamemodify(name, ":p:~:.")
- let dispname = empty(name) ? '[No Name]' : name
- let flag = a:b == bufnr('') ? s:blue('%', 'Conditional') :
- \ (a:b == bufnr('#') ? s:magenta('#', 'Special') : ' ')
- let modified = getbufvar(a:b, '&modified') ? s:red(' [+]', 'Exception') : ''
- let readonly = getbufvar(a:b, '&modifiable') ? '' : s:green(' [RO]', 'Constant')
- let extra = join(filter([modified, readonly], '!empty(v:val)'), '')
- let target = empty(name) ? '' : (line == 0 ? fullname : fullname.':'.line)
- return s:rstrip(printf("%s\t%d\t[%s] %s\t%s\t%s", target, line, s:yellow(a:b, 'Number'), flag, dispname, extra))
-endfunction
-
-function! s:sort_buffers(...)
- let [b1, b2] = map(copy(a:000), 'get(g:fzf#vim#buffers, v:val, v:val)')
- " Using minus between a float and a number in a sort function causes an error
- return b1 < b2 ? 1 : -1
-endfunction
-
-function! fzf#vim#_buflisted_sorted()
- return sort(s:buflisted(), 's:sort_buffers')
-endfunction
-
-" [query (string)], [bufnrs (list)], [spec (dict)], [fullscreen (bool)]
-function! fzf#vim#buffers(...)
- let [query, args] = (a:0 && type(a:1) == type('')) ?
- \ [a:1, a:000[1:]] : ['', a:000]
- if len(args) && type(args[0]) == s:TYPE.list
- let [buffers; args] = args
- else
- let buffers = s:buflisted()
- endif
- let sorted = sort(buffers, 's:sort_buffers')
- let header_lines = '--header-lines=' . (bufnr('') == get(sorted, 0, 0) ? 1 : 0)
- let tabstop = len(max(sorted)) >= 4 ? 9 : 8
- return s:fzf('buffers', {
- \ 'source': map(sorted, 'fzf#vim#_format_buffer(v:val)'),
- \ 'sink*': s:function('s:bufopen'),
- \ 'options': ['+m', '-x', '--tiebreak=index', header_lines, '--ansi', '-d', '\t', '--with-nth', '3..', '-n', '2,1..2', '--prompt', 'Buf> ', '--query', query, '--preview-window', '+{2}-/2', '--tabstop', tabstop]
- \}, args)
-endfunction
-
-" ------------------------------------------------------------------
-" Ag / Rg
-" ------------------------------------------------------------------
-function! s:ag_to_qf(line)
- let parts = matchlist(a:line, '\(.\{-}\)\s*:\s*\(\d\+\)\%(\s*:\s*\(\d\+\)\)\?\%(\s*:\(.*\)\)\?')
- let dict = {'filename': &acd ? fnamemodify(parts[1], ':p') : parts[1], 'lnum': parts[2], 'text': parts[4]}
- if len(parts[3])
- let dict.col = parts[3]
- endif
- return dict
-endfunction
-
-function! s:ag_handler(name, lines)
- if len(a:lines) < 2
- return
- endif
-
- let list = map(filter(a:lines[1:], 'len(v:val)'), 's:ag_to_qf(v:val)')
- if empty(list)
- return
- endif
-
- call s:action_for(a:lines[0], list[0].filename, len(list) > 1)
- if s:fill_quickfix(a:name, list)
- return
- endif
-
- " Single item selected
- let first = list[0]
- try
- execute first.lnum
- if has_key(first, 'col')
- call cursor(0, first.col)
- endif
- normal! zvzz
- catch
- endtry
-endfunction
-
-" query, [ag options], [spec (dict)], [fullscreen (bool)]
-function! fzf#vim#ag(query, ...)
- if type(a:query) != s:TYPE.string
- return s:warn('Invalid query argument')
- endif
- let query = empty(a:query) ? '^(?=.)' : a:query
- let args = copy(a:000)
- let ag_opts = len(args) > 1 && type(args[0]) == s:TYPE.string ? remove(args, 0) : ''
- let command = ag_opts . ' -- ' . fzf#shellescape(query)
- return call('fzf#vim#ag_raw', insert(args, command, 0))
-endfunction
-
-" ag command suffix, [spec (dict)], [fullscreen (bool)]
-function! fzf#vim#ag_raw(command_suffix, ...)
- if !executable('ag')
- return s:warn('ag is not found')
- endif
- return call('fzf#vim#grep', extend(['ag --nogroup --column --color '.a:command_suffix, 1], a:000))
-endfunction
-
-" command (string), [spec (dict)], [fullscreen (bool)]
-function! fzf#vim#grep(grep_command, ...)
- let args = copy(a:000)
- let words = []
- for word in split(a:grep_command)
- if word !~# '^[a-z]'
- break
- endif
- call add(words, word)
- endfor
- let words = empty(words) ? ['grep'] : words
- let name = join(words, '-')
- let capname = join(map(words, 'toupper(v:val[0]).v:val[1:]'), '')
- let opts = {
- \ 'options': ['--ansi', '--prompt', capname.'> ',
- \ '--multi', '--bind', 'alt-a:select-all,alt-d:deselect-all',
- \ '--delimiter', ':', '--preview-window', '+{2}-/2']
- \}
- if len(args) && type(args[0]) == s:TYPE.bool
- call remove(args, 0)
- endif
-
- function! opts.sink(lines) closure
- return s:ag_handler(get(opts, 'name', name), a:lines)
- endfunction
- let opts['sink*'] = remove(opts, 'sink')
- try
- let prev_default_command = $FZF_DEFAULT_COMMAND
- let $FZF_DEFAULT_COMMAND = a:grep_command
- return s:fzf(name, opts, args)
- finally
- let $FZF_DEFAULT_COMMAND = prev_default_command
- endtry
-endfunction
-
-
-" command_prefix (string), initial_query (string), [spec (dict)], [fullscreen (bool)]
-function! fzf#vim#grep2(command_prefix, query, ...)
- let args = copy(a:000)
- let words = []
- for word in split(a:command_prefix)
- if word !~# '^[a-z]'
- break
- endif
- call add(words, word)
- endfor
- let words = empty(words) ? ['grep'] : words
- let name = join(words, '-')
- let opts = {
- \ 'source': ':',
- \ 'options': ['--ansi', '--prompt', toupper(name).'> ', '--query', a:query,
- \ '--disabled',
- \ '--bind', 'start:reload:'.a:command_prefix.' '.fzf#shellescape(a:query),
- \ '--bind', 'change:reload:'.a:command_prefix.' {q} || :',
- \ '--multi', '--bind', 'alt-a:select-all,alt-d:deselect-all',
- \ '--delimiter', ':', '--preview-window', '+{2}-/2']
- \}
- if len(args) && type(args[0]) == s:TYPE.bool
- call remove(args, 0)
- endif
- function! opts.sink(lines) closure
- return s:ag_handler(name, a:lines)
- endfunction
- let opts['sink*'] = remove(opts, 'sink')
- return s:fzf(name, opts, args)
-endfunction
-
-" ------------------------------------------------------------------
-" BTags
-" ------------------------------------------------------------------
-function! s:btags_source(tag_cmds)
- if !filereadable(expand('%'))
- throw 'Save the file first'
- endif
-
- for cmd in a:tag_cmds
- let lines = split(system(cmd), "\n")
- if !v:shell_error && len(lines)
- break
- endif
- endfor
- if v:shell_error
- throw get(lines, 0, 'Failed to extract tags')
- elseif empty(lines)
- throw 'No tags found'
- endif
- return map(s:align_lists(map(lines, 'split(v:val, "\t")')), 'join(v:val, "\t")')
-endfunction
-
-function! s:btags_sink(lines)
- if len(a:lines) < 2
- return
- endif
- call s:action_for(a:lines[0])
- let qfl = []
- for line in a:lines[1:]
- call s:execute_silent(split(line, "\t")[2])
- call add(qfl, {'filename': expand('%'), 'lnum': line('.'), 'text': getline('.')})
- endfor
-
- if len(qfl) > 1
- " Go back to the original position
- normal! g`'
- " Because 'listproc' will use 'cfirst' to go to the first item in the list
- call s:fill_quickfix('btags', qfl)
- else
- normal! zvzz
- endif
-endfunction
-
-" query, [tag commands], [spec (dict)], [fullscreen (bool)]
-function! fzf#vim#buffer_tags(query, ...)
- let args = copy(a:000)
- let escaped = fzf#shellescape(expand('%'))
- let null = s:is_win ? 'nul' : '/dev/null'
- let sort = has('unix') && !has('win32unix') && executable('sort') ? '| sort -s -k 5' : ''
- let tag_cmds = (len(args) > 1 && type(args[0]) != type({})) ? remove(args, 0) : [
- \ printf('ctags -f - --sort=yes --excmd=number --language-force=%s %s 2> %s %s', get({ 'cpp': 'c++' }, &filetype, &filetype), escaped, null, sort),
- \ printf('ctags -f - --sort=yes --excmd=number %s 2> %s %s', escaped, null, sort)]
- if type(tag_cmds) != type([])
- let tag_cmds = [tag_cmds]
- endif
- try
- return s:fzf('btags', {
- \ 'source': s:btags_source(tag_cmds),
- \ 'sink*': s:function('s:btags_sink'),
- \ 'options': s:reverse_list(['-m', '-d', '\t', '--with-nth', '1,4..', '-n', '1', '--prompt', 'BTags> ', '--query', a:query, '--preview-window', '+{3}-/2'])}, args)
- catch
- return s:warn(v:exception)
- endtry
-endfunction
-
-" ------------------------------------------------------------------
-" Tags
-" ------------------------------------------------------------------
-function! s:tags_sink(lines)
- if len(a:lines) < 2
- return
- endif
-
- " Remember the current position
- let buf = bufnr()
- let view = winsaveview()
-
- let qfl = []
- let [key; list] = a:lines
-
- try
- let [magic, &magic, wrapscan, &wrapscan, acd, &acd] = [&magic, 0, &wrapscan, 1, &acd, 0]
- for line in list
- try
- let parts = split(line, '\t\zs')
- let excmd = matchstr(join(parts[2:-2], '')[:-2], '^.\{-}\ze;\?"\t')
- let base = fnamemodify(parts[-1], ':h')
- let relpath = parts[1][:-2]
- let abspath = relpath =~ (s:is_win ? '^[A-Z]:\' : '^/') ? relpath : join([base, relpath], '/')
-
- if len(list) == 1
- call s:action_for(key, expand(abspath, 1))
- else
- call s:open(expand(abspath, 1))
- endif
- call s:execute_silent(excmd)
- call add(qfl, {'filename': expand('%'), 'lnum': line('.'), 'text': getline('.')})
- catch /^Vim:Interrupt$/
- break
- catch
- call s:warn(v:exception)
- endtry
- endfor
- finally
- let [&magic, &wrapscan, &acd] = [magic, wrapscan, acd]
- endtry
-
- if len(qfl) > 1
- " Go back to the original position. Because 'listproc' will use 'cfirst'
- " to go to the first item in the list.
- call s:execute_silent('b '.buf)
- call winrestview(view)
-
- " However, if a non-default action is triggered, we need to open the first
- " entry using the action, to be as backward compatible as possible.
- call s:action_for(key, qfl[0].filename, 1)
-
- call s:fill_quickfix('tags', qfl)
- else
- normal! ^zvzz
- endif
-endfunction
-
-function! fzf#vim#tags(query, ...)
- if !executable('perl')
- return s:warn('Tags command requires perl')
- endif
- if empty(tagfiles())
- call inputsave()
- echohl WarningMsg
- let gen = input('tags not found. Generate? (y/N) ')
- echohl None
- call inputrestore()
- redraw
- if gen =~? '^y'
- call s:warn('Preparing tags')
- call system(s:conf('tags_command', 'ctags -R'.(s:is_win ? ' --output-format=e-ctags' : '')))
- if empty(tagfiles())
- return s:warn('Failed to create tags')
- endif
- else
- return s:warn('No tags found')
- endif
- endif
-
- let tagfiles = tagfiles()
- let v2_limit = 1024 * 1024 * 200
- for tagfile in tagfiles
- let v2_limit -= getfsize(tagfile)
- if v2_limit < 0
- break
- endif
- endfor
- let opts = v2_limit < 0 ? ['--algo=v1'] : []
-
- return s:fzf('tags', {
- \ 'source': 'perl '.fzf#shellescape(s:bin.tags).' '.join(map(tagfiles, 'fzf#shellescape(fnamemodify(v:val, ":p"))')),
- \ 'sink*': s:function('s:tags_sink'),
- \ 'options': extend(opts, ['--nth', '1..2', '-m', '-d', '\t', '--tiebreak=begin', '--prompt', 'Tags> ', '--query', a:query])}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Snippets (UltiSnips)
-" ------------------------------------------------------------------
-function! s:inject_snippet(line)
- let snip = split(a:line, "\t")[0]
- execute 'normal! a'.s:strip(snip)."\=UltiSnips#ExpandSnippet()\"
-endfunction
-
-function! fzf#vim#snippets(...)
- if !exists(':UltiSnipsEdit')
- return s:warn('UltiSnips not found')
- endif
- let list = UltiSnips#SnippetsInCurrentScope()
- if empty(list)
- return s:warn('No snippets available here')
- endif
- let aligned = sort(s:align_lists(items(list)))
- let colored = map(aligned, 's:yellow(v:val[0])."\t".v:val[1]')
- return s:fzf('snippets', {
- \ 'source': colored,
- \ 'options': '--ansi --tiebreak=index +m -n 1,.. -d "\t"',
- \ 'sink': s:function('s:inject_snippet')}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Commands
-" ------------------------------------------------------------------
-let s:nbs = nr2char(0xa0)
-
-function! s:format_cmd(line)
- return substitute(a:line, '\C \([A-Z]\S*\) ',
- \ '\=s:nbs.s:yellow(submatch(1), "Function").s:nbs', '')
-endfunction
-
-function! s:command_sink(lines)
- if len(a:lines) < 2
- return
- endif
- let cmd = matchstr(a:lines[1], s:nbs.'\zs\S*\ze'.s:nbs)
- if empty(a:lines[0])
- call feedkeys(':'.cmd.(a:lines[1][0] == '!' ? '' : ' '), 'n')
- else
- call feedkeys(':'.cmd."\", 'n')
- endif
-endfunction
-
-let s:fmt_excmd = ' '.s:blue('%-38s', 'Statement').'%s'
-
-function! s:format_excmd(ex)
- let match = matchlist(a:ex, '^|:\(\S\+\)|\s*\S*\(.*\)')
- return printf(s:fmt_excmd, s:nbs.match[1].s:nbs, s:strip(match[2]))
-endfunction
-
-function! s:excmds()
- let help = globpath($VIMRUNTIME, 'doc/index.txt')
- if empty(help)
- return []
- endif
-
- let commands = []
- let command = ''
- for line in readfile(help)
- if line =~ '^|:[^|]'
- if !empty(command)
- call add(commands, s:format_excmd(command))
- endif
- let command = line
- elseif line =~ '^\s\+\S' && !empty(command)
- let command .= substitute(line, '^\s*', ' ', '')
- elseif !empty(commands) && line =~ '^\s*$'
- break
- endif
- endfor
- if !empty(command)
- call add(commands, s:format_excmd(command))
- endif
- return commands
-endfunction
-
-function! fzf#vim#commands(...)
- redir => cout
- silent command
- redir END
- let list = split(cout, "\n")
- return s:fzf('commands', {
- \ 'source': extend(extend(list[0:0], map(list[1:], 's:format_cmd(v:val)')), s:excmds()),
- \ 'sink*': s:function('s:command_sink'),
- \ 'options': '--ansi --expect '.s:conf('commands_expect', 'ctrl-x').
- \ ' --tiebreak=index --header-lines 1 -x --prompt "Commands> " -n2,3,2..3 -d'.s:nbs}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Changes
-" ------------------------------------------------------------------
-
-function! s:format_change(bufnr, offset, item)
- return printf("%3d %s %4d %3d %s", a:bufnr, s:yellow(printf('%6s', a:offset)), a:item.lnum, a:item.col, getbufline(a:bufnr, a:item.lnum)[0])
-endfunction
-
-function! s:changes_sink(lines)
- if len(a:lines) < 2
- return
- endif
-
- call s:action_for(a:lines[0])
- let [b, o, l, c] = split(a:lines[1])[0:3]
-
- if o == '-'
- execute 'buffer' b
- call cursor(l, c)
- elseif o[0] == '+'
- execute 'normal!' o[1:].'g,'
- else
- execute 'normal!' o.'g;'
- endif
-endfunction
-
-function! s:format_change_offset(current, index, cursor)
- if !a:current
- return '-'
- endif
-
- let offset = a:index - a:cursor + 1
- if offset < 0
- return '+'.-offset
- endif
- return offset
-endfunction
-
-function! fzf#vim#changes(...)
- let all_changes = ["buf offset line col text"]
- let cursor = 0
- for bufnr in fzf#vim#_buflisted_sorted()
- let [changes, position_or_length] = getchangelist(bufnr)
- let current = bufnr() == bufnr
- if current
- let cursor = len(changes) - position_or_length
- endif
- let all_changes += map(reverse(changes), { idx, val -> s:format_change(bufnr, s:format_change_offset(current, idx, cursor), val) })
- endfor
-
- return s:fzf('changes', {
- \ 'source': all_changes,
- \ 'sink*': s:function('s:changes_sink'),
- \ 'options': printf('+m -x --ansi --tiebreak=index --header-lines=1 --cycle --scroll-off 999 --sync --bind start:pos:%d --prompt "Changes> "', cursor)}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Marks
-" ------------------------------------------------------------------
-function! s:format_mark(line)
- return substitute(a:line, '\S', '\=s:yellow(submatch(0), "Number")', '')
-endfunction
-
-function! s:mark_sink(lines)
- if len(a:lines) < 2
- return
- endif
- call s:action_for(a:lines[0])
- execute 'normal! `'.matchstr(a:lines[1], '\S').'zz'
-endfunction
-
-function! fzf#vim#marks(...)
- redir => cout
- silent marks
- redir END
- let list = split(cout, "\n")
- return s:fzf('marks', {
- \ 'source': extend(list[0:0], map(list[1:], 's:format_mark(v:val)')),
- \ 'sink*': s:function('s:mark_sink'),
- \ 'options': '+m -x --ansi --tiebreak=index --header-lines 1 --tiebreak=begin --prompt "Marks> "'}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Jumps
-" ------------------------------------------------------------------
-function! s:jump_format(line)
- return substitute(a:line, '[0-9]\+', '\=s:yellow(submatch(0), "Number")', '')
-endfunction
-
-function! s:jump_sink(lines)
- if len(a:lines) < 2
- return
- endif
- call s:action_for(a:lines[0])
- let idx = index(s:jumplist, a:lines[1])
- if idx == -1
- return
- endif
- let current = match(s:jumplist, '\v^\s*\>')
- let delta = idx - current
- if delta < 0
- execute 'normal! ' . -delta . "\"
- else
- execute 'normal! ' . delta . "\"
- endif
-endfunction
-
-function! fzf#vim#jumps(...)
- redir => cout
- silent jumps
- redir END
- let s:jumplist = split(cout, '\n')
- let current = -match(s:jumplist, '\v^\s*\>')
- return s:fzf('jumps', {
- \ 'source' : extend(s:jumplist[0:0], map(s:jumplist[1:], 's:jump_format(v:val)')),
- \ 'sink*' : s:function('s:jump_sink'),
- \ 'options' : '+m -x --ansi --tiebreak=index --cycle --scroll-off 999 --sync --bind start:pos:'.current.' --tac --header-lines 1 --tiebreak=begin --prompt "Jumps> "',
- \ }, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Help tags
-" ------------------------------------------------------------------
-function! s:helptag_sink(line)
- let [tag, file, path] = split(a:line, "\t")[0:2]
- let rtp = fnamemodify(path, ':p:h:h')
- if stridx(&rtp, rtp) < 0
- execute 'set rtp+='.s:escape(rtp)
- endif
- execute 'help' tag
-endfunction
-
-function! fzf#vim#helptags(...)
- if !executable('perl')
- return s:warn('Helptags command requires perl')
- endif
- let sorted = sort(split(globpath(&runtimepath, 'doc/tags', 1), '\n'))
- let tags = exists('*uniq') ? uniq(sorted) : fzf#vim#_uniq(sorted)
-
- if exists('s:helptags_script')
- silent! call delete(s:helptags_script)
- endif
- let s:helptags_script = tempname()
-
- call writefile(['for my $filename (@ARGV) { open(my $file,q(<),$filename) or die; while (<$file>) { /(.*?)\t(.*?)\t(.*)/; push @lines, sprintf(qq('.s:green('%-40s', 'Label').'\t%s\t%s\t%s\n), $1, $2, $filename, $3); } close($file) or die; } print for sort @lines;'], s:helptags_script)
- return s:fzf('helptags', {
- \ 'source': 'perl '.fzf#shellescape(s:helptags_script).' '.join(map(tags, 'fzf#shellescape(v:val)')),
- \ 'sink': s:function('s:helptag_sink'),
- \ 'options': ['--ansi', '+m', '--tiebreak=begin', '--with-nth', '..3']}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" File types
-" ------------------------------------------------------------------
-function! fzf#vim#filetypes(...)
- return s:fzf('filetypes', {
- \ 'source': fzf#vim#_uniq(sort(map(split(globpath(&rtp, 'syntax/*.vim'), '\n'),
- \ 'fnamemodify(v:val, ":t:r")'))),
- \ 'sink': 'setf',
- \ 'options': '+m --prompt="File types> "'
- \}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Windows
-" ------------------------------------------------------------------
-function! s:format_win(tab, win, buf)
- let modified = getbufvar(a:buf, '&modified')
- let name = bufname(a:buf)
- let name = empty(name) ? s:nbs.s:nbs.'[No Name]' : ' '.s:nbs.name
- let active = tabpagewinnr(a:tab) == a:win
- return (active? s:blue('>', 'Operator') : ' ') . name . s:nbs . (modified? s:red(' [+]', 'Exception') : '')
-endfunction
-
-function! s:windows_sink(line)
- let list = matchlist(a:line, '^ *\([0-9]\+\) *\([0-9]\+\)')
- call s:jump(list[1], list[2])
-endfunction
-
-function! fzf#vim#windows(...)
- let lines = []
- for t in range(1, tabpagenr('$'))
- let buffers = tabpagebuflist(t)
- for w in range(1, len(buffers))
- call add(lines,
- \ printf('%s %s %s',
- \ s:yellow(printf('%3d', t), 'Number'),
- \ s:cyan(printf('%3d', w), 'String'),
- \ s:format_win(t, w, buffers[w-1])))
- endfor
- endfor
- return s:fzf('windows', {
- \ 'source': extend(['Tab Win Name'], lines),
- \ 'sink': s:function('s:windows_sink'),
- \ 'options': '+m --ansi --tiebreak=begin --header-lines=1 -d'.s:nbs}, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" Commits / BCommits
-" ------------------------------------------------------------------
-function! s:yank_to_register(data)
- let @" = a:data
- silent! let @* = a:data
- silent! let @+ = a:data
-endfunction
-
-function! s:commits_sink(lines)
- if len(a:lines) < 2
- return
- endif
-
- let pat = '[0-9a-f]\{7,40}'
-
- if a:lines[0] == 'ctrl-y'
- let hashes = join(filter(map(a:lines[1:], 'matchstr(v:val, pat)'), 'len(v:val)'))
- return s:yank_to_register(hashes)
- end
-
- let diff = a:lines[0] == 'ctrl-d'
- let Cmd = get(get(g:, 'fzf_action', s:default_action), a:lines[0], '')
- let cmd = type(Cmd) == s:TYPE.string ? Cmd : ''
-
- let buf = bufnr('')
- for idx in range(1, len(a:lines) - 1)
- let sha = matchstr(a:lines[idx], pat)
- if !empty(sha)
- if diff
- if idx > 1
- execute 'tab sb' buf
- endif
- execute 'Gdiff' sha
- else
- " Since fugitive buffers are unlisted, we can't keep using 'e'
- let c = empty(cmd) ? (idx == 1 ? 'edit' : 'tab split') : cmd
- execute c FugitiveFind(sha)
- endif
- endif
- endfor
-endfunction
-
-function! s:commits(range, buffer_local, args)
- let s:git_root = s:get_git_root('')
- if empty(s:git_root)
- return s:warn('Not in git repository')
- endif
-
- let prefix = 'git -C ' . fzf#shellescape(s:git_root) . ' '
- let source = prefix . 'log '.s:conf('commits_log_options', '--color=always '.fzf#shellescape('--format=%C(auto)%h%d %s %C(green)%cr'))
- let current = expand('%:p')
- let managed = 0
- if !empty(current)
- call system(prefix . 'show '.fzf#shellescape(current).' 2> '.(s:is_win ? 'nul' : '/dev/null'))
- let managed = !v:shell_error
- endif
-
- let args = copy(a:args)
- let log_opts = len(args) && type(args[0]) == type('') ? remove(args, 0) : ''
-
- if len(a:range) || a:buffer_local
- if !managed
- return s:warn('The current buffer is not in the working tree')
- endif
- let source .= len(a:range)
- \ ? join([printf(' -L %d,%d:%s --no-patch', a:range[0], a:range[1], fzf#shellescape(current)), log_opts])
- \ : join([' --follow', log_opts, fzf#shellescape(current)])
- let command = 'BCommits'
- else
- let source .= join([' --graph', log_opts])
- let command = 'Commits'
- endif
-
- let expect_keys = join(keys(get(g:, 'fzf_action', s:default_action)), ',')
- let options = {
- \ 'source': source,
- \ 'sink*': s:function('s:commits_sink'),
- \ 'options': s:reverse_list(['--ansi', '--multi', '--tiebreak=index',
- \ '--inline-info', '--prompt', command.'> ', '--bind=ctrl-s:toggle-sort',
- \ '--header', ':: Press '.s:magenta('CTRL-S', 'Special').' to toggle sort, '.s:magenta('CTRL-Y', 'Special').' to yank commit hashes',
- \ '--expect=ctrl-y,'.expect_keys])
- \ }
-
- if a:buffer_local
- let options.options[-2] .= ', '.s:magenta('CTRL-D', 'Special').' to diff'
- let options.options[-1] .= ',ctrl-d'
- endif
-
- if !s:is_win && &columns > s:wide
- let suffix = executable('delta') ? '| delta --width $FZF_PREVIEW_COLUMNS' : ''
- let orderfile = tempname()
- call writefile([current[len(s:git_root)+1:]], orderfile)
- call extend(options.options,
- \ ['--preview', 'echo {} | grep -o "[a-f0-9]\{7,\}" | head -1 | xargs ' . prefix . 'show -O'.fzf#shellescape(orderfile).' --format=format: --color=always ' . suffix])
- endif
-
- return s:fzf(a:buffer_local ? 'bcommits' : 'commits', options, args)
-endfunction
-
-" Heuristically determine if the user specified a range
-function! s:given_range(line1, line2)
- " 1. From visual mode
- " :'<,'>Commits
- " 2. From command-line
- " :10,20Commits
- if a:line1 == line("'<") && a:line2 == line("'>") ||
- \ (a:line1 != 1 || a:line2 != line('$'))
- return [a:line1, a:line2]
- endif
-
- return []
-endfunction
-
-" [git-log-args], [spec (dict)], [fullscreen (bool)]
-function! fzf#vim#commits(...) range
- if exists('b:fzf_winview')
- call winrestview(b:fzf_winview)
- unlet b:fzf_winview
- endif
- return s:commits(s:given_range(a:firstline, a:lastline), 0, a:000)
-endfunction
-
-" [git-log-args], [spec (dict)], [fullscreen (bool)]
-function! fzf#vim#buffer_commits(...) range
- if exists('b:fzf_winview')
- call winrestview(b:fzf_winview)
- unlet b:fzf_winview
- endif
- return s:commits(s:given_range(a:firstline, a:lastline), 1, a:000)
-endfunction
-
-" ------------------------------------------------------------------
-" fzf#vim#maps(mode, opts[with count and op])
-" ------------------------------------------------------------------
-function! s:align_pairs(list)
- let maxlen = 0
- let pairs = []
- for elem in a:list
- let match = matchlist(elem, '^\(\S*\)\s*\(.*\)$')
- let [_, k, v] = match[0:2]
- let maxlen = max([maxlen, len(k)])
- call add(pairs, [k, substitute(v, '^\*\?[@ ]\?', '', '')])
- endfor
- let maxlen = min([maxlen, 35])
- return map(pairs, "printf('%-'.maxlen.'s', v:val[0]).' '.v:val[1]")
-endfunction
-
-function! s:highlight_keys(str)
- return substitute(
- \ substitute(a:str, '<[^ >]\+>', s:yellow('\0', 'Special'), 'g'),
- \ '', s:blue('', 'SpecialKey'), 'g')
-endfunction
-
-function! s:key_sink(line)
- let key = matchstr(a:line, '^\S*')
- redraw
- call feedkeys(s:map_gv.s:map_cnt.s:map_reg, 'n')
- call feedkeys(s:map_op.
- \ substitute(key, '<[^ >]\+>', '\=eval("\"\\".submatch(0)."\"")', 'g'))
-endfunction
-
-function! fzf#vim#maps(mode, ...)
- let s:map_gv = a:mode == 'x' ? 'gv' : ''
- let s:map_cnt = v:count == 0 ? '' : v:count
- let s:map_reg = empty(v:register) ? '' : ('"'.v:register)
- let s:map_op = a:mode == 'o' ? v:operator : ''
-
- redir => cout
- silent execute 'verbose' a:mode.'map'
- redir END
- let list = []
- let curr = ''
- for line in split(cout, "\n")
- if line =~ "^\t"
- let src = "\t".substitute(matchstr(line, '/\zs[^/\\]*\ze$'), ' [^ ]* ', ':', '')
- call add(list, printf('%s %s', curr, s:green(src, 'Comment')))
- let curr = ''
- else
- if !empty(curr)
- call add(list, curr)
- endif
- let curr = line[3:]
- endif
- endfor
- if !empty(curr)
- call add(list, curr)
- endif
- let aligned = s:align_pairs(list)
- let sorted = sort(aligned)
- let colored = map(sorted, 's:highlight_keys(v:val)')
- let pcolor = a:mode == 'x' ? 9 : a:mode == 'o' ? 10 : 12
- return s:fzf('maps', {
- \ 'source': colored,
- \ 'sink': s:function('s:key_sink'),
- \ 'options': '--prompt "Maps ('.a:mode.')> " --ansi --no-hscroll --nth 1,.. --color prompt:'.pcolor}, a:000)
-endfunction
-
-" ----------------------------------------------------------------------------
-" fzf#vim#complete - completion helper
-" ----------------------------------------------------------------------------
-inoremap (-fzf-complete-trigger) :call complete_trigger()
-
-function! s:pluck(dict, key, default)
- return has_key(a:dict, a:key) ? remove(a:dict, a:key) : a:default
-endfunction
-
-function! s:complete_trigger()
- let opts = copy(s:opts)
- call s:prepend_opts(opts, ['+m', '-q', s:query])
- let opts['sink*'] = s:function('s:complete_insert')
- let s:reducer = s:pluck(opts, 'reducer', s:function('s:first_line'))
- call fzf#run(opts)
-endfunction
-
-" The default reducer
-function! s:first_line(lines)
- return a:lines[0]
-endfunction
-
-function! s:complete_insert(lines)
- if empty(a:lines)
- return
- endif
-
- let chars = strchars(s:query)
- if chars == 0 | let del = ''
- elseif chars == 1 | let del = '"_x'
- else | let del = (chars - 1).'"_dvh'
- endif
-
- let data = call(s:reducer, [a:lines])
- let ve = &ve
- set ve=
- execute 'normal!' ((s:eol || empty(chars)) ? '' : 'h').del.(s:eol ? 'a': 'i').data
- let &ve = ve
- if mode() =~ 't'
- call feedkeys('a', 'n')
- elseif has('nvim')
- execute "normal! \la"
- else
- call feedkeys("\(-fzf-complete-finish)")
- endif
-endfunction
-
-nnoremap (-fzf-complete-finish) a
-inoremap (-fzf-complete-finish) l
-
-function! s:eval(dict, key, arg)
- if has_key(a:dict, a:key) && type(a:dict[a:key]) == s:TYPE.funcref
- let ret = copy(a:dict)
- let ret[a:key] = call(a:dict[a:key], [a:arg])
- return ret
- endif
- return a:dict
-endfunction
-
-function! fzf#vim#complete(...)
- if a:0 == 0
- let s:opts = fzf#wrap()
- elseif type(a:1) == s:TYPE.dict
- let s:opts = copy(a:1)
- elseif type(a:1) == s:TYPE.string
- let s:opts = extend({'source': a:1}, get(a:000, 1, fzf#wrap()))
- else
- echoerr 'Invalid argument: '.string(a:000)
- return ''
- endif
- for s in ['sink', 'sink*']
- if has_key(s:opts, s)
- call remove(s:opts, s)
- endif
- endfor
-
- let eol = col('$')
- let ve = &ve
- set ve=all
- let s:eol = col('.') == eol
- let &ve = ve
-
- let Prefix = s:pluck(s:opts, 'prefix', '\k*$')
- if col('.') == 1
- let s:query = ''
- else
- let full_prefix = getline('.')[0 : col('.')-2]
- if type(Prefix) == s:TYPE.funcref
- let s:query = call(Prefix, [full_prefix])
- else
- let s:query = matchstr(full_prefix, Prefix)
- endif
- endif
- let s:opts = s:eval(s:opts, 'source', s:query)
- let s:opts = s:eval(s:opts, 'options', s:query)
- let s:opts = s:eval(s:opts, 'extra_options', s:query)
- if has_key(s:opts, 'extra_options')
- call s:merge_opts(s:opts, remove(s:opts, 'extra_options'))
- endif
- if has_key(s:opts, 'options')
- if type(s:opts.options) == s:TYPE.list
- call add(s:opts.options, '--no-expect')
- else
- let s:opts.options .= ' --no-expect'
- endif
- endif
-
- call feedkeys("\(-fzf-complete-trigger)")
- return ''
-endfunction
-
-" ------------------------------------------------------------------
-let &cpo = s:cpo_save
-unlet s:cpo_save
diff --git a/.vim/bundle/vim-fzf/autoload/fzf/vim/complete.vim b/.vim/bundle/vim-fzf/autoload/fzf/vim/complete.vim
deleted file mode 100644
index 0f60b97..0000000
--- a/.vim/bundle/vim-fzf/autoload/fzf/vim/complete.vim
+++ /dev/null
@@ -1,164 +0,0 @@
-" Copyright (c) 2015 Junegunn Choi
-"
-" MIT License
-"
-" Permission is hereby granted, free of charge, to any person obtaining
-" a copy of this software and associated documentation files (the
-" "Software"), to deal in the Software without restriction, including
-" without limitation the rights to use, copy, modify, merge, publish,
-" distribute, sublicense, and/or sell copies of the Software, and to
-" permit persons to whom the Software is furnished to do so, subject to
-" the following conditions:
-"
-" The above copyright notice and this permission notice shall be
-" included in all copies or substantial portions of the Software.
-"
-" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-let s:cpo_save = &cpo
-set cpo&vim
-let s:is_win = has('win32') || has('win64')
-
-function! s:extend(base, extra)
- let base = copy(a:base)
- if has_key(a:extra, 'options')
- let extra = copy(a:extra)
- let extra.extra_options = remove(extra, 'options')
- return extend(base, extra)
- endif
- return extend(base, a:extra)
-endfunction
-
-if v:version >= 704
- function! s:function(name)
- return function(a:name)
- endfunction
-else
- function! s:function(name)
- " By Ingo Karkat
- return function(substitute(a:name, '^s:', matchstr(expand(''), '\d\+_\zefunction$'), ''))
- endfunction
-endif
-
-function! fzf#vim#complete#word(...)
- let sources = empty(&dictionary) ? ['/usr/share/dict/words'] : split(&dictionary, ',')
- return fzf#vim#complete(s:extend({
- \ 'source': 'cat ' . join(map(sources, 'fzf#shellescape(v:val)'))},
- \ get(a:000, 0, fzf#wrap())))
-endfunction
-
-" ----------------------------------------------------------------------------
-" (fzf-complete-path)
-" (fzf-complete-file)
-"