Reorginazation after switching to GNU Stow for organizing dotfiles

This commit is contained in:
Andrew R. M 2017-04-05 12:11:27 -04:00
parent e0445597d6
commit 7c52136278
205 changed files with 36928 additions and 82 deletions

42
.gitmodules vendored
View File

@ -1,42 +0,0 @@
[submodule "vim/bundle/pathogen"]
path = vim/bundle/pathogen
url = https://github.com/tpope/vim-pathogen
[submodule "vim/bundle/fugitive"]
path = vim/bundle/fugitive
url = https://github.com/tpope/vim-fugitive
[submodule "vim/bundle/commentary"]
path = vim/bundle/commentary
url = https://github.com/tpope/vim-commentary
[submodule "vim/bundle/eunuch"]
path = vim/bundle/eunuch
url = https://github.com/tpope/vim-eunuch
[submodule "vim/bundle/vinegar"]
path = vim/bundle/vinegar
url = https://github.com/tpope/vim-vinegar
[submodule "vim/bundle/sleuth"]
path = vim/bundle/sleuth
url = https://github.com/tpope/vim-sleuth
[submodule "vim/bundle/endwise"]
path = vim/bundle/endwise
url = https://github.com/tpope/vim-endwise
[submodule "vim/bundle/tagbar"]
path = vim/bundle/tagbar
url = https://github.com/majutsushi/tagbar
[submodule "vim/bundle/pencil"]
path = vim/bundle/pencil
url = https://github.com/reedes/vim-pencil
[submodule "vim/bundle/snipmate"]
path = vim/bundle/snipmate
url = https://github.com/garbas/vim-snipmate
[submodule "vim/bundle/snipmate-tlib"]
path = vim/bundle/snipmate-tlib
url = https://github.com/tomtom/tlib_vim
[submodule "vim/bundle/snipmate-addon-mw-utils"]
path = vim/bundle/snipmate-addon-mw-utils
url = https://github.com/MarcWeber/vim-addon-mw-utils
[submodule "vim/bundle/filetype-nix"]
path = vim/bundle/filetype-nix
url = https://github.com/LnL7/vim-nix
[submodule "vim/bundle/supertab"]
path = vim/bundle/supertab
url = https://github.com/ervandew/supertab

View File

@ -10,10 +10,16 @@ export PS3='select: '
#{- ENVIRONMENT VARIABLES -}#
# History preferences
export HISTSIZE=-1
export HISTFILESIZE=-1
export HISTFILE="$HOME/.history/bash"
if [ -w "$HOME/.history/bash" ]; then
if [ ! -d "$HOME/.history" ]; then
mkdir "$HOME/.history"
fi
touch "$HOME/.history/bash"
fi
export HISTCONTROL="erasedups:ignoreboth"
export HISTFILE="$HOME/.history/bash"
export HISTFILESIZE=-1
export HISTSIZE=-1
#{- SHELL OPTIONS -}#

6
ghci/.ghci Normal file
View File

@ -0,0 +1,6 @@
-- Enable overloaded string literals
:set -XOverloadedStrings
-- Enable multiline formatting
:set +m
:set prompt "\ESC[1;35mλ\ESC[1;34m>\ESC[0m "
:set prompt2 "\ESC[1;34m|\ESC[1;35m>\ESC[0m "

8
ghci/.haskeline Normal file
View File

@ -0,0 +1,8 @@
bellStyle: NoBell
maxHistorySize: Just 100
editMode: Vi
completionType: MenuCompletion
completionPaging: False
completionPromptLimit: Just 100
listCompletionsImmediately: True
historyDuplicates: IgnoreAll

69
kwm/.khdrc Normal file
View File

@ -0,0 +1,69 @@
# Enable kwm compatibility khd kwm on
khd kwm on
cmd + shift - q : kwmc quit
cmd + shift - r : kwmc config reload && khd -e "reload"
cmd - return : "$HOME"/.kwm/iterm
cmd - escape : "$HOME"/.kwm/screensaver
cmd + alt + ctrl - space : kwmc config focus-follows-mouse toggle
cmd - h : kwmc window -f west
cmd - j : kwmc window -f south
cmd - k : kwmc window -f north
cmd - l : kwmc window -f east
cmd + shift - h : kwmc window -s west
cmd + shift - j : kwmc window -s south
cmd + shift - k : kwmc window -s north
cmd + shift - l : kwmc window -s east
cmd + ctrl - h : kwmc window -c expand 0.05 west
cmd + ctrl - j : kwmc window -c expand 0.05 south
cmd + ctrl - k : kwmc window -c expand 0.05 north
cmd + ctrl - l : kwmc window -c expand 0.05 east
cmd + shift + ctrl - h : kwmc window -c reduce 0.05 west
cmd + shift + ctrl - j : kwmc window -c reduce 0.05 south
cmd + shift + ctrl - k : kwmc window -c reduce 0.05 north
cmd + shift + ctrl - l : kwmc window -c reduce 0.05 east
cmd - tab : kwmc window -f next
cmd + shift - tab : kwmc window -f prev
cmd - f : kwmc window -z fullscreen
cmd - r : kwmc tree rotate 90
cmd + ctrl - b : kwmc window -c type bsp
cmd + ctrl - m : kwmc window -c type monocle
cmd + ctrl - f : kwmc window -c type float
cmd + shift - b : kwmc space -t bsp
cmd + shift - m : kwmc space -t monocle
cmd + shift - f : kwmc space -t float
cmd - 1 : kwmc space -fExperimental 1
cmd - 2 : kwmc space -fExperimental 2
cmd - 3 : kwmc space -fExperimental 3
cmd - 4 : kwmc space -fExperimental 4
cmd - 5 : kwmc space -fExperimental 5
cmd - 6 : kwmc space -fExperimental 6
cmd - 7 : kwmc space -fExperimental 7
cmd - 8 : kwmc space -fExperimental 8
cmd - 9 : kwmc space -fExperimental 9
cmd - 0 : kwmc space -fExperimental 10
cmd + shift - 1 : kwmc window -m space 1
cmd + shift - 2 : kwmc window -m space 2
cmd + shift - 3 : kwmc window -m space 3
cmd + shift - 4 : kwmc window -m space 4
cmd + shift - 5 : kwmc window -m space 5
cmd + shift - 6 : kwmc window -m space 6
cmd + shift - 7 : kwmc window -m space 7
cmd + shift - 8 : kwmc window -m space 8
cmd + shift - 9 : kwmc window -m space 9
cmd + shift - 0 : kwmc window -m space 10
cmd - backspace : kwmc display -f next
cmd + shift - backspace : kwmc window -m display next

14
kwm/.kwm/iterm Executable file
View File

@ -0,0 +1,14 @@
#!/usr/bin/env bash
if [ $# -eq 0 ]; then
osascript <<< "
tell application \"iTerm2\"
create window with default profile
end tell
"
else
osascript <<< "
tell application \"iTerm2\"
create window with default profile command \"$*\"
end tell
"
fi

32
kwm/.kwm/kwmrc Normal file
View File

@ -0,0 +1,32 @@
/*{-- Functional --}*/
kwmc config tiling bsp
kwmc config spawn right
/* Focus follows the mouse and the mouse follows focus */
kwmc config focus-follows-mouse on
kwmc config mouse-follows-focus on
/* Allow a window to be moved and resized by clicking with CMD held */
kwmc config mouse-drag on
kwmc config mouse-drag mod cmd
/* Automagically resize windows */
kwmc config lock-to-container on
/* Allow window focus to wrap */
kwmc config cycle-focus on
kwmc config float-non-resizable on
kwmc config standby-on-float on
kwmc config center-on-float on
kwmc rule owner="iTerm2" properties={role="AXDialog"}
/*{-- Cosmetic --}*/
kwmc config padding 30 30 30 30
kwmc config gap 30 30
kwmc config border focused on
kwmc config border focused size 3
kwmc config border focused color 0xFFAE9DAB
kwmc config border focused radius 10

6
kwm/.kwm/screensaver Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
osascript << EOF
tell application "ScreenSaverEngine"
activate
end tell
EOF

6
kwm/.kwm/vim Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
osascript <<< "
tell application \"iTerm2\"
create window with default profile command \"/Users/andrew/.nix-profile/bin/vim \\\"$@\\\"\"
end tell
"

48
python/.pythonrc Normal file
View File

@ -0,0 +1,48 @@
#{- ~/.pythonrc -}#
import atexit
import os
import readline
import sys
blue = '\001\033[1;34m\002'
yellow = '\001\033[1;33m\002'
magenta = '\001\033[1;35m\002'
red = '\001\033[1;31m\002'
reset = '\001\033[0m\002'
# Primary prompt: (>>> ) in magenta
sys.ps1 = blue + '>' + reset + ' '
# Secondary prompt: (... ) in red
sys.ps2 = yellow + '.' + reset + ' '
# Use ~/.history/python as a history file instead of ~/.python_history
def custom_readline():
import atexit
try:
import readline
import rlcompleter
except ImportError:
return
readline_doc = getattr(readline, '__doc__', '')
if readline_doc is not None and 'libedit' in readline_doc:
readline.parse_and_bind('bind ^I rl_complete')
else:
readline.parse_and_bind('tab: complete')
try:
readline.read_init_file()
except OSError:
pass
if readline.get_current_history_length() == 0:
history = os.path.join(os.path.expanduser('~'), '.history', 'python')
try:
readline.read_history_file(history)
except IOError:
pass
atexit.register(readline.write_history_file, history)
sys.__interactivehook__ = custom_readline

View File

@ -1,17 +0,0 @@
#{- ~/.pythonrc -}#
import atexit
import os
import readline
import sys
# Primary prompt: (>>> ) in magenta
sys.ps1 = '\033[1;35m>>>\033[0m '
# Secondary prompt: (... ) in red
sys.ps2 = '\033[1;31m...\033[0m '
# Use ~/.history/python as a history file instead of ~/.python_history
history_file = os.path.join (os.environ['HOME'], '.history', 'python')
if os.path.exists(history_file):
readline.read_history_file(history_file)
atexit.register(readline.write_history_file, history_file)

View File

@ -2,10 +2,23 @@
#{- PROMPT -}#
# Primary prompt: ($/# ) in magenta
export PS1='\[\033[1;35m\]\$\[\033[0m\] '
# Secondary prompt: (> ) in red
export PS2='\[\033[1;31\]m>\[\033[0m\] '
magenta="\[\033[1;35m\]"
red="\[\033[1;31m\]"
no_color="\[\033[0m\]"
# Primary prompt: ($/# )
# Secondary prompt: (> )
# Primary prompt is magenta on local machines, red on remote hosts
case $(hostname) in
pebble|stone|rock|boulder)
export PS1="${magenta}\$${no_color} "
export PS2="${red}>${no_color} "
;;
*)
export PS1="$red\$$no_color "
export PS2="$magenta>$no_color "
;;
esac
#{- PATH -}#
@ -30,7 +43,13 @@ export LESSHISTFILE="-"
export PYTHONSTARTUP="$HOME/.pythonrc"
# History preferences
export HISTFILE="$HOME/.history/posh"
if [ -w "$HOME/.history/sh" ]; then
if [ ! -d "$HOME/.history" ]; then
mkdir "$HOME/.history"
fi
touch "$HOME/.history/sh"
fi
export HISTFILE="$HOME/.history/sh"
export HISTSIZE=10000
#{- SOURCING -}#

View File

@ -0,0 +1 @@
See the [contribution guidelines for pathogen.vim](https://github.com/tpope/vim-pathogen/blob/master/CONTRIBUTING.markdown).

View File

@ -0,0 +1,51 @@
# commentary.vim
Comment stuff out. Use `gcc` to comment out a line (takes a count),
`gc` to comment out the target of a motion (for example, `gcap` to
comment out a paragraph), `gc` in visual mode to comment out the selection,
and `gc` in operator pending mode to target a comment. You can also use
it as a command, either with a range like `:7,17Commentary`, or as part of a
`:global` invocation like with `:g/TODO/Commentary`. That's it.
I wrote this because 5 years after Vim added support for mapping an
operator, I still couldn't find a commenting plugin that leveraged that
feature (I overlooked
[tcomment.vim](https://github.com/tomtom/tcomment_vim)). Striving for
minimalism, it weighs in at under 100 lines of code.
Oh, and it uncomments, too. The above maps actually toggle, and `gcgc`
uncomments a set of adjacent commented lines.
## Installation
If you don't have a preferred installation method, I recommend
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
then simply copy and paste:
cd ~/.vim/bundle
git clone git://github.com/tpope/vim-commentary.git
Once help tags have been generated, you can view the manual with
`:help commentary`.
## FAQ
> My favorite file type isn't supported!
Relax! You just have to adjust `'commentstring'`:
autocmd FileType apache setlocal commentstring=#\ %s
## Self-Promotion
Like commentary.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-commentary) and vote for it on
[vim.org](http://www.vim.org/scripts/script.php?script_id=3695). And if
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope).
## License
Copyright (c) Tim Pope. Distributed under the same terms as Vim itself.
See `:help license`.

View File

@ -0,0 +1,32 @@
*commentary.txt* Comment stuff out
Author: Tim Pope <http://tpo.pe/>
License: Same terms as Vim itself (see |license|)
Comment stuff out. Then uncomment it later. Relies on 'commentstring' to be
correctly set, or uses b:commentary_format if it is set.
*gc*
gc{motion} Comment or uncomment lines that {motion} moves over.
*gcc*
gcc Comment or uncomment [count] lines.
*v_gc*
{Visual}gc Comment or uncomment the highlighted lines.
*o_gc*
gc Text object for a comment (operator pending mode
only.)
*gcgc* *gcu*
gcgc Uncomment the current and adjacent commented lines.
gcu
*:Commentary*
:[range]Commentary Comment or uncomment [range] lines
The |User| CommentaryPost autocommand fires after a successful operation and
can be used for advanced customization.
vim:tw=78:et:ft=help:norl:

View File

@ -0,0 +1,103 @@
" commentary.vim - Comment stuff out
" Maintainer: Tim Pope <http://tpo.pe/>
" Version: 1.3
" GetLatestVimScripts: 3695 1 :AutoInstall: commentary.vim
if exists("g:loaded_commentary") || &cp || v:version < 700
finish
endif
let g:loaded_commentary = 1
function! s:surroundings() abort
return split(get(b:, 'commentary_format', substitute(substitute(
\ &commentstring, '\S\zs%s',' %s','') ,'%s\ze\S', '%s ', '')), '%s', 1)
endfunction
function! s:strip_white_space(l,r,line) abort
let [l, r] = [a:l, a:r]
if stridx(a:line,l) == -1 && stridx(a:line,l[0:-2]) == 0 && a:line[strlen(a:line)-strlen(r[1:]):-1] == r[1:]
return [l[0:-2], r[1:]]
endif
return [l, r]
endfunction
function! s:go(type,...) abort
if a:0
let [lnum1, lnum2] = [a:type, a:1]
else
let [lnum1, lnum2] = [line("'["), line("']")]
endif
let [l_, r_] = s:surroundings()
let uncomment = 2
for lnum in range(lnum1,lnum2)
let line = matchstr(getline(lnum),'\S.*\s\@<!')
let [l, r] = s:strip_white_space(l_,r_,line)
if line != '' && (stridx(line,l) || line[strlen(line)-strlen(r) : -1] != r)
let uncomment = 0
endif
endfor
for lnum in range(lnum1,lnum2)
let line = getline(lnum)
if strlen(r) > 2 && l.r !~# '\\'
let line = substitute(line,
\'\M'.r[0:-2].'\zs\d\*\ze'.r[-1:-1].'\|'.l[0].'\zs\d\*\ze'.l[1:-1],
\'\=substitute(submatch(0)+1-uncomment,"^0$\\|^-\\d*$","","")','g')
endif
if uncomment
let line = substitute(line,'\S.*\s\@<!','\=submatch(0)[strlen(l):-strlen(r)-1]','')
else
let line = substitute(line,'^\%('.matchstr(getline(lnum1),'^\s*').'\|\s*\)\zs.*\S\@<=','\=l.submatch(0).r','')
endif
call setline(lnum,line)
endfor
let modelines = &modelines
try
set modelines=0
silent doautocmd User CommentaryPost
finally
let &modelines = modelines
endtry
endfunction
function! s:textobject(inner) abort
let [l_, r_] = s:surroundings()
let [l, r] = [l_, r_]
let lnums = [line('.')+1, line('.')-2]
for [index, dir, bound, line] in [[0, -1, 1, ''], [1, 1, line('$'), '']]
while lnums[index] != bound && line ==# '' || !(stridx(line,l) || line[strlen(line)-strlen(r) : -1] != r)
let lnums[index] += dir
let line = matchstr(getline(lnums[index]+dir),'\S.*\s\@<!')
let [l, r] = s:strip_white_space(l_,r_,line)
endwhile
endfor
while (a:inner || lnums[1] != line('$')) && empty(getline(lnums[0]))
let lnums[0] += 1
endwhile
while a:inner && empty(getline(lnums[1]))
let lnums[1] -= 1
endwhile
if lnums[0] <= lnums[1]
execute 'normal! 'lnums[0].'GV'.lnums[1].'G'
endif
endfunction
xnoremap <silent> <Plug>Commentary :<C-U>call <SID>go(line("'<"),line("'>"))<CR>
nnoremap <silent> <Plug>Commentary :<C-U>set opfunc=<SID>go<CR>g@
nnoremap <silent> <Plug>CommentaryLine :<C-U>set opfunc=<SID>go<Bar>exe 'norm! 'v:count1.'g@_'<CR>
onoremap <silent> <Plug>Commentary :<C-U>call <SID>textobject(0)<CR>
nnoremap <silent> <Plug>ChangeCommentary c:<C-U>call <SID>textobject(1)<CR>
nmap <silent> <Plug>CommentaryUndo <Plug>Commentary<Plug>Commentary
command! -range -bar Commentary call s:go(<line1>,<line2>)
if !hasmapto('<Plug>Commentary') || maparg('gc','n') ==# ''
xmap gc <Plug>Commentary
nmap gc <Plug>Commentary
omap gc <Plug>Commentary
nmap gcc <Plug>CommentaryLine
nmap cgc <Plug>ChangeCommentary
nmap gcu <Plug>Commentary<Plug>Commentary
endif
" vim:set et sw=2:

View File

@ -0,0 +1 @@
See the [contribution guidelines for pathogen.vim](https://github.com/tpope/vim-pathogen/blob/master/CONTRIBUTING.markdown).

View File

@ -0,0 +1,42 @@
# endwise.vim
This is a simple plugin that helps to end certain structures
automatically. In Ruby, this means adding `end` after `if`, `do`, `def`
and several other keywords. In Vimscript, this amounts to appropriately
adding `endfunction`, `endif`, etc. There's also Bourne shell, VB
(don't ask), C/C++ preprocessor, and Lua support.
A primary guiding principle in designing this plugin was that an
erroneous insertion is never acceptable. The behavior is only triggered
once pressing enter on the end of the line. When this happens, endwise
searches for a matching end structure and only adds one if none is
found.
While the goal was to make it customizable, this turned out to be a tall
order. Every language has vastly different requirements. Nonetheless,
for those bold enough to attempt it, you can follow the model of the
autocmds in the plugin to set the three magic variables governing
endwise's behavior.
## Installation
If you don't have a preferred installation method, I recommend
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
then simply copy and paste:
cd ~/.vim/bundle
git clone git://github.com/tpope/vim-endwise.git
## Self-Promotion
Like endwise.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-endwise) and vote for it on
[vim.org](http://www.vim.org/scripts/script.php?script_id=2386). And if
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope).
## License
Copyright (c) Tim Pope. Distributed under the same terms as Vim itself.
See `:help license`.

View File

@ -0,0 +1,196 @@
" Location: plugin/endwise.vim
" Author: Tim Pope <http://tpo.pe/>
" Version: 1.2
" License: Same as Vim itself. See :help license
" GetLatestVimScripts: 2386 1 :AutoInstall: endwise.vim
if exists("g:loaded_endwise") || &cp
finish
endif
let g:loaded_endwise = 1
augroup endwise " {{{1
autocmd!
autocmd FileType lua
\ let b:endwise_addition = 'end' |
\ let b:endwise_words = 'function,do,then' |
\ let b:endwise_pattern = '^\s*\zs\%(\%(local\s\+\)\=function\)\>\%(.*\<end\>\)\@!\|\<\%(then\|do\)\ze\s*$' |
\ let b:endwise_syngroups = 'luaFunction,luaStatement,luaCond'
autocmd FileType elixir
\ let b:endwise_addition = 'end' |
\ let b:endwise_words = 'do,fn' |
\ let b:endwise_pattern = '.*[^.:@$]\zs\<\%(do\(:\)\@!\|fn\)\>\ze\%(.*[^.:@$]\<end\>\)\@!' |
\ let b:endwise_syngroups = 'elixirBlockDefinition'
autocmd FileType ruby
\ let b:endwise_addition = 'end' |
\ let b:endwise_words = 'module,class,def,if,unless,case,while,until,begin,do' |
\ let b:endwise_pattern = '^\(.*=\)\?\s*\%(private\s\+\|protected\s\+\|public\s\+\|module_function\s\+\)*\zs\%(module\|class\|def\|if\|unless\|case\|while\|until\|for\|\|begin\)\>\%(.*[^.:@$]\<end\>\)\@!\|\<do\ze\%(\s*|.*|\)\=\s*$' |
\ let b:endwise_syngroups = 'rubyModule,rubyClass,rubyDefine,rubyControl,rubyConditional,rubyRepeat'
autocmd FileType crystal
\ let b:endwise_addition = 'end' |
\ let b:endwise_words = 'module,class,lib,macro,struct,union,enum,def,if,unless,ifdef,case,while,until,for,begin,do' |
\ let b:endwise_pattern = '^\(.*=\)\?\s*\%(private\s\+\|protected\s\+\|public\s\+\|abstract\s\+\)*\zs\%(module\|class\|lib\|macro\|struct\|union\|enum\|def\|if\|unless\|ifdef\|case\|while\|until\|for\|begin\)\>\%(.*[^.:@$]\<end\>\)\@!\|\<do\ze\%(\s*|.*|\)\=\s*$' |
\ let b:endwise_syngroups = 'crystalModule,crystalClass,crystalLib,crystalMacro,crystalStruct,crystalDefine,crystalConditional,crystalRepeat,crystalControl'
autocmd FileType sh,zsh
\ let b:endwise_addition = '\=submatch(0)=="then" ? "fi" : submatch(0)=="case" ? "esac" : "done"' |
\ let b:endwise_words = 'then,case,do' |
\ let b:endwise_pattern = '\%(^\s*\zscase\>\ze\|\zs\<\%(do\|then\)\ze\s*$\)' |
\ let b:endwise_syngroups = 'shConditional,shLoop,shIf,shFor,shRepeat,shCaseEsac,zshConditional,zshRepeat,zshDelimiter'
autocmd FileType vb,vbnet,aspvbs
\ let b:endwise_addition = 'End &' |
\ let b:endwise_words = 'Function,Sub,Class,Module,Enum,Namespace' |
\ let b:endwise_pattern = '\%(\<End\>.*\)\@<!\<&\>' |
\ let b:endwise_syngroups = 'vbStatement,vbnetStorage,vbnetProcedure,vbnet.*Words,AspVBSStatement'
autocmd FileType vim
\ let b:endwise_addition = '\=submatch(0)=="augroup" ? submatch(0) . " END" : "end" . submatch(0)' |
\ let b:endwise_words = 'fu,fun,func,function,wh,while,if,for,try,au,augroup' |
\ let b:endwise_syngroups = 'vimFuncKey,vimNotFunc,vimCommand,vimAugroupKey'
autocmd FileType c,cpp,xdefaults,haskell
\ let b:endwise_addition = '#endif' |
\ let b:endwise_words = 'if,ifdef,ifndef' |
\ let b:endwise_pattern = '^\s*#\%(if\|ifdef\|ifndef\)\>' |
\ let b:endwise_syngroups = 'cPreCondit,cPreConditMatch,cCppInWrapper,xdefaultsPreProc'
autocmd FileType objc
\ let b:endwise_addition = '@end' |
\ let b:endwise_words = 'interface,implementation' |
\ let b:endwise_pattern = '^\s*@\%(interface\|implementation\)\>' |
\ let b:endwise_syngroups = 'objcObjDef'
autocmd FileType matlab
\ let b:endwise_addition = 'end' |
\ let b:endwise_words = 'function,if,for' |
\ let b:endwise_syngroups = 'matlabStatement,matlabFunction,matlabConditional,matlabRepeat'
autocmd FileType htmldjango
\ let b:endwise_addition = '{% end& %}' |
\ let b:endwise_words = 'autoescape,block\(\s\+\S*\)\?,blocktrans,cache,comment,filter,for,if,ifchanged,ifequal,ifnotequal,language,spaceless,verbatim,with' |
\ let b:endwise_syngroups = 'djangoTagBlock,djangoStatement'
autocmd FileType snippets
\ let b:endwise_addition = 'endsnippet' |
\ let b:endwise_words = 'snippet' |
\ let b:endwise_syngroups = 'snipSnippet,snipSnippetHeader,snipSnippetHeaderKeyword'
autocmd FileType * call s:abbrev()
augroup END " }}}1
function! s:abbrev()
if exists('g:endwise_abbreviations')
for word in split(get(b:, 'endwise_words', ''), ',')
execute 'iabbrev <buffer><script>' word word.'<CR><SID>DiscretionaryEnd<Space><C-U><BS>'
endfor
endif
endfunction
function! s:teardownMappings()
inoremap <buffer> <C-X><CR> <C-X><CR>
inoremap <buffer> <CR> <CR>
endfunction
" Functions {{{1
function! EndwiseDiscretionary()
return <SID>crend(0)
endfunction
function! EndwiseAlways()
return <SID>crend(1)
endfunction
" }}}1
" Maps {{{1
if maparg("<Plug>DiscretionaryEnd") == ""
inoremap <silent> <SID>DiscretionaryEnd <C-R>=<SID>crend(0)<CR>
inoremap <silent> <SID>AlwaysEnd <C-R>=<SID>crend(1)<CR>
imap <script> <Plug>DiscretionaryEnd <SID>DiscretionaryEnd
imap <script> <Plug>AlwaysEnd <SID>AlwaysEnd
endif
if !exists('g:endwise_no_mappings')
if maparg('<CR>','i') =~# '<C-R>=.*crend(.)<CR>\|<\%(Plug\|SNR\|SID\)>.*End'
" Already mapped
elseif maparg('<CR>','i') =~ '<CR>'
exe "imap <script> <C-X><CR> ".maparg('<CR>','i')."<SID>AlwaysEnd"
exe "imap <script> <CR> ".maparg('<CR>','i')."<SID>DiscretionaryEnd"
elseif maparg('<CR>','i') =~ '<Plug>\w\+CR'
exe "imap <C-X><CR> ".maparg('<CR>', 'i')."<Plug>AlwaysEnd"
exe "imap <CR> ".maparg('<CR>', 'i')."<Plug>DiscretionaryEnd"
else
imap <script> <C-X><CR> <CR><SID>AlwaysEnd
imap <CR> <CR><Plug>DiscretionaryEnd
endif
autocmd endwise CmdwinEnter * call s:teardownMappings()
endif
" }}}1
" Code {{{1
function! s:mysearchpair(beginpat,endpat,synpat)
let g:endwise_syntaxes = ""
let s:lastline = line('.')
call s:synname()
let line = searchpair(a:beginpat,'',a:endpat,'Wn','<SID>synname() !~# "^'.substitute(a:synpat,'\\','\\\\','g').'$"',line('.')+50)
return line
endfunction
function! s:crend(always)
let n = ""
if !exists("b:endwise_addition") || !exists("b:endwise_words") || !exists("b:endwise_syngroups")
return n
end
let synpat = '\%('.substitute(b:endwise_syngroups,',','\\|','g').'\)'
let wordchoice = '\%('.substitute(b:endwise_words,',','\\|','g').'\)'
if exists("b:endwise_pattern")
let beginpat = substitute(b:endwise_pattern,'&',substitute(wordchoice,'\\','\\&','g'),'g')
else
let beginpat = '\<'.wordchoice.'\>'
endif
let lnum = line('.') - 1
let space = matchstr(getline(lnum),'^\s*')
let col = match(getline(lnum),beginpat) + 1
let word = matchstr(getline(lnum),beginpat)
let endword = substitute(word,'.*',b:endwise_addition,'')
let y = n.endword."\<C-O>O"
if b:endwise_addition[0:1] ==# '\='
let endpat = '\w\@<!'.endword.'\w\@!'
else
let endpat = '\w\@<!'.substitute('\w\+', '.*', b:endwise_addition, '').'\w\@!'
endif
if a:always
return y
elseif col <= 0 || synIDattr(synID(lnum,col,1),'name') !~ '^'.synpat.'$'
return n
elseif getline('.') !~ '^\s*#\=$'
return n
endif
let line = s:mysearchpair(beginpat,endpat,synpat)
" even is false if no end was found, or if the end found was less
" indented than the current line
let even = strlen(matchstr(getline(line),'^\s*')) >= strlen(space)
if line == 0
let even = 0
endif
if !even && line == line('.') + 1
return y
endif
if even
return n
endif
return y
endfunction
function! s:synname()
" Checking this helps to force things to stay in sync
while s:lastline < line('.')
let s = synIDattr(synID(s:lastline,indent(s:lastline)+1,1),'name')
let s:lastline = nextnonblank(s:lastline + 1)
endwhile
let s = synIDattr(synID(line('.'),col('.'),1),'name')
let g:endwise_syntaxes = g:endwise_syntaxes . line('.').','.col('.')."=".s."\n"
let s:lastline = line('.')
return s
endfunction
" }}}1
" vim:set sw=2 sts=2:

View File

@ -0,0 +1,52 @@
# eunuch.vim
Vim sugar for the UNIX shell commands that need it the most. Features
include:
* `:Remove`: Delete a buffer and the file on disk simultaneously.
* `:Unlink`: Like `:Remove`, but keeps the now empty buffer.
* `:Move`: Rename a buffer and the file on disk simultaneously.
* `:Rename`: Like `:Move`, but relative to the current file's containing directory.
* `:Chmod`: Change the permissions of the current file.
* `:Mkdir`: Create a directory, defaulting to the parent of the current file.
* `:Find`: Run `find` and load the results into the quickfix list.
* `:Locate`: Run `locate` and load the results into the quickfix list.
* `:Wall`: Write every open window. Handy for kicking off tools like [guard][].
* `:SudoWrite`: Write a privileged file with `sudo`.
* `:SudoEdit`: Edit a privileged file with `sudo`.
* File type detection for `sudo -e` is based on original file name.
* New files created with a shebang line are automatically made executable.
* New init scripts are automatically prepopulated with `/etc/init.d/skeleton`.
[guard]: https://github.com/guard/guard
## Installation
If you don't have a preferred installation method, I recommend
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
then simply copy and paste:
cd ~/.vim/bundle
git clone git://github.com/tpope/vim-eunuch.git
Once help tags have been generated, you can view the manual with
`:help eunuch`.
## Contributing
See the contribution guidelines for
[pathogen.vim](https://github.com/tpope/vim-pathogen#readme).
## Self-Promotion
Like eunuch.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-eunuch) and vote for it on
[vim.org](http://www.vim.org/scripts/script.php?script_id=4300). And if
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope).
## License
Copyright (c) Tim Pope. Distributed under the same terms as Vim itself.
See `:help license`.

View File

@ -0,0 +1,213 @@
" eunuch.vim - Helpers for UNIX
" Maintainer: Tim Pope <http://tpo.pe/>
" Version: 1.1
if exists('g:loaded_eunuch') || &cp || v:version < 700
finish
endif
let g:loaded_eunuch = 1
function! s:fnameescape(string) abort
if exists('*fnameescape')
return fnameescape(a:string)
elseif a:string ==# '-'
return '\-'
else
return substitute(escape(a:string," \t\n*?[{`$\\%#'\"|!<"),'^[+>]','\\&','')
endif
endfunction
function! s:separator()
return !exists('+shellslash') || &shellslash ? '/' : '\\'
endfunction
command! -bar -bang Unlink
\ if <bang>1 && &modified |
\ edit |
\ elseif delete(expand('%')) |
\ echoerr 'Failed to delete "'.expand('%').'"' |
\ else |
\ edit! |
\ endif
command! -bar -bang Remove
\ let s:file = fnamemodify(bufname(<q-args>),':p') |
\ execute 'bdelete<bang>' |
\ if !bufloaded(s:file) && delete(s:file) |
\ echoerr 'Failed to delete "'.s:file.'"' |
\ endif |
\ unlet s:file
command! -bar -nargs=1 -bang -complete=file Move :
\ let s:src = expand('%:p') |
\ let s:dst = expand(<q-args>) |
\ if isdirectory(s:dst) || s:dst[-1:-1] =~# '[\\/]' |
\ let s:dst .= (s:dst[-1:-1] =~# '[\\/]' ? '' : s:separator()) .
\ fnamemodify(s:src, ':t') |
\ endif |
\ if !isdirectory(fnamemodify(s:dst, ':h')) |
\ call mkdir(fnamemodify(s:dst, ':h'), 'p') |
\ endif |
\ let s:dst = substitute(simplify(s:dst), '^\.\'.s:separator(), '', '') |
\ if <bang>1 && filereadable(s:dst) |
\ exe 'keepalt saveas '.s:fnameescape(s:dst) |
\ elseif rename(s:src, s:dst) |
\ echoerr 'Failed to rename "'.s:src.'" to "'.s:dst.'"' |
\ else |
\ setlocal modified |
\ exe 'keepalt saveas! '.s:fnameescape(s:dst) |
\ if s:src !=# expand('%:p') |
\ execute 'bwipe '.s:fnameescape(s:src) |
\ endif |
\ endif |
\ unlet s:src |
\ unlet s:dst |
\ filetype detect
function! s:Rename_complete(A, L, P) abort
let sep = s:separator()
let prefix = expand('%:p:h').sep
let files = split(glob(prefix.a:A.'*'), "\n")
call filter(files, 'simplify(v:val) !=# simplify(expand("%:p"))')
call map(files, 'v:val[strlen(prefix) : -1] . (isdirectory(v:val) ? sep : "")')
return join(files + ['..'.s:separator()], "\n")
endfunction
command! -bar -nargs=1 -bang -complete=custom,s:Rename_complete Rename
\ Move<bang> %:h/<args>
command! -bar -nargs=1 Chmod :
\ echoerr get(split(system('chmod '.<q-args>.' '.shellescape(expand('%'))), "\n"), 0, '') |
command! -bar -bang -nargs=? -complete=dir Mkdir
\ call mkdir(empty(<q-args>) ? expand('%:h') : <q-args>, <bang>0 ? 'p' : '') |
\ if empty(<q-args>) |
\ silent keepalt execute 'file' s:fnameescape(expand('%')) |
\ endif
command! -bar -bang -complete=file -nargs=+ Find exe s:Grep(<q-bang>, <q-args>, 'find')
command! -bar -bang -complete=file -nargs=+ Locate exe s:Grep(<q-bang>, <q-args>, 'locate')
function! s:Grep(bang,args,prg) abort
let grepprg = &l:grepprg
let grepformat = &l:grepformat
let shellpipe = &shellpipe
try
let &l:grepprg = a:prg
setlocal grepformat=%f
if &shellpipe ==# '2>&1| tee' || &shellpipe ==# '|& tee'
let &shellpipe = "| tee"
endif
execute 'grep! '.a:args
if empty(a:bang) && !empty(getqflist())
return 'cfirst'
else
return ''
endif
finally
let &l:grepprg = grepprg
let &l:grepformat = grepformat
let &shellpipe = shellpipe
endtry
endfunction
function! s:SudoSetup(file) abort
if !filereadable(a:file) && !exists('#BufReadCmd#'.s:fnameescape(a:file))
execute 'autocmd BufReadCmd ' s:fnameescape(a:file) 'call s:SudoReadCmd()'
endif
if !filewritable(a:file) && !exists('#BufWriteCmd#'.s:fnameescape(a:file))
execute 'autocmd BufReadPost ' s:fnameescape(a:file) 'set noreadonly'
execute 'autocmd BufWriteCmd ' s:fnameescape(a:file) 'call s:SudoWriteCmd()'
endif
endfunction
function! s:SudoReadCmd() abort
silent %delete_
let pipe = printf(&shellpipe . (&shellpipe =~ '%s' ? '' : ' %s'), '/dev/null')
execute (has('gui_running') ? '' : 'silent') 'read !env SUDO_EDITOR=cat VISUAL=cat sudo -e "%" ' . pipe
silent 1delete_
set nomodified
endfunction
function! s:SudoWriteCmd() abort
execute (has('gui_running') ? '' : 'silent') 'write !env SUDO_EDITOR=tee VISUAL=tee sudo -e "%" >/dev/null'
let &modified = v:shell_error
endfunction
command! -bar -bang -complete=file -nargs=? SudoEdit
\ call s:SudoSetup(fnamemodify(empty(<q-args>) ? expand('%') : <q-args>, ':p')) |
\ if !&modified || !empty(<q-args>) |
\ edit<bang> <args> |
\ endif |
\ if empty(<q-args>) || expand('%:p') ==# fnamemodify(<q-args>, ':p') |
\ set noreadonly |
\ endif
if exists(':SudoWrite') != 2
command! -bar SudoWrite
\ call s:SudoSetup(expand('%:p')) |
\ write!
endif
function! s:SudoEditInit() abort
let files = split($SUDO_COMMAND, ' ')[1:-1]
if len(files) ==# argc()
for i in range(argc())
execute 'autocmd BufEnter' s:fnameescape(argv(i))
\ 'if empty(&filetype) || &filetype ==# "conf"'
\ '|doautocmd filetypedetect BufReadPost' s:fnameescape(files[i])
\ '|endif'
endfor
endif
endfunction
if $SUDO_COMMAND =~# '^sudoedit '
call s:SudoEditInit()
endif
command! -bar -nargs=? Wall
\ if empty(<q-args>) |
\ call s:Wall() |
\ else |
\ call system('wall', <q-args>) |
\ endif
if exists(':W') !=# 2
command! -bar W Wall
endif
function! s:Wall() abort
let tab = tabpagenr()
let win = winnr()
let seen = {}
if !&readonly && expand('%') !=# ''
let seen[bufnr('')] = 1
write
endif
tabdo windo if !&readonly && &buftype =~# '^\%(acwrite\)\=$' && expand('%') !=# '' && !has_key(seen, bufnr('')) | silent write | let seen[bufnr('')] = 1 | endif
execute 'tabnext '.tab
execute win.'wincmd w'
endfunction
augroup eunuch
autocmd!
autocmd BufNewFile * let b:brand_new_file = 1
autocmd BufWritePost * unlet! b:brand_new_file
autocmd BufWritePre *
\ if exists('b:brand_new_file') |
\ if getline(1) =~ '^#!' |
\ let b:chmod_post = '+x' |
\ endif |
\ endif
autocmd BufWritePost,FileWritePost * nested
\ if exists('b:chmod_post') && executable('chmod') |
\ silent! execute '!chmod '.b:chmod_post.' "<afile>"' |
\ edit |
\ unlet b:chmod_post |
\ endif
autocmd BufNewFile */init.d/*
\ if filereadable("/etc/init.d/skeleton") |
\ keepalt read /etc/init.d/skeleton |
\ 1delete_ |
\ endif |
\ set ft=sh
augroup END
" vim:set sw=2 sts=2:

View File

@ -0,0 +1,6 @@
language: vim
before_script: |
git clone https://github.com/junegunn/vader.vim.git
script: |
./test/run-tests.sh

View File

@ -0,0 +1,19 @@
Copyright (c) 2014 <Daiderd Jordan>
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.

View File

@ -0,0 +1,48 @@
# vim-nix
[![Build Status](https://travis-ci.org/LnL7/vim-nix.svg?branch=master)](https://travis-ci.org/LnL7/vim-nix)
Support for writing [Nix expressions](http://nixos.org/nix/manual/#chap-writing-nix-expressions) in vim.
Features included so far:
* Syntax highlighting for Nix
* Filetype detection for `.nix` files
* Automatic indentation
## Installation
### Plugin managers
The most common plugin managers include [vim-plug][vim-plug],
[NeoBundle][neobundle], [Vundle][vundle] and [pathogen.vim][pathogen].
With pathogen.vim, just clone this repository inside `~/.vim/bundle`:
```bash
git clone https://github.com/LnL7/vim-nix.git ~/.vim/bundle
```
With the other plugin managers, just follow the instructions on the homepage of
each plugin. In general, you have to add a line to your `~/.vimrc`:
```viml
" vim-plug
Plug 'LnL7/vim-nix'
" NeoBundle
NeoBundle 'LnL7/vim-nix'
" Vundle
Plugin 'LnL7/vim-nix'
```
### Manual installation
Copy the contents of each directory in the respective directories inside
`~/.vim`.
[vim-plug]: https://github.com/junegunn/vim-plug
[vundle]: https://github.com/gmarik/Vundle.vim
[neobundle]: https://github.com/Shougo/neobundle.vim
[pathogen]: https://github.com/tpope/vim-pathogen

View File

@ -0,0 +1,47 @@
{ pkgs ? import <nixpkgs> {} }:
let
inherit (pkgs) stdenv fetchFromGitHub writeText runCommand;
vim-vader = fetchFromGitHub {
owner = "junegunn";
repo = "vader.vim";
rev = "ad2c752435baba9e7544d0046f0277c3573439bd";
sha256 = "0yvnah4lxk5w5qidc3y5nvl6lpi8rcv26907b3w7vjskqc935b8f";
};
vim-nix = ./.;
rcFile = writeText "vimrc" ''
filetype off
set rtp+=${vim-vader}
set rtp+=${vim-nix}
filetype plugin indent on
syntax enable
'';
vim = "${pkgs.vim}/bin/vim";
env = stdenv.mkDerivation {
name = "build-environment";
shellHook = ''
alias vim='${vim} -XNu ${rcFile} -i NONE'
'';
};
in stdenv.mkDerivation {
name = "vim-nix-2016-08-07";
src = ./.;
installPhase = ''
mkdir -p $out
cp -r ftdetect ftplugin indent syntax $out
'';
checkPhase = ''
( ${vim} -XNu ${rcFile} -i NONE -c 'Vader! test/*.vader' ) |& tee vim-nix-test.log >&2
'';
doCheck = true;
} // { inherit env; }

View File

@ -0,0 +1,7 @@
" Vim filetype detect
" Language: Nix
" Maintainer: Daiderd Jordan <daiderd@gmail.com>
" URL: https://github.com/LnL7/vim-nix
au BufRead,BufNewFile *.nix set filetype=nix
au FileType nix setl sw=2 sts=2 et iskeyword+=-

View File

@ -0,0 +1,13 @@
" Vim filetype plugin
" Language: Nix
" Maintainer: Daiderd Jordan <daiderd@gmail.com>
" URL: https://github.com/LnL7/vim-nix
if (exists("b:did_ftplugin"))
finish
endif
let b:did_ftplugin = 1
setlocal comments=:#
setlocal commentstring=#\ %s

View File

@ -0,0 +1,62 @@
" Vim indent file
" Language: Nix
" Maintainer: Daiderd Jordan <daiderd@gmail.com>
" URL: https://github.com/LnL7/vim-nix
if exists("b:did_indent")
finish
endif
let b:did_indent = 1
setlocal indentexpr=GetNixIndent()
if exists("*GetNixIndent")
finish
endif
let s:cpo_save = &cpo
set cpo&vim
let s:skip_syntax = '\%(Comment\|String\)$'
let s:block_open = '\%({\|[\)'
let s:block_close = '\%(}\|]\)'
function! GetNixIndent()
let lnum = prevnonblank(v:lnum - 1)
let ind = indent(lnum)
" At the start of the file use zero indent.
if lnum == 0
return 0
endif
if synIDattr(synID(v:lnum, 1, 1), "name") !~ s:skip_syntax
let current_line = getline(v:lnum)
let last_line = getline(lnum)
if last_line =~ s:block_open . '\s*$'
let ind += &sw
endif
if current_line =~ '^\s*' . s:block_close
let ind -= &sw
endif
if last_line =~ '\<let\s*$'
let ind += &sw
endif
if last_line =~ '^\<in\s*$'
let ind += &sw
endif
if current_line =~ '^\s*in\>'
let ind -= &sw
endif
endif
return ind
endfunction
let &cpo = s:cpo_save
unlet s:cpo_save

View File

@ -0,0 +1,183 @@
" Vim syntax file
" Language: Nix
" Maintainer: Daiderd Jordan <daiderd@gmail.com>
" URL: https://github.com/LnL7/vim-nix
if exists("b:current_syntax")
finish
endif
syn keyword nixBoolean true false
syn keyword nixNull null
syn keyword nixRecKeyword rec
syn keyword nixOperator or
syn match nixOperator '!=\|!'
syn match nixOperator '<=\?'
syn match nixOperator '>=\?'
syn match nixOperator '&&'
syn match nixOperator '//\='
syn match nixOperator '=='
syn match nixOperator '?'
syn match nixOperator '||'
syn match nixOperator '++\='
syn match nixOperator '-'
syn match nixOperator '\*'
syn match nixOperator '->'
syn match nixParen '[()]'
syn match nixInteger '\d\+'
syn keyword nixTodo FIXME NOTE TODO OPTIMIZE XXX HACK contained
syn match nixComment '#.*' contains=nixTodo,@Spell
syn region nixComment start=+/\*+ end=+\*/+ contains=nixTodo,@Spell
syn region nixInterpolation matchgroup=nixInterpolationDelimiter start="\${" end="}" contained contains=@nixExpr,nixInterpolationParam
syn match nixSimpleStringSpecial /\\["nrt\\$]/ contained
syn match nixInterpolationSpecial /''['$]/ contained
syn region nixSimpleString matchgroup=nixStringDelimiter start=+"+ skip=+\\"+ end=+"+ contains=nixInterpolation,nixSimpleStringSpecial
syn region nixString matchgroup=nixStringDelimiter start=+''+ skip=+''['$]+ end=+''+ contains=nixInterpolation,nixInterpolationSpecial
syn match nixFunctionCall "[a-zA-Z_][a-zA-Z0-9_'-]*"
syn match nixPath "[a-zA-Z0-9._+-]*\%(/[a-zA-Z0-9._+-]\+\)\+"
syn match nixHomePath "\~\%(/[a-zA-Z0-9._+-]\+\)\+"
syn match nixSearchPath "[a-zA-Z0-9._+-]\+\%(\/[a-zA-Z0-9._+-]\+\)*" contained
syn match nixPathDelimiter "[<>]" contained
syn match nixSearchPathRef "<[a-zA-Z0-9._+-]\+\%(\/[a-zA-Z0-9._+-]\+\)*>" contains=nixSearchPath,nixPathDelimiter
syn match nixURI "[a-zA-Z][a-zA-Z0-9.+-]*:[a-zA-Z0-9%/?:@&=$,_.!~*'+-]\+"
syn match nixAttributeDot "\." contained
syn match nixAttribute "[a-zA-Z_][a-zA-Z0-9_'-]*\ze\%([^a-zA-Z0-9_'-.]\|$\)" contained
syn region nixAttributeAssignment start="=" end="\ze;" contained contains=@nixExpr
syn region nixAttributeDefinition start=/\ze[a-zA-Z_"$]/ end=";" contained contains=nixComment,nixAttribute,nixInterpolation,nixSimpleString,nixAttributeDot,nixAttributeAssignment
syn region nixInheritAttributeScope start="(" end=")" contained contains=nixComment,nixAttributeDot
syn region nixAttributeDefinition matchgroup=nixInherit start="\<inherit\>" matchgroup=NONE end=";" contained contains=nixComment,nixInheritAttributeScope,nixAttribute
syn region nixAttributeSet start="{" end="}" contains=nixComment,nixAttributeDefinition
" vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
syn region nixArgumentDefinitionWithDefault matchgroup=nixArgumentDefinition start="[a-zA-Z_][a-zA-Z0-9_'-]*\ze\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*?\@=" matchgroup=NONE end="[,}]\@=" transparent contained contains=@nixExpr
" vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
syn match nixArgumentDefinition "[a-zA-Z_][a-zA-Z0-9_'-]*\ze\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*[,}]\@=" contained
syn match nixArgumentEllipsis "\.\.\." contained
syn match nixArgumentSeparator "," contained
" vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
syn match nixArgOperator '@\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*[a-zA-Z_][a-zA-Z0-9_'-]*\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*:'he=s+1 contained contains=nixAttribute
" vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
syn match nixArgOperator '[a-zA-Z_][a-zA-Z0-9_'-]*\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*@'hs=e-1 contains=nixAttribute nextgroup=nixFunctionArgument
" This is a bit more complicated, because function arguments can be passed in a
" very similar form on how attribute sets are defined and two regions with the
" same start patterns will shadow each other. Instead of a region we could use a
" match on {\_.\{-\}}, which unfortunately doesn't take nesting into account.
"
" So what we do instead is that we look forward until we are sure that it's a
" function argument. Unfortunately, we need to catch comments and both vertical
" and horizontal white space, which the following regex should hopefully do:
"
" "\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*"
"
" It is also used throught the whole file and is marked with 'v's as well.
"
" Fortunately the matching rules for function arguments are much simpler than
" for real attribute sets, because we can stop when we hit the first ellipsis or
" default value operator, but we also need to paste the "whitespace & comments
" eating" regex all over the place (marked with 'v's):
"
" Region match 1: { foo ? ... } or { foo, ... } or { ... } (ellipsis)
" vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv {----- identifier -----}vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
syn region nixFunctionArgument start="{\ze\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*\%([a-zA-Z_][a-zA-Z0-9_'-]*\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*[,?}]\|\.\.\.\)" end="}" contains=nixComment,nixArgumentDefinitionWithDefault,nixArgumentDefinition,nixArgumentEllipsis,nixArgumentSeparator nextgroup=nixArgOperator
" Now it gets more tricky, because we need to look forward for the colon, but
" there could be something like "{}@foo:", even though it's highly unlikely.
"
" Region match 2: {}
" vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv@vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv{----- identifier -----} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
syn region nixFunctionArgument start="{\ze\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*}\%(\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*@\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*[a-zA-Z_][a-zA-Z0-9_'-]*\)\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*:" end="}" contains=nixComment nextgroup=nixArgOperator
" vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
syn match nixSimpleFunctionArgument "[a-zA-Z_][a-zA-Z0-9_'-]*\ze\%(\s\|#.\{-\}\n\|\n\|/\*\_.\{-\}\*/\)*:/\@!"
syn region nixList matchgroup=nixListBracket start="\[" end="\]" contains=@nixExpr
syn region nixLetExpr matchgroup=nixLetExprKeyword start="\<let\>" end="\<in\>" contains=nixComment,nixAttributeDefinition
syn keyword nixIfExprKeyword then contained
syn region nixIfExpr matchgroup=nixIfExprKeyword start="\<if\>" end="\<else\>" contains=@nixExpr,nixIfExprKeyword
syn region nixWithExpr matchgroup=nixWithExprKeyword start="\<with\>" matchgroup=NONE end=";" contains=@nixExpr
syn region nixAssertExpr matchgroup=nixAssertKeyword start="\<assert\>" matchgroup=NONE end=";" contains=@nixExpr
syn cluster nixExpr contains=nixBoolean,nixNull,nixOperator,nixParen,nixInteger,nixRecKeyword,nixConditional,nixBuiltin,nixSimpleBuiltin,nixComment,nixFunctionCall,nixFunctionArgument,nixSimpleFunctionArgument,nixPath,nixHomePath,nixSearchPathRef,nixURI,nixAttributeSet,nixList,nixSimpleString,nixString,nixLetExpr,nixIfExpr,nixWithExpr,nixAssertExpr
" These definitions override @nixExpr and have to come afterwards:
syn match nixInterpolationParam "[a-zA-Z_][a-zA-Z0-9_'-]*\%(\.[a-zA-Z_][a-zA-Z0-9_'-]*\)*" contained
" Non-namespaced Nix builtins as of version 1.10:
syn keyword nixSimpleBuiltin
\ abort baseNameOf derivation dirOf fetchTarball import map removeAttrs
\ throw toString
" Namespaced and non-namespaced Nix builtins as of version 1.10:
syn keyword nixNamespacedBuiltin contained
\ abort add all any attrNames attrValues baseNameOf compareVersions
\ concatLists currentSystem deepSeq derivation dirOf div elem elemAt
\ fetchTarball fetchurl filter filterSource foldl' fromJSON genList
\ getAttr getEnv hasAttr hashString head import intersectAttrs isAttrs
\ isBool isFunction isInt isList isString length lessThan listToAttrs map
\ mul parseDrvName pathExists readDir readFile removeAttrs replaceStrings
\ seq sort stringLength sub substring tail throw toFile toJSON toPath
\ toString toXML trace typeOf
syn match nixBuiltin "builtins\.[a-zA-Z']\+"he=s+9 contains=nixComment,nixNamespacedBuiltin
hi def link nixArgOperator Operator
hi def link nixArgumentDefinition Identifier
hi def link nixArgumentEllipsis Operator
hi def link nixAssertKeyword Keyword
hi def link nixAttribute Identifier
hi def link nixAttributeDot Operator
hi def link nixBoolean Boolean
hi def link nixBuiltin Special
hi def link nixComment Comment
hi def link nixConditional Conditional
hi def link nixHomePath Include
hi def link nixIfExprKeyword Keyword
hi def link nixInherit Keyword
hi def link nixInteger Integer
hi def link nixInterpolation Macro
hi def link nixInterpolationDelimiter Delimiter
hi def link nixInterpolationParam Macro
hi def link nixInterpolationSpecial Special
hi def link nixLetExprKeyword Keyword
hi def link nixNamespacedBuiltin Special
hi def link nixNull Constant
hi def link nixOperator Operator
hi def link nixPath Include
hi def link nixPathDelimiter Delimiter
hi def link nixRecKeyword Keyword
hi def link nixSearchPath Include
hi def link nixSimpleBuiltin Keyword
hi def link nixSimpleFunctionArgument Identifier
hi def link nixSimpleString String
hi def link nixSimpleStringSpecial SpecialChar
hi def link nixString String
hi def link nixStringDelimiter Delimiter
hi def link nixTodo Todo
hi def link nixURI Include
hi def link nixWithExprKeyword Keyword
" This could lead up to slow syntax highlighting for large files, but usually
" large files such as all-packages.nix are one large attribute set, so if we'd
" use sync patterns we'd have to go back to the start of the file anyway
syn sync fromstart
let b:current_syntax = "nix"

View File

@ -0,0 +1,326 @@
Given nix (attribute):
{
foo = pkgs.callPackage ./examples/foo {};
}
Do (reindent):
vip=
Expect (indentation):
~~~~~~~
{
foo = pkgs.callPackage ./examples/foo {};
}
~~~~~~~
Execute (syntax):
AssertEqual SyntaxOf('foo'), 'nixAttribute'
Given nix (attribute-assignment):
{
foo = rec { };
}
Execute (syntax):
AssertEqual SyntaxOf('foo'), 'nixAttribute'
AssertEqual SyntaxOf('rec'), 'nixRecKeyword'
Given nix (attribute-path):
{
foo.bar.baz = 2;
}
Execute (syntax):
AssertNotEqual SyntaxOf('foo'), 'nixAttribute'
AssertNotEqual SyntaxOf('bar'), 'nixAttribute'
AssertEqual SyntaxOf('\.'), 'nixAttributeDot'
AssertEqual SyntaxOf('baz'), 'nixAttribute'
AssertEqual SyntaxOf('2'), 'nixInteger'
Given nix (attribute-nested):
{
a = {
b = {
c = "2}";
};
};
}
Execute (syntax):
AssertEqual SyntaxOf('a'), 'nixAttribute'
AssertEqual SyntaxOf('b'), 'nixAttribute'
AssertEqual SyntaxOf('c'), 'nixAttribute'
AssertEqual SyntaxOf('2}'), 'nixSimpleString'
Given nix (attribute-inherit):
{
inherit (a.b.c) foo;
inherit bar baz;
}
Execute (syntax):
AssertNotEqual SyntaxOf('c'), 'nixAttribute'
AssertEqual SyntaxOf('inherit'), 'nixInherit'
AssertEqual SyntaxOf('('), 'nixInheritAttributeScope'
AssertEqual SyntaxOf(')'), 'nixInheritAttributeScope'
AssertEqual SyntaxOf('\.'), 'nixAttributeDot'
AssertEqual SyntaxOf('foo'), 'nixAttribute'
AssertEqual SyntaxOf('bar'), 'nixAttribute'
AssertEqual SyntaxOf('baz'), 'nixAttribute'
Given nix (list):
{
foo = [
a
b
];
}
Do (reindent):
vip=
Expect (indentation):
~~~~~~~
{
foo = [
a
b
];
}
~~~~~~~
Execute (syntax):
AssertEqual SyntaxOf('foo'), 'nixAttribute'
AssertEqual SyntaxOf('a'), 'nixFunctionCall'
AssertEqual SyntaxOf('b'), 'nixFunctionCall'
Given nix (string):
"https://github.com/${owner}/${repo}/archive/${rev}.tar.gz"
Execute (syntax):
AssertEqual SyntaxOf('"'), 'nixStringDelimiter'
AssertEqual SyntaxOf('https'), 'nixSimpleString'
AssertEqual SyntaxOf('${'), 'nixInterpolationDelimiter'
AssertEqual SyntaxOf('}'), 'nixInterpolationDelimiter'
AssertEqual SyntaxOf('owner'), 'nixInterpolationParam'
AssertEqual SyntaxOf('repo'), 'nixInterpolationParam'
AssertEqual SyntaxOf('rev'), 'nixInterpolationParam'
Given nix (multiline-string):
''
line1 ${ref1}
${ref2} line2
line3 ${ref3}
''
Execute (syntax):
AssertEqual SyntaxOf('line1'), 'nixString'
AssertEqual SyntaxOf('line2'), 'nixString'
AssertEqual SyntaxOf('line3'), 'nixString'
AssertEqual SyntaxOf('ref1'), 'nixInterpolationParam'
AssertEqual SyntaxOf('ref2'), 'nixInterpolationParam'
AssertEqual SyntaxOf('ref3'), 'nixInterpolationParam'
Given nix (url):
https://github.com/LnL7/vim-nix
Execute (syntax):
AssertEqual SyntaxOf('https'), 'nixURI'
AssertEqual SyntaxOf('github'), 'nixURI'
AssertEqual SyntaxOf('nix'), 'nixURI'
Given nix (nix-search-path):
assert <foo-bar/blah/xxx.nix>;
Execute (syntax):
AssertEqual SyntaxOf('<'), 'nixPathDelimiter'
AssertEqual SyntaxOf('foo'), 'nixSearchPath'
AssertEqual SyntaxOf('-'), 'nixSearchPath'
AssertEqual SyntaxOf('bar'), 'nixSearchPath'
AssertEqual SyntaxOf('/'), 'nixSearchPath'
AssertEqual SyntaxOf('\.'), 'nixSearchPath'
AssertEqual SyntaxOf('>'), 'nixPathDelimiter'
Given nix (nix-paths):
[ ~/homefile ./. /etc/passwd ]
Execute (syntax):
AssertEqual SyntaxOf('\~/homefile'), 'nixHomePath'
AssertEqual SyntaxOf('\./\.'), 'nixPath'
AssertEqual SyntaxOf('/etc/passwd'), 'nixPath'
Given nix (let):
let
foo = true;
bar = false;
in {
result = foo && bar;
}
Do (reindent):
vip=
Expect (indentation):
~~~~~~~
let
foo = true;
bar = false;
in {
result = foo && bar;
}
~~~~~~~
Execute (syntax):
AssertEqual SyntaxOf('let'), 'nixLetExprKeyword'
AssertEqual SyntaxOf('in'), 'nixLetExprKeyword'
AssertEqual SyntaxOf('foo'), 'nixAttribute'
AssertEqual SyntaxOf('bar'), 'nixAttribute'
AssertEqual SyntaxOf('result'), 'nixAttribute'
AssertEqual SyntaxOf('&&'), 'nixOperator'
Given nix (builtins):
builtins.doesntexist (builtins.map id [
hashString (builtins.fetchurl (toString "abort"))
])
Execute (syntax):
AssertNotEqual SyntaxOf('doesntexist'), 'nixBuiltin'
AssertEqual SyntaxOf('map'), 'nixNamespacedBuiltin'
AssertNotEqual SyntaxOf('hashString'), 'nixBuiltin'
AssertNotEqual SyntaxOf('hashString'), 'nixNamespacedBuiltin'
AssertEqual SyntaxOf('builtins'), 'nixBuiltin'
AssertEqual SyntaxOf('\.'), 'nixBuiltin'
AssertEqual SyntaxOf('fetchurl'), 'nixNamespacedBuiltin'
AssertEqual SyntaxOf('toString'), 'nixSimpleBuiltin'
AssertEqual SyntaxOf('abort'), 'nixSimpleString'
Given nix (simple-string-escape):
"foo\nbar\"end\${xxx}"
Execute (syntax):
AssertEqual SyntaxAt(1, 1), 'nixStringDelimiter'
AssertEqual SyntaxOf('foo'), 'nixSimpleString'
AssertEqual SyntaxOf('\\n'), 'nixSimpleStringSpecial'
AssertEqual SyntaxOf('bar'), 'nixSimpleString'
AssertEqual SyntaxOf('\\"'), 'nixSimpleStringSpecial'
AssertEqual SyntaxOf('end'), 'nixSimpleString'
AssertEqual SyntaxOf('\$'), 'nixSimpleStringSpecial'
AssertEqual SyntaxOf('{'), 'nixSimpleString'
AssertEqual SyntaxOf('xxx'), 'nixSimpleString'
AssertEqual SyntaxOf('}'), 'nixSimpleString'
AssertEqual SyntaxAt(1, 22), 'nixStringDelimiter'
Given nix (multiline-string-escape):
''
foo'''bar
''${xxx}
''
Execute (syntax):
AssertEqual SyntaxOf('foo'), 'nixString'
AssertEqual SyntaxOf("'''"), 'nixInterpolationSpecial'
AssertEqual SyntaxOf('bar'), 'nixString'
AssertEqual SyntaxOf("''\\$"), 'nixInterpolationSpecial'
AssertEqual SyntaxOf('{'), 'nixString'
AssertEqual SyntaxOf('xxx'), 'nixString'
AssertEqual SyntaxOf('}'), 'nixString'
Given nix (lambda-attrs):
{ # very descriptive comment
foo
/**/
? # another comment
/* yet another comment */
# default value here:
1
, bar ? "xxx"
, yyy
# last comment
, ...
}: {
result = null;
}
Execute (syntax):
AssertEqual SyntaxOf('very descriptive comment'), 'nixComment'
AssertEqual SyntaxOf('foo'), 'nixArgumentDefinition'
AssertEqual SyntaxOf('?'), 'nixOperator'
AssertEqual SyntaxOf('/\*\*/'), 'nixComment'
AssertEqual SyntaxOf('another comment'), 'nixComment'
AssertEqual SyntaxOf('yet another comment'), 'nixComment'
AssertEqual SyntaxOf('default value here:'), 'nixComment'
AssertEqual SyntaxOf('1'), 'nixInteger'
AssertEqual SyntaxOf('bar'), 'nixArgumentDefinition'
AssertEqual SyntaxOf('xxx'), 'nixSimpleString'
AssertEqual SyntaxOf('yyy'), 'nixArgumentDefinition'
AssertEqual SyntaxOf('last comment'), 'nixComment'
AssertEqual SyntaxOf('\.\.\.'), 'nixArgumentEllipsis'
AssertEqual SyntaxOf('result'), 'nixAttribute'
AssertEqual SyntaxOf('null'), 'nixNull'
Given nix (ifexpr):
if true then 111 else { a = 222; }
Execute (syntax):
AssertEqual SyntaxOf('if'), 'nixIfExprKeyword'
AssertEqual SyntaxOf('true'), 'nixBoolean'
AssertEqual SyntaxOf('then'), 'nixIfExprKeyword'
AssertEqual SyntaxOf('111'), 'nixInteger'
AssertEqual SyntaxOf('else'), 'nixIfExprKeyword'
AssertEqual SyntaxOf('a'), 'nixAttribute'
AssertEqual SyntaxOf('222'), 'nixInteger'
Given nix (with-expr):
with foo; withfoo
Execute (syntax):
AssertEqual SyntaxOf('with'), 'nixWithExprKeyword'
AssertEqual SyntaxOf('foo'), 'nixFunctionCall'
AssertEqual SyntaxOf('withfoo'), 'nixFunctionCall'
Given nix (assert-expr):
assert true -> false; null
Execute (syntax):
AssertEqual SyntaxOf('assert'), 'nixAssertKeyword'
AssertEqual SyntaxOf('true'), 'nixBoolean'
AssertEqual SyntaxOf('->'), 'nixOperator'
AssertEqual SyntaxOf('false'), 'nixBoolean'
AssertEqual SyntaxOf('null'), 'nixNull'
Given nix (funarg-let-attrset):
{ xxx ? null }@yyy:
bbb@{ ccc, ... }:
let foo = 11; in let xxx = 22; in {
bar = foo + zzz;
}
Execute (syntax):
AssertEqual SyntaxOf('xxx'), 'nixArgumentDefinition'
AssertEqual SyntaxOf('?'), 'nixOperator'
AssertEqual SyntaxOf('null'), 'nixNull'
AssertEqual SyntaxOf('@'), 'nixArgOperator'
AssertEqual SyntaxOf('yyy'), 'nixAttribute'
AssertEqual SyntaxOf('bbb'), 'nixAttribute'
AssertEqual SyntaxOf('ccc'), 'nixArgumentDefinition'
AssertEqual SyntaxOf('let'), 'nixLetExprKeyword'
AssertEqual SyntaxOf('bar'), 'nixAttribute'
Given nix (searchpath-versus-lt):
{
alwaysTrue = 4 < 5;
alwaysFalse = 4 > 5;
somePath = <foo/bar>;
tailTrue = 4 <= 5;
tailFalse = 4 >= 5;
}
Execute (syntax):
AssertEqual SyntaxOf('alwaysTrue.*\zs<'), 'nixOperator'
AssertEqual SyntaxOf('alwaysFalse.*\zs>'), 'nixOperator'
AssertEqual SyntaxOf('somePath.*\zs<'), 'nixPathDelimiter'
AssertEqual SyntaxOf('somePath.*\zs>'), 'nixPathDelimiter'
AssertEqual SyntaxOf('tailTrue.*\zs<'), 'nixOperator'
AssertEqual SyntaxOf('tailFalse.*\zs>'), 'nixOperator'

View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
cd "$( dirname "${BASH_SOURCE[0]}" )" && vim -Nu vimrc -c 'Vader! *'

View File

@ -0,0 +1,5 @@
filetype off
set rtp+=../vader.vim
set rtp+=../
filetype plugin indent on
syntax enable

View File

@ -0,0 +1,18 @@
Before reporting a bug, you should try stripping down your Vim configuration
and removing other plugins. The sad truth about VimScript is that it is
fraught with incompatibilities waiting to happen. I'm happy to work around
them where I can, but it's up to you to isolate the conflict.
Fugitive is particularly prone to regressions due to Git version issues,
platform issues, and interactions with other plugins. I end up bisecting a
lot more than other projects, and thus I'm especially meticulous here about
maintaining a clean, readable, history. Squash and force push any requested
changes to a pull request. And if your [commit message
sucks](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
I'm not going to accept it. Period.
Beyond that, don't be shy about asking before patching. What takes you hours
might take me minutes simply because I have both domain knowledge and a
perverse knowledge of VimScript so vast that many would consider it a symptom
of mental illness. On the flip side, some ideas I'll reject no matter how
good the implementation is. "Send a patch" is an edge case answer in my book.

View File

@ -0,0 +1,118 @@
# fugitive.vim
I'm not going to lie to you; fugitive.vim may very well be the best
Git wrapper of all time. Check out these features:
View any blob, tree, commit, or tag in the repository with `:Gedit` (and
`:Gsplit`, `:Gvsplit`, `:Gtabedit`, ...). Edit a file in the index and
write to it to stage the changes. Use `:Gdiff` to bring up the staged
version of the file side by side with the working tree version and use
Vim's diff handling capabilities to stage a subset of the file's
changes.
Bring up the output of `git status` with `:Gstatus`. Press `-` to
`add`/`reset` a file's changes, or `p` to `add`/`reset` `--patch`. And guess
what `:Gcommit` does!
`:Gblame` brings up an interactive vertical split with `git blame`
output. Press enter on a line to edit the commit where the line
changed, or `o` to open it in a split. When you're done, use `:Gedit`
in the historic buffer to go back to the work tree version.
`:Gmove` does a `git mv` on a file and simultaneously renames the
buffer. `:Gremove` does a `git rm` on a file and simultaneously deletes
the buffer.
Use `:Ggrep` to search the work tree (or any arbitrary commit) with
`git grep`, skipping over that which is not tracked in the repository.
`:Glog` loads all previous revisions of a file into the quickfix list so
you can iterate over them and watch the file evolve!
`:Gread` is a variant of `git checkout -- filename` that operates on the
buffer rather than the filename. This means you can use `u` to undo it
and you never get any warnings about the file changing outside Vim.
`:Gwrite` writes to both the work tree and index versions of a file,
making it like `git add` when called from a work tree file and like
`git checkout` when called from the index or a blob in history.
Use `:Gbrowse` to open the current file on GitHub, with optional line
range (try it in visual mode!). If your current repository isn't on
GitHub, `git instaweb` will be spun up instead.
Add `%{fugitive#statusline()}` to `'statusline'` to get an indicator
with the current branch in (surprise!) your statusline.
Last but not least, there's `:Git` for running any arbitrary command,
and `Git!` to open the output of a command in a temp file.
## Screencasts
* [A complement to command line git](http://vimcasts.org/e/31)
* [Working with the git index](http://vimcasts.org/e/32)
* [Resolving merge conflicts with vimdiff](http://vimcasts.org/e/33)
* [Browsing the git object database](http://vimcasts.org/e/34)
* [Exploring the history of a git repository](http://vimcasts.org/e/35)
## Installation
If you don't have a preferred installation method, one option is to install
[pathogen.vim](https://github.com/tpope/vim-pathogen), and then copy
and paste:
cd ~/.vim/bundle
git clone git://github.com/tpope/vim-fugitive.git
vim -u NONE -c "helptags vim-fugitive/doc" -c q
If your Vim version is below 7.2, I recommend also installing
[vim-git](https://github.com/tpope/vim-git) for syntax highlighting and
other Git niceties.
## FAQ
> I installed the plugin and started Vim. Why don't any of the commands
> exist?
Fugitive cares about the current file, not the current working
directory. Edit a file from the repository.
> I opened a new tab. Why don't any of the commands exist?
Fugitive cares about the current file, not the current working
directory. Edit a file from the repository.
> Why is `:Gbrowse` not using the right browser?
`:Gbrowse` delegates to `git web--browse`, which is less than perfect
when it comes to finding the right browser. You can tell it the correct
browser to use with `git config --global web.browser ...`. On OS X, for
example, you might want to set this to `open`. See `git web--browse --help`
for details.
> Here's a patch that automatically opens the quickfix window after
> `:Ggrep`.
This is a great example of why I recommend asking before patching.
There are valid arguments to be made both for and against automatically
opening the quickfix window. Whenever I have to make an arbitrary
decision like this, I ask what Vim would do. And Vim does not open a
quickfix window after `:grep`.
Luckily, it's easy to implement the desired behavior without changing
fugitive.vim. The following autocommand will cause the quickfix window
to open after any grep invocation:
autocmd QuickFixCmdPost *grep* cwindow
## Self-Promotion
Like fugitive.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-fugitive) and vote for it on
[vim.org](http://www.vim.org/scripts/script.php?script_id=2975). And if
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope).
## License
Copyright (c) Tim Pope. Distributed under the same terms as Vim itself.
See `:help license`.

View File

@ -0,0 +1,357 @@
*fugitive.txt* A Git wrapper so awesome, it should be illegal
Author: Tim Pope <http://tpo.pe/>
License: Same terms as Vim itself (see |license|)
This plugin is only available if 'compatible' is not set.
INTRODUCTION *fugitive*
Whenever you edit a file from a Git repository, a set of commands is defined
that serve as a gateway to Git.
COMMANDS *fugitive-commands*
These commands are local to the buffers in which they work (generally, buffers
that are part of Git repositories).
*fugitive-:Git*
:Git [args] Run an arbitrary git command. Similar to :!git [args]
but chdir to the repository tree first.
*fugitive-:Git!*
:Git! [args] Like |:Git|, but capture the output into a temp file,
and edit that temp file.
*fugitive-:Gcd*
:Gcd [directory] |:cd| relative to the repository.
*fugitive-:Glcd*
:Glcd [directory] |:lcd| relative to the repository.
*fugitive-:Gstatus*
:Gstatus Bring up the output of git-status in the preview
window. The following maps, which work on the cursor
line file where sensible, are provided:
g? show this help
<C-N> next file
<C-P> previous file
<CR> |:Gedit|
- |:Git| add
- |:Git| reset (staged files)
cA |:Gcommit| --amend --reuse-message=HEAD
ca |:Gcommit| --amend
cc |:Gcommit|
cva |:Gcommit| --amend --verbose
cvc |:Gcommit| --verbose
D |:Gdiff|
ds |:Gsdiff|
dp |:Git!| diff (p for patch; use :Gw to apply)
dp |:Git| add --intent-to-add (untracked files)
dv |:Gvdiff|
O |:Gtabedit|
o |:Gsplit|
p |:Git| add --patch
p |:Git| reset --patch (staged files)
q close status
r reload status
S |:Gvsplit|
U |:Git| checkout
U |:Git| checkout HEAD (staged files)
U |:Git| clean (untracked files)
U |:Git| rm (unmerged files)
*fugitive-:Gcommit*
:Gcommit [args] A wrapper around git-commit. If there is nothing
to commit, |:Gstatus| is called instead. Unless the
arguments given would skip the invocation of an editor
(e.g., -m), a split window will be used to obtain a
commit message, or a new tab if -v is given. Write
and close that window (:wq or |:Gwrite|) to finish the
commit. Unlike when running the actual git-commit
command, it is possible (but unadvisable) to alter the
index with commands like git-add and git-reset while a
commit message is pending.
*fugitive-:Gmerge*
:Gmerge [args] Calls git-merge and loads errors and conflicted files
into the quickfix list. Opens a |:Gcommit| style
split window for the commit message if the merge
succeeds. If called during a merge conflict, the
conflicted files from the current index are loaded
into the quickfix list.
*fugitive-:Gpull*
:Gpull [args] Like |:Gmerge|, but for git-pull.
*fugitive-:Gpush*
:Gpush [args] Invoke git-push, load the results into the quickfix
list, and invoke |:cwindow| to reveal any errors.
|:Dispatch| is used if available for asynchronous
invocation.
*fugitive-:Gfetch*
:Gfetch [args] Like |:Gpush|, but for git-fetch.
*fugitive-:Ggrep*
:Ggrep[!] [args] |:grep|[!] with git-grep as 'grepprg'.
*fugitive-:Glgrep*
:Glgrep[!] [args] |:lgrep|[!] with git-grep as 'grepprg'.
*fugitive-:Glog*
:Glog [args] Load all previous revisions of the current file into
the quickfix list. Additional git-log arguments can
be given (for example, --reverse). If "--" appears as
an argument, no file specific filtering is done, and
previous commits rather than previous file revisions
are loaded.
:{range}Glog [args] Use git-log -L to load previous revisions of the given
range of the current file into the quickfix list. The
cursor is positioned on the first line of the first
diff hunk for each commit.
*fugitive-:Gllog*
:Gllog [args] Like |:Glog|, but use the location list instead of the
quickfix list.
*fugitive-:Gedit* *fugitive-:Ge*
:Gedit [revision] |:edit| a |fugitive-revision|.
*fugitive-:Gsplit*
:Gsplit [revision] |:split| a |fugitive-revision|.
*fugitive-:Gvsplit*
:Gvsplit [revision] |:vsplit| a |fugitive-revision|.
*fugitive-:Gtabedit*
:Gtabedit [revision] |:tabedit| a |fugitive-revision|.
*fugitive-:Gpedit*
:Gpedit [revision] |:pedit| a |fugitive-revision|.
:Gsplit! [args] *fugitive-:Gsplit!* *fugitive-:Gvsplit!*
:Gvsplit! [args] *fugitive-:Gtabedit!* *fugitive-:Gpedit!*
:Gtabedit! [args] Like |:Git!|, but open the resulting temp file in a
:Gpedit! [args] split, tab, or preview window.
*fugitive-:Gread*
:Gread [revision] Empty the buffer and |:read| a |fugitive-revision|.
When the argument is omitted, this is similar to
git-checkout on a work tree file or git-add on a stage
file, but without writing anything to disk.
:{range}Gread [revision]
|:read| in a |fugitive-revision| after {range}.
*fugitive-:Gread!*
:Gread! [args] Empty the buffer and |:read| the output of a Git
command. For example, :Gread! show HEAD:%.
:{range}Gread! [args] |:read| the output of a Git command after {range}.
*fugitive-:Gw* *fugitive-:Gwrite*
:Gwrite Write to the current file's path and stage the results.
When run in a work tree file, it is effectively git
add. Elsewhere, it is effectively git-checkout. A
great deal of effort is expended to behave sensibly
when the work tree or index version of the file is
open in another buffer.
:Gwrite {path} You can give |:Gwrite| an explicit path of where in
the work tree to write. You can also give a path like
:0:foo.txt or even :0 to write to just that stage in
the index.
*fugitive-:Gwq*
:Gwq [path] Like |:Gwrite| followed by |:quit| if the write
succeeded.
:Gwq! [path] Like |:Gwrite|! followed by |:quit|! if the write
succeeded.
*fugitive-:Gdiff*
:Gdiff [revision] Perform a |vimdiff| against the current file in the
given revision. With no argument, the version in the
index is used (which means a three-way diff during a
merge conflict, making it a git-mergetool
alternative). The newer of the two files is placed
to the right or bottom, depending on 'diffopt' and
the width of the window relative to 'textwidth'. Use
|do| and |dp| and write to the index file to simulate
"git add --patch".
*fugitive-:Gsdiff*
:Gsdiff [revision] Like |:Gdiff|, but always split horizontally.
*fugitive-:Gvdiff*
:Gvdiff [revision] Like |:Gdiff|, but always split vertically.
*fugitive-:Gmove*
:Gmove {destination} Wrapper around git-mv that renames the buffer
afterward. The destination is relative to the current
directory except when started with a /, in which case
it is relative to the work tree. Add a ! to pass -f.
*fugitive-:Gremove*
:Gremove Wrapper around git-rm that deletes the buffer
afterward. When invoked in an index file, --cached is
passed. Add a ! to pass -f and forcefully discard the
buffer.
*fugitive-:Gblame*
:Gblame [flags] Run git-blame on the file and open the results in a
scroll bound vertical split. You can give any of
ltfnsewMC as flags and they will be passed along to
git-blame. The following maps, which work on the
cursor line commit where sensible, are provided:
g? show this help
A resize to end of author column
C resize to end of commit column
D resize to end of date/time column
q close blame and return to blamed window
gq q, then |:Gedit| to return to work tree version
<CR> q, then open commit
o open commit in horizontal split
O open commit in new tab
- reblame at commit
~ reblame at [count]th first grandparent
P reblame at [count]th parent (like HEAD^[count])
:[range]Gblame [flags] Run git-blame on the given range.
*fugitive-:Gbrowse*
:Gbrowse Open the current file, blob, tree, commit, or tag
in your browser at the upstream hosting provider.
If a range is given, it is appropriately appended to
the URL as an anchor.
Upstream providers can be added by installing an
appropriate Vim plugin. For example, GitHub can be
supported by installing rhubarb.vim, available at
<https://github.com/tpope/vim-rhubarb>. (Native
support for GitHub is currently included, but that is
slated to be removed.)
The hosting provider is determined by looking at the
remote for the current or specified branch and falls
back to "origin". In the special case of a "."
remote, a local instance of git-instaweb will be
started and used.
:Gbrowse {revision} Like :Gbrowse, but for a given |fugitive-revision|. A
useful value here is -, which ties the URL to the
latest commit rather than a volatile branch.
:Gbrowse [...]@{remote} Force using the given remote rather than the remote
for the current branch. The remote is used to
determine which GitHub repository to link to.
:{range}Gbrowse [args] Appends an anchor to the URL that emphasizes the
selected lines. You almost certainly want to give a
"-" argument in this case to force the URL to include
an exact revision.
:[range]Gbrowse! [args] Like :Gbrowse, but put the URL on the clipboard rather
than opening it.
MAPPINGS *fugitive-mappings*
These maps are available everywhere.
*fugitive-c_CTRL-R_CTRL-G*
<C-R><C-G> On the command line, recall the path to the current
object (that is, a representation of the object
recognized by |:Gedit|).
*fugitive-y_CTRL-G*
["x]y<C-G> Yank the commit SHA and path to the current object.
These maps are available in Git objects.
*fugitive-<CR>*
<CR> Jump to the revision under the cursor.
*fugitive-o*
o Jump to the revision under the cursor in a new split.
*fugitive-S*
S Jump to the revision under the cursor in a new
vertical split.
*fugitive-O*
O Jump to the revision under the cursor in a new tab.
*fugitive--*
- Go to the tree containing the current tree or blob.
*fugitive-~*
~ Go to the current file in the [count]th first
ancestor.
*fugitive-P*
P Go to the current file in the [count]th parent.
*fugitive-C*
C Go to the commit containing the current file.
*fugitive-.*
. Start a |:| command line with the current revision
prepopulated at the end of the line.
*fugitive-a*
a Show the current tag, commit, or tree in an alternate
format.
SPECIFYING REVISIONS *fugitive-revision*
Fugitive revisions are similar to Git revisions as defined in the "SPECIFYING
REVISIONS" section in the git-rev-parse man page. For commands that accept an
optional revision, the default is the file in the index for work tree files
and the work tree file for everything else. Example revisions follow.
Revision Meaning ~
HEAD .git/HEAD
master .git/refs/heads/master
HEAD^{} The commit referenced by HEAD
HEAD^ The parent of the commit referenced by HEAD
HEAD: The tree referenced by HEAD
/HEAD The file named HEAD in the work tree
Makefile The file named Makefile in the work tree
HEAD^:Makefile The file named Makefile in the parent of HEAD
:Makefile The file named Makefile in the index (writable)
- The current file in HEAD
^ The current file in the previous commit
~3 The current file 3 commits ago
: .git/index (Same as |:Gstatus|)
:0 The current file in the index
:1 The current file's common ancestor during a conflict
:2 The current file in the target branch during a conflict
:3 The current file in the merged branch during a conflict
:/foo The most recent commit with "foo" in the message
STATUSLINE *fugitive-statusline*
*fugitive#statusline()*
Add %{fugitive#statusline()} to your statusline to get an indicator including
the current branch and the currently edited file's commit. If you don't have
a statusline, this one matches the default when 'ruler' is set:
>
set statusline=%<%f\ %h%m%r%{fugitive#statusline()}%=%-14.(%l,%c%V%)\ %P
<
*fugitive#head(...)*
Use fugitive#head() to return the name of the current branch. If the current
HEAD is detached, fugitive#head() will return the empty string, unless the
optional argument is given, in which case the hash of the current commit will
be truncated to the given number of characters.
ABOUT *fugitive-about*
Grab the latest version or report a bug on GitHub:
http://github.com/tpope/vim-fugitive
vim:tw=78:et:ft=help:norl:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
If your [commit message sucks](http://stopwritingramblingcommitmessages.com/),
I'm not going to accept your pull request. I've explained very politely
dozens of times that
[my general guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
are absolute rules on my own repositories, so I may lack the energy to
explain it to you yet another time. And please, if I ask you to change
something, `git commit --amend`.
Beyond that, don't be shy about asking before patching. What takes you
hours might take me minutes simply because I have both domain knowledge
and a perverse knowledge of Vim script so vast that many would consider
it a symptom of mental illness. On the flip side, some ideas I'll
reject no matter how good the implementation is. "Send a patch" is an
edge case answer in my book.

View File

@ -0,0 +1,141 @@
# pathogen.vim
Manage your `'runtimepath'` with ease. In practical terms, pathogen.vim
makes it super easy to install plugins and runtime files in their own
private directories.
## Installation
Install to `~/.vim/autoload/pathogen.vim`. Or copy and paste:
mkdir -p ~/.vim/autoload ~/.vim/bundle && \
curl -LSso ~/.vim/autoload/pathogen.vim https://tpo.pe/pathogen.vim
If you're using Windows, change all occurrences of `~/.vim` to `~\vimfiles`.
## Runtime Path Manipulation
Add this to your vimrc:
execute pathogen#infect()
If you're brand new to Vim and lacking a vimrc, `vim ~/.vimrc` and paste
in the following super-minimal example:
execute pathogen#infect()
syntax on
filetype plugin indent on
Now any plugins you wish to install can be extracted to a subdirectory
under `~/.vim/bundle`, and they will be added to the `'runtimepath'`.
Observe:
cd ~/.vim/bundle && \
git clone git://github.com/tpope/vim-sensible.git
Now [sensible.vim](https://github.com/tpope/vim-sensible) is installed.
If you really want to get crazy, you could set it up as a submodule in
whatever repository you keep your dot files in. I don't like to get
crazy.
If you don't like the directory name `bundle`, you can pass a runtime relative
glob as an argument:
execute pathogen#infect('stuff/{}')
The `{}` indicates where the expansion should occur.
You can also pass an absolute path instead. I keep the plugins I maintain under `~/src`, and this is how I add them:
execute pathogen#infect('bundle/{}', '~/src/vim/bundle/{}')
Normally to generate documentation, Vim expects you to run `:helptags`
on each directory with documentation (e.g., `:helptags ~/.vim/doc`).
Provided with pathogen.vim is a `:Helptags` command that does this on
every directory in your `'runtimepath'`. If you really want to get
crazy, you could even invoke `Helptags` in your vimrc. I don't like to
get crazy.
Finally, pathogen.vim has a rich API that can manipulate `'runtimepath'`
and other comma-delimited path options in ways most people will never
need to do. If you're one of those edge cases, look at the source.
It's well documented.
## Runtime File Editing
`:Vopen`, `:Vedit`, `:Vsplit`, `:Vvsplit`, `:Vtabedit`, `:Vpedit`, and
`:Vread` have all moved to [scriptease.vim][].
[scriptease.vim]: https://github.com/tpope/vim-scriptease
## FAQ
> Can I put pathogen.vim in a submodule like all my other plugins?
Sure, stick it under `~/.vim/bundle`, and prepend the following to your
vimrc:
runtime bundle/vim-pathogen/autoload/pathogen.vim
Or if your bundles are somewhere other than `~/.vim` (say, `~/src/vim`):
source ~/src/vim/bundle/vim-pathogen/autoload/pathogen.vim
> Will you accept these 14 pull requests adding a `.gitignore` for
> `tags` so I don't see untracked changes in my dot files repository?
No, but I'll teach you how to ignore `tags` globally:
git config --global core.excludesfile '~/.cvsignore'
echo tags >> ~/.cvsignore
While any filename will work, I've chosen to follow the ancient
tradition of `.cvsignore` because utilities like rsync use it, too.
Clever, huh?
> What about Vimballs?
If you really must use one:
:e name.vba
:!mkdir ~/.vim/bundle/name
:UseVimball ~/.vim/bundle/name
> Why don't my plugins load when I use Vim sessions?
Vim sessions default to capturing all global options, which includes the
`'runtimepath'` that pathogen.vim manipulates. This can cause other problems
too, so I recommend turning that behavior off:
set sessionoptions-=options
## Contributing
If your [commit message sucks](http://stopwritingramblingcommitmessages.com/),
I'm not going to accept your pull request. I've explained very politely
dozens of times that
[my general guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
are absolute rules on my own repositories, so I may lack the energy to
explain it to you yet another time. And please, if I ask you to change
something, `git commit --amend`.
Beyond that, don't be shy about asking before patching. What takes you
hours might take me minutes simply because I have both domain knowledge
and a perverse knowledge of Vim script so vast that many would consider
it a symptom of mental illness. On the flip side, some ideas I'll
reject no matter how good the implementation is. "Send a patch" is an
edge case answer in my book.
## Self-Promotion
Like pathogen.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-pathogen) and vote for it on
[vim.org](http://www.vim.org/scripts/script.php?script_id=2332). And if
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope).
## License
Copyright (c) Tim Pope. Distributed under the same terms as Vim itself.
See `:help license`.

View File

@ -0,0 +1,353 @@
" pathogen.vim - path option manipulation
" Maintainer: Tim Pope <http://tpo.pe/>
" 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() (defaults to "bundle/{}"), 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.
function! pathogen#infect(...) abort
for path in a:0 ? filter(reverse(copy(a:000)), 'type(v:val) == type("")') : ['bundle/{}']
if path =~# '^\%({\=[$~\\/]\|{\=\w:[\\/]\).*[{}*]'
call pathogen#surround(path)
elseif path =~# '^\%([$~\\/]\|\w:[\\/]\)'
call s:warn('Change pathogen#infect('.string(path).') to pathogen#infect('.string(path.'/{}').')')
call pathogen#surround(path . '/{}')
elseif path =~# '[{}*]'
call pathogen#interpose(path)
else
call s:warn('Change pathogen#infect('.string(path).') to pathogen#infect('.string(path.'/{}').')')
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,'\\\@<!\%(\\\\\)*\zs,')
return map(split,'substitute(v:val,''\\\([\\,]\)'',''\1'',"g")')
endfunction
" Convert a list to a path.
function! pathogen#join(...) abort
if type(a:1) == type(1) && a:1
let i = 1
let space = ' '
else
let i = 0
let space = ''
endif
let path = ""
while i < a:0
if type(a:000[i]) == type([])
let list = a:000[i]
let j = 0
while j < len(list)
let escaped = substitute(list[j],'[,'.space.']\|\\[\,'.space.']\@=','\\&','g')
let path .= ',' . escaped
let j += 1
endwhile
else
let path .= "," . a:000[i]
endif
let i += 1
endwhile
return substitute(path,'^,','','')
endfunction
" Convert a list to a path with escaped spaces for 'path', 'tag', etc.
function! pathogen#legacyjoin(...) abort
return call('pathogen#join',[1] + a:000)
endfunction
" Turn filetype detection off and back on again if it was already enabled.
function! pathogen#cycle_filetype() abort
if exists('g:did_load_filetypes')
filetype off
filetype on
endif
endfunction
" Check if a bundle is disabled. A bundle is considered disabled if its
" basename or full name is included in the list g:pathogen_blacklist or the
" comma delimited environment variable $VIMBLACKLIST.
function! pathogen#is_disabled(path) abort
if a:path =~# '\~$'
return 1
endif
let sep = pathogen#slash()
let blacklist =
\ get(g:, 'pathogen_blacklist', get(g:, 'pathogen_disabled', [])) +
\ pathogen#split($VIMBLACKLIST)
if !empty(blacklist)
call map(blacklist, 'substitute(v:val, "[\\/]$", "", "")')
endif
return index(blacklist, fnamemodify(a:path, ':t')) != -1 || index(blacklist, a:path) != -1
endfunction
" Prepend the given directory to the runtime path and append its corresponding
" after directory. Curly braces are expanded with pathogen#expand().
function! pathogen#surround(path) abort
let sep = pathogen#slash()
let rtp = pathogen#split(&rtp)
let path = fnamemodify(a:path, ':s?[\\/]\=$??')
let before = filter(pathogen#expand(path), '!pathogen#is_disabled(v:val)')
let after = filter(reverse(pathogen#expand(path, sep.'after')), '!pathogen#is_disabled(v:val[0:-7])')
call filter(rtp, 'index(before + after, v:val) == -1')
let &rtp = pathogen#join(before, rtp, after)
return &rtp
endfunction
" For each directory in the runtime path, add a second entry with the given
" argument appended. Curly braces are expanded with pathogen#expand().
function! pathogen#interpose(name) abort
let sep = pathogen#slash()
let name = a:name
if has_key(s:done_bundles, name)
return ""
endif
let s:done_bundles[name] = 1
let list = []
for dir in pathogen#split(&rtp)
if dir =~# '\<after$'
let list += reverse(filter(pathogen#expand(dir[0:-6].name, sep.'after'), '!pathogen#is_disabled(v:val[0:-7])')) + [dir]
else
let list += [dir] + filter(pathogen#expand(dir.sep.name), '!pathogen#is_disabled(v:val)')
endif
endfor
let &rtp = pathogen#join(pathogen#uniq(list))
return 1
endfunction
let s:done_bundles = {}
" Invoke :helptags on all non-$VIM doc directories in runtimepath.
function! pathogen#helptags() abort
let sep = pathogen#slash()
for glob in pathogen#split(&rtp)
for dir in map(split(glob(glob), "\n"), 'v:val.sep."/doc/".sep')
if (dir)[0 : strlen($VIMRUNTIME)] !=# $VIMRUNTIME.sep && filewritable(dir) == 2 && !empty(split(glob(dir.'*.txt'))) && (!filereadable(dir.'tags') || filewritable(dir.'tags'))
silent! execute 'helptags' pathogen#fnameescape(dir)
endif
endfor
endfor
endfunction
command! -bar Helptags :call pathogen#helptags()
" Execute the given command. This is basically a backdoor for --remote-expr.
function! pathogen#execute(...) abort
for command in a:000
execute command
endfor
return ''
endfunction
" Section: Unofficial
function! pathogen#is_absolute(path) abort
return a:path =~# (has('win32') ? '^\%([\\/]\|\w:\)[\\/]\|^[~$]' : '^[/~$]')
endfunction
" Given a string, returns all possible permutations of comma delimited braced
" alternatives of that string. pathogen#expand('/{a,b}/{c,d}') yields
" ['/a/c', '/a/d', '/b/c', '/b/d']. Empty braces are treated as a wildcard
" and globbed. Actual globs are preserved.
function! pathogen#expand(pattern, ...) abort
let after = a:0 ? a:1 : ''
if a:pattern =~# '{[^{}]\+}'
let [pre, pat, post] = split(substitute(a:pattern, '\(.\{-\}\){\([^{}]\+\)}\(.*\)', "\\1\001\\2\001\\3", ''), "\001", 1)
let found = map(split(pat, ',', 1), 'pre.v:val.post')
let results = []
for pattern in found
call extend(results, pathogen#expand(pattern))
endfor
elseif a:pattern =~# '{}'
let pat = matchstr(a:pattern, '^.*{}[^*]*\%($\|[\\/]\)')
let post = a:pattern[strlen(pat) : -1]
let results = map(split(glob(substitute(pat, '{}', '*', 'g')), "\n"), 'v:val.post')
else
let results = [a:pattern]
endif
let vf = pathogen#slash() . 'vimfiles'
call map(results, 'v:val =~# "\\*" ? v:val.after : isdirectory(v:val.vf.after) ? v:val.vf.after : isdirectory(v:val.after) ? v:val.after : ""')
return filter(results, '!empty(v:val)')
endfunction
" \ on Windows unless shellslash is set, / everywhere else.
function! pathogen#slash() abort
return !exists("+shellslash") || &shellslash ? '/' : '\'
endfunction
function! pathogen#separator() abort
return pathogen#slash()
endfunction
" Convenience wrapper around glob() which returns a list.
function! pathogen#glob(pattern) abort
let files = split(glob(a:pattern),"\n")
return map(files,'substitute(v:val,"[".pathogen#slash()."/]$","","")')
endfunction
" Like pathogen#glob(), only limit the results to directories.
function! pathogen#glob_directories(pattern) abort
return filter(pathogen#glob(a:pattern),'isdirectory(v:val)')
endfunction
" Remove duplicates from a list.
function! pathogen#uniq(list) abort
let i = 0
let seen = {}
while i < len(a:list)
if (a:list[i] ==# '' && exists('empty')) || has_key(seen,a:list[i])
call remove(a:list,i)
elseif a:list[i] ==# ''
let i += 1
let empty = 1
else
let seen[a:list[i]] = 1
let i += 1
endif
endwhile
return a:list
endfunction
" Backport of fnameescape().
function! pathogen#fnameescape(string) abort
if exists('*fnameescape')
return fnameescape(a:string)
elseif a:string ==# '-'
return '\-'
else
return substitute(escape(a:string," \t\n*?[{`$\\%#'\"|!<"),'^[+>]','\\&','')
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
" Section: Deprecated
function! s:warn(msg) abort
echohl WarningMsg
echomsg a:msg
echohl NONE
endfunction
" Prepend all subdirectories of path to the rtp, and append all 'after'
" directories in those subdirectories. Deprecated.
function! pathogen#runtime_prepend_subdirectories(path) abort
call s:warn('Change pathogen#runtime_prepend_subdirectories('.string(a:path).') to pathogen#infect('.string(a:path.'/{}').')')
return pathogen#surround(a:path . pathogen#slash() . '{}')
endfunction
function! pathogen#incubate(...) abort
let name = a:0 ? a:1 : 'bundle/{}'
call s:warn('Change pathogen#incubate('.(a:0 ? string(a:1) : '').') to pathogen#infect('.string(name).')')
return pathogen#interpose(name)
endfunction
" Deprecated alias for pathogen#interpose().
function! pathogen#runtime_append_all_bundles(...) abort
if a:0
call s:warn('Change pathogen#runtime_append_all_bundles('.string(a:1).') to pathogen#infect('.string(a:1.'/{}').')')
else
call s:warn('Change pathogen#runtime_append_all_bundles() to pathogen#infect()')
endif
return pathogen#interpose(a:0 ? a:1 . '/{}' : 'bundle/{}')
endfunction
if exists(':Vedit')
finish
endif
let s:vopen_warning = 0
function! s:find(count,cmd,file,lcd)
let rtp = pathogen#join(1,pathogen#split(&runtimepath))
let file = pathogen#runtime_findfile(a:file,a:count)
if file ==# ''
return "echoerr 'E345: Can''t find file \"".a:file."\" in runtimepath'"
endif
if !s:vopen_warning
let s:vopen_warning = 1
let warning = '|echohl WarningMsg|echo "Install scriptease.vim to continue using :V'.a:cmd.'"|echohl NONE'
else
let warning = ''
endif
if a:lcd
let path = file[0:-strlen(a:file)-2]
execute 'lcd `=path`'
return a:cmd.' '.pathogen#fnameescape(a:file) . warning
else
return a:cmd.' '.pathogen#fnameescape(file) . warning
endif
endfunction
function! s:Findcomplete(A,L,P)
let sep = pathogen#slash()
let cheats = {
\'a': 'autoload',
\'d': 'doc',
\'f': 'ftplugin',
\'i': 'indent',
\'p': 'plugin',
\'s': 'syntax'}
if a:A =~# '^\w[\\/]' && has_key(cheats,a:A[0])
let request = cheats[a:A[0]].a:A[1:-1]
else
let request = a:A
endif
let pattern = substitute(request,'/\|\'.sep,'*'.sep,'g').'*'
let found = {}
for path in pathogen#split(&runtimepath)
let path = expand(path, ':p')
let matches = split(glob(path.sep.pattern),"\n")
call map(matches,'isdirectory(v:val) ? v:val.sep : v:val')
call map(matches,'expand(v:val, ":p")[strlen(path)+1:-1]')
for match in matches
let found[match] = 1
endfor
endfor
return sort(keys(found))
endfunction
command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Ve :execute s:find(<count>,'edit<bang>',<q-args>,0)
command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vedit :execute s:find(<count>,'edit<bang>',<q-args>,0)
command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vopen :execute s:find(<count>,'edit<bang>',<q-args>,1)
command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vsplit :execute s:find(<count>,'split',<q-args>,<bang>1)
command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vvsplit :execute s:find(<count>,'vsplit',<q-args>,<bang>1)
command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vtabedit :execute s:find(<count>,'tabedit',<q-args>,<bang>1)
command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vpedit :execute s:find(<count>,'pedit',<q-args>,<bang>1)
command! -bar -bang -range=1 -nargs=1 -complete=customlist,s:Findcomplete Vread :execute s:find(<count>,'read',<q-args>,<bang>1)
" vim:set et sw=2 foldmethod=expr foldexpr=getline(v\:lnum)=~'^\"\ Section\:'?'>1'\:getline(v\:lnum)=~#'^fu'?'a1'\:getline(v\:lnum)=~#'^endf'?'s1'\:'=':

View File

@ -0,0 +1,23 @@
License: The MIT License (MIT)
Copyright (c) 2013,2014 Reed Esau
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.
<!-- vim: set tw=74 :-->

View File

@ -0,0 +1,696 @@
# vim-pencil
> Rethinking Vim as a tool for writers
<br/>
- - -
![demo](http://i.imgur.com/0KYl5vU.gif)
- - -
# Features
The _pencil_ plugin aspires to make Vim as powerful a tool for writers as
it is for coders by focusing narrowly on the handful of tweaks needed to
smooth the path to writing prose.
* For editing prose-oriented file types such as _text_, _markdown_,
_mail_, _rst_, _tex_, _textile_, and _asciidoc_
* Agnostic on soft line wrap _versus_ hard line breaks, supporting both
* Auto-detects wrap mode via `modeline` and sampling
* Adjusts navigation key mappings to suit the wrap mode
* Creates undo points on common punctuation during Insert mode, including
deletion via line `<C-U>` and word `<C-W>`
* Buffer-scoped configuration (with a few minor exceptions, _pencil_ preserves
your global settings)
* Support for Vims Conceal feature to hide markup defined by Syntax plugins
(e.g., `_` and `*` markup for styled text in \_*Markdown*\_)
* Support for display of mode indicator (`␍` and `⤸`, e.g.) in the status line
* Pure Vimscript with no dependencies
In addition, when using hard line break mode:
* Makes use of Vims powerful autoformat while inserting text, except for
tables and code blocks where you wont want it.
* *NEW* Optional key mapping to suspend autoformat for the Insert.
Need spell-check, distraction-free editing, and other features? Vim is about
customization. To complete your editing environment, learn to configure Vim and
draw upon its rich ecosystem of plugins.
# Why use Vim for writing?
With plenty of word processing applications available, including those
that specifically cater to writers, why use a modal editor like Vim?
Several reasons have been offered:
* Your hands can rest in a neutral home position, only rarely straying
to reach for mouse, track pad, or arrow keys
* Minimal chording, with many mnemonic-friendly commands
* Sophisticated capabilities for navigating and manipulating text
* Highly configurable, enabling you to build a workflow that suits your
needs, with many great plugins available
* No proprietary format lock-in
But while such reasons might be sound, they remain scant justification to
switch away from the familiar word processor. Instead, you need
a compelling reason—one that can appeal to a writers love for language
and the tools of writing.
You can find that reason in Vim's mysterious command sequences. Take `cas`
for instance. You might see it as a mnemonic for _Change Around Sentence_
to replace an existing sentence. But dig a bit deeper to discover that
such commands have a grammar of their own, comprised of nouns, verbs, and
modifiers. Think of them as the composable building blocks of a _domain
specific language_ for manipulating text, one that can become a powerful
tool in expressing yourself. For more details on vi-style editing, see...
* [Learn to speak vim verbs, nouns, and modifiers!][ls] (December 2011)
* [Your problem with Vim is that you don't grok vi][gv] (December 2011)
* [Intro to Vim's Grammar][ig] (January 2013)
* [Why Atom Cant Replace Vim, Learning the lesson of vi][wa] (March 2014)
* [Language of Vim/Neovim][lovn] (January 2015)
[ls]: http://yanpritzker.com/2011/12/16/learn-to-speak-vim-verbs-nouns-and-modifiers/
[gv]: http://stackoverflow.com/questions/1218390/what-is-your-most-productive-shortcut-with-vim/1220118#1220118
[ig]: http://takac.github.io/2013/01/30/vim-grammar/
[wa]: https://medium.com/p/433852f4b4d1
[lovn]: http://allsyed.com/language-of-vim-neovim/
# Installation
_pencil_ is best installed using a Vim package manager, such as
[Vundle][vnd], [Plug][plg], [NeoBundle][nbn], or [Pathogen][pth].
_For those new to Vim: before installing this plugin, consider getting
comfortable with the basics of Vim by working through one of the many
tutorials available._
[vnd]: https://github.com/gmarik/Vundle.vim
[plg]: https://github.com/junegunn/vim-plug
[nbn]: https://github.com/Shougo/neobundle.vim
[pth]: https://github.com/tpope/vim-pathogen
#### Vundle
Add to your `.vimrc` and save:
```vim
Plugin 'reedes/vim-pencil'
```
…then run the following in Vim:
```vim
:source %
:PluginInstall
```
#### Plug
Add to your `.vimrc` and save:
```vim
Plug 'reedes/vim-pencil'
```
…then run the following in Vim:
```vim
:source %
:PlugInstall
```
#### NeoBundle
Add to your `.vimrc` and save:
```vim
NeoBundle 'reedes/vim-pencil'
```
…then run the following in Vim:
```vim
:source %
:NeoBundleInstall
```
#### Pathogen
Run the following in a terminal:
```bash
cd ~/.vim/bundle
git clone https://github.com/reedes/vim-pencil
```
# Configuration
## Initializing by command
You can manually enable, disable, and toggle _pencil_ as a command:
* `Pencil` - initialize _pencil_ with auto-detect for the current buffer
* `NoPencil` (or `PencilOff`) - removes navigation mappings and restores buffer to global settings
* `TogglePencil` (or `PencilToggle`) - if on, turns off; if off, initializes with auto-detect
Because auto-detect might not work as intended, you can invoke a command
to set the behavior for the current buffer:
* `SoftPencil` (or `PencilSoft`) - initialize _pencil_ with soft line wrap mode
* `HardPencil` (or `PencilHard`) - initialize _pencil_ with hard line break mode (and Vims autoformat)
## Initializing by file type
Initializing _pencil_ by file type is _optional_, though doing so will
automatically set up your buffers for editing prose.
Add support for your desired file types to your `.vimrc`:
```vim
set nocompatible
filetype plugin on " may already be in your .vimrc
augroup pencil
autocmd!
autocmd FileType markdown,mkd call pencil#init()
autocmd FileType text call pencil#init()
augroup END
```
You can initialize several prose-oriented plugins together:
```vim
augroup pencil
autocmd!
autocmd FileType markdown,mkd call pencil#init()
\ | call lexical#init()
\ | call litecorrect#init()
\ | call textobj#quote#init()
\ | call textobj#sentence#init()
augroup END
```
For a list of other prose-oriented plugins, consult the [See
also](#see-also) section below.
## Hard line breaks or soft line wrap?
Coders will have the most experience with the former, and writers the
latter. But whatever your background, chances are that you must contend
with both conventions. This plugin doesn't force you to choose a side—you
can configure each buffer independently.
In most cases you can set a default to suit your preference and let
auto-detection figure out what to do.
```vim
let g:pencil#wrapModeDefault = 'soft' " default is 'hard'
augroup pencil
autocmd!
autocmd FileType markdown,mkd call pencil#init()
autocmd FileType text call pencil#init({'wrap': 'hard'})
augroup END
```
In the example above, for buffers of type `markdown` this plugin will
auto-detect the line wrap approach, with soft line wrap as the default.
For buffers of type `text`, it will initialize with hard line breaks,
even if auto-detect might suggest soft line wrap.
## Automatic formatting
_The autoformat feature affects *HardPencil* (hard line break) mode
only._
When inserting text while in *HardPencil* mode, Vims powerful autoformat
feature will be _enabled_ by default and can offer many of the same
benefits as soft line wrap.
To set the default behavior in your `.vimrc`:
```vim
let g:pencil#autoformat = 1 " 0=disable, 1=enable (def)
```
You can override this default during initialization, as in:
```vim
augroup pencil
autocmd!
autocmd FileType markdown call pencil#init({'wrap': 'hard', 'autoformat': 1})
autocmd FileType text call pencil#init({'wrap': 'hard', 'autoformat': 0})
...
augroup END
```
...where buffers of type `markdown` and `text` will use hard line breaks,
but `text` buffers will have autoformat disabled.
## Suspend automatic formatting for the Insert
There are two useful exceptions where autoformat (when enabled for the
buffer) will be _temporarily disabled_ for the current Insert:
First is _pencils_ 'blacklisting' feature: if used with popular
prose-oriented syntax plugins, _pencil_ will suspend autoformat when you
enter Insert mode from inside a code block or table.
[**NEW**] Second, where blacklisting falls short, you can optionally map
a buffer-scoped modifier key to suspend autoformat during the next
Insert:
```vim
let g:pencil#map#suspend_af = 'K' " default is no mapping
```
Using the above mapping, with `Ko` youll enter Insert mode with the
cursor on a new line, but autoformat will suspend for that Insert. Using
`o` by itself will retain autoformat.
(See the advanced section below for details on how blacklisting is
implemented and configured).
## Manual formatting
Note that you need not rely on Vims autoformat exclusively and can
manually reformat paragraphs with standard Vim commands:
* `gqap` - format current paragraph (see `:help gq` for details)
* `vapJgqap` - merge two paragraphs (current and next) and format
* `ggVGgq` or `:g/^/norm gqq` - format all paragraphs in buffer
Optionally, you can map these operations to underutilized keys in your
`.vimrc`:
```vim
nnoremap <silent> Q gqap
xnoremap <silent> Q gq
nnoremap <silent> <leader>Q vapJgqap
```
Or you may wish to unformat, (i.e., remove hard line breaks) when using
soft line wrap.
* `vipJ` - join all lines in current paragraph
* `:%norm vipJ` - unformat all paragraphs in buffer
## Default textwidth
You can configure the textwidth to be used in **Hard Pencil** mode when no
textwidth is set globally, locally, or available via modeling. It
defaults to `74`, but you can change that value in your `.vimrc`:
```vim
let g:pencil#textwidth = 74
```
## Sentence spacing
By default, when formatting text (through `gwip`, e.g.) only one space
will be inserted after a period(`.`), exclamation point(`!`), or question
mark(`?`). You can change this default:
```vim
let g:pencil#joinspaces = 0 " 0=one_space (def), 1=two_spaces
```
## Cursor wrap
By default, `h`/`l` and the left/right cursor keys will move to the
previous/next line after reaching first/last character in a line with
a hard break. If you wish to retain the default Vim behavior, set the
`cursorwrap` value to `0` in your `.vimrc`:
```vim
let g:pencil#cursorwrap = 1 " 0=disable, 1=enable (def)
```
## Concealing \_\_markup\_\_
_pencil_ enables Vim's powerful Conceal feature, although support among
Syntax and Colorscheme plugins is currently spotty.
You can change _pencils_ default settings for conceal in your `.vimrc`:
```vim
let g:pencil#conceallevel = 3 " 0=disable, 1=one char, 2=hide char, 3=hide all (def)
let g:pencil#concealcursor = 'c' " n=normal, v=visual, i=insert, c=command (def)
```
For more details on Vims Conceal feature, see:
```vim
:help conceallevel
:help concealcursor
```
### Concealing styled text in Markdown
Syntax plugins such as [tpope/vim-markdown][tm] support concealing the
markup characters when displaying \_*italic*\_, \*\*__bold__\*\*, and
\*\*\*___bold italic___\*\*\* styled text.
To use Vims Conceal feature with Markdown, you will need to install:
1. [tpope/vim-markdown][tm] as its currently the only Markdown syntax
plugin that supports conceal.
2. A monospaced font (such as [Cousine][co]) featuring the _italic_,
**bold**, and ***bold italic*** style variant for styled text.
3. A colorscheme (such as [reedes/vim-colors-pencil][cp]) which supports
the Markdown-specific highlight groups for styled text.
You should then only see the `_` and `*` markup for the cursor line and in
visual selections.
**Terminal users:** consult your terminals documentation to configure your
terminal to support **bold** and _italic_ styles.
[co]: http://www.google.com/fonts/specimen/Cousine
[tm]: http://github.com/tpope/vim-markdown
## Status line indicator
Your status line can reflect the wrap mode for _pencil_ buffers. For
example, `␍` to represent `HardPencil` (hard line break) mode. To
configure your status line and ruler, add to your `.vimrc`:
```vim
set statusline=%<%f\ %h%m%r%w\ \ %{PencilMode()}\ %=\ col\ %c%V\ \ line\ %l\,%L\ %P
set rulerformat=%-12.(%l,%c%V%)%{PencilMode()}\ %P
```
or if using [bling/vim-airline][va]:
```vim
let g:airline_section_x = '%{PencilMode()}'
```
The default indicators now include auto for when Vims autoformat is
active in hard line break mode. (If autoformat is suspended for the
Insert, itll show the hard indicator.)
```vim
let g:pencil#mode_indicators = {'hard': 'H', 'auto': 'A', 'soft': 'S', 'off': '',}
```
If Unicode is detected, the default indicators are:
```vim
let g:pencil#mode_indicators = {'hard': '␍', 'auto': 'ª', 'soft': '⤸', 'off': '',}
```
If you dont like the default indicators, you can specify your own in
your `.vimrc`.
Note that `PencilMode()` will return blank for buffers in which _pencil_
has not been initialized.
[va]: http://github.com/bling/vim-airline
## Advanced pencil
### Advanced initialization
You may want to refactor initialization statements into a function in
your `.vimrc` to set up a buffer for writing:
```vim
function! Prose()
call pencil#init()
call lexical#init()
call litecorrect#init()
call textobj#quote#init()
call textobj#sentence#init()
" manual reformatting shortcuts
nnoremap <buffer> <silent> Q gqap
xnoremap <buffer> <silent> Q gq
nnoremap <buffer> <silent> <leader>Q vapJgqap
" force top correction on most recent misspelling
nnoremap <buffer> <c-s> [s1z=<c-o>
inoremap <buffer> <c-s> <c-g>u<Esc>[s1z=`]A<c-g>u
" replace common punctuation
iabbrev <buffer> --
iabbrev <buffer> --- —
iabbrev <buffer> << «
iabbrev <buffer> >> »
" open most folds
setlocal foldlevel=6
endfunction
" automatically initialize buffer by file type
autocmd FileType markdown,mkd,text call Prose()
" invoke manually by command for other file types
command! -nargs=0 Prose call Prose()
```
For highly-granular control, you can override _pencil_ and other configuration
settings when initializing buffers by file type:
```vim
augroup pencil
autocmd!
autocmd FileType markdown,mkd call pencil#init()
\ | call litecorrect#init()
\ | setl spell spl=en_us fdl=4 noru nonu nornu
\ | setl fdo+=search
autocmd Filetype git,gitsendemail,*commit*,*COMMIT*
\ call pencil#init({'wrap': 'hard', 'textwidth': 72})
\ | call litecorrect#init()
\ | setl spell spl=en_us et sw=2 ts=2 noai
autocmd Filetype mail call pencil#init({'wrap': 'hard', 'textwidth': 60})
\ | call litecorrect#init()
\ | setl spell spl=en_us et sw=2 ts=2 noai nonu nornu
autocmd Filetype html,xml call pencil#init({'wrap': 'soft'})
\ | call litecorrect#init()
\ | setl spell spl=en_us et sw=2 ts=2
augroup END
```
Configurable options for `pencil#init()` include: `autoformat`,
`concealcursor`, `conceallevel`, `cursorwrap`, `joinspaces`, `textwidth`,
and `wrap`. These are detailed above.
### Autoformat manual control
_The autoformat feature affects *HardPencil* (hard line break) mode
only._
To suspend autoformat for the next Insert, see above.
When you need to manually enable/disable autoformat for the current
buffer, you can do so with a command:
* `PFormat` - enable autoformat for buffer (can still be disabled via blacklisting)
* `PFormatOff` - disable autoformat for buffer
* `PFormatToggle` - toggle to enable if disabled, etc.
You can map a key in your `.vimrc` to toggle Vim's autoformat:
```vim
noremap <silent> <F7> :<C-u>PFormatToggle<cr>
inoremap <silent> <F7> <C-o>:PFormatToggle<cr>
```
### Autoformat blacklisting (and whitelisting)
_The autoformat feature affects *HardPencil* (hard line break) mode
only._
When editing formatted text, such as a table or code block, Vims
autoformat will wreak havoc with the formatting. In these cases you will
want autoformat suspended for the duration of the Insert.
When entering Insert mode, _pencil_ will determine the highlight group at
the cursor position. If that group has been blacklisted, _pencil_ will
suspend autoformat for the Insert. For example, if editing a buffer of
type markdown, autoformat will be suspended if you invoke Insert mode
from inside a `markdownFencedCodeBlock` highlight group.
Blacklists are now declared by file type. The default blacklists (and
whitelists) are declared in the `plugin/pencil.vim` module. Heres an
excerpt showing the configuration for the markdown file type:
```vim
let g:pencil#autoformat_config = {
\ 'markdown': {
\ 'black': [
\ 'htmlH[0-9]',
\ 'markdown(Code|H[0-9]|Url|IdDeclaration|Link|Rule|Highlight[A-Za-z0-9]+)',
\ 'markdown(FencedCodeBlock|InlineCode)',
\ 'mkd(Code|Rule|Delimiter|Link|ListItem|IndentCode)',
\ 'mmdTable[A-Za-z0-9]*',
\ ],
\ 'white': [
\ 'markdown(Code|Link)',
\ ],
\ },
[snip]
\ }
```
The whitelist will override the blacklist and enable Vims autoformat if
text that would normally be blacklisted doesnt dominate the entire line.
This allows autoformat to work with `inline` code and links.
### Auto-detecting wrap mode
If you didn't explicitly specify a wrap mode during initialization,
_pencil_ will attempt to detect it.
It will first look for a `textwidth` (or `tw`) specified in a modeline.
Failing that, _pencil_ will then sample lines from the start of the
buffer.
#### Detect via modeline
Will the wrap mode be detected accurately? Maybe. But you can improve its
chances by giving _pencil_ an explicit hint.
At the bottom of this document is a odd-looking code:
```html
<!-- vim: set tw=73 :-->
```
This is an **optional** modeline that tells Vim to run the following
command upon loading the file into a buffer:
```vim
:set textwidth=73
```
It tells _pencil_ to assume hard line breaks, regardless of whether or
not soft line wrap is the default editing mode for buffers of type
markdown.
You explicitly specify soft wrap mode by specifying a textwidth of `0`:
```html
<!-- vim: set tw=0 :-->
```
Note that if the modelines feature is disabled (such as for security
reasons) the textwidth will still be set by this plugin.
#### Detect via sampling
If no modeline with a textwidth is found, _pencil_ will sample the
initial lines from the buffer, looking for those excessively-long.
There are two settings you can add to your `.vimrc` to tweak this behavior.
The maximum number of lines to sample from the start of the buffer:
```vim
let g:pencil#softDetectSample = 20
```
Set that value to `0` to disable detection via line sampling.
When the number of bytes on a sampled line per exceeds this next value,
then _pencil_ assumes soft line wrap.
```vim
let g:pencil#softDetectThreshold = 130
```
If no such lines found, _pencil_ falls back to the default wrap mode.
# See also
* [To Vim][tv] - Writer and psychologist Ian Hocking on using Vim for writing
* [Vim Training Class - Basic motions and commands][tc] - video tutorial by Shawn Biddle
* [Vim for Writers][vw] - guide to the basics geared to writers
Bloggers and developers discuss _pencil_ and its brethern:
* [Reed Esau's growing list of Vim plugins for writers][regl] (2014) - by @pengwynn
* [Distraction Free Writing in Vim][dfwiv] (2014) - by @tlattimore
* [Safari Blog: Turning vim into an IDE through vim plugins][tviai] (2014) - by @jameydeorio
* [Quick tops for writing prose with Vim][qtfwp] (2014) - by @benoliver999
* [UseVim: Reed Esau's Writing Plugins][rewp] (2015) - by @alexyoung
* [Tomasino Labs: Vim in Context][vic] (2015) - by @jamestomasino
* [Writing with Vim][wwv] (2015) - by Pat Ambrosio
Other plugins of specific interest to writers:
* [danielbmarques/vim-ditto][vd] - highlight repeated words
* [tpope/vim-abolish][ab] - search for, substitute, and abbr. multiple variants of a word
* [tommcdo/vim-exchange][ex] - easy text exchange operator for Vim
* [junegunn/limelight.vim][jl] - focus mode that brightens current paragraph
* [junegunn/goyo.vim][jg] - distraction-free editing mode
[vd]: https://github.com/danielbmarques/vim-ditto
[qtfwp]: http://benoliver999.com/technology/2014/12/06/vimforprose/
[wwv]: https://lilii.co/aardvark/writing-with-vim
[vic]: https://labs.tomasino.org/vim-in-context.html
[rewp]: http://usevim.com/2015/05/27/reedes/
[tviai]: https://www.safaribooksonline.com/blog/2014/11/23/way-vim-ide/
[regl]: http://wynnnetherland.com/journal/reed-esau-s-growing-list-of-vim-plugins-for-writers/
[dfwiv]: http://tlattimore.com/blog/distraction-free-writing-in-vim/
[ab]: http://github.com/tpope/vim-abolish
[ex]: http://github.com/tommcdo/vim-exchange
[jl]: http://github.com/junegunn/limelight.vim
[jg]: http://github.com/junegunn/goyo.vim
Markdown syntax plugins
* [tpope/vim-markdown][tvm] - the latest version of the syntax plugin that ships with Vim
* [plasticboy/vim-markdown][pvm]
* [gabrielelana/vim-markdown][gvm]
* [mattly/vim-markdown-enhancements][mvme] - highlighting for tables and footnotes
[tvm]: http://github.com/tpope/vim-markdown
[pvm]: http://github.com/plasticboy/vim-markdown
[gvm]: http://github.com/gabrielelana/vim-markdown
[mvme]: http://github.com/mattly/vim-markdown-enhancements
If you find the _pencil_ plugin useful, check out these others by [@reedes][re]:
* [vim-colors-pencil][cp] - color scheme for Vim inspired by IA Writer
* [vim-lexical][lx] - building on Vims spell-check and thesaurus/dictionary completion
* [vim-litecorrect][lc] - lightweight auto-correction for Vim
* [vim-one][vo] - make use of Vims _+clientserver_ capabilities
* [vim-textobj-quote][qu] - extends Vim to support typographic (curly) quotes
* [vim-textobj-sentence][ts] - improving on Vim's native sentence motion command
* [vim-thematic][th] - modify Vims appearance to suit your task and environment
* [vim-wheel][wh] - screen-anchored cursor movement for Vim
* [vim-wordy][wo] - uncovering usage problems in writing
Unimpressed by _pencil_? [vim-pandoc][vp] offers prose-oriented features
with its own Markdown variant.
[cp]: http://github.com/reedes/vim-colors-pencil
[lc]: http://github.com/reedes/vim-litecorrect
[lx]: http://github.com/reedes/vim-lexical
[qu]: http://github.com/reedes/vim-textobj-quote
[re]: http://github.com/reedes
[tc]: https://www.youtube.com/watch?v=Nim4_f5QUxA
[th]: http://github.com/reedes/vim-thematic
[ts]: http://github.com/reedes/vim-textobj-sentence
[tv]: http://ianhocking.com/2013/11/17/to-vim/
[vo]: http://github.com/reedes/vim-one
[vw]: http://therandymon.com/woodnotes/vim-for-writers/vimforwriters.html
[wh]: http://github.com/reedes/vim-wheel
[wo]: http://github.com/reedes/vim-wordy
[vp]: http://github.com/vim-pandoc/vim-pandoc
# Future development
If youve spotted a problem or have an idea on improving _pencil_, please
report it as an issue, or better yet submit a pull request.
```
<!-- vim: set tw=73 :-->
```

View File

@ -0,0 +1,514 @@
" ============================================================================
" File: pencil.vim
" Description: autoload functions for vim-pencil plugin
" Maintainer: Reed Esau <github.com/reedes>
" Created: December 28, 2013
" License: The MIT License (MIT)
" ============================================================================
if exists("autoloaded_pencil") | fini | en
let autoloaded_pencil = 1
let s:WRAP_MODE_DEFAULT = -1
let s:WRAP_MODE_OFF = 0
let s:WRAP_MODE_HARD = 1
let s:WRAP_MODE_SOFT = 2
" Wrap-mode detector
" Scan lines at end and beginning of file to determine the wrap mode.
" Modelines has priority over long lines found.
fun! s:detect_wrap_mode() abort
let b:max_textwidth = -1 " assume no relevant modeline
call s:doModelines()
if b:max_textwidth > 0
" modelines(s) found with positive textwidth, so hard line breaks
return s:WRAP_MODE_HARD
en
if b:max_textwidth ==# 0 || g:pencil#wrapModeDefault ==# 'soft'
" modeline(s) found only with zero textwidth, so it's soft line wrap
" or, the user wants to default to soft line wrap
return s:WRAP_MODE_SOFT
en
" attempt to rule out soft line wrap
" scan initial lines in an attempt to detect long lines
for l:line in getline(1, g:pencil#softDetectSample)
if len(l:line) > g:pencil#softDetectThreshold
return s:WRAP_MODE_SOFT
en
endfo
" punt
return s:WRAP_MODE_DEFAULT
endf
fun! s:imap(preserve_completion, key, icmd) abort
if a:preserve_completion
exe ":ino <buffer> <silent> <expr> " . a:key . " pumvisible() ? \"" . a:key . "\" : \"" . a:icmd . "\""
el
exe ":ino <buffer> <silent> " . a:key . " " . a:icmd
en
endf
fun! s:maybe_enable_autoformat() abort
" don't enable autoformat if in a blacklisted code block or table,
" allowing for reprieve via whitelist in certain cases
" a flag to suspend autoformat for the Insert
if b:pencil_suspend_af
let b:pencil_suspend_af = 0 " clear the flag
return
en
let l:ft = get(g:pencil#autoformat_aliases, &ft, &ft)
let l:af_cfg = get(g:pencil#autoformat_config, l:ft, {})
let l:black = get(l:af_cfg, 'black', [])
let l:white = get(l:af_cfg, 'white', [])
let l:has_black_re = len(l:black) > 0
let l:has_white_re = len(l:white) > 0
let l:black_re = l:has_black_re ? '\v(' . join( l:black, '|') . ')' : ''
let l:white_re = l:has_white_re ? '\v(' . join( l:white, '|') . ')' : ''
let l:enforce_previous_line = get(l:af_cfg, 'enforce-previous-line', 0)
let l:okay_to_enable = 1
let l:line = line('.')
let l:col = col('.')
let l:last_col = col('$')
let l:stack = []
let l:found_empty = 0
" at end of line there may be no synstack, so scan back
while l:col > 0
let l:stack = synstack(l:line, l:col)
if l:stack != []
break
en
" the last column will always be empty, so ignore it
if l:col < l:last_col
let l:found_empty = 1
en
let l:col -= 1
endw
" if needed, scan towards end of line looking for highlight groups
if l:stack == []
let l:col = col('.') + 1
while l:col <= l:last_col
let l:stack = synstack(l:line, l:col)
if l:stack != []
break
en
" the last column will always be empty, so ignore it
if l:col < l:last_col
let l:found_empty = 1
en
let l:col += 1
endw
en
" enforce blacklist by scanning for syntax matches
if l:has_black_re
for l:sid in l:stack
if match(synIDattr(l:sid, 'name'), l:black_re) >= 0
let l:okay_to_enable = 0
"echohl WarningMsg
"echo 'hit blacklist line=' . l:line . ' col=' . l:col .
" \ ' name=' . synIDattr(l:sid, 'name')
"echohl NONE
break
en
endfo
en
" enforce whitelist by detecting inline `markup` for which we DO want
" autoformat to be enabled (e.g., tpope's markdownCode)
if l:has_white_re && !l:okay_to_enable
" one final check for an empty stack at the start and end of line,
" either of which greenlights a whitelist check
if !l:found_empty
if synstack(l:line, 1) == [] ||
\ (l:last_col > 1 && synstack(l:line, l:last_col-1) == [])
let l:found_empty = 1
en
en
if l:found_empty
for l:sid in l:stack
if match(synIDattr(l:sid, 'name'), l:white_re) >= 0
let l:okay_to_enable = 1
break
en
endfo
en
en
" disallow enable if start of previous line is in blacklist,
if l:has_black_re && l:enforce_previous_line && l:okay_to_enable && l:line > 1
let l:prev_stack = synstack(l:line - 1, 1)
for l:sid in l:prev_stack
if len(l:sid) > 0 &&
\ match(synIDattr(l:sid, 'name'), l:black_re) >= 0
let l:okay_to_enable = 0
break
en
endfo
en
if l:okay_to_enable
set formatoptions+=a
en
endf
fun! pencil#setAutoFormat(af) abort
" 1=enable, 0=disable, -1=toggle
if !exists('b:last_autoformat')
let b:last_autoformat = 0
en
let l:nu_af = a:af ==# -1 ? !b:last_autoformat : a:af
let l:is_hard =
\ exists('b:pencil_wrap_mode') &&
\ b:pencil_wrap_mode ==# s:WRAP_MODE_HARD
if l:nu_af && l:is_hard
aug pencil_autoformat
au InsertEnter <buffer> call s:maybe_enable_autoformat()
au InsertLeave <buffer> set formatoptions-=a
aug END
el
sil! au! pencil_autoformat * <buffer>
if l:nu_af && !l:is_hard
echohl WarningMsg
echo "autoformat can only be enabled in hard line break mode"
echohl NONE
return
en
en
let b:last_autoformat = l:nu_af
endf
" Create mappings for word processing
" args:
" 'wrap': 'detect|off|hard|soft|toggle'
fun! pencil#init(...) abort
let l:args = a:0 ? a:1 : {}
" flag to suspend autoformat for the next Insert
let b:pencil_suspend_af = 0
if !exists('b:pencil_wrap_mode')
let b:pencil_wrap_mode = s:WRAP_MODE_OFF
en
if !exists("b:max_textwidth")
let b:max_textwidth = -1
en
" If user explicitly requested wrap_mode thru args, go with that.
let l:wrap_arg = get(l:args, 'wrap', 'detect')
if (b:pencil_wrap_mode && l:wrap_arg ==# 'toggle') ||
\ l:wrap_arg =~# '^\(0\|off\|disable\|false\)$'
let b:pencil_wrap_mode = s:WRAP_MODE_OFF
elsei l:wrap_arg ==# 'hard'
let b:pencil_wrap_mode = s:WRAP_MODE_HARD
elsei l:wrap_arg ==# 'soft'
let b:pencil_wrap_mode = s:WRAP_MODE_SOFT
elsei l:wrap_arg ==# 'default'
let b:pencil_wrap_mode = s:WRAP_MODE_DEFAULT
el
" this can return s:WRAP_MODE_ for soft, hard or default
let b:pencil_wrap_mode = s:detect_wrap_mode()
en
" translate default(-1) to soft(1) or hard(2) or off(0)
if b:pencil_wrap_mode ==# s:WRAP_MODE_DEFAULT
if g:pencil#wrapModeDefault =~# '^\(0\|off\|disable\|false\)$'
let b:pencil_wrap_mode = s:WRAP_MODE_OFF
elsei g:pencil#wrapModeDefault ==# 'soft'
let b:pencil_wrap_mode = s:WRAP_MODE_SOFT
el
let b:pencil_wrap_mode = s:WRAP_MODE_HARD
en
en
" autoformat is only used in Hard mode, and then only during
" Insert mode
call pencil#setAutoFormat(
\ b:pencil_wrap_mode ==# s:WRAP_MODE_HARD &&
\ get(l:args, 'autoformat', g:pencil#autoformat))
if b:pencil_wrap_mode ==# s:WRAP_MODE_HARD
if &modeline ==# 0 && b:max_textwidth > 0
" Compensate for disabled modeline
exe 'setl textwidth=' . b:max_textwidth
elsei &textwidth ==# 0
exe 'setl textwidth=' .
\ get(l:args, 'textwidth', g:pencil#textwidth)
el
setl textwidth<
en
setl nowrap
" flag to suspend autoformat for next Insert
" optional user-defined mapping
if exists('g:pencil#map#suspend_af') &&
\ g:pencil#map#suspend_af != ''
exe 'no <buffer> <silent> ' . g:pencil#map#suspend_af . ' :let b:pencil_suspend_af=1<CR>'
en
elsei b:pencil_wrap_mode ==# s:WRAP_MODE_SOFT
setl textwidth=0
setl wrap
if has('linebreak')
setl linebreak
" TODO breakat not working yet with n and m-dash
setl breakat-=* " avoid breaking footnote*
setl breakat-=@ " avoid breaking at email addresses
en
if exists('&colorcolumn')
setl colorcolumn=0 " doesn't align as expected
en
el
setl textwidth<
setl wrap< nowrap<
if has('linebreak')
setl linebreak< nolinebreak<
setl breakat<
en
if exists('&colorcolumn')
setl colorcolumn<
en
en
if ( v:version > 704 ||
\ (v:version ==# 704 && has('patch-7.4.338')))
if b:pencil_wrap_mode ==# s:WRAP_MODE_SOFT
setl breakindent
el
setl breakindent<
en
en
" global settings
if b:pencil_wrap_mode
set display+=lastline
set backspace=indent,eol,start
if get(l:args, 'joinspaces', g:pencil#joinspaces)
set joinspaces " two spaces after .!?
el
set nojoinspaces " only one space after a .!? (default)
en
en
" because ve=onemore is relatively rare and could break
" other plugins, restrict its presence to buffer
" Better: restore ve to original setting
if has('virtualedit')
if b:pencil_wrap_mode && get(l:args, 'cursorwrap', g:pencil#cursorwrap)
set whichwrap+=<,>,b,s,h,l,[,]
aug pencil_cursorwrap
au BufEnter <buffer> set virtualedit+=onemore
au BufLeave <buffer> set virtualedit-=onemore
aug END
el
sil! au! pencil_cursorwrap * <buffer>
en
en
" Because syntax for fenced code blocks will mess with the
" definition of a word (via iskeyword) we'll impose a prose-
" oriented definition.
" e.g., let g:markdown_fenced_languages = ['sh',] " adds '.'
"
" Support $20 30% D&D #40 highest-rated O'Toole Mary's
" TODO how to separate quote from apostrophe use?
if b:pencil_wrap_mode
aug pencil_iskeyword
au BufEnter <buffer> setl isk& | setl isk-=_ | setl isk+=$,%,&,#,-,',+
aug END
el
sil! au! pencil_iskeyword * <buffer>
en
" window/buffer settings
if b:pencil_wrap_mode
setl nolist
setl wrapmargin=0
setl autoindent " needed by formatoptions=n
setl indentexpr=
if has('smartindent')
setl nosmartindent " avoid c-style indents in prose
en
if has('cindent')
setl nocindent " avoid c-style indents in prose
en
setl formatoptions+=n " recognize numbered lists
setl formatoptions+=1 " don't break line before 1 letter word
setl formatoptions+=t " autoformat of text (vim default)
"setl formatoptions+=2 " preserve indent based on 2nd line for rest of paragraph
" clean out stuff we likely don't want
setl formatoptions-=v " only break line at blank entered during insert
setl formatoptions-=w " avoid erratic behavior if mixed spaces
setl formatoptions-=a " autoformat will turn on with Insert in HardPencil mode
setl formatoptions-=2 " doesn't work with with fo+=n, says docs
" plasticboy/vim-markdown sets these to handle bullet points
" as comments. Not changing for now.
"setl formatoptions-=o " don't insert comment leader
"setl formatoptions-=c " no autoformat of comments
"setl formatoptions+=r " don't insert comment leader
if has('conceal') && v:version >= 703
exe ':setl conceallevel=' .
\ get(l:args, 'conceallevel', g:pencil#conceallevel)
exe ':setl concealcursor=' .
\ get(l:args, 'concealcursor', g:pencil#concealcursor)
en
el
if has('smartindent')
setl smartindent< nosmartindent<
en
if has('cindent')
setl cindent< nocindent<
en
if has('conceal')
setl conceallevel<
setl concealcursor<
en
setl indentexpr<
setl autoindent< noautoindent<
setl list< nolist<
setl wrapmargin<
setl formatoptions<
en
if b:pencil_wrap_mode ==# s:WRAP_MODE_SOFT
nn <buffer> <silent> $ g$
nn <buffer> <silent> 0 g0
vn <buffer> <silent> $ g$
vn <buffer> <silent> 0 g0
no <buffer> <silent> <Home> g<Home>
no <buffer> <silent> <End> g<End>
" preserve behavior of home/end keys in popups
call s:imap(1, '<Home>', '<C-o>g<Home>')
call s:imap(1, '<End>' , '<C-o>g<End>' )
el
sil! nun <buffer> $
sil! nun <buffer> 0
sil! vu <buffer> $
sil! vu <buffer> 0
sil! nun <buffer> <Home>
sil! nun <buffer> <End>
sil! iu <buffer> <Home>
sil! iu <buffer> <End>
en
if b:pencil_wrap_mode
nn <buffer> <silent> j gj
nn <buffer> <silent> k gk
vn <buffer> <silent> j gj
vn <buffer> <silent> k gk
no <buffer> <silent> <Up> gk
no <buffer> <silent> <Down> gj
" preserve behavior of up/down keys in popups
call s:imap(1, '<Up>' , '<C-o>g<Up>' )
call s:imap(1, '<Down>', '<C-o>g<Down>')
el
sil! nun <buffer> j
sil! nun <buffer> k
sil! vu <buffer> j
sil! vu <buffer> k
sil! unm <buffer> <Up>
sil! unm <buffer> <Down>
sil! iu <buffer> <Up>
sil! iu <buffer> <Down>
en
" set undo points around common punctuation,
" line <c-u> and word <c-w> deletions
if b:pencil_wrap_mode
ino <buffer> . .<c-g>u
ino <buffer> ! !<c-g>u
ino <buffer> ? ?<c-g>u
ino <buffer> , ,<c-g>u
ino <buffer> ; ;<c-g>u
ino <buffer> : :<c-g>u
ino <buffer> <c-u> <c-g>u<c-u>
ino <buffer> <c-w> <c-g>u<c-w>
" map <cr> only if not already mapped
if empty(maparg('<cr>', 'i'))
ino <buffer> <cr> <c-g>u<cr>
let b:pencil_cr_mapped = 1
el
let b:pencil_cr_mapped = 0
en
el
sil! iu <buffer> .
sil! iu <buffer> !
sil! iu <buffer> ?
sil! iu <buffer> ,
sil! iu <buffer> ;
sil! iu <buffer> :
sil! iu <buffer> <c-u>
sil! iu <buffer> <c-w>
" unmap <cr> only if we mapped it ourselves
if exists('b:pencil_cr_mapped') && b:pencil_cr_mapped
sil! iu <buffer> <cr>
en
en
endf
" attempt to find a non-zero textwidth, etc.
fun! s:doOne(item) abort
let l:matches = matchlist(a:item, '^\([a-z]\+\)=\([a-zA-Z0-9_\-.]\+\)$')
if len(l:matches) > 1
if l:matches[1] =~ 'textwidth\|tw'
let l:tw = str2nr(l:matches[2])
if l:tw > b:max_textwidth
let b:max_textwidth = l:tw
en
en
en
endf
" attempt to find a non-zero textwidth, etc.
fun! s:doModeline(line) abort
let l:matches = matchlist(a:line, '\%(\S\@<!\%(vi\|vim\([<>=]\?\)\([0-9]\+\)\?\)\|\sex\):\s*\%(set\s\+\)\?\([^:]\+\):\S\@!')
if len(l:matches) > 0
for l:item in split(l:matches[3])
call s:doOne(l:item)
endfo
en
let l:matches = matchlist(a:line, '\%(\S\@<!\%(vi\|vim\([<>=]\?\)\([0-9]\+\)\?\)\|\sex\):\(.\+\)')
if len(l:matches) > 0
for l:item in split(l:matches[3], '[ \t:]')
call s:doOne(l:item)
endfo
en
endf
" sample lines for detection, capturing both
" modeline(s) and max line length
" Hat tip to https://github.com/ciaranm/securemodelines
fun! s:doModelines() abort
if line("$") > &modelines
let l:lines={ }
call map(filter(getline(1, &modelines) +
\ getline(line("$") - &modelines, "$"),
\ 'v:val =~ ":"'), 'extend(l:lines, { v:val : 0 } )')
for l:line in keys(l:lines)
call s:doModeline(l:line)
endfo
el
for l:line in getline(1, "$")
call s:doModeline(l:line)
endfo
en
endf
" vim:ts=2:sw=2:sts=2

View File

@ -0,0 +1,198 @@
" ============================================================================
" File: pencil.vim
" Description: vim-pencil plugin
" Maintainer: Reed Esau <github.com/reedes>
" Created: December 28, 2013
" License: The MIT License (MIT)
" ============================================================================
"
if exists('g:loaded_pencil') || &cp | fini | en
let g:loaded_pencil = 1
" Save 'cpoptions' and set Vim default to enable line continuations.
let s:save_cpo = &cpo
set cpo&vim
let s:WRAP_MODE_DEFAULT = -1
let s:WRAP_MODE_OFF = 0
let s:WRAP_MODE_HARD = 1
let s:WRAP_MODE_SOFT = 2
fun! s:unicode_enabled()
retu &encoding ==# 'utf-8'
endf
" helper for statusline
"
" Note that it shouldn't be dependent on init(), which
" won't have been called for non-prose modules.
fun! PencilMode()
if exists('b:pencil_wrap_mode')
if b:pencil_wrap_mode ==# s:WRAP_MODE_SOFT
return get(g:pencil#mode_indicators, 'soft', 'S')
elsei b:pencil_wrap_mode ==# s:WRAP_MODE_HARD
if &fo =~ 'a'
return get(g:pencil#mode_indicators, 'auto', 'A')
el
return get(g:pencil#mode_indicators, 'hard', 'H')
en
el
return get(g:pencil#mode_indicators, 'off', '')
en
else
return '' " should be blank for non-prose modes
en
endf
if !exists('g:pencil#wrapModeDefault')
" user-overridable default, if detection fails
" should be 'soft' or 'hard' or 'off'
let g:pencil#wrapModeDefault = 'hard'
en
if !exists('g:pencil#textwidth')
" textwidth used when in hard linebreak mode
let g:pencil#textwidth = 74
en
if !exists('g:pencil#autoformat')
" by default, automatically format text when in Insert mode
" with hard wrap.
let g:pencil#autoformat = 1
en
if !exists('g:pencil#autoformat_config')
" Do not activate autoformat if entering Insert mode when
" the cursor is inside any of the following syntax groups.
"
" markdown* (tpope/vim-markdown)
" mkd*, htmlH[0-9] (plasticboy/vim-markdown)
" markdownFencedCodeBlock, markdownInlineCode, markdownRule, markdownH[0-9] (gabrielelana/vim-markdown)
" mmdTable[A-Za-z0-9]* (mattly/vim-markdown-enhancements)
" txtCode (timcharper/textile.vim)
" rst*,tex*,asciidoc* (syntax file shipped with vim)
let g:pencil#autoformat_config = {
\ 'markdown': {
\ 'black': [
\ 'htmlH[0-9]',
\ 'markdown(Code|H[0-9]|Url|IdDeclaration|Link|Rule|Highlight[A-Za-z0-9]+)',
\ 'markdown(FencedCodeBlock|InlineCode)',
\ 'mkd(Code|Rule|Delimiter|Link|ListItem|IndentCode)',
\ 'mmdTable[A-Za-z0-9]*',
\ ],
\ 'white': [
\ 'markdown(Code|Link)',
\ ],
\ },
\ 'asciidoc': {
\ 'black': [
\ 'asciidoc(AttributeList|AttributeEntry|ListLabel|Literal|SideBar|Source|Sect[0-9])',
\ 'asciidoc[A-Za-z]*(Block|Macro|Title)',
\ ],
\ 'white': [
\ 'asciidoc(AttributeRef|Macro)',
\ ],
\ 'enforce-previous-line': 1,
\ },
\ 'rst': {
\ 'black': [
\ 'rst(CodeBlock|Directive|LiteralBlock|Sections)',
\ ],
\ },
\ 'tex': {
\ 'black': [
\ 'tex(BeginEndName|Delimiter|DocType|InputFile|Math|RefZone|Statement|Title)',
\ 'texSection$',
\ ],
\ 'enforce-previous-line': 1,
\ },
\ 'textile': {
\ 'black': [
\ 'txtCode',
\ ],
\ },
\ }
en
if !exists('g:pencil#autoformat_aliases')
" Aliases used exclusively for autoformat config.
" Pencil will NOT modify the filetype setting.
let g:pencil#autoformat_aliases = {
\ 'md': 'markdown',
\ 'mkd': 'markdown',
\ }
en
if !exists('g:pencil#joinspaces')
" by default, only one space after full stop (.)
let g:pencil#joinspaces = 0
en
if !exists('g:pencil#cursorwrap')
" by default, h/l and cursor keys will wrap around hard
" linebreaks. Set to 0 if you don't want this behavior
let g:pencil#cursorwrap = 1
en
if !exists('g:pencil#conceallevel')
" by default, concealing capability in your syntax plugin
" will be enabled. See tpope/vim-markdown for example.
" 0=disable, 1=onechar, 2=hidecust, 3=hideall
let g:pencil#conceallevel = 3
en
if !exists('g:pencil#concealcursor')
" n=normal, v=visual, i=insert, c=command
let g:pencil#concealcursor = 'c'
en
if !exists('g:pencil#softDetectSample')
" if no modeline, read as many as this many lines at
" start of file in attempt to detect at least one line
" whose byte count exceeds g:pencil#softDetectThreshold
let g:pencil#softDetectSample = 20
en
if !exists('g:pencil#softDetectThreshold')
" if the byte count of at least one sampled line exceeds
" this number, then pencil assumes soft line wrapping
let g:pencil#softDetectThreshold = 130
en
if !exists('g:pencil#mode_indicators')
" used to set PencilMode() for statusline
if s:unicode_enabled()
let g:pencil#mode_indicators = {'hard': '␍', 'auto': 'ª', 'soft': '⤸', 'off': '',}
el
let g:pencil#mode_indicators = {'hard': 'H', 'auto': 'A', 'soft': 'S', 'off': '',}
en
en
" Commands
com -nargs=0 Pencil call pencil#init({'wrap': 'on' })
com -nargs=0 PencilOff call pencil#init({'wrap': 'off' })
com -nargs=0 NoPencil call pencil#init({'wrap': 'off' })
com -nargs=0 HardPencil call pencil#init({'wrap': 'hard'})
com -nargs=0 PencilHard call pencil#init({'wrap': 'hard'})
com -nargs=0 SoftPencil call pencil#init({'wrap': 'soft'})
com -nargs=0 PencilSoft call pencil#init({'wrap': 'soft'})
com -nargs=0 PencilToggle call pencil#init({'wrap': 'toggle'})
com -nargs=0 TogglePencil call pencil#init({'wrap': 'toggle'})
com -nargs=0 PFormat call pencil#setAutoFormat(1)
com -nargs=0 PFormatOff call pencil#setAutoFormat(0)
com -nargs=0 PFormatToggle call pencil#setAutoFormat(-1)
" NOTE: legacy commands have been disabled by default as of 31-Dec-15
if !exists('g:pencil#legacyCommands')
let g:pencil#legacyCommands = 0
en
if g:pencil#legacyCommands
com -nargs=0 DropPencil call pencil#init({'wrap': 'off' })
com -nargs=0 AutoPencil call pencil#setAutoFormat(1)
com -nargs=0 ManualPencil call pencil#setAutoFormat(0)
com -nargs=0 ShiftPencil call pencil#setAutoFormat(-1)
en
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:ts=2:sw=2:sts=2

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 KiB

View File

@ -0,0 +1,7 @@
Captured with Quicktime.
Processed with:
$ ffmpeg -i four.mov -s 700x242 -pix_fmt rgb24 -vf "lutyuv=y=val*1.3" -r 10 -f gif - | \
gifsicle --optimize=3 --delay=3 > out.gif

View File

@ -0,0 +1 @@
See the [contribution guidelines for pathogen.vim](https://github.com/tpope/vim-pathogen/blob/master/CONTRIBUTING.markdown).

View File

@ -0,0 +1,48 @@
# sleuth.vim
This plugin automatically adjusts `'shiftwidth'` and `'expandtab'`
heuristically based on the current file, or, in the case the current file is
new, blank, or otherwise insufficient, by looking at other files of the same
type in the current and parent directories. In lieu of adjusting
`'softtabstop'`, `'smarttab'` is enabled.
Compare to [DetectIndent][]. I wrote this because I wanted something fully
automatic. My goal is that by installing this plugin, you can remove all
indenting related configuration from your vimrc.
[DetectIndent]: http://www.vim.org/scripts/script.php?script_id=1171
## Installation
If you don't have a preferred installation method, I recommend
installing [pathogen.vim](https://github.com/tpope/vim-pathogen), and
then simply copy and paste:
cd ~/.vim/bundle
git clone git://github.com/tpope/vim-sleuth.git
## Notes
* Searching for other files of the same type continues up the directory
hierarchy until a match is found. This means, for example, the indent for
the first file in a brand new Ruby project might very well be derived from
your `.irbrc`. I consider this a feature.
* If your file is consistently indented with hard tabs, `'shiftwidth'` will be
set to your `'tabstop'`. Otherwise, a `'tabstop'` of 8 is enforced.
* The algorithm is rolled from scratch, fairly simplistic, and only lightly
battle tested. It's probably not (yet) as good as [DetectIndent][].
Let me know what it fails on for you.
## Self-Promotion
Like sleuth.vim? Follow the repository on
[GitHub](https://github.com/tpope/vim-sleuth) and vote for it on
[vim.org](http://www.vim.org/scripts/script.php?script_id=4375). And if
you're feeling especially charitable, follow [tpope](http://tpo.pe/) on
[Twitter](http://twitter.com/tpope) and
[GitHub](https://github.com/tpope).
## License
Copyright © Tim Pope. Distributed under the same terms as Vim itself.
See `:help license`.

View File

@ -0,0 +1,17 @@
*sleuth.txt* Heuristically set buffer options
Author: Tim Pope <http://tpo.pe/>
Repo: https://github.com/tpope/vim-sleuth
License: Same terms as Vim itself (see |license|)
This plugin is only available if 'compatible' is not set.
SUMMARY *sleuth*
This plugin automatically adjusts 'shiftwidth' and 'expandtab' heuristically
based on the current file, or, in the case the current file is new, blank, or
otherwise insufficient, by looking at other files of the same type in the
current and parent directories. In lieu of adjusting 'softtabstop',
'smarttab' is enabled.
vim:tw=78:et:ft=help:norl:

View File

@ -0,0 +1,171 @@
" sleuth.vim - Heuristically set buffer options
" Maintainer: Tim Pope <http://tpo.pe/>
" Version: 1.1
" GetLatestVimScripts: 4375 1 :AutoInstall: sleuth.vim
if exists("g:loaded_sleuth") || v:version < 700 || &cp
finish
endif
let g:loaded_sleuth = 1
function! s:guess(lines) abort
let options = {}
let heuristics = {'spaces': 0, 'hard': 0, 'soft': 0}
let ccomment = 0
let podcomment = 0
let triplequote = 0
let backtick = 0
for line in a:lines
if line =~# '^\s*$'
continue
endif
if line =~# '^\s*/\*'
let ccomment = 1
endif
if ccomment
if line =~# '\*/'
let ccomment = 0
endif
continue
endif
if line =~# '^=\w'
let podcomment = 1
endif
if podcomment
if line =~# '^=\%(end\|cut\)\>'
let podcomment = 0
endif
continue
endif
if triplequote
if line =~# '^[^"]*"""[^"]*$'
let triplequote = 0
endif
continue
elseif line =~# '^[^"]*"""[^"]*$'
let triplequote = 1
endif
if backtick
if line =~# '^[^`]*`[^`]*$'
let backtick = 0
endif
continue
elseif line =~# '^[^`]*`[^`]*$'
let backtick = 1
endif
let softtab = repeat(' ', 8)
if line =~# '^\t'
let heuristics.hard += 1
elseif line =~# '^' . softtab
let heuristics.soft += 1
endif
if line =~# '^ '
let heuristics.spaces += 1
endif
let indent = len(matchstr(substitute(line, '\t', softtab, 'g'), '^ *'))
if indent > 1 && get(options, 'shiftwidth', 99) > indent
let options.shiftwidth = indent
endif
endfor
if heuristics.hard && !heuristics.spaces
return {'expandtab': 0, 'shiftwidth': &tabstop}
elseif heuristics.soft != heuristics.hard
let options.expandtab = heuristics.soft > heuristics.hard
if heuristics.hard
let options.tabstop = 8
endif
endif
return options
endfunction
function! s:patterns_for(type) abort
if a:type ==# ''
return []
endif
if !exists('s:patterns')
redir => capture
silent autocmd BufRead
redir END
let patterns = {
\ 'c': ['*.c'],
\ 'html': ['*.html'],
\ 'sh': ['*.sh'],
\ }
let setfpattern = '\s\+\%(setf\%[iletype]\s\+\|set\%[local]\s\+\%(ft\|filetype\)=\|call SetFileTypeSH(["'']\%(ba\|k\)\=\%(sh\)\@=\)'
for line in split(capture, "\n")
let match = matchlist(line, '^\s*\(\S\+\)\='.setfpattern.'\(\w\+\)')
if !empty(match)
call extend(patterns, {match[2]: []}, 'keep')
call extend(patterns[match[2]], [match[1] ==# '' ? last : match[1]])
endif
let last = matchstr(line, '\S.*')
endfor
let s:patterns = patterns
endif
return copy(get(s:patterns, a:type, []))
endfunction
function! s:apply_if_ready(options) abort
if !has_key(a:options, 'expandtab') || !has_key(a:options, 'shiftwidth')
return 0
else
for [option, value] in items(a:options)
call setbufvar('', '&'.option, value)
endfor
return 1
endif
endfunction
function! s:detect() abort
if &modifiable == 0
return
endif
let options = s:guess(getline(1, 1024))
if s:apply_if_ready(options)
return
endif
let patterns = s:patterns_for(&filetype)
call filter(patterns, 'v:val !~# "/"')
let dir = expand('%:p:h')
while isdirectory(dir) && dir !=# fnamemodify(dir, ':h')
for pattern in patterns
for neighbor in split(glob(dir.'/'.pattern), "\n")[0:7]
if neighbor !=# expand('%:p') && filereadable(neighbor)
call extend(options, s:guess(readfile(neighbor, '', 256)), 'keep')
endif
if s:apply_if_ready(options)
let b:sleuth_culprit = neighbor
return
endif
endfor
endfor
let dir = fnamemodify(dir, ':h')
endwhile
if has_key(options, 'shiftwidth')
return s:apply_if_ready(extend({'expandtab': 1}, options))
endif
endfunction
setglobal smarttab
if !exists('g:did_indent_on')
filetype indent on
endif
augroup sleuth
autocmd!
autocmd FileType * call s:detect()
augroup END
" vim:set et sw=2:

1
vim/.vim/bundle/slime Submodule

@ -0,0 +1 @@
Subproject commit 7d0374935e7bd4a3a3c2c5d7ac7d70c2650b89ae

View File

@ -0,0 +1,24 @@
" buf_identifier is either a buf_nr or a filename
" If any window shows the buffer move to the buffer
" If not show it in current window (by c-w s c^ you can always
" reshow the last buffer
"
" Example: buf_utils#GotoBuf("/tmp/tfile.txt", {'create': 1})
" returns: The command which was used to switch to the buffer
fun! buf_utils#GotoBuf(buf_identifier, opts)
let buf_nr = bufnr(a:buf_identifier)
if buf_nr == -1 && ( get(a:opts, 'create', 0) || has_key(a:opts, 'create_cmd'))
exec get(a:opts,'create_cmd','e').' '.fnameescape(a:buf_identifier)
return "e"
else
let win_nr = bufwinnr(buf_nr)
if win_nr == -1
exec 'b '.buf_nr
return "b"
else
exec win_nr.'wincmd w'
return "w"
endif
wincmd w"
endif
endf

View File

@ -0,0 +1,104 @@
" cached_file_contents.vim
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2010-01-03.
" @Revision: 0.3.0
"exec vam#DefineAndBind('s:c','g:cache_dir_options','{}')
if !exists('g:cache_dir_options') | let g:cache_dir_options = {} | endif | let s:c = g:cache_dir_options
let s:c['cache_dir'] = get(s:c, 'cache_dir', expand('$HOME').'/.vim-cache')
let s:c['scanned_files'] = get(s:c, 'scanned_files', {})
let s:scanned_files = s:c['scanned_files']
let s:define_cache_file = "let this_dir = s:c['cache_dir'].'/cached-file-contents' | let cache_file = expand(this_dir.'/'.substitute(string([func_as_string, a:file]),'[[\\]{}:/\\,''\"# ]\\+','_','g'))"
" read a file, run function to extract contents and cache the result returned
" by that function in memory. Optionally the result can be cached on disk as
" because VimL can be slow!
"
" file : the file to be read
" func: { 'func': function which will be called by funcref#Call
" , 'version' : if this version changes cache will be invalidate automatically
" , 'ftime_check': optional, default 1. if set to 0 cache isn't updated when file changes and file is in cache
" }
"
" default: what to return if file doesn't exist
" think twice about adding lines. This function is called many times.
function! cached_file_contents#CachedFileContents(file, func, ...) abort
let ignore_ftime = a:0 > 0 ? a:1 : 0
" using string for default so that is evaluated when needed only
let use_file_cache = get(a:func, 'use_file_cache', 0)
" simple kind of normalization. necessary when using file caching
" this seems to be slower:
" let file = fnamemodify(a:file, ':p') " simple kind of normalization. necessary when using file caching
" / = assume its an absolute path
" let file = a:file[0] == '/' ? a:file : expand(a:file, ':p')
let file = a:file[0] == '/' ? a:file : fnamemodify(a:file, ':p') " simple kind of normalization. necessary when using file caching
let func_as_string = string(a:func['func'])
if (!has_key(s:scanned_files, func_as_string))
let s:scanned_files[func_as_string] = {}
endif
let dict = s:scanned_files[func_as_string]
if use_file_cache && !has_key(dict, a:file)
exec s:define_cache_file
if filereadable(cache_file)
let dict[file] = eval(readfile(cache_file,'b')[0])
endif
endif
if has_key(dict, a:file)
let d = dict[a:file]
if use_file_cache
\ && (ignore_ftime || getftime(a:file) <= d['ftime'])
\ && d['version'] == a:func['version']
return dict[a:file]['scan_result']
endif
endif
let scan_result = funcref#Call(a:func['func'], [a:file] )
let dict[a:file] = {"ftime": getftime(a:file), 'version': a:func['version'], "scan_result": scan_result }
if use_file_cache
if !exists('cache_file') | exec s:define_cache_file | endif
if !isdirectory(this_dir) | call mkdir(this_dir,'p',0700) | endif
call writefile([string(dict[a:file])], cache_file)
endif
return scan_result
endfunction
fun! cached_file_contents#ClearScanCache()
let s:c['scanned_files'] = {}
" Don't run rm -fr. Ask user to run it. It cache_dir may have been set to
" $HOME ! (should nevere be the case but who knows
echoe "run manually in your shell: rm -fr ".shellescape(s:c['cache_dir'])."/*"
endf
fun! cached_file_contents#Test()
" usually you use a global option so that the function can be reused
let my_interpreting_func = {'func' : funcref#Function('return len(readfile(ARGS[0]))'), 'version': 2, 'use_file_cache':1}
let my_interpreting_func2 = {'func' : funcref#Function('return ARGS[0]') , 'version': 2, 'use_file_cache':1}
let tmp = tempname()
call writefile(['some text','2nd line'], tmp)
let r = [ cached_file_contents#CachedFileContents(tmp, my_interpreting_func)
\ , cached_file_contents#CachedFileContents(tmp, my_interpreting_func2) ]
if r != [2, tmp]
throw "test failed 1, got ".string(r)
endif
unlet r
sleep 3
" now let's change contents
call writefile(['some text','2nd line','3rd line'], tmp)
let r = cached_file_contents#CachedFileContents(tmp, my_interpreting_func)
if 3 != r
throw "test failed 2, got ".string(r)
endif
echo "test passed"
endf

View File

@ -0,0 +1,12 @@
" in sh/bash you can type export to get a list of environment variables
" This function assigns those env vars to Vim.
" Does not delete env vars yet
" Example: env_reload#ReloadEnv(system("sh -c 'export'")
fun! env_reload#ReloadEnv(bash_export_command_output)
for i in split(a:bash_export_command_output,"\n")
let m = matchlist(i, 'export \([^=]\+\)="\(.*\)"')
if empty(m) | continue | endif
" don't care about quoted values right now.
exec 'let $'.m[1].'='.string(m[2])
endfor
endf

View File

@ -0,0 +1,95 @@
" funcref.vim
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2010-01-03.
" @Revision: 0.1.0
" documentation see doc/funcref.txt
" usage:
" funcref#Function("filename#Function")
" optionally pass arguments:
" funcref#Function("filename#Function",{'args': [2]})
" optionally define self:
" funcref#Function("filename#Function",{'self': object})
function! funcref#Function(name,...)
let d = a:0 > 0 ? a:1 : {}
let d['faked_function_reference'] = a:name
return d
endfunction
" args : same as used for call(f,[args], self)
" f must be either
" - a string which can be evaled (use "return 'value'" to return a value)
" - a Vim function reference created by function('..')
" - a faked function reference created by funcref#Function(..)
"
" the last "self" argument can be overriden by the function reference
" You can pass arguments in a closure like style
function! funcref#Call(...)
let args = copy(a:000)
" add parameters:
if (len(args) < 2)
call add(args, [])
endif
let isDict = type(args[0]) == type({})
" prepend parameters which were passed by faked function reference:
if isDict && has_key(args[0], 'args')
let args[1] = args[0]['args']+args[1]
endif
" always pass self. this way you can call functions from dictionaries not
" refering to self
if (len(args) < 3)
call add(args, {})
endif
" the funcref overrides self:
if isDict && has_key(args[0], 'self')
let args[2] = args[0]['self']
endif
if type(a:1) == 2
" funcref: function must have been laoded
return call(function('call'), args)
elseif isDict && has_key(args[0], 'faked_function_reference')
let Fun = args[0]['faked_function_reference']
if type(Fun) == type('')
\ && (Fun[:len('return ')-1] == 'return '
\ || Fun[:len('call ')-1] == 'call '
\ || Fun[:len('if ')-1] == 'if '
\ || Fun[:len('let ')-1] == 'let '
\ || Fun[:len('echo ')-1] == 'echo '
\ || Fun[:len('exec ')-1] == 'exec '
\ || Fun[:len('debug ')-1] == 'debug ')
" it doesn't make sense to list all vim commands here
" So if you want to execute another action consider using
" funcref#Function('exec '.string('aw')) or such
" function is a String, call exec
let ARGS = args[1]
let SELF = args[2]
exec Fun
else
" pseudo function, let's load it..
if type(Fun) == 1
if !exists('*'.Fun)
" lazily load function
let file = substitute(substitute(Fun,'#[^#]*$','',''),'#','/','g')
exec 'runtime /autoload/'.file.'.vim'
endif
let Fun2 = function(Fun)
else
let Fun2 = Fun
endif
let args[0] = Fun
return call(function('call'), args)
endif
else
" no function, return the value
return args[0]
endif
endfunction

View File

@ -0,0 +1,27 @@
exec vam#DefineAndBind('s:c','g:glob_like', '{}')
" ignore vcs stuff, Don't think you want those..
let s:c['regex_ignore_directory'] = '\<\%([_.]darcs\|\.git\|.svn\|.hg\|.cvs\|.bzr\)\>'
let s:c['glob_cache'] = get(s:c, 'glob_cache', {})
let s:glob_cache = s:c['glob_cache']
fun! glob#Glob(pattern, ...)
let pattern = a:pattern
if pattern[0] == '~'
let pattern = $HOME.pattern[1:]
endif
let opts = a:0 > 0 ? a:1 : {}
" never cache current directory. You're very likely to edit files in it.
let c = getcwd()
let cachable = get(opts, 'cachable', 0) && pattern[:len(c)-1] != c
if cachable && has_key(s:glob_cache, pattern)
return s:glob_cache[pattern]
endif
" FIXME: don't recurse into \.git directory (thus reimplement glob in vimL!)
let r = filter(split(glob(pattern),"\n"),'v:val !~ '.string(s:c['regex_ignore_directory']))
if cachable | let s:glob_cache[pattern] = r | endif
return r
endf

View File

@ -0,0 +1,19 @@
" vim suffers:
exec vam#DefineAndBind('s:c','g:vim_tiny_cmd', '{}')
fun! tiny_cmd#Put(a)
let new = get(s:c,'next',0) +1
let s:c['next'] = new
let s:c[new] = a:a
return new
endf
fun! tiny_cmd#Get(nr)
return s:c[a:nr]
endf
" Get and remove item
fun! tiny_cmd#Pop(nr)
let r = s:c[a:nr] | unlet s:c[a:nr] | return r
endf

View File

@ -0,0 +1,103 @@
" old code
augroup TOVLWrite
augroup end
" =========== scratch buffer =========================================
" a scratch buffer is a temporary buffer where the user can enter some text
" It can be used to get commit messages, edit configuration options and so on
function! tovl#scratch_buffer#KeepIntactLineNr()
let i = 0
while getline(i)!= b:keepIntact && i < line('$')
let i = i+1
endwhile
if i > line('$')
return -1
else
return i
endif
endfunction
" opens a buffer and runs an action when the buffer is written
" keys:
" name : the name of the buffer
" onWrite : will be called on write
" onWrite is responsible for setlocal nomodified to indicate that
" saving has been successful
" help : callback returning additional information lines
" getContent : callback returning lines
" cmds : extra commands to be run (optional)
" (maybe you prefer adding them the default way afer the
" ScratchBuffer call. They'll be rerun on GetContents
" sp_cmd : the command to use to create the new buffer. Defaults to :e
" buftype : ...
" modifiable : 1 / 0 defaults to 1
function! tovl#scratch_buffer#ScratchBuffer(opts)
let a:opts['name'] = get(a:opts,'name', 'strach_buffer_without_name')
exec get(a:opts, 'sp_cmd', 'e').' '.escape(a:opts['name'],' ')
let b:settings = a:opts
let b:settings['modifiable'] = get(a:opts,'modifiable', 1)
setlocal buftype=acwrite
command! -buffer -nargs=0 Help call tovl#scratch_buffer#Help()
" setup write notification
au TOVLWrite BufWriteCmd <buffer> call tovl#scratch_buffer#Write()
if has_key(a:opts,'getContent')
command! -buffer -nargs=0 GetContents call tovl#scratch_buffer#GetContents()
GetContents
if !b:settings['modifiable']
setlocal nomodifiable
endif
endif
"let u=&undolevels
"setlocal undolevels=-1
"exec 'setlocal undolevels='.u
" mark buffer as not modified
setlocal nomodified
au BufReadCmd <buffer> GetContents
" run addittional commands
for cmd in get(a:opts,'cmds',[])
exec cmd
endfor
silent echo get(a:opts,'echo_help', "type :Help for help")
endfunction
" =========== utility functions ======================================
function! tovl#scratch_buffer#Write()
if has_key(b:settings, 'onWrite')
call funcref#Call(b:settings['onWrite'])
else
echo "don't know how to write. Option hasn't been passed"
endif
endfunction
function! tovl#scratch_buffer#GetContents()
setlocal modifiable
" empty buffer
%g!//d
call append(0, funcref#Call(b:settings['getContent']))
if !b:settings['modifiable']
setlocal nomodifiable
endif
for cmd in get(b:settings,'cmds',[])
exec cmd
endfor
endfunction
function! tovl#scratch_buffer#Help()
let help = ["use :e! to reload contents, ZZ or :w(q) to write and quit"
\ ,""
\ ,"Help for this scratch buffer:"
\ ,"=======================================================","",""]
\ + funcref#Call(get(b:settings, 'help', []))
call tovl#scratch_buffer#ScratchBuffer({
\ 'name' : "return Help of ".b:settings['name'],
\ 'getContent' : help
\ })
endfunction

View File

@ -0,0 +1,473 @@
" OLD CODE !
" I should contribute the multiple filter feature to tlib
" filter list displays a list of items
" you can white / black filter them by regular expressions (similar to the
" tlib TToC command
" However you can edit the filters afterwards and select the cols which should
" be shown
fun! tovl#ui#filter_list#ListTest()
call tovl#ui#filter_list#ListView({
\ 'aligned' : 1,
\ 'Continuation' : funcref#Function('echo string(ARGS[0])'),
\ 'items' : [ {"aa" : "a\nAAAAAAAAAAA", 'bb' : "bbbbbbbbbbbbb\nB" },
\ {"aa" : "2a\n2AAAAAAAAAAAA", "bb" : "2 bbbbbbbbbbbbb\n2B"},
\ {"aa" : "XXX", "bb" : "YY"} ],
\ })
endfun
fun! s:Intersection(a, b)
return filter(copy(a:a), 'index(a:b, v:val) >= 0')
endf
fun! tovl#ui#filter_list#ListTestGotoLineCurrentBuf()
let nr=1
let lines = []
for l in getline(0,line('$'))
call add(lines, {'nr': nr, 'line' :l})
let nr = nr +1
endfor
call tovl#ui#filter_list#ListView({
\ 'aligned' : 0,
\ 'keys' : ['nr','line'],
\ 'number' : 1,
\ 'selectByIdOrFilter' : 1,
\ 'Continuation' : funcref#Function('exec ARGS[0]["nr"]'),
\ 'items' : lines,
\ })
endfun
" opens a new filtered list
" keys of opts parameters:
" Continuation: This function will be called with the selected items
" items: { key : (string or dict) }
" items willl be modified. use copy(youritems) as argument to prevent
" this. An item is either a string or a dict
" (eg {'file' : .., 'line': ... , 'msg' : .. )
" keys: list of keys to be shown (optional)
" filter: list of inital filters which must be applied
" contains [ { filter: .. , keep : .. }, ] see FilterItems() below
" aligned: default 0
" sp_cmd: the command to be used to create the new buffer (default ':e')
" init : 0 / 1 (default 1): wether to show the view right now
" number: 0 /1 (default 1): number items ?
" selectByIdOrFilter: 1: start in getchar() loop so that the user can select
" the item even faster
" auto: only do this if all items fit on screen
" (recommend)
" cmds: extra cmds to be run
" cursorAt : at which item to put the cursor?
"
" If you don't like the default view you can override UpdateDisplay
"
" Usage examples of this list control:
" - db results
" - replacement of the quickfix window
" - select a buffer etc
fun! tovl#ui#filter_list#ListView(opts)
" ActivateAddons theonevimlib
let d = {}
let d.items = a:opts.items
let d.cursorAt = get(a:opts, 'cursorAt', 0)
let d.aligned = get(a:opts, 'aligned', 0)
let d.sep = ' '
let d.filter = get(a:opts, 'filter', [])
" using sp because of bd! (FIXME)
let d.sp_cmd = get(a:opts, 'sp_cmd', 'sp')
let d.allKeys = {}
let d.closeOnContinuation = get(a:opts,'closeOnContinuation',1)
" don't recommend OnSingleMatch, use OnSingleMatchCR instead
let d.continueOnSingleMatch = get(a:opts, 'continueOnSingleMatch',0)
let d.continueOnSingleMatchCR = get(a:opts, 'continueOnSingleMatchCR',1)
let d.selectByIdOrFilter = get(a:opts, 'selectByIdOrFilter', 0)
let d.linesToItems = {}
let d.number = get(a:opts, 'number', 1)
let d.cmds = get(a:opts, 'cmds', [])
let d.syn_cmds = get(a:opts, 'syn_cmds', [])
if has_key(a:opts,'keys') | let d.keys = a:opts.keys | endif
if has_key(a:opts,'Continuation') | let d.Continuation = a:opts.Continuation | endif
" cache already filtered items in case we want to view really long results
" contains [ { filter : { regex: .. , keep : .. } , items : .. , cursorAt :},
" { filter : { ... } , items: .. , cursorAt : }
let d.cached = []
" id of buffer
let d.buffer = -1
let d.modeText = ''
fun d.HelpText()
return [ "you've entered the the help of the powerful filtered view buffer",
\ "",
\ "type f to start filtering items by regex",
\ "type F to start dropping items by regex",
\ "k / K will ask you for the key to apply the filter to first",
\ "apply the filter by <cr> and press <cr> again to select item",
\ "",
\ "use :ShowAppliedFilters to list active filters",
\ "use :ToggleAlignment to toggle alignment",
\ "",
\ "TODO: Implement sorting, implement interface to change keys (displayed columns)"
\ ]
endfun
" create new scratch buffer
" preprocess items calculating line count and maxwidth for all items
fun d.NewBufferAndInit()
let self.bufferId = bufnr(bufname('%'))
for idx in range(0,len(self.items)-1)
if type(self.items[idx]) != 4
" no dict yet, make it one
let self.items[idx] = {'string_line' : self.items[idx]}
endif
let new = {}
for [k,v] in items(self.items[idx])
let lines = split(v,"\n")
let self.items[idx][k] = { 'text' : v, 'rows' : len(lines), 'cols' : max(map(copy(lines),'len(v:val)')), 'lines' : lines }
let self.allKeys[k] = 1
unlet k v
endfor
endfor
call tovl#scratch_buffer#ScratchBuffer({
\ 'help' : funcref#Function(self.HelpText,{ 'self' : self }),
\ 'sp_cmd' : self.sp_cmd,
\ 'cmds' : self.cmds
\ })
" I assume we have some kind of formatting anyway. Thus breaking lines is bad!
set nowrap
setlocal cursorline
let b:filtered_view = self
command! -buffer -nargs=0 ToggleAlignment call b:filtered_view.ToggleAlignment()
command! -buffer -nargs=0 ShowAppliedFilters call b:filtered_view.ShowAppliedFilters()
command! -buffer -nargs=0 RemoveFilters call b:filtered_view.RemoveFilters()
noremap <buffer> f :call b:filtered_view.FilterFromKeyboard(1,'')<cr>
" noremap <buffer> f :call b:filtered_view.FilterFromKeyboard(1)<cr>
noremap <buffer> F :call b:filtered_view.FilterFromKeyboard(0,'')<cr>
if has_key(self,'Continuation')
nnoremap <buffer> <cr> :call b:filtered_view.Continue()<cr>
endif
"noremap <buffer> k
"noremap <buffer> K
let [items, cursorAt] = self.FilteredItems()
" len(items) is an approximation because one item can have multiple
" lines.. However adding the lines first to check takes too much time
if self.selectByIdOrFilter == 1 || (self.selectByIdOrFilter == 'auto' && winheight('%') > len(items) )
call self.SelectByIdOrFilter()
else
" user should choose how to proceed
call self.UpdateDisplay()
endif
endfun
" user interface
fun d.ToggleAlignment()
let self.aligned = !self.aligned
call self.UpdateDisplay()
endfun
fun d.ShowAppliedFilters()
for i in self.filter | echo string(i) | endfor
endfun
fun d.RemoveFilters()
let self.filter = []
call self.UpdateDisplay()
endfun
fun d.Continue()
let item = self.CurrentItem()
call self.DoContinue(item)
endfun
fun d.DoContinue(v)
if self.closeOnContinuation | bw! | endif
call funcref#Call(self.Continuation,[a:v])
endfun
fun d.MapToOriginal(v)
if has_key(a:v, 'string_line')
return a:v.string_line.text
else
let d = {}
for [k,v] in items(a:v)
let d[k] = v.text
unlet k v
endfor
return d
endif
endfun
fun d.CurrentItem()
let idx=line('.')-len(self.headerLines)
while idx >= 0
if has_key(self.linesToItems, idx)
return self.MapToOriginal(self.FilteredItems()[0][self.linesToItems[idx]])
else
let idx = idx -1
endif
endwhile
throw "internal error, couldn't determine selected item!"
endfun
" updates the filter cache and returns the final filtered items
fun d.FilteredItems()
" update cache
let idx = 0
let [items, cursorAt] = [self.items, self.cursorAt]
for idx in range(0, len(self.filter)-1)
if idx +1 > len(self.cached) || self.cached[idx]['filter'] != self.filter[idx]
let self.cached = self.cached[:idx-1]
let [items, cursorAt] = self.FilterItem(copy(items), self.filter[idx], cursorAt)
call add(self.cached, { 'cursorAt' : cursorAt, 'items' : items, 'filter' : self.filter[idx]})
else
let ci = self.cached[idx]
let [items, cursorAt] = [ci['items'], ci['cursorAt']]
endif
endfor
return [items, cursorAt]
endfun
" calling this will return a set of lines which are expected to be the new
" buffer contents. The self.linesToItems dict is updated
fun d.UpdateDisplay()
if empty(self.filter)
let self.statusline= 'no filter applied, :Help for help'
else
let self.statusline = len(self.filter).' '.string(self.filter[-1])
endif
let self.linesToItems = {}
let [items, cursorAt] = self.FilteredItems()
"let num_width = printf('%.0f', trunc(log10(len(items))+1))
let num_width = 4
if self.aligned
" get column width.. (probably will not work with unicde characters.. I
" don't have a better solution)
let maxlens={}
for i in items
for [k,v] in items(i)
if get(maxlens,k,0) < v.cols
let maxlens[k] = v.cols
endif
endfor
endfor
endif
" format lines
let self.headerLines = [self.modeText]
let lines = copy(self.headerLines)
let lines_count = 0
if self.number
let fmt_startA = '%'.num_width.'s)'
let fmt_startB = '%'.num_width.'s'
else
let fmt_startA = '' | let fmt_startB = ''
endif
let cursorAtLine = 1 " sane default
for idx in range(0,len(items)-1)
let self.linesToItems[lines_count + 1] = idx
let i = items[idx]
let keys = has_key(self,'keys')
\ ? s:Intersection(self.keys, keys(i))
\ : keys(i)
let fmt = ''
let args = [i]
let cols = []
for k in keys
let fmt .= self.sep.'%-'.(self.aligned ? maxlens[k] : i[k]['cols']).'s'
call add(cols, i[k])
endfor
for row in range(0, max([1] + map(copy(cols),'v:val["rows"]'))-1)
let fmt_args = row == 0 ? [fmt_startA.fmt] : [fmt_startB.fmt]
if self.number
call add(fmt_args, row == 0 ? idx : '')
endif
for c in cols
call add(fmt_args, c.rows <= row ? '' : c.lines[row])
endfor
call add(lines, call('printf', fmt_args))
let lines_count += 1
endfor
if idx == cursorAt
let cursorAtLine = lines_count
endif
endfor
" update stauts line to show last applied filter
" disabled cause it causes trouble on :wincmd w
" setlocal statusline=%!b:filtered_view.statusline
" syntax
syn clear
for s in self.syn_cmds | exec s | endfor
let id = 0
" highlight filter regex in buffer as well
let syn_ids = [ 'Underlined', 'Todo', 'Error', 'Type', 'Statement' ]
for f in self.filter
if !f.keep || !has_key(f, 'regex') | continue | endif
if f.regex != ''
try
exec 'syn match '.syn_ids[id % len(syn_ids)].' '.string(f.regex)
catch /.*/
" ignore errors such as \ without following characters. Thus just
" ignore and wait for the next character
endtry
endif
let id = id +1
endfor
if len(lines) > winheight('%')
call extend(lines, self.headerLines)
endif
normal ggdG
call append(0, lines)
" place cursor
exec (cursorAtLine+1)
" move cursor into the middle of the window
normal zz
endf
" filter = keys :
" filter = string to be executed containing Val
" keep = 1 keep on match
" = 0 drop on match
" key (optional)
" cursorAt: at which item to put the cursor
" if that item is deleted it will be placed at the item above
" optional: key of dict if dict
fun d.FilterItem(items, filter, cursorAt)
let filter = 'Val =~ '.string(a:filter.regex)
let keep = a:filter.keep
let cursorAt = a:cursorAt
for idx in reverse(range(0, len(a:items)-1))
let i = a:items[idx]
if has_key(a:filter,'key')
let key = a:filter.key
if has_key(i, key)
" key given, only filter by this column
let Val = i[key]['text']
exec 'let any = '.filter
else
let any = 0
endif
else
let any = 0
" no key given, try all
for x in values(i)
let Val = x['text']
exec 'let any = '.filter
if any | break | endif
endfor
endif
if any != keep
call remove(a:items, idx)
if idx <= cursorAt
let cursorAt = cursorAt -1
endif
endif
endfor
return [a:items, cursorAt]
endfun
" if the user enters a number select by index else start filtering..
fun d.SelectByIdOrFilter()
let idx=''
let items = self.FilteredItems()[0]
try
let self.modeText = '[0-9]* : select by index| <esc>: escape getchar() loop, any char: start filtering'
call self.UpdateDisplay() | redraw
while 1
let c=getchar()
if index([13,10],c) >= 0
return self.DoContinue(self.MapToOriginal(items[idx]))
elseif index([27], c) >=0
" esc, abort
return
else
if type(c) == 0
let c = nr2char(c)
endif
if c == "\<bs>" || index(map(range(0,10),'v:val.""'),c) >= 0
if c == "\<bs>"
let idx = idx[:-2]
else
let idx .= c
endif
if idx < len(items) && idx.'0' > len(items) || idx == 0 && len(items) < 10
" only match
return self.DoContinue(self.MapToOriginal(items[idx]))
endif
else
return self.FilterFromKeyboard(1,c)
endif
endif
endwhile
finally
let self.modeText = ''
endtry
endfun
" gets a regular expresion filter by keybaord and updates the display while
" you're typing. The regex ist shown in the statusline
fun d.FilterFromKeyboard(keep, start, ...)
let self.modeText = 'press ESC to exit getchar() loop'
call self.UpdateDisplay() | redraw
try
let key_text = a:0 > 0 ? 'key : '.a:1 : ''
let filter_bak = self.filter
let filter = copy(self.filter)
let start = a:start
let filter_new = ''
while 1
if start != ''
" use c= last char to force updating display etc
let filter_new = start[:-2]
let c = start[-1:]
let start = ''
else
let c=getchar()
endif
if index([13,10],c) >= 0
" c-j or return, accept new filter
let items = self.FilteredItems()
if len(items) == 1 && has_key(self, 'Continuation') && self.continueOnSingleMatchCR
call self.DoContinue(self.MapToOriginal(items[0]))
endif
return
elseif index([27], c) >=0
" esc, abort
let self.filter = filter_bak
call self.UpdateDisplay()
return
else
if type(c) == 0
let c = nr2char(c)
endif
if c == "\<bs>"
let filter_new = filter_new[:-2]
else
let filter_new .= c
endif
let d = {'keep' : a:keep, 'regex' : filter_new }
if a:0 > 0
let d['key'] = a:1
endif
let self.filter = copy(filter_bak)
call add(self.filter, d)
let items = self.FilteredItems()
if len(items) == 1 && has_key(self, 'Continuation') && self.continueOnSingleMatch
call self.DoContinue(self.MapToOriginal(items[0]))
return
endif
call self.UpdateDisplay() | redraw
endif
endwhile
finally
let self.modeText = ''
endtry
endfun
if get(a:opts,'init',1)
call d.NewBufferAndInit()
endif
endfun

View File

@ -0,0 +1,7 @@
*cached_file_contents* read contents of a file then cache extracted data
Author: Marc Weber, marco-oweber@gmx.de
-----------------------------------------------------------------------
HOWTO~
see cached_file_contents#Test()

View File

@ -0,0 +1,35 @@
*funcref* create lazier function references. Pass arguments to create closure
like function calls
Author: Marc Weber, marco-oweber@gmx.de
-----------------------------------------------------------------------
HOWTO~
Use *funcref#Function* to create a special dict called
*faked-function-reference* which can be called by *funcref#Call*
>
{ 'faked_function_reference': 'file#FuncName' }
< passing some arguments and / or self: >
{ 'faked_function_reference': 'MyFunc', 'args': [1,2], 'self' : { a object ] }
< You can also create lambda like functions which will be evaled: >
{ 'faked_function_reference': 'return ARGS[1]' }
REASONS ~
Creating a Vim funcref pointing to an autoload function will make Vim source
that file. This is not lazy enough. (Seems to be no longer true? Has this changed?)
A Vim function reference neither allows attaching arguments nor self.
Don't care about case of variables. Normally when using Vim function
references you have to use variable names starting with an upper case letter
(E704)
Example: ~
>
let f = funcref#Function('return ARGS[0].ARGS[1].SELF["key"]',{'args':[3], 'self':{'key': 'value'} })
echo funcref#Call(f, [2])
" prints "32value"
echo funcref#Call('no value')
<
echo funcref#Call(f, [2])

View File

@ -0,0 +1,18 @@
*tiny-cmd* make long commands short so that they hopefully no longer trigger "press Enter .. [ok]"
Author: Marc Weber, marco-oweber@gmx.de
-----------------------------------------------------------------------
HOWTO~
Problem: >
exec 'map <F2> :silent! let g:g="'.repeat('foobar ',200).'"<cr>'
Now run the mapping by pressing <F2> and you notice what I'm talking about
Solution (Example):
Example usage: >
let nr = tiny_cmd#Put('let g:g="'.repeat('foobar ',200).'"')
exec 'map <F2> :exec tiny_cmd#Get('.nr.')<cr>'
<
Use Pop instead of Get if you use this command once only

View File

@ -0,0 +1,9 @@
{
"name" : "vim-addon-mw-utils",
"version" : "0.0",
"author" : "Marc Weber <marco-oweber@gmx.de>",
"maintainer" : "Marc Weber <marco-oweber@gmx.de>",
"repository" : {"type": "git", "url": "git://github.com/MarcWeber/vim-addon-manager-known-repositories.git"},
"dependencies" : {},
"description" : "various utils such as caching interpreted contents of files or advanced glob like things"
}

View File

@ -0,0 +1,755 @@
0.1
Initial release
0.2
- More list convenience functions
- tlib#EditList()
- tlib#InputList(): properly handle duplicate items; it type contains
'i', the list index + 1 is returned, not the element
0.3
- tlib#InputList(): Show feedback in statusline instead of the echo area
- tlib#GetVar(), tlib#GetValue()
0.4
- tlib#InputList(): Up/Down keys wrap around list
- tlib#InputList(): FIX: Problem when reducing the filter & using AND
- tlib#InputList(): Made <a-numeric> work (can be configured via
- tlib#InputList(): special display_format: "filename"
- tlib#Object: experimental support for some kind of OOP
- tlib#World: Extracted some functions from tlib.vim to tlib/World.vim
- tlib#FileJoin(), tlib#FileSplit(), tlib#RelativeFilename()
- tlib#Let()
- tlib#EnsureDirectoryExists(dir)
- tlib#DirName(dir)
- tlib#DecodeURL(url), tlib#EncodeChar(char), tlib#EncodeURL(url)
- FIX: Problem when using shift-up/down with filtered lists
0.5
- tlib#InputList(): FIX: Selecting items in filtered view
- tlib#InputList(): <c-bs>: Remove last AND pattern from filter
0.6
- tlib#InputList(): Disabled <c-space> map
- tlib#InputList(): try to be smart about user itentions only if a
list's length is < g:tlib_sortprefs_threshold (default: 200)
- tlib#Object: Super() method
- tlib#MyRuntimeDir()
- tlib#GetCacheName(), tlib#CacheSave(), tlib#CacheGet()
- tlib#Args(), tlib#GetArg()
- FIX: tlib#InputList(): Display problem with first item
0.7
- tlib#InputList(): <c-z> ... Suspend/Resume input
- tlib#InputList(): <c-q> ... Input text on the command line (useful on
slow systems when working with very large lists)
- tlib#InputList(): AND-pattern starting with '!' will work as 'exclude
matches'
- tlib#InputList(): FIX <c-bs> pop OR-patterns properly
- tlib#InputList(): display_format == filename: don't add '/' to
directory names (avoid filesystem access)
0.8
- FIX: Return empty cache name for buffers that have no files attached to it
- Some re-arranging
0.9
- Re-arrangements & modularization (this means many function names have
changed, on the other hand only those functions are loaded that are
actually needed)
- tlib#input#List(): Added maps with m-modifiers for <c-q>, <c-z>, <c-a>
- tlib#input#List(): Make sure &fdm is manual
- tlib#input#List(): When exiting the list view, consume the next 5
characters in the queue (if any)
- tlib#input#EditList(): Now has cut, copy, paste functionality.
- Added documentation and examples
0.10
- tlib#input#List(): (v)split type of commands leave the original window
untouched (you may use <c-w> to replace its contents)
- tlib#file#With(): Check whether an existing buffer is loaded.
- Scratch related functions went to tlib/scratch.vim so that they are
accessible from other scripts.
- Configure the list window height via g:tlib_inputlist_pct (1..100%)
0.11
NEW:
- The :TLet command replaces :TLLet (which was removed)
- :TScratch[!] command (with ! don't split but use the whole window)
- tlib#rx#Escape(text, ?magic='m')
- tlib#buffer#GetList(?show_hidden=0)
- tlib#dir#CD(), tlib#dir#Push(), tlib#dir#Pop()
- tlib#input#ListW: A slightly remodeled version of tlib#input#List
that takes a World as second argument.
- Added some documentation doc/tlib.txt (most of it is automatically
compiled from the source files)
CHANGES:
- tlib#input#List(): The default keys for AND, NOT have changed to
be more Google-like (space, minus); the keys can be configured via
global variables.
IMPROVEMENTS:
- In file listings, indicate if a file is loaded, listed, modified
etc.
- tlib#input#List(): Highlight the filter pattern
- tlib#input#List(): <c-up/down> scrolls g:tlib_scroll_lines
(default=10) lines
FIXES:
- tlib#input#List(): Centering line, clear match, clear & restore
the search register
- tlib#input#List(): Ensure the window layout doesn't change (if the
number of windows hasn't changed)
- tlib#arg#Ex(): Don't escape backslashes by default
0.12
NEW:
- tlib/tab.vim
CHANGES:
- Renamed tlib#win#SetWin() to tlib#win#Set()
IMPROVEMENTS:
- tlib#input#List(): <left>, <right> keys work in some lists
- tlib#input#List(): If an index_table is provided this will be used
instead of the item's list index.
FIXES:
- tlib#input#List(): Problem with scrolling, when the list was
shorter than the window (eg when using a vertical window).
- tlib#cache#Filename(): Don't rewrite name as relative filename if
explicitly given as argument. Avoid double (back)slashes.
- TLet: simplified
0.13
CHANGES:
- Scratch: Set &fdc=0.
- The cache directory can be configured via g:tlib_cache
- Renamed tlib#buffer#SetBuffer() to tlib#buffer#Set().
FIXES:
- tlib#input#List(): Select the active item per mouse.
- TLet: simplified
0.14
NEW:
- tlib#buffer#InsertText()
CHANGES:
- tlib#win#[SG]etLayout(): Use a dictionnary, set &cmdheight.
FIXES:
- Wrong order with pre-defined filters.
0.15
NEW:
- tlib#string#TrimLeft(), tlib#string#TrimRight(), tlib#string#Strip()
- Progress bar
0.16
NEW:
- tlib#string#Printf1()
0.17
NEW:
- TBrowseOutput
- Some minor changes
0.18
NEW:
- tlib/time.vim
- g:tlib_inputlist_livesearch_threshold
CHANGES:
- tlib#input#ListD(), World: Don't redisplay the list while typing
new letters; calculate filter regexps only once before filtering the
list.
- World.vim: Minor changes to how filenames are handled.
0.19
NEW:
- tag.vim
FIX:
- dir.vim: Use plain dir name in tlib#dir#Ensure()
- tlib#input#List(): An initial filter argument creates [[filter]]
and not as before [[''], [filter]].
- tlib#input#List(): When type was "si" and the item was picked by
filter, the wrong index was returned.
- tlib#input#List(): Don't check if chars are typed when displaying
the list for the first time.
0.20
- The arguments of tlib#tag#Collect() have changed.
- tlib#input#List(): The view can be "suspended" on initial display.
- tlib#input#List(): Follow/trace cursor functionality
0.21
- tlib#buffer#InsertText(): Respect tabs and (experimental) formatoptions+=or
- tlib/syntax.vim: Syntax-related functions
0.22
- FIX: very magic mode for tlib#rx#Escape() (thanks A Politz)
- FIX: tlib#arg#Ex: escape "!"
0.23
- Respect the setting of g:tlib_inputlist_filename_indicators
- tlib#input#List(): Reset syntax on resume; option to make list window "sticky"
- tlib#agent#ToggleStickyList()
- Simplified tlib#url#Decode()
- tlib#arg#Ex(): use fnameescape() if available
0.24
- s:prototype.SetInitialFilter: accept list as argument
- Maintain buffer MRU if required
0.25
- NEW: tlib#notify#TrimMessage(): trim message to prevent "Press ENTER"
messages (contributed by Erik Falor)
- NEW: tlib#notify#Echo()
- FIX: World.CloseScratch(): Set window
- FIX: tlib#input#ListW(): Set initial_display = 1 on reset
0.26
- NEW: tlib#normal#WithRegister()
- FIX: Try not to change numbered registers
0.27
- FIX: Cosmetic bug, wrong packaging (thanks Nathan Neff)
- Meaning of World#filter_format changed; new World#filter_options
- Filtering didn't work as advertised
- tlib#string#Count()
0.28
- tlib#input#List():
-- Improved handling of sticky lists; <cr> and <Leftmouse> resume a
suspended list and immediately selects the item under the cursor
-- Experimental "seq" matching style: the conjunctions are sequentially
ordered, they are combined with "OR" (disjunctions), the regexp is
'magic', and "." is expanded to '.\{-}'
-- Experimental "cnfd" matching style: Same as cnf but with an "elastic"
dot "." that matches '\.\{-}'
-- Filtering acts as if &ic=1 && $sc=1
-- Weighting is done by the filter
- tlib#agent#Input(): Consume <esc> when aborting input()
- INCOMPATIBLE CHANGE: Changed eligible values of g:tlib_inputlist_match
to "cnf", "cnfd", "seq" and "fuzzy"
- NEW: tlib#buffer#KeepCursorPosition()
- tlib#buffer#InsertText(): Take care of the extra line when appending
text to an empty buffer.
0.29
- tlib#string#Strip(): Strip also control characters (newlines etc.)
- tlib#rx#Suffixes(): 'suffixes' as Regexp
- World#RestoreOrigin(): Don't assume &splitbelow
0.30
- World#RestoreOrigin(): Don't assume &splitright
0.31
- :TRequire command
-tlib#input#List: For i-type list views, make sure agents are called
with the base indices.
0.32
- tlib#agent#Exit: explicitly return empty value (as a consequence,
pressing <esc> when browsing an index-list, returns 0 and not "")
- tlib#signs
- tlib#input#List: set local statusline
0.33
- Don't reset statusline
- Don't use fnamemodify() to split filenames (for performance reasons)
- scratch: Set ft after setting up scratch options
- tlib#map#PumAccept(key)
0.34
- tlib#buffer#HighlightLine(line): call tlib#autocmdgroup#Init()
(reported by Sergey Khorev)
0.35
- tlib#input#EditList(): return the list if the user presses esc
0.36
- Display a message when the filter is for whatever reason invalid
- Removed tlib#paragraph#Delete()
- New: tlib#paragraph#Define(), tlib#textobjects#StandardParagraph()
- Try to speed up list display (a rewrite of World.DisplayList() etc. is
required)
0.37
- g:tlib_inputlist_livesearch_threshold defaults to 1000
- tlib#World: optional scratch_pos field
- tlib#input#List: By default <m-NUMBER> selects by number but NUMBER is
interpreted as string
- tlib#date
- TTimeCommand
0.38
- tlib#World#Resize: set winfix{height|width}
0.39
- g:tlib#cache#dont_purge
- tlib#vim#RestoreWindow()
- tlib#ballon#...()
0.40
- tlib#agent#ViewFile: Use split/sbuffer if nohidden && modified
- tlib#buffer#GetList(): order by "basename"
version: "0.41"
- World.UseScratch(): keepalt
- Really include balloon.vim
MD5 checksum: 3fcbc4f7556f5378d39622e62ab8f379
version: "0.42"
- tlib#input#List: <s-space> inserts a *-like wildcard (represented as "__")
- Check if a cache file cannot be created because a directory of the same name exists (display a message if so)
- tlib#cache#Filename: Removed check if a directory of the same name exists (due to inconsistent use)
- Minor improvements related to buffer handling (scratch_split)
- .gitignore
- docs (thanks to blueyed)
- There is no "edit" answer possibility.
- Fix first purge: do nothing if no timestamp file.
- g:tlib_pick_single_item
- Removed pick_single_item. Changed the default behavour when a list has only 1 item. See doc for g:tlib_pick_last_item.
- Updated help for tlib#input#List(); help_extra attribute
- EXPERIMENTAL: cache_var, restore_from_cache, on_leave properties; #Initialize(), #Leave()
- added tlib#cmd#BrowseOutputWithCallback function and :TBrowseScriptnames command
- tlib#cmd#BrowseOutputWithCallback function and :TBrowseScriptnames command documentation
- s:prototype.Initialize(): unlet self.cache_var after restoring values
- tlib#input#List: filter-specific help
- Removed the seq filter (use cnfd or fuzzy instead)
- tlib#input#List: temp_prompt (for help message)
MD5 checksum: aa8b5a4602235cc1a5bc9ee45d801b81
version: "0.42"
- g:tlib#cache#silent: don't display messages when purging the cache (fixes #9)
- Changed message when deleting directories in the cache.
- g:tlib#input#use_popup: Don't rely on has('menu') but also check for gtk & win gui (fixes #10)
- debug
- tlib#input#ListW(): Didn't return a list when type == "m"
- docs (solves #11)
MD5 checksum: aa8b5a4602235cc1a5bc9ee45d801b81
version: "0.45"
- fuzzy mode: prototype.highlight defaults to g:tlib_inputlist_higroup
- tlib#scratch: Use noautocmd
- tlib#input#ListW(): Use world.RestoreOrigin() instead of tlib#win#SetLayout(world.winview)
- tlib#input#ListW(): Revert to tlib#win#SetLayout(world.winview)
- tlib#cmd#OutputAsList(): Also save output in g:tlib#cmd#last_output
- tlib#agent#Suspend(): Resume on BufEnter
- tlib#input#Resume(): Make sure we are in the right buffer
- tlib#agent#Suspend(): Use only BufEnter event to trigger a Resume
- tlib#input#ListW(): When redisplaying a list, make sure prefix > 0
- tlib#vcs: Access vcs (initially only git is supported)
- tlib#vcs: improved
- tlib#persistent: Persistent data file names
- tlib#file#With(): Trigger BufRead autocommands
- Duplicate help tags (fixes #13)
- Make sure scrolloff is 0 while viewing the list (fixes https://github.com/tomtom/vikitasks_vim/issues/2)
MD5 checksum: 0af19ebc0e424727a598a988fdc90f4e
- Support for tinykeymap (move paragraph)
- Moved para_move to autoload/tinykeymap/map
- tlib#vcs: some "diff" commands were defined as "ls"; updated hg def; %s is optional
MD5 checksum: f2f2fe0893e75bb9423c1ddcd01f38f6
version: "0.46"
- tlib#input#List: optimizations
- Prepare for multi-mode maps
- tlib#input#List: cnfx is new default filter
- Filters: minor changes to how the pattern is displayed
- g:tlib#input#format_filename: alternative method for formatting filenames
- tlib#input#List: allow multiple keymaps / modes
- Handle rezise events
- Don't initialize the same window twice
- Minor optimizations to how help is displayed
- Handle VimResize event per buffer
- Improve display of filenames & highlighting
- Filename highlighter: set Highlight_filename()
- RunStateHandlers(): set world variable
- Optimize help display
MD5 checksum: e3652927722bdc51935eb1a04238546b
version: "1.00"
- Set g:tlib_inputlist_and to ' ' again
- g:tlib#input#filename_max_width: maximum display width of filenames
- tlib#input#List: <s-esc>, <f10>: run command by name
MD5 checksum: a42f90275cdbe9f7d92cac61b884a2d1
version: "1.01"
- #UseInputListScratch(): Make sure the TLib autogroup was created (fixes #14)
MD5 checksum: 5a6da7fc99c7fc7584e8fc2f7bf86fe4
version: "1.02"
- tlib#cache#Value(cfile, generator, ftime, ...): cache value & check timestamp
- Replaced g:tlib#cache#silent with g:tlib#cache#verbosity
- FormatFilenames: improved handling of utf8 characters
- tlib#persistent#Value()
- tlib#input#List: Allow filename indiactors defined by the caller
- Custom filename_indicators are displayed after (and clearly separted from) the standard indicators
- Check the return value of an unknown_key agent
- Format filename = "l": Allow ".." as start of a directory name
- Format filename = "l": If the filename is just a filename's tail, display it on both sides
- Set g:tlib_filename_sep to "\" on Windows (again)
- g:tlib#cache#max_filename: If the cache filename is longer than N characters, use |pathshorten()|.
MD5 checksum: b64ce6764f39f40bfc95f3916bbb0057
version: "1.04"
version: "1.05"
- tlib#hash: Adler32 & CRC32 (using zlib via ruby) algorithms
- tlib#cache#Filename(): If the cache filename is too long, add the Adler32 checksum to the shortened path
- tlib#cache#Filename(): Use tlib#hash#Adler32() only if the or() function exists
- tlib#hash#Adler32(): Raise error, if or() doesn't exist
- tlib#hash#CRC32(): Alternative implementation of crc32 (doesn't work yet, thus currently disabled)
- tlib#bitwise: Bitwise operations for older versions of vim
- tlib#number: Base conversion
- tlib#input#ListW(): Handle mouse clicks more correctly
- tlib#bitwise#Num2Bits(): Supports returning floats
- tlib#hash#CRC32(): Alternative implementation of crc32 (doesn't work yet)
- tlib#hash#CRC32(): Re-enable ruby version
- tlib#hash#CRC32B(): Implementation of CRC32B checksum in vimscript (used only if +ruby isn't available)
- tlib#hash#CRC32B(): vim version: cache the crc table
- tlib#cache#Filename(): Use tlib#hash#CRC32B(file) instead of not Adler32 for filenames too long
- tlib#hash#CRC32B(): ruby version: return upper case hex value
- g:tlib#hash#use_crc32: define which crc32b version should be used
- Moved spec files from vimtlib to tlib_vim
- tlib#bitwise#Add() and tlib#bitwise#Sub()
- tlib#file#Relative(): Wrong results for filenames that don't exist
- Implementation of hash#Adler32 for earlier vim versions; g:tlib#hash#use_adler32
- tlib#cache#Filename(): Use adler32 again
- addon-info
- tlib#file#Absolute(): remove redundant "." parts in full filename
- win32: Fix moving window when using :vertical for tlib#inpu#List()
- tlib#cache#Filename(): Don't create wrong directory if the cache filename is too long
- tlib#file#Join(): if strip_slashes, also strip redundant (back)slashes
- tlib#input#ListW(): Always set post_keys variable
- tlib#file#With(): escape backslashes
- tlib#cmd#OutputAsList(): Support for nesting
- tlib#dir#NativeName(dirname)
MD5 checksum: 493f9beca44374de386f20d1613155e3
- Rename g:tlib_debug to g:tlib#debug
- Renamed g:tlib_sortprefs_threshold to g:tlib#input#sortprefs_threshold
- Renamed g:tlib#input#livesearch_threshold
- Renamed g:tlib_inputlist_match to g:tlib#input#filter_mode
- Renamed g:tlib_inputlist_higroup to g:tlib#input#higroup
- Renamed g:tlib#debug
- Moved g:tlib_pick_last_item
- Renamed g:tlib#input#and, g:tlib#input#or, g:tlib#input#not
- Moved g:tlib_numeric_chars to autoload/tlib/input.vim
- Renamed g:tlib#input#keyagents_InputList_s, g:tlib#input#keyagents_InputList_m, g:tlib#input#handlers_EditList
- Moved g:tlib_inputlist_pct, g:tlib_inputlist_width_filename, g:tlib_inputlist_filename_indicators, g:tlib_inputlist_shortmessage to autoload/tlib/World.vim
- Renamed tlib#input#pick_last_item (2)
- prototype.SelectItemsByNames()
- filtered_items: Restricted view
- prototype.PrintLines()
- Restricted view (2)
- Moved g:tlib_scroll_lines to autoload/tlib/agent.vim
- prototype.PrintLines() (2)
- tlib#input: Improved handling of popup menu (allows submenu)
- tlib#input: Allow mods in keys
- Moved g:tlib_scratch_pos to autoload/tlib/scratch.vim
- Moved g:tlib_tags_extra, g:tlib_tag_substitute to autoload/tlib/tag.vim
- tlib#agent#CompleteAgentNames(): Respect Arglead
- Move g:tlib_viewline_position to autoload/tlib/buffer.vim
- Move g:tlib_cache to autoload/tlib/cache.vim
- Renamed g:tlib_filename_sep to g:tlib#dir#sep
- prototype.UseScratch(): Set b:tlib_world
- tlib#input: f9 toggles resticted view
- tlib#input: next_agent, next_eval
- tlib#input: Revised use of the popup menu
- tlib#input: Disable popup menu for gui_gtk
- tlib#input: Re-enabled the popup menu for gtk gui
- tlib#input: FIX popup menu on Windows
- Renamed g:tlib_numeric_chars to g:tlib#input#numeric_chars (disabled per-buffer values) (fixes #35)
- Improve scratch list
- New: tlib#grep
- Merge branch 'master' of https://github.com/bruno-/tlib_vim into pull16
- g:tlib_scratch_hidden: Configure how to "hide" the scratch buffer
- tlib#grep#Do: don't escape "*" in patterns
- Optimize use of visible scratch buffers
- World.scratch_hidden parameter
- scratch: Always use keepalt & keepjumps
MD5 checksum: 2e40449c47dc606ccef57aa0b1e22e8e
version: "1.06"
version: "1.07"
- Help template
- prototype.Highlight_filename(): Use matchstr() instead of fnamemodify()
- Display buffer-related filename indicators only if g:tlib_inputlist_filename_indicators is true
- tlib#file#Join(): strip_slashes defaults to 1
MD5 checksum: 6c8fa96fd3747be05df848ee93dd789b
version: "1.08"
- list#input: Improved support for file indicators (closes #17)
- tlib#char#Get(): Optionally, also return mod
- tlib#input#ListW: Use #DisplayFormat(world.list)
- Renamed cnfx filter to glob & minor filter-related enhancements
- list#input: Make help available as command; help cannot be called via ?
- list#input: Improved help message
- list#input: Support Home & End keys
- list#input: Added glob filter
- tlib#agent#ShowInfo: Show full filename
- tlib#cmd#BrowseOutputWithCallback: Support calling callback with multiple results
- tlib#cmd#ParseScriptname: Properly parse results from :scriptnames
- tlib#tab#Set()
- Prepare for proper handling of scratch_split == -1
- tlib#vim#CopyFunction()
- tlib#cache#Value(): If generator is empty, use the optional argument as start value
- tlib#persistent#Get() refers to tlib#cache#Get()
MD5 checksum: 459ec620168d1ae9b18c69eb3f991832
- tlib#cache#Filename(): Use sha256() for VIM >= 7.4
- tlib#cache#Value(): Undo previous hack
- tlib#list#Uniq(): option to remove empty values
- tlib#cache#MTime(); tlib#persistent#Save() calls tlib#cache#Save()
- tlib#input#ListW: Temporarily set noshowmode
- tlib#list#Uniq(): Fix handling of empty items
- lis picker: Remove <C-Space> from help
- tlib#list#Uniq(): Implementation based on syntastic#util#unique(list) by scrooloose
MD5 checksum: b5fb4107d63930c2c8b1f0f6b3a7ff07
version: "1.09"
- tlib#cache#Filename(): Use sha256() for VIM >= 7.4
- tlib#cache#Value(): Undo previous hack
- tlib#list#Uniq(): option to remove empty values
- tlib#cache#MTime(); tlib#persistent#Save() calls tlib#cache#Save()
- tlib#input#ListW: Temporarily set noshowmode
- tlib#list#Uniq(): Fix handling of empty items
- lis picker: Remove <C-Space> from help
- tlib#list#Uniq(): Implementation based on syntastic#util#unique(list) by scrooloose
MD5 checksum: b5fb4107d63930c2c8b1f0f6b3a7ff07
version: "1.09"
- tlib#string#Chomp: Optional argument: max number of chars that should be removed
MD5 checksum: 8c1b94e25045580874e2f892d509291b
version: "1.10"
- tlib#vcs#FindVCS(filename): Wrong parameters to fnamemodifiy if filename is a directory
- Some system-related functions (e.g. facilitate use of cygwin tools)
- tlib#arg#StringAsKeyArgsEqual(), tlib#arg#StringAsKeyArgs(): Support "key=val" type argument lists
- tlib#vcs#Executable()
- scripts/create_crc_table.rb
- tlib#var#Get(): For namespaces other than global, replace "#" with "_"
MD5 checksum: 4a33f2f23e1fc6600b32e7f8323e001e
version: "1.11"
- tlib#list#ToDictionary()
- tlib#dir#CanonicName(): Use tlib#file#Canonic()
- tlib#file#Canonic()
MD5 checksum: 7995ab58f31eb6673d20deab8761838e
version: "1.12"
- SetInitialFilter(): Use deepcopy()
- tlib#var#List(): use keys(namespace) for newer versions of vim
- g:tlib#input#user_shortcuts (not functional yet)
- tlib#input#List: state "picked"
- UseInputListScratch(): Allow customization via self.index_next_syntax
- tlib#cmd#Capture()
- Facilitate customization of key agents via g:tlib_extend_keyagents_InputList_s, g:tlib_extend_keyagents_InputList_m
MD5 checksum: 7dd8b17a1a5b555df979381dcbd4c9aa
version: "1.13"
- SetInitialFilter(): Use deepcopy()
- tlib#var#List(): use keys(namespace) for newer versions of vim
- g:tlib#input#user_shortcuts (not functional yet)
- tlib#input#List: state "picked"
- UseInputListScratch(): Allow customization via self.index_next_syntax
- tlib#cmd#Capture()
- Facilitate customization of key agents via g:tlib_extend_keyagents_InputList_s, g:tlib_extend_keyagents_InputList_m
MD5 checksum: 7dd8b17a1a5b555df979381dcbd4c9aa
version: "1.13"
version: "1.14"
- FIX #18: Make sure the scratch isn't readonly
- FIX: display filter (properly handle backslashes)
- Remove loaded_* guard from autoload files
- tlib#notify#Echo(): minor changes
- tlib#file#Edit() (used by tlib#agent#ViewFile)
- tlib#buffer#GetList(): Buffer numbers are converted to numbers
- tlib#sys: Change order of functions (move tlib#sys#IsCygwinBin to the (possibly FIX #19)
- g:tlib#sys#check_cygpath: Call tlib#sys#IsExecutable('cygpath', 1) (possibly FIX #19)
MD5 checksum: 2cf6386218736a2d09db43c8e751e5a4
version: "1.15"
- tlib#file#Join(): New optional argument: maybe_absolute Drop preceding parts if a part looks like an absolute filename
- tlib#sys#Open(), tlib#sys#IsSpecial() (moved from viki)
- tlib#list#Uniq(): Handle hetergenous lists
- FIX #21: duplicate help tag
- NEW tlib#dictionary#Rev()
- tlib#input#List(): Use <Tab> to complete current word
- NEW tlib#arg#GetOpts(); ENH tlib#arg#StringAsKeyArgsEqual()
- cache: Allow for in memory cache
- NEW tlib#eval#Extend()
- Move qfl/loclist browser from trag to tlib
- FIX tlib#eval#Extend()
- Simplify tlib#eval#Extend()
- World.index_next_syntax may be a dict
- tlib#qfl#QflList: Use copy()
- tlib#arg#GetOpts: Handle exit code
MD5 checksum: 13fd8b0e4ba9cd932c57fc40ac3f641f
version: "1.15"
- tlib#file#Join(): New optional argument: maybe_absolute Drop preceding parts if a part looks like an absolute filename
- tlib#sys#Open(), tlib#sys#IsSpecial() (moved from viki)
- tlib#list#Uniq(): Handle hetergenous lists
- FIX #21: duplicate help tag
- NEW tlib#dictionary#Rev()
- tlib#input#List(): Use <Tab> to complete current word
- NEW tlib#arg#GetOpts(); ENH tlib#arg#StringAsKeyArgsEqual()
- cache: Allow for in memory cache
- NEW tlib#eval#Extend()
- Move qfl/loclist browser from trag to tlib
- FIX tlib#eval#Extend()
- Simplify tlib#eval#Extend()
- World.index_next_syntax may be a dict
- tlib#qfl#QflList: Use copy()
- tlib#arg#GetOpts: Handle exit code
MD5 checksum: 13fd8b0e4ba9cd932c57fc40ac3f641f
- tlib#arg#GetOpts: Handle short options
- tlib#arg: support short flags & facilitate completion
- NEW :TLibTrace
- tlib#sys#system_browser: FIX XDG string
- NEW tlib#sys#SystemInDir() (used by tlib#vcs#Ls)
- tlib#agent#Complete: improve fltrx
- Remove tlib#arg#Key(), :TKeyArg
- Move :TRequire, :TTimeCommand to macros/tlib.vim
- NEW tlib#cmd#TBrowseScriptnames()
- TScratch: use empty('<bang>')
- NEW :TLibTrace
- tlib#qfl: FIX TTagedFilesFilename regexp
- Remove tlib#arg#Key()
- tlib#buffer#InsertText(): Don't use TKeyArg
- tlib#eval#Extend: don't assign value
- NEW :TLibTrace, tlib#trace (was tlib#debug)
- NEW tlib#string#SplitCommaList()
- NEW tlib#time#FormatNow()
- tlib#arg#GetOpts: selectively disable "long", "short" flags
- tlib#arg#CComplete(): Support values completion (complete_customlist field)
- NEW tlib#date#Shift()
- tlib#qfl#Balloon(): Handle items with no bufnr
- NEW tlib#file#Glob, tlib#file#Globpath
- tlib#progressbar#Display(): optional "always" argument
- tlib#vcs#GitLsPostprocess(): Try to handle encoded filenames from git ls-files
- tlib#vcs#GitLsPostprocess: Eval only \ddd substrings
- FIX #22: duplicate tag
- tlib#buffer: Use 2match instead of 3match (incompatibility with matchparen)
- FIX #23: duplicate help tag
- tlib#string#SplitCommaList: optional "sep" argument
- Rename TLibTrace -> Tlibtrace; NEW Tlibtraceset command
- Rename s:SetSyntax -> tlib#qfl#SetSyntax
- mv tlib#rx#Convert to incubator
MD5 checksum: f3656fb35b7b3033084d6c5e504aca61
version: "1.16"
- tlib#input#List: #ReduceFilter: make sure the regexp is valid
- TTimeCommand -> Ttimecommand
- tlib#eval#Extend: mode argument for expand() compatibility
- tlib#input#List: Key handlers can have additional arguments
- tlib#qfl#AgentWithSelected: Set world
- prototype.UseInputListScratch: Run tlib_UseInputListScratch hook earlier
- tlib#qfl#AgentWithSelected: typo
- tlib#arg#GetOpts: type conversion (comma-separated lists etc.)
- tlib#arg: validators
- NEW tlib#date#IsDate()
- tlib#balloon#Remove: Unset &ballooneval, &balloonexpr
- NEW tlib#balloon#Expand()
- NEW tlib#date#Format()
- FIX tlib#date#Shift(..., "+Xm") for months
- NEW tlib#trace#Backtrace()
- NEW tlib#type#Is(), tlib#type#Are(), tlib#type#Has(), tlib#type#Have()
- NEW :Tlibassert
MD5 checksum: 3c4125a28ff1860accd254846651c251
version: "1.17"
- tlib#input#List: #ReduceFilter: make sure the regexp is valid
- TTimeCommand -> Ttimecommand
- tlib#eval#Extend: mode argument for expand() compatibility
- tlib#input#List: Key handlers can have additional arguments
- tlib#qfl#AgentWithSelected: Set world
- prototype.UseInputListScratch: Run tlib_UseInputListScratch hook earlier
- tlib#qfl#AgentWithSelected: typo
- tlib#arg#GetOpts: type conversion (comma-separated lists etc.)
- tlib#arg: validators
- NEW tlib#date#IsDate()
- tlib#balloon#Remove: Unset &ballooneval, &balloonexpr
- NEW tlib#balloon#Expand()
- NEW tlib#date#Format()
- FIX tlib#date#Shift(..., "+Xm") for months
- NEW tlib#trace#Backtrace()
- NEW tlib#type#Is(), tlib#type#Are(), tlib#type#Has(), tlib#type#Have()
- NEW :Tlibassert
MD5 checksum: 3c4125a28ff1860accd254846651c251
version: "1.17"
- tlib#input#List: #ReduceFilter: make sure the regexp is valid
- TTimeCommand -> Ttimecommand
- tlib#eval#Extend: mode argument for expand() compatibility
- tlib#input#List: Key handlers can have additional arguments
- tlib#qfl#AgentWithSelected: Set world
- prototype.UseInputListScratch: Run tlib_UseInputListScratch hook earlier
- tlib#qfl#AgentWithSelected: typo
- tlib#arg#GetOpts: type conversion (comma-separated lists etc.)
- tlib#arg: validators
- NEW tlib#date#IsDate()
- tlib#balloon#Remove: Unset &ballooneval, &balloonexpr
- NEW tlib#balloon#Expand()
- NEW tlib#date#Format()
- FIX tlib#date#Shift(..., "+Xm") for months
- NEW tlib#trace#Backtrace()
- NEW tlib#type#Is(), tlib#type#Are(), tlib#type#Has(), tlib#type#Have()
- NEW :Tlibassert
MD5 checksum: 3c4125a28ff1860accd254846651c251
version: "1.17"
- tlib#input#List: #ReduceFilter: make sure the regexp is valid
- TTimeCommand -> Ttimecommand
- tlib#eval#Extend: mode argument for expand() compatibility
- tlib#input#List: Key handlers can have additional arguments
- tlib#qfl#AgentWithSelected: Set world
- prototype.UseInputListScratch: Run tlib_UseInputListScratch hook earlier
- tlib#qfl#AgentWithSelected: typo
- tlib#arg#GetOpts: type conversion (comma-separated lists etc.)
- tlib#arg: validators
- NEW tlib#date#IsDate()
- tlib#balloon#Remove: Unset &ballooneval, &balloonexpr
- NEW tlib#balloon#Expand()
- NEW tlib#date#Format()
- FIX tlib#date#Shift(..., "+Xm") for months
- NEW tlib#trace#Backtrace()
- NEW tlib#type#Is(), tlib#type#Are(), tlib#type#Has(), tlib#type#Have()
- NEW :Tlibassert
MD5 checksum: 3c4125a28ff1860accd254846651c251
version: "1.17"
- tlib#arg: Completion for comma-separated lists
- Use "silent cd"
- NEW tlib#type#DefSchema(); FIX tlib#type#Has()
- tlib#cache#Value(): minor change
- tlib#date#IsDate() also checks whether the date is valid
- ! tlib#sys#Open(): escape special chars only once
- tlib#trace#Print: Allow for strings
- :Tlibtrace, :Tlibtraceset, :Tlibassert remove `-bar`
- NEW :Tlibtype (type/schema assertions); tlib#type#Is() also accepts schemas as "types"
- tlib#dir#CD(): Use haslocaldir()
- tlib#qfl#AgentGotoQFE: Don't use wincmd w
- NEW tlib#string#Input()
- FIX g:tlib#sys#system_rx; add OpenOffice exensions to g:tlib#sys#special_suffixes
- NEW tlib#selection#GetSelection()
- tlib#date#Shift(): Fix "Xm", ++specs
- tlib#trace#Set: FIX Properly handly "-label"
MD5 checksum: c3a1fe7d3cd86becbd3f7b0ba7ae9cd8
version: "1.19"
version: "1.20"
- tlib#arg: Completion for comma-separated lists
- Use "silent cd"
- NEW tlib#type#DefSchema(); FIX tlib#type#Has()
- tlib#cache#Value(): minor change
- tlib#date#IsDate() also checks whether the date is valid
- ! tlib#sys#Open(): escape special chars only once
- tlib#trace#Print: Allow for strings
- :Tlibtrace, :Tlibtraceset, :Tlibassert remove `-bar`
- NEW :Tlibtype (type/schema assertions); tlib#type#Is() also accepts schemas as "types"
- tlib#dir#CD(): Use haslocaldir()
- tlib#qfl#AgentGotoQFE: Don't use wincmd w
- NEW tlib#string#Input()
- FIX g:tlib#sys#system_rx; add OpenOffice exensions to g:tlib#sys#special_suffixes
- NEW tlib#selection#GetSelection()
- tlib#date#Shift(): Fix "Xm", ++specs
- tlib#trace#Set: FIX Properly handly "-label"
MD5 checksum: c919e0782931a8c628c6996903f989d3

View File

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -0,0 +1,21 @@
This library provides some utility functions. There isn't much need to
install it unless another plugin requires you to do so.
Most of the library is included in autoload files. No autocommands are
created. With the exception of loading ../plugin/02tlib.vim at startup
the library has no impact on startup time or anything else.
The change-log is included at the bottom of ../plugin/02tlib.vim
(move the cursor over the file name and type gfG)
Demo of |tlib#input#List()|:
http://vimsomnia.blogspot.com/2010/11/selecting-items-from-list-with-tlibs.html
-----------------------------------------------------------------------
License: GPLv3 or later
Install: See http://github.com/tomtom/vimtlib/blob/master/INSTALL.TXT
See http://github.com/tomtom for related plugins.

View File

@ -0,0 +1,9 @@
{
"name" : "tlib",
"version" : "dev",
"author" : "Tom Link <micathom at gmail com>",
"maintainer" : "Tom Link <micathom at gmail com>",
"repository" : {"type": "git", "url": "git://github.com/tomtom/tlib_vim.git"},
"dependencies" : {},
"description" : "tlib -- A library of vim functions"
}

View File

@ -0,0 +1,12 @@
" para_move.vim
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2012-08-28.
" @Last Change: 2012-08-29.
" @Revision: 3
" Move paragraphs
call tinykeymap#EnterMap("para_move", "gp", {'name': 'move paragraph'})
call tinykeymap#Map("para_move", "j", "silent call tlib#paragraph#Move('Down', '<count>')")
call tinykeymap#Map("para_move", "k", "silent call tlib#paragraph#Move('Up', '<count>')")

View File

@ -0,0 +1,8 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 13
" :nodefault:
TLet g:tlib#debug = 0

View File

@ -0,0 +1,151 @@
" Filter_cnf.vim
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2008-11-25.
" @Last Change: 2014-11-18.
" @Revision: 0.0.114
let s:prototype = tlib#Object#New({'_class': ['Filter_cnf'], 'name': 'cnf'}) "{{{2
let s:prototype.highlight = g:tlib#input#higroup
" The search pattern for |tlib#input#List()| is in conjunctive normal
" form: (P1 OR P2 ...) AND (P3 OR P4 ...) ...
" The pattern is a '/\V' very no-'/magic' regexp pattern.
"
" Pressing <space> joins two patterns with AND.
" Pressing | joins two patterns with OR.
" I.e. In order to get "lala AND (foo OR bar)", you type
" "lala foo|bar".
"
" This is also the base class for other filters.
function! tlib#Filter_cnf#New(...) "{{{3
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
return object
endf
" :nodoc:
function! s:prototype.Init(world) dict "{{{3
endf
" :nodoc:
function! s:prototype.Help(world) dict "{{{3
call a:world.PushHelp(
\ printf('"%s", "%s", "%sWORD"', g:tlib#input#and, g:tlib#input#or, g:tlib#input#not),
\ 'AND, OR, NOT')
endf
" :nodoc:
function! s:prototype.AssessName(world, name) dict "{{{3
let xa = 0
let prefix = self.FilterRxPrefix()
for flt in a:world.filter_pos
" let flt = prefix . a:world.GetRx(fltl)
" if flt =~# '\u' && a:name =~# flt
" let xa += 5
" endif
if a:name =~ '\^'. flt
let xa += 4
elseif a:name =~ '\<'. flt
let xa += 3
" elseif a:name =~ '[[:punct:][:space:][:digit:]]'. flt
" let xa += 2
elseif a:name =~ '\A'. flt .'\|'. flt .'\A'
let xa += 1
endif
endfor
" TLogVAR a:name, xa
return xa
endf
" :nodoc:
function! s:prototype.Match(world, text) dict "{{{3
" TLogVAR a:text
" let sc = &smartcase
" let ic = &ignorecase
" if &ignorecase
" set smartcase
" endif
" try
if !empty(a:world.filter_neg)
for rx in a:world.filter_neg
" TLogVAR rx
if a:text =~ rx
return 0
endif
endfor
endif
if !empty(a:world.filter_pos)
for rx in a:world.filter_pos
" TLogVAR rx
if a:text !~ rx
return 0
endif
endfor
endif
" finally
" let &smartcase = sc
" let &ignorecase = ic
" endtry
return 1
endf
" :nodoc:
function! s:prototype.DisplayFilter(filter) dict "{{{3
let filter1 = deepcopy(a:filter)
call map(filter1, '"(". join(reverse(self.Pretty(v:val)), " OR ") .")"')
return join(reverse(filter1), ' AND ')
endf
function! s:prototype.Pretty(filter) dict "{{{3
" call map(a:filter, 'substitute(v:val, ''\\\.\\{-}'', ''=>'', ''g'')')
call map(a:filter, 'self.CleanFilter(v:val)')
return a:filter
endf
" :nodoc:
function! s:prototype.SetFrontFilter(world, pattern) dict "{{{3
let a:world.filter[0] = reverse(split(a:pattern, '\s*|\s*')) + a:world.filter[0][1 : -1]
endf
" :nodoc:
function! s:prototype.PushFrontFilter(world, char) dict "{{{3
let a:world.filter[0][0] .= nr2char(a:char)
endf
" :nodoc:
function! s:prototype.ReduceFrontFilter(world) dict "{{{3
let filter = a:world.filter[0][0]
" TLogVAR filter
let str = matchstr(filter, '\(\\\(\.\\{-}\|[.?*+$^]\)\|\)$')
if empty(str)
let filter = filter[0 : -2]
else
let filter = strpart(filter, 0, len(filter) - len(str))
endif
" TLogVAR str, filter
let a:world.filter[0][0] = filter
endf
" :nodoc:
function! s:prototype.FilterRxPrefix() dict "{{{3
return '\V'
endf
" :nodoc:
function! s:prototype.CleanFilter(filter) dict "{{{3
return a:filter
endf

View File

@ -0,0 +1,53 @@
" Filter_cnfd.vim
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2008-11-25.
" @Last Change: 2014-01-23.
" @Revision: 0.0.57
let s:prototype = tlib#Filter_cnf#New({'_class': ['Filter_cnfd'], 'name': 'cnfd'}) "{{{2
let s:prototype.highlight = g:tlib#input#higroup
" The same as |tlib#Filter_cnf#New()| but a dot is expanded to '\.\{-}'.
" As a consequence, patterns cannot match dots.
" The pattern is a '/\V' very no-'/magic' regexp pattern.
function! tlib#Filter_cnfd#New(...) "{{{3
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
return object
endf
" :nodoc:
function! s:prototype.Init(world) dict "{{{3
endf
let s:Help = s:prototype.Help
" :nodoc:
function! s:prototype.Help(world) dict "{{{3
call call(s:Help, [a:world], self)
call a:world.PushHelp('.', 'Any characters')
endf
" :nodoc:
function! s:prototype.SetFrontFilter(world, pattern) dict "{{{3
let pattern = substitute(a:pattern, '\.', '\\.\\{-}', 'g')
let a:world.filter[0] = reverse(split(pattern, '\s*|\s*')) + a:world.filter[0][1 : -1]
endf
" :nodoc:
function! s:prototype.PushFrontFilter(world, char) dict "{{{3
let a:world.filter[0][0] .= a:char == 46 ? '\.\{-}' : nr2char(a:char)
endf
" :nodoc:
function! s:prototype.CleanFilter(filter) dict "{{{3
return substitute(a:filter, '\\.\\{-}', '.', 'g')
endf

View File

@ -0,0 +1,83 @@
" Filter_fuzzy.vim
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2008-11-25.
" @Last Change: 2013-09-25.
" @Revision: 0.0.47
let s:prototype = tlib#Filter_cnf#New({'_class': ['Filter_fuzzy'], 'name': 'fuzzy'}) "{{{2
let s:prototype.highlight = g:tlib#input#higroup
" Support for "fuzzy" pattern matching in |tlib#input#List()|.
" Patterns are interpreted as if characters were connected with '.\{-}'.
"
" In "fuzzy" mode, the pretty printing of filenames is disabled.
function! tlib#Filter_fuzzy#New(...) "{{{3
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
return object
endf
" :nodoc:
function! s:prototype.Init(world) dict "{{{3
" TLogVAR a:world.display_format
" :nodoc:
function! a:world.Set_display_format(value) dict
if a:value == 'filename'
let self.display_format = ''
else
let self.display_format = a:value
endif
endf
endf
let s:Help = s:prototype.Help
" :nodoc:
function! s:prototype.Help(world) dict "{{{3
call call(s:Help, [a:world], self)
call a:world.PushHelp('Patterns are interpreted as if characters were connected with .\{-}')
endf
" :nodoc:
function! s:prototype.DisplayFilter(filter) dict "{{{3
" TLogVAR a:filter
let filter1 = deepcopy(a:filter)
call map(filter1, '"{". join(reverse(v:val), " OR ") ."}"')
return join(reverse(filter1), ' AND ')
endf
" :nodoc:
function! s:prototype.SetFrontFilter(world, pattern) dict "{{{3
let a:world.filter[0] = map(reverse(split(a:pattern, '\s*|\s*')), 'join(map(split(v:val, ''\zs''), ''tlib#rx#Escape(v:val, "V")''), ''\.\{-}'')') + a:world.filter[0][1 : -1]
endif
endf
" :nodoc:
function! s:prototype.PushFrontFilter(world, char) dict "{{{3
let ch = tlib#rx#Escape(nr2char(a:char), 'V')
if empty(a:world.filter[0][0])
let a:world.filter[0][0] .= ch
else
let a:world.filter[0][0] .= '\.\{-}'. ch
endif
endf
" :nodoc:
function! s:prototype.ReduceFrontFilter(world) dict "{{{3
let a:world.filter[0][0] = substitute(a:world.filter[0][0], '\(\\\.\\{-}\)\?.$', '', '')
endf
" :nodoc:
function! s:prototype.CleanFilter(filter) dict "{{{3
return substitute(a:filter, '\\\.\\{-}', '', 'g')
endf

View File

@ -0,0 +1,68 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2008-11-25.
" @Last Change: 2014-11-18.
" @Revision: 0.0.82
let s:prototype = tlib#Filter_cnf#New({'_class': ['Filter_glob'], 'name': 'glob'}) "{{{2
let s:prototype.highlight = g:tlib#input#higroup
" A character that should be expanded to '\.\{-}'.
TLet g:tlib#Filter_glob#seq = '*'
" A character that should be expanded to '\.\?'.
TLet g:tlib#Filter_glob#char = '?'
" The same as |tlib#Filter_cnf#New()| but a a customizable character
" |see tlib#Filter_glob#seq| is expanded to '\.\{-}' and
" |g:tlib#Filter_glob#char| is expanded to '\.'.
" The pattern is a '/\V' very no-'/magic' regexp pattern.
function! tlib#Filter_glob#New(...) "{{{3
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
return object
endf
let s:Help = s:prototype.Help
" :nodoc:
function! s:prototype.Help(world) dict "{{{3
call call(s:Help, [a:world], self)
call a:world.PushHelp(g:tlib#Filter_glob#seq, 'Any characters')
call a:world.PushHelp(g:tlib#Filter_glob#char, 'Single characters')
endf
" :nodoc:
function! s:prototype.SetFrontFilter(world, pattern) dict "{{{3
let pattern = substitute(a:pattern, tlib#rx#Escape(g:tlib#Filter_glob#seq, 'V'), '\\.\\{-}', 'g')
let pattern = substitute(a:pattern, tlib#rx#Escape(g:tlib#Filter_glob#char, 'V'), '\\.', 'g')
let a:world.filter[0] = reverse(split(pattern, '\s*|\s*')) + a:world.filter[0][1 : -1]
endf
" :nodoc:
function! s:prototype.PushFrontFilter(world, char) dict "{{{3
" TLogVAR a:char, nr2char(a:char)
if a:char == char2nr(g:tlib#Filter_glob#seq)
let char = '\.\{-}'
elseif a:char == char2nr(g:tlib#Filter_glob#char)
let char = '\.'
else
let char = nr2char(a:char)
endif
let a:world.filter[0][0] .= char
endf
" :nodoc:
function! s:prototype.CleanFilter(filter) dict "{{{3
let filter = substitute(a:filter, '\\\.\\{-}', g:tlib#Filter_glob#seq, 'g')
let filter = substitute(filter, '\\\.', g:tlib#Filter_glob#char, 'g')
return filter
endf

View File

@ -0,0 +1,154 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 127
" :filedoc:
" Provides a prototype plus some OO-like methods.
let s:id_counter = 0
let s:prototype = {'_class': ['object'], '_super': [], '_id': 0} "{{{2
" :def: function! tlib#Object#New(?fields={})
" This function creates a prototype that provides some kind of
" inheritance mechanism and a way to call parent/super methods.
"
" The usage demonstrated in the following example works best when every
" class/prototype is defined in a file of its own.
"
" The reason for why there is a dedicated constructor function is that
" this layout facilitates the use of templates and that methods are
" hidden from the user. Other solutions are possible.
"
" EXAMPLES: >
" let s:prototype = tlib#Object#New({
" \ '_class': ['FooBar'],
" \ 'foo': 1,
" \ 'bar': 2,
" \ })
" " Constructor
" function! FooBar(...)
" let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
" return object
" endf
" function! s:prototype.babble() {
" echo "I think, therefore I am ". (self.foo * self.bar) ." months old."
" }
"
" < This could now be used like this: >
" let myfoo = FooBar({'foo': 3})
" call myfoo.babble()
" => I think, therefore I am 6 months old.
" echo myfoo.IsA('FooBar')
" => 1
" echo myfoo.IsA('object')
" => 1
" echo myfoo.IsA('Foo')
" => 0
" echo myfoo.RespondTo('babble')
" => 1
" echo myfoo.RespondTo('speak')
" => 0
function! tlib#Object#New(...) "{{{3
return s:prototype.New(a:0 >= 1 ? a:1 : {})
endf
function! s:prototype.New(...) dict "{{{3
let object = deepcopy(self)
let s:id_counter += 1
let object._id = s:id_counter
if a:0 >= 1 && !empty(a:1)
" call object.Extend(deepcopy(a:1))
call object.Extend(a:1)
endif
return object
endf
function! s:prototype.Inherit(object) dict "{{{3
let class = copy(self._class)
" TLogVAR class
let objid = self._id
for c in get(a:object, '_class', [])
" TLogVAR c
if index(class, c) == -1
call add(class, c)
endif
endfor
call extend(self, a:object, 'keep')
let self._class = class
" TLogVAR self._class
let self._id = objid
" let self._super = [super] + self._super
call insert(self._super, a:object)
return self
endf
function! s:prototype.Extend(dictionary) dict "{{{3
let super = copy(self)
let class = copy(self._class)
" TLogVAR class
let objid = self._id
let thisclass = get(a:dictionary, '_class', [])
for c in type(thisclass) == 3 ? thisclass : [thisclass]
" TLogVAR c
if index(class, c) == -1
call add(class, c)
endif
endfor
call extend(self, a:dictionary)
let self._class = class
" TLogVAR self._class
let self._id = objid
" let self._super = [super] + self._super
call insert(self._super, super)
return self
endf
function! s:prototype.IsA(class) dict "{{{3
return index(self._class, a:class) != -1
endf
function! s:prototype.IsRelated(object) dict "{{{3
return len(filter(a:object._class, 'self.IsA(v:val)')) > 1
endf
function! s:prototype.RespondTo(name) dict "{{{3
" return has_key(self, a:name) && type(self[a:name]) == 2
return has_key(self, a:name)
endf
function! s:prototype.Super(method, arglist) dict "{{{3
for o in self._super
" TLogVAR o
if o.RespondTo(a:method)
" let self._tmp_method = o[a:method]
" TLogVAR self._tmp_method
" return call(self._tmp_method, a:arglist, self)
return call(o[a:method], a:arglist, self)
endif
endfor
echoerr 'tlib#Object: Does not respond to '. a:method .': '. string(self)
endf
function! tlib#Object#Methods(object, ...) "{{{3
TVarArg ['pattern', '\d\+']
let o = items(a:object)
call filter(o, 'type(v:val[1]) == 2 && string(v:val[1]) =~ "^function(''\\d\\+'')"')
let acc = {}
for e in o
let id = matchstr(string(e[1]), pattern)
if !empty(id)
let acc[id] = e[0]
endif
endfor
return acc
endf

View File

@ -0,0 +1,19 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 11
" :enddoc:
let s:prototype = tlib#Object#New({'_class': ['Test']}) "{{{2
function! tlib#Test#New(...) "{{{3
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
return object
endf
function! s:prototype.Dummy() dict "{{{3
return 'Test.vim'
endf

View File

@ -0,0 +1,19 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 15
" :enddoc:
let s:prototype = tlib#Test#New({'_class': ['TestChild']}) "{{{2
function! tlib#TestChild#New(...) "{{{3
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
return object
endf
function! s:prototype.Dummy() dict "{{{3
return 'TestChild.vim'
endf

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,665 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 329
" :filedoc:
" Various agents for use as key handlers in tlib#input#List()
" Number of items to move when pressing <c-up/down> in the input list window.
TLet g:tlib_scroll_lines = 10
" General {{{1
function! tlib#agent#Exit(world, selected) "{{{3
if a:world.key_mode == 'default'
call a:world.CloseScratch()
let a:world.state = 'exit empty escape'
let a:world.list = []
" let a:world.base = []
call a:world.ResetSelected()
else
let a:world.key_mode = 'default'
let a:world.state = 'redisplay'
endif
return a:world
endf
function! tlib#agent#CopyItems(world, selected) "{{{3
let @* = join(a:selected, "\n")
let a:world.state = 'redisplay'
return a:world
endf
" InputList related {{{1
function! tlib#agent#PageUp(world, selected) "{{{3
let a:world.offset -= (winheight(0) / 2)
let a:world.state = 'scroll'
return a:world
endf
function! tlib#agent#PageDown(world, selected) "{{{3
let a:world.offset += (winheight(0) / 2)
let a:world.state = 'scroll'
return a:world
endf
function! tlib#agent#Home(world, selected) "{{{3
let a:world.prefidx = 1
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#End(world, selected) "{{{3
let a:world.prefidx = len(a:world.list)
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#Up(world, selected, ...) "{{{3
TVarArg ['lines', 1]
let a:world.idx = ''
if a:world.prefidx > lines
let a:world.prefidx -= lines
else
let a:world.prefidx = len(a:world.list)
endif
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#Down(world, selected, ...) "{{{3
TVarArg ['lines', 1]
let a:world.idx = ''
if a:world.prefidx <= (len(a:world.list) - lines)
let a:world.prefidx += lines
else
let a:world.prefidx = 1
endif
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#UpN(world, selected) "{{{3
return tlib#agent#Up(a:world, a:selected, g:tlib_scroll_lines)
endf
function! tlib#agent#DownN(world, selected) "{{{3
return tlib#agent#Down(a:world, a:selected, g:tlib_scroll_lines)
endf
function! tlib#agent#ShiftLeft(world, selected) "{{{3
let a:world.offset_horizontal -= (winwidth(0) / 2)
if a:world.offset_horizontal < 0
let a:world.offset_horizontal = 0
endif
let a:world.state = 'display shift'
return a:world
endf
function! tlib#agent#ShiftRight(world, selected) "{{{3
let a:world.offset_horizontal += (winwidth(0) / 2)
let a:world.state = 'display shift'
return a:world
endf
function! tlib#agent#Reset(world, selected) "{{{3
let a:world.state = 'reset'
return a:world
endf
function! tlib#agent#ToggleRestrictView(world, selected) "{{{3
if empty(a:world.filtered_items)
return tlib#agent#RestrictView(a:world, a:selected)
else
return tlib#agent#UnrestrictView(a:world, a:selected)
endif
endf
function! tlib#agent#RestrictView(world, selected) "{{{3
" TLogVAR a:selected
let filtered_items = map(copy(a:selected), 'index(a:world.base, v:val) + 1')
" TLogVAR 1, filtered_items
let filtered_items = filter(filtered_items, 'v:val > 0')
" TLogVAR 2, filtered_items
if !empty(filtered_items)
let a:world.filtered_items = filtered_items
endif
let a:world.state = 'display'
return a:world
endf
function! tlib#agent#UnrestrictView(world, selected) "{{{3
let a:world.filtered_items = []
let a:world.state = 'display'
return a:world
endf
function! tlib#agent#Input(world, selected) "{{{3
let flt0 = a:world.CleanFilter(a:world.filter[0][0])
let flt1 = input('Filter: ', flt0)
echo
if flt1 != flt0
if empty(flt1)
call getchar(0)
else
call a:world.SetFrontFilter(flt1)
endif
endif
let a:world.state = 'display'
return a:world
endf
" Suspend (see |tlib#agent#Suspend|) the input loop and jump back to the
" original position in the parent window.
function! tlib#agent#SuspendToParentWindow(world, selected) "{{{3
let world = a:world
let winnr = world.win_wnr
" TLogVAR winnr
if winnr != -1
let world = tlib#agent#Suspend(world, a:selected)
if world.state =~ '\<suspend\>'
call world.SwitchWindow('win')
" let pos = world.cursor
" " TLogVAR pos
" if !empty(pos)
" call setpos('.', pos)
" endif
return world
endif
endif
let world.state = 'redisplay'
return world
endf
" Suspend lets you temporarily leave the input loop of
" |tlib#input#List|. You can resume editing the list by pressing <c-z>,
" <m-z>. <space>, <c-LeftMouse> or <MiddleMouse> in the suspended window.
" <cr> and <LeftMouse> will immediatly select the item under the cursor.
" < will select the item but the window will remain opened.
function! tlib#agent#Suspend(world, selected) "{{{3
if a:world.allow_suspend
" TAssert IsNotEmpty(a:world.scratch)
" TLogDBG bufnr('%')
let br = tlib#buffer#Set(a:world.scratch)
" TLogVAR br, a:world.bufnr, a:world.scratch
if bufnr('%') != a:world.scratch
echohl WarningMsg
echom "tlib#agent#Suspend: Internal error: Not a scratch buffer:" bufname('%')
echohl NONE
endif
" TLogVAR bufnr('%'), bufname('%'), a:world.scratch
call tlib#autocmdgroup#Init()
exec 'autocmd TLib BufEnter <buffer='. a:world.scratch .'> call tlib#input#Resume("world", 0, '. a:world.scratch .')'
let b:tlib_world = a:world
exec br
let a:world.state = 'exit suspend'
else
echom 'Suspend disabled'
let a:world.state = 'redisplay'
endif
return a:world
endf
function! tlib#agent#Help(world, selected) "{{{3
let a:world.state = 'help'
return a:world
endf
function! tlib#agent#OR(world, selected) "{{{3
if !empty(a:world.filter[0])
call insert(a:world.filter[0], '')
endif
let a:world.state = 'display'
return a:world
endf
function! tlib#agent#AND(world, selected) "{{{3
if !empty(a:world.filter[0])
call insert(a:world.filter, [''])
endif
let a:world.state = 'display'
return a:world
endf
function! tlib#agent#ReduceFilter(world, selected) "{{{3
call a:world.ReduceFilter()
let a:world.offset = 1
let a:world.state = 'display'
return a:world
endf
function! tlib#agent#PopFilter(world, selected) "{{{3
call a:world.PopFilter()
let a:world.offset = 1
let a:world.state = 'display'
return a:world
endf
function! tlib#agent#Debug(world, selected) "{{{3
" echo string(world.state)
echo string(a:world.filter)
echo string(a:world.idx)
echo string(a:world.prefidx)
echo string(a:world.sel_idx)
call getchar()
let a:world.state = 'display'
return a:world
endf
function! tlib#agent#Select(world, selected) "{{{3
call a:world.SelectItem('toggle', a:world.prefidx)
" let a:world.state = 'display keepcursor'
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#SelectUp(world, selected) "{{{3
call a:world.SelectItem('toggle', a:world.prefidx)
if a:world.prefidx > 1
let a:world.prefidx -= 1
endif
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#SelectDown(world, selected) "{{{3
call a:world.SelectItem('toggle', a:world.prefidx)
if a:world.prefidx < len(a:world.list)
let a:world.prefidx += 1
endif
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#SelectAll(world, selected) "{{{3
let listrange = range(1, len(a:world.list))
let mode = empty(filter(copy(listrange), 'index(a:world.sel_idx, a:world.GetBaseIdx(v:val)) == -1'))
\ ? 'toggle' : 'set'
for i in listrange
call a:world.SelectItem(mode, i)
endfor
let a:world.state = 'display keepcursor'
return a:world
endf
function! tlib#agent#ToggleStickyList(world, selected) "{{{3
let a:world.sticky = !a:world.sticky
let a:world.state = 'display keepcursor'
return a:world
endf
" EditList related {{{1
function! tlib#agent#EditItem(world, selected) "{{{3
let lidx = a:world.prefidx
" TLogVAR lidx
" TLogVAR a:world.table
let bidx = a:world.GetBaseIdx(lidx)
" TLogVAR bidx
let item = a:world.GetBaseItem(bidx)
let item = input(lidx .'@'. bidx .': ', item)
if item != ''
call a:world.SetBaseItem(bidx, item)
endif
let a:world.state = 'display'
return a:world
endf
" Insert a new item below the current one.
function! tlib#agent#NewItem(world, selected) "{{{3
let basepi = a:world.GetBaseIdx(a:world.prefidx)
let item = input('New item: ')
call insert(a:world.base, item, basepi)
let a:world.state = 'reset'
return a:world
endf
function! tlib#agent#DeleteItems(world, selected) "{{{3
let remove = copy(a:world.sel_idx)
let basepi = a:world.GetBaseIdx(a:world.prefidx)
if index(remove, basepi) == -1
call add(remove, basepi)
endif
" call map(remove, 'a:world.GetBaseIdx(v:val)')
for idx in reverse(sort(remove))
call remove(a:world.base, idx - 1)
endfor
let a:world.state = 'display'
call a:world.ResetSelected()
" let a:world.state = 'reset'
return a:world
endf
function! tlib#agent#Cut(world, selected) "{{{3
let world = tlib#agent#Copy(a:world, a:selected)
return tlib#agent#DeleteItems(world, a:selected)
endf
function! tlib#agent#Copy(world, selected) "{{{3
let a:world.clipboard = []
let bidxs = copy(a:world.sel_idx)
call add(bidxs, a:world.GetBaseIdx(a:world.prefidx))
for bidx in sort(bidxs)
call add(a:world.clipboard, a:world.GetBaseItem(bidx))
endfor
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#Paste(world, selected) "{{{3
if has_key(a:world, 'clipboard')
for e in reverse(copy(a:world.clipboard))
call insert(a:world.base, e, a:world.prefidx)
endfor
endif
let a:world.state = 'display'
call a:world.ResetSelected()
return a:world
endf
function! tlib#agent#EditReturnValue(world, rv) "{{{3
return [a:world.state !~ '\<exit\>', a:world.base]
endf
" Files related {{{1
function! tlib#agent#ViewFile(world, selected) "{{{3
if !empty(a:selected)
let back = a:world.SwitchWindow('win')
" TLogVAR back
for filename in a:selected
call tlib#file#Edit(filename)
endfor
" if !&hidden && &l:modified
" let cmd0 = 'split'
" let cmd1 = 'sbuffer'
" else
" let cmd0 = 'edit'
" let cmd1 = 'buffer'
" endif
" call tlib#file#With(cmd0, cmd1, a:selected, a:world)
" TLogVAR &filetype
exec back
let a:world.state = 'display'
endif
return a:world
endf
function! tlib#agent#EditFile(world, selected) "{{{3
return tlib#agent#Exit(tlib#agent#ViewFile(a:world, a:selected), a:selected)
endf
function! tlib#agent#EditFileInSplit(world, selected) "{{{3
call a:world.CloseScratch()
" call tlib#file#With('edit', 'buffer', a:selected[0:0], a:world)
" call tlib#file#With('split', 'sbuffer', a:selected[1:-1], a:world)
call tlib#file#With('split', 'sbuffer', a:selected, a:world)
return tlib#agent#Exit(a:world, a:selected)
endf
function! tlib#agent#EditFileInVSplit(world, selected) "{{{3
call a:world.CloseScratch()
" call tlib#file#With('edit', 'buffer', a:selected[0:0], a:world)
" call tlib#file#With('vertical split', 'vertical sbuffer', a:selected[1:-1], a:world)
let winpos = tlib#fixes#Winpos()
call tlib#file#With('vertical split', 'vertical sbuffer', a:selected, a:world)
if !empty(winpos)
exec winpos
endif
return tlib#agent#Exit(a:world, a:selected)
endf
function! tlib#agent#EditFileInTab(world, selected) "{{{3
" TLogVAR a:selected
call a:world.CloseScratch()
call tlib#file#With('tabedit', 'tab sbuffer', a:selected, a:world)
return tlib#agent#Exit(a:world, a:selected)
endf
function! tlib#agent#ToggleScrollbind(world, selected) "{{{3
let a:world.scrollbind = get(a:world, 'scrollbind') ? 0 : 1
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#ShowInfo(world, selected)
let lines = []
for f in a:selected
if filereadable(f)
let desc = [getfperm(f), strftime('%c', getftime(f)), getfsize(f) .' bytes', getftype(f)]
call add(lines, fnamemodify(f, ':p'))
call add(lines, ' '. join(desc, '; '))
endif
endfor
let a:world.temp_lines = lines
let a:world.state = 'printlines'
return a:world
endf
" Buffer related {{{1
function! tlib#agent#PreviewLine(world, selected) "{{{3
let l = a:selected[0]
let ww = winnr()
exec a:world.win_wnr .'wincmd w'
call tlib#buffer#ViewLine(l, 1)
exec ww .'wincmd w'
let a:world.state = 'redisplay'
return a:world
endf
" If not called from the scratch, we assume/guess that we don't have to
" suspend the input-evaluation loop.
function! tlib#agent#GotoLine(world, selected) "{{{3
if !empty(a:selected)
" let l = a:selected[0]
" " TLogVAR l
" let back = a:world.SwitchWindow('win')
" " TLogVAR back
" " if a:world.win_wnr != winnr()
" " let world = tlib#agent#Suspend(a:world, a:selected)
" " exec a:world.win_wnr .'wincmd w'
" " endif
" call tlib#buffer#ViewLine(l)
" exec back
" let a:world.state = 'display'
let l = a:selected[0]
if a:world.win_wnr != winnr()
let world = tlib#agent#Suspend(a:world, a:selected)
exec a:world.win_wnr .'wincmd w'
endif
call tlib#buffer#ViewLine(l, 1)
endif
return a:world
endf
function! tlib#agent#DoAtLine(world, selected) "{{{3
if !empty(a:selected)
let cmd = input('Command: ', '', 'command')
if !empty(cmd)
call a:world.SwitchWindow('win')
" let pos = getpos('.')
let view = winsaveview()
for l in a:selected
call tlib#buffer#ViewLine(l, '')
exec cmd
endfor
" call setpos('.', pos)
call winrestview(view)
endif
endif
call a:world.ResetSelected()
let a:world.state = 'exit'
return a:world
endf
function! tlib#agent#Wildcard(world, selected) "{{{3
if !empty(a:world.filter[0])
let rx_type = a:world.matcher.FilterRxPrefix()
let flt0 = a:world.CleanFilter(a:world.filter[0][0])
if rx_type == '\V'
let flt0 .= '\.\{-}'
else
let flt0 .= '.\{-}'
endif
call a:world.SetFrontFilter(flt0)
endif
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#Null(world, selected) "{{{3
let a:world.state = 'redisplay'
return a:world
endf
function! tlib#agent#ExecAgentByName(world, selected) "{{{3
let s:agent_names_world = a:world
let agent_names = {'Help': 'tlib#agent#Help'}
for def in values(a:world.key_map[a:world.key_mode])
if has_key(def, 'help') && !empty(def.help) && has_key(def, 'agent') && !empty(def.agent)
let agent_names[def.help] = def.agent
endif
endfor
let s:agent_names = sort(keys(agent_names))
let command = input('Command: ', '', 'customlist,tlib#agent#CompleteAgentNames')
" TLogVAR command
if !has_key(agent_names, command)
" TLogVAR command
silent! let matches = filter(keys(agent_names), 'v:val =~ command')
" TLogVAR matches
if len(matches) == 1
let command = matches[0]
endif
endif
if has_key(agent_names, command)
let agent = agent_names[command]
return call(agent, [a:world, a:selected])
else
if !empty(command)
echohl WarningMsg
echom "Unknown command:" command
echohl NONE
sleep 1
endif
let a:world.state = 'display'
return a:world
endif
endf
function! tlib#agent#CompleteAgentNames(ArgLead, CmdLine, CursorPos)
let arglead = tolower(a:Arglead)
return filter(copy(s:agent_names), 'stridx(tolower(v:val), arglead) != -1')
endf
function! tlib#agent#Complete(world, selected) abort "{{{3
let rxprefix = a:world.matcher.FilterRxPrefix()
let flt = a:world.filter[0][0]
" TLogVAR flt
let fltrx = rxprefix . flt . '\m[^[:space:][:cntrl:][:punct:]<>*+?&~{}()\[\]\\/]\+'
let fltrx0 = '\m^' . fltrx
" TLogVAR fltrx, fltrx0
let words = {}
for item in a:world.list
let parts = split(item, '\ze'. fltrx)
" TLogVAR item, parts
for part in parts
let word = matchstr(part, fltrx0)
" TLogVAR part, word
if !empty(word)
let words[word] = 1
endif
endfor
endfor
" TLogVAR keys(words)
let completions = keys(words)
" let completions = filter(keys(words), 'matchstr(v:val, fltrx0)')
let completions = sort(completions, 's:SortCompletions')
let completions = tlib#list#Uniq(completions)
" TLogVAR 0, completions
while len(completions) > 1
let nchar = strwidth(completions[0]) - 1
let completions = map(completions, 'strpart(v:val, 0, nchar)')
" TLogVAR 'reduce', completions
let completions = tlib#list#Uniq(completions)
" TLogVAR 'unique', len(completions), completions
endwh
" TLogVAR 9, completions
if empty(completions)
let a:world.state = 'redisplay update'
else
let a:world.filter[0][0] = completions[0]
let a:world.state = 'display update'
endif
return a:world
endf
function! s:SortCompletions(a, b) abort "{{{3
let i1 = strwidth(a:a)
let i2 = strwidth(a:b)
return i2 - i1
endf

View File

@ -0,0 +1,338 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2016-06-06.
" @Revision: 267
" :def: function! tlib#arg#Get(n, var, ?default="", ?test='')
" Set a positional argument from a variable argument list.
" See tlib#string#RemoveBackslashes() for an example.
function! tlib#arg#Get(n, var, ...) "{{{3
let default = a:0 >= 1 ? a:1 : ''
let atest = a:0 >= 2 ? a:2 : ''
" TLogVAR default, atest
if !empty(atest)
let atest = ' && (a:'. a:n .' '. atest .')'
endif
let test = printf('a:0 >= %d', a:n) . atest
return printf('let %s = %s ? a:%d : %s', a:var, test, a:n, string(default))
endf
" :def: function! tlib#arg#Let(list, ?default='')
" Set a positional arguments from a variable argument list.
" See tlib#input#List() for an example.
function! tlib#arg#Let(list, ...) "{{{3
let default = a:0 >= 1 ? a:1 : ''
let list = map(copy(a:list), 'type(v:val) == 3 ? v:val : [v:val, default]')
let args = map(range(1, len(list)), 'call("tlib#arg#Get", [v:val] + list[v:val - 1])')
return join(args, ' | ')
endf
" :def: function! tlib#arg#StringAsKeyArgs(string, ?keys=[], ?evaluate=0, ?sep=':', ?booleans=0)
function! tlib#arg#StringAsKeyArgs(string, ...) "{{{1
TVarArg ['keys', {}], ['evaluate', 0], ['sep', ':'], ['booleans', 0]
let keyargs = {}
let args = split(a:string, '\\\@<! ')
let key_rx = booleans ? '\([-+]\?\w\+\)' : '\(\w\+\)'
let arglist = map(args, 'matchlist(v:val, ''^\%('. key_rx . sep .'\(.*\)\|\(.*\)\)$'')')
" TLogVAR a:string, args, arglist
let pos = -1
for matchlist in arglist
if !empty(matchlist[3])
if booleans && matchlist[3] =~ '^[-+]'
let key = substitute(matchlist[3], '^[-+]', '', '')
let val = matchstr(matchlist[3], '^[-+]')
let keyargs[key] = val ==# '+'
else
let pos += 1
let keyargs[pos] = matchlist[3]
endif
else
let [match, key, val; rest] = matchlist
if empty(keys) || has_key(keys, key)
let val = substitute(val, '\\\\', '\\', 'g')
if evaluate
let val = eval(val)
endif
let keyargs[key] = val
else
echom 'Unknown key: '. key .'='. val
endif
endif
endfor
if pos >= 0
let keyargs['__posargs__'] = range(0, pos)
endif
return keyargs
endf
function! tlib#arg#StringAsKeyArgsEqual(string) "{{{1
return tlib#arg#StringAsKeyArgs(a:string, [], 0, '=', 1)
endf
" :display: tlib#arg#GetOpts(args, ?def={})
" Convert a list of strings of command-line arguments into a dictonary.
"
" The main use case is to pass [<f-args>], i.e. the command-line
" arguments of a command as list, from a command definition to this
" function.
"
" Example:
" ['-h']
" => If def contains a 'help' key, invoke |:help| on its value.
"
" ['-ab', '--foo', '--bar=BAR', 'bla', bla']
" => {'a': 1, 'b': 1, 'foo': 1, 'bar': 'BAR', '__rest__': ['bla', 'bla']}
"
" ['-ab', '--', '--foo', '--bar=BAR']
" => {'a': 1, 'b': 1, '__rest__': ['--foo', '--bar=BAR']}
function! tlib#arg#GetOpts(args, ...) abort "{{{3
let throw = a:0 == 0
TVarArg ['def', {}]
" TLogVAR def
let opts = {'__exit__': 0}
for [key, vdef] in items(get(def, 'values', {}))
if has_key(vdef, 'default')
let opts[key] = vdef.default
endif
endfor
let idx = 0
for o in a:args
let [break, idx] = s:SetOpt(def, opts, idx, o)
if break == 1
break
elseif break == 2
if throw
throw 'tlib#arg#GetOpts: Show help'
else
let opts.__exit__ = 5
endif
endif
endfor
let opts.__rest__ = a:args[idx : -1]
return opts
endf
function! s:GetValueType(def) abort "{{{3
return get(a:def, 'type', type(get(a:def, 'default', '')))
endf
function! s:SetOpt(def, opts, idx, opt) abort "{{{3
" TLogVAR a:def
let idx = a:idx + 1
let break = 0
let long = get(a:def, 'long', 1)
let short = get(a:def, 'short', 1)
if (short && a:opt =~# '^-[?h]$') || (long && a:opt ==# '--help')
if has_key(a:def, 'help')
exec 'help' a:def.help
else
" TLogVAR a:def
let values = get(a:def, 'values', {})
let flags = get(a:def, 'flags', {})
if empty(values) && empty(flags)
echom 'No help'
else
if !empty(values)
echom 'Options:'
for [key, vdef] in sort(items(values))
let opt = key
let default = get(vdef, 'default', '')
let type = s:GetValueType(vdef)
if default =~ '^-\?\d\+\%(\.\d\+\)$'
if type == -1
let opt .= ' (flag)'
elseif type == 1
let opt .= '=INT'
else
let opt .= '=INT or maybe BOOL'
endif
elseif type(default) == 1
let opt .= '=STRING'
elseif type(default) == 3
let opt .= '=COMMA-LIST'
endif
echom printf(' --%20s (default: %s)', opt, string(default))
endfor
endif
if !empty(flags)
echom 'Short flags:'
for [sflag, lflag] in sort(items(flags))
echom printf(' -%s -> %s', sflag, lflag)
endfor
endif
endif
endif
let break = 2
elseif long && a:opt =~# '^--\%(no-\)\?debug$'
if has_key(a:def, 'trace')
let mod = a:opt =~# '--no-' ? '-' : '+'
exec 'Tlibtraceset' mod . a:def.trace
endif
elseif long && a:opt =~# '^--no-.\+'
let key = matchstr(a:opt, '^--no-\zs.\+$')
let a:opts[key] = s:Validate(a:def, key, 0)
elseif long && a:opt =~# '^--\w\+$'
let key = matchstr(a:opt, '^--\zs.\+$')
let a:opts[key] = s:Validate(a:def, key, 1)
elseif long && a:opt =~# '^--\w\+='
let ml = matchlist(a:opt, '^--\(\w\+\)=\(.*\)$')
if empty(ml)
throw 'tlib#arg#GetOpts: Cannot parse: '. a:opt
else
let values = get(a:def, 'values', {})
if has_key(values, ml[1])
let vdef = values[ml[1]]
let type = s:GetValueType(vdef)
if type == -1
let opt_value = !!str2nr(ml[2])
elseif type == 0
let opt_value = str2nr(ml[2])
elseif type == 1
let opt_value = ml[2]
elseif type == 2
let opt_value = function(ml[2])
elseif type == 3
let opt_value = tlib#string#SplitCommaList(ml[2])
elseif type == 4
throw 'tlib#arg#GetOpts: Unsupported type conversion for '. ml[1]
elseif type == 5
let opt_value = str2float(ml[2])
endif
else
let opt_value = ml[2]
endif
let a:opts[ml[1]] = s:Validate(a:def, ml[1], opt_value)
unlet opt_value
endif
elseif short && a:opt =~# '^-\w='
let flagdefs = get(a:def, 'flags', {})
let flag = matchstr(a:opt, '^-\zs\w')
let rest = matchstr(a:opt, '^-\w\zs.*$')
call s:SetFlag(a:def, a:opts, idx, flag, rest, flagdefs)
elseif short && a:opt =~# '^-\w\+$'
let flagdefs = get(a:def, 'flags', {})
for flag in split(substitute(a:opt, '^-', '', ''), '\zs')
call s:SetFlag(a:def, a:opts, idx, flag, '', flagdefs)
endfor
else
let break = 1
if a:opt !=# '--'
let idx -= 1
endif
endif
return [break, idx]
endf
function! s:SetFlag(def, opts, idx, flag, rest, flagdefs) abort "{{{3
" TLogVAR a:def
if has_key(a:flagdefs, a:flag)
call s:SetOpt(a:def, a:opts, a:idx, a:flagdefs[a:flag] . a:rest)
else
let a:opts[a:flag] = s:Validate(a:def, a:flag, 1)
endif
endf
function! s:Validate(def, name, value) abort "{{{3
let values = get(a:def, 'values', {})
if has_key(values, a:name)
let vdef = values[a:name]
if has_key(vdef, 'validate')
if !call(vdef.validate, [a:value])
throw printf('tlib#arg: %s has invalid value: %s', string(a:name), string(a:value))
endif
endif
endif
return a:value
endf
":nodoc:
function! tlib#arg#CComplete(def, ArgLead) abort "{{{3
let values = get(a:def, 'values', {})
let opt = matchstr(a:ArgLead, '^--\zs\w\+\ze=')
if has_key(values, opt)
let words = []
let vals = values[opt]
let complete_customlist = get(vals, 'complete_customlist', '')
if !empty(complete_customlist)
let words = eval(complete_customlist)
" else
" let complete = get(vals, 'complete', '')
" if !empty(complete)
" endif
endif
if !empty(words)
let prefix = matchstr(a:ArgLead, '^--\w\+=\%([^,]\+,\s*\)*')
let lead = substitute(a:ArgLead, '^--\w\+=\%([^,]\+,\s*\)*', '', '')
" TLogVAR a:ArgLead, lead
if !empty(lead)
let nchar = len(lead)
call filter(words, 'strpart(v:val, 0, nchar) ==# lead')
endif
let words = map(words, 'prefix . v:val')
return sort(words)
endif
endif
let cs = {'-h': 1, '--help': 1}
for [name, vdef] in items(values)
let type = s:GetValueType(vdef)
if type >= 0
let name .= '='
else
let cs['--no-'. name] = 1
endif
let cs['--'. name] = 1
endfor
for [name, subst] in items(get(a:def, 'flags', {}))
let ldef = get(values, substitute(subst, '^--', '', ''), {})
let type = s:GetValueType(ldef)
if type >= 0
let name .= '='
endif
let cs['-'. name] = 1
endfor
if has_key(a:def, 'trace')
let cs['--debug'] = 1
endif
let nchar = len(a:ArgLead)
if nchar > 0
call filter(cs, 'strpart(v:key, 0, nchar) ==# a:ArgLead')
endif
return sort(keys(cs))
endf
""" Command line {{{1
" :def: function! tlib#arg#Ex(arg, ?chars='%#! ')
" Escape some characters in a string.
"
" Use |fnamescape()| if available.
"
" EXAMPLES: >
" exec 'edit '. tlib#arg#Ex('foo%#bar.txt')
function! tlib#arg#Ex(arg, ...) "{{{3
if exists('*fnameescape') && a:0 == 0
return fnameescape(a:arg)
else
" let chars = '%# \'
let chars = '%#! '
if a:0 >= 1
let chars .= a:1
endif
return escape(a:arg, chars)
endif
endf

View File

@ -0,0 +1,44 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: https://github.com/tomtom
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2015-12-04
" @Revision: 41
" Enable tracing via |:Tlibassert|.
function! tlib#assert#Enable() abort "{{{3
" :nodoc:
command! -nargs=+ -bang Tlibassert call tlib#assert#Assert(expand('<sfile>'), <q-args>, [<args>])
endf
" Disable tracing via |:Tlibassert|.
function! tlib#assert#Disable() abort "{{{3
" :nodoc:
command! -nargs=+ -bang Tlibassert :
endf
function! tlib#assert#Assert(caller, check, vals) abort "{{{3
for val in a:vals
" TLogVAR val
if type(val) == 3
call tlib#assert#Assert(a:caller, a:check, val)
elseif !val
throw 'Tlibassert: '. tlib#trace#Backtrace(a:caller) .': '. a:check
endif
endfor
endf
function! tlib#assert#Map(vals, expr) abort "{{{3
return tlib#assert#All(map(a:vals, a:expr))
endf
function! tlib#assert#All(vals) abort "{{{3
" TLogVAR a:vals, empty(filter(a:vals, '!v:val'))
return empty(filter(a:vals, '!v:val'))
endf

View File

@ -0,0 +1,14 @@
" autocmdgroup.vim
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 7
augroup TLib
autocmd!
augroup END
function! tlib#autocmdgroup#Init() "{{{3
endf

View File

@ -0,0 +1,73 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @GIT: http://github.com/tomtom/tlib_vim/
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2010-08-30.
" @Last Change: 2015-11-23.
" @Revision: 48
function! tlib#balloon#Register(expr) "{{{3
if !has('balloon_eval')
return
endif
if !exists('b:tlib_balloons')
let b:tlib_balloons = []
endif
if !&ballooneval
setlocal ballooneval
endif
if &balloonexpr != 'tlib#balloon#Expr()'
if !empty(&balloonexpr)
call add(b:tlib_balloons, &balloonexpr)
endif
setlocal ballooneval balloonexpr=tlib#balloon#Expr()
endif
if index(b:tlib_balloons, a:expr) == -1
call add(b:tlib_balloons, a:expr)
endif
endf
function! tlib#balloon#Remove(expr) "{{{3
if exists('b:tlib_balloons')
call filter(b:tlib_balloons, 'v:val != a:expr')
if empty(b:tlib_balloons)
setlocal ballooneval&
setlocal balloonexpr&
unlet b:tlib_balloons
endif
endif
endf
function! tlib#balloon#Expr() "{{{3
" TLogVAR exists('b:tlib_balloons')
if !exists('b:tlib_balloons')
return ''
endif
let text = map(copy(b:tlib_balloons), 'eval(v:val)')
" TLogVAR b:tlib_balloons, text
call filter(text, '!empty(v:val)')
if has('balloon_multiline')
return join(text, "\n----------------------------------\n")
else
return get(text, 0, '')
endif
endf
function! tlib#balloon#Expand(expr) abort "{{{3
if v:beval_bufnr != bufnr('%')
" TLogVAR v:beval_bufnr, bufnr('%')
return ''
endif
let win = winsaveview()
try
call setpos('.', [v:beval_bufnr, v:beval_lnum, v:beval_col, 0])
return expand(a:expr)
finally
call winrestview(win)
endtry
endf

View File

@ -0,0 +1,141 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 124
function! tlib#bitwise#Num2Bits(num) "{{{3
if type(a:num) <= 1 || type(a:num) == 5
let bits = reverse(tlib#number#ConvertBase(a:num, 2, 'list'))
elseif type(a:num) == 3
let bits = copy(a:num)
else
throw "tlib#bitwise#Num2Bits: Must be number of list: ". string(a:num)
endif
return bits
endf
function! tlib#bitwise#Bits2Num(bits, ...) "{{{3
let base = a:0 >= 1 ? a:1 : 10
" TLogVAR a:bits
let num = 0.0
for i in range(len(a:bits))
if get(a:bits, i, 0)
let num += pow(2, i)
endif
endfor
" TLogVAR num
if base == 10
if type(base) == 5
return num
else
return float2nr(num)
endif
else
return tlib#number#ConvertBase(num, base)
endif
endf
function! tlib#bitwise#AND(num1, num2, ...) "{{{3
let rtype = a:0 >= 1 ? a:1 : 'num'
return s:BitwiseComparison(a:num1, a:num2, rtype,
\ 'get(bits1, v:val) && get(bits2, v:val)')
endf
function! tlib#bitwise#OR(num1, num2, ...) "{{{3
let rtype = a:0 >= 1 ? a:1 : 'num'
return s:BitwiseComparison(a:num1, a:num2, rtype,
\ 'get(bits1, v:val) || get(bits2, v:val)')
endf
function! tlib#bitwise#XOR(num1, num2, ...) "{{{3
let rtype = a:0 >= 1 ? a:1 : 'num'
return s:BitwiseComparison(a:num1, a:num2, rtype,
\ 'get(bits1, v:val) ? !get(bits2, v:val) : get(bits2, v:val)')
endf
function! s:BitwiseComparison(num1, num2, rtype, expr) "{{{3
let bits1 = tlib#bitwise#Num2Bits(a:num1)
let bits2 = tlib#bitwise#Num2Bits(a:num2)
let range = range(max([len(bits1), len(bits2)]))
let bits = map(range, a:expr)
if a:rtype == 'num' || (a:rtype == 'auto' && type(a:num1) <= 1)
return tlib#bitwise#Bits2Num(bits)
else
return bits
endif
endf
function! tlib#bitwise#ShiftRight(bits, n) "{{{3
let bits = a:bits[a:n : -1]
if empty(bits)
let bits = [0]
endif
return bits
endf
function! tlib#bitwise#ShiftLeft(bits, n) "{{{3
let bits = repeat([0], a:n) + a:bits
return bits
endf
function! tlib#bitwise#Add(num1, num2, ...) "{{{3
let rtype = a:0 >= 1 ? a:1 : 'num'
let bits1 = tlib#bitwise#Num2Bits(a:num1)
let bits2 = tlib#bitwise#Num2Bits(a:num2)
let range = range(max([len(bits1), len(bits2)]))
" TLogVAR bits1, bits2, range
let carry = 0
let bits = []
for i in range
let sum = get(bits1, i) + get(bits2, i) + carry
if sum == 3
let bit = 1
let carry = 1
elseif sum == 2
let bit = 0
let carry = 1
elseif sum == 1
let bit = 1
let carry = 0
elseif sum == 0
let bit = 0
let carry = 0
endif
call add(bits, bit)
" TLogVAR i, bits, bit
endfor
if carry == 1
call add(bits, carry)
endif
if rtype == 'num' || (rtype == 'auto' && type(a:num1) <= 1)
return tlib#bitwise#Bits2Num(bits)
else
return bits
endif
endf
function! tlib#bitwise#Sub(num1, num2, ...) "{{{3
let rtype = a:0 >= 1 ? a:1 : 'num'
let bits1 = tlib#bitwise#Num2Bits(a:num1)
let bits2 = tlib#bitwise#Num2Bits(a:num2)
let range = range(max([len(bits1), len(bits2)]))
let bits2 = map(range, '!get(bits2, v:val)')
let bits2 = tlib#bitwise#Add(bits2, [1], 'bits')
let bits3 = tlib#bitwise#Add(bits1, bits2, 'bits')
let bits = bits3[0 : -2]
if rtype == 'num' || (rtype == 'auto' && type(a:num1) <= 1)
return tlib#bitwise#Bits2Num(bits)
else
return bits
endif
endf

View File

@ -0,0 +1,401 @@
" buffer.vim
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2007-06-30.
" @Last Change: 2015-11-06.
" @Revision: 7.1.352
" Where to display the line when using |tlib#buffer#ViewLine|.
" For possible values for position see |scroll-cursor|.
TLet g:tlib_viewline_position = 'zz'
let s:bmru = []
function! tlib#buffer#EnableMRU() "{{{3
call tlib#autocmdgroup#Init()
autocmd TLib BufEnter * call s:BMRU_Push(bufnr('%'))
endf
function! tlib#buffer#DisableMRU() "{{{3
call tlib#autocmdgroup#Init()
autocmd! TLib BufEnter
endf
function! s:BMRU_Push(bnr) "{{{3
let i = index(s:bmru, a:bnr)
if i >= 0
call remove(s:bmru, i)
endif
call insert(s:bmru, a:bnr)
endf
function! s:CompareBuffernameByBasename(a, b) "{{{3
let rx = '"\zs.\{-}\ze" \+\S\+ \+\d\+$'
let an = matchstr(a:a, rx)
let an = fnamemodify(an, ':t')
let bn = matchstr(a:b, rx)
let bn = fnamemodify(bn, ':t')
let rv = an == bn ? 0 : an > bn ? 1 : -1
return rv
endf
function! s:CompareBufferNrByMRU(a, b) "{{{3
let an = matchstr(a:a, '\s*\zs\d\+\ze')
let bn = matchstr(a:b, '\s*\zs\d\+\ze')
let ai = index(s:bmru, 0 + an)
if ai == -1
return 1
else
let bi = index(s:bmru, 0 + bn)
if bi == -1
return -1
else
return ai == bi ? 0 : ai > bi ? 1 : -1
endif
endif
endf
" Set the buffer to buffer and return a command as string that can be
" evaluated by |:execute| in order to restore the original view.
function! tlib#buffer#Set(buffer) "{{{3
let lazyredraw = &lazyredraw
set lazyredraw
try
let cb = bufnr('%')
let sn = bufnr(a:buffer)
if sn != cb
let ws = bufwinnr(sn)
if ws != -1
let wb = bufwinnr('%')
exec ws.'wincmd w'
return wb.'wincmd w'
else
silent exec 'sbuffer! '. sn
return 'wincmd c'
endif
else
return ''
endif
finally
let &lazyredraw = lazyredraw
endtry
endf
" :def: function! tlib#buffer#Eval(buffer, code)
" Evaluate CODE in BUFFER.
"
" EXAMPLES: >
" call tlib#buffer#Eval('foo.txt', 'echo b:bar')
function! tlib#buffer#Eval(buffer, code) "{{{3
" let cb = bufnr('%')
" let wb = bufwinnr('%')
" " TLogVAR cb
" let sn = bufnr(a:buffer)
" let sb = sn != cb
let lazyredraw = &lazyredraw
set lazyredraw
let restore = tlib#buffer#Set(a:buffer)
try
exec a:code
" if sb
" let ws = bufwinnr(sn)
" if ws != -1
" try
" exec ws.'wincmd w'
" exec a:code
" finally
" exec wb.'wincmd w'
" endtry
" else
" try
" silent exec 'sbuffer! '. sn
" exec a:code
" finally
" wincmd c
" endtry
" endif
" else
" exec a:code
" endif
finally
exec restore
let &lazyredraw = lazyredraw
endtry
endf
" :def: function! tlib#buffer#GetList(?show_hidden=0, ?show_number=0, " ?order='bufnr')
" Possible values for the "order" argument:
" bufnr :: Default behaviour
" mru :: Sort buffers according to most recent use
" basename :: Sort by the file's basename (last component)
"
" NOTE: MRU order works on second invocation only. If you want to always
" use MRU order, call tlib#buffer#EnableMRU() in your ~/.vimrc file.
function! tlib#buffer#GetList(...)
TVarArg ['show_hidden', 0], ['show_number', 0], ['order', '']
" TLogVAR show_hidden, show_number, order
let ls_bang = show_hidden ? '!' : ''
redir => bfs
exec 'silent ls'. ls_bang
redir END
let buffer_list = split(bfs, '\n')
if order == 'mru'
if empty(s:bmru)
call tlib#buffer#EnableMRU()
echom 'tlib: Installed Buffer MRU logger; disable with: call tlib#buffer#DisableMRU()'
else
call sort(buffer_list, function('s:CompareBufferNrByMRU'))
endif
elseif order == 'basename'
call sort(buffer_list, function('s:CompareBuffernameByBasename'))
endif
let buffer_nr = map(copy(buffer_list), 'str2nr(matchstr(v:val, ''\s*\zs\d\+\ze''))')
" TLogVAR buffer_list, buffer_nr
if show_number
call map(buffer_list, 'matchstr(v:val, ''^\s*\d\+.\{-}\ze\s\+\S\+ \d\+\s*$'')')
else
call map(buffer_list, 'matchstr(v:val, ''^\s*\d\+\zs.\{-}\ze\s\+\S\+ \d\+\s*$'')')
endif
" TLogVAR buffer_list
" call map(buffer_list, 'matchstr(v:val, ''^.\{-}\ze\s\+line \d\+\s*$'')')
" TLogVAR buffer_list
call map(buffer_list, 'matchstr(v:val, ''^[^"]\+''). printf("%-20s %s", fnamemodify(matchstr(v:val, ''"\zs.\{-}\ze"$''), ":t"), fnamemodify(matchstr(v:val, ''"\zs.\{-}\ze"$''), ":h"))')
" TLogVAR buffer_list
return [buffer_nr, buffer_list]
endf
" :def: function! tlib#buffer#ViewLine(line, ?position='z')
" line is either a number or a string that begins with a number.
" For possible values for position see |scroll-cursor|.
" See also |g:tlib_viewline_position|.
function! tlib#buffer#ViewLine(line, ...) "{{{3
if a:line
TVarArg 'pos'
let ln = matchstr(a:line, '^\d\+')
let lt = matchstr(a:line, '^\d\+: \zs.*')
" TLogVAR pos, ln, lt
exec ln
if empty(pos)
let pos = tlib#var#Get('tlib_viewline_position', 'wbg')
endif
" TLogVAR pos
if !empty(pos)
exec 'norm! '. pos
endif
call tlib#buffer#HighlightLine(ln)
" let @/ = '\%'. ln .'l.*'
endif
endf
function! s:UndoHighlightLine() "{{{3
2match none
autocmd! TLib CursorMoved,CursorMovedI <buffer>
autocmd! TLib CursorHold,CursorHoldI <buffer>
autocmd! TLib InsertEnter,InsertChange,InsertLeave <buffer>
autocmd! TLib BufLeave,BufWinLeave,WinLeave,BufHidden <buffer>
endf
function! tlib#buffer#HighlightLine(...) "{{{3
TVarArg ['line', line('.')]
" exec '2match MatchParen /^\%'. a:line .'l.*/'
exec '2match Search /^\%'. line .'l.*/'
call tlib#autocmdgroup#Init()
exec 'autocmd TLib CursorMoved,CursorMovedI <buffer> if line(".") != '. line .' | call s:UndoHighlightLine() | endif'
autocmd TLib CursorHold,CursorHoldI <buffer> call s:UndoHighlightLine()
autocmd TLib InsertEnter <buffer> call s:UndoHighlightLine()
" autocmd TLib BufLeave,BufWinLeave,WinLeave,BufHidden <buffer> call s:UndoHighlightLine()
endf
" Delete the lines in the current buffer. Wrapper for |:delete|.
function! tlib#buffer#DeleteRange(line1, line2) "{{{3
let r = @t
try
exec a:line1.','.a:line2.'delete t'
finally
let @t = r
endtry
endf
" Replace a range of lines.
function! tlib#buffer#ReplaceRange(line1, line2, lines)
call tlib#buffer#DeleteRange(a:line1, a:line2)
call append(a:line1 - 1, a:lines)
endf
" Initialize some scratch area at the bottom of the current buffer.
function! tlib#buffer#ScratchStart() "{{{3
norm! Go
let b:tlib_inbuffer_scratch = line('$')
return b:tlib_inbuffer_scratch
endf
" Remove the in-buffer scratch area.
function! tlib#buffer#ScratchEnd() "{{{3
if !exists('b:tlib_inbuffer_scratch')
echoerr 'tlib: In-buffer scratch not initalized'
endif
call tlib#buffer#DeleteRange(b:tlib_inbuffer_scratch, line('$'))
unlet b:tlib_inbuffer_scratch
endf
" Run exec on all buffers via bufdo and return to the original buffer.
function! tlib#buffer#BufDo(exec) "{{{3
let bn = bufnr('%')
exec 'bufdo '. a:exec
exec 'buffer! '. bn
endf
" :def: function! tlib#buffer#InsertText(text, keyargs)
" Keyargs:
" 'shift': 0|N
" 'col': col('.')|N
" 'lineno': line('.')|N
" 'indent': 0|1
" 'pos': 'e'|'s' ... Where to locate the cursor (somewhat like s and e in {offset})
" Insert text (a string) in the buffer.
function! tlib#buffer#InsertText(text, ...) "{{{3
TVarArg ['keyargs', {}]
" TLogVAR a:text, keyargs
let keyargs = extend({
\ 'shift': 0, 'col': col('.'), 'lineno': line('.'), 'pos': 'e', 'indent': 0
\ }, keyargs)
" TLogVAR keyargs
let grow = 0
let post_del_last_line = line('$') == 1
let line = getline(keyargs.lineno)
if keyargs.col + keyargs.shift > 0
let pre = line[0 : (keyargs.col - 1 + keyargs.shift)]
let post = line[(keyargs.col + keyargs.shift): -1]
else
let pre = ''
let post = line
endif
" TLogVAR keyargs.lineno, line, pre, post
let text0 = pre . a:text . post
let text = split(text0, '\n', 1)
" TLogVAR text
let icol = len(pre)
" exec 'norm! '. keyargs.lineno .'G'
call cursor(keyargs.lineno, keyargs.col)
if keyargs.indent && keyargs.col > 1
if &fo =~# '[or]'
" FIXME: Is the simple version sufficient?
" VERSION 1
" " This doesn't work because it's not guaranteed that the
" " cursor is set.
" let cline = getline('.')
" norm! a
" "norm! o
" " TAssertExec redraw | sleep 3
" let idt = strpart(getline('.'), 0, keyargs.col('.') + keyargs.shift)
" " TLogVAR idt
" let idtl = len(idt)
" -1,.delete
" " TAssertExec redraw | sleep 3
" call append(keyargs.lineno - 1, cline)
" call cursor(keyargs.lineno, keyargs.col)
" " TAssertExec redraw | sleep 3
" if idtl == 0 && icol != 0
" let idt = matchstr(pre, '^\s\+')
" let idtl = len(idt)
" endif
" VERSION 2
let idt = matchstr(pre, '^\s\+')
let idtl = len(idt)
else
let [m_0, idt, iline; rest] = matchlist(pre, '^\(\s*\)\(.*\)$')
let idtl = len(idt)
endif
if idtl < icol
let idt .= repeat(' ', icol - idtl)
endif
" TLogVAR idt
let idtl1 = len(idt)
for i in range(1, len(text) - 1)
let text[i] = idt . text[i]
let grow += idtl1
endfor
endif
" TLogVAR text
" exec 'norm! '. keyargs.lineno .'Gdd'
call tlib#normal#WithRegister('"tdd', 't')
call append(keyargs.lineno - 1, text)
if post_del_last_line
call tlib#buffer#KeepCursorPosition('$delete')
endif
let tlen = len(text)
let posshift = matchstr(keyargs.pos, '\d\+')
" TLogVAR keyargs.pos
if keyargs.pos =~ '^e'
exec keyargs.lineno + tlen - 1
exec 'norm! 0'. (len(text[-1]) - len(post) + posshift - 1) .'l'
elseif keyargs.pos =~ '^s'
" TLogVAR keyargs.lineno, pre, posshift
exec keyargs.lineno
exec 'norm! '. len(pre) .'|'
if !empty(posshift)
exec 'norm! '. posshift .'h'
endif
endif
" TLogDBG getline(keyargs.lineno)
" TLogDBG string(getline(1, '$'))
return grow
endf
function! tlib#buffer#InsertText0(text, ...) "{{{3
TVarArg ['keyargs', {}]
let mode = get(keyargs, 'mode', 'i')
" TLogVAR mode
if !has_key(keyargs, 'shift')
let col = col('.')
" if mode =~ 'i'
" let col += 1
" endif
let keyargs.shift = col >= col('$') ? 0 : -1
" let keyargs.shift = col('.') >= col('$') ? 0 : -1
" TLogVAR col
" TLogDBG col('.') .'-'. col('$') .': '. string(getline('.'))
endif
" TLogVAR keyargs.shift
return tlib#buffer#InsertText(a:text, keyargs)
endf
function! tlib#buffer#CurrentByte() "{{{3
return line2byte(line('.')) + col('.')
endf
" Evaluate cmd while maintaining the cursor position and jump registers.
function! tlib#buffer#KeepCursorPosition(cmd) "{{{3
" let pos = getpos('.')
let view = winsaveview()
try
keepjumps exec a:cmd
finally
" call setpos('.', pos)
call winrestview(view)
endtry
endf

View File

@ -0,0 +1,360 @@
" cache.vim
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2007-06-30.
" @Last Change: 2015-11-26.
" @Revision: 35.1.243
" The cache directory. If empty, use |tlib#dir#MyRuntime|.'/cache'.
" You might want to delete old files from this directory from time to
" time with a command like: >
" find ~/vimfiles/cache/ -atime +31 -type f -print -delete
TLet g:tlib_cache = ''
" |tlib#cache#Purge()|: Remove cache files older than N days.
TLet g:tlib#cache#purge_days = 31
" Purge the cache every N days. Disable automatic purging by setting
" this value to a negative value.
TLet g:tlib#cache#purge_every_days = 31
" The encoding used for the purge-cache script.
" Default: 'enc'
TLet g:tlib#cache#script_encoding = &enc
" Whether to run the directory removal script:
" 0 ... No
" 1 ... Query user
" 2 ... Yes
TLet g:tlib#cache#run_script = 1
" Verbosity level:
" 0 ... Be quiet
" 1 ... Display informative message
" 2 ... Display detailed messages
TLet g:tlib#cache#verbosity = 1
" A list of regexps that are matched against partial filenames of the
" cached files. If a regexp matches, the file won't be removed by
" |tlib#cache#Purge()|.
TLet g:tlib#cache#dont_purge = ['[\/]\.last_purge$']
" If the cache filename is longer than N characters, use
" |pathshorten()|.
TLet g:tlib#cache#max_filename = 200
let s:cache = {}
" :display: tlib#cache#Dir(?mode = 'bg')
" The default cache directory.
function! tlib#cache#Dir(...) "{{{3
TVarArg ['mode', 'bg']
let dir = tlib#var#Get('tlib_cache', mode)
if empty(dir)
let dir = tlib#file#Join([tlib#dir#MyRuntime(), 'cache'])
endif
return dir
endf
" :def: function! tlib#cache#Filename(type, ?file=%, ?mkdir=0, ?dir='')
function! tlib#cache#Filename(type, ...) "{{{3
" TLogDBG 'bufname='. bufname('.')
let dir0 = a:0 >= 3 && !empty(a:3) ? a:3 : tlib#cache#Dir()
let dir = dir0
if a:0 >= 1 && !empty(a:1)
let file = a:1
else
if empty(expand('%:t'))
return ''
endif
let file = expand('%:p')
let file = tlib#file#Relative(file, tlib#file#Join([dir, '..']))
endif
" TLogVAR file, dir
let mkdir = a:0 >= 2 ? a:2 : 0
let file = substitute(file, '\.\.\|[:&<>]\|//\+\|\\\\\+', '_', 'g')
let dirs = [dir, a:type]
let dirf = fnamemodify(file, ':h')
if dirf != '.'
call add(dirs, dirf)
endif
let dir = tlib#file#Join(dirs)
" TLogVAR dir
let dir = tlib#dir#PlainName(dir)
" TLogVAR dir
let file = fnamemodify(file, ':t')
" TLogVAR file, dir, mkdir
let cache_file = tlib#file#Join([dir, file])
if len(cache_file) > g:tlib#cache#max_filename
if v:version >= 704
let shortfilename = pathshorten(file) .'_'. sha256(file)
else
let shortfilename = pathshorten(file) .'_'. tlib#hash#Adler32(file)
endif
let cache_file = tlib#cache#Filename(a:type, shortfilename, mkdir, dir0)
else
if mkdir && !isdirectory(dir)
try
call mkdir(dir, 'p')
catch /^Vim\%((\a\+)\)\=:E739:/
if filereadable(dir) && !isdirectory(dir)
echoerr 'TLib: Cannot create directory for cache file because a file with the same name exists (please delete it):' dir
" call delete(dir)
" call mkdir(dir, 'p')
endif
endtry
endif
endif
" TLogVAR cache_file
return cache_file
endf
let s:timestamps = {}
function! s:SetTimestamp(cfile, type) "{{{3
if !has_key(s:timestamps, a:cfile)
let s:timestamps[a:cfile] = {}
endif
let s:timestamps[a:cfile].atime = getftime(a:cfile)
let s:timestamps[a:cfile][a:type] = s:timestamps[a:cfile].atime
endf
function! tlib#cache#Save(cfile, dictionary, ...) "{{{3
TVarArg ['options', {}]
let in_memory = get(options, 'in_memory', 0)
if in_memory
" TLogVAR in_memory, a:cfile, localtime()
let s:cache[a:cfile] = {'mtime': localtime(), 'data': a:dictionary}
elseif !empty(a:cfile)
" TLogVAR a:dictionary
call writefile([string(a:dictionary)], a:cfile, 'b')
call s:SetTimestamp(a:cfile, 'write')
endif
endf
function! tlib#cache#MTime(cfile) "{{{3
let mtime = {'mtime': getftime(a:cfile)}
let mtime = extend(mtime, get(s:timestamps, a:cfile, {}))
return mtime
endf
function! tlib#cache#Get(cfile, ...) "{{{3
TVarArg ['default', {}], ['options', {}]
let in_memory = get(options, 'in_memory', 0)
if in_memory
" TLogVAR in_memory, a:cfile
return get(get(s:cache, a:cfile, {}), 'data', default)
else
call tlib#cache#MaybePurge()
if !empty(a:cfile) && filereadable(a:cfile)
let val = readfile(a:cfile, 'b')
call s:SetTimestamp(a:cfile, 'read')
return eval(join(val, "\n"))
else
return default
endif
endif
endf
" :display: tlib#cache#Value(cfile, generator, ftime, ?generator_args=[], ?options={})
" Get a cached value from cfile. If it is outdated (compared to ftime)
" or does not exist, create it calling a generator function.
function! tlib#cache#Value(cfile, generator, ftime, ...) "{{{3
TVarArg ['args', []], ['options', {}]
let in_memory = get(options, 'in_memory', 0)
if in_memory
let not_found = !has_key(s:cache, a:cfile)
let cftime = not_found ? -1 : s:cache[a:cfile].mtime
else
let cftime = getftime(a:cfile)
endif
" TLogVAR in_memory, cftime
if cftime == -1 || (a:ftime != 0 && cftime < a:ftime)
" TLogVAR a:generator, args
let val = call(a:generator, args)
" TLogVAR val
let cval = {'val': val}
" TLogVAR cval
call tlib#cache#Save(a:cfile, cval, options)
return val
else
let val = tlib#cache#Get(a:cfile, {}, options)
if !has_key(val, 'val')
throw 'tlib#cache#Value: Internal error: '. a:cfile
else
return val.val
endif
endif
endf
" Call |tlib#cache#Purge()| if the last purge was done before
" |g:tlib#cache#purge_every_days|.
function! tlib#cache#MaybePurge() "{{{3
if g:tlib#cache#purge_every_days < 0
return
endif
let dir = tlib#cache#Dir('g')
let last_purge = tlib#file#Join([dir, '.last_purge'])
let last_purge_exists = filereadable(last_purge)
if last_purge_exists
let threshold = localtime() - g:tlib#cache#purge_every_days * g:tlib#date#dayshift
let should_purge = getftime(last_purge) < threshold
else
let should_purge = 0 " should ignore empty dirs, like the tmru one: !empty(glob(tlib#file#Join([dir, '**'])))
endif
if should_purge
if last_purge_exists
let yn = 'y'
else
let txt = "TLib: The cache directory '". dir ."' should be purged of old files.\nDelete files older than ". g:tlib#cache#purge_days ." days now?"
let yn = tlib#input#Dialog(txt, ['yes', 'no'], 'no')
endif
if yn =~ '^y\%[es]$'
call tlib#cache#Purge()
else
let g:tlib#cache#purge_every_days = -1
if !last_purge_exists
call s:PurgeTimestamp(dir)
endif
echohl WarningMsg
echom "TLib: Please run :call tlib#cache#Purge() to clean up ". dir
echohl NONE
endif
elseif !last_purge_exists
call s:PurgeTimestamp(dir)
endif
endf
" Delete old files.
function! tlib#cache#Purge() "{{{3
let threshold = localtime() - g:tlib#cache#purge_days * g:tlib#date#dayshift
let dir = tlib#cache#Dir('g')
if g:tlib#cache#verbosity >= 1
echohl WarningMsg
echom "TLib: Delete files older than ". g:tlib#cache#purge_days ." days from ". dir
echohl NONE
endif
let files = tlib#cache#ListFilesInCache()
let deldir = []
let newer = []
let msg = []
let more = &more
set nomore
try
for file in files
if isdirectory(file)
if empty(filter(copy(newer), 'strpart(v:val, 0, len(file)) ==# file'))
call add(deldir, file)
endif
else
if getftime(file) < threshold
if delete(file)
call add(msg, "TLib: Could not delete cache file: ". file)
elseif g:tlib#cache#verbosity >= 2
call add(msg, "TLib: Delete cache file: ". file)
endif
else
call add(newer, file)
endif
endif
endfor
finally
let &more = more
endtry
if !empty(msg) && g:tlib#cache#verbosity >= 1
echo join(msg, "\n")
endif
if !empty(deldir)
if &shell =~ 'sh\(\.exe\)\?$'
let scriptfile = 'deldir.sh'
let rmdir = 'rm -rf %s'
else
let scriptfile = 'deldir.bat'
let rmdir = 'rmdir /S /Q %s'
endif
let enc = g:tlib#cache#script_encoding
if has('multi_byte') && enc != &enc
call map(deldir, 'iconv(v:val, &enc, enc)')
endif
let scriptfile = tlib#file#Join([dir, scriptfile])
if filereadable(scriptfile)
let script = readfile(scriptfile)
else
let script = []
endif
let script += map(copy(deldir), 'printf(rmdir, shellescape(v:val, 1))')
let script = tlib#list#Uniq(script)
call writefile(script, scriptfile)
call inputsave()
if g:tlib#cache#run_script == 0
if g:tlib#cache#verbosity >= 1
echohl WarningMsg
if g:tlib#cache#verbosity >= 2
echom "TLib: Purged cache. Need to run script to delete directories"
endif
echom "TLib: Please review and execute: ". scriptfile
echohl NONE
endif
else
try
let yn = g:tlib#cache#run_script == 2 ? 'y' : tlib#input#Dialog("TLib: About to delete directories by means of a shell script.\nDirectory removal script: ". scriptfile ."\nRun script to delete directories now?", ['yes', 'no', 'edit'], 'no')
if yn =~ '^y\%[es]$'
exec 'silent cd '. fnameescape(dir)
exec '! ' &shell shellescape(scriptfile, 1)
exec 'silent cd -'
call delete(scriptfile)
elseif yn =~ '^e\%[dit]$'
exec 'edit '. fnameescape(scriptfile)
endif
finally
call inputrestore()
endtry
endif
endif
call s:PurgeTimestamp(dir)
endf
function! s:PurgeTimestamp(dir) "{{{3
let last_purge = tlib#file#Join([a:dir, '.last_purge'])
" TLogVAR last_purge
call writefile([" "], last_purge)
endf
function! tlib#cache#ListFilesInCache(...) "{{{3
let dir = a:0 >= 1 ? a:1 : tlib#cache#Dir('g')
if v:version > 702 || (v:version == 702 && has('patch51'))
let filess = glob(tlib#file#Join([dir, '**']), 1)
else
let filess = glob(tlib#file#Join([dir, '**']))
endif
let files = reverse(split(filess, '\n'))
let pos0 = len(tlib#dir#CanonicName(dir))
call filter(files, 's:ShouldPurge(strpart(v:val, pos0))')
return files
endf
function! s:ShouldPurge(partial_filename) "{{{3
" TLogVAR a:partial_filename
for rx in g:tlib#cache#dont_purge
if a:partial_filename =~ rx
" TLogVAR a:partial_filename, rx
return 0
endif
endfor
return 1
endf

View File

@ -0,0 +1,59 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 38
" :def: function! tlib#char#Get(?timeout=0)
" Get a character.
"
" EXAMPLES: >
" echo tlib#char#Get()
" echo tlib#char#Get(5)
function! tlib#char#Get(...) "{{{3
TVarArg ['timeout', 0], ['resolution', 0], ['getmod', 0]
let char = -1
let mode = 0
if timeout == 0 || !has('reltime')
let char = getchar()
else
let char = tlib#char#GetWithTimeout(timeout, resolution)
endif
if getmod
if char != -1
let mode = getcharmod()
endif
return [char, mode]
else
return char
endif
endf
function! tlib#char#IsAvailable() "{{{3
let ch = getchar(1)
return type(ch) == 0 && ch != 0
endf
function! tlib#char#GetWithTimeout(timeout, ...) "{{{3
TVarArg ['resolution', 2]
" TLogVAR a:timeout, resolution
let start = tlib#time#MSecs()
while 1
let c = getchar(0)
if type(c) != 0 || c != 0
return c
else
let now = tlib#time#MSecs()
let diff = tlib#time#DiffMSecs(now, start, resolution)
" TLogVAR diff
if diff > a:timeout
return -1
endif
endif
endwh
return -1
endf

View File

@ -0,0 +1,117 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 58
let g:tlib#cmd#last_output = []
function! tlib#cmd#OutputAsList(command) "{{{3
" TLogVAR a:command
if exists('s:redir_lines')
redir END
let cache = s:redir_lines
endif
let s:redir_lines = ''
redir =>> s:redir_lines
silent! exec a:command
redir END
let g:tlib#cmd#last_output = split(s:redir_lines, '\n')
unlet s:redir_lines
if exists('cache')
let s:redir_lines = cache
redir =>> s:redir_lines
endif
return g:tlib#cmd#last_output
endf
" See |:TBrowseOutput|.
function! tlib#cmd#BrowseOutput(command) "{{{3
call tlib#cmd#BrowseOutputWithCallback("tlib#cmd#DefaultBrowseOutput", a:command)
endf
" :def: function! tlib#cmd#BrowseOutputWithCallback(callback, command)
" Execute COMMAND and present its output in a |tlib#input#List()|;
" when a line is selected, execute the function named as the CALLBACK
" and pass in that line as an argument.
"
" The CALLBACK function gives you an opportunity to massage the COMMAND output
" and possibly act on it in a meaningful way. For example, if COMMAND listed
" all URIs found in the current buffer, CALLBACK could validate and then open
" the selected URI in the system's default browser.
"
" This function is meant to be a tool to help compose the implementations of
" powerful commands that use |tlib#input#List()| as a common interface. See
" |TBrowseScriptnames| as an example.
"
" EXAMPLES: >
" call tlib#cmd#BrowseOutputWithCallback('tlib#cmd#ParseScriptname', 'scriptnames')
function! tlib#cmd#BrowseOutputWithCallback(callback, command) "{{{3
let list = tlib#cmd#OutputAsList(a:command)
let cmds = tlib#input#List('m', 'Output of: '. a:command, list)
if !empty(cmds)
for cmd in cmds
let Callback = function(a:callback)
call call(Callback, [cmd])
endfor
endif
endf
function! tlib#cmd#DefaultBrowseOutput(cmd) "{{{3
call feedkeys(':'. a:cmd)
endf
function! tlib#cmd#ParseScriptname(line) "{{{3
" let parsedValue = substitute(a:line, '^.\{-}\/', '/', '')
let parsedValue = matchstr(a:line, '^\s*\d\+:\s*\zs.*$')
exe 'drop '. fnameescape(parsedValue)
endf
function! tlib#cmd#TBrowseScriptnames() abort "{{{3
call tlib#cmd#BrowseOutputWithCallback("tlib#cmd#ParseScriptname", "scriptnames")
endf
" :def: function! tlib#cmd#UseVertical(?rx='')
" Look at the history whether the command was called with vertical. If
" an rx is provided check first if the last entry in the history matches
" this rx.
function! tlib#cmd#UseVertical(...) "{{{3
TVarArg ['rx']
let h0 = histget(':')
let rx0 = '\C\<vert\%[ical]\>\s\+'
if !empty(rx)
let rx0 .= '.\{-}'.rx
endif
" TLogVAR h0, rx0
return h0 =~ rx0
endf
" Print the time in seconds or milliseconds (if your version of VIM
" has |+reltime|) a command takes.
function! tlib#cmd#Time(cmd) "{{{3
if has('reltime')
let start = tlib#time#Now()
exec a:cmd
let end = tlib#time#Now()
let diff = string(tlib#time#Diff(end, start)) .'ms'
else
let start = localtime()
exec a:cmd
let diff = (localtime() - start) .'s'
endif
echom 'Time: '. diff .': '. a:cmd
endf
function! tlib#cmd#Capture(cmd) "{{{3
redir => s
silent exec a:cmd
redir END
return s
endf

View File

@ -0,0 +1,26 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 25
" function! tlib#comments#Comments(?rx='')
function! tlib#comments#Comments(...)
TVarArg ['rx', '']
let comments = {}
let co = &comments
while !empty(co)
" TLogVAR co
let [m_0, m_key, m_val, m_val1, co0, co; rest] = matchlist(co, '^\([^:]*\):\(\(\\.\|[^,]*\)\+\)\(,\(.*\)$\|$\)')
" TLogVAR m_key, m_val, co
if empty(m_key)
let m_key = ':'
endif
if empty(rx) || m_key =~ rx
let comments[m_key] = m_val
endif
endwh
return comments
endf

View File

@ -0,0 +1,189 @@
" date.vim
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2010-03-25.
" @Last Change: 2016-06-06.
" @Revision: 41.0.34
if !exists('g:tlib#date#ShortDatePrefix') | let g:tlib#date#ShortDatePrefix = '20' | endif "{{{2
if !exists('g:tlib#date#TimeZoneShift') | let g:tlib#date#TimeZoneShift = 0 | endif "{{{2
let g:tlib#date#dayshift = 60 * 60 * 24
" let g:tlib#date#date_rx = '\<\(\d\{4}\)-\(\d\d\)-\(\d\d\)\%(\s\+\(\(\d\d\):\(\d\d\)\)\)\?\>'
let g:tlib#date#date_rx = '\<\(\d\{4}\)-\(\d\d\)-\(\d\d\)\>'
let g:tlib#date#date_format = '%Y-%m-%d'
function! tlib#date#IsDate(text) abort "{{{3
return a:text =~# '^'. g:tlib#date#date_rx .'$' &&
\ !empty(tlib#date#Parse(a:text, 0, 1))
endf
function! tlib#date#Format(...) abort "{{{3
let secs1970 = a:0 >= 1 ? a:1 : localtime()
return strftime(g:tlib#date#date_format, secs1970)
endf
" :display: tlib#date#DiffInDays(date1, ?date2=localtime(), ?allow_zero=0)
function! tlib#date#DiffInDays(date, ...)
let allow_zero = a:0 >= 2 ? a:2 : 0
let s0 = tlib#date#SecondsSince1970(a:date, 0, allow_zero)
let s1 = a:0 >= 1 ? tlib#date#SecondsSince1970(a:1, 0, allow_zero) : localtime()
let dd = (s0 - s1) / g:tlib#date#dayshift
" TLogVAR dd
return dd
endf
" :display: tlib#date#Parse(date, ?allow_zero=0, ?silent=0) "{{{3
function! tlib#date#Parse(date, ...) "{{{3
let min = a:0 >= 1 && a:1 ? 0 : 1
let silent = a:0 >= 2 ? a:2 : 0
" TLogVAR a:date, min
let m = matchlist(a:date, '^\(\d\{2}\|\d\{4}\)-\(\d\{1,2}\)-\(\d\{1,2}\)$')
if !empty(m)
let year = m[1]
let month = m[2]
let days = m[3]
else
let m = matchlist(a:date, '^\(\d\+\)/\(\d\{1,2}\)/\(\d\{1,2}\)$')
if !empty(m)
let year = m[1]
let month = m[3]
let days = m[2]
else
let m = matchlist(a:date, '^\(\d\{1,2}\)\.\s*\(\d\{1,2}\)\.\s*\(\d\d\{2}\|\d\{4}\)$')
if !empty(m)
let year = m[3]
let month = m[2]
let days = m[1]
endif
endif
endif
if empty(m) || year == '' || month == '' || days == '' ||
\ month < min || month > 12 || days < min || days > 31
if !silent
echoerr 'TLib: Invalid date: '. a:date
endif
return []
endif
if strlen(year) == 2
let year = g:tlib#date#ShortDatePrefix . year
endif
return [0 + year, 0 + month, 0 + days]
endf
" tlib#date#SecondsSince1970(date, ?daysshift=0, ?allow_zero=0)
function! tlib#date#SecondsSince1970(date, ...) "{{{3
let allow_zero = a:0 >= 2 ? a:2 : 0
" TLogVAR a:date, allow_zero
let date = tlib#date#Parse(a:date, allow_zero)
if empty(date)
return 0
endif
let [year, month, days] = date
if a:0 >= 1 && a:1 > 0
let days = days + a:1
end
let days_passed = days
let i = 1970
while i < year
let days_passed = days_passed + 365
if i % 4 == 0 || i == 2000
let days_passed = days_passed + 1
endif
let i = i + 1
endwh
let i = 1
while i < month
if i == 1
let days_passed = days_passed + 31
elseif i == 2
let days_passed = days_passed + 28
if year % 4 == 0 || year == 2000
let days_passed = days_passed + 1
endif
elseif i == 3
let days_passed = days_passed + 31
elseif i == 4
let days_passed = days_passed + 30
elseif i == 5
let days_passed = days_passed + 31
elseif i == 6
let days_passed = days_passed + 30
elseif i == 7
let days_passed = days_passed + 31
elseif i == 8
let days_passed = days_passed + 31
elseif i == 9
let days_passed = days_passed + 30
elseif i == 10
let days_passed = days_passed + 31
elseif i == 11
let days_passed = days_passed + 30
endif
let i = i + 1
endwh
let seconds = (days_passed - 1) * 24 * 60 * 60
let seconds = seconds + (strftime('%H') + g:tlib#date#TimeZoneShift) * 60 * 60
let seconds = seconds + strftime('%M') * 60
let seconds = seconds + strftime('%S')
return seconds
endf
function! tlib#date#Shift(date, shift) abort "{{{3
let n = str2nr(matchstr(a:shift, '\d\+'))
let ml = matchlist(a:date, g:tlib#date#date_rx)
" TLogVAR a:date, a:shift, n, ml
if a:shift =~ 'd$'
let date = tlib#date#AddDays(a:date, n)
elseif a:shift =~ 'b$'
let n1 = n
let secs = tlib#date#SecondsSince1970(a:date)
while n1 > 0
let n1 -= 1
let secs += g:tlib#date#dayshift
let uday = strftime('%u', secs)
if uday == 6
let secs += g:tlib#date#dayshift * 2
elseif uday == 7
let secs += g:tlib#date#dayshift
endif
endwh
let date = tlib#date#Format(secs)
elseif a:shift =~ 'w$'
let date = tlib#date#AddDays(a:date, n * 7)
elseif a:shift =~ 'm$'
let d = str2nr(ml[3])
let ms = str2nr(ml[2]) + n
let m = (ms - 1) % 12 + 1
let yr = str2nr(ml[1]) + (ms - 1) / 12
let date = printf('%04d-%02d-%02d', yr, m, d)
" TLogVAR d, ms, m, yr, date
elseif a:shift =~ 'y$'
let yr = str2nr(ml[1]) + n
let date = substitute(a:date, '^\d\{4}', yr, '')
else
throw 'tlib#date#Shift: Unsupported arguments: '. string(a:shift)
endif
" if !empty(ml[4]) && date !~ '\s'. ml[4] .'$'
" let date .= ' '. ml[4]
" endif
" TLogVAR date
return date
endf
function! tlib#date#AddDays(date, n) abort "{{{3
let secs = tlib#date#SecondsSince1970(a:date) + g:tlib#date#dayshift * a:n
" TLogVAR secs
let date = tlib#date#Format(secs)
return date
endf

View File

@ -0,0 +1,45 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: https://github.com/tomtom
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2016-04-06
" @Revision: 22
" :display: tlib#dictionary#Rev(dict, ?opts = {}) abort "{{{3
function! tlib#dictionary#Rev(dict, ...) abort "{{{3
let opts = a:0 >= 1 ? a:1 : {}
Tlibtype a:dict, 'dict', opts, 'dict'
let rev = {}
let use_string = get(opts, 'use_string', 0)
let use_eval = get(opts, 'use_eval', 0)
let values_as_list = get(opts, 'values_as_list', 0)
for [m, f] in items(a:dict)
if use_string
let k = string(f)
else
let k = type(f) == 1 ? f : string(f)
if k ==# ''
let k = get(opts, 'empty', '')
if empty(k)
continue
endif
endif
endif
if use_eval
let v = eval(m)
else
let v = m
endif
if values_as_list
if has_key(rev, k)
call add(rev[k], v)
else
let rev[k] = [v]
endif
else
let rev[k] = v
endif
endfor
return rev
endf

View File

@ -0,0 +1,93 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 43
" TLet g:tlib#dir#sep = '/'
TLet g:tlib#dir#sep = exists('+shellslash') && !&shellslash ? '\' : '/'
let s:dir_stack = []
" EXAMPLES: >
" tlib#dir#CanonicName('foo/bar')
" => 'foo/bar/'
function! tlib#dir#CanonicName(dirname) "{{{3
let dirname = tlib#file#Canonic(a:dirname)
if dirname !~ '[/\\]$'
return dirname . g:tlib#dir#sep
endif
return dirname
endf
" EXAMPLES: >
" tlib#dir#NativeName('foo/bar/')
" On Windows:
" => 'foo\bar\'
" On Linux:
" => 'foo/bar/'
function! tlib#dir#NativeName(dirname) "{{{3
let sep = tlib#rx#EscapeReplace(g:tlib#dir#sep)
let dirname = substitute(a:dirname, '[\/]', sep, 'g')
return dirname
endf
" EXAMPLES: >
" tlib#dir#PlainName('foo/bar/')
" => 'foo/bar'
function! tlib#dir#PlainName(dirname) "{{{3
let dirname = a:dirname
while index(['/', '\'], dirname[-1 : -1]) != -1
let dirname = dirname[0 : -2]
endwh
return dirname
" return substitute(a:dirname, tlib#rx#Escape(g:tlib#dir#sep).'\+$', '', '')
endf
" Create a directory if it doesn't already exist.
function! tlib#dir#Ensure(dir) "{{{3
if !isdirectory(a:dir)
let dir = tlib#dir#PlainName(a:dir)
return mkdir(dir, 'p')
endif
return 1
endf
" Return the first directory in &rtp.
function! tlib#dir#MyRuntime() "{{{3
return get(split(&rtp, ','), 0)
endf
" :def: function! tlib#dir#CD(dir, ?locally=0) => CWD
function! tlib#dir#CD(dir, ...) "{{{3
TVarArg ['locally', haslocaldir()]
let cmd = locally ? 'lcd! ' : 'cd! '
" let cwd = getcwd()
let cmd .= tlib#arg#Ex(a:dir)
" TLogVAR a:dir, locally, cmd
exec 'silent' cmd
" return cwd
return getcwd()
endf
" :def: function! tlib#dir#Push(dir, ?locally=0) => CWD
function! tlib#dir#Push(dir, ...) "{{{3
TVarArg ['locally', haslocaldir()]
call add(s:dir_stack, [getcwd(), locally])
return tlib#dir#CD(a:dir, locally)
endf
" :def: function! tlib#dir#Pop() => CWD
function! tlib#dir#Pop() "{{{3
let [dir, locally] = remove(s:dir_stack, -1)
return tlib#dir#CD(dir, locally)
endf

View File

@ -0,0 +1,72 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 56
function! tlib#eval#FormatValue(value, ...) "{{{3
TVarArg ['indent', 0]
" TLogVAR a:value, indent
let indent1 = indent + 1
let indenti = repeat(' ', &sw)
let type = type(a:value)
let acc = []
if type == 0 || type == 1 || type == 2
" TLogDBG 'Use string() for type='. type
call add(acc, string(a:value))
elseif type == 3 "List
" TLogDBG 'List'
call add(acc, '[')
for e in a:value
call add(acc, printf('%s%s,', indenti, tlib#eval#FormatValue(e, indent1)))
unlet e
endfor
call add(acc, ']')
elseif type == 4 "Dictionary
" TLogDBG 'Dictionary'
call add(acc, '{')
let indent1 = indent + 1
for [k, v] in items(a:value)
call add(acc, printf("%s%s: %s,", indenti, string(k), tlib#eval#FormatValue(v, indent1)))
unlet k v
endfor
call add(acc, '}')
else
" TLogDBG 'Unknown type: '. string(a:value)
call add(acc, string(a:value))
endif
if indent > 0
let is = repeat(' ', indent * &sw)
for i in range(1,len(acc) - 1)
let acc[i] = is . acc[i]
endfor
endif
return join(acc, "\n")
endf
function! tlib#eval#Extend(a, b, ...) abort "{{{3
let mode = a:0 >= 1 ? a:1 : 'force'
if type(a:a) != type(a:b)
throw 'tlib#eval#Extend: Incompatible types: a='. string(a:a) .' b='. string(a:b)
elseif type(a:a) == 3 " list
return extend(a:a, a:b, mode)
elseif type(a:a) == 4 " dict
for k in keys(a:b)
if has_key(a:a, k)
if mode == 'force'
let a:a[k] = tlib#eval#Extend(copy(a:a[k]), a:b[k], mode)
elseif mode == 'error'
throw 'tlib#eval#Extend: Key already exists: '. k
endif
else
let a:a[k] = a:b[k]
endif
unlet! k
endfor
return a:a
else
return a:b
endif
endf

View File

@ -0,0 +1,283 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 169
if !exists('g:tlib#file#drop')
" If true, use |:drop| to edit loaded buffers (only available with GUI).
let g:tlib#file#drop = has('gui') "{{{2
endif
if !exists('g:tlib#file#use_tabs')
let g:tlib#file#use_tabs = 0 "{{{2
endif
if !exists('g:tlib#file#edit_cmds')
let g:tlib#file#edit_cmds = g:tlib#file#use_tabs ? {'buffer': 'tab split | buffer', 'edit': 'tabedit'} : {} "{{{2
endif
if !exists('g:tlib#file#absolute_filename_rx')
let g:tlib#file#absolute_filename_rx = '^\~\?[\/]' "{{{2
endif
""" File related {{{1
" For the following functions please see ../../test/tlib.vim for examples.
" EXAMPLES: >
" tlib#file#Split('foo/bar/filename.txt')
" => ['foo', 'bar', 'filename.txt']
function! tlib#file#Split(filename) "{{{3
let prefix = matchstr(a:filename, '^\(\w\+:\)\?/\+')
" TLogVAR prefix
if !empty(prefix)
let filename = a:filename[len(prefix) : -1]
else
let filename = a:filename
endif
let rv = split(filename, '[\/]')
" let rv = split(filename, '[\/]', 1)
if !empty(prefix)
call insert(rv, prefix[0:-2])
endif
return rv
endf
" :display: tlib#file#Join(filename_parts, ?strip_slashes=1, ?maybe_absolute=0)
" EXAMPLES: >
" tlib#file#Join(['foo', 'bar', 'filename.txt'])
" => 'foo/bar/filename.txt'
function! tlib#file#Join(filename_parts, ...) "{{{3
TVarArg ['strip_slashes', 1], 'maybe_absolute'
" TLogVAR a:filename_parts, strip_slashes
if maybe_absolute
let filename_parts = []
for part in a:filename_parts
if part =~ g:tlib#file#absolute_filename_rx
let filename_parts = []
endif
call add(filename_parts, part)
endfor
else
let filename_parts = a:filename_parts
endif
if strip_slashes
" let rx = tlib#rx#Escape(g:tlib#dir#sep) .'$'
let rx = '[/\\]\+$'
let parts = map(copy(filename_parts), 'substitute(v:val, rx, "", "")')
" TLogVAR parts
return join(parts, g:tlib#dir#sep)
else
return join(filename_parts, g:tlib#dir#sep)
endif
endf
" EXAMPLES: >
" tlib#file#Relative('foo/bar/filename.txt', 'foo')
" => 'bar/filename.txt'
function! tlib#file#Relative(filename, basedir) "{{{3
" TLogVAR a:filename, a:basedir
" TLogDBG getcwd()
" TLogDBG expand('%:p')
let b0 = tlib#file#Absolute(a:basedir)
let b = tlib#file#Split(b0)
" TLogVAR b
let f0 = tlib#file#Absolute(a:filename)
let fn = fnamemodify(f0, ':t')
let fd = fnamemodify(f0, ':h')
let f = tlib#file#Split(fd)
" TLogVAR f0, fn, fd, f
if f[0] != b[0]
let rv = f0
else
while !empty(f) && !empty(b)
if f[0] != b[0]
break
endif
call remove(f, 0)
call remove(b, 0)
endwh
" TLogVAR f, b
let rv = tlib#file#Join(repeat(['..'], len(b)) + f + [fn])
endif
" TLogVAR rv
return rv
endf
function! tlib#file#IsAbsolute(filename) "{{{3
return a:filename =~? '^\%(/\|\w\+:/\)'
endf
function! tlib#file#Absolute(filename, ...) "{{{3
if filereadable(a:filename)
let filename = fnamemodify(a:filename, ':p')
elseif a:filename =~ '^\(/\|[^\/]\+:\)'
let filename = a:filename
else
let cwd = a:0 >= 1 ? a:1 : getcwd()
let filename = tlib#file#Join([cwd, a:filename])
endif
let filename = substitute(filename, '\(^\|[\/]\)\zs\.[\/]', '', 'g')
let filename = substitute(filename, '[\/]\zs[^\/]\+[\/]\.\.[\/]', '', 'g')
return filename
endf
function! tlib#file#Canonic(filename, ...) "{{{3
TVarArg ['mode', '']
if a:filename =~ '^\\\\'
let mode = 'windows'
elseif a:filename =~ '^\(file\|ftp\|http\)s\?:'
let mode = 'url'
elseif (empty(mode) && g:tlib#sys#windows)
let mode = 'windows'
endif
let filename = a:filename
if mode == 'windows'
let filename = substitute(filename, '/', '\\', 'g')
else
let filename = substitute(filename, '\\', '/', 'g')
endif
return filename
endf
function! s:SetScrollBind(world) "{{{3
let sb = get(a:world, 'scrollbind', &scrollbind)
if sb != &scrollbind
let &scrollbind = sb
endif
endf
" :def: function! tlib#file#With(fcmd, bcmd, files, ?world={})
function! tlib#file#With(fcmd, bcmd, files, ...) "{{{3
" TLogVAR a:fcmd, a:bcmd, a:files
exec tlib#arg#Let([['world', {}]])
call tlib#autocmdgroup#Init()
augroup TLibFileRead
autocmd!
augroup END
for f in a:files
let bn = bufnr('^'.f.'$')
" TLogVAR f, bn
let bufloaded = bufloaded(bn)
let ok = 0
let s:bufread = ""
if bn != -1 && buflisted(bn)
if !empty(a:bcmd)
" TLogDBG a:bcmd .' '. bn
exec a:bcmd .' '. bn
let ok = 1
call s:SetScrollBind(world)
endif
else
if filereadable(f)
if !empty(a:fcmd)
" TLogDBG a:fcmd .' '. tlib#arg#Ex(f)
exec 'autocmd TLibFileRead BufRead' escape(f, '\ ') 'let s:bufread=expand("<afile>:p")'
try
exec a:fcmd .' '. tlib#arg#Ex(f)
finally
exec 'autocmd! TLibFileRead BufRead'
endtry
let ok = 1
call s:SetScrollBind(world)
endif
else
echohl error
echom 'File not readable: '. f
echohl NONE
endif
endif
" TLogVAR ok, bufloaded, &filetype
if empty(s:bufread) && ok && !bufloaded && empty(&filetype)
doautocmd BufRead
endif
endfor
augroup! TLibFileRead
unlet! s:bufread
" TLogDBG "done"
endf
" Return 0 if the file isn't readable/doesn't exist.
" Otherwise return 1.
function! tlib#file#Edit(fileid) "{{{3
if type(a:fileid) == 0
let bn = a:fileid
let filename = fnamemodify(bufname(bn), ':p')
else
let filename = fnamemodify(a:fileid, ':p')
let bn = bufnr(filename)
endif
if filename == expand('%:p')
return 1
else
" TLogVAR a:fileid, bn, filename, g:tlib#file#drop, filereadable(filename)
if bn != -1 && buflisted(bn)
if g:tlib#file#drop
" echom "DBG" get(g:tlib#file#edit_cmds, 'drop', 'drop') fnameescape(filename)
exec get(g:tlib#file#edit_cmds, 'drop', 'drop') fnameescape(filename)
else
" echom "DBG" get(g:tlib#file#edit_cmds, 'buffer', 'buffer') bn
exec get(g:tlib#file#edit_cmds, 'buffer', 'buffer') bn
endif
return 1
elseif filereadable(filename)
try
" let file = tlib#arg#Ex(filename)
" " TLogVAR file
" echom "DBG" get(g:tlib#file#edit_cmds, 'edit', 'edit') fnameescape(filename)
exec get(g:tlib#file#edit_cmds, 'edit', 'edit') fnameescape(filename)
catch /E325/
" swap file exists, let the user handle it
catch
echohl error
echom v:exception
echohl NONE
endtry
return 1
else
echom "TLIB: File not readable: " . filename
if filename != a:fileid
echom "TLIB: original filename: " . a:fileid
endif
endif
endif
return 0
endf
if v:version > 704 || (v:version == 704 && has('patch279'))
function! tlib#file#Glob(pattern) abort "{{{3
return glob(a:pattern, 0, 1)
endf
function! tlib#file#Globpath(path, pattern) abort "{{{3
return globpath(a:path, a:pattern, 0, 1)
endf
else
" :nodoc:
function! tlib#file#Glob(pattern) abort "{{{3
return split(glob(a:pattern), '\n')
endf
" :nodoc:
function! tlib#file#Globpath(path, pattern) abort "{{{3
return split(globpath(a:path, a:pattern), '\n')
endf
endif

View File

@ -0,0 +1,14 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2013-02-22.
" @Revision: 3
function! tlib#fixes#Winpos() "{{{3
if has('gui_win32')
return 'winpos '. getwinposx() .' '. getwinposy()
else
return ''
endif
endf

View File

@ -0,0 +1,38 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Last Change: 2013-10-16.
" @Revision: 31
function! tlib#grep#Do(cmd, rx, files) "{{{3
" TLogVAR a:cmd, a:rx, a:files
let files = join(map(copy(a:files), 'tlib#arg#Ex(v:val, "")'), ' ')
let rx = '/'. escape(a:rx, '/') .'/j'
" TLogVAR rx, files
silent exec a:cmd rx files
endf
function! tlib#grep#LocList(rx, files) "{{{3
return tlib#grep#Do('noautocmd lvimgrep', a:rx, a:files)
endf
function! tlib#grep#QuickFixList(rx, files) "{{{3
return tlib#grep#Do('noautocmd vimgrep', a:rx, a:files)
endf
function! tlib#grep#List(rx, files) "{{{3
call setqflist([])
call tlib#grep#Do('noautocmd vimgrepadd', a:rx, a:files)
let qfl = getqflist()
" TLogVAR qfl
" try
silent! colder
" catch
" call setqflist([], 'r')
" endtry
return qfl
endf

View File

@ -0,0 +1,145 @@
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 276
if !exists('g:tlib#hash#use_crc32')
let g:tlib#hash#use_crc32 = '' "{{{2
endif
if !exists('g:tlib#hash#use_adler32')
let g:tlib#hash#use_adler32 = '' "{{{2
endif
function! tlib#hash#CRC32B(chars) "{{{3
if !empty(g:tlib#hash#use_crc32)
let use = g:tlib#hash#use_crc32
elseif has('ruby')
let use = 'ruby'
else
let use = 'vim'
endif
if exists('*tlib#hash#CRC32B_'. use)
return tlib#hash#CRC32B_{use}(a:chars)
else
throw "Unknown version of tlib#hash#CRC32B: ". use
endif
endf
function! tlib#hash#CRC32B_ruby(chars) "{{{3
if has('ruby')
let rv = ''
if !exists('s:loaded_ruby_zlib')
ruby require 'zlib'
let s:loaded_ruby_zlib = 1
endif
ruby VIM::command('let rv = "%08X"' % Zlib.crc32(VIM::evaluate("a:chars")))
return rv
else
throw "tlib#hash#CRC32B_ruby not supported in this version of vim"
endif
endf
function! tlib#hash#CRC32B_vim(chars) "{{{3
if !exists('s:crc_table')
let cfile = tlib#persistent#Filename('tlib', 'crc_table', 1)
let s:crc_table = tlib#persistent#Value(cfile, 'tlib#hash#CreateCrcTable', 0)
endif
let xFFFF_FFFF = repeat([1], 32)
let crc = tlib#bitwise#XOR([0], xFFFF_FFFF, 'bits')
for char in split(a:chars, '\zs')
let octet = char2nr(char)
let r1 = tlib#bitwise#ShiftRight(crc, 8)
let i0 = tlib#bitwise#AND(crc, xFFFF_FFFF, 'bits')
let i1 = tlib#bitwise#XOR(i0, octet, 'bits')
let i2 = tlib#bitwise#Bits2Num(tlib#bitwise#AND(i1, 0xff, 'bits'))
let r2 = s:crc_table[i2]
let crc = tlib#bitwise#XOR(r1, r2, 'bits')
endfor
let crc = tlib#bitwise#XOR(crc, xFFFF_FFFF, 'bits')
let rv = tlib#bitwise#Bits2Num(crc, 16)
if len(rv) < 8
let rv = repeat('0', 8 - len(rv)) . rv
endif
return rv
endf
" :nodoc:
function! tlib#hash#CreateCrcTable() "{{{3
let sum = 0.0
for exponent in [0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26, 32]
let exp = tlib#bitwise#Bits2Num(repeat([0], 32 - exponent) + [1], 10.0)
let sum += exp
endfor
let divisor = tlib#bitwise#Num2Bits(sum)
let crc_table = []
for octet in range(256)
let remainder = tlib#bitwise#Num2Bits(octet)
for i in range(8)
if get(remainder, i) != 0
let remainder = tlib#bitwise#XOR(remainder, tlib#bitwise#ShiftLeft(divisor, i), "bits")
endif
endfor
let remainder = tlib#bitwise#ShiftRight(remainder, 8)
call add(crc_table, remainder)
endfor
return crc_table
endf
function! tlib#hash#Adler32(chars) "{{{3
if !empty(g:tlib#hash#use_adler32)
let use = g:tlib#hash#use_adler32
elseif exists('*or')
let use = 'vim'
else
let use = 'tlib'
endif
if exists('*tlib#hash#Adler32_'. use)
return tlib#hash#Adler32_{use}(a:chars)
else
throw "Unknown version of tlib#hash#Adler32_: ". use
endif
endf
function! tlib#hash#Adler32_vim(chars) "{{{3
if exists('*or')
let mod_adler = 65521
let a = 1
let b = 0
for index in range(len(a:chars))
let c = char2nr(a:chars[index])
let a = (a + c) % mod_adler
let b = (b + a) % mod_adler
endfor
let bb = b * float2nr(pow(2, 16))
let checksum = or(bb, a)
" TLogVAR checksum, a, b, bb
return printf("%08X", checksum)
else
throw "TLIB: Vim version doesn't support bitwise or()"
endif
endf
function! tlib#hash#Adler32_tlib(chars) "{{{3
let mod_adler = 65521
let a = 1
let b = 0
for index in range(len(a:chars))
let c = char2nr(a:chars[index])
let a = (a + c) % mod_adler
let b = (b + a) % mod_adler
endfor
let bb = tlib#bitwise#ShiftLeft(tlib#bitwise#Num2Bits(b), 16)
let checksum = tlib#bitwise#OR(bb, a, "bits")
return printf('%08s', tlib#bitwise#Bits2Num(checksum, 16))
endf

View File

@ -0,0 +1,25 @@
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Revision: 11
" :def: function! tlib#hook#Run(hook, ?dict={})
" Execute dict[hook], w:{hook}, b:{hook}, or g:{hook} if existent.
function! tlib#hook#Run(hook, ...) "{{{3
TVarArg ['dict', {}]
if has_key(dict, a:hook)
let hook = dict[a:hook]
else
let hook = tlib#var#Get(a:hook, 'wbg')
endif
if empty(hook)
return 0
else
let world = dict
exec hook
return 1
endif
endf

Some files were not shown because too many files have changed in this diff Show More