Clean up plugins
This commit is contained in:
parent
3a637519e7
commit
a3c1287028
213
iterm/dive-blue.itermcolors
Normal file
213
iterm/dive-blue.itermcolors
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Ansi 0 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.13863241792929293</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.13863241792929293</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.13863241792929293</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 1 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.0</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.0</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.73333334922790527</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 10 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.0</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.93863123655319214</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.81519259891667195</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 11 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.95831196345308145</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.90818294859853477</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 12 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.35028249216144114</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.33228410804237429</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 13 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.95580336202768557</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.43898106009313798</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 14 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.69175738096237183</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.18206536769866943</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 15 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.98374009132385254</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.96765059232711792</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 2 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.0</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.48821133375167847</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 3 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.44253450624810831</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.37018267775822222</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 4 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.6520163853240426</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.0</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 5 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.9444358223077236</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.0</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 6 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.63589870929718018</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.73333334922790527</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.063085161149501801</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 7 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.7519041080853881</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.71496204568995447</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.79409998655319214</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 8 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.33333333333333331</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.33333333333333331</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.33333333333333331</real>
|
||||||
|
</dict>
|
||||||
|
<key>Ansi 9 Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.3333333432674408</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.3333333432674408</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
</dict>
|
||||||
|
<key>Background Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.87079782196969691</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.1721805548914164</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.0</real>
|
||||||
|
</dict>
|
||||||
|
<key>Bold Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.87799109818097032</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.75928070281883253</real>
|
||||||
|
</dict>
|
||||||
|
<key>Cursor Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.73333334922790527</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.73333334922790527</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.73333334922790527</real>
|
||||||
|
</dict>
|
||||||
|
<key>Cursor Text Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
</dict>
|
||||||
|
<key>Foreground Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.94509803921568625</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.94117647058823528</real>
|
||||||
|
</dict>
|
||||||
|
<key>Selected Text Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>1</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.18293527746864413</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.94237203617683463</real>
|
||||||
|
</dict>
|
||||||
|
<key>Selection Color</key>
|
||||||
|
<dict>
|
||||||
|
<key>Blue Component</key>
|
||||||
|
<real>0.28296638257575757</real>
|
||||||
|
<key>Green Component</key>
|
||||||
|
<real>0.062421906360556716</real>
|
||||||
|
<key>Red Component</key>
|
||||||
|
<real>0.12213946629502002</real>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0b28e334e65b6628b0a61c412fcb45204a2f2bab
|
Subproject commit cfd3b2d388a8c2e9903d7a9d80a65539aabfe933
|
||||||
2
vim/bundle/ag/.gitignore
vendored
2
vim/bundle/ag/.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
tags
|
|
||||||
ag-vim.tgz
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
# ag.vim #
|
|
||||||
|
|
||||||
This plugin is a front for ag, A.K.A.
|
|
||||||
[the_silver_searcher](https://github.com/ggreer/the_silver_searcher). Ag can
|
|
||||||
be used as a replacement for 153% of the uses of `ack`. This plugin will allow
|
|
||||||
you to run ag from vim, and shows the results in a split window.
|
|
||||||
|
|
||||||
## Installation ##
|
|
||||||
|
|
||||||
### The Silver Searcher
|
|
||||||
|
|
||||||
You have to first install [ag](https://github.com/ggreer/the_silver_searcher), itself. On Mac+Homebrew, Gentoo Linux, several others, there's package named `the_silver_searcher`, but if your OS/distro don't have one, the GitHub repo installs fine:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
git clone https://github.com/ggreer/the_silver_searcher ag && cd ag && ./build.sh && sudo make install
|
|
||||||
```
|
|
||||||
|
|
||||||
* Then, if you're using [pathogen](https://github.com/tpope/vim-pathogen):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cd ~/.vim/bundle && git clone https://github.com/rking/ag.vim ag && vim +Helptags
|
|
||||||
```
|
|
||||||
|
|
||||||
* Or, if you're using [Vundle](https://github.com/gmarik/vundle):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
echo "Bundle 'rking/ag.vim'" >> ~/.vimrc && vim +BundleInstall
|
|
||||||
```
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
You can specify a custom ag name and path in your .vimrc like so:
|
|
||||||
|
|
||||||
let g:agprg="<custom-ag-path-goes-here> --column"
|
|
||||||
|
|
||||||
## Usage ##
|
|
||||||
|
|
||||||
:Ag [options] {pattern} [{directory}]
|
|
||||||
|
|
||||||
Search recursively in {directory} (which defaults to the current directory) for the {pattern}.
|
|
||||||
|
|
||||||
Files containing the search term will be listed in the split window, along with
|
|
||||||
the line number of the occurrence, once for each occurrence. [Enter] on a line
|
|
||||||
in this window will open the file, and place the cursor on the matching line.
|
|
||||||
|
|
||||||
Just like where you use :grep, :grepadd, :lgrep, and :lgrepadd, you can use `:Ag`, `:AgAdd`, `:LAg`, and `:LAgAdd` respectively. (See `doc/ag.txt`, or install and `:h Ag` for more information.)
|
|
||||||
|
|
||||||
### Gotchas ###
|
|
||||||
|
|
||||||
Some characters have special meaning, and need to be escaped your search pattern. For instance, '#'. You have to escape it like this `:Ag '\\\#define foo'` to search for `#define foo`. (From [blueyed in issue #5](https://github.com/mileszs/ack.vim/issues/5).)
|
|
||||||
|
|
||||||
Sometimes `git grep` is even faster, though in my experience it's not noticeably so.
|
|
||||||
|
|
||||||
### Keyboard Shortcuts ###
|
|
||||||
|
|
||||||
In the quickfix window, you can use:
|
|
||||||
|
|
||||||
e to open file and close the quickfix window
|
|
||||||
o to open (same as enter)
|
|
||||||
go to preview file (open but maintain focus on ag.vim results)
|
|
||||||
t to open in new tab
|
|
||||||
T to open in new tab silently
|
|
||||||
h to open in horizontal split
|
|
||||||
H to open in horizontal split silently
|
|
||||||
v to open in vertical split
|
|
||||||
gv to open in vertical split silently
|
|
||||||
q to close the quickfix window
|
|
||||||
|
|
||||||
### Acknowledgements
|
|
||||||
|
|
||||||
This Vim plugin is derived (and by derived, I mean copied, almost entirely)
|
|
||||||
from [milesz's ack.vim](https://github.com/mileszs/ack.vim), which I also
|
|
||||||
recommend installing since you might be in a situation where you have ack but
|
|
||||||
not ag, and don't want to stop to install ag. Also, ack supports `--type`, and
|
|
||||||
a few other features.
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
task :tgz do
|
|
||||||
sh 'cd ..; tar czvf ag/ag-vim.tgz ag/{plugin,autoload,doc}'
|
|
||||||
end
|
|
||||||
|
|
@ -1,147 +0,0 @@
|
||||||
" NOTE: You must, of course, install ag / the_silver_searcher
|
|
||||||
|
|
||||||
" Location of the ag utility
|
|
||||||
if !exists("g:agprg")
|
|
||||||
let g:agprg="ag --column"
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:ag_apply_qmappings")
|
|
||||||
let g:ag_apply_qmappings=1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:ag_apply_lmappings")
|
|
||||||
let g:ag_apply_lmappings=1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:ag_qhandler")
|
|
||||||
let g:ag_qhandler="botright copen"
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:ag_lhandler")
|
|
||||||
let g:ag_lhandler="botright lopen"
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists("g:ag_mapping_message")
|
|
||||||
let g:ag_mapping_message=1
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! ag#Ag(cmd, args)
|
|
||||||
let l:ag_executable = get(split(g:agprg, " "), 0)
|
|
||||||
|
|
||||||
" Ensure that `ag` is installed
|
|
||||||
if !executable(l:ag_executable)
|
|
||||||
echoe "Ag command '" . l:ag_executable . "' was not found. Is the silver searcher installed and on your $PATH?"
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
" If no pattern is provided, search for the word under the cursor
|
|
||||||
if empty(a:args)
|
|
||||||
let l:grepargs = expand("<cword>")
|
|
||||||
else
|
|
||||||
let l:grepargs = a:args . join(a:000, ' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
" Format, used to manage column jump
|
|
||||||
if a:cmd =~# '-g$'
|
|
||||||
let s:agformat_backup=g:agformat
|
|
||||||
let g:agformat="%f"
|
|
||||||
elseif exists("s:agformat_backup")
|
|
||||||
let g:agformat=s:agformat_backup
|
|
||||||
elseif !exists("g:agformat")
|
|
||||||
let g:agformat="%f:%l:%c:%m"
|
|
||||||
endif
|
|
||||||
|
|
||||||
let l:grepprg_bak=&grepprg
|
|
||||||
let l:grepformat_bak=&grepformat
|
|
||||||
let l:t_ti_bak=&t_ti
|
|
||||||
let l:t_te_bak=&t_te
|
|
||||||
try
|
|
||||||
let &grepprg=g:agprg
|
|
||||||
let &grepformat=g:agformat
|
|
||||||
set t_ti=
|
|
||||||
set t_te=
|
|
||||||
silent execute a:cmd . " " . escape(l:grepargs, '|')
|
|
||||||
finally
|
|
||||||
let &grepprg=l:grepprg_bak
|
|
||||||
let &grepformat=l:grepformat_bak
|
|
||||||
let &t_ti=l:t_ti_bak
|
|
||||||
let &t_te=l:t_te_bak
|
|
||||||
endtry
|
|
||||||
|
|
||||||
if a:cmd =~# '^l'
|
|
||||||
let l:match_count = len(getloclist(winnr()))
|
|
||||||
else
|
|
||||||
let l:match_count = len(getqflist())
|
|
||||||
endif
|
|
||||||
|
|
||||||
if a:cmd =~# '^l' && l:match_count
|
|
||||||
exe g:ag_lhandler
|
|
||||||
let l:apply_mappings = g:ag_apply_lmappings
|
|
||||||
let l:matches_window_prefix = 'l' " we're using the location list
|
|
||||||
elseif l:match_count
|
|
||||||
exe g:ag_qhandler
|
|
||||||
let l:apply_mappings = g:ag_apply_qmappings
|
|
||||||
let l:matches_window_prefix = 'c' " we're using the quickfix window
|
|
||||||
endif
|
|
||||||
|
|
||||||
" If highlighting is on, highlight the search keyword.
|
|
||||||
if exists("g:aghighlight")
|
|
||||||
let @/=a:args
|
|
||||||
set hlsearch
|
|
||||||
end
|
|
||||||
|
|
||||||
redraw!
|
|
||||||
|
|
||||||
if l:match_count
|
|
||||||
if l:apply_mappings
|
|
||||||
nnoremap <silent> <buffer> h <C-W><CR><C-w>K
|
|
||||||
nnoremap <silent> <buffer> H <C-W><CR><C-w>K<C-w>b
|
|
||||||
nnoremap <silent> <buffer> o <CR>
|
|
||||||
nnoremap <silent> <buffer> t <C-w><CR><C-w>T
|
|
||||||
nnoremap <silent> <buffer> T <C-w><CR><C-w>TgT<C-W><C-W>
|
|
||||||
nnoremap <silent> <buffer> v <C-w><CR><C-w>H<C-W>b<C-W>J<C-W>t
|
|
||||||
|
|
||||||
exe 'nnoremap <silent> <buffer> e <CR><C-w><C-w>:' . l:matches_window_prefix .'close<CR>'
|
|
||||||
exe 'nnoremap <silent> <buffer> go <CR>:' . l:matches_window_prefix . 'open<CR>'
|
|
||||||
exe 'nnoremap <silent> <buffer> q :' . l:matches_window_prefix . 'close<CR>'
|
|
||||||
|
|
||||||
exe 'nnoremap <silent> <buffer> gv :let b:height=winheight(0)<CR><C-w><CR><C-w>H:' . l:matches_window_prefix . 'open<CR><C-w>J:exe printf(":normal %d\<lt>c-w>_", b:height)<CR>'
|
|
||||||
" Interpretation:
|
|
||||||
" :let b:height=winheight(0)<CR> Get the height of the quickfix/location list window
|
|
||||||
" <CR><C-w> Open the current item in a new split
|
|
||||||
" <C-w>H Slam the newly opened window against the left edge
|
|
||||||
" :copen<CR> -or- :lopen<CR> Open either the quickfix window or the location list (whichever we were using)
|
|
||||||
" <C-w>J Slam the quickfix/location list window against the bottom edge
|
|
||||||
" :exe printf(":normal %d\<lt>c-w>_", b:height)<CR> Restore the quickfix/location list window's height from before we opened the match
|
|
||||||
|
|
||||||
if g:ag_mapping_message && l:apply_mappings
|
|
||||||
echom "ag.vim keys: q=quit <cr>/e/t/h/v=enter/edit/tab/split/vsplit go/T/H/gv=preview versions of same"
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
echom 'No matches for "'.a:args.'"'
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! ag#AgFromSearch(cmd, args)
|
|
||||||
let search = getreg('/')
|
|
||||||
" translate vim regular expression to perl regular expression.
|
|
||||||
let search = substitute(search,'\(\\<\|\\>\)','\\b','g')
|
|
||||||
call ag#Ag(a:cmd, '"' . search .'" '. a:args)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! ag#GetDocLocations()
|
|
||||||
let dp = ''
|
|
||||||
for p in split(&runtimepath,',')
|
|
||||||
let p = p.'/doc/'
|
|
||||||
if isdirectory(p)
|
|
||||||
let dp = p.'*.txt '.dp
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return dp
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! ag#AgHelp(cmd,args)
|
|
||||||
let args = a:args.' '.ag#GetDocLocations()
|
|
||||||
call ag#Ag(a:cmd,args)
|
|
||||||
endfunction
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
*ag.txt* Plugin that integrates ag with Vim
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTRODUCTION *ag*
|
|
||||||
|
|
||||||
This plugin is a front for the_silver_searcher: ag. Ag can be used as a
|
|
||||||
replacement for ack. This plugin will allow you to run ag from vim, and
|
|
||||||
shows the results in a split window.
|
|
||||||
|
|
||||||
:Ag[!] [options] {pattern} [{directory}] *:Ag*
|
|
||||||
|
|
||||||
Search recursively in {directory} (which defaults to the current
|
|
||||||
directory) for the {pattern}. Behaves just like the |:grep| command, but
|
|
||||||
will open the |Quickfix| window for you. If [!] is not given the first
|
|
||||||
error is jumped to.
|
|
||||||
|
|
||||||
:AgAdd [options] {pattern} [{directory}] *:AgAdd*
|
|
||||||
|
|
||||||
Just like |:Ag|, but instead of making a new list, the matches are
|
|
||||||
appended to the current |quickfix| list.
|
|
||||||
|
|
||||||
:AgFromSearch [{directory}] *:AgFromSearch*
|
|
||||||
|
|
||||||
Just like |:Ag| but the pattern is from previous search.
|
|
||||||
|
|
||||||
:LAg [options] {pattern} [{directory}] *:LAg*
|
|
||||||
|
|
||||||
Just like |:Ag| but instead of the |quickfix| list, matches are placed in
|
|
||||||
the current |location-list|.
|
|
||||||
|
|
||||||
:LAgAdd [options] {pattern} [{directory}] *:LAgAdd*
|
|
||||||
|
|
||||||
Just like |:AgAdd| but instead of the |quickfix| list, matches are added
|
|
||||||
to the current |location-list|
|
|
||||||
|
|
||||||
:AgFile [options] {pattern} [{directory}] *:AgFile*
|
|
||||||
|
|
||||||
Search recursively in {directory} (which defaults to the current
|
|
||||||
directory) for filenames matching the {pattern}. Behaves just like the
|
|
||||||
|:grep| command, but will open the |Quickfix| window for you.
|
|
||||||
|
|
||||||
:AgHelp[!] [options] {pattern} *:AgHelp*
|
|
||||||
|
|
||||||
Search vim documentation files for the {pattern}. Behaves just like the
|
|
||||||
|:Ag| command, but searches only vim documentation .txt files
|
|
||||||
|
|
||||||
:LAgHelp [options] {pattern} *:LAgHelp*
|
|
||||||
|
|
||||||
Just like |:AgHelp| but instead of the |quickfix| list, matches are placed
|
|
||||||
in the current |location-list|.
|
|
||||||
|
|
||||||
Files containing the search term will be listed in the split window, along
|
|
||||||
with the line number of the occurrence, once for each occurrence. <Enter> on
|
|
||||||
a line in this window will open the file, and place the cursor on the matching
|
|
||||||
line.
|
|
||||||
|
|
||||||
See http://geoff.greer.fm/2011/12/27/the-silver-searcher-better-than-ack/ for
|
|
||||||
more information.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
OPTIONS *ag-options*
|
|
||||||
|
|
||||||
*g:agprg*
|
|
||||||
The location of the Ag program, and any options you want passed to it before
|
|
||||||
searching. Default: "ag --column". Example: >
|
|
||||||
let g:agprg="ag --column --smart-case"
|
|
||||||
<
|
|
||||||
|
|
||||||
*g:aghighlight*
|
|
||||||
If 1, highlight the search terms after searching. Default: 0. Example: >
|
|
||||||
let g:aghighlight=1
|
|
||||||
<
|
|
||||||
|
|
||||||
*g:agformat*
|
|
||||||
Format to recognize the matches. See 'errorformat' for more info. Default:
|
|
||||||
"%f" when searching for files, "%f:%l:%c:%m" if not otherwise set. For
|
|
||||||
example, if your `g:agprg` is set to just "ag" (no column numbers in the
|
|
||||||
output, so when you jump to a match your cursor will be on the start of the
|
|
||||||
line): >
|
|
||||||
let g:agformat="%f:%l:%m"
|
|
||||||
<
|
|
||||||
|
|
||||||
*g:ag_apply_lmappings*
|
|
||||||
Whether or not to add custom mappings to location list windows opened by this
|
|
||||||
plugin. Only applies if you're using the location list. Default 1. Example: >
|
|
||||||
let g:ag_apply_lmappings=0
|
|
||||||
<
|
|
||||||
|
|
||||||
*g:ag_apply_qmappings*
|
|
||||||
Whether or not to add custom mappings to quickfix windows opened by this
|
|
||||||
plugin. Only applies if you're using the error list. Default 1. Example: >
|
|
||||||
let g:ag_apply_qmappings=0
|
|
||||||
<
|
|
||||||
|
|
||||||
*g:ag_lhandler*
|
|
||||||
A custom command used to open the location list after it's populated.
|
|
||||||
Default: "botright lopen". You might want to set this to change where the
|
|
||||||
location list is opened, or what size it is. Example: >
|
|
||||||
let g:ag_lhandler="topleft lopen"
|
|
||||||
<
|
|
||||||
|
|
||||||
*g:ag_qhandler*
|
|
||||||
A custom command used to open the error list after it's populated. Default:
|
|
||||||
"botright copen". You might want to set this to change where the quickfix
|
|
||||||
window is opened, or what size it is. Example: >
|
|
||||||
let g:ag_qhandler="copen 20"
|
|
||||||
<
|
|
||||||
|
|
||||||
*g:ag_mapping_message*
|
|
||||||
Whether or not to show the message explaining the extra mappings that are
|
|
||||||
added to the results list this plugin populates. This message is not shown if
|
|
||||||
the mappings are not applied (see |g:ag_apply_qmappings| and
|
|
||||||
|g:ag_apply_lmappings| for more info. Default 1. Example: >
|
|
||||||
let g:ag_mapping_message=0
|
|
||||||
<
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
MAPPINGS *ag-mappings*
|
|
||||||
|
|
||||||
The following keyboard shortcuts are available in the quickfix window:
|
|
||||||
|
|
||||||
e open file and close the quickfix window.
|
|
||||||
|
|
||||||
o open file (same as enter).
|
|
||||||
|
|
||||||
go preview file (open but maintain focus on ag.vim results).
|
|
||||||
|
|
||||||
t open in a new tab.
|
|
||||||
|
|
||||||
T open in new tab silently.
|
|
||||||
|
|
||||||
h open in horizontal split.
|
|
||||||
|
|
||||||
H open in horizontal split silently.
|
|
||||||
|
|
||||||
v open in vertical split.
|
|
||||||
|
|
||||||
gv open in vertical split silently.
|
|
||||||
|
|
||||||
q close the quickfix window.
|
|
||||||
|
|
||||||
vim:tw=78:fo=tcq2:ft=help:norl:
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
" NOTE: You must, of course, install ag / the_silver_searcher
|
|
||||||
command! -bang -nargs=* -complete=file Ag call ag#Ag('grep<bang>',<q-args>)
|
|
||||||
command! -bang -nargs=* -complete=file AgAdd call ag#Ag('grepadd<bang>', <q-args>)
|
|
||||||
command! -bang -nargs=* -complete=file AgFromSearch call ag#AgFromSearch('grep<bang>', <q-args>)
|
|
||||||
command! -bang -nargs=* -complete=file LAg call ag#Ag('lgrep<bang>', <q-args>)
|
|
||||||
command! -bang -nargs=* -complete=file LAgAdd call ag#Ag('lgrepadd<bang>', <q-args>)
|
|
||||||
command! -bang -nargs=* -complete=file AgFile call ag#Ag('grep<bang> -g', <q-args>)
|
|
||||||
command! -bang -nargs=* -complete=help AgHelp call ag#AgHelp('grep<bang>',<q-args>)
|
|
||||||
command! -bang -nargs=* -complete=help LAgHelp call ag#AgHelp('lgrep<bang>',<q-args>)
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
all : gist-vim.zip
|
|
||||||
|
|
||||||
remove-zip:
|
|
||||||
-rm -f doc/tags
|
|
||||||
-rm -f gist-vim.zip
|
|
||||||
|
|
||||||
gist-vim.zip: remove-zip
|
|
||||||
zip -r gist-vim.zip autoload plugin doc README.mkd
|
|
||||||
|
|
||||||
release: gist-vim.zip
|
|
||||||
vimup update-script gist.vim
|
|
||||||
|
|
@ -1,224 +0,0 @@
|
||||||
### Gist.vim
|
|
||||||
|
|
||||||
This is a vimscript for creating gists (http://gist.github.com).
|
|
||||||
|
|
||||||
For the latest version please see https://github.com/mattn/gist-vim.
|
|
||||||
|
|
||||||
## Usage:
|
|
||||||
|
|
||||||
- Post current buffer to gist, using default privacy option.
|
|
||||||
|
|
||||||
:Gist
|
|
||||||
|
|
||||||
- Post selected text to gist, using default privacy option.
|
|
||||||
This applies to all permutations listed below (except multi).
|
|
||||||
|
|
||||||
:'<,'>Gist
|
|
||||||
|
|
||||||
- Create a private gist.
|
|
||||||
|
|
||||||
:Gist -p
|
|
||||||
|
|
||||||
- Create a public gist.
|
|
||||||
(Only relevant if you've set gists to be private by default.)
|
|
||||||
|
|
||||||
:Gist -P
|
|
||||||
|
|
||||||
> This is only relevant if you've set gists to be private by default;
|
|
||||||
> if you get an empty gist list, try ":Gist --abandon".
|
|
||||||
|
|
||||||
- Create a gist anonymously.
|
|
||||||
|
|
||||||
:Gist -a
|
|
||||||
|
|
||||||
- Create a gist with all open buffers.
|
|
||||||
|
|
||||||
:Gist -m
|
|
||||||
|
|
||||||
- Edit the gist (you need to have opened the gist buffer first).
|
|
||||||
You can update the gist with the ":w" command within the gist buffer.
|
|
||||||
|
|
||||||
:Gist -e
|
|
||||||
|
|
||||||
- Edit the gist with name 'foo.js' (you need to have opened the gist buffer
|
|
||||||
first).
|
|
||||||
|
|
||||||
:Gist -e foo.js
|
|
||||||
|
|
||||||
- Post/Edit with the description " (you need to have opened the gist buffer
|
|
||||||
first). >
|
|
||||||
|
|
||||||
:Gist -s something
|
|
||||||
:Gist -e -s something
|
|
||||||
|
|
||||||
- Delete the gist (you need to have opened the gist buffer first).
|
|
||||||
Password authentication is needed.
|
|
||||||
|
|
||||||
:Gist -d
|
|
||||||
|
|
||||||
- Fork the gist (you need to have opened the gist buffer first).
|
|
||||||
Password authentication is needed.
|
|
||||||
|
|
||||||
:Gist -f
|
|
||||||
|
|
||||||
- Star the gist (you need to have opened the gist buffer first).
|
|
||||||
Password authentication is needed.
|
|
||||||
|
|
||||||
:Gist +1
|
|
||||||
|
|
||||||
- Unstar the gist (you need to have opened the gist buffer first).
|
|
||||||
Password authentication is needed.
|
|
||||||
|
|
||||||
:Gist -1
|
|
||||||
|
|
||||||
- Get gist XXXXX.
|
|
||||||
|
|
||||||
:Gist XXXXX
|
|
||||||
|
|
||||||
- Get gist XXXXX and add to clipboard.
|
|
||||||
|
|
||||||
:Gist -c XXXXX
|
|
||||||
|
|
||||||
- List your public gists.
|
|
||||||
|
|
||||||
:Gist -l
|
|
||||||
|
|
||||||
- List gists from user "mattn".
|
|
||||||
|
|
||||||
:Gist -l mattn
|
|
||||||
|
|
||||||
- List everyone's gists.
|
|
||||||
|
|
||||||
:Gist -la
|
|
||||||
|
|
||||||
- List gists from your starred gists.
|
|
||||||
|
|
||||||
:Gist -ls
|
|
||||||
|
|
||||||
## Tips:
|
|
||||||
|
|
||||||
If you set g:gist_clip_command, gist.vim will copy the gist code with option
|
|
||||||
'-c'.
|
|
||||||
|
|
||||||
- Mac:
|
|
||||||
|
|
||||||
let g:gist_clip_command = 'pbcopy'
|
|
||||||
|
|
||||||
- Linux:
|
|
||||||
|
|
||||||
let g:gist_clip_command = 'xclip -selection clipboard'
|
|
||||||
|
|
||||||
- Others (cygwin?):
|
|
||||||
|
|
||||||
let g:gist_clip_command = 'putclip'
|
|
||||||
|
|
||||||
If you want to detect filetype from the filename:
|
|
||||||
|
|
||||||
let g:gist_detect_filetype = 1
|
|
||||||
|
|
||||||
If you want to open browser after the post:
|
|
||||||
|
|
||||||
let g:gist_open_browser_after_post = 1
|
|
||||||
|
|
||||||
If you want to change the browser:
|
|
||||||
|
|
||||||
let g:gist_browser_command = 'w3m %URL%'
|
|
||||||
|
|
||||||
or:
|
|
||||||
|
|
||||||
let g:gist_browser_command = 'opera %URL% &'
|
|
||||||
|
|
||||||
On windows, this should work with your user settings.
|
|
||||||
|
|
||||||
If you want to show your private gists with ":Gist -l":
|
|
||||||
|
|
||||||
let g:gist_show_privates = 1
|
|
||||||
|
|
||||||
If you want your gist to be private by default:
|
|
||||||
|
|
||||||
let g:gist_post_private = 1
|
|
||||||
|
|
||||||
If you want to manipulate multiple files in a gist:
|
|
||||||
|
|
||||||
let g:gist_get_multiplefile = 1
|
|
||||||
|
|
||||||
If you want to use on Github Enterprise:
|
|
||||||
|
|
||||||
let g:github_api_url = 'http://your-github-enterprise-domain/api/v3'
|
|
||||||
|
|
||||||
You need to either set global git config:
|
|
||||||
|
|
||||||
$ git config --global github.user Username
|
|
||||||
|
|
||||||
## License:
|
|
||||||
|
|
||||||
Copyright 2010 by Yasuhiro Matsumoto
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
||||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
## Install:
|
|
||||||
|
|
||||||
Copy it to your plugin directory.
|
|
||||||
gist.vim will create a curl cookie-jar file in your runtimepath.
|
|
||||||
|
|
||||||
- rtp:
|
|
||||||
- autoload/gist.vim
|
|
||||||
- plugin/gist.vim
|
|
||||||
|
|
||||||
If you want to uninstall gist.vim, remember to also remove `~/.gist-vim`.
|
|
||||||
|
|
||||||
You need to install webapi-vim also:
|
|
||||||
|
|
||||||
http://www.vim.org/scripts/script.php?script_id=4019
|
|
||||||
|
|
||||||
If you want to use latest one:
|
|
||||||
|
|
||||||
https://github.com/mattn/webapi-vim
|
|
||||||
|
|
||||||
### Install with [Vundle](https://github.com/gmarik/vundle)
|
|
||||||
|
|
||||||
Add the following lines to your `.vimrc`.
|
|
||||||
|
|
||||||
Bundle 'mattn/webapi-vim'
|
|
||||||
Bundle 'mattn/gist-vim'
|
|
||||||
|
|
||||||
Now restart Vim and run `:BundleInstall`.
|
|
||||||
|
|
||||||
## Requirements:
|
|
||||||
|
|
||||||
- curl command (http://curl.haxx.se/)
|
|
||||||
- webapi-vim (https://github.com/mattn/webapi-vim)
|
|
||||||
- and if you want to use your git profile, the git command-line client.
|
|
||||||
|
|
||||||
## Setup:
|
|
||||||
|
|
||||||
This plugin uses github API v3. Setting value is stored in `~/.gist-vim`.
|
|
||||||
gist-vim have two ways to access APIs.
|
|
||||||
|
|
||||||
First, you need to set your Github username in global git config:
|
|
||||||
|
|
||||||
$ git config --global github.user Username
|
|
||||||
|
|
||||||
Then, gist.vim will ask for your password to create an authorization when you
|
|
||||||
first use it. The password is not stored and only the OAuth access token will
|
|
||||||
be kept for later use. You can revoke the token at any time from the list of
|
|
||||||
["Authorized applications" on Github's "Account Settings" page](https://github.com/settings/applications).
|
|
||||||
|
|
@ -1,919 +0,0 @@
|
||||||
"=============================================================================
|
|
||||||
" File: gist.vim
|
|
||||||
" Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" Last Change: 21-Jan-2013.
|
|
||||||
" Version: 7.1
|
|
||||||
" WebPage: http://github.com/mattn/gist-vim
|
|
||||||
" License: BSD
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
if !exists('g:github_user') && !executable('git')
|
|
||||||
echohl ErrorMsg | echomsg "Gist: require 'git' command" | echohl None
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !executable('curl')
|
|
||||||
echohl ErrorMsg | echomsg "Gist: require 'curl' command" | echohl None
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
|
|
||||||
let s:configfile = expand('~/.gist-vim')
|
|
||||||
|
|
||||||
if !exists('g:github_user')
|
|
||||||
let s:system = function(get(g:, 'webapi#system_function', 'system'))
|
|
||||||
let g:github_user = substitute(s:system('git config --get github.user'), "\n", '', '')
|
|
||||||
if strlen(g:github_user) == 0
|
|
||||||
let g:github_user = $GITHUB_USER
|
|
||||||
end
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists('g:github_api_url')
|
|
||||||
let g:github_api_url = 'https://api.github.com'
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists('g:gist_update_on_write')
|
|
||||||
let g:gist_update_on_write = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! s:get_browser_command()
|
|
||||||
let gist_browser_command = get(g:, 'gist_browser_command', '')
|
|
||||||
if gist_browser_command == ''
|
|
||||||
if has('win32') || has('win64')
|
|
||||||
let gist_browser_command = '!start rundll32 url.dll,FileProtocolHandler %URL%'
|
|
||||||
elseif has('mac') || has('macunix') || has('gui_macvim') || system('uname') =~? '^darwin'
|
|
||||||
let gist_browser_command = 'open %URL%'
|
|
||||||
elseif executable('xdg-open')
|
|
||||||
let gist_browser_command = 'xdg-open %URL%'
|
|
||||||
elseif executable('firefox')
|
|
||||||
let gist_browser_command = 'firefox %URL% &'
|
|
||||||
else
|
|
||||||
let gist_browser_command = ''
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return gist_browser_command
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:open_browser(url)
|
|
||||||
let cmd = s:get_browser_command()
|
|
||||||
if len(cmd) == 0
|
|
||||||
redraw
|
|
||||||
echohl WarningMsg
|
|
||||||
echo "It seems that you don't have general web browser. Open URL below."
|
|
||||||
echohl None
|
|
||||||
echo a:url
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if cmd =~ '^!'
|
|
||||||
let cmd = substitute(cmd, '%URL%', '\=shellescape(a:url)', 'g')
|
|
||||||
silent! exec cmd
|
|
||||||
elseif cmd =~ '^:[A-Z]'
|
|
||||||
let cmd = substitute(cmd, '%URL%', '\=a:url', 'g')
|
|
||||||
exec cmd
|
|
||||||
else
|
|
||||||
let cmd = substitute(cmd, '%URL%', '\=shellescape(a:url)', 'g')
|
|
||||||
call system(cmd)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:shellwords(str)
|
|
||||||
let words = split(a:str, '\%(\([^ \t\''"]\+\)\|''\([^\'']*\)''\|"\(\%([^\"\\]\|\\.\)*\)"\)\zs\s*\ze')
|
|
||||||
let words = map(words, 'substitute(v:val, ''\\\([\\ ]\)'', ''\1'', "g")')
|
|
||||||
let words = map(words, 'matchstr(v:val, ''^\%\("\zs\(.*\)\ze"\|''''\zs\(.*\)\ze''''\|.*\)$'')')
|
|
||||||
return words
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:format_gist(gist)
|
|
||||||
let files = sort(keys(a:gist.files))
|
|
||||||
if empty(files)
|
|
||||||
return ""
|
|
||||||
endif
|
|
||||||
let file = a:gist.files[files[0]]
|
|
||||||
if has_key(file, "content")
|
|
||||||
let code = file.content
|
|
||||||
let code = "\n".join(map(split(code, "\n"), '" ".v:val'), "\n")
|
|
||||||
else
|
|
||||||
let code = ""
|
|
||||||
endif
|
|
||||||
return printf("gist: %s %s%s", a:gist.id, type(a:gist.description)==0?"": a:gist.description, code)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" Note: A colon in the file name has side effects on Windows due to NTFS Alternate Data Streams; avoid it.
|
|
||||||
let s:bufprefix = 'gist' . (has('unix') ? ':' : '_')
|
|
||||||
function! s:GistList(gistls, page)
|
|
||||||
if a:gistls == '-all'
|
|
||||||
let url = g:github_api_url.'/gists/public'
|
|
||||||
elseif get(g:, 'gist_show_privates', 0) && a:gistls == 'starred'
|
|
||||||
let url = g:github_api_url.'/gists/starred'
|
|
||||||
elseif get(g:, 'gist_show_privates') && a:gistls == 'mine'
|
|
||||||
let url = g:github_api_url.'/gists'
|
|
||||||
else
|
|
||||||
let url = g:github_api_url.'/users/'.a:gistls.'/gists'
|
|
||||||
endif
|
|
||||||
let winnum = bufwinnr(bufnr(s:bufprefix.a:gistls))
|
|
||||||
if winnum != -1
|
|
||||||
if winnum != bufwinnr('%')
|
|
||||||
exe winnum 'wincmd w'
|
|
||||||
endif
|
|
||||||
setlocal modifiable
|
|
||||||
else
|
|
||||||
exec 'silent noautocmd split' s:bufprefix.a:gistls
|
|
||||||
endif
|
|
||||||
if a:page > 1
|
|
||||||
let oldlines = getline(0, line('$'))
|
|
||||||
let url = url . '?page=' . a:page
|
|
||||||
endif
|
|
||||||
|
|
||||||
setlocal modifiable
|
|
||||||
let old_undolevels = &undolevels
|
|
||||||
let oldlines = []
|
|
||||||
silent %d _
|
|
||||||
|
|
||||||
redraw | echon 'Listing gists... '
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
bw!
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg v:errmsg | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let res = webapi#http#get(url, '', { "Authorization": auth })
|
|
||||||
if v:shell_error != 0
|
|
||||||
bw!
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg 'Gists not found' | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let content = webapi#json#decode(res.content)
|
|
||||||
if type(content) == 4 && has_key(content, 'message') && len(content.message)
|
|
||||||
bw!
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg content.message | echohl None
|
|
||||||
if content.message == 'Bad credentials'
|
|
||||||
call delete(s:configfile)
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let lines = map(filter(content, '!empty(v:val.files)'), 's:format_gist(v:val)')
|
|
||||||
call setline(1, split(join(lines, "\n"), "\n"))
|
|
||||||
|
|
||||||
$put='more...'
|
|
||||||
|
|
||||||
let b:gistls = a:gistls
|
|
||||||
let b:page = a:page
|
|
||||||
setlocal buftype=nofile bufhidden=hide noswapfile
|
|
||||||
setlocal nomodified
|
|
||||||
setlocal nomodifiable
|
|
||||||
syntax match SpecialKey /^gist:/he=e-1
|
|
||||||
nnoremap <silent> <buffer> <cr> :call <SID>GistListAction(0)<cr>
|
|
||||||
nnoremap <silent> <buffer> <s-cr> :call <SID>GistListAction(1)<cr>
|
|
||||||
|
|
||||||
cal cursor(1+len(oldlines),1)
|
|
||||||
nohlsearch
|
|
||||||
redraw | echo ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! gist#list(user, ...)
|
|
||||||
let page = get(a:000, 0, 0)
|
|
||||||
if a:user == '-all'
|
|
||||||
let url = g:github_api_url.'/gists/public'
|
|
||||||
elseif get(g:, 'gist_show_privates', 0) && a:user == 'starred'
|
|
||||||
let url = g:github_api_url.'/gists/starred'
|
|
||||||
elseif get(g:, 'gist_show_privates') && a:user == 'mine'
|
|
||||||
let url = g:github_api_url.'/gists'
|
|
||||||
else
|
|
||||||
let url = g:github_api_url.'/users/'.a:user.'/gists'
|
|
||||||
endif
|
|
||||||
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
return []
|
|
||||||
endif
|
|
||||||
let res = webapi#http#get(url, '', { "Authorization": auth })
|
|
||||||
return webapi#json#decode(res.content)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistGetFileName(gistid)
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
let res = webapi#http#get(g:github_api_url.'/gists/'.a:gistid, '', { "Authorization": auth })
|
|
||||||
let gist = webapi#json#decode(res.content)
|
|
||||||
if has_key(gist, 'files')
|
|
||||||
return sort(keys(gist.files))[0]
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistDetectFiletype(gistid)
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
let res = webapi#http#get(g:github_api_url.'/gists/'.a:gistid, '', { "Authorization": auth })
|
|
||||||
let gist = webapi#json#decode(res.content)
|
|
||||||
let filename = sort(keys(gist.files))[0]
|
|
||||||
let ext = fnamemodify(filename, ':e')
|
|
||||||
if has_key(s:extmap, ext)
|
|
||||||
let type = s:extmap[ext]
|
|
||||||
else
|
|
||||||
let type = get(gist.files[filename], "type", "text")
|
|
||||||
endif
|
|
||||||
silent! exec "setlocal ft=".tolower(type)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistWrite(fname)
|
|
||||||
if substitute(a:fname, '\\', '/', 'g') == expand("%:p:gs@\\@/@")
|
|
||||||
if g:gist_update_on_write != 2 || v:cmdbang
|
|
||||||
Gist -e
|
|
||||||
else
|
|
||||||
echohl ErrorMsg | echomsg 'Please type ":w!" to update a gist.' | echohl None
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
exe "w".(v:cmdbang ? "!" : "") fnameescape(v:cmdarg) fnameescape(a:fname)
|
|
||||||
silent! exe "file" fnameescape(a:fname)
|
|
||||||
silent! au! BufWriteCmd <buffer>
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistGet(gistid, clipboard)
|
|
||||||
redraw | echon 'Getting gist... '
|
|
||||||
let res = webapi#http#get(g:github_api_url.'/gists/'.a:gistid, '', { "Authorization": s:GistGetAuthHeader() })
|
|
||||||
let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*')
|
|
||||||
if status =~ '^2'
|
|
||||||
let gist = webapi#json#decode(res.content)
|
|
||||||
if get(g:, 'gist_get_multiplefile', 0) != 0
|
|
||||||
let num_file = len(keys(gist.files))
|
|
||||||
else
|
|
||||||
let num_file = 1
|
|
||||||
endif
|
|
||||||
redraw
|
|
||||||
if num_file > len(keys(gist.files))
|
|
||||||
echohl ErrorMsg | echomsg 'Gist not found' | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
for n in range(num_file)
|
|
||||||
try
|
|
||||||
let old_undolevels = &undolevels
|
|
||||||
let filename = sort(keys(gist.files))[n]
|
|
||||||
|
|
||||||
let winnum = bufwinnr(bufnr(s:bufprefix.a:gistid."/".filename))
|
|
||||||
if winnum != -1
|
|
||||||
if winnum != bufwinnr('%')
|
|
||||||
exe winnum 'wincmd w'
|
|
||||||
endif
|
|
||||||
setlocal modifiable
|
|
||||||
else
|
|
||||||
exec 'silent noautocmd new'
|
|
||||||
setlocal noswapfile
|
|
||||||
exec 'noautocmd file' s:bufprefix.a:gistid."/".fnameescape(filename)
|
|
||||||
endif
|
|
||||||
set undolevels=-1
|
|
||||||
filetype detect
|
|
||||||
silent %d _
|
|
||||||
|
|
||||||
let content = gist.files[filename].content
|
|
||||||
call setline(1, split(content, "\n"))
|
|
||||||
let b:gist = {
|
|
||||||
\ "filename": filename,
|
|
||||||
\ "id": gist.id,
|
|
||||||
\ "description": gist.description,
|
|
||||||
\ "private": gist.public =~ 'true',
|
|
||||||
\}
|
|
||||||
catch
|
|
||||||
let &undolevels = old_undolevels
|
|
||||||
bw!
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg 'Gist contains binary' | echohl None
|
|
||||||
return
|
|
||||||
endtry
|
|
||||||
let &undolevels = old_undolevels
|
|
||||||
setlocal buftype=acwrite bufhidden=delete noswapfile
|
|
||||||
setlocal nomodified
|
|
||||||
doau StdinReadPost,BufRead,BufReadPost
|
|
||||||
let gist_detect_filetype = get(g:, 'gist_detect_filetype', 0)
|
|
||||||
if (&ft == '' && gist_detect_filetype == 1) || gist_detect_filetype == 2
|
|
||||||
call s:GistDetectFiletype(a:gistid)
|
|
||||||
endif
|
|
||||||
if a:clipboard
|
|
||||||
if exists('g:gist_clip_command')
|
|
||||||
exec 'silent w !'.g:gist_clip_command
|
|
||||||
elseif has('clipboard')
|
|
||||||
silent! %yank +
|
|
||||||
else
|
|
||||||
%yank
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
1
|
|
||||||
au! BufWriteCmd <buffer> call s:GistWrite(expand("<amatch>"))
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
bw!
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg 'Gist not found' | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistListAction(shift)
|
|
||||||
let line = getline('.')
|
|
||||||
let mx = '^gist:\s*\zs\(\w\+\)\ze.*'
|
|
||||||
if line =~# mx
|
|
||||||
let gistid = matchstr(line, mx)
|
|
||||||
if a:shift
|
|
||||||
call s:open_browser("https://gist.github.com/" . gistid)
|
|
||||||
else
|
|
||||||
call s:GistGet(gistid, 0)
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
if line =~# '^more\.\.\.$'
|
|
||||||
call s:GistList(b:gistls, b:page+1)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistUpdate(content, gistid, gistnm, desc)
|
|
||||||
let gist = { "id": a:gistid, "files" : {}, "description": "","public": function('webapi#json#true') }
|
|
||||||
if exists('b:gist')
|
|
||||||
if has_key(b:gist, 'private') && b:gist.private | let gist["public"] = function('webapi#json#false') | endif
|
|
||||||
if has_key(b:gist, 'description') | let gist["description"] = b:gist.description | endif
|
|
||||||
if has_key(b:gist, 'filename') | let filename = b:gist.filename | endif
|
|
||||||
else
|
|
||||||
let filename = a:gistnm
|
|
||||||
if len(filename) == 0 | let filename = s:GistGetFileName(a:gistid) | endif
|
|
||||||
if len(filename) == 0 | let filename = s:get_current_filename(1) | endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg v:errmsg | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Update description
|
|
||||||
" If no new description specified, keep the old description
|
|
||||||
if a:desc != ' '
|
|
||||||
let gist["description"] = a:desc
|
|
||||||
else
|
|
||||||
let res = webapi#http#get(g:github_api_url.'/gists/'.a:gistid, '', { "Authorization": auth })
|
|
||||||
let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*')
|
|
||||||
if status =~ '^2'
|
|
||||||
let old_gist = webapi#json#decode(res.content)
|
|
||||||
let gist["description"] = old_gist.description
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
let gist.files[filename] = { "content": a:content, "filename": filename }
|
|
||||||
|
|
||||||
redraw | echon 'Updating gist... '
|
|
||||||
let res = webapi#http#post(g:github_api_url.'/gists/' . a:gistid,
|
|
||||||
\ webapi#json#encode(gist), {
|
|
||||||
\ "Authorization": auth,
|
|
||||||
\ "Content-Type": "application/json",
|
|
||||||
\})
|
|
||||||
let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*')
|
|
||||||
if status =~ '^2'
|
|
||||||
let obj = webapi#json#decode(res.content)
|
|
||||||
let loc = obj["html_url"]
|
|
||||||
redraw | echomsg 'Done: '.loc
|
|
||||||
let b:gist = {"id": a:gistid, "filename": filename}
|
|
||||||
setlocal nomodified
|
|
||||||
else
|
|
||||||
let loc = ''
|
|
||||||
let status = matchstr(status, '^\d\+\s*\zs.*')
|
|
||||||
echohl ErrorMsg | echomsg 'Post failed: '.status | echohl None
|
|
||||||
endif
|
|
||||||
return loc
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistDelete(gistid)
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg v:errmsg | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
redraw | echon 'Deleting gist... '
|
|
||||||
let res = webapi#http#post(g:github_api_url.'/gists/'.a:gistid, '', {
|
|
||||||
\ "Authorization": auth,
|
|
||||||
\ "Content-Type": "application/json",
|
|
||||||
\}, 'DELETE')
|
|
||||||
let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*')
|
|
||||||
if status =~ '^2'
|
|
||||||
redraw | echomsg 'Done: '
|
|
||||||
if exists('b:gist')
|
|
||||||
unlet b:gist
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let status = matchstr(status, '^\d\+\s*\zs.*')
|
|
||||||
echohl ErrorMsg | echomsg 'Delete failed: '.status | echohl None
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_current_filename(no)
|
|
||||||
let filename = expand('%:t')
|
|
||||||
if len(filename) == 0 && &ft != ''
|
|
||||||
let pair = filter(items(s:extmap), 'v:val[1] == &ft')
|
|
||||||
if len(pair) > 0
|
|
||||||
let filename = printf('gistfile%d%s', a:no, pair[0][0])
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if filename == ''
|
|
||||||
let filename = printf('gistfile%d.txt', a:no)
|
|
||||||
endif
|
|
||||||
return filename
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" GistPost function:
|
|
||||||
" Post new gist to github
|
|
||||||
"
|
|
||||||
" if there is an embedded gist url or gist id in your file,
|
|
||||||
" it will just update it.
|
|
||||||
" -- by c9s
|
|
||||||
"
|
|
||||||
" embedded gist url format:
|
|
||||||
"
|
|
||||||
" Gist: https://gist.github.com/123123
|
|
||||||
"
|
|
||||||
" embedded gist id format:
|
|
||||||
"
|
|
||||||
" GistID: 123123
|
|
||||||
"
|
|
||||||
function! s:GistPost(content, private, desc, anonymous)
|
|
||||||
let gist = { "files" : {}, "description": "","public": function('webapi#json#true') }
|
|
||||||
if a:desc != ' ' | let gist["description"] = a:desc | endif
|
|
||||||
if a:private | let gist["public"] = function('webapi#json#false') | endif
|
|
||||||
let filename = s:get_current_filename(1)
|
|
||||||
let gist.files[filename] = { "content": a:content, "filename": filename }
|
|
||||||
|
|
||||||
let header = {"Content-Type": "application/json"}
|
|
||||||
if !a:anonymous
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg v:errmsg | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let header["Authorization"] = auth
|
|
||||||
endif
|
|
||||||
|
|
||||||
redraw | echon 'Posting it to gist... '
|
|
||||||
let res = webapi#http#post(g:github_api_url.'/gists', webapi#json#encode(gist), header)
|
|
||||||
let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*')
|
|
||||||
if status =~ '^2'
|
|
||||||
let obj = webapi#json#decode(res.content)
|
|
||||||
let loc = obj["html_url"]
|
|
||||||
redraw | echomsg 'Done: '.loc
|
|
||||||
let b:gist = {
|
|
||||||
\ "filename": filename,
|
|
||||||
\ "id": matchstr(loc, '[^/]\+$'),
|
|
||||||
\ "description": gist['description'],
|
|
||||||
\ "private": a:private,
|
|
||||||
\}
|
|
||||||
else
|
|
||||||
let loc = ''
|
|
||||||
let status = matchstr(status, '^\d\+\s*\zs.*')
|
|
||||||
echohl ErrorMsg | echomsg 'Post failed: '.status | echohl None
|
|
||||||
endif
|
|
||||||
return loc
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistPostBuffers(private, desc, anonymous)
|
|
||||||
let bufnrs = range(1, bufnr("$"))
|
|
||||||
let bn = bufnr('%')
|
|
||||||
let query = []
|
|
||||||
|
|
||||||
let gist = { "files" : {}, "description": "","public": function('webapi#json#true') }
|
|
||||||
if a:desc != ' ' | let gist["description"] = a:desc | endif
|
|
||||||
if a:private | let gist["public"] = function('webapi#json#false') | endif
|
|
||||||
|
|
||||||
let index = 1
|
|
||||||
for bufnr in bufnrs
|
|
||||||
if !bufexists(bufnr) || buflisted(bufnr) == 0
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
echo "Creating gist content".index."... "
|
|
||||||
silent! exec "buffer!" bufnr
|
|
||||||
let content = join(getline(1, line('$')), "\n")
|
|
||||||
let filename = s:get_current_filename(index)
|
|
||||||
let gist.files[filename] = { "content": content, "filename": filename }
|
|
||||||
let index = index + 1
|
|
||||||
endfor
|
|
||||||
silent! exec "buffer!" bn
|
|
||||||
|
|
||||||
let header = {"Content-Type": "application/json"}
|
|
||||||
if !a:anonymous
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
redraw
|
|
||||||
echohl ErrorMsg | echomsg v:errmsg | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let header["Authorization"] = auth
|
|
||||||
endif
|
|
||||||
|
|
||||||
redraw | echon 'Posting it to gist... '
|
|
||||||
let res = webapi#http#post(g:github_api_url.'/gists', webapi#json#encode(gist), header)
|
|
||||||
let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*')
|
|
||||||
if status =~ '^2'
|
|
||||||
let obj = webapi#json#decode(res.content)
|
|
||||||
let loc = obj["html_url"]
|
|
||||||
redraw | echomsg 'Done: '.loc
|
|
||||||
let b:gist = {"id": matchstr(loc, '[^/]\+$'), "filename": filename, "private": a:private}
|
|
||||||
else
|
|
||||||
let loc = ''
|
|
||||||
let status = matchstr(status, '^\d\+\s*\zs.*')
|
|
||||||
echohl ErrorMsg | echomsg 'Post failed: '.status | echohl None
|
|
||||||
endif
|
|
||||||
return loc
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! gist#Gist(count, line1, line2, ...)
|
|
||||||
redraw
|
|
||||||
if strlen(g:github_user) == 0
|
|
||||||
echohl ErrorMsg | echomsg "You don't have github account. read ':help gist-vim-setup'." | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let bufname = bufname("%")
|
|
||||||
" find GistID: in content , then we should just update
|
|
||||||
let gistid = ''
|
|
||||||
let gistls = ''
|
|
||||||
let gistnm = ''
|
|
||||||
let gistdesc = ' '
|
|
||||||
let private = get(g:, 'gist_post_private', 0)
|
|
||||||
let multibuffer = 0
|
|
||||||
let clipboard = 0
|
|
||||||
let deletepost = 0
|
|
||||||
let editpost = 0
|
|
||||||
let anonymous = 0
|
|
||||||
let listmx = '^\%(-l\|--list\)\s*\([^\s]\+\)\?$'
|
|
||||||
let bufnamemx = '^' . s:bufprefix .'\(\zs[0-9a-f]\+\ze\|\zs[0-9a-f]\+\ze[/\\].*\)$'
|
|
||||||
if bufname =~ bufnamemx
|
|
||||||
let gistidbuf = matchstr(bufname, bufnamemx)
|
|
||||||
else
|
|
||||||
let gistidbuf = matchstr(join(getline(a:line1, a:line2), "\n"), 'GistID:\s*\zs\w\+')
|
|
||||||
endif
|
|
||||||
|
|
||||||
let args = (a:0 > 0) ? s:shellwords(a:1) : []
|
|
||||||
for arg in args
|
|
||||||
if arg =~ '^\(-h\|--help\)$\C'
|
|
||||||
help :Gist
|
|
||||||
return
|
|
||||||
elseif arg =~ '^\(-la\|--listall\)$\C'
|
|
||||||
let gistls = '-all'
|
|
||||||
elseif arg =~ '^\(-ls\|--liststar\)$\C'
|
|
||||||
let gistls = 'starred'
|
|
||||||
elseif arg =~ '^\(-l\|--list\)$\C'
|
|
||||||
if get(g:, 'gist_show_privates')
|
|
||||||
let gistls = 'mine'
|
|
||||||
else
|
|
||||||
let gistls = g:github_user
|
|
||||||
endif
|
|
||||||
elseif arg =~ '^\(-m\|--multibuffer\)$\C'
|
|
||||||
let multibuffer = 1
|
|
||||||
elseif arg =~ '^\(-p\|--private\)$\C'
|
|
||||||
let private = 1
|
|
||||||
elseif arg =~ '^\(-P\|--public\)$\C'
|
|
||||||
let private = 0
|
|
||||||
elseif arg =~ '^\(-a\|--anonymous\)$\C'
|
|
||||||
let anonymous = 1
|
|
||||||
elseif arg =~ '^\(-s\|--description\)$\C'
|
|
||||||
let gistdesc = ''
|
|
||||||
elseif arg =~ '^\(-c\|--clipboard\)$\C'
|
|
||||||
let clipboard = 1
|
|
||||||
elseif arg =~ '^--rawurl$\C' && gistidbuf != '' && g:github_api_url == 'https://api.github.com'
|
|
||||||
let gistid = gistidbuf
|
|
||||||
echo 'https://gist.github.com/raw/'.gistid
|
|
||||||
return
|
|
||||||
elseif arg =~ '^\(-d\|--delete\)$\C' && gistidbuf != ''
|
|
||||||
let gistid = gistidbuf
|
|
||||||
let deletepost = 1
|
|
||||||
elseif arg =~ '^\(-e\|--edit\)$\C' && gistidbuf != ''
|
|
||||||
let gistid = gistidbuf
|
|
||||||
let editpost = 1
|
|
||||||
elseif arg =~ '^\(+1\|--star\)$\C' && gistidbuf != ''
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
echohl ErrorMsg | echomsg v:errmsg | echohl None
|
|
||||||
else
|
|
||||||
let gistid = gistidbuf
|
|
||||||
let res = webapi#http#post(g:github_api_url.'/gists/'.gistid.'/star', '', { "Authorization": auth }, 'PUT')
|
|
||||||
let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*')
|
|
||||||
if status =~ '^2'
|
|
||||||
echomsg "Stared" gistid
|
|
||||||
else
|
|
||||||
echohl ErrorMsg | echomsg 'Star failed' | echohl None
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
elseif arg =~ '^\(-1\|--unstar\)$\C' && gistidbuf != ''
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
echohl ErrorMsg | echomsg v:errmsg | echohl None
|
|
||||||
else
|
|
||||||
let gistid = gistidbuf
|
|
||||||
let res = webapi#http#post(g:github_api_url.'/gists/'.gistid.'/star', '', { "Authorization": auth }, 'DELETE')
|
|
||||||
if status =~ '^2'
|
|
||||||
echomsg "Unstared" gistid
|
|
||||||
else
|
|
||||||
echohl ErrorMsg | echomsg 'Unstar failed' | echohl None
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return
|
|
||||||
elseif arg =~ '^\(-f\|--fork\)$\C' && gistidbuf != ''
|
|
||||||
let auth = s:GistGetAuthHeader()
|
|
||||||
if len(auth) == 0
|
|
||||||
echohl ErrorMsg | echomsg v:errmsg | echohl None
|
|
||||||
return
|
|
||||||
else
|
|
||||||
let gistid = gistidbuf
|
|
||||||
let res = webapi#http#post(g:github_api_url.'/gists/'.gistid.'/fork', '', { "Authorization": auth })
|
|
||||||
let status = matchstr(matchstr(res.header, '^Status:'), '^[^:]\+: \zs.*')
|
|
||||||
if status =~ '^2'
|
|
||||||
let obj = webapi#json#decode(res.content)
|
|
||||||
let gistid = obj["id"]
|
|
||||||
else
|
|
||||||
echohl ErrorMsg | echomsg 'Fork failed' | echohl None
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
elseif arg !~ '^-' && len(gistnm) == 0
|
|
||||||
if gistdesc != ' '
|
|
||||||
let gistdesc = matchstr(arg, '^\s*\zs.*\ze\s*$')
|
|
||||||
elseif editpost == 1 || deletepost == 1
|
|
||||||
let gistnm = arg
|
|
||||||
elseif len(gistls) > 0 && arg != '^\w\+$\C'
|
|
||||||
let gistls = arg
|
|
||||||
elseif arg =~ '^[0-9a-z]\+$\C'
|
|
||||||
let gistid = arg
|
|
||||||
else
|
|
||||||
echohl ErrorMsg | echomsg 'Invalid arguments: '.arg | echohl None
|
|
||||||
unlet args
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
elseif len(arg) > 0
|
|
||||||
echohl ErrorMsg | echomsg 'Invalid arguments: '.arg | echohl None
|
|
||||||
unlet args
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
unlet args
|
|
||||||
"echo "gistid=".gistid
|
|
||||||
"echo "gistls=".gistls
|
|
||||||
"echo "gistnm=".gistnm
|
|
||||||
"echo "gistdesc=".gistdesc
|
|
||||||
"echo "private=".private
|
|
||||||
"echo "clipboard=".clipboard
|
|
||||||
"echo "editpost=".editpost
|
|
||||||
"echo "deletepost=".deletepost
|
|
||||||
|
|
||||||
if gistidbuf != '' && gistid == '' && editpost == 0 && deletepost == 0
|
|
||||||
let editpost = 1
|
|
||||||
let gistid = gistidbuf
|
|
||||||
endif
|
|
||||||
|
|
||||||
if len(gistls) > 0
|
|
||||||
call s:GistList(gistls, 1)
|
|
||||||
elseif len(gistid) > 0 && editpost == 0 && deletepost == 0
|
|
||||||
call s:GistGet(gistid, clipboard)
|
|
||||||
else
|
|
||||||
let url = ''
|
|
||||||
if multibuffer == 1
|
|
||||||
let url = s:GistPostBuffers(private, gistdesc, anonymous)
|
|
||||||
else
|
|
||||||
if a:count < 1
|
|
||||||
let content = join(getline(a:line1, a:line2), "\n")
|
|
||||||
else
|
|
||||||
let save_regcont = @"
|
|
||||||
let save_regtype = getregtype('"')
|
|
||||||
silent! normal! gvy
|
|
||||||
let content = @"
|
|
||||||
call setreg('"', save_regcont, save_regtype)
|
|
||||||
endif
|
|
||||||
if editpost == 1
|
|
||||||
let url = s:GistUpdate(content, gistid, gistnm, gistdesc)
|
|
||||||
elseif deletepost == 1
|
|
||||||
call s:GistDelete(gistid)
|
|
||||||
else
|
|
||||||
let url = s:GistPost(content, private, gistdesc, anonymous)
|
|
||||||
endif
|
|
||||||
if a:count >= 1 && get(g:, 'gist_keep_selection', 0) == 1
|
|
||||||
silent! normal! gv
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if len(url) > 0
|
|
||||||
if get(g:, 'gist_open_browser_after_post', 0) == 1
|
|
||||||
call s:open_browser(url)
|
|
||||||
endif
|
|
||||||
let gist_put_url_to_clipboard_after_post = get(g:, 'gist_put_url_to_clipboard_after_post', 1)
|
|
||||||
if gist_put_url_to_clipboard_after_post > 0
|
|
||||||
if gist_put_url_to_clipboard_after_post == 2
|
|
||||||
let url = url . "\n"
|
|
||||||
endif
|
|
||||||
if exists('g:gist_clip_command')
|
|
||||||
call system(g:gist_clip_command, url)
|
|
||||||
elseif has('unix') && !has('xterm_clipboard')
|
|
||||||
let @" = url
|
|
||||||
else
|
|
||||||
let @+ = url
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:GistGetAuthHeader()
|
|
||||||
if get(g:, 'gist_use_password_in_gitconfig', 0) != 0
|
|
||||||
let password = substitute(system('git config --get github.password'), "\n", '', '')
|
|
||||||
if password =~ '^!' | let password = system(password[1:]) | endif
|
|
||||||
return printf("basic %s", webapi#base64#b64encode(g:github_user.":".password))
|
|
||||||
endif
|
|
||||||
let auth = ""
|
|
||||||
if filereadable(s:configfile)
|
|
||||||
let str = join(readfile(s:configfile), "")
|
|
||||||
if type(str) == 1
|
|
||||||
let auth = str
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if len(auth) > 0
|
|
||||||
return auth
|
|
||||||
endif
|
|
||||||
|
|
||||||
redraw
|
|
||||||
echohl WarningMsg
|
|
||||||
echo 'Gist.vim requires authorization to use the Github API. These settings are stored in "~/.gist-vim". If you want to revoke, do "rm ~/.gist-vim".'
|
|
||||||
echohl None
|
|
||||||
let password = inputsecret("Github Password for ".g:github_user.":")
|
|
||||||
if len(password) > 0
|
|
||||||
let insecureSecret = printf("basic %s", webapi#base64#b64encode(g:github_user.":".password))
|
|
||||||
let res = webapi#http#post(g:github_api_url.'/authorizations', webapi#json#encode({
|
|
||||||
\ "scopes" : ["gist"],
|
|
||||||
\ "note" : "Gist.vim on ".hostname(),
|
|
||||||
\ "note_url" : "http://www.vim.org/scripts/script.php?script_id=2423"
|
|
||||||
\}), {
|
|
||||||
\ "Content-Type" : "application/json",
|
|
||||||
\ "Authorization" : insecureSecret,
|
|
||||||
\})
|
|
||||||
let authorization = webapi#json#decode(res.content)
|
|
||||||
if has_key(authorization, 'token')
|
|
||||||
let secret = printf("token %s", authorization.token)
|
|
||||||
call writefile([secret], s:configfile)
|
|
||||||
if !(has('win32') || has('win64'))
|
|
||||||
call system("chmod go= ".s:configfile)
|
|
||||||
endif
|
|
||||||
elseif has_key(authorization, 'message')
|
|
||||||
let secret = ''
|
|
||||||
let v:errmsg = authorization.message
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let secret = ''
|
|
||||||
let v:errmsg = 'Canceled'
|
|
||||||
endif
|
|
||||||
return secret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:extmap = {
|
|
||||||
\".adb": "ada",
|
|
||||||
\".ahk": "ahk",
|
|
||||||
\".arc": "arc",
|
|
||||||
\".as": "actionscript",
|
|
||||||
\".asm": "asm",
|
|
||||||
\".asp": "asp",
|
|
||||||
\".aw": "php",
|
|
||||||
\".b": "b",
|
|
||||||
\".bat": "bat",
|
|
||||||
\".befunge": "befunge",
|
|
||||||
\".bmx": "bmx",
|
|
||||||
\".boo": "boo",
|
|
||||||
\".c-objdump": "c-objdump",
|
|
||||||
\".c": "c",
|
|
||||||
\".cfg": "cfg",
|
|
||||||
\".cfm": "cfm",
|
|
||||||
\".ck": "ck",
|
|
||||||
\".cl": "cl",
|
|
||||||
\".clj": "clj",
|
|
||||||
\".cmake": "cmake",
|
|
||||||
\".coffee": "coffee",
|
|
||||||
\".cpp": "cpp",
|
|
||||||
\".cppobjdump": "cppobjdump",
|
|
||||||
\".cs": "csharp",
|
|
||||||
\".css": "css",
|
|
||||||
\".cw": "cw",
|
|
||||||
\".d-objdump": "d-objdump",
|
|
||||||
\".d": "d",
|
|
||||||
\".darcspatch": "darcspatch",
|
|
||||||
\".diff": "diff",
|
|
||||||
\".duby": "duby",
|
|
||||||
\".dylan": "dylan",
|
|
||||||
\".e": "e",
|
|
||||||
\".ebuild": "ebuild",
|
|
||||||
\".eclass": "eclass",
|
|
||||||
\".el": "lisp",
|
|
||||||
\".erb": "erb",
|
|
||||||
\".erl": "erlang",
|
|
||||||
\".f90": "f90",
|
|
||||||
\".factor": "factor",
|
|
||||||
\".feature": "feature",
|
|
||||||
\".fs": "fs",
|
|
||||||
\".fy": "fy",
|
|
||||||
\".go": "go",
|
|
||||||
\".groovy": "groovy",
|
|
||||||
\".gs": "gs",
|
|
||||||
\".gsp": "gsp",
|
|
||||||
\".haml": "haml",
|
|
||||||
\".hs": "haskell",
|
|
||||||
\".html": "html",
|
|
||||||
\".hx": "hx",
|
|
||||||
\".ik": "ik",
|
|
||||||
\".ino": "ino",
|
|
||||||
\".io": "io",
|
|
||||||
\".j": "j",
|
|
||||||
\".java": "java",
|
|
||||||
\".js": "javascript",
|
|
||||||
\".json": "json",
|
|
||||||
\".jsp": "jsp",
|
|
||||||
\".kid": "kid",
|
|
||||||
\".lhs": "lhs",
|
|
||||||
\".lisp": "lisp",
|
|
||||||
\".ll": "ll",
|
|
||||||
\".lua": "lua",
|
|
||||||
\".ly": "ly",
|
|
||||||
\".m": "objc",
|
|
||||||
\".mak": "mak",
|
|
||||||
\".man": "man",
|
|
||||||
\".mao": "mao",
|
|
||||||
\".matlab": "matlab",
|
|
||||||
\".md": "markdown",
|
|
||||||
\".minid": "minid",
|
|
||||||
\".ml": "ml",
|
|
||||||
\".moo": "moo",
|
|
||||||
\".mu": "mu",
|
|
||||||
\".mustache": "mustache",
|
|
||||||
\".mxt": "mxt",
|
|
||||||
\".myt": "myt",
|
|
||||||
\".n": "n",
|
|
||||||
\".nim": "nim",
|
|
||||||
\".nu": "nu",
|
|
||||||
\".numpy": "numpy",
|
|
||||||
\".objdump": "objdump",
|
|
||||||
\".ooc": "ooc",
|
|
||||||
\".parrot": "parrot",
|
|
||||||
\".pas": "pas",
|
|
||||||
\".pasm": "pasm",
|
|
||||||
\".pd": "pd",
|
|
||||||
\".phtml": "phtml",
|
|
||||||
\".pir": "pir",
|
|
||||||
\".pl": "perl",
|
|
||||||
\".po": "po",
|
|
||||||
\".py": "python",
|
|
||||||
\".pytb": "pytb",
|
|
||||||
\".pyx": "pyx",
|
|
||||||
\".r": "r",
|
|
||||||
\".raw": "raw",
|
|
||||||
\".rb": "ruby",
|
|
||||||
\".rhtml": "rhtml",
|
|
||||||
\".rkt": "rkt",
|
|
||||||
\".rs": "rs",
|
|
||||||
\".rst": "rst",
|
|
||||||
\".s": "s",
|
|
||||||
\".sass": "sass",
|
|
||||||
\".sc": "sc",
|
|
||||||
\".scala": "scala",
|
|
||||||
\".scm": "scheme",
|
|
||||||
\".scpt": "scpt",
|
|
||||||
\".scss": "scss",
|
|
||||||
\".self": "self",
|
|
||||||
\".sh": "sh",
|
|
||||||
\".sml": "sml",
|
|
||||||
\".sql": "sql",
|
|
||||||
\".st": "smalltalk",
|
|
||||||
\".tcl": "tcl",
|
|
||||||
\".tcsh": "tcsh",
|
|
||||||
\".tex": "tex",
|
|
||||||
\".textile": "textile",
|
|
||||||
\".tpl": "smarty",
|
|
||||||
\".twig": "twig",
|
|
||||||
\".txt" : "text",
|
|
||||||
\".v": "verilog",
|
|
||||||
\".vala": "vala",
|
|
||||||
\".vb": "vbnet",
|
|
||||||
\".vhd": "vhdl",
|
|
||||||
\".vim": "vim",
|
|
||||||
\".weechatlog": "weechatlog",
|
|
||||||
\".xml": "xml",
|
|
||||||
\".xq": "xquery",
|
|
||||||
\".xs": "xs",
|
|
||||||
\".yml": "yaml",
|
|
||||||
\}
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,279 +0,0 @@
|
||||||
*Gist.vim* Vimscript for creating gists (http://gist.github.com)
|
|
||||||
|
|
||||||
Usage |gist-vim-usage|
|
|
||||||
Tips |gist-vim-tips|
|
|
||||||
License |gist-vim-license|
|
|
||||||
Install |gist-vim-install|
|
|
||||||
Requirements |gist-vim-requirements|
|
|
||||||
Setup |gist-vim-setup|
|
|
||||||
|
|
||||||
This is a vimscript for creating gists (http://gist.github.com)
|
|
||||||
|
|
||||||
For the latest version please see https://github.com/mattn/gist-vim.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
USAGE *:Gist* *gist-vim-usage*
|
|
||||||
|
|
||||||
- Post current buffer to gist, using default privacy option. >
|
|
||||||
|
|
||||||
:Gist
|
|
||||||
<
|
|
||||||
- Post selected text to gist, using defualt privacy option.
|
|
||||||
This applies to all permutations listed below (except multi). >
|
|
||||||
|
|
||||||
:'<,'>Gist
|
|
||||||
<
|
|
||||||
- Create a private gist. >
|
|
||||||
|
|
||||||
:Gist -p
|
|
||||||
<
|
|
||||||
- Create a public gist.
|
|
||||||
(Only relevant if you've set gists to be private by default.) >
|
|
||||||
|
|
||||||
:Gist -P
|
|
||||||
<
|
|
||||||
- Post whole text to gist as public.
|
|
||||||
This is only relevant if you've set gists to be private by default.
|
|
||||||
>
|
|
||||||
:Gist -P
|
|
||||||
<
|
|
||||||
- Create a gist anonymously. >
|
|
||||||
|
|
||||||
:Gist -a
|
|
||||||
<
|
|
||||||
- Create a gist with all open buffers. >
|
|
||||||
|
|
||||||
:Gist -m
|
|
||||||
<
|
|
||||||
- Edit the gist (you need to have opened the gist buffer first).
|
|
||||||
You can update the gist with the {:w} command within the gist buffer. >
|
|
||||||
|
|
||||||
:Gist -e
|
|
||||||
<
|
|
||||||
- Edit the gist with name "foo.js" (you need to have opened the gist buffer
|
|
||||||
first). >
|
|
||||||
|
|
||||||
:Gist -e foo.js
|
|
||||||
<
|
|
||||||
- Post/Edit with the description " (you need to have opened the gist buffer
|
|
||||||
first). >
|
|
||||||
|
|
||||||
:Gist -s something
|
|
||||||
:Gist -e -s something
|
|
||||||
<
|
|
||||||
- Delete the gist (you need to have opened the gist buffer first).
|
|
||||||
Password authentication is needed. >
|
|
||||||
|
|
||||||
:Gist -d
|
|
||||||
<
|
|
||||||
- Fork the gist (you need to have opened the gist buffer first).
|
|
||||||
Password authentication is needed. >
|
|
||||||
|
|
||||||
:Gist -f
|
|
||||||
<
|
|
||||||
- Star the gist (you need to have opened the gist buffer first).
|
|
||||||
Password authentication is needed.
|
|
||||||
>
|
|
||||||
:Gist +1
|
|
||||||
<
|
|
||||||
- Unstar the gist (you need to have opened the gist buffer first).
|
|
||||||
Password authentication is needed.
|
|
||||||
>
|
|
||||||
:Gist -1
|
|
||||||
<
|
|
||||||
- Get gist XXXXX. >
|
|
||||||
|
|
||||||
:Gist XXXXX
|
|
||||||
<
|
|
||||||
- Get gist XXXXX and add to clipboard. >
|
|
||||||
|
|
||||||
:Gist -c XXXXX
|
|
||||||
<
|
|
||||||
- List your public gists. >
|
|
||||||
|
|
||||||
:Gist -l
|
|
||||||
<
|
|
||||||
- List gists from user "mattn". >
|
|
||||||
|
|
||||||
:Gist -l mattn
|
|
||||||
<
|
|
||||||
- List everyone's gists. >
|
|
||||||
|
|
||||||
:Gist -la
|
|
||||||
<
|
|
||||||
- List gists from your starred gists.
|
|
||||||
>
|
|
||||||
:Gist -ls
|
|
||||||
<
|
|
||||||
==============================================================================
|
|
||||||
TIPS *gist-vim-tips*
|
|
||||||
|
|
||||||
If you set "g:gist_clip_command", gist.vim will copy the gist code with option
|
|
||||||
"-c".
|
|
||||||
|
|
||||||
- Mac: >
|
|
||||||
let g:gist_clip_command = 'pbcopy'
|
|
||||||
<
|
|
||||||
- Linux: >
|
|
||||||
let g:gist_clip_command = 'xclip -selection clipboard'
|
|
||||||
<
|
|
||||||
- Others (cygwin?): >
|
|
||||||
let g:gist_clip_command = 'putclip'
|
|
||||||
<
|
|
||||||
If you want to detect filetype from the filename: >
|
|
||||||
|
|
||||||
let g:gist_detect_filetype = 1
|
|
||||||
<
|
|
||||||
If you want to open the browser after the post: >
|
|
||||||
|
|
||||||
let g:gist_open_browser_after_post = 1
|
|
||||||
<
|
|
||||||
If you want to change the browser: >
|
|
||||||
|
|
||||||
let g:gist_browser_command = 'w3m %URL%'
|
|
||||||
<
|
|
||||||
or: >
|
|
||||||
|
|
||||||
let g:gist_browser_command = 'opera %URL% &'
|
|
||||||
<
|
|
||||||
On windows, this should work with your user settings.
|
|
||||||
|
|
||||||
If you want to show your private gists with ":Gist -l": >
|
|
||||||
|
|
||||||
let g:gist_show_privates = 1
|
|
||||||
<
|
|
||||||
If you want your gist to be private by default: >
|
|
||||||
|
|
||||||
let g:gist_post_private = 1
|
|
||||||
|
|
||||||
<
|
|
||||||
If you want to edit all files for gists containing more than one: >
|
|
||||||
|
|
||||||
let g:gist_get_multiplefile = 1
|
|
||||||
<
|
|
||||||
|
|
||||||
If you want to use on Github Enterprise: >
|
|
||||||
|
|
||||||
let g:github_api_url = 'http://your-github-enterprise-domain/api/v3'
|
|
||||||
<
|
|
||||||
|
|
||||||
If you want to update a gist, embed >
|
|
||||||
|
|
||||||
GistID: xxxxx
|
|
||||||
>
|
|
||||||
in your local file, then call >
|
|
||||||
|
|
||||||
:Gist
|
|
||||||
>
|
|
||||||
|
|
||||||
If you want to update a gist when only |:w!|: >
|
|
||||||
|
|
||||||
" :w and :w! update a gist.
|
|
||||||
let g:gist_update_on_write = 1
|
|
||||||
|
|
||||||
" Only :w! updates a gist.
|
|
||||||
let g:gist_update_on_write = 2
|
|
||||||
>
|
|
||||||
All other values are treated as 1.
|
|
||||||
This variable's value is 1 by default.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
LICENSE *gist-vim-license*
|
|
||||||
|
|
||||||
|
|
||||||
Copyright 2010 by Yasuhiro Matsumoto
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
||||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INSTALL *gist-vim-install*
|
|
||||||
|
|
||||||
Copy following files into your plugin directory.
|
|
||||||
|
|
||||||
rtp:
|
|
||||||
- autoload/gist.vim
|
|
||||||
- plugin/gist.vim
|
|
||||||
|
|
||||||
If you want to uninstall gist.vim, remember to also remove `~/.gist-vim`.
|
|
||||||
|
|
||||||
You need to install webapi-vim also:
|
|
||||||
|
|
||||||
http://www.vim.org/scripts/script.php?script_id=4019
|
|
||||||
|
|
||||||
If you want to use latest one:
|
|
||||||
|
|
||||||
https://github.com/mattn/webapi-vim
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
REQUIREMENTS *gist-vim-requirements*
|
|
||||||
|
|
||||||
- curl command (http://curl.haxx.se/)
|
|
||||||
- webapi-vim (https://github.com/mattn/webapi-vim)
|
|
||||||
- and, if you want to use your git profile, the git command-line client.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
SETUP *gist-vim-setup*
|
|
||||||
|
|
||||||
This plugin uses github API v3. Setting value is stored in `~/.gist.vim`.
|
|
||||||
gist-vim have two ways to access APIs.
|
|
||||||
|
|
||||||
First, you need to set your Github username in global git config:
|
|
||||||
>
|
|
||||||
$ git config --global github.user Username
|
|
||||||
<
|
|
||||||
Then, gist.vim will ask for your password to create an authorization when you
|
|
||||||
first use it. The password is not stored and only the OAuth access token will
|
|
||||||
be kept for later use. You can revoke the token at any time from the list of
|
|
||||||
"Authorized applications" on Github's "Account Settings" page.
|
|
||||||
(https://github.com/settings/applications)
|
|
||||||
|
|
||||||
If you happen to have your password already written in ~/.gitconfig like
|
|
||||||
below:
|
|
||||||
>
|
|
||||||
[github]
|
|
||||||
password = xxxxx
|
|
||||||
<
|
|
||||||
Then, add following into your ~/.vimrc
|
|
||||||
>
|
|
||||||
let g:gist_use_password_in_gitconfig = 1
|
|
||||||
<
|
|
||||||
This is not secure at all, so strongly discouraged.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
THANKS *gist-vim-thanks*
|
|
||||||
|
|
||||||
AD7six
|
|
||||||
Bruno Bigras
|
|
||||||
c9s
|
|
||||||
Daniel Bretoi
|
|
||||||
Jeremy Michael Cantrell
|
|
||||||
Kien N
|
|
||||||
kongo2002
|
|
||||||
MATSUU Takuto
|
|
||||||
Matthew Weier O'Phinney
|
|
||||||
ornicar
|
|
||||||
Roland Schilter
|
|
||||||
steve
|
|
||||||
tyru
|
|
||||||
Will Gray
|
|
||||||
netj
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:ft=help:norl:
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
:Gist gist-vim.txt /*:Gist*
|
|
||||||
Gist.vim gist-vim.txt /*Gist.vim*
|
|
||||||
gist-vim-install gist-vim.txt /*gist-vim-install*
|
|
||||||
gist-vim-license gist-vim.txt /*gist-vim-license*
|
|
||||||
gist-vim-requirements gist-vim.txt /*gist-vim-requirements*
|
|
||||||
gist-vim-setup gist-vim.txt /*gist-vim-setup*
|
|
||||||
gist-vim-thanks gist-vim.txt /*gist-vim-thanks*
|
|
||||||
gist-vim-tips gist-vim.txt /*gist-vim-tips*
|
|
||||||
gist-vim-usage gist-vim.txt /*gist-vim-usage*
|
|
||||||
|
|
@ -1,297 +0,0 @@
|
||||||
script_name: Gist.vim
|
|
||||||
script_id: '2423'
|
|
||||||
script_type: utility
|
|
||||||
script_package: gist-vim.zip
|
|
||||||
script_version: '7.1'
|
|
||||||
required_vim_version: '7.0'
|
|
||||||
summary: vimscript for gist
|
|
||||||
|
|
||||||
detailed_description: |
|
|
||||||
This is vimscript for gist (http://gist.github.com)
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
|
|
||||||
:Gist
|
|
||||||
post whole text to gist.
|
|
||||||
|
|
||||||
:'<,'>Gist
|
|
||||||
post selected text to gist.
|
|
||||||
|
|
||||||
:Gist -p
|
|
||||||
post whole text to gist with private.
|
|
||||||
if you got empty gist list, try :Gist --abandon
|
|
||||||
|
|
||||||
:Gist -a
|
|
||||||
post whole text to gist with anonymous.
|
|
||||||
|
|
||||||
:Gist -m
|
|
||||||
post multi buffer to gist.
|
|
||||||
|
|
||||||
:Gist -e
|
|
||||||
edit the gist. (shoud be work on gist buffer)
|
|
||||||
you can update the gist with :w command on gist buffer.
|
|
||||||
|
|
||||||
:Gist -e foo.js
|
|
||||||
edit the gist with name 'foo.js'. (shoud be work on gist buffer)
|
|
||||||
|
|
||||||
:Gist -d
|
|
||||||
delete the gist. (should be work on gist buffer)
|
|
||||||
authentication required.
|
|
||||||
|
|
||||||
:Gist -f
|
|
||||||
fork the gist. (should be work on gist buffer)
|
|
||||||
authentication required.
|
|
||||||
|
|
||||||
:Gist XXXXX
|
|
||||||
get gist XXXXX.
|
|
||||||
|
|
||||||
:Gist -c XXXXX.
|
|
||||||
get gist XXXXX and put to clipboard.
|
|
||||||
|
|
||||||
:Gist -l
|
|
||||||
list gists from mine.
|
|
||||||
|
|
||||||
:Gist -la
|
|
||||||
list gists from all.
|
|
||||||
|
|
||||||
Tips:
|
|
||||||
if set g:gist_clip_command, gist.vim will copy the gist code
|
|
||||||
with option '-c'.
|
|
||||||
|
|
||||||
# mac
|
|
||||||
let g:gist_clip_command = 'pbcopy'
|
|
||||||
|
|
||||||
# linux
|
|
||||||
let g:gist_clip_command = 'xclip -selection clipboard'
|
|
||||||
|
|
||||||
# others(cygwin?)
|
|
||||||
let g:gist_clip_command = 'putclip'
|
|
||||||
|
|
||||||
if you want to detect filetype from filename...
|
|
||||||
|
|
||||||
let g:gist_detect_filetype = 1
|
|
||||||
|
|
||||||
if you want to open browser after the post...
|
|
||||||
|
|
||||||
let g:gist_open_browser_after_post = 1
|
|
||||||
|
|
||||||
if you want to change the browser...
|
|
||||||
|
|
||||||
let g:gist_browser_command = 'w3m %URL%'
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
let g:gist_browser_command = 'opera %URL% &'
|
|
||||||
|
|
||||||
on windows, should work with original setting.
|
|
||||||
|
|
||||||
Require:
|
|
||||||
curl command (http://curl.haxx.se/)
|
|
||||||
and if you want to use profile of git, it require git command.
|
|
||||||
|
|
||||||
install_details: |
|
|
||||||
copy it to your plugin directory.
|
|
||||||
|
|
||||||
gist.vim leave cookie-jar file into runtimepath.
|
|
||||||
|
|
||||||
rtp:
|
|
||||||
plugin/gist.vim
|
|
||||||
cookies/github
|
|
||||||
|
|
||||||
See also: https://github.com/mattn/gist-vim/blob/master/README.mkd
|
|
||||||
|
|
||||||
versions:
|
|
||||||
- '7.1': |
|
|
||||||
This is an upgrade for Gist.vim: updated installation notes.
|
|
||||||
|
|
||||||
- '7.0': |
|
|
||||||
This is an upgrade for Gist.vim: fixed few bugs.
|
|
||||||
|
|
||||||
- '6.9': |
|
|
||||||
This is an upgrade for Gist.vim: fixed few bugs.
|
|
||||||
|
|
||||||
- '6.8': |
|
|
||||||
This is an upgrade for Gist.vim: changed authentication. removed password authentication. if you want to keep using password authentication, let gist_use_password_in_gitconfig to 1.
|
|
||||||
|
|
||||||
- '6.7': |
|
|
||||||
This is an upgrade for Gist.vim: fix behavior of g:gist_browser_command = ':OpenBrowser %URL%'.
|
|
||||||
|
|
||||||
- '6.6': |
|
|
||||||
This is an upgrade for Gist.vim: fixed detecting filetype.
|
|
||||||
|
|
||||||
- '6.5': |
|
|
||||||
This is an upgrade for Gist.vim: use webapi namespace. NOTE: please upgrade webapi-vim also.
|
|
||||||
|
|
||||||
- '6.4': |
|
|
||||||
This is an upgrade for Gist.vim: fixed updating with description.
|
|
||||||
|
|
||||||
- '6.3': |
|
|
||||||
This is an upgrade for Gist.vim: fixed typos.
|
|
||||||
|
|
||||||
- '6.2': |
|
|
||||||
This is an upgrade for Gist.vim: fixed some bugs.
|
|
||||||
|
|
||||||
- '6.1': |
|
|
||||||
This is an upgrade for Gist.vim: fixed opening browser.
|
|
||||||
|
|
||||||
- '6.0': |
|
|
||||||
This is an upgrade for Gist.vim: changed to use github APIs. Note to remove cookies directory if you used.
|
|
||||||
|
|
||||||
- '5.9': |
|
|
||||||
This is an upgrade for Gist.vim: add support anonymous post. fixed many bugs.
|
|
||||||
|
|
||||||
- '5.8': |
|
|
||||||
This is an upgrade for Gist.vim: add support for description. you can post description using -s option.
|
|
||||||
|
|
||||||
- '5.7': |
|
|
||||||
This is an upgrade for Gist.vim: post with filetype more cleverly.
|
|
||||||
|
|
||||||
- '5.6': |
|
|
||||||
This is an upgrade for Gist.vim: fix '--abandon'.
|
|
||||||
|
|
||||||
- '5.5': |
|
|
||||||
This is an upgrade for Gist.vim: fix: forgot to upload autoload/gist.vim.
|
|
||||||
|
|
||||||
- '5.4': |
|
|
||||||
This is an upgrade for Gist.vim: fix: does not work correctly with blockwize selection.
|
|
||||||
|
|
||||||
- '5.3': |
|
|
||||||
This is an upgrade for Gist.vim: upd: support autoload.
|
|
||||||
|
|
||||||
- '5.2': |
|
|
||||||
This is an upgrade for Gist.vim: add: support block-wise selection.
|
|
||||||
|
|
||||||
- '5.1': |
|
|
||||||
This is an upgrade for Gist.vim: fix: can't update privates.
|
|
||||||
|
|
||||||
- '5.0': |
|
|
||||||
This is an upgrade for Gist.vim: follow update of gist.github.com
|
|
||||||
|
|
||||||
- '4.9': |
|
|
||||||
fix: don't add new line after "Done: xxx".
|
|
||||||
fix: show WHY FAILED' when failed to post.
|
|
||||||
add: support for :OpenBrowser.
|
|
||||||
add: new option 'gist_curl_options'.
|
|
||||||
|
|
||||||
- '4.8': |
|
|
||||||
This is an upgrade for Gist.vim: fix: can't open private gist with ":Gist XXXXX".
|
|
||||||
|
|
||||||
- '4.7': |
|
|
||||||
This is an upgrade for Gist.vim: fix: filetype detection.
|
|
||||||
|
|
||||||
- '4.6': |
|
|
||||||
This is an upgrade for Gist.vim: fix: strange cookies folder.
|
|
||||||
|
|
||||||
- '4.5': |
|
|
||||||
This is an upgrade for Gist.vim: fix: use gist_clip_command for copying URL to clipboard. this fix strange behavior on Mac OSX.
|
|
||||||
|
|
||||||
- '4.4': |
|
|
||||||
This is an upgrade for Gist.vim: fix: gist is now only using https.
|
|
||||||
|
|
||||||
- '4.3': |
|
|
||||||
This is an upgrade for Gist.vim: add new option '-f' for fork.
|
|
||||||
|
|
||||||
- '4.2': |
|
|
||||||
This is an upgrade for Gist.vim: fixed code for login.
|
|
||||||
|
|
||||||
- '4.1': |
|
|
||||||
This is an upgrade for Gist.vim: fixed code cleanup.
|
|
||||||
|
|
||||||
- '4.0': |
|
|
||||||
This is an upgrade for Gist.vim: fixed deleting gist, listing privates.
|
|
||||||
|
|
||||||
- '3.9': |
|
|
||||||
This is an upgrade for Gist.vim: fixed :w handler in gist buffer.
|
|
||||||
|
|
||||||
- '3.8': |
|
|
||||||
This is an upgrade for Gist.vim: 'more...' on gist list.
|
|
||||||
|
|
||||||
- '3.7': |
|
|
||||||
This is an upgrade for Gist.vim: fix problem that break "gist list" window at twice.
|
|
||||||
|
|
||||||
- '3.6': |
|
|
||||||
This is an upgrade for Gist.vim: fix filetype detection for 'vimscript'.
|
|
||||||
|
|
||||||
- '3.5': |
|
|
||||||
This is an upgrade for Gist.vim: fix filetype detection.
|
|
||||||
|
|
||||||
- '3.4': |
|
|
||||||
This is an upgrade for Gist.vim: use '+' register on unix only if built with 'xterm_clipboard'. and some bug fixes.
|
|
||||||
|
|
||||||
- '3.3': |
|
|
||||||
This is an upgrade for Gist.vim: fix problem that append empty line when getting gist.
|
|
||||||
|
|
||||||
- '3.2': |
|
|
||||||
This is an upgrade for Gist.vim: added Gist header to recognize the gist. added script type header for Vimana.
|
|
||||||
|
|
||||||
- '3.1': |
|
|
||||||
This is an upgrade for Gist.vim: fix checking redirect url.
|
|
||||||
|
|
||||||
- '3.0': |
|
|
||||||
This is an upgrade for Gist.vim: fix for official changes(private button name was changed).
|
|
||||||
|
|
||||||
- '2.9': |
|
|
||||||
This is an upgrade for Gist.vim: fix for official changes(private button name was changed).
|
|
||||||
|
|
||||||
- '2.8': |
|
|
||||||
This is an upgrade for Gist.vim: be able to post multi buffer. currently updating or showing not supported. and ':Gist -d' delete the gist.
|
|
||||||
|
|
||||||
- '2.7': |
|
|
||||||
This is an upgrade for Gist.vim: be able to write the gist to local file with ':w foo.txt'.
|
|
||||||
|
|
||||||
- '2.6': |
|
|
||||||
This is an upgrade for Gist.vim: fixed problem that does not work 'Gist XXXX'.
|
|
||||||
|
|
||||||
- '2.5': |
|
|
||||||
This is an upgrade for Gist.vim: use existing buffer when open the list or gist.
|
|
||||||
|
|
||||||
- '2.4': |
|
|
||||||
This is an upgrade for Gist.vim: show error message when no any github settings.
|
|
||||||
|
|
||||||
- '2.3': |
|
|
||||||
This is an upgrade for Gist.vim: added :w BufWriteCmd for GistUpdate.
|
|
||||||
|
|
||||||
- '2.2': |
|
|
||||||
This is an upgrade for Gist.vim: fixed a bug for anonymous post. and new option '-a' for anonymous post.
|
|
||||||
|
|
||||||
- '2.1': |
|
|
||||||
This is an upgrade for Gist.vim: support changing gist filename.
|
|
||||||
|
|
||||||
- '2.0': |
|
|
||||||
This is an upgrade for Gist.vim: bugfix for listing gists in specified user.
|
|
||||||
|
|
||||||
- '1.9': |
|
|
||||||
This is an upgrade for Gist.vim: added support editing the gist. and bits bug fix.
|
|
||||||
|
|
||||||
- '1.8': |
|
|
||||||
This is an upgrade for Gist.vim: added new option g:gist_open_browser_after_post/g:gist_browser_command to open posted gist.
|
|
||||||
|
|
||||||
- '1.7': |
|
|
||||||
This is an upgrade for Gist.vim: now changed argument for putting clipboard as ':Gist -c XXXXX'.
|
|
||||||
|
|
||||||
- '1.6': |
|
|
||||||
This is an upgrade for Gist.vim: add gist's author in gist list.
|
|
||||||
|
|
||||||
- '1.5': |
|
|
||||||
This is an upgrade for Gist.vim: oops. bugfix for auto-detection.
|
|
||||||
|
|
||||||
- '1.4': |
|
|
||||||
This is an upgrade for Gist.vim: bugfix for auto-detection.
|
|
||||||
|
|
||||||
- '1.3': |
|
|
||||||
This is an upgrade for Gist.vim: more auto-detection for filetype.
|
|
||||||
|
|
||||||
- '1.2': |
|
|
||||||
This is an upgrade for Gist.vim: added new option for detect filetype from filename.
|
|
||||||
|
|
||||||
- '1.1': |
|
|
||||||
This is an upgrade for Gist.vim: calling StdinReadPost.
|
|
||||||
|
|
||||||
- '1.0': |
|
|
||||||
This is an upgrade for Gist.vim: treat literal "-" as part of username.
|
|
||||||
|
|
||||||
- '0.9': |
|
|
||||||
This is an upgrade for Gist.vim: added new option 'g:gist_clip_command' that copy the gist code.
|
|
||||||
|
|
||||||
# __END__
|
|
||||||
# vim: filetype=yaml
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
"=============================================================================
|
|
||||||
" File: gist.vim
|
|
||||||
" Author: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" WebPage: http://github.com/mattn/gist-vim
|
|
||||||
" License: BSD
|
|
||||||
" GetLatestVimScripts: 2423 1 :AutoInstall: gist.vim
|
|
||||||
" script type: plugin
|
|
||||||
|
|
||||||
if &cp || (exists('g:loaded_gist_vim') && g:loaded_gist_vim)
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_gist_vim = 1
|
|
||||||
|
|
||||||
command! -nargs=? -range=% Gist :call gist#Gist(<count>, <line1>, <line2>, <f-args>)
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 0761708c890becd3e027551068e0ae272da003e0
|
|
||||||
3
vim/bundle/nerdtree/.gitignore
vendored
3
vim/bundle/nerdtree/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
*~
|
|
||||||
*.swp
|
|
||||||
tags
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
The NERD Tree
|
|
||||||
=============
|
|
||||||
|
|
||||||
Intro
|
|
||||||
-----
|
|
||||||
|
|
||||||
The NERD tree allows you to explore your filesystem and to open files and
|
|
||||||
directories. It presents the filesystem to you in the form of a tree which you
|
|
||||||
manipulate with the keyboard and/or mouse. It also allows you to perform
|
|
||||||
simple filesystem operations.
|
|
||||||
|
|
||||||
The following features and functionality are provided by the NERD tree:
|
|
||||||
|
|
||||||
* Files and directories are displayed in a hierarchical tree structure
|
|
||||||
* Different highlighting is provided for the following types of nodes:
|
|
||||||
* files
|
|
||||||
* directories
|
|
||||||
* sym-links
|
|
||||||
* windows .lnk files
|
|
||||||
* read-only files
|
|
||||||
* executable files
|
|
||||||
* Many (customisable) mappings are provided to manipulate the tree:
|
|
||||||
* Mappings to open/close/explore directory nodes
|
|
||||||
* Mappings to open files in new/existing windows/tabs
|
|
||||||
* Mappings to change the current root of the tree
|
|
||||||
* Mappings to navigate around the tree
|
|
||||||
* ...
|
|
||||||
* Directories and files can be bookmarked.
|
|
||||||
* Most NERD tree navigation can also be done with the mouse
|
|
||||||
* Filtering of tree content (can be toggled at runtime)
|
|
||||||
* custom file filters to prevent e.g. vim backup files being displayed
|
|
||||||
* optional displaying of hidden files (. files)
|
|
||||||
* files can be "turned off" so that only directories are displayed
|
|
||||||
* The position and size of the NERD tree window can be customised
|
|
||||||
* The order in which the nodes in the tree are listed can be customised.
|
|
||||||
* A model of your filesystem is created/maintained as you explore it. This
|
|
||||||
has several advantages:
|
|
||||||
* All filesystem information is cached and is only re-read on demand
|
|
||||||
* If you revisit a part of the tree that you left earlier in your
|
|
||||||
session, the directory nodes will be opened/closed as you left them
|
|
||||||
* The script remembers the cursor position and window position in the NERD
|
|
||||||
tree so you can toggle it off (or just close the tree window) and then
|
|
||||||
reopen it (with NERDTreeToggle) the NERD tree window will appear exactly
|
|
||||||
as you left it
|
|
||||||
* You can have a separate NERD tree for each tab, share trees across tabs,
|
|
||||||
or a mix of both.
|
|
||||||
* By default the script overrides the default file browser (netrw), so if
|
|
||||||
you :edit a directory a (slightly modified) NERD tree will appear in the
|
|
||||||
current window
|
|
||||||
* A programmable menu system is provided (simulates right clicking on a node)
|
|
||||||
* one default menu plugin is provided to perform basic filesystem
|
|
||||||
operations (create/delete/move/copy files/directories)
|
|
||||||
* There's an API for adding your own keymappings
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
[pathogen.vim](https://github.com/tpope/vim-pathogen) is the recommended way to install nerdtree.
|
|
||||||
|
|
||||||
cd ~/.vim/bundle
|
|
||||||
git clone https://github.com/scrooloose/nerdtree.git
|
|
||||||
|
|
||||||
Then reload vim, run `:helptags`, and check out `:help NERD_tree.txt`.
|
|
||||||
|
|
||||||
|
|
||||||
Faq
|
|
||||||
---
|
|
||||||
|
|
||||||
__Q. Can I have the nerdtree on every tab automatically?__
|
|
||||||
|
|
||||||
A. Nope. If this is something you want then chances are you aren't using tabs
|
|
||||||
and buffers as they were intended to be used. Read this
|
|
||||||
http://stackoverflow.com/questions/102384/using-vims-tabs-like-buffers
|
|
||||||
|
|
||||||
If you are interested in this behaviour then consider [vim-nerdtree-tabs](https://github.com/jistr/vim-nerdtree-tabs)
|
|
||||||
|
|
||||||
__Q. How can I open a NERDTree automatically when vim starts up?__
|
|
||||||
|
|
||||||
A. Stick this in your vimrc: `autocmd vimenter * NERDTree`
|
|
||||||
|
|
||||||
__Q. How can I open a NERDTree automatically when vim starts up if no files were specified?__
|
|
||||||
|
|
||||||
A. Stick this in your vimrc `autocmd vimenter * if !argc() | NERDTree | endif`
|
|
||||||
|
|
||||||
__Q. How can I map a specific key or shortcut to open NERDTree?__
|
|
||||||
|
|
||||||
A. Stick this in your vimrc to open NERDTree with `Ctrl+n` (you can set whatever key you want): `map <C-n> :NERDTreeToggle<CR>`
|
|
||||||
|
|
||||||
__Q. How can I close vim if the only window left open is a NERDTree?__
|
|
||||||
|
|
||||||
A. Stick this in your vimrc:
|
|
||||||
|
|
||||||
`autocmd bufenter * if (winnr("$") == 1 && exists("b:NERDTreeType") && b:NERDTreeType == "primary") | q | endif`
|
|
||||||
|
|
||||||
|
|
||||||
Changelog
|
|
||||||
---------
|
|
||||||
|
|
||||||
4.2.0 (2011-12-28)
|
|
||||||
|
|
||||||
* Add NERDTreeDirArrows option to make the UI use pretty arrow chars instead of the old +~| chars to define the tree structure (sickill)
|
|
||||||
* shift the syntax highlighting out into its own syntax file (gnap) * add some mac specific options to the filesystem menu - for macvim only (andersonfreitas)
|
|
||||||
* Add NERDTreeMinimalUI option to remove some non functional parts of the nerdtree ui (camthompson)
|
|
||||||
* tweak the behaviour of :NERDTreeFind - see :help :NERDTreeFind for the new behaviour (benjamingeiger)
|
|
||||||
* if no name is given to :Bookmark, make it default to the name of the target file/dir (minyoung)
|
|
||||||
* use 'file' completion when doing copying, create, and move operations (EvanDotPro)
|
|
||||||
* lots of misc bug fixes (paddyoloughlin, sdewald, camthompson, Vitaly Bogdanov, AndrewRadev, mathias, scottstvnsn, kml, wycats, me RAWR!)
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,315 +0,0 @@
|
||||||
"CLASS: Bookmark
|
|
||||||
"============================================================
|
|
||||||
let s:Bookmark = {}
|
|
||||||
let g:NERDTreeBookmark = s:Bookmark
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.activate() {{{1
|
|
||||||
function! s:Bookmark.activate(...)
|
|
||||||
call self.open(a:0 ? a:1 : {})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.AddBookmark(name, path) {{{1
|
|
||||||
" Class method to add a new bookmark to the list, if a previous bookmark exists
|
|
||||||
" with the same name, just update the path for that bookmark
|
|
||||||
function! s:Bookmark.AddBookmark(name, path)
|
|
||||||
for i in s:Bookmark.Bookmarks()
|
|
||||||
if i.name ==# a:name
|
|
||||||
let i.path = a:path
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
call add(s:Bookmark.Bookmarks(), s:Bookmark.New(a:name, a:path))
|
|
||||||
call s:Bookmark.Sort()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.Bookmarks() {{{1
|
|
||||||
" Class method to get all bookmarks. Lazily initializes the bookmarks global
|
|
||||||
" variable
|
|
||||||
function! s:Bookmark.Bookmarks()
|
|
||||||
if !exists("g:NERDTreeBookmarks")
|
|
||||||
let g:NERDTreeBookmarks = []
|
|
||||||
endif
|
|
||||||
return g:NERDTreeBookmarks
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.BookmarkExistsFor(name) {{{1
|
|
||||||
" class method that returns 1 if a bookmark with the given name is found, 0
|
|
||||||
" otherwise
|
|
||||||
function! s:Bookmark.BookmarkExistsFor(name)
|
|
||||||
try
|
|
||||||
call s:Bookmark.BookmarkFor(a:name)
|
|
||||||
return 1
|
|
||||||
catch /^NERDTree.BookmarkNotFoundError/
|
|
||||||
return 0
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.BookmarkFor(name) {{{1
|
|
||||||
" Class method to get the bookmark that has the given name. {} is return if no
|
|
||||||
" bookmark is found
|
|
||||||
function! s:Bookmark.BookmarkFor(name)
|
|
||||||
for i in s:Bookmark.Bookmarks()
|
|
||||||
if i.name ==# a:name
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
throw "NERDTree.BookmarkNotFoundError: no bookmark found for name: \"". a:name .'"'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.BookmarkNames() {{{1
|
|
||||||
" Class method to return an array of all bookmark names
|
|
||||||
function! s:Bookmark.BookmarkNames()
|
|
||||||
let names = []
|
|
||||||
for i in s:Bookmark.Bookmarks()
|
|
||||||
call add(names, i.name)
|
|
||||||
endfor
|
|
||||||
return names
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.CacheBookmarks(silent) {{{1
|
|
||||||
" Class method to read all bookmarks from the bookmarks file initialize
|
|
||||||
" bookmark objects for each one.
|
|
||||||
"
|
|
||||||
" Args:
|
|
||||||
" silent - dont echo an error msg if invalid bookmarks are found
|
|
||||||
function! s:Bookmark.CacheBookmarks(silent)
|
|
||||||
if filereadable(g:NERDTreeBookmarksFile)
|
|
||||||
let g:NERDTreeBookmarks = []
|
|
||||||
let g:NERDTreeInvalidBookmarks = []
|
|
||||||
let bookmarkStrings = readfile(g:NERDTreeBookmarksFile)
|
|
||||||
let invalidBookmarksFound = 0
|
|
||||||
for i in bookmarkStrings
|
|
||||||
|
|
||||||
"ignore blank lines
|
|
||||||
if i != ''
|
|
||||||
|
|
||||||
let name = substitute(i, '^\(.\{-}\) .*$', '\1', '')
|
|
||||||
let path = substitute(i, '^.\{-} \(.*\)$', '\1', '')
|
|
||||||
|
|
||||||
try
|
|
||||||
let bookmark = s:Bookmark.New(name, g:NERDTreePath.New(path))
|
|
||||||
call add(g:NERDTreeBookmarks, bookmark)
|
|
||||||
catch /^NERDTree.InvalidArgumentsError/
|
|
||||||
call add(g:NERDTreeInvalidBookmarks, i)
|
|
||||||
let invalidBookmarksFound += 1
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
if invalidBookmarksFound
|
|
||||||
call s:Bookmark.Write()
|
|
||||||
if !a:silent
|
|
||||||
call nerdtree#echo(invalidBookmarksFound . " invalid bookmarks were read. See :help NERDTreeInvalidBookmarks for info.")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call s:Bookmark.Sort()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.compareTo(otherbookmark) {{{1
|
|
||||||
" Compare these two bookmarks for sorting purposes
|
|
||||||
function! s:Bookmark.compareTo(otherbookmark)
|
|
||||||
return a:otherbookmark.name < self.name
|
|
||||||
endfunction
|
|
||||||
" FUNCTION: Bookmark.ClearAll() {{{1
|
|
||||||
" Class method to delete all bookmarks.
|
|
||||||
function! s:Bookmark.ClearAll()
|
|
||||||
for i in s:Bookmark.Bookmarks()
|
|
||||||
call i.delete()
|
|
||||||
endfor
|
|
||||||
call s:Bookmark.Write()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.delete() {{{1
|
|
||||||
" Delete this bookmark. If the node for this bookmark is under the current
|
|
||||||
" root, then recache bookmarks for its Path object
|
|
||||||
function! s:Bookmark.delete()
|
|
||||||
let node = {}
|
|
||||||
try
|
|
||||||
let node = self.getNode(1)
|
|
||||||
catch /^NERDTree.BookmarkedNodeNotFoundError/
|
|
||||||
endtry
|
|
||||||
call remove(s:Bookmark.Bookmarks(), index(s:Bookmark.Bookmarks(), self))
|
|
||||||
if !empty(node)
|
|
||||||
call node.path.cacheDisplayString()
|
|
||||||
endif
|
|
||||||
call s:Bookmark.Write()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.getNode(searchFromAbsoluteRoot) {{{1
|
|
||||||
" Gets the treenode for this bookmark
|
|
||||||
"
|
|
||||||
" Args:
|
|
||||||
" searchFromAbsoluteRoot: specifies whether we should search from the current
|
|
||||||
" tree root, or the highest cached node
|
|
||||||
function! s:Bookmark.getNode(searchFromAbsoluteRoot)
|
|
||||||
let searchRoot = a:searchFromAbsoluteRoot ? g:NERDTreeDirNode.AbsoluteTreeRoot() : b:NERDTreeRoot
|
|
||||||
let targetNode = searchRoot.findNode(self.path)
|
|
||||||
if empty(targetNode)
|
|
||||||
throw "NERDTree.BookmarkedNodeNotFoundError: no node was found for bookmark: " . self.name
|
|
||||||
endif
|
|
||||||
return targetNode
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.GetNodeForName(name, searchFromAbsoluteRoot) {{{1
|
|
||||||
" Class method that finds the bookmark with the given name and returns the
|
|
||||||
" treenode for it.
|
|
||||||
function! s:Bookmark.GetNodeForName(name, searchFromAbsoluteRoot)
|
|
||||||
let bookmark = s:Bookmark.BookmarkFor(a:name)
|
|
||||||
return bookmark.getNode(a:searchFromAbsoluteRoot)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.GetSelected() {{{1
|
|
||||||
" returns the Bookmark the cursor is over, or {}
|
|
||||||
function! s:Bookmark.GetSelected()
|
|
||||||
let line = getline(".")
|
|
||||||
let name = substitute(line, '^>\(.\{-}\) .\+$', '\1', '')
|
|
||||||
if name != line
|
|
||||||
try
|
|
||||||
return s:Bookmark.BookmarkFor(name)
|
|
||||||
catch /^NERDTree.BookmarkNotFoundError/
|
|
||||||
return {}
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.InvalidBookmarks() {{{1
|
|
||||||
" Class method to get all invalid bookmark strings read from the bookmarks
|
|
||||||
" file
|
|
||||||
function! s:Bookmark.InvalidBookmarks()
|
|
||||||
if !exists("g:NERDTreeInvalidBookmarks")
|
|
||||||
let g:NERDTreeInvalidBookmarks = []
|
|
||||||
endif
|
|
||||||
return g:NERDTreeInvalidBookmarks
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.mustExist() {{{1
|
|
||||||
function! s:Bookmark.mustExist()
|
|
||||||
if !self.path.exists()
|
|
||||||
call s:Bookmark.CacheBookmarks(1)
|
|
||||||
throw "NERDTree.BookmarkPointsToInvalidLocationError: the bookmark \"".
|
|
||||||
\ self.name ."\" points to a non existing location: \"". self.path.str()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.New(name, path) {{{1
|
|
||||||
" Create a new bookmark object with the given name and path object
|
|
||||||
function! s:Bookmark.New(name, path)
|
|
||||||
if a:name =~# ' '
|
|
||||||
throw "NERDTree.IllegalBookmarkNameError: illegal name:" . a:name
|
|
||||||
endif
|
|
||||||
|
|
||||||
let newBookmark = copy(self)
|
|
||||||
let newBookmark.name = a:name
|
|
||||||
let newBookmark.path = a:path
|
|
||||||
return newBookmark
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.open([options]) {{{1
|
|
||||||
"Args:
|
|
||||||
"A dictionary containing the following keys (all optional):
|
|
||||||
" 'where': Specifies whether the node should be opened in new split/tab or in
|
|
||||||
" the previous window. Can be either 'v' (vertical split), 'h'
|
|
||||||
" (horizontal split), 't' (new tab) or 'p' (previous window).
|
|
||||||
" 'reuse': if a window is displaying the file then jump the cursor there
|
|
||||||
" 'keepopen': dont close the tree window
|
|
||||||
" 'stay': open the file, but keep the cursor in the tree win
|
|
||||||
"
|
|
||||||
function! s:Bookmark.open(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
|
|
||||||
if self.path.isDirectory && !has_key(opts, 'where')
|
|
||||||
call self.toRoot()
|
|
||||||
else
|
|
||||||
let opener = g:NERDTreeOpener.New(self.path, opts)
|
|
||||||
call opener.open(self)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.openInNewTab(options) {{{1
|
|
||||||
" Create a new bookmark object with the given name and path object
|
|
||||||
function! s:Bookmark.openInNewTab(options)
|
|
||||||
call nerdtree#deprecated('Bookmark.openInNewTab', 'is deprecated, use open() instead')
|
|
||||||
call self.open(a:options)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.setPath(path) {{{1
|
|
||||||
" makes this bookmark point to the given path
|
|
||||||
function! s:Bookmark.setPath(path)
|
|
||||||
let self.path = a:path
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.Sort() {{{1
|
|
||||||
" Class method that sorts all bookmarks
|
|
||||||
function! s:Bookmark.Sort()
|
|
||||||
let CompareFunc = function("nerdtree#compareBookmarks")
|
|
||||||
call sort(s:Bookmark.Bookmarks(), CompareFunc)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.str() {{{1
|
|
||||||
" Get the string that should be rendered in the view for this bookmark
|
|
||||||
function! s:Bookmark.str()
|
|
||||||
let pathStrMaxLen = winwidth(nerdtree#getTreeWinNum()) - 4 - len(self.name)
|
|
||||||
if &nu
|
|
||||||
let pathStrMaxLen = pathStrMaxLen - &numberwidth
|
|
||||||
endif
|
|
||||||
|
|
||||||
let pathStr = self.path.str({'format': 'UI'})
|
|
||||||
if len(pathStr) > pathStrMaxLen
|
|
||||||
let pathStr = '<' . strpart(pathStr, len(pathStr) - pathStrMaxLen)
|
|
||||||
endif
|
|
||||||
return '>' . self.name . ' ' . pathStr
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.toRoot() {{{1
|
|
||||||
" Make the node for this bookmark the new tree root
|
|
||||||
function! s:Bookmark.toRoot()
|
|
||||||
if self.validate()
|
|
||||||
try
|
|
||||||
let targetNode = self.getNode(1)
|
|
||||||
catch /^NERDTree.BookmarkedNodeNotFoundError/
|
|
||||||
let targetNode = g:NERDTreeFileNode.New(s:Bookmark.BookmarkFor(self.name).path)
|
|
||||||
endtry
|
|
||||||
call targetNode.makeRoot()
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call targetNode.putCursorHere(0, 0)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.ToRoot(name) {{{1
|
|
||||||
" Make the node for this bookmark the new tree root
|
|
||||||
function! s:Bookmark.ToRoot(name)
|
|
||||||
let bookmark = s:Bookmark.BookmarkFor(a:name)
|
|
||||||
call bookmark.toRoot()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.validate() {{{1
|
|
||||||
function! s:Bookmark.validate()
|
|
||||||
if self.path.exists()
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
call s:Bookmark.CacheBookmarks(1)
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call nerdtree#echo(self.name . "now points to an invalid location. See :help NERDTreeInvalidBookmarks for info.")
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Bookmark.Write() {{{1
|
|
||||||
" Class method to write all bookmarks to the bookmarks file
|
|
||||||
function! s:Bookmark.Write()
|
|
||||||
let bookmarkStrings = []
|
|
||||||
for i in s:Bookmark.Bookmarks()
|
|
||||||
call add(bookmarkStrings, i.name . ' ' . i.path.str())
|
|
||||||
endfor
|
|
||||||
|
|
||||||
"add a blank line before the invalid ones
|
|
||||||
call add(bookmarkStrings, "")
|
|
||||||
|
|
||||||
for j in s:Bookmark.InvalidBookmarks()
|
|
||||||
call add(bookmarkStrings, j)
|
|
||||||
endfor
|
|
||||||
call writefile(bookmarkStrings, g:NERDTreeBookmarksFile)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,322 +0,0 @@
|
||||||
"CLASS: Creator
|
|
||||||
"Creates primary/secondary/mirror nerdtree windows. Sets up all the window and
|
|
||||||
"buffer options and key mappings etc.
|
|
||||||
"============================================================
|
|
||||||
let s:Creator = {}
|
|
||||||
let g:NERDTreeCreator = s:Creator
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._bindMappings() {{{1
|
|
||||||
function! s:Creator._bindMappings()
|
|
||||||
"make <cr> do the same as the default 'o' mapping
|
|
||||||
exec "nnoremap <silent> <buffer> <cr> :call nerdtree#invokeKeyMap('". g:NERDTreeMapActivateNode ."')<cr>"
|
|
||||||
|
|
||||||
call g:NERDTreeKeyMap.BindAll()
|
|
||||||
|
|
||||||
command! -buffer -nargs=? Bookmark :call nerdtree#bookmarkNode('<args>')
|
|
||||||
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 RevealBookmark :call nerdtree#revealBookmark('<args>')
|
|
||||||
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=1 OpenBookmark :call nerdtree#openBookmark('<args>')
|
|
||||||
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=* ClearBookmarks call nerdtree#clearBookmarks('<args>')
|
|
||||||
command! -buffer -complete=customlist,nerdtree#completeBookmarks -nargs=+ BookmarkToRoot call g:NERDTreeBookmark.ToRoot('<args>')
|
|
||||||
command! -buffer -nargs=0 ClearAllBookmarks call g:NERDTreeBookmark.ClearAll() <bar> call nerdtree#renderView()
|
|
||||||
command! -buffer -nargs=0 ReadBookmarks call g:NERDTreeBookmark.CacheBookmarks(0) <bar> call nerdtree#renderView()
|
|
||||||
command! -buffer -nargs=0 WriteBookmarks call g:NERDTreeBookmark.Write()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._broadcastInitEvent() {{{1
|
|
||||||
function! s:Creator._broadcastInitEvent()
|
|
||||||
silent doautocmd User NERDTreeInit
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: s:Creator.BufNamePrefix() {{{2
|
|
||||||
function! s:Creator.BufNamePrefix()
|
|
||||||
return 'NERD_tree_'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.CreatePrimary(a:name) {{{1
|
|
||||||
function! s:Creator.CreatePrimary(name)
|
|
||||||
let creator = s:Creator.New()
|
|
||||||
call creator.createPrimary(a:name)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.createPrimary(a:name) {{{1
|
|
||||||
"name: the name of a bookmark or a directory
|
|
||||||
function! s:Creator.createPrimary(name)
|
|
||||||
let path = self._pathForString(a:name)
|
|
||||||
|
|
||||||
"if instructed to, then change the vim CWD to the dir the NERDTree is
|
|
||||||
"inited in
|
|
||||||
if g:NERDTreeChDirMode != 0
|
|
||||||
call path.changeToDir()
|
|
||||||
endif
|
|
||||||
|
|
||||||
if nerdtree#treeExistsForTab()
|
|
||||||
if nerdtree#isTreeOpen()
|
|
||||||
call nerdtree#closeTree()
|
|
||||||
endif
|
|
||||||
unlet t:NERDTreeBufName
|
|
||||||
endif
|
|
||||||
|
|
||||||
let newRoot = g:NERDTreeDirNode.New(path)
|
|
||||||
call newRoot.open()
|
|
||||||
|
|
||||||
call self._createTreeWin()
|
|
||||||
let b:treeShowHelp = 0
|
|
||||||
let b:NERDTreeIgnoreEnabled = 1
|
|
||||||
let b:NERDTreeShowFiles = g:NERDTreeShowFiles
|
|
||||||
let b:NERDTreeShowHidden = g:NERDTreeShowHidden
|
|
||||||
let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
|
|
||||||
let b:NERDTreeRoot = newRoot
|
|
||||||
let b:NERDTreeType = "primary"
|
|
||||||
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call b:NERDTreeRoot.putCursorHere(0, 0)
|
|
||||||
|
|
||||||
call self._broadcastInitEvent()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.CreateSecondary(dir) {{{1
|
|
||||||
function! s:Creator.CreateSecondary(dir)
|
|
||||||
let creator = s:Creator.New()
|
|
||||||
call creator.createSecondary(a:dir)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.createSecondary(dir) {{{1
|
|
||||||
function! s:Creator.createSecondary(dir)
|
|
||||||
try
|
|
||||||
let path = g:NERDTreePath.New(a:dir)
|
|
||||||
catch /^NERDTree.InvalidArgumentsError/
|
|
||||||
call nerdtree#echo("Invalid directory name:" . a:name)
|
|
||||||
return
|
|
||||||
endtry
|
|
||||||
|
|
||||||
"we want the directory buffer to disappear when we do the :edit below
|
|
||||||
setlocal bufhidden=wipe
|
|
||||||
|
|
||||||
let previousBuf = expand("#")
|
|
||||||
|
|
||||||
"we need a unique name for each secondary tree buffer to ensure they are
|
|
||||||
"all independent
|
|
||||||
exec "silent edit " . self._nextBufferName()
|
|
||||||
|
|
||||||
let b:NERDTreePreviousBuf = bufnr(previousBuf)
|
|
||||||
|
|
||||||
let b:NERDTreeRoot = g:NERDTreeDirNode.New(path)
|
|
||||||
call b:NERDTreeRoot.open()
|
|
||||||
|
|
||||||
call self._setCommonBufOptions()
|
|
||||||
let b:NERDTreeType = "secondary"
|
|
||||||
|
|
||||||
call nerdtree#renderView()
|
|
||||||
|
|
||||||
call self._broadcastInitEvent()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: s:Creator.CreateMirror() {{{1
|
|
||||||
function! s:Creator.CreateMirror()
|
|
||||||
let creator = s:Creator.New()
|
|
||||||
call creator.createMirror()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: s:Creator.createMirror() {{{1
|
|
||||||
function! s:Creator.createMirror()
|
|
||||||
"get the names off all the nerd tree buffers
|
|
||||||
let treeBufNames = []
|
|
||||||
for i in range(1, tabpagenr("$"))
|
|
||||||
let nextName = nerdtree#tabpagevar(i, 'NERDTreeBufName')
|
|
||||||
if nextName != -1 && (!exists("t:NERDTreeBufName") || nextName != t:NERDTreeBufName)
|
|
||||||
call add(treeBufNames, nextName)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
let treeBufNames = nerdtree#unique(treeBufNames)
|
|
||||||
|
|
||||||
"map the option names (that the user will be prompted with) to the nerd
|
|
||||||
"tree buffer names
|
|
||||||
let options = {}
|
|
||||||
let i = 0
|
|
||||||
while i < len(treeBufNames)
|
|
||||||
let bufName = treeBufNames[i]
|
|
||||||
let treeRoot = getbufvar(bufName, "NERDTreeRoot")
|
|
||||||
let options[i+1 . '. ' . treeRoot.path.str() . ' (buf name: ' . bufName . ')'] = bufName
|
|
||||||
let i = i + 1
|
|
||||||
endwhile
|
|
||||||
|
|
||||||
"work out which tree to mirror, if there is more than 1 then ask the user
|
|
||||||
let bufferName = ''
|
|
||||||
if len(keys(options)) > 1
|
|
||||||
let choices = ["Choose a tree to mirror"]
|
|
||||||
let choices = extend(choices, sort(keys(options)))
|
|
||||||
let choice = inputlist(choices)
|
|
||||||
if choice < 1 || choice > len(options) || choice ==# ''
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let bufferName = options[sort(keys(options))[choice-1]]
|
|
||||||
elseif len(keys(options)) ==# 1
|
|
||||||
let bufferName = values(options)[0]
|
|
||||||
else
|
|
||||||
call nerdtree#echo("No trees to mirror")
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
if nerdtree#treeExistsForTab() && nerdtree#isTreeOpen()
|
|
||||||
call nerdtree#closeTree()
|
|
||||||
endif
|
|
||||||
|
|
||||||
let t:NERDTreeBufName = bufferName
|
|
||||||
call self._createTreeWin()
|
|
||||||
exec 'buffer ' . bufferName
|
|
||||||
if !&hidden
|
|
||||||
call nerdtree#renderView()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._createTreeWin() {{{1
|
|
||||||
"Inits the NERD tree window. ie. opens it, sizes it, sets all the local
|
|
||||||
"options etc
|
|
||||||
function! s:Creator._createTreeWin()
|
|
||||||
"create the nerd tree window
|
|
||||||
let splitLocation = g:NERDTreeWinPos ==# "left" ? "topleft " : "botright "
|
|
||||||
let splitSize = g:NERDTreeWinSize
|
|
||||||
|
|
||||||
if !exists('t:NERDTreeBufName')
|
|
||||||
let t:NERDTreeBufName = self._nextBufferName()
|
|
||||||
silent! exec splitLocation . 'vertical ' . splitSize . ' new'
|
|
||||||
silent! exec "edit " . t:NERDTreeBufName
|
|
||||||
else
|
|
||||||
silent! exec splitLocation . 'vertical ' . splitSize . ' split'
|
|
||||||
silent! exec "buffer " . t:NERDTreeBufName
|
|
||||||
endif
|
|
||||||
|
|
||||||
setlocal winfixwidth
|
|
||||||
call self._setCommonBufOptions()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.New() {{{1
|
|
||||||
function! s:Creator.New()
|
|
||||||
let newCreator = copy(self)
|
|
||||||
return newCreator
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: s:Creator._nextBufferName() {{{2
|
|
||||||
" returns the buffer name for the next nerd tree
|
|
||||||
function! s:Creator._nextBufferName()
|
|
||||||
let name = s:Creator.BufNamePrefix() . self._nextBufferNumber()
|
|
||||||
return name
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: s:Creator._nextBufferNumber() {{{2
|
|
||||||
" the number to add to the nerd tree buffer name to make the buf name unique
|
|
||||||
function! s:Creator._nextBufferNumber()
|
|
||||||
if !exists("s:Creator._NextBufNum")
|
|
||||||
let s:Creator._NextBufNum = 1
|
|
||||||
else
|
|
||||||
let s:Creator._NextBufNum += 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
return s:Creator._NextBufNum
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._pathForString(str) {{{1
|
|
||||||
"find a bookmark or adirectory for the given string
|
|
||||||
function! s:Creator._pathForString(str)
|
|
||||||
let path = {}
|
|
||||||
if g:NERDTreeBookmark.BookmarkExistsFor(a:str)
|
|
||||||
let path = g:NERDTreeBookmark.BookmarkFor(a:str).path
|
|
||||||
else
|
|
||||||
let dir = a:str ==# '' ? getcwd() : a:str
|
|
||||||
|
|
||||||
"hack to get an absolute path if a relative path is given
|
|
||||||
if dir =~# '^\.'
|
|
||||||
let dir = getcwd() . g:NERDTreePath.Slash() . dir
|
|
||||||
endif
|
|
||||||
let dir = g:NERDTreePath.Resolve(dir)
|
|
||||||
|
|
||||||
try
|
|
||||||
let path = g:NERDTreePath.New(dir)
|
|
||||||
catch /^NERDTree.InvalidArgumentsError/
|
|
||||||
call nerdtree#echo("No bookmark or directory found for: " . a:str)
|
|
||||||
return
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
if !path.isDirectory
|
|
||||||
let path = path.getParent()
|
|
||||||
endif
|
|
||||||
|
|
||||||
return path
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._setCommonBufOptions() {{{1
|
|
||||||
function! s:Creator._setCommonBufOptions()
|
|
||||||
"throwaway buffer options
|
|
||||||
setlocal noswapfile
|
|
||||||
setlocal buftype=nofile
|
|
||||||
setlocal bufhidden=hide
|
|
||||||
setlocal nowrap
|
|
||||||
setlocal foldcolumn=0
|
|
||||||
setlocal foldmethod=manual
|
|
||||||
setlocal nofoldenable
|
|
||||||
setlocal nobuflisted
|
|
||||||
setlocal nospell
|
|
||||||
if g:NERDTreeShowLineNumbers
|
|
||||||
setlocal nu
|
|
||||||
else
|
|
||||||
setlocal nonu
|
|
||||||
if v:version >= 703
|
|
||||||
setlocal nornu
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
iabc <buffer>
|
|
||||||
|
|
||||||
if g:NERDTreeHighlightCursorline
|
|
||||||
setlocal cursorline
|
|
||||||
endif
|
|
||||||
|
|
||||||
call self._setupStatusline()
|
|
||||||
|
|
||||||
let b:treeShowHelp = 0
|
|
||||||
let b:NERDTreeIgnoreEnabled = 1
|
|
||||||
let b:NERDTreeShowFiles = g:NERDTreeShowFiles
|
|
||||||
let b:NERDTreeShowHidden = g:NERDTreeShowHidden
|
|
||||||
let b:NERDTreeShowBookmarks = g:NERDTreeShowBookmarks
|
|
||||||
setfiletype nerdtree
|
|
||||||
call self._bindMappings()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator._setupStatusline() {{{1
|
|
||||||
function! s:Creator._setupStatusline()
|
|
||||||
if g:NERDTreeStatusline != -1
|
|
||||||
let &l:statusline = g:NERDTreeStatusline
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.TogglePrimary(dir) {{{1
|
|
||||||
function! s:Creator.TogglePrimary(dir)
|
|
||||||
let creator = s:Creator.New()
|
|
||||||
call creator.togglePrimary(a:dir)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:Creator.togglePrimary(dir) {{{1
|
|
||||||
"Toggles the NERD tree. I.e the NERD tree is open, it is closed, if it is
|
|
||||||
"closed it is restored or initialized (if it doesnt exist)
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"dir: the full path for the root node (is only used if the NERD tree is being
|
|
||||||
"initialized.
|
|
||||||
function! s:Creator.togglePrimary(dir)
|
|
||||||
if nerdtree#treeExistsForTab()
|
|
||||||
if !nerdtree#isTreeOpen()
|
|
||||||
call self._createTreeWin()
|
|
||||||
if !&hidden
|
|
||||||
call nerdtree#renderView()
|
|
||||||
endif
|
|
||||||
call nerdtree#restoreScreenState()
|
|
||||||
else
|
|
||||||
call nerdtree#closeTree()
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call self.createPrimary(a:dir)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
"CLASS: KeyMap
|
|
||||||
"============================================================
|
|
||||||
let s:KeyMap = {}
|
|
||||||
let g:NERDTreeKeyMap = s:KeyMap
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.All() {{{1
|
|
||||||
function! s:KeyMap.All()
|
|
||||||
if !exists("s:keyMaps")
|
|
||||||
let s:keyMaps = []
|
|
||||||
endif
|
|
||||||
return s:keyMaps
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.FindFor(key, scope) {{{1
|
|
||||||
function! s:KeyMap.FindFor(key, scope)
|
|
||||||
for i in s:KeyMap.All()
|
|
||||||
if i.key ==# a:key && i.scope ==# a:scope
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.BindAll() {{{1
|
|
||||||
function! s:KeyMap.BindAll()
|
|
||||||
for i in s:KeyMap.All()
|
|
||||||
call i.bind()
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.bind() {{{1
|
|
||||||
function! s:KeyMap.bind()
|
|
||||||
" If the key sequence we're trying to map contains any '<>' notation, we
|
|
||||||
" must replace each of the '<' characters with '<lt>' to ensure the string
|
|
||||||
" is not translated into its corresponding keycode during the later part
|
|
||||||
" of the map command below
|
|
||||||
" :he <>
|
|
||||||
let specialNotationRegex = '\m<\([[:alnum:]_-]\+>\)'
|
|
||||||
if self.key =~# specialNotationRegex
|
|
||||||
let keymapInvokeString = substitute(self.key, specialNotationRegex, '<lt>\1', 'g')
|
|
||||||
else
|
|
||||||
let keymapInvokeString = self.key
|
|
||||||
endif
|
|
||||||
|
|
||||||
let premap = self.key == "<LeftRelease>" ? " <LeftRelease>" : " "
|
|
||||||
|
|
||||||
exec 'nnoremap <buffer> <silent> '. self.key . premap . ':call nerdtree#invokeKeyMap("'. keymapInvokeString .'")<cr>'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.Remove(key, scope) {{{1
|
|
||||||
function! s:KeyMap.Remove(key, scope)
|
|
||||||
let maps = s:KeyMap.All()
|
|
||||||
for i in range(len(maps))
|
|
||||||
if maps[i].key ==# a:key && maps[i].scope ==# a:scope
|
|
||||||
return remove(maps, i)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.invoke() {{{1
|
|
||||||
"Call the KeyMaps callback function
|
|
||||||
function! s:KeyMap.invoke(...)
|
|
||||||
let Callback = function(self.callback)
|
|
||||||
if a:0
|
|
||||||
call Callback(a:1)
|
|
||||||
else
|
|
||||||
call Callback()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.Invoke() {{{1
|
|
||||||
"Find a keymapping for a:key and the current scope invoke it.
|
|
||||||
"
|
|
||||||
"Scope is determined as follows:
|
|
||||||
" * if the cursor is on a dir node then "DirNode"
|
|
||||||
" * if the cursor is on a file node then "FileNode"
|
|
||||||
" * if the cursor is on a bookmark then "Bookmark"
|
|
||||||
"
|
|
||||||
"If a keymap has the scope of "all" then it will be called if no other keymap
|
|
||||||
"is found for a:key and the scope.
|
|
||||||
function! s:KeyMap.Invoke(key)
|
|
||||||
let node = g:NERDTreeFileNode.GetSelected()
|
|
||||||
if !empty(node)
|
|
||||||
|
|
||||||
"try file node
|
|
||||||
if !node.path.isDirectory
|
|
||||||
let km = s:KeyMap.FindFor(a:key, "FileNode")
|
|
||||||
if !empty(km)
|
|
||||||
return km.invoke(node)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
"try dir node
|
|
||||||
if node.path.isDirectory
|
|
||||||
let km = s:KeyMap.FindFor(a:key, "DirNode")
|
|
||||||
if !empty(km)
|
|
||||||
return km.invoke(node)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
"try generic node
|
|
||||||
let km = s:KeyMap.FindFor(a:key, "Node")
|
|
||||||
if !empty(km)
|
|
||||||
return km.invoke(node)
|
|
||||||
endif
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
"try bookmark
|
|
||||||
let bm = g:NERDTreeBookmark.GetSelected()
|
|
||||||
if !empty(bm)
|
|
||||||
let km = s:KeyMap.FindFor(a:key, "Bookmark")
|
|
||||||
if !empty(km)
|
|
||||||
return km.invoke(bm)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
"try all
|
|
||||||
let km = s:KeyMap.FindFor(a:key, "all")
|
|
||||||
if !empty(km)
|
|
||||||
return km.invoke()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.Create(options) {{{1
|
|
||||||
function! s:KeyMap.Create(options)
|
|
||||||
let newKeyMap = copy(self)
|
|
||||||
let opts = extend({'scope': 'all', 'quickhelpText': ''}, copy(a:options))
|
|
||||||
let newKeyMap.key = opts['key']
|
|
||||||
let newKeyMap.quickhelpText = opts['quickhelpText']
|
|
||||||
let newKeyMap.callback = opts['callback']
|
|
||||||
let newKeyMap.scope = opts['scope']
|
|
||||||
|
|
||||||
call s:KeyMap.Add(newKeyMap)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: KeyMap.Add(keymap) {{{1
|
|
||||||
function! s:KeyMap.Add(keymap)
|
|
||||||
call s:KeyMap.Remove(a:keymap.key, a:keymap.scope)
|
|
||||||
call add(s:KeyMap.All(), a:keymap)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,180 +0,0 @@
|
||||||
"CLASS: MenuController
|
|
||||||
"============================================================
|
|
||||||
let s:MenuController = {}
|
|
||||||
let g:NERDTreeMenuController = s:MenuController
|
|
||||||
|
|
||||||
"FUNCTION: MenuController.New(menuItems) {{{1
|
|
||||||
"create a new menu controller that operates on the given menu items
|
|
||||||
function! s:MenuController.New(menuItems)
|
|
||||||
let newMenuController = copy(self)
|
|
||||||
if a:menuItems[0].isSeparator()
|
|
||||||
let newMenuController.menuItems = a:menuItems[1:-1]
|
|
||||||
else
|
|
||||||
let newMenuController.menuItems = a:menuItems
|
|
||||||
endif
|
|
||||||
return newMenuController
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController.showMenu() {{{1
|
|
||||||
"start the main loop of the menu and get the user to choose/execute a menu
|
|
||||||
"item
|
|
||||||
function! s:MenuController.showMenu()
|
|
||||||
call self._saveOptions()
|
|
||||||
|
|
||||||
try
|
|
||||||
let self.selection = 0
|
|
||||||
|
|
||||||
let done = 0
|
|
||||||
while !done
|
|
||||||
redraw!
|
|
||||||
call self._echoPrompt()
|
|
||||||
let key = nr2char(getchar())
|
|
||||||
let done = self._handleKeypress(key)
|
|
||||||
endwhile
|
|
||||||
finally
|
|
||||||
call self._restoreOptions()
|
|
||||||
endtry
|
|
||||||
|
|
||||||
if self.selection != -1
|
|
||||||
let m = self._current()
|
|
||||||
call m.execute()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._echoPrompt() {{{1
|
|
||||||
function! s:MenuController._echoPrompt()
|
|
||||||
echo "NERDTree Menu. Use j/k/enter and the shortcuts indicated"
|
|
||||||
echo "=========================================================="
|
|
||||||
|
|
||||||
for i in range(0, len(self.menuItems)-1)
|
|
||||||
if self.selection == i
|
|
||||||
echo "> " . self.menuItems[i].text
|
|
||||||
else
|
|
||||||
echo " " . self.menuItems[i].text
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._current(key) {{{1
|
|
||||||
"get the MenuItem that is currently selected
|
|
||||||
function! s:MenuController._current()
|
|
||||||
return self.menuItems[self.selection]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._handleKeypress(key) {{{1
|
|
||||||
"change the selection (if appropriate) and return 1 if the user has made
|
|
||||||
"their choice, 0 otherwise
|
|
||||||
function! s:MenuController._handleKeypress(key)
|
|
||||||
if a:key == 'j'
|
|
||||||
call self._cursorDown()
|
|
||||||
elseif a:key == 'k'
|
|
||||||
call self._cursorUp()
|
|
||||||
elseif a:key == nr2char(27) "escape
|
|
||||||
let self.selection = -1
|
|
||||||
return 1
|
|
||||||
elseif a:key == "\r" || a:key == "\n" "enter and ctrl-j
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
let index = self._nextIndexFor(a:key)
|
|
||||||
if index != -1
|
|
||||||
let self.selection = index
|
|
||||||
if len(self._allIndexesFor(a:key)) == 1
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._allIndexesFor(shortcut) {{{1
|
|
||||||
"get indexes to all menu items with the given shortcut
|
|
||||||
function! s:MenuController._allIndexesFor(shortcut)
|
|
||||||
let toReturn = []
|
|
||||||
|
|
||||||
for i in range(0, len(self.menuItems)-1)
|
|
||||||
if self.menuItems[i].shortcut == a:shortcut
|
|
||||||
call add(toReturn, i)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._nextIndexFor(shortcut) {{{1
|
|
||||||
"get the index to the next menu item with the given shortcut, starts from the
|
|
||||||
"current cursor location and wraps around to the top again if need be
|
|
||||||
function! s:MenuController._nextIndexFor(shortcut)
|
|
||||||
for i in range(self.selection+1, len(self.menuItems)-1)
|
|
||||||
if self.menuItems[i].shortcut == a:shortcut
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
for i in range(0, self.selection)
|
|
||||||
if self.menuItems[i].shortcut == a:shortcut
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return -1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._setCmdheight() {{{1
|
|
||||||
"sets &cmdheight to whatever is needed to display the menu
|
|
||||||
function! s:MenuController._setCmdheight()
|
|
||||||
let &cmdheight = len(self.menuItems) + 3
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._saveOptions() {{{1
|
|
||||||
"set any vim options that are required to make the menu work (saving their old
|
|
||||||
"values)
|
|
||||||
function! s:MenuController._saveOptions()
|
|
||||||
let self._oldLazyredraw = &lazyredraw
|
|
||||||
let self._oldCmdheight = &cmdheight
|
|
||||||
set nolazyredraw
|
|
||||||
call self._setCmdheight()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._restoreOptions() {{{1
|
|
||||||
"restore the options we saved in _saveOptions()
|
|
||||||
function! s:MenuController._restoreOptions()
|
|
||||||
let &cmdheight = self._oldCmdheight
|
|
||||||
let &lazyredraw = self._oldLazyredraw
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._cursorDown() {{{1
|
|
||||||
"move the cursor to the next menu item, skipping separators
|
|
||||||
function! s:MenuController._cursorDown()
|
|
||||||
let done = 0
|
|
||||||
while !done
|
|
||||||
if self.selection < len(self.menuItems)-1
|
|
||||||
let self.selection += 1
|
|
||||||
else
|
|
||||||
let self.selection = 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !self._current().isSeparator()
|
|
||||||
let done = 1
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuController._cursorUp() {{{1
|
|
||||||
"move the cursor to the previous menu item, skipping separators
|
|
||||||
function! s:MenuController._cursorUp()
|
|
||||||
let done = 0
|
|
||||||
while !done
|
|
||||||
if self.selection > 0
|
|
||||||
let self.selection -= 1
|
|
||||||
else
|
|
||||||
let self.selection = len(self.menuItems)-1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !self._current().isSeparator()
|
|
||||||
let done = 1
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
"CLASS: MenuItem
|
|
||||||
"============================================================
|
|
||||||
let s:MenuItem = {}
|
|
||||||
let g:NERDTreeMenuItem = s:MenuItem
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.All() {{{1
|
|
||||||
"get all top level menu items
|
|
||||||
function! s:MenuItem.All()
|
|
||||||
if !exists("s:menuItems")
|
|
||||||
let s:menuItems = []
|
|
||||||
endif
|
|
||||||
return s:menuItems
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.AllEnabled() {{{1
|
|
||||||
"get all top level menu items that are currently enabled
|
|
||||||
function! s:MenuItem.AllEnabled()
|
|
||||||
let toReturn = []
|
|
||||||
for i in s:MenuItem.All()
|
|
||||||
if i.enabled()
|
|
||||||
call add(toReturn, i)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.Create(options) {{{1
|
|
||||||
"make a new menu item and add it to the global list
|
|
||||||
function! s:MenuItem.Create(options)
|
|
||||||
let newMenuItem = copy(self)
|
|
||||||
|
|
||||||
let newMenuItem.text = a:options['text']
|
|
||||||
let newMenuItem.shortcut = a:options['shortcut']
|
|
||||||
let newMenuItem.children = []
|
|
||||||
|
|
||||||
let newMenuItem.isActiveCallback = -1
|
|
||||||
if has_key(a:options, 'isActiveCallback')
|
|
||||||
let newMenuItem.isActiveCallback = a:options['isActiveCallback']
|
|
||||||
endif
|
|
||||||
|
|
||||||
let newMenuItem.callback = -1
|
|
||||||
if has_key(a:options, 'callback')
|
|
||||||
let newMenuItem.callback = a:options['callback']
|
|
||||||
endif
|
|
||||||
|
|
||||||
if has_key(a:options, 'parent')
|
|
||||||
call add(a:options['parent'].children, newMenuItem)
|
|
||||||
else
|
|
||||||
call add(s:MenuItem.All(), newMenuItem)
|
|
||||||
endif
|
|
||||||
|
|
||||||
return newMenuItem
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.CreateSeparator(options) {{{1
|
|
||||||
"make a new separator menu item and add it to the global list
|
|
||||||
function! s:MenuItem.CreateSeparator(options)
|
|
||||||
let standard_options = { 'text': '--------------------',
|
|
||||||
\ 'shortcut': -1,
|
|
||||||
\ 'callback': -1 }
|
|
||||||
let options = extend(a:options, standard_options, "force")
|
|
||||||
|
|
||||||
return s:MenuItem.Create(options)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.CreateSubmenu(options) {{{1
|
|
||||||
"make a new submenu and add it to global list
|
|
||||||
function! s:MenuItem.CreateSubmenu(options)
|
|
||||||
let standard_options = { 'callback': -1 }
|
|
||||||
let options = extend(a:options, standard_options, "force")
|
|
||||||
|
|
||||||
return s:MenuItem.Create(options)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.enabled() {{{1
|
|
||||||
"return 1 if this menu item should be displayed
|
|
||||||
"
|
|
||||||
"delegates off to the isActiveCallback, and defaults to 1 if no callback was
|
|
||||||
"specified
|
|
||||||
function! s:MenuItem.enabled()
|
|
||||||
if self.isActiveCallback != -1
|
|
||||||
return {self.isActiveCallback}()
|
|
||||||
endif
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.execute() {{{1
|
|
||||||
"perform the action behind this menu item, if this menuitem has children then
|
|
||||||
"display a new menu for them, otherwise deletegate off to the menuitem's
|
|
||||||
"callback
|
|
||||||
function! s:MenuItem.execute()
|
|
||||||
if len(self.children)
|
|
||||||
let mc = s:MenuController.New(self.children)
|
|
||||||
call mc.showMenu()
|
|
||||||
else
|
|
||||||
if self.callback != -1
|
|
||||||
call {self.callback}()
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.isSeparator() {{{1
|
|
||||||
"return 1 if this menuitem is a separator
|
|
||||||
function! s:MenuItem.isSeparator()
|
|
||||||
return self.callback == -1 && self.children == []
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: MenuItem.isSubmenu() {{{1
|
|
||||||
"return 1 if this menuitem is a submenu
|
|
||||||
function! s:MenuItem.isSubmenu()
|
|
||||||
return self.callback == -1 && !empty(self.children)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,264 +0,0 @@
|
||||||
"CLASS: Opener
|
|
||||||
"============================================================
|
|
||||||
let s:Opener = {}
|
|
||||||
let g:NERDTreeOpener = s:Opener
|
|
||||||
|
|
||||||
"FUNCTION: Opener._checkToCloseTree(newtab) {{{1
|
|
||||||
"Check the class options and global options (i.e. NERDTreeQuitOnOpen) to see
|
|
||||||
"if the tree should be closed now.
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"a:newtab - boolean. If set, only close the tree now if we are opening the
|
|
||||||
"target in a new tab. This is needed because we have to close tree before we
|
|
||||||
"leave the tab
|
|
||||||
function! s:Opener._checkToCloseTree(newtab)
|
|
||||||
if self._keepopen
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
if (a:newtab && self._where == 't') || !a:newtab
|
|
||||||
call nerdtree#closeTreeIfQuitOnOpen()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._gotoTargetWin() {{{1
|
|
||||||
function! s:Opener._gotoTargetWin()
|
|
||||||
if b:NERDTreeType ==# "secondary"
|
|
||||||
if self._where == 'v'
|
|
||||||
vsplit
|
|
||||||
elseif self._where == 'h'
|
|
||||||
split
|
|
||||||
elseif self._where == 't'
|
|
||||||
tabnew
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call self._checkToCloseTree(1)
|
|
||||||
|
|
||||||
if self._where == 'v'
|
|
||||||
call self._newVSplit()
|
|
||||||
elseif self._where == 'h'
|
|
||||||
call self._newSplit()
|
|
||||||
elseif self._where == 't'
|
|
||||||
tabnew
|
|
||||||
elseif self._where == 'p'
|
|
||||||
call self._previousWindow()
|
|
||||||
endif
|
|
||||||
|
|
||||||
call self._checkToCloseTree(0)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener.New(path, opts) {{{1
|
|
||||||
"Args:
|
|
||||||
"
|
|
||||||
"a:path: The path object that is to be opened.
|
|
||||||
"
|
|
||||||
"a:opts:
|
|
||||||
"
|
|
||||||
"A dictionary containing the following keys (all optional):
|
|
||||||
" 'where': Specifies whether the node should be opened in new split/tab or in
|
|
||||||
" the previous window. Can be either 'v' or 'h' or 't' (for open in
|
|
||||||
" new tab)
|
|
||||||
" 'reuse': if a window is displaying the file then jump the cursor there
|
|
||||||
" 'keepopen': dont close the tree window
|
|
||||||
" 'stay': open the file, but keep the cursor in the tree win
|
|
||||||
function! s:Opener.New(path, opts)
|
|
||||||
let newObj = copy(self)
|
|
||||||
|
|
||||||
let newObj._path = a:path
|
|
||||||
let newObj._stay = nerdtree#has_opt(a:opts, 'stay')
|
|
||||||
let newObj._reuse = nerdtree#has_opt(a:opts, 'reuse')
|
|
||||||
let newObj._keepopen = nerdtree#has_opt(a:opts, 'keepopen')
|
|
||||||
let newObj._where = has_key(a:opts, 'where') ? a:opts['where'] : ''
|
|
||||||
let newObj._treetype = b:NERDTreeType
|
|
||||||
call newObj._saveCursorPos()
|
|
||||||
|
|
||||||
return newObj
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._newSplit() {{{1
|
|
||||||
function! s:Opener._newSplit()
|
|
||||||
" Save the user's settings for splitbelow and splitright
|
|
||||||
let savesplitbelow=&splitbelow
|
|
||||||
let savesplitright=&splitright
|
|
||||||
|
|
||||||
" 'there' will be set to a command to move from the split window
|
|
||||||
" back to the explorer window
|
|
||||||
"
|
|
||||||
" 'back' will be set to a command to move from the explorer window
|
|
||||||
" back to the newly split window
|
|
||||||
"
|
|
||||||
" 'right' and 'below' will be set to the settings needed for
|
|
||||||
" splitbelow and splitright IF the explorer is the only window.
|
|
||||||
"
|
|
||||||
let there= g:NERDTreeWinPos ==# "left" ? "wincmd h" : "wincmd l"
|
|
||||||
let back = g:NERDTreeWinPos ==# "left" ? "wincmd l" : "wincmd h"
|
|
||||||
let right= g:NERDTreeWinPos ==# "left"
|
|
||||||
let below=0
|
|
||||||
|
|
||||||
" Attempt to go to adjacent window
|
|
||||||
call nerdtree#exec(back)
|
|
||||||
|
|
||||||
let onlyOneWin = (winnr("$") ==# 1)
|
|
||||||
|
|
||||||
" If no adjacent window, set splitright and splitbelow appropriately
|
|
||||||
if onlyOneWin
|
|
||||||
let &splitright=right
|
|
||||||
let &splitbelow=below
|
|
||||||
else
|
|
||||||
" found adjacent window - invert split direction
|
|
||||||
let &splitright=!right
|
|
||||||
let &splitbelow=!below
|
|
||||||
endif
|
|
||||||
|
|
||||||
let splitMode = onlyOneWin ? "vertical" : ""
|
|
||||||
|
|
||||||
" Open the new window
|
|
||||||
try
|
|
||||||
exec(splitMode." sp ")
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E37/
|
|
||||||
call nerdtree#putCursorInTreeWin()
|
|
||||||
throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified."
|
|
||||||
catch /^Vim\%((\a\+)\)\=:/
|
|
||||||
"do nothing
|
|
||||||
endtry
|
|
||||||
|
|
||||||
"resize the tree window if no other window was open before
|
|
||||||
if onlyOneWin
|
|
||||||
let size = exists("b:NERDTreeOldWindowSize") ? b:NERDTreeOldWindowSize : g:NERDTreeWinSize
|
|
||||||
call nerdtree#exec(there)
|
|
||||||
exec("silent ". splitMode ." resize ". size)
|
|
||||||
call nerdtree#exec('wincmd p')
|
|
||||||
endif
|
|
||||||
|
|
||||||
" Restore splitmode settings
|
|
||||||
let &splitbelow=savesplitbelow
|
|
||||||
let &splitright=savesplitright
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._newVSplit() {{{1
|
|
||||||
function! s:Opener._newVSplit()
|
|
||||||
let winwidth = winwidth(".")
|
|
||||||
if winnr("$")==#1
|
|
||||||
let winwidth = g:NERDTreeWinSize
|
|
||||||
endif
|
|
||||||
|
|
||||||
call nerdtree#exec("wincmd p")
|
|
||||||
vnew
|
|
||||||
|
|
||||||
"resize the nerd tree back to the original size
|
|
||||||
call nerdtree#putCursorInTreeWin()
|
|
||||||
exec("silent vertical resize ". winwidth)
|
|
||||||
call nerdtree#exec('wincmd p')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener.open(target) {{{1
|
|
||||||
function! s:Opener.open(target)
|
|
||||||
if self._path.isDirectory
|
|
||||||
call self._openDirectory(a:target)
|
|
||||||
else
|
|
||||||
call self._openFile()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._openFile() {{{1
|
|
||||||
function! s:Opener._openFile()
|
|
||||||
if self._reuse && self._reuseWindow()
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
call self._gotoTargetWin()
|
|
||||||
|
|
||||||
if self._treetype ==# "secondary"
|
|
||||||
call self._path.edit()
|
|
||||||
else
|
|
||||||
call self._path.edit()
|
|
||||||
|
|
||||||
|
|
||||||
if self._stay
|
|
||||||
call self._restoreCursorPos()
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._openDirectory(node) {{{1
|
|
||||||
function! s:Opener._openDirectory(node)
|
|
||||||
if self._treetype ==# "secondary"
|
|
||||||
call self._gotoTargetWin()
|
|
||||||
call g:NERDTreeCreator.CreateSecondary(a:node.path.str())
|
|
||||||
else
|
|
||||||
call self._gotoTargetWin()
|
|
||||||
if empty(self._where)
|
|
||||||
call a:node.makeRoot()
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call a:node.putCursorHere(0, 0)
|
|
||||||
elseif self._where == 't'
|
|
||||||
call g:NERDTreeCreator.CreatePrimary(a:node.path.str())
|
|
||||||
else
|
|
||||||
call g:NERDTreeCreator.CreateSecondary(a:node.path.str())
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if self._stay
|
|
||||||
call self._restoreCursorPos()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._previousWindow() {{{1
|
|
||||||
function! s:Opener._previousWindow()
|
|
||||||
if !nerdtree#isWindowUsable(winnr("#")) && nerdtree#firstUsableWindow() ==# -1
|
|
||||||
call self._newSplit()
|
|
||||||
else
|
|
||||||
try
|
|
||||||
if !nerdtree#isWindowUsable(winnr("#"))
|
|
||||||
call nerdtree#exec(nerdtree#firstUsableWindow() . "wincmd w")
|
|
||||||
else
|
|
||||||
call nerdtree#exec('wincmd p')
|
|
||||||
endif
|
|
||||||
catch /^Vim\%((\a\+)\)\=:E37/
|
|
||||||
call nerdtree#putCursorInTreeWin()
|
|
||||||
throw "NERDTree.FileAlreadyOpenAndModifiedError: ". self._path.str() ." is already open and modified."
|
|
||||||
catch /^Vim\%((\a\+)\)\=:/
|
|
||||||
echo v:exception
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._restoreCursorPos(){{{1
|
|
||||||
function! s:Opener._restoreCursorPos()
|
|
||||||
call nerdtree#exec('normal ' . self._tabnr . 'gt')
|
|
||||||
call nerdtree#exec(bufwinnr(self._bufnr) . 'wincmd w')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._reuseWindow(){{{1
|
|
||||||
"put the cursor in the first window we find for this file
|
|
||||||
"
|
|
||||||
"return 1 if we were successful
|
|
||||||
function! s:Opener._reuseWindow()
|
|
||||||
"check the current tab for the window
|
|
||||||
let winnr = bufwinnr('^' . self._path.str() . '$')
|
|
||||||
if winnr != -1
|
|
||||||
call nerdtree#exec(winnr . "wincmd w")
|
|
||||||
call self._checkToCloseTree(0)
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
"check other tabs
|
|
||||||
let tabnr = self._path.tabnr()
|
|
||||||
if tabnr
|
|
||||||
call self._checkToCloseTree(1)
|
|
||||||
call nerdtree#exec('normal! ' . tabnr . 'gt')
|
|
||||||
let winnr = bufwinnr('^' . self._path.str() . '$')
|
|
||||||
call nerdtree#exec(winnr . "wincmd w")
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Opener._saveCursorPos(){{{1
|
|
||||||
function! s:Opener._saveCursorPos()
|
|
||||||
let self._bufnr = bufnr("")
|
|
||||||
let self._tabnr = tabpagenr()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,724 +0,0 @@
|
||||||
"we need to use this number many times for sorting... so we calculate it only
|
|
||||||
"once here
|
|
||||||
let s:NERDTreeSortStarIndex = index(g:NERDTreeSortOrder, '*')
|
|
||||||
|
|
||||||
"CLASS: Path
|
|
||||||
"============================================================
|
|
||||||
let s:Path = {}
|
|
||||||
let g:NERDTreePath = s:Path
|
|
||||||
|
|
||||||
"FUNCTION: Path.AbsolutePathFor(str) {{{1
|
|
||||||
function! s:Path.AbsolutePathFor(str)
|
|
||||||
let prependCWD = 0
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
let prependCWD = a:str !~# '^.:\(\\\|\/\)' && a:str !~# '^\(\\\\\|\/\/\)'
|
|
||||||
else
|
|
||||||
let prependCWD = a:str !~# '^/'
|
|
||||||
endif
|
|
||||||
|
|
||||||
let toReturn = a:str
|
|
||||||
if prependCWD
|
|
||||||
let toReturn = getcwd() . s:Path.Slash() . a:str
|
|
||||||
endif
|
|
||||||
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.bookmarkNames() {{{1
|
|
||||||
function! s:Path.bookmarkNames()
|
|
||||||
if !exists("self._bookmarkNames")
|
|
||||||
call self.cacheDisplayString()
|
|
||||||
endif
|
|
||||||
return self._bookmarkNames
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.cacheDisplayString() {{{1
|
|
||||||
function! s:Path.cacheDisplayString()
|
|
||||||
let self.cachedDisplayString = self.getLastPathComponent(1)
|
|
||||||
|
|
||||||
if self.isExecutable
|
|
||||||
let self.cachedDisplayString = self.cachedDisplayString . '*'
|
|
||||||
endif
|
|
||||||
|
|
||||||
let self._bookmarkNames = []
|
|
||||||
for i in g:NERDTreeBookmark.Bookmarks()
|
|
||||||
if i.path.equals(self)
|
|
||||||
call add(self._bookmarkNames, i.name)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
if !empty(self._bookmarkNames)
|
|
||||||
let self.cachedDisplayString .= ' {' . join(self._bookmarkNames) . '}'
|
|
||||||
endif
|
|
||||||
|
|
||||||
if self.isSymLink
|
|
||||||
let self.cachedDisplayString .= ' -> ' . self.symLinkDest
|
|
||||||
endif
|
|
||||||
|
|
||||||
if self.isReadOnly
|
|
||||||
let self.cachedDisplayString .= ' [RO]'
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.changeToDir() {{{1
|
|
||||||
function! s:Path.changeToDir()
|
|
||||||
let dir = self.str({'format': 'Cd'})
|
|
||||||
if self.isDirectory ==# 0
|
|
||||||
let dir = self.getParent().str({'format': 'Cd'})
|
|
||||||
endif
|
|
||||||
|
|
||||||
try
|
|
||||||
execute "cd " . dir
|
|
||||||
call nerdtree#echo("CWD is now: " . getcwd())
|
|
||||||
catch
|
|
||||||
throw "NERDTree.PathChangeError: cannot change CWD to " . dir
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.compareTo() {{{1
|
|
||||||
"
|
|
||||||
"Compares this Path to the given path and returns 0 if they are equal, -1 if
|
|
||||||
"this Path is "less than" the given path, or 1 if it is "greater".
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: the path object to compare this to
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"1, -1 or 0
|
|
||||||
function! s:Path.compareTo(path)
|
|
||||||
let thisPath = self.getLastPathComponent(1)
|
|
||||||
let thatPath = a:path.getLastPathComponent(1)
|
|
||||||
|
|
||||||
"if the paths are the same then clearly we return 0
|
|
||||||
if thisPath ==# thatPath
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
let thisSS = self.getSortOrderIndex()
|
|
||||||
let thatSS = a:path.getSortOrderIndex()
|
|
||||||
|
|
||||||
"compare the sort sequences, if they are different then the return
|
|
||||||
"value is easy
|
|
||||||
if thisSS < thatSS
|
|
||||||
return -1
|
|
||||||
elseif thisSS > thatSS
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
"if the sort sequences are the same then compare the paths
|
|
||||||
"alphabetically
|
|
||||||
let pathCompare = g:NERDTreeCaseSensitiveSort ? thisPath <# thatPath : thisPath <? thatPath
|
|
||||||
if pathCompare
|
|
||||||
return -1
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.Create(fullpath) {{{1
|
|
||||||
"
|
|
||||||
"Factory method.
|
|
||||||
"
|
|
||||||
"Creates a path object with the given path. The path is also created on the
|
|
||||||
"filesystem. If the path already exists, a NERDTree.Path.Exists exception is
|
|
||||||
"thrown. If any other errors occur, a NERDTree.Path exception is thrown.
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"fullpath: the full filesystem path to the file/dir to create
|
|
||||||
function! s:Path.Create(fullpath)
|
|
||||||
"bail if the a:fullpath already exists
|
|
||||||
if isdirectory(a:fullpath) || filereadable(a:fullpath)
|
|
||||||
throw "NERDTree.CreatePathError: Directory Exists: '" . a:fullpath . "'"
|
|
||||||
endif
|
|
||||||
|
|
||||||
try
|
|
||||||
|
|
||||||
"if it ends with a slash, assume its a dir create it
|
|
||||||
if a:fullpath =~# '\(\\\|\/\)$'
|
|
||||||
"whack the trailing slash off the end if it exists
|
|
||||||
let fullpath = substitute(a:fullpath, '\(\\\|\/\)$', '', '')
|
|
||||||
|
|
||||||
call mkdir(fullpath, 'p')
|
|
||||||
|
|
||||||
"assume its a file and create
|
|
||||||
else
|
|
||||||
call writefile([], a:fullpath)
|
|
||||||
endif
|
|
||||||
catch
|
|
||||||
throw "NERDTree.CreatePathError: Could not create path: '" . a:fullpath . "'"
|
|
||||||
endtry
|
|
||||||
|
|
||||||
return s:Path.New(a:fullpath)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.copy(dest) {{{1
|
|
||||||
"
|
|
||||||
"Copies the file/dir represented by this Path to the given location
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"dest: the location to copy this dir/file to
|
|
||||||
function! s:Path.copy(dest)
|
|
||||||
if !s:Path.CopyingSupported()
|
|
||||||
throw "NERDTree.CopyingNotSupportedError: Copying is not supported on this OS"
|
|
||||||
endif
|
|
||||||
|
|
||||||
let dest = s:Path.WinToUnixPath(a:dest)
|
|
||||||
|
|
||||||
let cmd = g:NERDTreeCopyCmd . " " . escape(self.str(), nerdtree#escChars()) . " " . escape(dest, nerdtree#escChars())
|
|
||||||
let success = system(cmd)
|
|
||||||
if success != 0
|
|
||||||
throw "NERDTree.CopyError: Could not copy ''". self.str() ."'' to: '" . a:dest . "'"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.CopyingSupported() {{{1
|
|
||||||
"
|
|
||||||
"returns 1 if copying is supported for this OS
|
|
||||||
function! s:Path.CopyingSupported()
|
|
||||||
return exists('g:NERDTreeCopyCmd')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.copyingWillOverwrite(dest) {{{1
|
|
||||||
"
|
|
||||||
"returns 1 if copy this path to the given location will cause files to
|
|
||||||
"overwritten
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"dest: the location this path will be copied to
|
|
||||||
function! s:Path.copyingWillOverwrite(dest)
|
|
||||||
if filereadable(a:dest)
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if isdirectory(a:dest)
|
|
||||||
let path = s:Path.JoinPathStrings(a:dest, self.getLastPathComponent(0))
|
|
||||||
if filereadable(path)
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.delete() {{{1
|
|
||||||
"
|
|
||||||
"Deletes the file represented by this path.
|
|
||||||
"Deletion of directories is not supported
|
|
||||||
"
|
|
||||||
"Throws NERDTree.Path.Deletion exceptions
|
|
||||||
function! s:Path.delete()
|
|
||||||
if self.isDirectory
|
|
||||||
|
|
||||||
let cmd = g:NERDTreeRemoveDirCmd . self.str({'escape': 1})
|
|
||||||
let success = system(cmd)
|
|
||||||
|
|
||||||
if v:shell_error != 0
|
|
||||||
throw "NERDTree.PathDeletionError: Could not delete directory: '" . self.str() . "'"
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let success = delete(self.str())
|
|
||||||
if success != 0
|
|
||||||
throw "NERDTree.PathDeletionError: Could not delete file: '" . self.str() . "'"
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
"delete all bookmarks for this path
|
|
||||||
for i in self.bookmarkNames()
|
|
||||||
let bookmark = g:NERDTreeBookmark.BookmarkFor(i)
|
|
||||||
call bookmark.delete()
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.displayString() {{{1
|
|
||||||
"
|
|
||||||
"Returns a string that specifies how the path should be represented as a
|
|
||||||
"string
|
|
||||||
function! s:Path.displayString()
|
|
||||||
if self.cachedDisplayString ==# ""
|
|
||||||
call self.cacheDisplayString()
|
|
||||||
endif
|
|
||||||
|
|
||||||
return self.cachedDisplayString
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.edit() {{{1
|
|
||||||
function! s:Path.edit()
|
|
||||||
exec "edit " . self.str({'format': 'Edit'})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.extractDriveLetter(fullpath) {{{1
|
|
||||||
"
|
|
||||||
"If running windows, cache the drive letter for this path
|
|
||||||
function! s:Path.extractDriveLetter(fullpath)
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
if a:fullpath =~ '^\(\\\\\|\/\/\)'
|
|
||||||
"For network shares, the 'drive' consists of the first two parts of the path, i.e. \\boxname\share
|
|
||||||
let self.drive = substitute(a:fullpath, '^\(\(\\\\\|\/\/\)[^\\\/]*\(\\\|\/\)[^\\\/]*\).*', '\1', '')
|
|
||||||
let self.drive = substitute(self.drive, '/', '\', "g")
|
|
||||||
else
|
|
||||||
let self.drive = substitute(a:fullpath, '\(^[a-zA-Z]:\).*', '\1', '')
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let self.drive = ''
|
|
||||||
endif
|
|
||||||
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.exists() {{{1
|
|
||||||
"return 1 if this path points to a location that is readable or is a directory
|
|
||||||
function! s:Path.exists()
|
|
||||||
let p = self.str()
|
|
||||||
return filereadable(p) || isdirectory(p)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.getDir() {{{1
|
|
||||||
"
|
|
||||||
"Returns this path if it is a directory, else this paths parent.
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"a Path object
|
|
||||||
function! s:Path.getDir()
|
|
||||||
if self.isDirectory
|
|
||||||
return self
|
|
||||||
else
|
|
||||||
return self.getParent()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.getParent() {{{1
|
|
||||||
"
|
|
||||||
"Returns a new path object for this paths parent
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"a new Path object
|
|
||||||
function! s:Path.getParent()
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
let path = self.drive . '\' . join(self.pathSegments[0:-2], '\')
|
|
||||||
else
|
|
||||||
let path = '/'. join(self.pathSegments[0:-2], '/')
|
|
||||||
endif
|
|
||||||
|
|
||||||
return s:Path.New(path)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.getLastPathComponent(dirSlash) {{{1
|
|
||||||
"
|
|
||||||
"Gets the last part of this path.
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"dirSlash: if 1 then a trailing slash will be added to the returned value for
|
|
||||||
"directory nodes.
|
|
||||||
function! s:Path.getLastPathComponent(dirSlash)
|
|
||||||
if empty(self.pathSegments)
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
let toReturn = self.pathSegments[-1]
|
|
||||||
if a:dirSlash && self.isDirectory
|
|
||||||
let toReturn = toReturn . '/'
|
|
||||||
endif
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.getSortOrderIndex() {{{1
|
|
||||||
"returns the index of the pattern in g:NERDTreeSortOrder that this path matches
|
|
||||||
function! s:Path.getSortOrderIndex()
|
|
||||||
let i = 0
|
|
||||||
while i < len(g:NERDTreeSortOrder)
|
|
||||||
if self.getLastPathComponent(1) =~# g:NERDTreeSortOrder[i]
|
|
||||||
return i
|
|
||||||
endif
|
|
||||||
let i = i + 1
|
|
||||||
endwhile
|
|
||||||
return s:NERDTreeSortStarIndex
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.isUnixHiddenFile() {{{1
|
|
||||||
"check for unix hidden files
|
|
||||||
function! s:Path.isUnixHiddenFile()
|
|
||||||
return self.getLastPathComponent(0) =~# '^\.'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.isUnixHiddenPath() {{{1
|
|
||||||
"check for unix path with hidden components
|
|
||||||
function! s:Path.isUnixHiddenPath()
|
|
||||||
if self.getLastPathComponent(0) =~# '^\.'
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
for segment in self.pathSegments
|
|
||||||
if segment =~# '^\.'
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.ignore() {{{1
|
|
||||||
"returns true if this path should be ignored
|
|
||||||
function! s:Path.ignore()
|
|
||||||
"filter out the user specified paths to ignore
|
|
||||||
if b:NERDTreeIgnoreEnabled
|
|
||||||
for i in g:NERDTreeIgnore
|
|
||||||
if self._ignorePatternMatches(i)
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
|
|
||||||
"dont show hidden files unless instructed to
|
|
||||||
if b:NERDTreeShowHidden ==# 0 && self.isUnixHiddenFile()
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if b:NERDTreeShowFiles ==# 0 && self.isDirectory ==# 0
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if exists("*NERDTreeCustomIgnoreFilter") && NERDTreeCustomIgnoreFilter(self)
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._ignorePatternMatches(pattern) {{{1
|
|
||||||
"returns true if this path matches the given ignore pattern
|
|
||||||
function! s:Path._ignorePatternMatches(pattern)
|
|
||||||
let pat = a:pattern
|
|
||||||
if strpart(pat,len(pat)-7) == '[[dir]]'
|
|
||||||
if !self.isDirectory
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let pat = strpart(pat,0, len(pat)-7)
|
|
||||||
elseif strpart(pat,len(pat)-8) == '[[file]]'
|
|
||||||
if self.isDirectory
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
let pat = strpart(pat,0, len(pat)-8)
|
|
||||||
endif
|
|
||||||
|
|
||||||
return self.getLastPathComponent(0) =~# pat
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.isUnder(path) {{{1
|
|
||||||
"return 1 if this path is somewhere under the given path in the filesystem.
|
|
||||||
"
|
|
||||||
"a:path should be a dir
|
|
||||||
function! s:Path.isUnder(path)
|
|
||||||
if a:path.isDirectory == 0
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
let this = self.str()
|
|
||||||
let that = a:path.str()
|
|
||||||
return stridx(this, that . s:Path.Slash()) == 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.JoinPathStrings(...) {{{1
|
|
||||||
function! s:Path.JoinPathStrings(...)
|
|
||||||
let components = []
|
|
||||||
for i in a:000
|
|
||||||
let components = extend(components, split(i, '/'))
|
|
||||||
endfor
|
|
||||||
return '/' . join(components, '/')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.equals() {{{1
|
|
||||||
"
|
|
||||||
"Determines whether 2 path objects are "equal".
|
|
||||||
"They are equal if the paths they represent are the same
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: the other path obj to compare this with
|
|
||||||
function! s:Path.equals(path)
|
|
||||||
return self.str() ==# a:path.str()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.New() {{{1
|
|
||||||
"The Constructor for the Path object
|
|
||||||
function! s:Path.New(path)
|
|
||||||
let newPath = copy(self)
|
|
||||||
|
|
||||||
call newPath.readInfoFromDisk(s:Path.AbsolutePathFor(a:path))
|
|
||||||
|
|
||||||
let newPath.cachedDisplayString = ""
|
|
||||||
|
|
||||||
return newPath
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.Slash() {{{1
|
|
||||||
"return the slash to use for the current OS
|
|
||||||
function! s:Path.Slash()
|
|
||||||
return nerdtree#runningWindows() ? '\' : '/'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.Resolve() {{{1
|
|
||||||
"Invoke the vim resolve() function and return the result
|
|
||||||
"This is necessary because in some versions of vim resolve() removes trailing
|
|
||||||
"slashes while in other versions it doesn't. This always removes the trailing
|
|
||||||
"slash
|
|
||||||
function! s:Path.Resolve(path)
|
|
||||||
let tmp = resolve(a:path)
|
|
||||||
return tmp =~# '.\+/$' ? substitute(tmp, '/$', '', '') : tmp
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.readInfoFromDisk(fullpath) {{{1
|
|
||||||
"
|
|
||||||
"
|
|
||||||
"Throws NERDTree.Path.InvalidArguments exception.
|
|
||||||
function! s:Path.readInfoFromDisk(fullpath)
|
|
||||||
call self.extractDriveLetter(a:fullpath)
|
|
||||||
|
|
||||||
let fullpath = s:Path.WinToUnixPath(a:fullpath)
|
|
||||||
|
|
||||||
if getftype(fullpath) ==# "fifo"
|
|
||||||
throw "NERDTree.InvalidFiletypeError: Cant handle FIFO files: " . a:fullpath
|
|
||||||
endif
|
|
||||||
|
|
||||||
let self.pathSegments = split(fullpath, '/')
|
|
||||||
|
|
||||||
let self.isReadOnly = 0
|
|
||||||
if isdirectory(a:fullpath)
|
|
||||||
let self.isDirectory = 1
|
|
||||||
elseif filereadable(a:fullpath)
|
|
||||||
let self.isDirectory = 0
|
|
||||||
let self.isReadOnly = filewritable(a:fullpath) ==# 0
|
|
||||||
else
|
|
||||||
throw "NERDTree.InvalidArgumentsError: Invalid path = " . a:fullpath
|
|
||||||
endif
|
|
||||||
|
|
||||||
let self.isExecutable = 0
|
|
||||||
if !self.isDirectory
|
|
||||||
let self.isExecutable = getfperm(a:fullpath) =~# 'x'
|
|
||||||
endif
|
|
||||||
|
|
||||||
"grab the last part of the path (minus the trailing slash)
|
|
||||||
let lastPathComponent = self.getLastPathComponent(0)
|
|
||||||
|
|
||||||
"get the path to the new node with the parent dir fully resolved
|
|
||||||
let hardPath = s:Path.Resolve(self.strTrunk()) . '/' . lastPathComponent
|
|
||||||
|
|
||||||
"if the last part of the path is a symlink then flag it as such
|
|
||||||
let self.isSymLink = (s:Path.Resolve(hardPath) != hardPath)
|
|
||||||
if self.isSymLink
|
|
||||||
let self.symLinkDest = s:Path.Resolve(fullpath)
|
|
||||||
|
|
||||||
"if the link is a dir then slap a / on the end of its dest
|
|
||||||
if isdirectory(self.symLinkDest)
|
|
||||||
|
|
||||||
"we always wanna treat MS windows shortcuts as files for
|
|
||||||
"simplicity
|
|
||||||
if hardPath !~# '\.lnk$'
|
|
||||||
|
|
||||||
let self.symLinkDest = self.symLinkDest . '/'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.refresh() {{{1
|
|
||||||
function! s:Path.refresh()
|
|
||||||
call self.readInfoFromDisk(self.str())
|
|
||||||
call self.cacheDisplayString()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.rename() {{{1
|
|
||||||
"
|
|
||||||
"Renames this node on the filesystem
|
|
||||||
function! s:Path.rename(newPath)
|
|
||||||
if a:newPath ==# ''
|
|
||||||
throw "NERDTree.InvalidArgumentsError: Invalid newPath for renaming = ". a:newPath
|
|
||||||
endif
|
|
||||||
|
|
||||||
let success = rename(self.str(), a:newPath)
|
|
||||||
if success != 0
|
|
||||||
throw "NERDTree.PathRenameError: Could not rename: '" . self.str() . "'" . 'to:' . a:newPath
|
|
||||||
endif
|
|
||||||
call self.readInfoFromDisk(a:newPath)
|
|
||||||
|
|
||||||
for i in self.bookmarkNames()
|
|
||||||
let b = g:NERDTreeBookmark.BookmarkFor(i)
|
|
||||||
call b.setPath(copy(self))
|
|
||||||
endfor
|
|
||||||
call g:NERDTreeBookmark.Write()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.str() {{{1
|
|
||||||
"
|
|
||||||
"Returns a string representation of this Path
|
|
||||||
"
|
|
||||||
"Takes an optional dictionary param to specify how the output should be
|
|
||||||
"formatted.
|
|
||||||
"
|
|
||||||
"The dict may have the following keys:
|
|
||||||
" 'format'
|
|
||||||
" 'escape'
|
|
||||||
" 'truncateTo'
|
|
||||||
"
|
|
||||||
"The 'format' key may have a value of:
|
|
||||||
" 'Cd' - a string to be used with the :cd command
|
|
||||||
" 'Edit' - a string to be used with :e :sp :new :tabedit etc
|
|
||||||
" 'UI' - a string used in the NERD tree UI
|
|
||||||
"
|
|
||||||
"The 'escape' key, if specified will cause the output to be escaped with
|
|
||||||
"shellescape()
|
|
||||||
"
|
|
||||||
"The 'truncateTo' key causes the resulting string to be truncated to the value
|
|
||||||
"'truncateTo' maps to. A '<' char will be prepended.
|
|
||||||
function! s:Path.str(...)
|
|
||||||
let options = a:0 ? a:1 : {}
|
|
||||||
let toReturn = ""
|
|
||||||
|
|
||||||
if has_key(options, 'format')
|
|
||||||
let format = options['format']
|
|
||||||
if has_key(self, '_strFor' . format)
|
|
||||||
exec 'let toReturn = self._strFor' . format . '()'
|
|
||||||
else
|
|
||||||
raise 'NERDTree.UnknownFormatError: unknown format "'. format .'"'
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
let toReturn = self._str()
|
|
||||||
endif
|
|
||||||
|
|
||||||
if nerdtree#has_opt(options, 'escape')
|
|
||||||
let toReturn = shellescape(toReturn)
|
|
||||||
endif
|
|
||||||
|
|
||||||
if has_key(options, 'truncateTo')
|
|
||||||
let limit = options['truncateTo']
|
|
||||||
if len(toReturn) > limit
|
|
||||||
let toReturn = "<" . strpart(toReturn, len(toReturn) - limit + 1)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._strForUI() {{{1
|
|
||||||
function! s:Path._strForUI()
|
|
||||||
let toReturn = '/' . join(self.pathSegments, '/')
|
|
||||||
if self.isDirectory && toReturn != '/'
|
|
||||||
let toReturn = toReturn . '/'
|
|
||||||
endif
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._strForCd() {{{1
|
|
||||||
"
|
|
||||||
" returns a string that can be used with :cd
|
|
||||||
function! s:Path._strForCd()
|
|
||||||
return escape(self.str(), nerdtree#escChars())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._strForEdit() {{{1
|
|
||||||
"
|
|
||||||
"Return: the string for this path that is suitable to be used with the :edit
|
|
||||||
"command
|
|
||||||
function! s:Path._strForEdit()
|
|
||||||
let p = escape(self.str({'format': 'UI'}), nerdtree#escChars())
|
|
||||||
let cwd = getcwd() . s:Path.Slash()
|
|
||||||
|
|
||||||
"return a relative path if we can
|
|
||||||
let isRelative = 0
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
let isRelative = stridx(tolower(p), tolower(cwd)) == 0
|
|
||||||
else
|
|
||||||
let isRelative = stridx(p, cwd) == 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
if isRelative
|
|
||||||
let p = strpart(p, strlen(cwd))
|
|
||||||
|
|
||||||
"handle the edge case where the file begins with a + (vim interprets
|
|
||||||
"the +foo in `:e +foo` as an option to :edit)
|
|
||||||
if p[0] == "+"
|
|
||||||
let p = '\' . p
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if p ==# ''
|
|
||||||
let p = '.'
|
|
||||||
endif
|
|
||||||
|
|
||||||
return p
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._strForGlob() {{{1
|
|
||||||
function! s:Path._strForGlob()
|
|
||||||
let lead = s:Path.Slash()
|
|
||||||
|
|
||||||
"if we are running windows then slap a drive letter on the front
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
let lead = self.drive . '\'
|
|
||||||
endif
|
|
||||||
|
|
||||||
let toReturn = lead . join(self.pathSegments, s:Path.Slash())
|
|
||||||
|
|
||||||
if !nerdtree#runningWindows()
|
|
||||||
let toReturn = escape(toReturn, nerdtree#escChars())
|
|
||||||
endif
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path._str() {{{1
|
|
||||||
"
|
|
||||||
"Gets the string path for this path object that is appropriate for the OS.
|
|
||||||
"EG, in windows c:\foo\bar
|
|
||||||
" in *nix /foo/bar
|
|
||||||
function! s:Path._str()
|
|
||||||
let lead = s:Path.Slash()
|
|
||||||
|
|
||||||
"if we are running windows then slap a drive letter on the front
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
let lead = self.drive . '\'
|
|
||||||
endif
|
|
||||||
|
|
||||||
return lead . join(self.pathSegments, s:Path.Slash())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.strTrunk() {{{1
|
|
||||||
"Gets the path without the last segment on the end.
|
|
||||||
function! s:Path.strTrunk()
|
|
||||||
return self.drive . '/' . join(self.pathSegments[0:-2], '/')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: Path.tabnr() {{{1
|
|
||||||
" return the number of the first tab that is displaying this file
|
|
||||||
"
|
|
||||||
" return 0 if no tab was found
|
|
||||||
function! s:Path.tabnr()
|
|
||||||
let str = self.str()
|
|
||||||
for t in range(tabpagenr('$'))
|
|
||||||
for b in tabpagebuflist(t+1)
|
|
||||||
if str == expand('#' . b . ':p')
|
|
||||||
return t+1
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: Path.WinToUnixPath(pathstr){{{1
|
|
||||||
"Takes in a windows path and returns the unix equiv
|
|
||||||
"
|
|
||||||
"A class level method
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"pathstr: the windows path to convert
|
|
||||||
function! s:Path.WinToUnixPath(pathstr)
|
|
||||||
if !nerdtree#runningWindows()
|
|
||||||
return a:pathstr
|
|
||||||
endif
|
|
||||||
|
|
||||||
let toReturn = a:pathstr
|
|
||||||
|
|
||||||
"remove the x:\ of the front
|
|
||||||
let toReturn = substitute(toReturn, '^.*:\(\\\|/\)\?', '/', "")
|
|
||||||
|
|
||||||
"remove the \\ network share from the front
|
|
||||||
let toReturn = substitute(toReturn, '^\(\\\\\|\/\/\)[^\\\/]*\(\\\|\/\)[^\\\/]*\(\\\|\/\)\?', '/', "")
|
|
||||||
|
|
||||||
"convert all \ chars to /
|
|
||||||
let toReturn = substitute(toReturn, '\', '/', "g")
|
|
||||||
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,528 +0,0 @@
|
||||||
"CLASS: TreeDirNode
|
|
||||||
"A subclass of NERDTreeFileNode.
|
|
||||||
"
|
|
||||||
"The 'composite' part of the file/dir composite.
|
|
||||||
"============================================================
|
|
||||||
let s:TreeDirNode = copy(g:NERDTreeFileNode)
|
|
||||||
let g:NERDTreeDirNode = s:TreeDirNode
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.AbsoluteTreeRoot(){{{1
|
|
||||||
"class method that returns the highest cached ancestor of the current root
|
|
||||||
function! s:TreeDirNode.AbsoluteTreeRoot()
|
|
||||||
let currentNode = b:NERDTreeRoot
|
|
||||||
while currentNode.parent != {}
|
|
||||||
let currentNode = currentNode.parent
|
|
||||||
endwhile
|
|
||||||
return currentNode
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.activate([options]) {{{1
|
|
||||||
unlet s:TreeDirNode.activate
|
|
||||||
function! s:TreeDirNode.activate(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
call self.toggleOpen(opts)
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call self.putCursorHere(0, 0)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.addChild(treenode, inOrder) {{{1
|
|
||||||
"Adds the given treenode to the list of children for this node
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"-treenode: the node to add
|
|
||||||
"-inOrder: 1 if the new node should be inserted in sorted order
|
|
||||||
function! s:TreeDirNode.addChild(treenode, inOrder)
|
|
||||||
call add(self.children, a:treenode)
|
|
||||||
let a:treenode.parent = self
|
|
||||||
|
|
||||||
if a:inOrder
|
|
||||||
call self.sortChildren()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.close() {{{1
|
|
||||||
"Closes this directory
|
|
||||||
function! s:TreeDirNode.close()
|
|
||||||
let self.isOpen = 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.closeChildren() {{{1
|
|
||||||
"Closes all the child dir nodes of this node
|
|
||||||
function! s:TreeDirNode.closeChildren()
|
|
||||||
for i in self.children
|
|
||||||
if i.path.isDirectory
|
|
||||||
call i.close()
|
|
||||||
call i.closeChildren()
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.createChild(path, inOrder) {{{1
|
|
||||||
"Instantiates a new child node for this node with the given path. The new
|
|
||||||
"nodes parent is set to this node.
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: a Path object that this node will represent/contain
|
|
||||||
"inOrder: 1 if the new node should be inserted in sorted order
|
|
||||||
"
|
|
||||||
"Returns:
|
|
||||||
"the newly created node
|
|
||||||
function! s:TreeDirNode.createChild(path, inOrder)
|
|
||||||
let newTreeNode = g:NERDTreeFileNode.New(a:path)
|
|
||||||
call self.addChild(newTreeNode, a:inOrder)
|
|
||||||
return newTreeNode
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.findNode(path) {{{1
|
|
||||||
"Will find one of the children (recursively) that has the given path
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: a path object
|
|
||||||
unlet s:TreeDirNode.findNode
|
|
||||||
function! s:TreeDirNode.findNode(path)
|
|
||||||
if a:path.equals(self.path)
|
|
||||||
return self
|
|
||||||
endif
|
|
||||||
if stridx(a:path.str(), self.path.str(), 0) ==# -1
|
|
||||||
return {}
|
|
||||||
endif
|
|
||||||
|
|
||||||
if self.path.isDirectory
|
|
||||||
for i in self.children
|
|
||||||
let retVal = i.findNode(a:path)
|
|
||||||
if retVal != {}
|
|
||||||
return retVal
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.getChildCount() {{{1
|
|
||||||
"Returns the number of children this node has
|
|
||||||
function! s:TreeDirNode.getChildCount()
|
|
||||||
return len(self.children)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.getChild(path) {{{1
|
|
||||||
"Returns child node of this node that has the given path or {} if no such node
|
|
||||||
"exists.
|
|
||||||
"
|
|
||||||
"This function doesnt not recurse into child dir nodes
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: a path object
|
|
||||||
function! s:TreeDirNode.getChild(path)
|
|
||||||
if stridx(a:path.str(), self.path.str(), 0) ==# -1
|
|
||||||
return {}
|
|
||||||
endif
|
|
||||||
|
|
||||||
let index = self.getChildIndex(a:path)
|
|
||||||
if index ==# -1
|
|
||||||
return {}
|
|
||||||
else
|
|
||||||
return self.children[index]
|
|
||||||
endif
|
|
||||||
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.getChildByIndex(indx, visible) {{{1
|
|
||||||
"returns the child at the given index
|
|
||||||
"Args:
|
|
||||||
"indx: the index to get the child from
|
|
||||||
"visible: 1 if only the visible children array should be used, 0 if all the
|
|
||||||
"children should be searched.
|
|
||||||
function! s:TreeDirNode.getChildByIndex(indx, visible)
|
|
||||||
let array_to_search = a:visible? self.getVisibleChildren() : self.children
|
|
||||||
if a:indx > len(array_to_search)
|
|
||||||
throw "NERDTree.InvalidArgumentsError: Index is out of bounds."
|
|
||||||
endif
|
|
||||||
return array_to_search[a:indx]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.getChildIndex(path) {{{1
|
|
||||||
"Returns the index of the child node of this node that has the given path or
|
|
||||||
"-1 if no such node exists.
|
|
||||||
"
|
|
||||||
"This function doesnt not recurse into child dir nodes
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: a path object
|
|
||||||
function! s:TreeDirNode.getChildIndex(path)
|
|
||||||
if stridx(a:path.str(), self.path.str(), 0) ==# -1
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
"do a binary search for the child
|
|
||||||
let a = 0
|
|
||||||
let z = self.getChildCount()
|
|
||||||
while a < z
|
|
||||||
let mid = (a+z)/2
|
|
||||||
let diff = a:path.compareTo(self.children[mid].path)
|
|
||||||
|
|
||||||
if diff ==# -1
|
|
||||||
let z = mid
|
|
||||||
elseif diff ==# 1
|
|
||||||
let a = mid+1
|
|
||||||
else
|
|
||||||
return mid
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
return -1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.GetSelected() {{{1
|
|
||||||
"Returns the current node if it is a dir node, or else returns the current
|
|
||||||
"nodes parent
|
|
||||||
unlet s:TreeDirNode.GetSelected
|
|
||||||
function! s:TreeDirNode.GetSelected()
|
|
||||||
let currentDir = g:NERDTreeFileNode.GetSelected()
|
|
||||||
if currentDir != {} && !currentDir.isRoot()
|
|
||||||
if currentDir.path.isDirectory ==# 0
|
|
||||||
let currentDir = currentDir.parent
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return currentDir
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.getVisibleChildCount() {{{1
|
|
||||||
"Returns the number of visible children this node has
|
|
||||||
function! s:TreeDirNode.getVisibleChildCount()
|
|
||||||
return len(self.getVisibleChildren())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.getVisibleChildren() {{{1
|
|
||||||
"Returns a list of children to display for this node, in the correct order
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"an array of treenodes
|
|
||||||
function! s:TreeDirNode.getVisibleChildren()
|
|
||||||
let toReturn = []
|
|
||||||
for i in self.children
|
|
||||||
if i.path.ignore() ==# 0
|
|
||||||
call add(toReturn, i)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return toReturn
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.hasVisibleChildren() {{{1
|
|
||||||
"returns 1 if this node has any childre, 0 otherwise..
|
|
||||||
function! s:TreeDirNode.hasVisibleChildren()
|
|
||||||
return self.getVisibleChildCount() != 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode._initChildren() {{{1
|
|
||||||
"Removes all childen from this node and re-reads them
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"silent: 1 if the function should not echo any "please wait" messages for
|
|
||||||
"large directories
|
|
||||||
"
|
|
||||||
"Return: the number of child nodes read
|
|
||||||
function! s:TreeDirNode._initChildren(silent)
|
|
||||||
"remove all the current child nodes
|
|
||||||
let self.children = []
|
|
||||||
|
|
||||||
"get an array of all the files in the nodes dir
|
|
||||||
let dir = self.path
|
|
||||||
let globDir = dir.str({'format': 'Glob'})
|
|
||||||
|
|
||||||
if version >= 703
|
|
||||||
let filesStr = globpath(globDir, '*', 1) . "\n" . globpath(globDir, '.*', 1)
|
|
||||||
else
|
|
||||||
let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*')
|
|
||||||
endif
|
|
||||||
|
|
||||||
let files = split(filesStr, "\n")
|
|
||||||
|
|
||||||
if !a:silent && len(files) > g:NERDTreeNotificationThreshold
|
|
||||||
call nerdtree#echo("Please wait, caching a large dir ...")
|
|
||||||
endif
|
|
||||||
|
|
||||||
let invalidFilesFound = 0
|
|
||||||
for i in files
|
|
||||||
|
|
||||||
"filter out the .. and . directories
|
|
||||||
"Note: we must match .. AND ../ cos sometimes the globpath returns
|
|
||||||
"../ for path with strange chars (eg $)
|
|
||||||
if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$'
|
|
||||||
|
|
||||||
"put the next file in a new node and attach it
|
|
||||||
try
|
|
||||||
let path = g:NERDTreePath.New(i)
|
|
||||||
call self.createChild(path, 0)
|
|
||||||
catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
|
|
||||||
let invalidFilesFound += 1
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
call self.sortChildren()
|
|
||||||
|
|
||||||
if !a:silent && len(files) > g:NERDTreeNotificationThreshold
|
|
||||||
call nerdtree#echo("Please wait, caching a large dir ... DONE (". self.getChildCount() ." nodes cached).")
|
|
||||||
endif
|
|
||||||
|
|
||||||
if invalidFilesFound
|
|
||||||
call nerdtree#echoWarning(invalidFilesFound . " file(s) could not be loaded into the NERD tree")
|
|
||||||
endif
|
|
||||||
return self.getChildCount()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.New(path) {{{1
|
|
||||||
"Returns a new TreeNode object with the given path and parent
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: a path object representing the full filesystem path to the file/dir that the node represents
|
|
||||||
unlet s:TreeDirNode.New
|
|
||||||
function! s:TreeDirNode.New(path)
|
|
||||||
if a:path.isDirectory != 1
|
|
||||||
throw "NERDTree.InvalidArgumentsError: A TreeDirNode object must be instantiated with a directory Path object."
|
|
||||||
endif
|
|
||||||
|
|
||||||
let newTreeNode = copy(self)
|
|
||||||
let newTreeNode.path = a:path
|
|
||||||
|
|
||||||
let newTreeNode.isOpen = 0
|
|
||||||
let newTreeNode.children = []
|
|
||||||
|
|
||||||
let newTreeNode.parent = {}
|
|
||||||
|
|
||||||
return newTreeNode
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.open([opts]) {{{1
|
|
||||||
"Open the dir in the current tree or in a new tree elsewhere.
|
|
||||||
"
|
|
||||||
"If opening in the current tree, return the number of cached nodes.
|
|
||||||
unlet s:TreeDirNode.open
|
|
||||||
function! s:TreeDirNode.open(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
|
|
||||||
if has_key(opts, 'where') && !empty(opts['where'])
|
|
||||||
let opener = g:NERDTreeOpener.New(self.path, opts)
|
|
||||||
call opener.open(self)
|
|
||||||
else
|
|
||||||
let self.isOpen = 1
|
|
||||||
if self.children ==# []
|
|
||||||
return self._initChildren(0)
|
|
||||||
else
|
|
||||||
return 0
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.openAlong([opts]) {{{1
|
|
||||||
"recursive open the dir if it has only one directory child.
|
|
||||||
"
|
|
||||||
"return the level of opened directories.
|
|
||||||
function! s:TreeDirNode.openAlong(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
let level = 0
|
|
||||||
|
|
||||||
let node = self
|
|
||||||
while node.path.isDirectory
|
|
||||||
call node.open(opts)
|
|
||||||
let level += 1
|
|
||||||
if node.getVisibleChildCount() == 1
|
|
||||||
let node = node.getChildByIndex(0, 1)
|
|
||||||
else
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
return level
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: TreeDirNode.openExplorer() {{{1
|
|
||||||
" opens an explorer window for this node in the previous window (could be a
|
|
||||||
" nerd tree or a netrw)
|
|
||||||
function! s:TreeDirNode.openExplorer()
|
|
||||||
call self.open({'where': 'p'})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.openInNewTab(options) {{{1
|
|
||||||
unlet s:TreeDirNode.openInNewTab
|
|
||||||
function! s:TreeDirNode.openInNewTab(options)
|
|
||||||
call nerdtree#deprecated('TreeDirNode.openInNewTab', 'is deprecated, use open() instead')
|
|
||||||
call self.open({'where': 't'})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode._openInNewTab() {{{1
|
|
||||||
function! s:TreeDirNode._openInNewTab()
|
|
||||||
tabnew
|
|
||||||
call g:NERDTreeCreator.CreatePrimary(self.path.str())
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.openRecursively() {{{1
|
|
||||||
"Opens this treenode and all of its children whose paths arent 'ignored'
|
|
||||||
"because of the file filters.
|
|
||||||
"
|
|
||||||
"This method is actually a wrapper for the OpenRecursively2 method which does
|
|
||||||
"the work.
|
|
||||||
function! s:TreeDirNode.openRecursively()
|
|
||||||
call self._openRecursively2(1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode._openRecursively2() {{{1
|
|
||||||
"Opens this all children of this treenode recursively if either:
|
|
||||||
" *they arent filtered by file filters
|
|
||||||
" *a:forceOpen is 1
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"forceOpen: 1 if this node should be opened regardless of file filters
|
|
||||||
function! s:TreeDirNode._openRecursively2(forceOpen)
|
|
||||||
if self.path.ignore() ==# 0 || a:forceOpen
|
|
||||||
let self.isOpen = 1
|
|
||||||
if self.children ==# []
|
|
||||||
call self._initChildren(1)
|
|
||||||
endif
|
|
||||||
|
|
||||||
for i in self.children
|
|
||||||
if i.path.isDirectory ==# 1
|
|
||||||
call i._openRecursively2(0)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.refresh() {{{1
|
|
||||||
unlet s:TreeDirNode.refresh
|
|
||||||
function! s:TreeDirNode.refresh()
|
|
||||||
call self.path.refresh()
|
|
||||||
|
|
||||||
"if this node was ever opened, refresh its children
|
|
||||||
if self.isOpen || !empty(self.children)
|
|
||||||
"go thru all the files/dirs under this node
|
|
||||||
let newChildNodes = []
|
|
||||||
let invalidFilesFound = 0
|
|
||||||
let dir = self.path
|
|
||||||
let globDir = dir.str({'format': 'Glob'})
|
|
||||||
let filesStr = globpath(globDir, '*') . "\n" . globpath(globDir, '.*')
|
|
||||||
let files = split(filesStr, "\n")
|
|
||||||
for i in files
|
|
||||||
"filter out the .. and . directories
|
|
||||||
"Note: we must match .. AND ../ cos sometimes the globpath returns
|
|
||||||
"../ for path with strange chars (eg $)
|
|
||||||
if i !~# '\/\.\.\/\?$' && i !~# '\/\.\/\?$'
|
|
||||||
|
|
||||||
try
|
|
||||||
"create a new path and see if it exists in this nodes children
|
|
||||||
let path = g:NERDTreePath.New(i)
|
|
||||||
let newNode = self.getChild(path)
|
|
||||||
if newNode != {}
|
|
||||||
call newNode.refresh()
|
|
||||||
call add(newChildNodes, newNode)
|
|
||||||
|
|
||||||
"the node doesnt exist so create it
|
|
||||||
else
|
|
||||||
let newNode = g:NERDTreeFileNode.New(path)
|
|
||||||
let newNode.parent = self
|
|
||||||
call add(newChildNodes, newNode)
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
catch /^NERDTree.\(InvalidArguments\|InvalidFiletype\)Error/
|
|
||||||
let invalidFilesFound = 1
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
"swap this nodes children out for the children we just read/refreshed
|
|
||||||
let self.children = newChildNodes
|
|
||||||
call self.sortChildren()
|
|
||||||
|
|
||||||
if invalidFilesFound
|
|
||||||
call nerdtree#echoWarning("some files could not be loaded into the NERD tree")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.reveal(path) {{{1
|
|
||||||
"reveal the given path, i.e. cache and open all treenodes needed to display it
|
|
||||||
"in the UI
|
|
||||||
function! s:TreeDirNode.reveal(path)
|
|
||||||
if !a:path.isUnder(self.path)
|
|
||||||
throw "NERDTree.InvalidArgumentsError: " . a:path.str() . " should be under " . self.path.str()
|
|
||||||
endif
|
|
||||||
|
|
||||||
call self.open()
|
|
||||||
|
|
||||||
if self.path.equals(a:path.getParent())
|
|
||||||
let n = self.findNode(a:path)
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call n.putCursorHere(1,0)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
let p = a:path
|
|
||||||
while !p.getParent().equals(self.path)
|
|
||||||
let p = p.getParent()
|
|
||||||
endwhile
|
|
||||||
|
|
||||||
let n = self.findNode(p)
|
|
||||||
call n.reveal(a:path)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.removeChild(treenode) {{{1
|
|
||||||
"
|
|
||||||
"Removes the given treenode from this nodes set of children
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"treenode: the node to remove
|
|
||||||
"
|
|
||||||
"Throws a NERDTree.ChildNotFoundError if the given treenode is not found
|
|
||||||
function! s:TreeDirNode.removeChild(treenode)
|
|
||||||
for i in range(0, self.getChildCount()-1)
|
|
||||||
if self.children[i].equals(a:treenode)
|
|
||||||
call remove(self.children, i)
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
throw "NERDTree.ChildNotFoundError: child node was not found"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.sortChildren() {{{1
|
|
||||||
"
|
|
||||||
"Sorts the children of this node according to alphabetical order and the
|
|
||||||
"directory priority.
|
|
||||||
"
|
|
||||||
function! s:TreeDirNode.sortChildren()
|
|
||||||
let CompareFunc = function("nerdtree#compareNodes")
|
|
||||||
call sort(self.children, CompareFunc)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.toggleOpen([options]) {{{1
|
|
||||||
"Opens this directory if it is closed and vice versa
|
|
||||||
function! s:TreeDirNode.toggleOpen(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
if self.isOpen ==# 1
|
|
||||||
call self.close()
|
|
||||||
else
|
|
||||||
if g:NERDTreeCasadeOpenSingleChildDir == 0
|
|
||||||
call self.open(opts)
|
|
||||||
else
|
|
||||||
call self.openAlong(opts)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeDirNode.transplantChild(newNode) {{{1
|
|
||||||
"Replaces the child of this with the given node (where the child node's full
|
|
||||||
"path matches a:newNode's fullpath). The search for the matching node is
|
|
||||||
"non-recursive
|
|
||||||
"
|
|
||||||
"Arg:
|
|
||||||
"newNode: the node to graft into the tree
|
|
||||||
function! s:TreeDirNode.transplantChild(newNode)
|
|
||||||
for i in range(0, self.getChildCount()-1)
|
|
||||||
if self.children[i].equals(a:newNode)
|
|
||||||
let self.children[i] = a:newNode
|
|
||||||
let a:newNode.parent = self
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,485 +0,0 @@
|
||||||
"CLASS: TreeFileNode
|
|
||||||
"This class is the parent of the TreeDirNode class and is the
|
|
||||||
"'Component' part of the composite design pattern between the treenode
|
|
||||||
"classes.
|
|
||||||
"============================================================
|
|
||||||
let s:TreeFileNode = {}
|
|
||||||
let g:NERDTreeFileNode = s:TreeFileNode
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.activate(...) {{{1
|
|
||||||
function! s:TreeFileNode.activate(...)
|
|
||||||
call self.open(a:0 ? a:1 : {})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.bookmark(name) {{{1
|
|
||||||
"bookmark this node with a:name
|
|
||||||
function! s:TreeFileNode.bookmark(name)
|
|
||||||
|
|
||||||
"if a bookmark exists with the same name and the node is cached then save
|
|
||||||
"it so we can update its display string
|
|
||||||
let oldMarkedNode = {}
|
|
||||||
try
|
|
||||||
let oldMarkedNode = g:NERDTreeBookmark.GetNodeForName(a:name, 1)
|
|
||||||
catch /^NERDTree.BookmarkNotFoundError/
|
|
||||||
catch /^NERDTree.BookmarkedNodeNotFoundError/
|
|
||||||
endtry
|
|
||||||
|
|
||||||
call g:NERDTreeBookmark.AddBookmark(a:name, self.path)
|
|
||||||
call self.path.cacheDisplayString()
|
|
||||||
call g:NERDTreeBookmark.Write()
|
|
||||||
|
|
||||||
if !empty(oldMarkedNode)
|
|
||||||
call oldMarkedNode.path.cacheDisplayString()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.cacheParent() {{{1
|
|
||||||
"initializes self.parent if it isnt already
|
|
||||||
function! s:TreeFileNode.cacheParent()
|
|
||||||
if empty(self.parent)
|
|
||||||
let parentPath = self.path.getParent()
|
|
||||||
if parentPath.equals(self.path)
|
|
||||||
throw "NERDTree.CannotCacheParentError: already at root"
|
|
||||||
endif
|
|
||||||
let self.parent = s:TreeFileNode.New(parentPath)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.clearBookmarks() {{{1
|
|
||||||
function! s:TreeFileNode.clearBookmarks()
|
|
||||||
for i in g:NERDTreeBookmark.Bookmarks()
|
|
||||||
if i.path.equals(self.path)
|
|
||||||
call i.delete()
|
|
||||||
end
|
|
||||||
endfor
|
|
||||||
call self.path.cacheDisplayString()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.copy(dest) {{{1
|
|
||||||
function! s:TreeFileNode.copy(dest)
|
|
||||||
call self.path.copy(a:dest)
|
|
||||||
let newPath = g:NERDTreePath.New(a:dest)
|
|
||||||
let parent = b:NERDTreeRoot.findNode(newPath.getParent())
|
|
||||||
if !empty(parent)
|
|
||||||
call parent.refresh()
|
|
||||||
return parent.findNode(newPath)
|
|
||||||
else
|
|
||||||
return {}
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.delete {{{1
|
|
||||||
"Removes this node from the tree and calls the Delete method for its path obj
|
|
||||||
function! s:TreeFileNode.delete()
|
|
||||||
call self.path.delete()
|
|
||||||
call self.parent.removeChild(self)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.displayString() {{{1
|
|
||||||
"
|
|
||||||
"Returns a string that specifies how the node should be represented as a
|
|
||||||
"string
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"a string that can be used in the view to represent this node
|
|
||||||
function! s:TreeFileNode.displayString()
|
|
||||||
return self.path.displayString()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.equals(treenode) {{{1
|
|
||||||
"
|
|
||||||
"Compares this treenode to the input treenode and returns 1 if they are the
|
|
||||||
"same node.
|
|
||||||
"
|
|
||||||
"Use this method instead of == because sometimes when the treenodes contain
|
|
||||||
"many children, vim seg faults when doing ==
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"treenode: the other treenode to compare to
|
|
||||||
function! s:TreeFileNode.equals(treenode)
|
|
||||||
return self.path.str() ==# a:treenode.path.str()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.findNode(path) {{{1
|
|
||||||
"Returns self if this node.path.Equals the given path.
|
|
||||||
"Returns {} if not equal.
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: the path object to compare against
|
|
||||||
function! s:TreeFileNode.findNode(path)
|
|
||||||
if a:path.equals(self.path)
|
|
||||||
return self
|
|
||||||
endif
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction) {{{1
|
|
||||||
"
|
|
||||||
"Finds the next sibling for this node in the indicated direction. This sibling
|
|
||||||
"must be a directory and may/may not have children as specified.
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"direction: 0 if you want to find the previous sibling, 1 for the next sibling
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"a treenode object or {} if no appropriate sibling could be found
|
|
||||||
function! s:TreeFileNode.findOpenDirSiblingWithVisibleChildren(direction)
|
|
||||||
"if we have no parent then we can have no siblings
|
|
||||||
if self.parent != {}
|
|
||||||
let nextSibling = self.findSibling(a:direction)
|
|
||||||
|
|
||||||
while nextSibling != {}
|
|
||||||
if nextSibling.path.isDirectory && nextSibling.hasVisibleChildren() && nextSibling.isOpen
|
|
||||||
return nextSibling
|
|
||||||
endif
|
|
||||||
let nextSibling = nextSibling.findSibling(a:direction)
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.findSibling(direction) {{{1
|
|
||||||
"
|
|
||||||
"Finds the next sibling for this node in the indicated direction
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"direction: 0 if you want to find the previous sibling, 1 for the next sibling
|
|
||||||
"
|
|
||||||
"Return:
|
|
||||||
"a treenode object or {} if no sibling could be found
|
|
||||||
function! s:TreeFileNode.findSibling(direction)
|
|
||||||
"if we have no parent then we can have no siblings
|
|
||||||
if self.parent != {}
|
|
||||||
|
|
||||||
"get the index of this node in its parents children
|
|
||||||
let siblingIndx = self.parent.getChildIndex(self.path)
|
|
||||||
|
|
||||||
if siblingIndx != -1
|
|
||||||
"move a long to the next potential sibling node
|
|
||||||
let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
|
|
||||||
|
|
||||||
"keep moving along to the next sibling till we find one that is valid
|
|
||||||
let numSiblings = self.parent.getChildCount()
|
|
||||||
while siblingIndx >= 0 && siblingIndx < numSiblings
|
|
||||||
|
|
||||||
"if the next node is not an ignored node (i.e. wont show up in the
|
|
||||||
"view) then return it
|
|
||||||
if self.parent.children[siblingIndx].path.ignore() ==# 0
|
|
||||||
return self.parent.children[siblingIndx]
|
|
||||||
endif
|
|
||||||
|
|
||||||
"go to next node
|
|
||||||
let siblingIndx = a:direction ==# 1 ? siblingIndx+1 : siblingIndx-1
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.getLineNum(){{{1
|
|
||||||
"returns the line number this node is rendered on, or -1 if it isnt rendered
|
|
||||||
function! s:TreeFileNode.getLineNum()
|
|
||||||
"if the node is the root then return the root line no.
|
|
||||||
if self.isRoot()
|
|
||||||
return s:TreeFileNode.GetRootLineNum()
|
|
||||||
endif
|
|
||||||
|
|
||||||
let totalLines = line("$")
|
|
||||||
|
|
||||||
"the path components we have matched so far
|
|
||||||
let pathcomponents = [substitute(b:NERDTreeRoot.path.str({'format': 'UI'}), '/ *$', '', '')]
|
|
||||||
"the index of the component we are searching for
|
|
||||||
let curPathComponent = 1
|
|
||||||
|
|
||||||
let fullpath = self.path.str({'format': 'UI'})
|
|
||||||
|
|
||||||
|
|
||||||
let lnum = s:TreeFileNode.GetRootLineNum()
|
|
||||||
while lnum > 0
|
|
||||||
let lnum = lnum + 1
|
|
||||||
"have we reached the bottom of the tree?
|
|
||||||
if lnum ==# totalLines+1
|
|
||||||
return -1
|
|
||||||
endif
|
|
||||||
|
|
||||||
let curLine = getline(lnum)
|
|
||||||
|
|
||||||
let indent = nerdtree#indentLevelFor(curLine)
|
|
||||||
if indent ==# curPathComponent
|
|
||||||
let curLine = nerdtree#stripMarkupFromLine(curLine, 1)
|
|
||||||
|
|
||||||
let curPath = join(pathcomponents, '/') . '/' . curLine
|
|
||||||
if stridx(fullpath, curPath, 0) ==# 0
|
|
||||||
if fullpath ==# curPath || strpart(fullpath, len(curPath)-1,1) ==# '/'
|
|
||||||
let curLine = substitute(curLine, '/ *$', '', '')
|
|
||||||
call add(pathcomponents, curLine)
|
|
||||||
let curPathComponent = curPathComponent + 1
|
|
||||||
|
|
||||||
if fullpath ==# curPath
|
|
||||||
return lnum
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
return -1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.GetRootForTab(){{{1
|
|
||||||
"get the root node for this tab
|
|
||||||
function! s:TreeFileNode.GetRootForTab()
|
|
||||||
if nerdtree#treeExistsForTab()
|
|
||||||
return getbufvar(t:NERDTreeBufName, 'NERDTreeRoot')
|
|
||||||
end
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.GetRootLineNum(){{{1
|
|
||||||
"gets the line number of the root node
|
|
||||||
function! s:TreeFileNode.GetRootLineNum()
|
|
||||||
let rootLine = 1
|
|
||||||
while getline(rootLine) !~# '^\(/\|<\)'
|
|
||||||
let rootLine = rootLine + 1
|
|
||||||
endwhile
|
|
||||||
return rootLine
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.GetSelected() {{{1
|
|
||||||
"gets the treenode that the cursor is currently over
|
|
||||||
function! s:TreeFileNode.GetSelected()
|
|
||||||
try
|
|
||||||
let path = nerdtree#getPath(line("."))
|
|
||||||
if path ==# {}
|
|
||||||
return {}
|
|
||||||
endif
|
|
||||||
return b:NERDTreeRoot.findNode(path)
|
|
||||||
catch /^NERDTree/
|
|
||||||
return {}
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.isVisible() {{{1
|
|
||||||
"returns 1 if this node should be visible according to the tree filters and
|
|
||||||
"hidden file filters (and their on/off status)
|
|
||||||
function! s:TreeFileNode.isVisible()
|
|
||||||
return !self.path.ignore()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.isRoot() {{{1
|
|
||||||
"returns 1 if this node is b:NERDTreeRoot
|
|
||||||
function! s:TreeFileNode.isRoot()
|
|
||||||
if !nerdtree#treeExistsForBuf()
|
|
||||||
throw "NERDTree.NoTreeError: No tree exists for the current buffer"
|
|
||||||
endif
|
|
||||||
|
|
||||||
return self.equals(b:NERDTreeRoot)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.makeRoot() {{{1
|
|
||||||
"Make this node the root of the tree
|
|
||||||
function! s:TreeFileNode.makeRoot()
|
|
||||||
if self.path.isDirectory
|
|
||||||
let b:NERDTreeRoot = self
|
|
||||||
else
|
|
||||||
call self.cacheParent()
|
|
||||||
let b:NERDTreeRoot = self.parent
|
|
||||||
endif
|
|
||||||
|
|
||||||
call b:NERDTreeRoot.open()
|
|
||||||
|
|
||||||
"change dir to the dir of the new root if instructed to
|
|
||||||
if g:NERDTreeChDirMode ==# 2
|
|
||||||
exec "cd " . b:NERDTreeRoot.path.str({'format': 'Edit'})
|
|
||||||
endif
|
|
||||||
|
|
||||||
silent doautocmd User NERDTreeNewRoot
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.New(path) {{{1
|
|
||||||
"Returns a new TreeNode object with the given path and parent
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"path: a path object representing the full filesystem path to the file/dir that the node represents
|
|
||||||
function! s:TreeFileNode.New(path)
|
|
||||||
if a:path.isDirectory
|
|
||||||
return g:NERDTreeDirNode.New(a:path)
|
|
||||||
else
|
|
||||||
let newTreeNode = copy(self)
|
|
||||||
let newTreeNode.path = a:path
|
|
||||||
let newTreeNode.parent = {}
|
|
||||||
return newTreeNode
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.open() {{{1
|
|
||||||
function! s:TreeFileNode.open(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
let opener = g:NERDTreeOpener.New(self.path, opts)
|
|
||||||
call opener.open(self)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.openSplit() {{{1
|
|
||||||
"Open this node in a new window
|
|
||||||
function! s:TreeFileNode.openSplit()
|
|
||||||
call nerdtree#deprecated('TreeFileNode.openSplit', 'is deprecated, use .open() instead.')
|
|
||||||
call self.open({'where': 'h'})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.openVSplit() {{{1
|
|
||||||
"Open this node in a new vertical window
|
|
||||||
function! s:TreeFileNode.openVSplit()
|
|
||||||
call nerdtree#deprecated('TreeFileNode.openVSplit', 'is deprecated, use .open() instead.')
|
|
||||||
call self.open({'where': 'v'})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.openInNewTab(options) {{{1
|
|
||||||
function! s:TreeFileNode.openInNewTab(options)
|
|
||||||
echomsg 'TreeFileNode.openInNewTab is deprecated'
|
|
||||||
call self.open(extend({'where': 't'}, a:options))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.putCursorHere(isJump, recurseUpward){{{1
|
|
||||||
"Places the cursor on the line number this node is rendered on
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"isJump: 1 if this cursor movement should be counted as a jump by vim
|
|
||||||
"recurseUpward: try to put the cursor on the parent if the this node isnt
|
|
||||||
"visible
|
|
||||||
function! s:TreeFileNode.putCursorHere(isJump, recurseUpward)
|
|
||||||
let ln = self.getLineNum()
|
|
||||||
if ln != -1
|
|
||||||
if a:isJump
|
|
||||||
mark '
|
|
||||||
endif
|
|
||||||
call cursor(ln, col("."))
|
|
||||||
else
|
|
||||||
if a:recurseUpward
|
|
||||||
let node = self
|
|
||||||
while node != {} && node.getLineNum() ==# -1
|
|
||||||
let node = node.parent
|
|
||||||
call node.open()
|
|
||||||
endwhile
|
|
||||||
call nerdtree#renderView()
|
|
||||||
call node.putCursorHere(a:isJump, 0)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.refresh() {{{1
|
|
||||||
function! s:TreeFileNode.refresh()
|
|
||||||
call self.path.refresh()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.rename() {{{1
|
|
||||||
"Calls the rename method for this nodes path obj
|
|
||||||
function! s:TreeFileNode.rename(newName)
|
|
||||||
let newName = substitute(a:newName, '\(\\\|\/\)$', '', '')
|
|
||||||
call self.path.rename(newName)
|
|
||||||
call self.parent.removeChild(self)
|
|
||||||
|
|
||||||
let parentPath = self.path.getParent()
|
|
||||||
let newParent = b:NERDTreeRoot.findNode(parentPath)
|
|
||||||
|
|
||||||
if newParent != {}
|
|
||||||
call newParent.createChild(self.path, 1)
|
|
||||||
call newParent.refresh()
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: TreeFileNode.renderToString {{{1
|
|
||||||
"returns a string representation for this tree to be rendered in the view
|
|
||||||
function! s:TreeFileNode.renderToString()
|
|
||||||
return self._renderToString(0, 0, [], self.getChildCount() ==# 1)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"Args:
|
|
||||||
"depth: the current depth in the tree for this call
|
|
||||||
"drawText: 1 if we should actually draw the line for this node (if 0 then the
|
|
||||||
"child nodes are rendered only)
|
|
||||||
"vertMap: a binary array that indicates whether a vertical bar should be draw
|
|
||||||
"for each depth in the tree
|
|
||||||
"isLastChild:true if this curNode is the last child of its parent
|
|
||||||
function! s:TreeFileNode._renderToString(depth, drawText, vertMap, isLastChild)
|
|
||||||
let output = ""
|
|
||||||
if a:drawText ==# 1
|
|
||||||
|
|
||||||
let treeParts = ''
|
|
||||||
|
|
||||||
"get all the leading spaces and vertical tree parts for this line
|
|
||||||
if a:depth > 1
|
|
||||||
for j in a:vertMap[0:-2]
|
|
||||||
if g:NERDTreeDirArrows
|
|
||||||
let treeParts = treeParts . ' '
|
|
||||||
else
|
|
||||||
if j ==# 1
|
|
||||||
let treeParts = treeParts . '| '
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . ' '
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
|
|
||||||
"get the last vertical tree part for this line which will be different
|
|
||||||
"if this node is the last child of its parent
|
|
||||||
if !g:NERDTreeDirArrows
|
|
||||||
if a:isLastChild
|
|
||||||
let treeParts = treeParts . '`'
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . '|'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
"smack the appropriate dir/file symbol on the line before the file/dir
|
|
||||||
"name itself
|
|
||||||
if self.path.isDirectory
|
|
||||||
if self.isOpen
|
|
||||||
if g:NERDTreeDirArrows
|
|
||||||
let treeParts = treeParts . '▾ '
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . '~'
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if g:NERDTreeDirArrows
|
|
||||||
let treeParts = treeParts . '▸ '
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . '+'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
if g:NERDTreeDirArrows
|
|
||||||
let treeParts = treeParts . ' '
|
|
||||||
else
|
|
||||||
let treeParts = treeParts . '-'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
let line = treeParts . self.displayString()
|
|
||||||
|
|
||||||
let output = output . line . "\n"
|
|
||||||
endif
|
|
||||||
|
|
||||||
"if the node is an open dir, draw its children
|
|
||||||
if self.path.isDirectory ==# 1 && self.isOpen ==# 1
|
|
||||||
|
|
||||||
let childNodesToDraw = self.getVisibleChildren()
|
|
||||||
if len(childNodesToDraw) > 0
|
|
||||||
|
|
||||||
"draw all the nodes children except the last
|
|
||||||
let lastIndx = len(childNodesToDraw)-1
|
|
||||||
if lastIndx > 0
|
|
||||||
for i in childNodesToDraw[0:lastIndx-1]
|
|
||||||
let output = output . i._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 1), 0)
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
|
|
||||||
"draw the last child, indicating that it IS the last
|
|
||||||
let output = output . childNodesToDraw[lastIndx]._renderToString(a:depth + 1, 1, add(copy(a:vertMap), 0), 1)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
return output
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
" ============================================================================
|
|
||||||
" File: exec_menuitem.vim
|
|
||||||
" Description: plugin for NERD Tree that provides an execute file menu item
|
|
||||||
" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
|
|
||||||
" Last Change: 22 July, 2009
|
|
||||||
" License: This program is free software. It comes without any warranty,
|
|
||||||
" to the extent permitted by applicable law. You can redistribute
|
|
||||||
" it and/or modify it under the terms of the Do What The Fuck You
|
|
||||||
" Want To Public License, Version 2, as published by Sam Hocevar.
|
|
||||||
" See http://sam.zoy.org/wtfpl/COPYING for more details.
|
|
||||||
"
|
|
||||||
" ============================================================================
|
|
||||||
if exists("g:loaded_nerdtree_exec_menuitem")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_nerdtree_exec_menuitem = 1
|
|
||||||
|
|
||||||
call NERDTreeAddMenuItem({
|
|
||||||
\ 'text': '(!)Execute file',
|
|
||||||
\ 'shortcut': '!',
|
|
||||||
\ 'callback': 'NERDTreeExecFile',
|
|
||||||
\ 'isActiveCallback': 'NERDTreeExecFileActive' })
|
|
||||||
|
|
||||||
function! NERDTreeExecFileActive()
|
|
||||||
let node = g:NERDTreeFileNode.GetSelected()
|
|
||||||
return !node.path.isDirectory && node.path.isExecutable
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeExecFile()
|
|
||||||
let treenode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
echo "==========================================================\n"
|
|
||||||
echo "Complete the command to execute (add arguments etc):\n"
|
|
||||||
let cmd = treenode.path.str({'escape': 1})
|
|
||||||
let cmd = input(':!', cmd . ' ')
|
|
||||||
|
|
||||||
if cmd != ''
|
|
||||||
exec ':!' . cmd
|
|
||||||
else
|
|
||||||
echo "Aborted"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
@ -1,262 +0,0 @@
|
||||||
" ============================================================================
|
|
||||||
" File: fs_menu.vim
|
|
||||||
" Description: plugin for the NERD Tree that provides a file system menu
|
|
||||||
" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
|
|
||||||
" Last Change: 17 July, 2009
|
|
||||||
" License: This program is free software. It comes without any warranty,
|
|
||||||
" to the extent permitted by applicable law. You can redistribute
|
|
||||||
" it and/or modify it under the terms of the Do What The Fuck You
|
|
||||||
" Want To Public License, Version 2, as published by Sam Hocevar.
|
|
||||||
" See http://sam.zoy.org/wtfpl/COPYING for more details.
|
|
||||||
"
|
|
||||||
" ============================================================================
|
|
||||||
if exists("g:loaded_nerdtree_fs_menu")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_nerdtree_fs_menu = 1
|
|
||||||
|
|
||||||
"Automatically delete the buffer after deleting or renaming a file
|
|
||||||
if !exists("g:NERDTreeAutoDeleteBuffer")
|
|
||||||
let g:NERDTreeAutoDeleteBuffer = 0
|
|
||||||
endif
|
|
||||||
|
|
||||||
call NERDTreeAddMenuItem({'text': '(a)dd a childnode', 'shortcut': 'a', 'callback': 'NERDTreeAddNode'})
|
|
||||||
call NERDTreeAddMenuItem({'text': '(m)ove the current node', 'shortcut': 'm', 'callback': 'NERDTreeMoveNode'})
|
|
||||||
call NERDTreeAddMenuItem({'text': '(d)elete the current node', 'shortcut': 'd', 'callback': 'NERDTreeDeleteNode'})
|
|
||||||
|
|
||||||
if has("gui_mac") || has("gui_macvim")
|
|
||||||
call NERDTreeAddMenuItem({'text': '(r)eveal in Finder the current node', 'shortcut': 'r', 'callback': 'NERDTreeRevealInFinder'})
|
|
||||||
call NERDTreeAddMenuItem({'text': '(o)pen the current node with system editor', 'shortcut': 'o', 'callback': 'NERDTreeExecuteFile'})
|
|
||||||
call NERDTreeAddMenuItem({'text': '(q)uicklook the current node', 'shortcut': 'q', 'callback': 'NERDTreeQuickLook'})
|
|
||||||
endif
|
|
||||||
|
|
||||||
if g:NERDTreePath.CopyingSupported()
|
|
||||||
call NERDTreeAddMenuItem({'text': '(c)opy the current node', 'shortcut': 'c', 'callback': 'NERDTreeCopyNode'})
|
|
||||||
endif
|
|
||||||
|
|
||||||
"FUNCTION: s:echo(msg){{{1
|
|
||||||
function! s:echo(msg)
|
|
||||||
redraw
|
|
||||||
echomsg "NERDTree: " . a:msg
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:echoWarning(msg){{{1
|
|
||||||
function! s:echoWarning(msg)
|
|
||||||
echohl warningmsg
|
|
||||||
call s:echo(a:msg)
|
|
||||||
echohl normal
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:promptToDelBuffer(bufnum, msg){{{1
|
|
||||||
"prints out the given msg and, if the user responds by pushing 'y' then the
|
|
||||||
"buffer with the given bufnum is deleted
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"bufnum: the buffer that may be deleted
|
|
||||||
"msg: a message that will be echoed to the user asking them if they wish to
|
|
||||||
" del the buffer
|
|
||||||
function! s:promptToDelBuffer(bufnum, msg)
|
|
||||||
echo a:msg
|
|
||||||
if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
|
|
||||||
" 1. ensure that all windows which display the just deleted filename
|
|
||||||
" now display an empty buffer (so a layout is preserved).
|
|
||||||
" Is not it better to close single tabs with this file only ?
|
|
||||||
let s:originalTabNumber = tabpagenr()
|
|
||||||
let s:originalWindowNumber = winnr()
|
|
||||||
exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':enew! ' | endif"
|
|
||||||
exec "tabnext " . s:originalTabNumber
|
|
||||||
exec s:originalWindowNumber . "wincmd w"
|
|
||||||
" 3. We don't need a previous buffer anymore
|
|
||||||
exec "bwipeout! " . a:bufnum
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: s:promptToRenameBuffer(bufnum, msg){{{1
|
|
||||||
"prints out the given msg and, if the user responds by pushing 'y' then the
|
|
||||||
"buffer with the given bufnum is replaced with a new one
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"bufnum: the buffer that may be deleted
|
|
||||||
"msg: a message that will be echoed to the user asking them if they wish to
|
|
||||||
" del the buffer
|
|
||||||
function! s:promptToRenameBuffer(bufnum, msg, newFileName)
|
|
||||||
echo a:msg
|
|
||||||
if g:NERDTreeAutoDeleteBuffer || nr2char(getchar()) ==# 'y'
|
|
||||||
" 1. ensure that a new buffer is loaded
|
|
||||||
exec "badd " . a:newFileName
|
|
||||||
" 2. ensure that all windows which display the just deleted filename
|
|
||||||
" display a buffer for a new filename.
|
|
||||||
let s:originalTabNumber = tabpagenr()
|
|
||||||
let s:originalWindowNumber = winnr()
|
|
||||||
exec "tabdo windo if winbufnr(0) == " . a:bufnum . " | exec ':e! " . a:newFileName . "' | endif"
|
|
||||||
exec "tabnext " . s:originalTabNumber
|
|
||||||
exec s:originalWindowNumber . "wincmd w"
|
|
||||||
" 3. We don't need a previous buffer anymore
|
|
||||||
exec "bwipeout! " . a:bufnum
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
"FUNCTION: NERDTreeAddNode(){{{1
|
|
||||||
function! NERDTreeAddNode()
|
|
||||||
let curDirNode = g:NERDTreeDirNode.GetSelected()
|
|
||||||
|
|
||||||
let newNodeName = input("Add a childnode\n".
|
|
||||||
\ "==========================================================\n".
|
|
||||||
\ "Enter the dir/file name to be created. Dirs end with a '/'\n" .
|
|
||||||
\ "", curDirNode.path.str() . g:NERDTreePath.Slash(), "file")
|
|
||||||
|
|
||||||
if newNodeName ==# ''
|
|
||||||
call s:echo("Node Creation Aborted.")
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
try
|
|
||||||
let newPath = g:NERDTreePath.Create(newNodeName)
|
|
||||||
let parentNode = b:NERDTreeRoot.findNode(newPath.getParent())
|
|
||||||
|
|
||||||
let newTreeNode = g:NERDTreeFileNode.New(newPath)
|
|
||||||
if parentNode.isOpen || !empty(parentNode.children)
|
|
||||||
call parentNode.addChild(newTreeNode, 1)
|
|
||||||
call NERDTreeRender()
|
|
||||||
call newTreeNode.putCursorHere(1, 0)
|
|
||||||
endif
|
|
||||||
catch /^NERDTree/
|
|
||||||
call s:echoWarning("Node Not Created.")
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"FUNCTION: NERDTreeMoveNode(){{{1
|
|
||||||
function! NERDTreeMoveNode()
|
|
||||||
let curNode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
let newNodePath = input("Rename the current node\n" .
|
|
||||||
\ "==========================================================\n" .
|
|
||||||
\ "Enter the new path for the node: \n" .
|
|
||||||
\ "", curNode.path.str(), "file")
|
|
||||||
|
|
||||||
if newNodePath ==# ''
|
|
||||||
call s:echo("Node Renaming Aborted.")
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
|
|
||||||
try
|
|
||||||
let bufnum = bufnr(curNode.path.str())
|
|
||||||
|
|
||||||
call curNode.rename(newNodePath)
|
|
||||||
call NERDTreeRender()
|
|
||||||
|
|
||||||
"if the node is open in a buffer, ask the user if they want to
|
|
||||||
"close that buffer
|
|
||||||
if bufnum != -1
|
|
||||||
let prompt = "\nNode renamed.\n\nThe old file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Replace this buffer with a new file? (yN)"
|
|
||||||
call s:promptToRenameBuffer(bufnum, prompt, newNodePath)
|
|
||||||
endif
|
|
||||||
|
|
||||||
call curNode.putCursorHere(1, 0)
|
|
||||||
|
|
||||||
redraw
|
|
||||||
catch /^NERDTree/
|
|
||||||
call s:echoWarning("Node Not Renamed.")
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: NERDTreeDeleteNode() {{{1
|
|
||||||
function! NERDTreeDeleteNode()
|
|
||||||
let currentNode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
let confirmed = 0
|
|
||||||
|
|
||||||
if currentNode.path.isDirectory
|
|
||||||
let choice =input("Delete the current node\n" .
|
|
||||||
\ "==========================================================\n" .
|
|
||||||
\ "STOP! To delete this entire directory, type 'yes'\n" .
|
|
||||||
\ "" . currentNode.path.str() . ": ")
|
|
||||||
let confirmed = choice ==# 'yes'
|
|
||||||
else
|
|
||||||
echo "Delete the current node\n" .
|
|
||||||
\ "==========================================================\n".
|
|
||||||
\ "Are you sure you wish to delete the node:\n" .
|
|
||||||
\ "" . currentNode.path.str() . " (yN):"
|
|
||||||
let choice = nr2char(getchar())
|
|
||||||
let confirmed = choice ==# 'y'
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
if confirmed
|
|
||||||
try
|
|
||||||
call currentNode.delete()
|
|
||||||
call NERDTreeRender()
|
|
||||||
|
|
||||||
"if the node is open in a buffer, ask the user if they want to
|
|
||||||
"close that buffer
|
|
||||||
let bufnum = bufnr(currentNode.path.str())
|
|
||||||
if buflisted(bufnum)
|
|
||||||
let prompt = "\nNode deleted.\n\nThe file is open in buffer ". bufnum . (bufwinnr(bufnum) ==# -1 ? " (hidden)" : "") .". Delete this buffer? (yN)"
|
|
||||||
call s:promptToDelBuffer(bufnum, prompt)
|
|
||||||
endif
|
|
||||||
|
|
||||||
redraw
|
|
||||||
catch /^NERDTree/
|
|
||||||
call s:echoWarning("Could not remove node")
|
|
||||||
endtry
|
|
||||||
else
|
|
||||||
call s:echo("delete aborted")
|
|
||||||
endif
|
|
||||||
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" FUNCTION: NERDTreeCopyNode() {{{1
|
|
||||||
function! NERDTreeCopyNode()
|
|
||||||
let currentNode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
let newNodePath = input("Copy the current node\n" .
|
|
||||||
\ "==========================================================\n" .
|
|
||||||
\ "Enter the new path to copy the node to: \n" .
|
|
||||||
\ "", currentNode.path.str(), "file")
|
|
||||||
|
|
||||||
if newNodePath != ""
|
|
||||||
"strip trailing slash
|
|
||||||
let newNodePath = substitute(newNodePath, '\/$', '', '')
|
|
||||||
|
|
||||||
let confirmed = 1
|
|
||||||
if currentNode.path.copyingWillOverwrite(newNodePath)
|
|
||||||
call s:echo("Warning: copying may overwrite files! Continue? (yN)")
|
|
||||||
let choice = nr2char(getchar())
|
|
||||||
let confirmed = choice ==# 'y'
|
|
||||||
endif
|
|
||||||
|
|
||||||
if confirmed
|
|
||||||
try
|
|
||||||
let newNode = currentNode.copy(newNodePath)
|
|
||||||
if !empty(newNode)
|
|
||||||
call NERDTreeRender()
|
|
||||||
call newNode.putCursorHere(0, 0)
|
|
||||||
endif
|
|
||||||
catch /^NERDTree/
|
|
||||||
call s:echoWarning("Could not copy node")
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
call s:echo("Copy aborted.")
|
|
||||||
endif
|
|
||||||
redraw
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeQuickLook()
|
|
||||||
let treenode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
if treenode != {}
|
|
||||||
call system("qlmanage -p 2>/dev/null '" . treenode.path.str() . "'")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeRevealInFinder()
|
|
||||||
let treenode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
if treenode != {}
|
|
||||||
let x = system("open -R '" . treenode.path.str() . "'")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeExecuteFile()
|
|
||||||
let treenode = g:NERDTreeFileNode.GetSelected()
|
|
||||||
if treenode != {}
|
|
||||||
let x = system("open '" . treenode.path.str() . "'")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,210 +0,0 @@
|
||||||
" ============================================================================
|
|
||||||
" File: NERD_tree.vim
|
|
||||||
" Description: vim global plugin that provides a nice tree explorer
|
|
||||||
" Maintainer: Martin Grenfell <martin.grenfell at gmail dot com>
|
|
||||||
" Last Change: 28 December, 2011
|
|
||||||
" License: This program is free software. It comes without any warranty,
|
|
||||||
" to the extent permitted by applicable law. You can redistribute
|
|
||||||
" it and/or modify it under the terms of the Do What The Fuck You
|
|
||||||
" Want To Public License, Version 2, as published by Sam Hocevar.
|
|
||||||
" See http://sam.zoy.org/wtfpl/COPYING for more details.
|
|
||||||
"
|
|
||||||
" ============================================================================
|
|
||||||
"
|
|
||||||
" SECTION: Script init stuff {{{1
|
|
||||||
"============================================================
|
|
||||||
if exists("loaded_nerd_tree")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
if v:version < 700
|
|
||||||
echoerr "NERDTree: this plugin requires vim >= 7. DOWNLOAD IT! You'll thank me later!"
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let loaded_nerd_tree = 1
|
|
||||||
|
|
||||||
"for line continuation - i.e dont want C in &cpo
|
|
||||||
let s:old_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
"Function: s:initVariable() function {{{2
|
|
||||||
"This function is used to initialise a given variable to a given value. The
|
|
||||||
"variable is only initialised if it does not exist prior
|
|
||||||
"
|
|
||||||
"Args:
|
|
||||||
"var: the name of the var to be initialised
|
|
||||||
"value: the value to initialise var to
|
|
||||||
"
|
|
||||||
"Returns:
|
|
||||||
"1 if the var is set, 0 otherwise
|
|
||||||
function! s:initVariable(var, value)
|
|
||||||
if !exists(a:var)
|
|
||||||
exec 'let ' . a:var . ' = ' . "'" . substitute(a:value, "'", "''", "g") . "'"
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"SECTION: Init variable calls and other random constants {{{2
|
|
||||||
call s:initVariable("g:NERDChristmasTree", 1)
|
|
||||||
call s:initVariable("g:NERDTreeAutoCenter", 1)
|
|
||||||
call s:initVariable("g:NERDTreeAutoCenterThreshold", 3)
|
|
||||||
call s:initVariable("g:NERDTreeCaseSensitiveSort", 0)
|
|
||||||
call s:initVariable("g:NERDTreeChDirMode", 0)
|
|
||||||
call s:initVariable("g:NERDTreeMinimalUI", 0)
|
|
||||||
if !exists("g:NERDTreeIgnore")
|
|
||||||
let g:NERDTreeIgnore = ['\~$']
|
|
||||||
endif
|
|
||||||
call s:initVariable("g:NERDTreeBookmarksFile", expand('$HOME') . '/.NERDTreeBookmarks')
|
|
||||||
call s:initVariable("g:NERDTreeHighlightCursorline", 1)
|
|
||||||
call s:initVariable("g:NERDTreeHijackNetrw", 1)
|
|
||||||
call s:initVariable("g:NERDTreeMouseMode", 1)
|
|
||||||
call s:initVariable("g:NERDTreeNotificationThreshold", 100)
|
|
||||||
call s:initVariable("g:NERDTreeQuitOnOpen", 0)
|
|
||||||
call s:initVariable("g:NERDTreeShowBookmarks", 0)
|
|
||||||
call s:initVariable("g:NERDTreeShowFiles", 1)
|
|
||||||
call s:initVariable("g:NERDTreeShowHidden", 0)
|
|
||||||
call s:initVariable("g:NERDTreeShowLineNumbers", 0)
|
|
||||||
call s:initVariable("g:NERDTreeSortDirs", 1)
|
|
||||||
call s:initVariable("g:NERDTreeDirArrows", !nerdtree#runningWindows())
|
|
||||||
call s:initVariable("g:NERDTreeCasadeOpenSingleChildDir", 1)
|
|
||||||
|
|
||||||
if !exists("g:NERDTreeSortOrder")
|
|
||||||
let g:NERDTreeSortOrder = ['\/$', '*', '\.swp$', '\.bak$', '\~$']
|
|
||||||
else
|
|
||||||
"if there isnt a * in the sort sequence then add one
|
|
||||||
if count(g:NERDTreeSortOrder, '*') < 1
|
|
||||||
call add(g:NERDTreeSortOrder, '*')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !exists('g:NERDTreeStatusline')
|
|
||||||
|
|
||||||
"the exists() crap here is a hack to stop vim spazzing out when
|
|
||||||
"loading a session that was created with an open nerd tree. It spazzes
|
|
||||||
"because it doesnt store b:NERDTreeRoot (its a b: var, and its a hash)
|
|
||||||
let g:NERDTreeStatusline = "%{exists('b:NERDTreeRoot')?b:NERDTreeRoot.path.str():''}"
|
|
||||||
|
|
||||||
endif
|
|
||||||
call s:initVariable("g:NERDTreeWinPos", "left")
|
|
||||||
call s:initVariable("g:NERDTreeWinSize", 31)
|
|
||||||
|
|
||||||
"init the shell commands that will be used to copy nodes, and remove dir trees
|
|
||||||
"
|
|
||||||
"Note: the space after the command is important
|
|
||||||
if nerdtree#runningWindows()
|
|
||||||
call s:initVariable("g:NERDTreeRemoveDirCmd", 'rmdir /s /q ')
|
|
||||||
else
|
|
||||||
call s:initVariable("g:NERDTreeRemoveDirCmd", 'rm -rf ')
|
|
||||||
call s:initVariable("g:NERDTreeCopyCmd", 'cp -r ')
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
"SECTION: Init variable calls for key mappings {{{2
|
|
||||||
call s:initVariable("g:NERDTreeMapActivateNode", "o")
|
|
||||||
call s:initVariable("g:NERDTreeMapChangeRoot", "C")
|
|
||||||
call s:initVariable("g:NERDTreeMapChdir", "cd")
|
|
||||||
call s:initVariable("g:NERDTreeMapCloseChildren", "X")
|
|
||||||
call s:initVariable("g:NERDTreeMapCloseDir", "x")
|
|
||||||
call s:initVariable("g:NERDTreeMapDeleteBookmark", "D")
|
|
||||||
call s:initVariable("g:NERDTreeMapMenu", "m")
|
|
||||||
call s:initVariable("g:NERDTreeMapHelp", "?")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpFirstChild", "K")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpLastChild", "J")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpNextSibling", "<C-j>")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpParent", "p")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpPrevSibling", "<C-k>")
|
|
||||||
call s:initVariable("g:NERDTreeMapJumpRoot", "P")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenExpl", "e")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenInTab", "t")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenInTabSilent", "T")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenRecursively", "O")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenSplit", "i")
|
|
||||||
call s:initVariable("g:NERDTreeMapOpenVSplit", "s")
|
|
||||||
call s:initVariable("g:NERDTreeMapPreview", "g" . NERDTreeMapActivateNode)
|
|
||||||
call s:initVariable("g:NERDTreeMapPreviewSplit", "g" . NERDTreeMapOpenSplit)
|
|
||||||
call s:initVariable("g:NERDTreeMapPreviewVSplit", "g" . NERDTreeMapOpenVSplit)
|
|
||||||
call s:initVariable("g:NERDTreeMapQuit", "q")
|
|
||||||
call s:initVariable("g:NERDTreeMapRefresh", "r")
|
|
||||||
call s:initVariable("g:NERDTreeMapRefreshRoot", "R")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleBookmarks", "B")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleFiles", "F")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleFilters", "f")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleHidden", "I")
|
|
||||||
call s:initVariable("g:NERDTreeMapToggleZoom", "A")
|
|
||||||
call s:initVariable("g:NERDTreeMapUpdir", "u")
|
|
||||||
call s:initVariable("g:NERDTreeMapUpdirKeepOpen", "U")
|
|
||||||
call s:initVariable("g:NERDTreeMapCWD", "CD")
|
|
||||||
|
|
||||||
"SECTION: Load class files{{{2
|
|
||||||
call nerdtree#loadClassFiles()
|
|
||||||
|
|
||||||
" SECTION: Commands {{{1
|
|
||||||
"============================================================
|
|
||||||
"init the command that users start the nerd tree with
|
|
||||||
command! -n=? -complete=dir -bar NERDTree :call g:NERDTreeCreator.CreatePrimary('<args>')
|
|
||||||
command! -n=? -complete=dir -bar NERDTreeToggle :call g:NERDTreeCreator.TogglePrimary('<args>')
|
|
||||||
command! -n=0 -bar NERDTreeClose :call nerdtree#closeTreeIfOpen()
|
|
||||||
command! -n=1 -complete=customlist,nerdtree#completeBookmarks -bar NERDTreeFromBookmark call g:NERDTreeCreator.CreatePrimary('<args>')
|
|
||||||
command! -n=0 -bar NERDTreeMirror call g:NERDTreeCreator.CreateMirror()
|
|
||||||
command! -n=0 -bar NERDTreeFind call nerdtree#findAndRevealPath()
|
|
||||||
command! -n=0 -bar NERDTreeFocus call NERDTreeFocus()
|
|
||||||
command! -n=0 -bar NERDTreeCWD call NERDTreeCWD()
|
|
||||||
" SECTION: Auto commands {{{1
|
|
||||||
"============================================================
|
|
||||||
augroup NERDTree
|
|
||||||
"Save the cursor position whenever we close the nerd tree
|
|
||||||
exec "autocmd BufWinLeave ". g:NERDTreeCreator.BufNamePrefix() ."* call nerdtree#saveScreenState()"
|
|
||||||
|
|
||||||
"disallow insert mode in the NERDTree
|
|
||||||
exec "autocmd BufEnter ". g:NERDTreeCreator.BufNamePrefix() ."* stopinsert"
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
if g:NERDTreeHijackNetrw
|
|
||||||
augroup NERDTreeHijackNetrw
|
|
||||||
autocmd VimEnter * silent! autocmd! FileExplorer
|
|
||||||
au BufEnter,VimEnter * call nerdtree#checkForBrowse(expand("<amatch>"))
|
|
||||||
augroup END
|
|
||||||
endif
|
|
||||||
|
|
||||||
" SECTION: Public API {{{1
|
|
||||||
"============================================================
|
|
||||||
function! NERDTreeAddMenuItem(options)
|
|
||||||
call g:NERDTreeMenuItem.Create(a:options)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeAddMenuSeparator(...)
|
|
||||||
let opts = a:0 ? a:1 : {}
|
|
||||||
call g:NERDTreeMenuItem.CreateSeparator(opts)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeAddSubmenu(options)
|
|
||||||
return g:NERDTreeMenuItem.Create(a:options)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeAddKeyMap(options)
|
|
||||||
call g:NERDTreeKeyMap.Create(a:options)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeRender()
|
|
||||||
call nerdtree#renderView()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeFocus()
|
|
||||||
if nerdtree#isTreeOpen()
|
|
||||||
call nerdtree#putCursorInTreeWin()
|
|
||||||
else
|
|
||||||
call g:NERDTreeCreator.TogglePrimary("")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! NERDTreeCWD()
|
|
||||||
call NERDTreeFocus()
|
|
||||||
call nerdtree#chRootCwd()
|
|
||||||
endfunction
|
|
||||||
" SECTION: Post Source Actions {{{1
|
|
||||||
call nerdtree#postSourceActions()
|
|
||||||
|
|
||||||
"reset &cpo back to users setting
|
|
||||||
let &cpo = s:old_cpo
|
|
||||||
|
|
||||||
" vim: set sw=4 sts=4 et fdm=marker:
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
let s:tree_up_dir_line = '.. (up a dir)'
|
|
||||||
"NERDTreeFlags are syntax items that should be invisible, but give clues as to
|
|
||||||
"how things should be highlighted
|
|
||||||
syn match NERDTreeFlag #\~#
|
|
||||||
syn match NERDTreeFlag #\[RO\]#
|
|
||||||
|
|
||||||
"highlighting for the .. (up dir) line at the top of the tree
|
|
||||||
execute "syn match NERDTreeUp #\\V". s:tree_up_dir_line ."#"
|
|
||||||
|
|
||||||
"highlighting for the ~/+ symbols for the directory nodes
|
|
||||||
syn match NERDTreeClosable #\~\<#
|
|
||||||
syn match NERDTreeClosable #\~\.#
|
|
||||||
syn match NERDTreeOpenable #+\<#
|
|
||||||
syn match NERDTreeOpenable #+\.#he=e-1
|
|
||||||
|
|
||||||
"highlighting for the tree structural parts
|
|
||||||
syn match NERDTreePart #|#
|
|
||||||
syn match NERDTreePart #`#
|
|
||||||
syn match NERDTreePartFile #[|`]-#hs=s+1 contains=NERDTreePart
|
|
||||||
|
|
||||||
"quickhelp syntax elements
|
|
||||||
syn match NERDTreeHelpKey #" \{1,2\}[^ ]*:#hs=s+2,he=e-1
|
|
||||||
syn match NERDTreeHelpKey #" \{1,2\}[^ ]*,#hs=s+2,he=e-1
|
|
||||||
syn match NERDTreeHelpTitle #" .*\~#hs=s+2,he=e-1 contains=NERDTreeFlag
|
|
||||||
syn match NERDTreeToggleOn #".*(on)#hs=e-2,he=e-1 contains=NERDTreeHelpKey
|
|
||||||
syn match NERDTreeToggleOff #".*(off)#hs=e-3,he=e-1 contains=NERDTreeHelpKey
|
|
||||||
syn match NERDTreeHelpCommand #" :.\{-}\>#hs=s+3
|
|
||||||
syn match NERDTreeHelp #^".*# contains=NERDTreeHelpKey,NERDTreeHelpTitle,NERDTreeFlag,NERDTreeToggleOff,NERDTreeToggleOn,NERDTreeHelpCommand
|
|
||||||
|
|
||||||
"highlighting for readonly files
|
|
||||||
syn match NERDTreeRO #.*\[RO\]#hs=s+2 contains=NERDTreeFlag,NERDTreeBookmark,NERDTreePart,NERDTreePartFile
|
|
||||||
|
|
||||||
"highlighting for sym links
|
|
||||||
syn match NERDTreeLink #[^-| `].* -> # contains=NERDTreeBookmark,NERDTreeOpenable,NERDTreeClosable,NERDTreeDirSlash
|
|
||||||
|
|
||||||
"highlighing for directory nodes and file nodes
|
|
||||||
syn match NERDTreeDirSlash #/#
|
|
||||||
syn match NERDTreeDir #[^-| `].*/# contains=NERDTreeLink,NERDTreeDirSlash,NERDTreeOpenable,NERDTreeClosable
|
|
||||||
syn match NERDTreeExecFile #[|` ].*\*\($\| \)# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark
|
|
||||||
syn match NERDTreeFile #|-.*# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile
|
|
||||||
syn match NERDTreeFile #`-.*# contains=NERDTreeLink,NERDTreePart,NERDTreeRO,NERDTreePartFile,NERDTreeBookmark,NERDTreeExecFile
|
|
||||||
syn match NERDTreeCWD #^[</].*$#
|
|
||||||
|
|
||||||
"highlighting for bookmarks
|
|
||||||
syn match NERDTreeBookmark # {.*}#hs=s+1
|
|
||||||
|
|
||||||
"highlighting for the bookmarks table
|
|
||||||
syn match NERDTreeBookmarksLeader #^>#
|
|
||||||
syn match NERDTreeBookmarksHeader #^>-\+Bookmarks-\+$# contains=NERDTreeBookmarksLeader
|
|
||||||
syn match NERDTreeBookmarkName #^>.\{-} #he=e-1 contains=NERDTreeBookmarksLeader
|
|
||||||
syn match NERDTreeBookmark #^>.*$# contains=NERDTreeBookmarksLeader,NERDTreeBookmarkName,NERDTreeBookmarksHeader
|
|
||||||
|
|
||||||
if exists("g:NERDChristmasTree") && g:NERDChristmasTree
|
|
||||||
hi def link NERDTreePart Special
|
|
||||||
hi def link NERDTreePartFile Type
|
|
||||||
hi def link NERDTreeFile Normal
|
|
||||||
hi def link NERDTreeExecFile Title
|
|
||||||
hi def link NERDTreeDirSlash Identifier
|
|
||||||
hi def link NERDTreeClosable Type
|
|
||||||
else
|
|
||||||
hi def link NERDTreePart Normal
|
|
||||||
hi def link NERDTreePartFile Normal
|
|
||||||
hi def link NERDTreeFile Normal
|
|
||||||
hi def link NERDTreeClosable Title
|
|
||||||
endif
|
|
||||||
|
|
||||||
hi def link NERDTreeBookmarksHeader statement
|
|
||||||
hi def link NERDTreeBookmarksLeader ignore
|
|
||||||
hi def link NERDTreeBookmarkName Identifier
|
|
||||||
hi def link NERDTreeBookmark normal
|
|
||||||
|
|
||||||
hi def link NERDTreeHelp String
|
|
||||||
hi def link NERDTreeHelpKey Identifier
|
|
||||||
hi def link NERDTreeHelpCommand Identifier
|
|
||||||
hi def link NERDTreeHelpTitle Macro
|
|
||||||
hi def link NERDTreeToggleOn Question
|
|
||||||
hi def link NERDTreeToggleOff WarningMsg
|
|
||||||
|
|
||||||
hi def link NERDTreeDir Directory
|
|
||||||
hi def link NERDTreeUp Directory
|
|
||||||
hi def link NERDTreeCWD Statement
|
|
||||||
hi def link NERDTreeLink Macro
|
|
||||||
hi def link NERDTreeOpenable Title
|
|
||||||
hi def link NERDTreeFlag ignore
|
|
||||||
hi def link NERDTreeRO WarningMsg
|
|
||||||
hi def link NERDTreeBookmark Statement
|
|
||||||
|
|
||||||
hi def link NERDTreeCurrentNode Search
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 53f319728a57caed6c7db0304b218d662a67981f
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 616daceb735771ed27535abe8a6e4907320f1e82
|
|
||||||
1
vim/bundle/vim-bundler/.gitignore
vendored
1
vim/bundle/vim-bundler/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
/doc/tags
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
See the contribution guidelines for
|
|
||||||
[rails.vim](https://github.com/tpope/vim-rails/blob/HEAD/CONTRIBUTING.markdown).
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
# bundler.vim
|
|
||||||
|
|
||||||
This is a lightweight bag of Vim goodies for
|
|
||||||
[Bundler](http://gembundler.com), best accompanied by
|
|
||||||
[rake.vim](https://github.com/tpope/vim-rake) and/or
|
|
||||||
[rails.vim](https://github.com/tpope/vim-rails). Features:
|
|
||||||
|
|
||||||
* `:Bundle`, which wraps `bundle`.
|
|
||||||
* An internalized version of `bundle open`: `:Bopen` (and `:Bsplit`,
|
|
||||||
`:Btabedit`, etc.).
|
|
||||||
* `'path'` and `'tags'` are automatically altered to include all gems
|
|
||||||
from your bundle. (Generate those tags with
|
|
||||||
[gem-ctags](https://github.com/tpope/gem-ctags)!)
|
|
||||||
* Highlight Bundler keywords in `Gemfile`.
|
|
||||||
* Support for `gf` in `Gemfile.lock`, plus syntax highlighting that
|
|
||||||
distinguishes between installed and missing gems.
|
|
||||||
|
|
||||||
## 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-bundler.git
|
|
||||||
|
|
||||||
Once help tags have been generated, you can view the manual with
|
|
||||||
`:help bundler`.
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
> I installed the plugin and started Vim. Why don't any of the commands
|
|
||||||
> exist?
|
|
||||||
|
|
||||||
This plugin cares about the current file, not the current working
|
|
||||||
directory. Edit a file that's covered by a `Gemfile`.
|
|
||||||
|
|
||||||
> I opened a new tab. Why don't any of the commands exist?
|
|
||||||
|
|
||||||
This plugin cares about the current file, not the current working
|
|
||||||
directory. Edit a file that's covered by a `Gemfile`.
|
|
||||||
|
|
||||||
## Self-Promotion
|
|
||||||
|
|
||||||
Like bundler.vim? Follow the repository on
|
|
||||||
[GitHub](https://github.com/tpope/vim-bundler) and vote for it on
|
|
||||||
[vim.org](http://www.vim.org/scripts/script.php?script_id=4280). 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`.
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
" Vim compiler file
|
|
||||||
|
|
||||||
if exists("current_compiler")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let current_compiler = "bundler"
|
|
||||||
|
|
||||||
let s:cpo_save = &cpo
|
|
||||||
set cpo-=C
|
|
||||||
|
|
||||||
CompilerSet makeprg=bundle
|
|
||||||
|
|
||||||
CompilerSet errorformat=
|
|
||||||
\%+E%f:%l:\ parse\ error,
|
|
||||||
\%W%f:%l:\ warning:\ %m,
|
|
||||||
\%E%f:%l:in\ %*[^:]:\ %m,
|
|
||||||
\%E%f:%l:\ %m,
|
|
||||||
\%-C%\tfrom\ %f:%l:in\ %.%#,
|
|
||||||
\%-Z%\tfrom\ %f:%l,
|
|
||||||
\%-Z%p^,
|
|
||||||
\%-G%.%#
|
|
||||||
|
|
||||||
let &cpo = s:cpo_save
|
|
||||||
unlet s:cpo_save
|
|
||||||
|
|
||||||
" vim: sw=2:
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
*bundler.txt* Support for Ruby's Bundler
|
|
||||||
|
|
||||||
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 *bundler*
|
|
||||||
|
|
||||||
This lightweight companion to rails.vim and rake.vim provides support for
|
|
||||||
Bundler. In addition to the below commands, it also syntax highlights
|
|
||||||
Gemfile and Gemfile.lock, and alters 'path' and 'tags' to include bundled
|
|
||||||
gems. I recommend gem-ctags for generating tags for your gems.
|
|
||||||
|
|
||||||
COMMANDS *bundler-commands*
|
|
||||||
|
|
||||||
*bundler-:Bundle*
|
|
||||||
:Bundle[!] [args] Invoke `bundle` via |:make|.
|
|
||||||
|
|
||||||
|
|
||||||
*bundler-:Bopen*
|
|
||||||
:Bopen[!] [gem] With no argument, edits the Gemfile. Otherwise,
|
|
||||||
effectively does a `bundle open` of a gem inside of
|
|
||||||
Vim, including an |:lcd| to the gem's root directory.
|
|
||||||
Add ! to discard the current buffer's changes.
|
|
||||||
|
|
||||||
*bundler-:Bedit*
|
|
||||||
:Bedit[!] [gem] Like |:Bopen|, but don't |:lcd| afterwards.
|
|
||||||
|
|
||||||
*bundler-:Bsplit*
|
|
||||||
:Bsplit[!] [gem] Like |:Bopen|, but horizontally split. Add ! to
|
|
||||||
suppress the |:lcd|.
|
|
||||||
|
|
||||||
*bundler-:Bvsplit*
|
|
||||||
:Bvsplit[!] [gem] Like |:Bopen|, but vertically split. Add ! to
|
|
||||||
suppress the |:lcd|.
|
|
||||||
|
|
||||||
*bundler-:Btabedit*
|
|
||||||
:Btabedit[!] [gem] Like |:Bopen|, but use a new tab. Add ! to
|
|
||||||
suppress the |:lcd|.
|
|
||||||
|
|
||||||
*bundler-:Bpedit*
|
|
||||||
:Bpedit[!] [gem] Like |:Bopen|, but use a preview window. Add ! to
|
|
||||||
suppress the |:lcd|.
|
|
||||||
|
|
||||||
API *bundler-api*
|
|
||||||
|
|
||||||
Use bundler#project(root) to retrieve an object for the project at the given
|
|
||||||
root path. If no path is given, the current buffer's project root is used.
|
|
||||||
An empty object is returned if no project is found. Use |empty()| to check
|
|
||||||
for that.
|
|
||||||
|
|
||||||
On the bundler#project() object, versions() returns a dictionary mapping
|
|
||||||
between gem names and their locked versions, paths() returns a dictionary
|
|
||||||
mapping between gem names and their installation path (omitting gems which
|
|
||||||
aren't installed), and has(gem) returns true if the given gem name is in the
|
|
||||||
bundle (regardless of whether or not it is installed).
|
|
||||||
|
|
||||||
The original data structures are returned for performance reasons. Do not
|
|
||||||
mutate.
|
|
||||||
|
|
||||||
ABOUT *bundler-about*
|
|
||||||
|
|
||||||
Grab the latest version or report a bug on GitHub:
|
|
||||||
|
|
||||||
http://github.com/tpope/vim-bundler
|
|
||||||
|
|
||||||
vim:tw=78:et:ft=help:norl:
|
|
||||||
|
|
@ -1,581 +0,0 @@
|
||||||
" bundler.vim - Support for Ruby's Bundler
|
|
||||||
" Maintainer: Tim Pope <http://tpo.pe/>
|
|
||||||
" Version: 2.0
|
|
||||||
|
|
||||||
if exists('g:loaded_bundler') || &cp || v:version < 700
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_bundler = 1
|
|
||||||
|
|
||||||
" Utility {{{1
|
|
||||||
|
|
||||||
function! s:function(name) abort
|
|
||||||
return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:sub(str,pat,rep) abort
|
|
||||||
return substitute(a:str,'\v\C'.a:pat,a:rep,'')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:gsub(str,pat,rep) abort
|
|
||||||
return substitute(a:str,'\v\C'.a:pat,a:rep,'g')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:shellesc(arg) abort
|
|
||||||
if a:arg =~ '^[A-Za-z0-9_/.-]\+$'
|
|
||||||
return a:arg
|
|
||||||
else
|
|
||||||
return shellescape(a:arg)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:fnameescape(file) abort
|
|
||||||
if exists('*fnameescape')
|
|
||||||
return fnameescape(a:file)
|
|
||||||
else
|
|
||||||
return escape(a:file," \t\n*?[{`$\\%#'\"|!<")
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:shellslash(path)
|
|
||||||
if exists('+shellslash') && !&shellslash
|
|
||||||
return s:gsub(a:path,'\\','/')
|
|
||||||
else
|
|
||||||
return a:path
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:completion_filter(results,A)
|
|
||||||
let results = sort(copy(a:results))
|
|
||||||
call filter(results,'v:val !~# "\\~$"')
|
|
||||||
let filtered = filter(copy(results),'v:val[0:strlen(a:A)-1] ==# a:A')
|
|
||||||
if !empty(filtered) | return filtered | endif
|
|
||||||
let regex = s:gsub(a:A,'[^/:]','[&].*')
|
|
||||||
let filtered = filter(copy(results),'v:val =~# "^".regex')
|
|
||||||
if !empty(filtered) | return filtered | endif
|
|
||||||
let filtered = filter(copy(results),'"/".v:val =~# "[/:]".regex')
|
|
||||||
if !empty(filtered) | return filtered | endif
|
|
||||||
let regex = s:gsub(a:A,'.','[&].*')
|
|
||||||
let filtered = filter(copy(results),'"/".v:val =~# regex')
|
|
||||||
return filtered
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:throw(string) abort
|
|
||||||
let v:errmsg = 'bundler: '.a:string
|
|
||||||
throw v:errmsg
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:warn(str)
|
|
||||||
echohl WarningMsg
|
|
||||||
echomsg a:str
|
|
||||||
echohl None
|
|
||||||
let v:warningmsg = a:str
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:add_methods(namespace, method_names) abort
|
|
||||||
for name in a:method_names
|
|
||||||
let s:{a:namespace}_prototype[name] = s:function('s:'.a:namespace.'_'.name)
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:commands = []
|
|
||||||
function! s:command(definition) abort
|
|
||||||
let s:commands += [a:definition]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:define_commands()
|
|
||||||
for command in s:commands
|
|
||||||
exe 'command! -buffer '.command
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
augroup bundler_utility
|
|
||||||
autocmd!
|
|
||||||
autocmd User Bundler call s:define_commands()
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
let s:abstract_prototype = {}
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Syntax highlighting {{{1
|
|
||||||
|
|
||||||
function! s:syntaxfile()
|
|
||||||
syntax keyword rubyGemfileMethod gemspec gem source path git group platforms env ruby
|
|
||||||
hi def link rubyGemfileMethod Function
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:syntaxlock()
|
|
||||||
setlocal iskeyword+=-,.
|
|
||||||
syn match gemfilelockHeading '^[[:upper:]]\+$'
|
|
||||||
syn match gemfilelockKey '^\s\+\zs\S\+:'he=e-1 skipwhite nextgroup=gemfilelockRevision
|
|
||||||
syn match gemfilelockKey 'remote:'he=e-1 skipwhite nextgroup=gemfilelockRemote
|
|
||||||
syn match gemfilelockRemote '\S\+' contained
|
|
||||||
syn match gemfilelockRevision '[[:alnum:]._-]\+$' contained
|
|
||||||
syn match gemfilelockGem '^\s\+\zs[[:alnum:]._-]\+\%([ !]\|$\)\@=' contains=gemfilelockFound,gemfilelockMissing skipwhite nextgroup=gemfilelockVersions,gemfilelockBang
|
|
||||||
syn match gemfilelockVersions '([^()]*)' contained contains=gemfilelockVersion
|
|
||||||
syn match gemfilelockVersion '[^,()]*' contained
|
|
||||||
syn match gemfilelockBang '!' contained
|
|
||||||
if !empty(bundler#project())
|
|
||||||
exe 'syn match gemfilelockFound "\<\%(bundler\|' . join(keys(s:project().paths()), '\|') . '\)\>" contained'
|
|
||||||
exe 'syn match gemfilelockMissing "\<\%(' . join(keys(filter(s:project().versions(), '!has_key(s:project().paths(), v:key)')), '\|') . '\)\>" contained'
|
|
||||||
else
|
|
||||||
exe 'syn match gemfilelockFound "\<\%(\S*\)\>" contained'
|
|
||||||
endif
|
|
||||||
syn match gemfilelockHeading '^PLATFORMS$' nextgroup=gemfilelockPlatform skipnl skipwhite
|
|
||||||
syn match gemfilelockPlatform '^ \zs[[:alnum:]._-]\+$' contained nextgroup=gemfilelockPlatform skipnl skipwhite
|
|
||||||
|
|
||||||
hi def link gemfilelockHeading PreProc
|
|
||||||
hi def link gemfilelockPlatform Typedef
|
|
||||||
hi def link gemfilelockKey Identifier
|
|
||||||
hi def link gemfilelockRemote String
|
|
||||||
hi def link gemfilelockRevision Number
|
|
||||||
hi def link gemfilelockFound Statement
|
|
||||||
hi def link gemfilelockMissing Error
|
|
||||||
hi def link gemfilelockVersion Type
|
|
||||||
hi def link gemfilelockBang Special
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:setuplock()
|
|
||||||
nnoremap <silent><buffer> gf :Bopen <C-R><C-F><CR>
|
|
||||||
nnoremap <silent><buffer> <C-W>f :Bsplit <C-R><C-F><CR>
|
|
||||||
nnoremap <silent><buffer> <C-W><C-F> :Bsplit <C-R><C-F><CR>
|
|
||||||
nnoremap <silent><buffer> <C-W>gf :Btabedit <C-R><C-F><CR>
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
augroup bundler_syntax
|
|
||||||
autocmd!
|
|
||||||
autocmd BufNewFile,BufRead */.bundle/config set filetype=yaml
|
|
||||||
autocmd BufNewFile,BufRead Gemfile set filetype=ruby
|
|
||||||
autocmd Syntax ruby if expand('<afile>:t') ==? 'gemfile' | call s:syntaxfile() | endif
|
|
||||||
autocmd BufNewFile,BufRead [Gg]emfile.lock setf gemfilelock
|
|
||||||
autocmd FileType gemfilelock set suffixesadd=.rb
|
|
||||||
autocmd Syntax gemfilelock call s:syntaxlock()
|
|
||||||
autocmd FileType gemfilelock call s:setuplock()
|
|
||||||
autocmd User Rails/Gemfile.lock call s:setuplock()
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Initialization {{{1
|
|
||||||
|
|
||||||
function! s:FindBundlerRoot(path) abort
|
|
||||||
let path = s:shellslash(a:path)
|
|
||||||
let fn = fnamemodify(path,':s?[\/]$??')
|
|
||||||
let ofn = ""
|
|
||||||
let nfn = fn
|
|
||||||
while fn != ofn
|
|
||||||
if filereadable(fn.'/Gemfile')
|
|
||||||
return s:sub(simplify(fnamemodify(fn,':p')),'[\\/]$','')
|
|
||||||
endif
|
|
||||||
let ofn = fn
|
|
||||||
let fn = fnamemodify(ofn,':h')
|
|
||||||
endwhile
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:Detect(path)
|
|
||||||
if !exists('b:bundler_root')
|
|
||||||
let dir = s:FindBundlerRoot(a:path)
|
|
||||||
if dir != ''
|
|
||||||
let b:bundler_root = dir
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if exists('b:bundler_root')
|
|
||||||
silent doautocmd User Bundler
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
augroup bundler
|
|
||||||
autocmd!
|
|
||||||
autocmd FileType * call s:Detect(expand('<afile>:p'))
|
|
||||||
autocmd BufNewFile,BufReadPost *
|
|
||||||
\ if empty(&filetype) |
|
|
||||||
\ call s:Detect(expand('<afile>:p')) |
|
|
||||||
\ endif
|
|
||||||
autocmd VimEnter * if expand('<amatch>')==''|call s:Detect(getcwd())|endif
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Project {{{1
|
|
||||||
|
|
||||||
let s:project_prototype = {}
|
|
||||||
let s:projects = {}
|
|
||||||
|
|
||||||
function! bundler#project(...) abort
|
|
||||||
let dir = a:0 ? a:1 : (exists('b:bundler_root') && b:bundler_root !=# '' ? b:bundler_root : s:FindBundlerRoot(expand('%:p')))
|
|
||||||
if dir !=# ''
|
|
||||||
if has_key(s:projects,dir)
|
|
||||||
let project = get(s:projects,dir)
|
|
||||||
else
|
|
||||||
let project = {'root': dir}
|
|
||||||
let s:projects[dir] = project
|
|
||||||
endif
|
|
||||||
return extend(extend(project,s:project_prototype,'keep'),s:abstract_prototype,'keep')
|
|
||||||
endif
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:project(...) abort
|
|
||||||
let project = a:0 ? bundler#project(a:1) : bundler#project()
|
|
||||||
if empty(project)
|
|
||||||
call s:throw('not a Bundler project: '.(a:0 ? a:1 : expand('%')))
|
|
||||||
else
|
|
||||||
return project
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:project_path(...) dict abort
|
|
||||||
return join([self.root]+a:000,'/')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:add_methods('project',['path'])
|
|
||||||
|
|
||||||
function! s:project_locked() dict abort
|
|
||||||
let lock_file = self.path('Gemfile.lock')
|
|
||||||
let time = getftime(lock_file)
|
|
||||||
if time != -1 && time != get(self,'_lock_time',-1)
|
|
||||||
let self._locked = {'git': [], 'gem': [], 'path': []}
|
|
||||||
let self._versions = {}
|
|
||||||
|
|
||||||
for line in readfile(lock_file)
|
|
||||||
if line =~# '^\S'
|
|
||||||
let properties = {'versions': {}}
|
|
||||||
if has_key(self._locked, tolower(line))
|
|
||||||
call extend(self._locked[tolower(line)], [properties])
|
|
||||||
endif
|
|
||||||
elseif line =~# '^ \w\+: '
|
|
||||||
let properties[matchstr(line, '\w\+')] = matchstr(line, ': \zs.*')
|
|
||||||
elseif line =~# '^ [a-zA-Z0-9._-]\+\s\+(\d\+'
|
|
||||||
let name = split(line, ' ')[0]
|
|
||||||
let ver = substitute(line, '.*(\|).*', '', 'g')
|
|
||||||
let properties.versions[name] = ver
|
|
||||||
let self._versions[name] = ver
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
let self._lock_time = time
|
|
||||||
endif
|
|
||||||
return get(self, '_locked', {})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:project_paths(...) dict abort
|
|
||||||
call self.locked()
|
|
||||||
let time = get(self, '_lock_time', -1)
|
|
||||||
if a:0 && a:1 ==# 'refresh' || time != -1 && time != get(self, '_path_time', -1)
|
|
||||||
let paths = {}
|
|
||||||
|
|
||||||
let chdir = exists("*haslocaldir") && haslocaldir() ? "lchdir" : "chdir"
|
|
||||||
let cwd = getcwd()
|
|
||||||
|
|
||||||
" Explicitly setting $PATH means /etc/zshenv on OS X can't touch it.
|
|
||||||
if executable('env')
|
|
||||||
let prefix = 'env PATH='.s:shellesc($PATH).' '
|
|
||||||
else
|
|
||||||
let prefix = ''
|
|
||||||
endif
|
|
||||||
|
|
||||||
let gem_paths = []
|
|
||||||
if exists('$GEM_PATH')
|
|
||||||
let gem_paths = split($GEM_PATH, has('win32') ? ';' : ':')
|
|
||||||
else
|
|
||||||
try
|
|
||||||
exe chdir s:fnameescape(self.path())
|
|
||||||
let gem_paths = split(system(prefix.'ruby -rubygems -e "print Gem.path.join(%(;))"'), ';')
|
|
||||||
finally
|
|
||||||
exe chdir s:fnameescape(cwd)
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
|
|
||||||
let abi_version = matchstr(get(gem_paths, 0, '1.9.1'), '[0-9.]\+$')
|
|
||||||
for config in [expand('~/.bundle/config'), self.path('.bundle/config')]
|
|
||||||
if filereadable(config)
|
|
||||||
let body = join(readfile(config), "\n")
|
|
||||||
let bundle_path = matchstr(body, "\\C\\<BUNDLE_PATH: \\zs[^\n]*")
|
|
||||||
if !empty(bundle_path)
|
|
||||||
if body =~# '\C\<BUNDLE_DISABLE_SHARED_GEMS:'
|
|
||||||
let gem_paths = [self.path(bundle_path, 'ruby', abi_version)]
|
|
||||||
else
|
|
||||||
let gem_paths = [self.path(bundle_path)]
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
for source in self._locked.git
|
|
||||||
for [name, ver] in items(source.versions)
|
|
||||||
for path in gem_paths
|
|
||||||
let dir = path . '/bundler/gems/' . matchstr(source.remote, '.*/\zs.\{-\}\ze\%(\.git\)\=$') . '-' . source.revision[0:11]
|
|
||||||
if isdirectory(dir)
|
|
||||||
let files = split(glob(dir . '/*/' . name . '.gemspec'), "\n")
|
|
||||||
if empty(files)
|
|
||||||
let paths[name] = dir
|
|
||||||
else
|
|
||||||
let paths[name] = files[0][0 : -10-strlen(name)]
|
|
||||||
endif
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
|
|
||||||
for source in self._locked.path
|
|
||||||
for [name, ver] in items(source.versions)
|
|
||||||
if source.remote !~# '^/'
|
|
||||||
let local = simplify(self.path(source.remote))
|
|
||||||
else
|
|
||||||
let local = source.remote
|
|
||||||
endif
|
|
||||||
let files = split(glob(local . '/*/' . name . '.gemspec'), "\n")
|
|
||||||
if empty(files)
|
|
||||||
let paths[name] = local
|
|
||||||
else
|
|
||||||
let paths[name] = files[0][0 : -10-strlen(name)]
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
|
|
||||||
for source in self._locked.gem
|
|
||||||
for [name, ver] in items(source.versions)
|
|
||||||
for path in gem_paths
|
|
||||||
let dir = path . '/gems/' . name . '-' . ver
|
|
||||||
if isdirectory(dir)
|
|
||||||
let paths[name] = dir
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
if !has_key(paths, name)
|
|
||||||
for path in gem_paths
|
|
||||||
let dir = glob(path . '/gems/' . name . '-' . ver . '-*')
|
|
||||||
if isdirectory(dir)
|
|
||||||
let paths[name] = dir
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
|
|
||||||
let self._path_time = time
|
|
||||||
let self._paths = paths
|
|
||||||
let self._sorted = sort(values(paths))
|
|
||||||
let index = index(self._sorted, self.path())
|
|
||||||
if index > 0
|
|
||||||
call insert(self._sorted, remove(self._sorted,index))
|
|
||||||
endif
|
|
||||||
call self.alter_buffer_paths()
|
|
||||||
return paths
|
|
||||||
endif
|
|
||||||
return get(self,'_paths',{})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:project_sorted() dict abort
|
|
||||||
call self.paths()
|
|
||||||
return get(self, '_sorted', [])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:project_gems() dict abort
|
|
||||||
return self.paths()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:project_versions() dict abort
|
|
||||||
call self.locked()
|
|
||||||
return get(self, '_versions', {})
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:project_has(gem) dict abort
|
|
||||||
call self.locked()
|
|
||||||
return has_key(self.versions(), a:gem)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:add_methods('project', ['locked', 'gems', 'paths', 'sorted', 'versions', 'has'])
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Buffer {{{1
|
|
||||||
|
|
||||||
let s:buffer_prototype = {}
|
|
||||||
|
|
||||||
function! s:buffer(...) abort
|
|
||||||
let buffer = {'#': bufnr(a:0 ? a:1 : '%')}
|
|
||||||
let g:buffer = buffer
|
|
||||||
call extend(extend(buffer,s:buffer_prototype,'keep'),s:abstract_prototype,'keep')
|
|
||||||
if buffer.getvar('bundler_root') !=# ''
|
|
||||||
return buffer
|
|
||||||
endif
|
|
||||||
call s:throw('not a Bundler project: '.(a:0 ? a:1 : expand('%')))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! bundler#buffer(...) abort
|
|
||||||
return s:buffer(a:0 ? a:1 : '%')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:buffer_getvar(var) dict abort
|
|
||||||
return getbufvar(self['#'],a:var)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:buffer_setvar(var,value) dict abort
|
|
||||||
return setbufvar(self['#'],a:var,a:value)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:buffer_project() dict abort
|
|
||||||
return s:project(self.getvar('bundler_root'))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:add_methods('buffer',['getvar','setvar','project'])
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Bundle {{{1
|
|
||||||
|
|
||||||
function! s:push_chdir()
|
|
||||||
if !exists("s:command_stack") | let s:command_stack = [] | endif
|
|
||||||
let chdir = exists("*haslocaldir") && haslocaldir() ? "lchdir " : "chdir "
|
|
||||||
call add(s:command_stack,chdir.s:fnameescape(getcwd()))
|
|
||||||
exe chdir.'`=s:project().path()`'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:pop_command()
|
|
||||||
if exists("s:command_stack") && len(s:command_stack) > 0
|
|
||||||
exe remove(s:command_stack,-1)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:Bundle(bang,arg)
|
|
||||||
let old_makeprg = &l:makeprg
|
|
||||||
let old_errorformat = &l:errorformat
|
|
||||||
let old_compiler = get(b:, 'current_compiler', '')
|
|
||||||
try
|
|
||||||
compiler bundler
|
|
||||||
execute 'make! '.a:arg
|
|
||||||
if a:bang ==# ''
|
|
||||||
return 'if !empty(getqflist()) | cfirst | endif'
|
|
||||||
else
|
|
||||||
return ''
|
|
||||||
endif
|
|
||||||
finally
|
|
||||||
let &l:errorformat = old_errorformat
|
|
||||||
let &l:makeprg = old_makeprg
|
|
||||||
let b:current_compiler = old_compiler
|
|
||||||
if empty(b:current_compiler)
|
|
||||||
unlet b:current_compiler
|
|
||||||
endif
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:BundleComplete(A,L,P)
|
|
||||||
if a:L =~# '^\S\+\s\+\%(show\|update\) '
|
|
||||||
return s:completion_filter(keys(s:project().paths()),a:A)
|
|
||||||
endif
|
|
||||||
return s:completion_filter(['install','update','exec','package','config','check','list','show','outdated','console','viz','benchmark'],a:A)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:SetupMake() abort
|
|
||||||
compiler bundler
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:command("-bar -bang -nargs=? -complete=customlist,s:BundleComplete Bundle :execute s:Bundle('<bang>',<q-args>)")
|
|
||||||
|
|
||||||
augroup bundler_make
|
|
||||||
autocmd FileType gemfilelock call s:SetupMake()
|
|
||||||
autocmd FileType ruby
|
|
||||||
\ if expand('<afile>:t') ==? 'gemfile' |
|
|
||||||
\ call s:SetupMake() |
|
|
||||||
\ endif
|
|
||||||
autocmd QuickFixCmdPre make,lmake
|
|
||||||
\ if &makeprg =~# '^bundle' && exists('b:bundler_root') |
|
|
||||||
\ call s:push_chdir() |
|
|
||||||
\ endif
|
|
||||||
autocmd QuickFixCmdPost make,lmake
|
|
||||||
\ if &makeprg =~# '^bundle' && exists('b:bundler_root') |
|
|
||||||
\ call s:pop_command() |
|
|
||||||
\ call s:project().paths("refresh") |
|
|
||||||
\ endif
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Bopen {{{1
|
|
||||||
|
|
||||||
function! s:Open(cmd,gem,lcd)
|
|
||||||
if a:gem ==# '' && a:lcd
|
|
||||||
return a:cmd.' `=bundler#buffer().project().path("Gemfile")`'
|
|
||||||
elseif a:gem ==# ''
|
|
||||||
return a:cmd.' `=bundler#buffer().project().path("Gemfile.lock")`'
|
|
||||||
else
|
|
||||||
if !has_key(s:project().paths(), a:gem)
|
|
||||||
call s:project().paths('refresh')
|
|
||||||
endif
|
|
||||||
if !has_key(s:project().paths(), a:gem)
|
|
||||||
if has_key(s:project().versions(), a:gem)
|
|
||||||
let v:errmsg = "Gem \"".a:gem."\" is in bundle but not installed"
|
|
||||||
else
|
|
||||||
let v:errmsg = "Gem \"".a:gem."\" is not in bundle"
|
|
||||||
endif
|
|
||||||
return 'echoerr v:errmsg'
|
|
||||||
endif
|
|
||||||
let path = fnameescape(bundler#buffer().project().paths()[a:gem])
|
|
||||||
let exec = a:cmd.' '.path
|
|
||||||
if a:cmd =~# '^pedit' && a:lcd
|
|
||||||
let exec .= '|wincmd P|lcd '.path.'|wincmd p'
|
|
||||||
elseif a:lcd
|
|
||||||
let exec .= '|lcd '.path
|
|
||||||
endif
|
|
||||||
return exec
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:OpenComplete(A,L,P)
|
|
||||||
return s:completion_filter(keys(s:project().paths()),a:A)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:command("-bar -bang -nargs=? -complete=customlist,s:OpenComplete Bopen :execute s:Open('edit<bang>',<q-args>,1)")
|
|
||||||
call s:command("-bar -bang -nargs=? -complete=customlist,s:OpenComplete Bedit :execute s:Open('edit<bang>',<q-args>,0)")
|
|
||||||
call s:command("-bar -bang -nargs=? -complete=customlist,s:OpenComplete Bsplit :execute s:Open('split',<q-args>,<bang>1)")
|
|
||||||
call s:command("-bar -bang -nargs=? -complete=customlist,s:OpenComplete Bvsplit :execute s:Open('vsplit',<q-args>,<bang>1)")
|
|
||||||
call s:command("-bar -bang -nargs=? -complete=customlist,s:OpenComplete Btabedit :execute s:Open('tabedit',<q-args>,<bang>1)")
|
|
||||||
call s:command("-bar -bang -nargs=? -complete=customlist,s:OpenComplete Bpedit :execute s:Open('pedit',<q-args>,<bang>1)")
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Paths {{{1
|
|
||||||
|
|
||||||
function! s:build_path_option(paths,suffix) abort
|
|
||||||
return join(map(copy(a:paths),'",".escape(s:shellslash(v:val."/".a:suffix),", ")'),'')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:buffer_alter_paths() dict abort
|
|
||||||
if self.getvar('&suffixesadd') =~# '\.rb\>'
|
|
||||||
let new = self.project().sorted()
|
|
||||||
let old = type(self.getvar('bundler_paths')) == type([]) ? self.getvar('bundler_paths') : []
|
|
||||||
for [option, suffix] in [['path', 'lib'], ['tags', 'tags']]
|
|
||||||
let value = self.getvar('&'.option)
|
|
||||||
if !empty(old)
|
|
||||||
let drop = s:build_path_option(old,suffix)
|
|
||||||
let index = stridx(value,drop)
|
|
||||||
if index > 0
|
|
||||||
let value = value[0:index-1] . value[index+strlen(drop):-1]
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
call self.setvar('&'.option,value.s:build_path_option(new,suffix))
|
|
||||||
endfor
|
|
||||||
call self.setvar('bundler_paths',new)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:add_methods('buffer',['alter_paths'])
|
|
||||||
|
|
||||||
function! s:project_alter_buffer_paths() dict abort
|
|
||||||
for bufnr in range(1,bufnr('$'))
|
|
||||||
if getbufvar(bufnr,'bundler_root') ==# self.path()
|
|
||||||
let vim_parsing_quirk = s:buffer(bufnr).alter_paths()
|
|
||||||
endif
|
|
||||||
if getbufvar(bufnr, '&syntax') ==# 'gemfilelock'
|
|
||||||
call setbufvar(bufnr, '&syntax', 'gemfilelock')
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
call s:add_methods('project',['alter_buffer_paths'])
|
|
||||||
|
|
||||||
augroup bundler_path
|
|
||||||
autocmd!
|
|
||||||
autocmd User Bundler call s:buffer().alter_paths()
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
|
|
||||||
" vim:set sw=2 sts=2:
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 1ef18a10512fe0f84bb2c412b38e613c331a7b55
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit aac76b431b1ed726a7f3e2608bdfc02cce76ec8e
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit bdf57577b8c1f3677da788f93490209688870e58
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit fd09aea1c0944eddd9dd6e5a22db4d52b7894490
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit b79c5177caac6810af07cb15e4f6db9324f1f42f
|
|
||||||
|
|
@ -1,267 +0,0 @@
|
||||||
---
|
|
||||||
Title: Solarized Colorscheme for Vim
|
|
||||||
Description: Precision colors for machines and people
|
|
||||||
Author: Ethan Schoonover
|
|
||||||
Colors: light yellow
|
|
||||||
Created: 2011 Mar 15
|
|
||||||
Modified: 2011 Apr 16
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Solarized Colorscheme for Vim
|
|
||||||
=============================
|
|
||||||
|
|
||||||
Developed by Ethan Schoonover <es@ethanschoonover.com>
|
|
||||||
|
|
||||||
Visit the [Solarized homepage]
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
See the [Solarized homepage] for screenshots,
|
|
||||||
details and colorscheme versions for Vim, Mutt, popular terminal emulators and
|
|
||||||
other applications.
|
|
||||||
|
|
||||||
Screenshots
|
|
||||||
-----------
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Downloads
|
|
||||||
---------
|
|
||||||
|
|
||||||
If you have come across this colorscheme via the [Vim-only repository] on
|
|
||||||
github, or the [vim.org script] page see the link above to the Solarized
|
|
||||||
homepage or visit the main [Solarized repository].
|
|
||||||
|
|
||||||
The [Vim-only repository] is kept in sync with the main [Solarized repository]
|
|
||||||
and is for installation convenience only (with [Pathogen] or [Vundle], for
|
|
||||||
instance). Issues, bug reports, changelogs are centralized at the main
|
|
||||||
[Solarized repository].
|
|
||||||
|
|
||||||
[Solarized homepage]: http://ethanschoonover.com/solarized
|
|
||||||
[Solarized repository]: https://github.com/altercation/solarized
|
|
||||||
[Vim-only repository]: https://github.com/altercation/vim-colors-solarized
|
|
||||||
[vimorg-script]: http://vim.org/script
|
|
||||||
[Pathogen]: https://github.com/tpope/vim-pathogen
|
|
||||||
[Vundle]: https://github.com/gmarik/vundle
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
### Option 1: Manual installation
|
|
||||||
|
|
||||||
1. Move `solarized.vim` to your `.vim/colors` directory. After downloading the
|
|
||||||
vim script or package:
|
|
||||||
|
|
||||||
$ cd vim-colors-solarized/colors
|
|
||||||
$ mv solarized.vim ~/.vim/colors/
|
|
||||||
|
|
||||||
### Option 2: Pathogen installation ***(recommended)***
|
|
||||||
|
|
||||||
1. Download and install Tim Pope's [Pathogen].
|
|
||||||
|
|
||||||
2. Next, move or clone the `vim-colors-solarized` directory so that it is
|
|
||||||
a subdirectory of the `.vim/bundle` directory.
|
|
||||||
|
|
||||||
a. **Clone:**
|
|
||||||
|
|
||||||
$ cd ~/.vim/bundle
|
|
||||||
$ git clone git://github.com/altercation/vim-colors-solarized.git
|
|
||||||
|
|
||||||
b. **Move:**
|
|
||||||
|
|
||||||
In the parent directory of vim-colors-solarized:
|
|
||||||
|
|
||||||
$ mv vim-colors-solarized ~/.vim/bundle/
|
|
||||||
|
|
||||||
### Modify .vimrc
|
|
||||||
|
|
||||||
After either Option 1 or Option 2 above, put the following two lines in your
|
|
||||||
.vimrc:
|
|
||||||
|
|
||||||
syntax enable
|
|
||||||
set background=dark
|
|
||||||
colorscheme solarized
|
|
||||||
|
|
||||||
or, for the light background mode of Solarized:
|
|
||||||
|
|
||||||
syntax enable
|
|
||||||
set background=light
|
|
||||||
colorscheme solarized
|
|
||||||
|
|
||||||
I like to have a different background in GUI and terminal modes, so I can use
|
|
||||||
the following if-then. However, I find vim's background autodetection to be
|
|
||||||
pretty good and, at least with MacVim, I can leave this background value
|
|
||||||
assignment out entirely and get the same results.
|
|
||||||
|
|
||||||
if has('gui_running')
|
|
||||||
set background=light
|
|
||||||
else
|
|
||||||
set background=dark
|
|
||||||
endif
|
|
||||||
|
|
||||||
See the [Solarized homepage] for screenshots which will help you
|
|
||||||
select either the light or dark background.
|
|
||||||
|
|
||||||
### IMPORTANT NOTE FOR TERMINAL USERS:
|
|
||||||
|
|
||||||
If you are going to use Solarized in Terminal mode (i.e. not in a GUI version
|
|
||||||
like gvim or macvim), **please please please** consider setting your terminal
|
|
||||||
emulator's colorscheme to used the Solarized palette. I've included palettes
|
|
||||||
for some popular terminal emulator as well as Xdefaults in the official
|
|
||||||
Solarized download available from [Solarized homepage]. If you use
|
|
||||||
Solarized *without* these colors, Solarized will need to be told to degrade its
|
|
||||||
colorscheme to a set compatible with the limited 256 terminal palette (whereas
|
|
||||||
by using the terminal's 16 ansi color values, you can set the correct, specific
|
|
||||||
values for the Solarized palette).
|
|
||||||
|
|
||||||
If you do use the custom terminal colors, solarized.vim should work out of the
|
|
||||||
box for you. If you are using a terminal emulator that supports 256 colors and
|
|
||||||
don't want to use the custom Solarized terminal colors, you will need to use
|
|
||||||
the degraded 256 colorscheme. To do so, simply add the following line *before*
|
|
||||||
the `colorschem solarized` line:
|
|
||||||
|
|
||||||
let g:solarized_termcolors=256
|
|
||||||
|
|
||||||
Again, I recommend just changing your terminal colors to Solarized values
|
|
||||||
either manually or via one of the many terminal schemes available for import.
|
|
||||||
|
|
||||||
Advanced Configuration
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
Solarized will work out of the box with just the two lines specified above but
|
|
||||||
does include several other options that can be set in your .vimrc file.
|
|
||||||
|
|
||||||
Set these in your vimrc file prior to calling the colorscheme.
|
|
||||||
"
|
|
||||||
option name default optional
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_termcolors= 16 | 256
|
|
||||||
g:solarized_termtrans = 0 | 1
|
|
||||||
g:solarized_degrade = 0 | 1
|
|
||||||
g:solarized_bold = 1 | 0
|
|
||||||
g:solarized_underline = 1 | 0
|
|
||||||
g:solarized_italic = 1 | 0
|
|
||||||
g:solarized_contrast = "normal"| "high" or "low"
|
|
||||||
g:solarized_visibility= "normal"| "high" or "low"
|
|
||||||
------------------------------------------------
|
|
||||||
|
|
||||||
### Option Details
|
|
||||||
|
|
||||||
* g:solarized_termcolors
|
|
||||||
|
|
||||||
This is set to *16* by default, meaning that Solarized will attempt to use
|
|
||||||
the standard 16 colors of your terminal emulator. You will need to set
|
|
||||||
those colors to the correct Solarized values either manually or by
|
|
||||||
importing one of the many colorscheme available for popular terminal
|
|
||||||
emulators and Xdefaults.
|
|
||||||
|
|
||||||
* g:solarized_termtrans
|
|
||||||
|
|
||||||
If you use a terminal emulator with a transparent background and Solarized
|
|
||||||
isn't displaying the background color transparently, set this to 1 and
|
|
||||||
Solarized will use the default (transparent) background of the terminal
|
|
||||||
emulator. *urxvt* required this in my testing; iTerm2 did not.
|
|
||||||
|
|
||||||
Note that on Mac OS X Terminal.app, solarized_termtrans is set to 1 by
|
|
||||||
default as this is almost always the best option. The only exception to
|
|
||||||
this is if the working terminfo file supports 256 colors (xterm-256color).
|
|
||||||
|
|
||||||
* g:solarized_degrade
|
|
||||||
|
|
||||||
For test purposes only; forces Solarized to use the 256 degraded color mode
|
|
||||||
to test the approximate color values for accuracy.
|
|
||||||
|
|
||||||
* g:solarized_bold | g:solarized_underline | g:solarized_italic
|
|
||||||
|
|
||||||
If you wish to stop Solarized from displaying bold, underlined or
|
|
||||||
italicized typefaces, simply assign a zero value to the appropriate
|
|
||||||
variable, for example: `let g:solarized_italic=0`
|
|
||||||
|
|
||||||
* g:solarized_contrast
|
|
||||||
|
|
||||||
Stick with normal! It's been carefully tested. Setting this option to high
|
|
||||||
or low does use the same Solarized palette but simply shifts some values up
|
|
||||||
or down in order to expand or compress the tonal range displayed.
|
|
||||||
|
|
||||||
* g:solarized_visibility
|
|
||||||
|
|
||||||
Special characters such as trailing whitespace, tabs, newlines, when
|
|
||||||
displayed using `:set list` can be set to one of three levels depending on
|
|
||||||
your needs. Default value is `normal` with `high` and `low` options.
|
|
||||||
|
|
||||||
Toggle Background Function
|
|
||||||
--------------------------
|
|
||||||
|
|
||||||
Solarized comes with a Toggle Background plugin that by default will map to
|
|
||||||
<F5> if that mapping is available. If it is not available you will need to
|
|
||||||
either map the function manually or change your current <F5> mapping to
|
|
||||||
something else.
|
|
||||||
|
|
||||||
To set your own mapping in your .vimrc file, simply add the following line to
|
|
||||||
support normal, insert and visual mode usage, changing the "<F5>" value to the
|
|
||||||
key or key combination you wish to use:
|
|
||||||
|
|
||||||
call togglebg#map("<F5>")
|
|
||||||
|
|
||||||
Note that you'll want to use a single function key or equivalent if you want
|
|
||||||
the plugin to work in all modes (normal, insert, visual).
|
|
||||||
|
|
||||||
Code Notes
|
|
||||||
----------
|
|
||||||
|
|
||||||
Use folding to view the `solarized.vim` script with `foldmethod=marker` turned
|
|
||||||
on.
|
|
||||||
|
|
||||||
I have attempted to modularize the creation of Vim colorschemes in this script
|
|
||||||
and, while it could be refactored further, it should be a good foundation for
|
|
||||||
the creation of any color scheme. By simply changing the sixteen values in the
|
|
||||||
GUI section and testing in gvim (or mvim) you can rapidly prototype new
|
|
||||||
colorschemes without diving into the weeds of line-item editing each syntax
|
|
||||||
highlight declaration.
|
|
||||||
|
|
||||||
The Values
|
|
||||||
----------
|
|
||||||
|
|
||||||
L\*a\*b values are canonical (White D65, Reference D50), other values are
|
|
||||||
matched in sRGB space.
|
|
||||||
|
|
||||||
SOLARIZED HEX 16/8 TERMCOL XTERM/HEX L*A*B sRGB HSB
|
|
||||||
--------- ------- ---- ------- ----------- ---------- ----------- -----------
|
|
||||||
base03 #002b36 8/4 brblack 234 #1c1c1c 15 -12 -12 0 43 54 193 100 21
|
|
||||||
base02 #073642 0/4 black 235 #262626 20 -12 -12 7 54 66 192 90 26
|
|
||||||
base01 #586e75 10/7 brgreen 240 #4e4e4e 45 -07 -07 88 110 117 194 25 46
|
|
||||||
base00 #657b83 11/7 bryellow 241 #585858 50 -07 -07 101 123 131 195 23 51
|
|
||||||
base0 #839496 12/6 brblue 244 #808080 60 -06 -03 131 148 150 186 13 59
|
|
||||||
base1 #93a1a1 14/4 brcyan 245 #8a8a8a 65 -05 -02 147 161 161 180 9 63
|
|
||||||
base2 #eee8d5 7/7 white 254 #d7d7af 92 -00 10 238 232 213 44 11 93
|
|
||||||
base3 #fdf6e3 15/7 brwhite 230 #ffffd7 97 00 10 253 246 227 44 10 99
|
|
||||||
yellow #b58900 3/3 yellow 136 #af8700 60 10 65 181 137 0 45 100 71
|
|
||||||
orange #cb4b16 9/3 brred 166 #d75f00 50 50 55 203 75 22 18 89 80
|
|
||||||
red #dc322f 1/1 red 160 #d70000 50 65 45 220 50 47 1 79 86
|
|
||||||
magenta #d33682 5/5 magenta 125 #af005f 50 65 -05 211 54 130 331 74 83
|
|
||||||
violet #6c71c4 13/5 brmagenta 61 #5f5faf 50 15 -45 108 113 196 237 45 77
|
|
||||||
blue #268bd2 4/4 blue 33 #0087ff 55 -10 -45 38 139 210 205 82 82
|
|
||||||
cyan #2aa198 6/6 cyan 37 #00afaf 60 -35 -05 42 161 152 175 74 63
|
|
||||||
green #859900 2/2 green 64 #5f8700 60 -20 65 133 153 0 68 100 60
|
|
||||||
|
|
||||||
License
|
|
||||||
-------
|
|
||||||
Copyright (c) 2011 Ethan Schoonover
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
" Toggle Background
|
|
||||||
" Modified: 2011 Apr 29
|
|
||||||
" Maintainer: Ethan Schoonover
|
|
||||||
" License: OSI approved MIT license
|
|
||||||
|
|
||||||
if exists("g:loaded_togglebg")
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_togglebg = 1
|
|
||||||
|
|
||||||
" noremap is a bit misleading here if you are unused to vim mapping.
|
|
||||||
" in fact, there is remapping, but only of script locally defined remaps, in
|
|
||||||
" this case <SID>TogBG. The <script> argument modifies the noremap scope in
|
|
||||||
" this regard (and the noremenu below).
|
|
||||||
nnoremap <unique> <script> <Plug>ToggleBackground <SID>TogBG
|
|
||||||
inoremap <unique> <script> <Plug>ToggleBackground <ESC><SID>TogBG<ESC>a
|
|
||||||
vnoremap <unique> <script> <Plug>ToggleBackground <ESC><SID>TogBG<ESC>gv
|
|
||||||
nnoremenu <script> Window.Toggle\ Background <SID>TogBG
|
|
||||||
inoremenu <script> Window.Toggle\ Background <ESC><SID>TogBG<ESC>a
|
|
||||||
vnoremenu <script> Window.Toggle\ Background <ESC><SID>TogBG<ESC>gv
|
|
||||||
tmenu Window.Toggle\ Background Toggle light and dark background modes
|
|
||||||
nnoremenu <script> ToolBar.togglebg <SID>TogBG
|
|
||||||
inoremenu <script> ToolBar.togglebg <ESC><SID>TogBG<ESC>a
|
|
||||||
vnoremenu <script> ToolBar.togglebg <ESC><SID>TogBG<ESC>gv
|
|
||||||
tmenu ToolBar.togglebg Toggle light and dark background modes
|
|
||||||
noremap <SID>TogBG :call <SID>TogBG()<CR>
|
|
||||||
|
|
||||||
function! s:TogBG()
|
|
||||||
let &background = ( &background == "dark"? "light" : "dark" )
|
|
||||||
if exists("g:colors_name")
|
|
||||||
exe "colorscheme " . g:colors_name
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
if !exists(":ToggleBG")
|
|
||||||
command ToggleBG :call s:TogBG()
|
|
||||||
endif
|
|
||||||
|
|
||||||
function! ToggleBackground()
|
|
||||||
echo "Please update your ToggleBackground mapping. ':help togglebg' for information."
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! togglebg#map(mapActivation)
|
|
||||||
try
|
|
||||||
exe "silent! nmap <unique> ".a:mapActivation." <Plug>ToggleBackground"
|
|
||||||
exe "silent! imap <unique> ".a:mapActivation." <Plug>ToggleBackground"
|
|
||||||
exe "silent! vmap <unique> ".a:mapActivation." <Plug>ToggleBackground"
|
|
||||||
finally
|
|
||||||
return 0
|
|
||||||
endtry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
if !exists("no_plugin_maps") && !hasmapto('<Plug>ToggleBackground')
|
|
||||||
call togglebg#map("<F5>")
|
|
||||||
endif
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
File diff suppressed because it is too large
Load Diff
|
|
@ -1,254 +0,0 @@
|
||||||
*solarized.vim* for Vim version 7.3 or newer. Modified: 2011 May 05
|
|
||||||
|
|
||||||
|
|
||||||
Solarized Vim Colorscheme by Ethan Schoonover ~
|
|
||||||
|
|
||||||
Solarized Colorscheme *solarized*
|
|
||||||
*solarized-help*
|
|
||||||
*solarized-colors*
|
|
||||||
*solarized-colorscheme*
|
|
||||||
*vim-colors-solarized*
|
|
||||||
|
|
||||||
Solarized is a carefully designed selective contrast colorscheme with dual
|
|
||||||
light and dark modes that runs in both GUI, 256 and 16 color modes.
|
|
||||||
|
|
||||||
See the homepage at http://ethanschoonover.com/solarized for screenshots and
|
|
||||||
details.
|
|
||||||
|
|
||||||
0. Install |solarized-install|
|
|
||||||
1. Solarized Menu |solarized-menu|
|
|
||||||
2. Options |solarized-options|
|
|
||||||
3. Toggle Background |solarized-togglebg|
|
|
||||||
4. Terminal Issues |solarized-term|
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
0. Install *solarized-install*
|
|
||||||
|
|
||||||
Note: I recommend using Tim Pope's pathogen plugin to install this
|
|
||||||
colorscheme. See https://github.com/tpope/vim-pathogen . If you've installed
|
|
||||||
pathogen properly you can install Solarized with the following commands,
|
|
||||||
followed by the .vimrc configuration below.
|
|
||||||
|
|
||||||
$ cd ~/.vim/bundle
|
|
||||||
$ git clone https://github.com/altercation/vim-colors-solarized.git
|
|
||||||
|
|
||||||
If you aren't using pathogen, you can use the following three steps to install
|
|
||||||
Solarized:
|
|
||||||
|
|
||||||
1. Download the solarized distribution (available on the homepage above)
|
|
||||||
and unarchive the file.
|
|
||||||
|
|
||||||
2. Move `solarized.vim` to your `.vim/colors` directory.
|
|
||||||
|
|
||||||
3. Move each of the files in each subdirectories to the corresponding .vim
|
|
||||||
subdirectory (e.g. autoload/togglebg.vim goes into your .vim/autoload
|
|
||||||
directory as .vim/autoload/togglebg.vim).
|
|
||||||
|
|
||||||
|
|
||||||
After installation, place the following lines in your .vimrc:
|
|
||||||
|
|
||||||
syntax enable
|
|
||||||
set background=dark
|
|
||||||
colorscheme solarized
|
|
||||||
|
|
||||||
or, for the light background mode of Solarized:
|
|
||||||
|
|
||||||
syntax enable
|
|
||||||
set background=light
|
|
||||||
colorscheme solarized
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
1. Solarized Menu *solarized-menu*
|
|
||||||
|
|
||||||
Solarized makes available a menu when used in Vim GUI mode (gvim, macvim).
|
|
||||||
This menu includes many of the options detailed below so that you can test out
|
|
||||||
different values quickly without modifying your .vimrc file. If you wish to
|
|
||||||
turn off this menu permanently, simply place the following line in your .vimrc
|
|
||||||
above the "colorscheme solarized" line.
|
|
||||||
|
|
||||||
let g:solarized_menu=0
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
2. Toggle Background *solarized-togglebg*
|
|
||||||
*toggle-bg* *togglebg*
|
|
||||||
*toggle-background*
|
|
||||||
|
|
||||||
Solarized comes with Toggle Background, a simple plugin to switch between
|
|
||||||
light and dark background modes and reset the colorscheme. This is most useful
|
|
||||||
for colorschemes that support both light and dark modes and in terminals or
|
|
||||||
gui vim windows where the background will be properly set.
|
|
||||||
|
|
||||||
Toggle Background can be accessed by:
|
|
||||||
|
|
||||||
* the Solarized menu (in Vim gui mode)
|
|
||||||
* the Window menu (in Vim gui mode, even if the Solarized menu is off)
|
|
||||||
* the "yin/yang" toolbar button (in Vim gui mode)
|
|
||||||
* the default mapping of <F5>
|
|
||||||
* custom key mapping you set in your .vimrc (see below)
|
|
||||||
* command line via ":ToggleBG" (no quotes)
|
|
||||||
|
|
||||||
Toggle Background starts with a default mapping to function key <F5>. If you
|
|
||||||
are already using this in a mapping, Toggle Background will not map itself to
|
|
||||||
a default and you will have to map it manually in your .vimrc file, or
|
|
||||||
remove/change your existing <F5> mapping to another value. To customize the
|
|
||||||
keyboard mapping in your .vimrc file, use the following line, changing the
|
|
||||||
"<F5>" value to the key or key combination you wish to use:
|
|
||||||
|
|
||||||
call togglebg#map("<F5>")
|
|
||||||
|
|
||||||
Note that you'll want to use a single function key or equivalent if you want
|
|
||||||
the plugin to work in all modes (normal, insert, visual).
|
|
||||||
|
|
||||||
When using the plugin during normal, visual, or insert mode, there should be
|
|
||||||
no interruption in workflow. However, if you activate the plugin during
|
|
||||||
REPLACE mode, you will switch to standard insert mode (you will leave the
|
|
||||||
overwrite replace mode).
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
3. Solarized Terminal Issues *solarized-term*
|
|
||||||
|
|
||||||
If you are going to use Solarized in Terminal mode (i.e. not in a GUI version
|
|
||||||
like gvim or macvim), **please please please** consider setting your terminal
|
|
||||||
emulator's colorscheme to used the Solarized palette. I've included palettes
|
|
||||||
for some popular terminal emulator as well as Xdefaults in the official
|
|
||||||
Solarized download available from the Solarized homepage listed at the top of
|
|
||||||
this help document. If you use Solarized *without* these colors, Solarized
|
|
||||||
will need to be told to degrade its colorscheme to a set compatible with the
|
|
||||||
limited 256 terminal palette (whereas by using the terminal's 16 ansi color
|
|
||||||
values, you can set the correct, specific values for the Solarized palette).
|
|
||||||
|
|
||||||
If you do use the custom terminal colors, solarized.vim should work out of
|
|
||||||
the box for you. If you are using a terminal emulator that supports 256
|
|
||||||
colors and don't want to use the custom Solarized terminal colors, you will
|
|
||||||
need to use the degraded 256 colorscheme. To do so, simply add the following
|
|
||||||
line *before* the `colorschem solarized` line:
|
|
||||||
|
|
||||||
let g:solarized_termcolors=256
|
|
||||||
|
|
||||||
Again, I recommend just changing your terminal colors to Solarized values
|
|
||||||
either manually or via one of the many terminal schemes available for import.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
4. Solarized Options *solarized-options*
|
|
||||||
|
|
||||||
|
|
||||||
AUTOGENERATE OPTIONS
|
|
||||||
|
|
||||||
You can easily modify and experiment with Solarized display options using the
|
|
||||||
Solarized menu when using Vim in gui mode. Once you have things set to your
|
|
||||||
liking, you can autogenerate the current option list in a format ready for
|
|
||||||
insertion into your .vimrc file using the Solarized menu "Autogenerate
|
|
||||||
Options" command or at the command line with:
|
|
||||||
|
|
||||||
:SolarizedOptions
|
|
||||||
|
|
||||||
|
|
||||||
OPTION LIST
|
|
||||||
|
|
||||||
Set these in your vimrc file prior to calling the colorscheme.
|
|
||||||
|
|
||||||
option name default optional
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_termcolors= 16 | 256
|
|
||||||
g:solarized_termtrans = 0 | 1
|
|
||||||
g:solarized_degrade = 0 | 1
|
|
||||||
g:solarized_bold = 1 | 0
|
|
||||||
g:solarized_underline = 1 | 0
|
|
||||||
g:solarized_italic = 1 | 0
|
|
||||||
g:solarized_contrast = "normal"| "high" or "low"
|
|
||||||
g:solarized_visibility= "normal"| "high" or "low"
|
|
||||||
g:solarized_hitrail = 0 | 1
|
|
||||||
g:solarized_menu = 1 | 0
|
|
||||||
------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
OPTION DETAILS
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_termcolors= 256 | 16 *'solarized_termcolors'*
|
|
||||||
------------------------------------------------
|
|
||||||
The most important option if you are using vim in terminal (non gui) mode!
|
|
||||||
This tells Solarized to use the 256 degraded color mode if running in a 256
|
|
||||||
color capable terminal. Otherwise, if set to `16` it will use the terminal
|
|
||||||
emulators colorscheme (best option as long as you've set the emulators colors
|
|
||||||
to the Solarized palette).
|
|
||||||
|
|
||||||
If you are going to use Solarized in Terminal mode (i.e. not in a GUI
|
|
||||||
version like gvim or macvim), **please please please** consider setting your
|
|
||||||
terminal emulator's colorscheme to used the Solarized palette. I've included
|
|
||||||
palettes for some popular terminal emulator as well as Xdefaults in the
|
|
||||||
official Solarized download available from:
|
|
||||||
http://ethanschoonover.com/solarized . If you use Solarized without these
|
|
||||||
colors, Solarized will by default use an approximate set of 256 colors. It
|
|
||||||
isn't bad looking and has been extensively tweaked, but it's still not quite
|
|
||||||
the real thing.
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_termtrans = 0 | 1 *'solarized_termtrans'*
|
|
||||||
------------------------------------------------
|
|
||||||
If you use a terminal emulator with a transparent background and Solarized
|
|
||||||
isn't displaying the background color transparently, set this to 1 and
|
|
||||||
Solarized will use the default (transparent) background of the terminal
|
|
||||||
emulator. *urxvt* required this in my testing; iTerm2 did not.
|
|
||||||
|
|
||||||
Note that on Mac OS X Terminal.app, solarized_termtrans is set to 1 by
|
|
||||||
default as this is almost always the best option. The only exception to this
|
|
||||||
is if the working terminfo file supports 256 colors (xterm-256color).
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_degrade = 0 | 1 *'solarized_degrade'*
|
|
||||||
------------------------------------------------
|
|
||||||
For test purposes only; forces Solarized to use the 256 degraded color mode
|
|
||||||
to test the approximate color values for accuracy.
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_bold = 1 | 0 *'solarized_bold'*
|
|
||||||
------------------------------------------------
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_underline = 1 | 0 *'solarized_underline'*
|
|
||||||
------------------------------------------------
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_italic = 1 | 0 *'solarized_italic'*
|
|
||||||
------------------------------------------------
|
|
||||||
If you wish to stop Solarized from displaying bold, underlined or
|
|
||||||
italicized typefaces, simply assign a zero value to the appropriate
|
|
||||||
variable, for example: `let g:solarized_italic=0`
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_contrast = "normal"| "high" or "low" *'solarized_contrast'*
|
|
||||||
------------------------------------------------
|
|
||||||
Stick with normal! It's been carefully tested. Setting this option to high
|
|
||||||
or low does use the same Solarized palette but simply shifts some values up
|
|
||||||
or down in order to expand or compress the tonal range displayed.
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_visibility = "normal"| "high" or "low" *'solarized_visibility'*
|
|
||||||
------------------------------------------------
|
|
||||||
Special characters such as trailing whitespace, tabs, newlines, when
|
|
||||||
displayed using ":set list" can be set to one of three levels depending on
|
|
||||||
your needs.
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_hitrail = 0 | 1 *'solarized_hitrail'*
|
|
||||||
------------------------------------------------
|
|
||||||
Visibility can make listchar entities more visible, but if one has set
|
|
||||||
cursorline on, these same listchar values standout somewhat less due to the
|
|
||||||
background color of the cursorline. g:solarized_hitrail enables highlighting
|
|
||||||
of trailing spaces (only one of the listchar types, but a particularly
|
|
||||||
important one) while in the cursoline in a different manner in order to make
|
|
||||||
them more visible. This may not work consistently as Solarized is using
|
|
||||||
a pattern match than can be overridden by a more encompassing syntax-native
|
|
||||||
match such as a comment line.
|
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------
|
|
||||||
g:solarized_menu = 1 | 0 *'solarized_menu'*
|
|
||||||
------------------------------------------------
|
|
||||||
Solarized includes a menu providing access to several of the above
|
|
||||||
display related options, including contrast and visibility. This allows
|
|
||||||
for an easy method of testing different values quickly before settling
|
|
||||||
on a final assignment for your .vimrc. If you wish to turn off this menu,
|
|
||||||
assign g:solarized_menu a value of 0.
|
|
||||||
|
|
||||||
|
|
||||||
vim:tw=78:noet:ts=8:ft=help:norl:
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
'solarized_bold' solarized.txt /*'solarized_bold'*
|
|
||||||
'solarized_contrast' solarized.txt /*'solarized_contrast'*
|
|
||||||
'solarized_degrade' solarized.txt /*'solarized_degrade'*
|
|
||||||
'solarized_hitrail' solarized.txt /*'solarized_hitrail'*
|
|
||||||
'solarized_italic' solarized.txt /*'solarized_italic'*
|
|
||||||
'solarized_menu' solarized.txt /*'solarized_menu'*
|
|
||||||
'solarized_termcolors' solarized.txt /*'solarized_termcolors'*
|
|
||||||
'solarized_termtrans' solarized.txt /*'solarized_termtrans'*
|
|
||||||
'solarized_underline' solarized.txt /*'solarized_underline'*
|
|
||||||
'solarized_visibility' solarized.txt /*'solarized_visibility'*
|
|
||||||
before solarized.txt /*before*
|
|
||||||
solarized solarized.txt /*solarized*
|
|
||||||
solarized-colors solarized.txt /*solarized-colors*
|
|
||||||
solarized-colorscheme solarized.txt /*solarized-colorscheme*
|
|
||||||
solarized-help solarized.txt /*solarized-help*
|
|
||||||
solarized-install solarized.txt /*solarized-install*
|
|
||||||
solarized-menu solarized.txt /*solarized-menu*
|
|
||||||
solarized-options solarized.txt /*solarized-options*
|
|
||||||
solarized-term solarized.txt /*solarized-term*
|
|
||||||
solarized-togglebg solarized.txt /*solarized-togglebg*
|
|
||||||
solarized.vim solarized.txt /*solarized.vim*
|
|
||||||
toggle-background solarized.txt /*toggle-background*
|
|
||||||
toggle-bg solarized.txt /*toggle-bg*
|
|
||||||
togglebg solarized.txt /*togglebg*
|
|
||||||
urxvt solarized.txt /*urxvt*
|
|
||||||
vim-colors-solarized solarized.txt /*vim-colors-solarized*
|
|
||||||
without solarized.txt /*without*
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
## Vim Colorscheme 'Elrodeo'
|
|
||||||
|
|
||||||
This is a dark low contrast vim color scheme influenced by colors used by Chris Granger (@ibdknox) for Clojure code, e.g., on the Noir web page (webnoir.org).
|
|
||||||
|
|
||||||
## Screenshot
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
The color scheme can be installed as a pathogen plugin, i.e., just check it out to `~/.vim/bundle`, or copy the content of `colors`to `~/.vim/colors`.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
In Vim: `:colorscheme elrodeo`.
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
" Vim color file
|
|
||||||
" Name: elrodeo
|
|
||||||
" Maintainer: Christian Müller (@chmllr)
|
|
||||||
" Version: 1.0
|
|
||||||
"
|
|
||||||
" Inspired by the color scheme used by ibdknox.
|
|
||||||
|
|
||||||
set background=dark
|
|
||||||
|
|
||||||
hi clear
|
|
||||||
if exists("syntax_on")
|
|
||||||
syntax reset
|
|
||||||
endif
|
|
||||||
|
|
||||||
let g:colors_name="elrodeo"
|
|
||||||
|
|
||||||
" the nexz block is copied from the wombat theme:
|
|
||||||
" Vim >= 7.0 specific colors
|
|
||||||
if version >= 700
|
|
||||||
hi CursorLine guibg=#2d2d2d
|
|
||||||
hi CursorColumn guibg=#2d2d2d
|
|
||||||
hi MatchParen guifg=#f6f3e8 guibg=#857b6f gui=bold
|
|
||||||
hi Pmenu guifg=#f6f3e8 guibg=#444444
|
|
||||||
hi PmenuSel guifg=#000000 guibg=#cae682
|
|
||||||
endif
|
|
||||||
" General colors
|
|
||||||
hi Normal guibg=#404040 guifg=#d0d0d0
|
|
||||||
hi Cursor guifg=#656565 guibg=#d0d0d0
|
|
||||||
hi NonText guifg=#808080 guibg=#404040
|
|
||||||
hi LineNr guifg=#666666 guibg=#383838
|
|
||||||
hi StatusLine guifg=#f6f3e8 guibg=#444444
|
|
||||||
hi StatusLineNC guifg=#857b6f guibg=#444444
|
|
||||||
hi VertSplit guifg=#444444 guibg=#444444
|
|
||||||
hi Folded guibg=#384048 guifg=#a0a8b0
|
|
||||||
hi Title guifg=#f6f3e8 guibg=NONE gui=bold
|
|
||||||
hi Visual guifg=#f6f3e8 guibg=#444444
|
|
||||||
hi SpecialKey guifg=#808080 guibg=#343434
|
|
||||||
|
|
||||||
|
|
||||||
" Syntax highlighting
|
|
||||||
hi Comment guifg=#677c99
|
|
||||||
hi Operator guifg=#a080f0
|
|
||||||
hi Todo guifg=#333333 guibg=#cccccc
|
|
||||||
hi Constant guifg=white
|
|
||||||
hi String guifg=#bbddff
|
|
||||||
hi Identifier guifg=#30c080
|
|
||||||
hi Define guifg=#30c080
|
|
||||||
hi Function guifg=#30c080
|
|
||||||
hi Macro guifg=#30c080
|
|
||||||
hi Number guifg=#319899
|
|
||||||
hi Special guifg=#30c080
|
|
||||||
hi Conditional guifg=#30c080
|
|
||||||
hi Boolean guifg=#99dd99
|
|
||||||
hi Delimiter guifg=#999999
|
|
||||||
hi Character guifg=#55d2ee
|
|
||||||
hi Search guifg=black guibg=#30c080
|
|
||||||
hi Visual guibg=#303030
|
|
||||||
|
|
||||||
" not used in Clojure (left as in wombat)
|
|
||||||
hi Type guifg=#cae682
|
|
||||||
hi Statement guifg=#8ac6f2
|
|
||||||
hi Keyword guifg=#8ac6f2
|
|
||||||
hi PreProc guifg=#e5786d
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 75 KiB |
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit b27b35e401b5fa3a13f23c52a902533436c50368
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 874505e9f292767e85503573365f613d0ead3895
|
|
||||||
1
vim/bundle/vim-fugitive/.gitignore
vendored
1
vim/bundle/vim-fugitive/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
/doc/tags
|
|
||||||
|
|
@ -1,150 +0,0 @@
|
||||||
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` that
|
|
||||||
mofo. And guess what `:Gcommit` does!
|
|
||||||
|
|
||||||
`:Gblame` brings up an interactive vertical split with `git blame`
|
|
||||||
output. Press enter on a line to reblame the file as it stood in that
|
|
||||||
commit, or `o` to open that commit 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, 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-fugitive.git
|
|
||||||
|
|
||||||
Once help tags have been generated, you can view the manual with
|
|
||||||
`:help fugitive`.
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
------------
|
|
||||||
|
|
||||||
Before reporting a bug, you should try stripping down your Vim
|
|
||||||
configuration and removing other plugins. The sad nature of 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.
|
|
||||||
|
|
||||||
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 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.
|
|
||||||
|
|
||||||
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`.
|
|
||||||
|
|
@ -1,313 +0,0 @@
|
||||||
*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:
|
|
||||||
|
|
||||||
<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|
|
|
||||||
|
|
||||||
*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. 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 muck with the index with commands like
|
|
||||||
git-add and git-reset while a commit message is
|
|
||||||
pending.
|
|
||||||
|
|
||||||
*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.
|
|
||||||
|
|
||||||
*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-: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. Use |do| and |dp| and write to the
|
|
||||||
index file to simulate "git add --patch".
|
|
||||||
|
|
||||||
*fugitive-:Gsdiff*
|
|
||||||
:Gsdiff [revision] Like |:Gdiff|, but split horizontally.
|
|
||||||
|
|
||||||
*fugitive-:Gvdiff*
|
|
||||||
:Gvdiff [revision] Identical to |:Gdiff|. For symmetry with |:Gsdiff|.
|
|
||||||
|
|
||||||
*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. Press enter on a line to
|
|
||||||
reblame the file as it was in that commit. 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:
|
|
||||||
|
|
||||||
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
|
|
||||||
i 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*
|
|
||||||
:[range]Gbrowse If the remote for the current branch is on GitHub,
|
|
||||||
open the current file, blob, tree, commit, or tag
|
|
||||||
(with git-web--browse) on GitHub. Otherwise, open the
|
|
||||||
current file, blob, tree, commit, or tag in
|
|
||||||
git-instaweb (if you have issues, verify you can run
|
|
||||||
"git instaweb" from a terminal). If a range is given,
|
|
||||||
it is appropriately appended to the URL as an anchor.
|
|
||||||
|
|
||||||
To use with GitHub FI, point g:fugitive_github_domains
|
|
||||||
at a list of domains:
|
|
||||||
>
|
|
||||||
let g:fugitive_github_domains = ['git.example.com']
|
|
||||||
~
|
|
||||||
:[range]Gbrowse! Like :Gbrowse, but put the URL on the clipboard rather
|
|
||||||
than opening it.
|
|
||||||
|
|
||||||
:[range]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.
|
|
||||||
|
|
||||||
:[range]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.
|
|
||||||
|
|
||||||
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-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
|
|
@ -1,7 +0,0 @@
|
||||||
# vim-monokai
|
|
||||||
|
|
||||||
Monokai color scheme for Vim converted with [coloration](http://coloration.sickill.net) from Textmate theme with the same name.
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||

|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
" Vim color file
|
|
||||||
" Converted from Textmate theme Monokai using Coloration v0.3.2 (http://github.com/sickill/coloration)
|
|
||||||
|
|
||||||
set background=dark
|
|
||||||
highlight clear
|
|
||||||
|
|
||||||
if exists("syntax_on")
|
|
||||||
syntax reset
|
|
||||||
endif
|
|
||||||
|
|
||||||
let g:colors_name = "Monokai"
|
|
||||||
|
|
||||||
hi Cursor ctermfg=235 ctermbg=231 cterm=NONE guifg=#272822 guibg=#f8f8f0 gui=NONE
|
|
||||||
hi Visual ctermfg=NONE ctermbg=59 cterm=NONE guifg=NONE guibg=#49483e gui=NONE
|
|
||||||
hi CursorLine ctermfg=NONE ctermbg=237 cterm=NONE guifg=NONE guibg=#3c3d37 gui=NONE
|
|
||||||
hi CursorColumn ctermfg=NONE ctermbg=237 cterm=NONE guifg=NONE guibg=#3c3d37 gui=NONE
|
|
||||||
hi ColorColumn ctermfg=NONE ctermbg=237 cterm=NONE guifg=NONE guibg=#3c3d37 gui=NONE
|
|
||||||
hi LineNr ctermfg=102 ctermbg=237 cterm=NONE guifg=#90908a guibg=#3c3d37 gui=NONE
|
|
||||||
hi VertSplit ctermfg=241 ctermbg=241 cterm=NONE guifg=#64645e guibg=#64645e gui=NONE
|
|
||||||
hi MatchParen ctermfg=197 ctermbg=NONE cterm=underline guifg=#f92672 guibg=NONE gui=underline
|
|
||||||
hi StatusLine ctermfg=231 ctermbg=241 cterm=bold guifg=#f8f8f2 guibg=#64645e gui=bold
|
|
||||||
hi StatusLineNC ctermfg=231 ctermbg=241 cterm=NONE guifg=#f8f8f2 guibg=#64645e gui=NONE
|
|
||||||
hi Pmenu ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi PmenuSel ctermfg=NONE ctermbg=59 cterm=NONE guifg=NONE guibg=#49483e gui=NONE
|
|
||||||
hi IncSearch ctermfg=235 ctermbg=186 cterm=NONE guifg=#272822 guibg=#e6db74 gui=NONE
|
|
||||||
hi Search ctermfg=NONE ctermbg=NONE cterm=underline guifg=NONE guibg=NONE gui=underline
|
|
||||||
hi Directory ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi Folded ctermfg=242 ctermbg=235 cterm=NONE guifg=#75715e guibg=#272822 gui=NONE
|
|
||||||
|
|
||||||
hi Normal ctermfg=231 ctermbg=235 cterm=NONE guifg=#f8f8f2 guibg=#272822 gui=NONE
|
|
||||||
hi Boolean ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi Character ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi Comment ctermfg=242 ctermbg=NONE cterm=NONE guifg=#75715e guibg=NONE gui=NONE
|
|
||||||
hi Conditional ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi Constant ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi Define ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi DiffAdd ctermfg=231 ctermbg=64 cterm=bold guifg=#f8f8f2 guibg=#46830c gui=bold
|
|
||||||
hi DiffDelete ctermfg=88 ctermbg=NONE cterm=NONE guifg=#8b0807 guibg=NONE gui=NONE
|
|
||||||
hi DiffChange ctermfg=231 ctermbg=23 cterm=NONE guifg=#f8f8f2 guibg=#243955 gui=NONE
|
|
||||||
hi DiffText ctermfg=231 ctermbg=24 cterm=bold guifg=#f8f8f2 guibg=#204a87 gui=bold
|
|
||||||
hi ErrorMsg ctermfg=231 ctermbg=197 cterm=NONE guifg=#f8f8f0 guibg=#f92672 gui=NONE
|
|
||||||
hi WarningMsg ctermfg=231 ctermbg=197 cterm=NONE guifg=#f8f8f0 guibg=#f92672 gui=NONE
|
|
||||||
hi Float ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi Function ctermfg=148 ctermbg=NONE cterm=NONE guifg=#a6e22e guibg=NONE gui=NONE
|
|
||||||
hi Identifier ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=italic
|
|
||||||
hi Keyword ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi Label ctermfg=186 ctermbg=NONE cterm=NONE guifg=#e6db74 guibg=NONE gui=NONE
|
|
||||||
hi NonText ctermfg=59 ctermbg=236 cterm=NONE guifg=#49483e guibg=#31322c gui=NONE
|
|
||||||
hi Number ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi Operator ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi PreProc ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi Special ctermfg=231 ctermbg=NONE cterm=NONE guifg=#f8f8f2 guibg=NONE gui=NONE
|
|
||||||
hi SpecialKey ctermfg=59 ctermbg=237 cterm=NONE guifg=#49483e guibg=#3c3d37 gui=NONE
|
|
||||||
hi Statement ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi StorageClass ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=italic
|
|
||||||
hi String ctermfg=186 ctermbg=NONE cterm=NONE guifg=#e6db74 guibg=NONE gui=NONE
|
|
||||||
hi Tag ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi Title ctermfg=231 ctermbg=NONE cterm=bold guifg=#f8f8f2 guibg=NONE gui=bold
|
|
||||||
hi Todo ctermfg=95 ctermbg=NONE cterm=inverse,bold guifg=#75715e guibg=NONE gui=inverse,bold
|
|
||||||
hi Type ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi Underlined ctermfg=NONE ctermbg=NONE cterm=underline guifg=NONE guibg=NONE gui=underline
|
|
||||||
hi rubyClass ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi rubyFunction ctermfg=148 ctermbg=NONE cterm=NONE guifg=#a6e22e guibg=NONE gui=NONE
|
|
||||||
hi rubyInterpolationDelimiter ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi rubySymbol ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi rubyConstant ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=italic
|
|
||||||
hi rubyStringDelimiter ctermfg=186 ctermbg=NONE cterm=NONE guifg=#e6db74 guibg=NONE gui=NONE
|
|
||||||
hi rubyBlockParameter ctermfg=208 ctermbg=NONE cterm=NONE guifg=#fd971f guibg=NONE gui=italic
|
|
||||||
hi rubyInstanceVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi rubyInclude ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi rubyGlobalVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi rubyRegexp ctermfg=186 ctermbg=NONE cterm=NONE guifg=#e6db74 guibg=NONE gui=NONE
|
|
||||||
hi rubyRegexpDelimiter ctermfg=186 ctermbg=NONE cterm=NONE guifg=#e6db74 guibg=NONE gui=NONE
|
|
||||||
hi rubyEscape ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi rubyControl ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi rubyClassVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi rubyOperator ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi rubyException ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi rubyPseudoVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi rubyRailsUserClass ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=italic
|
|
||||||
hi rubyRailsARAssociationMethod ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=NONE
|
|
||||||
hi rubyRailsARMethod ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=NONE
|
|
||||||
hi rubyRailsRenderMethod ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=NONE
|
|
||||||
hi rubyRailsMethod ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=NONE
|
|
||||||
hi erubyDelimiter ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi erubyComment ctermfg=95 ctermbg=NONE cterm=NONE guifg=#75715e guibg=NONE gui=NONE
|
|
||||||
hi erubyRailsMethod ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=NONE
|
|
||||||
hi htmlTag ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi htmlEndTag ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi htmlTagName ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi htmlArg ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi htmlSpecialChar ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi javaScriptFunction ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=italic
|
|
||||||
hi javaScriptRailsFunction ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=NONE
|
|
||||||
hi javaScriptBraces ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi yamlKey ctermfg=197 ctermbg=NONE cterm=NONE guifg=#f92672 guibg=NONE gui=NONE
|
|
||||||
hi yamlAnchor ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi yamlAlias ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
hi yamlDocumentHeader ctermfg=186 ctermbg=NONE cterm=NONE guifg=#e6db74 guibg=NONE gui=NONE
|
|
||||||
hi cssURL ctermfg=208 ctermbg=NONE cterm=NONE guifg=#fd971f guibg=NONE gui=italic
|
|
||||||
hi cssFunctionName ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=NONE
|
|
||||||
hi cssColor ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi cssPseudoClassId ctermfg=148 ctermbg=NONE cterm=NONE guifg=#a6e22e guibg=NONE gui=NONE
|
|
||||||
hi cssClassName ctermfg=148 ctermbg=NONE cterm=NONE guifg=#a6e22e guibg=NONE gui=NONE
|
|
||||||
hi cssValueLength ctermfg=141 ctermbg=NONE cterm=NONE guifg=#ae81ff guibg=NONE gui=NONE
|
|
||||||
hi cssCommonAttr ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=NONE
|
|
||||||
hi cssBraces ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
|
|
||||||
1
vim/bundle/vim-obsession/.gitignore
vendored
1
vim/bundle/vim-obsession/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
/doc/tags
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
See the [contribution guidelines for pathogen.vim](https://github.com/tpope/vim-pathogen/blob/master/CONTRIBUTING.markdown).
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# obsession.vim
|
|
||||||
|
|
||||||
Vim features a `:mksession` command to write a file containing the current
|
|
||||||
state of Vim: window positions, open folds, stuff like that. For most of my
|
|
||||||
existence, I found the interface way too awkward and manual to be useful, but
|
|
||||||
I've recently discovered that the only thing standing between me and simple,
|
|
||||||
no-hassle Vim sessions is a few tweaks:
|
|
||||||
|
|
||||||
* Instead of making me remember to capture the session immediately before
|
|
||||||
exiting Vim, allow me to do it at any time, and automatically re-invoke
|
|
||||||
`:mksession` immediately before exit.
|
|
||||||
* Also invoke `:mksession` whenever the layout changes (in particular, on
|
|
||||||
`BufEnter`), so that even if Vim exits abnormally, I'm good to go.
|
|
||||||
* If I load an existing session, automatically keep it updated as above.
|
|
||||||
* If I try to create a new session on top of an existing session, don't refuse
|
|
||||||
to overwrite it. Just do what I mean.
|
|
||||||
* If I pass in a directory rather than a file name, just create a
|
|
||||||
`Session.vim` inside of it.
|
|
||||||
* Don't capture options and maps. Options are sometimes mutilated and maps
|
|
||||||
just interfere with updating plugins.
|
|
||||||
|
|
||||||
Use `:Obsess` (with optional file/directory name) to start recording to a
|
|
||||||
session file and `:Obsess!` to stop and throw it away. That's it. Load a
|
|
||||||
session in the usual manner: `vim -S`, or `:source` it.
|
|
||||||
|
|
||||||
## 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-obsession.git
|
|
||||||
|
|
||||||
## Self-Promotion
|
|
||||||
|
|
||||||
Like obsession.vim? Follow the repository on
|
|
||||||
[GitHub](https://github.com/tpope/vim-obsession) and vote for it on
|
|
||||||
[vim.org](http://www.vim.org/scripts/script.php?script_id=4472). 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`.
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
*obsession.txt* Continuously updated session files
|
|
||||||
|
|
||||||
Author: Tim Pope <http://tpo.pe/>
|
|
||||||
Repo: https://github.com/tpope/vim-obsession
|
|
||||||
License: Same terms as Vim itself (see |license|)
|
|
||||||
|
|
||||||
USAGE *obsession* *:Obsession*
|
|
||||||
|
|
||||||
:Obsession {file} Invoke |:mksession| on {file} and continue to keep it
|
|
||||||
updated until Vim exits, triggering on the |BufEnter|
|
|
||||||
and |VimLeavePre| autocommands. If the file exists,
|
|
||||||
it will be overwritten if and only if it looks like a
|
|
||||||
session file.
|
|
||||||
|
|
||||||
:Obsession {dir} Invoke |:Obsession| on {dir}/Session.vim. Use "." to
|
|
||||||
write to a session file in the current directory.
|
|
||||||
|
|
||||||
:Obsession If session tracking is already in progress, pause it.
|
|
||||||
Otherwise, resume tracking or create a new session in
|
|
||||||
the current directory.
|
|
||||||
|
|
||||||
:Obsession! Stop obsession and delete the underlying session file.
|
|
||||||
|
|
||||||
Loading a session created with |:Obsession| automatically resumes updates to
|
|
||||||
that file.
|
|
||||||
|
|
||||||
vim:tw=78:et:ft=help:norl:
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
" obsession.vim - Continuously updated session files
|
|
||||||
" Maintainer: Tim Pope <http://tpo.pe/>
|
|
||||||
" Version: 1.0
|
|
||||||
|
|
||||||
if exists("g:loaded_obsession") || v:version < 700 || &cp
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_obsession = 1
|
|
||||||
|
|
||||||
command! -bar -bang -complete=file -nargs=? Obsession execute s:dispatch(<bang>0, <q-args>)
|
|
||||||
|
|
||||||
function! s:dispatch(bang, file) abort
|
|
||||||
if a:bang && empty(a:file) && filereadable(get(g:, 'this_obsession', v:this_session))
|
|
||||||
echo 'Deleting session in '.fnamemodify(get(g:, 'this_obsession', v:this_session), ':~:.')
|
|
||||||
call delete(get(g:, 'this_obsession', v:this_session))
|
|
||||||
unlet! g:this_obsession
|
|
||||||
return ''
|
|
||||||
elseif empty(a:file) && exists('g:this_obsession')
|
|
||||||
echo 'Pausing session in '.fnamemodify(g:this_obsession, ':~:.')
|
|
||||||
unlet g:this_obsession
|
|
||||||
return ''
|
|
||||||
elseif empty(a:file) && !empty(v:this_session)
|
|
||||||
let file = v:this_session
|
|
||||||
elseif empty(a:file)
|
|
||||||
let file = getcwd() . '/Session.vim'
|
|
||||||
elseif isdirectory(a:file)
|
|
||||||
let file = fnamemodify(expand(a:file), ':p') . '/Session.vim'
|
|
||||||
else
|
|
||||||
let file = fnamemodify(expand(a:file), ':p')
|
|
||||||
endif
|
|
||||||
if !a:bang
|
|
||||||
\ && file !~# 'Session\.vim$'
|
|
||||||
\ && filereadable(file)
|
|
||||||
\ && getfsize(file) > 0
|
|
||||||
\ && readfile(file, '', 1)[0] !=# 'let SessionLoad = 1'
|
|
||||||
return 'mksession '.fnameescape(file)
|
|
||||||
endif
|
|
||||||
let g:this_obsession = file
|
|
||||||
let error = s:persist()
|
|
||||||
if empty(error)
|
|
||||||
echo 'Tracking session in '.fnamemodify(file, ':~:.')
|
|
||||||
let v:this_session = file
|
|
||||||
return ''
|
|
||||||
else
|
|
||||||
return error
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:persist()
|
|
||||||
if exists('g:this_obsession')
|
|
||||||
let sessionoptions = &sessionoptions
|
|
||||||
try
|
|
||||||
set sessionoptions-=options
|
|
||||||
execute 'mksession! '.fnameescape(g:this_obsession)
|
|
||||||
call writefile(insert(readfile(g:this_obsession), 'let g:this_obsession = v:this_session', -2), g:this_obsession)
|
|
||||||
catch
|
|
||||||
unlet g:this_obsession
|
|
||||||
return 'echoerr '.string(v:exception)
|
|
||||||
finally
|
|
||||||
let &sessionoptions = sessionoptions
|
|
||||||
endtry
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
augroup obsession
|
|
||||||
autocmd!
|
|
||||||
autocmd BufEnter,VimLeavePre * exe s:persist()
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
" vim:set et sw=2:
|
|
||||||
3
vim/bundle/vim-rails/.gitignore
vendored
3
vim/bundle/vim-rails/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
/rails.zip
|
|
||||||
/rails.vba
|
|
||||||
/doc/tags
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
If your [commit message sucks][suck], I'm not going to accept your pull
|
|
||||||
request. I've explained very politely dozens of times that [my general
|
|
||||||
guidelines][guidelines] 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` and `git push -f`.
|
|
||||||
|
|
||||||
If a feature idea is nontrivial, you should probably open an issue to [discuss
|
|
||||||
it][] before attempting a pull request. One of the biggest challenges in
|
|
||||||
maintaining rails.vim has been beating back the bloat, so do not assume that
|
|
||||||
your idea will make the cut. And if I like your idea, I'm generally amenable
|
|
||||||
to just knocking it out myself, rather than making you familiarize yourself
|
|
||||||
with a 4 thousand line code base.
|
|
||||||
|
|
||||||
[suck]: http://stopwritingramblingcommitmessages.com/
|
|
||||||
[guidelines]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
|
||||||
[discuss it]: http://www.igvita.com/2011/12/19/dont-push-your-pull-requests/
|
|
||||||
|
|
@ -1,135 +0,0 @@
|
||||||
# rails.vim
|
|
||||||
|
|
||||||
Remember when everybody and their mother was using TextMate for Ruby on
|
|
||||||
Rails development? Well if it wasn't for rails.vim, we'd still be in
|
|
||||||
that era. So shut up and pay some respect. And check out these
|
|
||||||
features:
|
|
||||||
|
|
||||||
* Easy navigation of the Rails directory structure. `gf` considers
|
|
||||||
context and knows about partials, fixtures, and much more. There are
|
|
||||||
two commands, `:A` (alternate) and `:R` (related) for easy jumping
|
|
||||||
between files, including favorites like model to schema, template to
|
|
||||||
helper, and controller to functional test. Commands like `:Emodel`,
|
|
||||||
`:Eview`, `:Econtroller`, are provided to `:edit` files by type, along
|
|
||||||
with `S`, `V`, and `T` variants for `:split`, `:vsplit`, and
|
|
||||||
`:tabedit`. Throw a bang on the end (`:Emodel foo!`) to automatically
|
|
||||||
create the file with the standard boilerplate if it doesn't exist.
|
|
||||||
`:help rails-navigation`
|
|
||||||
|
|
||||||
* Enhanced syntax highlighting. From `has_and_belongs_to_many` to
|
|
||||||
`distance_of_time_in_words`, it's here. For easy completion of these
|
|
||||||
long method names, `'completefunc'` is set to enable syntax based
|
|
||||||
completion on CTRL-X CTRL-U.
|
|
||||||
|
|
||||||
* Interface to rake. Use `:Rake` to run the current test, spec, or
|
|
||||||
feature. Use `:.Rake` to do a focused run of just the method,
|
|
||||||
example, or scenario on the current line. `:Rake` can also run
|
|
||||||
arbitrary migrations, load individual fixtures, and more.
|
|
||||||
`:help rails-rake`
|
|
||||||
|
|
||||||
* Interface to the `rails` command. Generally, use `:Rails console` to
|
|
||||||
call `rails console`. Many commands have wrappers with additional features:
|
|
||||||
`:Rgenerate controller Blog` generates a blog controller and loads the
|
|
||||||
generated files into the quickfix list, and `:Rrunner` wraps `rails runner`
|
|
||||||
and doubles as a direct test runner. `:help rails-scripts`
|
|
||||||
|
|
||||||
* Partial and concern extraction. In a view, `:Rextract {file}`
|
|
||||||
replaces the desired range (typically selected in visual line mode)
|
|
||||||
with `render '{file}'`, which is automatically created with your
|
|
||||||
content. In a model or controller, a concern is created, with the
|
|
||||||
appropriate `include` declaration left behind.
|
|
||||||
`:help rails-:Rextract`
|
|
||||||
|
|
||||||
* Fully customizable. Define "projections" at the global, app, or gem
|
|
||||||
level to define navigation commands and override the alternate file,
|
|
||||||
default rake task, syntax highlighting, abbreviations, and more.
|
|
||||||
`:help rails-projections`.
|
|
||||||
|
|
||||||
* Integration with other plugins. If
|
|
||||||
[dbext.vim](http://www.vim.org/scripts/script.php?script_id=356) is
|
|
||||||
installed, it will be transparently configured to reflect
|
|
||||||
`database.yml`. Users of
|
|
||||||
[abolish.vim](https://github.com/tpope/vim-abolish) get pluralize and
|
|
||||||
tableize coercions, and users of
|
|
||||||
[bundler.vim](https://github.com/tpope/vim-bundler) get a smattering of
|
|
||||||
features. `:help rails-integration`
|
|
||||||
|
|
||||||
## 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-rails.git
|
|
||||||
git clone git://github.com/tpope/vim-bundler.git
|
|
||||||
|
|
||||||
You don't strictly need [bundler.vim][], but it helps.
|
|
||||||
|
|
||||||
Once help tags have been generated, you can view the manual with
|
|
||||||
`:help rails`.
|
|
||||||
|
|
||||||
[bundler.vim]: https://github.com/tpope/vim-bundler
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
> I installed the plugin and started Vim. Why does only the `:Rails`
|
|
||||||
> command exist?
|
|
||||||
|
|
||||||
This plugin cares about the current file, not the current working
|
|
||||||
directory. Edit a file from a Rails application.
|
|
||||||
|
|
||||||
> I opened a new tab. Why does only the `:Rails` command exist?
|
|
||||||
|
|
||||||
This plugin cares about the current file, not the current working
|
|
||||||
directory. Edit a file from a Rails application. You can use the `:RT`
|
|
||||||
family of commands to open a new tab and edit a file at the same time.
|
|
||||||
|
|
||||||
> Can I use rails.vim to edit Rails engines?
|
|
||||||
|
|
||||||
It's not supported, but if you `touch config/environment.rb` in the root
|
|
||||||
of the engine, things should mostly work.
|
|
||||||
|
|
||||||
> Can I use rails.vim to edit other Ruby projects?
|
|
||||||
|
|
||||||
I wrote [rake.vim](https://github.com/tpope/vim-rake) for exactly that
|
|
||||||
purpose. It activates for any project with a `Rakefile` that's not a
|
|
||||||
Rails application.
|
|
||||||
|
|
||||||
> What Rails versions are supported?
|
|
||||||
|
|
||||||
All of them. A few features like syntax highlighting tend to reflect the
|
|
||||||
latest version only.
|
|
||||||
|
|
||||||
> Rake is slow. How about making `:Rake` run
|
|
||||||
> `testrb`/`rspec`/`cucumber` directly instead of `rake`?
|
|
||||||
|
|
||||||
Well then it wouldn't make sense to call it `:Rake`, now, would it?
|
|
||||||
Maybe one day I'll add a separate `:Run` command or something. In the
|
|
||||||
meantime, here's how you can set up `:make` to run the current test:
|
|
||||||
|
|
||||||
autocmd FileType cucumber compiler cucumber | setl makeprg=cucumber\ \"%:p\"
|
|
||||||
autocmd FileType ruby
|
|
||||||
\ if expand('%') =~# '_test\.rb$' |
|
|
||||||
\ compiler rubyunit | setl makeprg=testrb\ \"%:p\" |
|
|
||||||
\ elseif expand('%') =~# '_spec\.rb$' |
|
|
||||||
\ compiler rspec | setl makeprg=rspec\ \"%:p\" |
|
|
||||||
\ else |
|
|
||||||
\ compiler ruby | setl makeprg=ruby\ -wc\ \"%:p\" |
|
|
||||||
\ endif
|
|
||||||
autocmd User Bundler
|
|
||||||
\ if &makeprg !~# 'bundle' | setl makeprg^=bundle\ exec\ | endif
|
|
||||||
|
|
||||||
## Self-Promotion
|
|
||||||
|
|
||||||
Like rails.vim? Follow the repository on
|
|
||||||
[GitHub](https://github.com/tpope/vim-rails) and vote for it on
|
|
||||||
[vim.org](http://www.vim.org/scripts/script.php?script_id=1567). 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`.
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,930 +0,0 @@
|
||||||
*rails.txt* Plugin for working with Ruby on Rails applications
|
|
||||||
|
|
||||||
Author: Tim Pope <http://tpo.pe/>
|
|
||||||
|
|
||||||
|rails-introduction| Introduction and Feature Summary
|
|
||||||
|rails-commands| General Commands
|
|
||||||
|rails-navigation| Navigation
|
|
||||||
|rails-gf| File Under Cursor - gf
|
|
||||||
|rails-alternate-related| Alternate and Related Files
|
|
||||||
|rails-type-navigation| File Type Commands
|
|
||||||
|rails-rake| Rake
|
|
||||||
|rails-scripts| Script Wrappers
|
|
||||||
|rails-refactoring| Refactoring Helpers
|
|
||||||
|rails-partials| Partial Extraction
|
|
||||||
|rails-migrations| Migration Inversion
|
|
||||||
|rails-integration| Integration
|
|
||||||
|rails-vim-integration| Integration with the Vim Universe
|
|
||||||
|rails-rails-integration| Integration with the Rails Universe
|
|
||||||
|rails-abbreviations| Abbreviations
|
|
||||||
|rails-syntax| Syntax Highlighting
|
|
||||||
|rails-options| Managed Vim Options
|
|
||||||
|rails-projections| Projections
|
|
||||||
|rails-configuration| Configuration
|
|
||||||
|rails-global-settings| Global Settings
|
|
||||||
|rails-about| About rails.vim
|
|
||||||
|rails-license| License
|
|
||||||
|
|
||||||
This plugin is only available if 'compatible' is not set.
|
|
||||||
|
|
||||||
{Vi does not have any of this}
|
|
||||||
|
|
||||||
INTRODUCTION *rails-introduction* *rails*
|
|
||||||
|
|
||||||
Whenever you edit a file in a Rails application, this plugin will be
|
|
||||||
automatically activated. This sets various options and defines a few
|
|
||||||
buffer-specific commands.
|
|
||||||
|
|
||||||
If you are in a hurry to get started, with a minimal amount of reading, you
|
|
||||||
are encouraged to at least skim through the headings and command names in this
|
|
||||||
file, to get a better idea of what is offered. If you only read one thing,
|
|
||||||
make sure it is the navigation section: |rails-navigation|.
|
|
||||||
|
|
||||||
GENERAL COMMANDS *rails-commands*
|
|
||||||
|
|
||||||
All commands are buffer local, unless otherwise stated. This means you must
|
|
||||||
actually edit a file from a Rails application.
|
|
||||||
|
|
||||||
*rails-:Rails-new*
|
|
||||||
:Rails new {directory} The only global command. Invokes "rails new
|
|
||||||
{directory}" and loads the generated files into the
|
|
||||||
quickfix list.
|
|
||||||
|
|
||||||
*rails-:Rails!*
|
|
||||||
:Rails! Show the version of rails.vim installed. If rails.vim
|
|
||||||
is active for the current buffer, also show the type
|
|
||||||
of Rails file detected.
|
|
||||||
|
|
||||||
*rails-:Redit*
|
|
||||||
:Redit {file} Obsolete alias for |:R| or |:A|.
|
|
||||||
|
|
||||||
*rails-:Rfind*
|
|
||||||
:Rfind [{file}] Obsolete alias for |:find|.
|
|
||||||
|
|
||||||
*rails-:Rlog*
|
|
||||||
:Rlog [{logfile}] Split window and open {logfile} ($RAILS_ENV or
|
|
||||||
development by default). The control characters used
|
|
||||||
for highlighting are removed. If you have a :Tail
|
|
||||||
command (provided by |tailminusf|.vim), that is used;
|
|
||||||
otherwise, the file does NOT reload upon change.
|
|
||||||
Use |:checktime| to tell Vim to check for changes.
|
|
||||||
|G| has been mapped to do just that prior to jumping
|
|
||||||
to the end of the file, and q is mapped to close the
|
|
||||||
window. If the delay in loading is too long, you
|
|
||||||
might like :Rake log:clear.
|
|
||||||
|
|
||||||
*rails-:Rpreview*
|
|
||||||
:Rpreview [path] Open the given [path] for the current app in a
|
|
||||||
browser. The host and port are determined by applying
|
|
||||||
some netstat/lsof trickery to the current server pid.
|
|
||||||
If no server is running, Pow is consulted, and if all
|
|
||||||
else fails, a default of localhost:3000 is used. If
|
|
||||||
[path] is omitted, a sensible default is used
|
|
||||||
(considers the current controller/template, but does
|
|
||||||
not take routing into account). The default is
|
|
||||||
overridden by comments like the following that are
|
|
||||||
either before the current method call or at the top of
|
|
||||||
the file: >
|
|
||||||
|
|
||||||
# GET /users
|
|
||||||
# PUT /users/1
|
|
||||||
<
|
|
||||||
If it's not using the right browser, define an OpenURL
|
|
||||||
command:
|
|
||||||
>
|
|
||||||
:command -bar -nargs=1 OpenURL :!open <args>
|
|
||||||
<
|
|
||||||
*rails-:Rpreview!*
|
|
||||||
:Rpreview! [{path}] Like :Rpreview, but open the path inside Vim using
|
|
||||||
|netrw| instead.
|
|
||||||
|
|
||||||
*rails-:Rrefresh*
|
|
||||||
:Rrefresh Refreshes certain cached settings. Most noticeably,
|
|
||||||
this clears the cached list of classes that are syntax
|
|
||||||
highlighted as railsUserClass.
|
|
||||||
|
|
||||||
*rails-:Rrefresh!*
|
|
||||||
:Rrefresh! As above, and also reloads rails.vim.
|
|
||||||
|
|
||||||
*rails-:Cd* *rails-:Rcd*
|
|
||||||
:Cd [{directory}] |:cd| to /path/to/railsapp/{directory}.
|
|
||||||
|
|
||||||
*rails-:Lcd* *rails-:Rlcd*
|
|
||||||
:Lcd [{directory}] |:lcd| to /path/to/railsapp/{directory}.
|
|
||||||
|
|
||||||
*rails-:Ctags* *rails-:Rtags*
|
|
||||||
:Ctags Calls ctags -R on the current application root.
|
|
||||||
Exuberant ctags must be installed. Additional
|
|
||||||
arguments can be passed to ctags with
|
|
||||||
|g:rails_ctags_arguments|.
|
|
||||||
|
|
||||||
NAVIGATION *rails-navigation*
|
|
||||||
|
|
||||||
Navigation is where the real power of this plugin lies. Efficient use of the
|
|
||||||
following features will greatly ease navigating the Rails file structure.
|
|
||||||
|
|
||||||
The standard Rails load path is prepended to 'path', enabling |:find| to work:
|
|
||||||
>
|
|
||||||
:find application_controller.rb
|
|
||||||
<
|
|
||||||
File Under Cursor - gf ~
|
|
||||||
*rails-gf*
|
|
||||||
The |gf| command, which normally edits the current file under the cursor, has
|
|
||||||
been remapped to take context into account. |CTRL-W_f| (open in new window)
|
|
||||||
and |CTRL-W_gf| (open in new tab) are also remapped.
|
|
||||||
|
|
||||||
Example uses of |gf|, and where they might lead.
|
|
||||||
(* indicates cursor position)
|
|
||||||
>
|
|
||||||
Pos*t.first
|
|
||||||
< app/models/post.rb ~
|
|
||||||
>
|
|
||||||
has_many :c*omments
|
|
||||||
< app/models/comment.rb ~
|
|
||||||
>
|
|
||||||
link_to 'Home', :controller => 'bl*og'
|
|
||||||
< app/controllers/blog_controller.rb ~
|
|
||||||
>
|
|
||||||
<%= render 'sh*ared/sidebar' %>
|
|
||||||
< app/views/shared/_sidebar.html.erb ~
|
|
||||||
>
|
|
||||||
<%= stylesheet_link_tag 'scaf*fold' %>
|
|
||||||
< public/stylesheets/scaffold.css ~
|
|
||||||
>
|
|
||||||
class BlogController < Applica*tionController
|
|
||||||
< app/controllers/application_controller.rb ~
|
|
||||||
>
|
|
||||||
class ApplicationController < ActionCont*roller::Base
|
|
||||||
< .../action_controller/base.rb ~
|
|
||||||
>
|
|
||||||
fixtures :pos*ts
|
|
||||||
< test/fixtures/posts.yml ~
|
|
||||||
>
|
|
||||||
layout :pri*nt
|
|
||||||
< app/views/layouts/print.html.erb ~
|
|
||||||
>
|
|
||||||
<%= link_to "New", new_comme*nt_path %>
|
|
||||||
< app/controllers/comments_controller.rb (jumps to def new) ~
|
|
||||||
|
|
||||||
In the last example, the controller and action for the named route are
|
|
||||||
determined by evaluating routes.rb as Ruby and doing some introspection. This
|
|
||||||
means code from the application is executed. Keep this in mind when
|
|
||||||
navigating unfamiliar applications.
|
|
||||||
|
|
||||||
Alternate and Related Files ~
|
|
||||||
*rails-alternate-related*
|
|
||||||
Two commands, :A and :R, are used to quickly jump to an "alternate" and a
|
|
||||||
"related" file, defined below.
|
|
||||||
|
|
||||||
*rails-:A* *rails-:AE* *rails-:AS* *rails-:AV* *rails-:AT* *rails-:AD*
|
|
||||||
:A These commands were picked to mimic Michael Sharpe's
|
|
||||||
:AE a.vim. Briefly, they edit the "alternate" file, in
|
|
||||||
:AS either the same window (:A and :AE), a new split
|
|
||||||
:AV window (:AS), a new vertically split window (:AV), a
|
|
||||||
:AT new tab (:AT), or read it into the current buffer
|
|
||||||
:AD (:AD).
|
|
||||||
|
|
||||||
*rails-:R* *rails-:RE* *rails-:RS* *rails-:RV* *rails-:RT* *rails-:RD*
|
|
||||||
:R These are similar |rails-:A| and friends above, only
|
|
||||||
:RE they jump to the "related" file rather than the
|
|
||||||
:RS "alternate." With a file name argument, they edit
|
|
||||||
:RV a file relative to the application root (:R Rakefile),
|
|
||||||
:RT and with a count and a file name argument, they find a
|
|
||||||
:RD file in 'path' (e.g., :1R PostsController.) You can
|
|
||||||
also append a line number (post.rb:42) or a method
|
|
||||||
(PostsController#index) to both forms.
|
|
||||||
|
|
||||||
*rails-alternate* *rails-related*
|
|
||||||
The alternate file is most frequently the test file, though there are
|
|
||||||
exceptions. The related file varies, and is sometimes dependent on current
|
|
||||||
location in the file. For example, when editing a controller, the related
|
|
||||||
file is template for the method currently being edited.
|
|
||||||
|
|
||||||
The easiest way to learn these commands is to experiment. A few examples of
|
|
||||||
alternate and related files for a Test::Unit application follow:
|
|
||||||
|
|
||||||
Current file Alternate file Related file ~
|
|
||||||
model unit test schema definition
|
|
||||||
controller (in method) functional test template (view)
|
|
||||||
template (view) functional test controller (jump to method)
|
|
||||||
migration previous migration next migration
|
|
||||||
database.yml database.example.yml environments/*.rb
|
|
||||||
|
|
||||||
Alternates can be tweaked with |rails-projections|.
|
|
||||||
|
|
||||||
File Type Navigation Commands ~
|
|
||||||
*rails-type-navigation*
|
|
||||||
For the less common cases, a more deliberate set of commands are provided.
|
|
||||||
Each of the upcoming commands takes an optional argument (with tab completion)
|
|
||||||
but defaults to a reasonable guess. Commands that default to the current
|
|
||||||
model or controller generally behave like you'd expect in other file types.
|
|
||||||
For example, in app/helpers/posts_helper.rb, the current controller is
|
|
||||||
"posts", and in test/fixtures/comments.yml, the current model is "comment".
|
|
||||||
In model related files, the current controller is the pluralized model name,
|
|
||||||
and in controller related files, the current model is the singularized
|
|
||||||
controller name.
|
|
||||||
|
|
||||||
Each of the following commands has variants for splitting, vertical splitting,
|
|
||||||
opening in a new tab, and reading the file into the current buffer. For
|
|
||||||
:Emodel, those variants would be :Smodel, :Vmodel, :Tmodel, and :Dmodel.
|
|
||||||
They also allow for jumping to methods or line numbers using the same syntax
|
|
||||||
as |:R|, and file creation (with a bit of boilerplate) can be forced by adding
|
|
||||||
a ! after the filename (not after the command itself!).
|
|
||||||
|
|
||||||
There are also "classic" versions of these commands that start with :R (e.g.,
|
|
||||||
:Rmodel, :RSmodel, :RVmodel, :RTmodel, and :RDmodel).
|
|
||||||
|
|
||||||
:Econtroller |rails-:Econtroller|
|
|
||||||
:Eenvironment |rails-:Eenvironment|
|
|
||||||
:Efixtures |rails-:Efixtures|
|
|
||||||
:Efunctionaltest |rails-:Efunctionaltest|
|
|
||||||
:Ehelper |rails-:Ehelper|
|
|
||||||
:Einitializer |rails-:Einitializer|
|
|
||||||
:Eintegrationtest |rails-:Eintegrationtest|
|
|
||||||
:Ejavascript |rails-:Ejavascript|
|
|
||||||
:Elayout |rails-:Elayout|
|
|
||||||
:Elib |rails-:Elib|
|
|
||||||
:Elocale |rails-:Elocale|
|
|
||||||
:Emailer |rails-:Emailer|
|
|
||||||
:Emigration |rails-:Emigration|
|
|
||||||
:Emodel |rails-:Emodel|
|
|
||||||
:Eschema |rails-:Eschema|
|
|
||||||
:Espec |rails-:Espec|
|
|
||||||
:Estylesheet |rails-:Estylesheet|
|
|
||||||
:Etask |rails-:Etask|
|
|
||||||
:Eunittest |rails-:Eunittest|
|
|
||||||
:Eview |rails-:Eview|
|
|
||||||
|
|
||||||
*rails-:Econtroller* *rails-:Rcontroller*
|
|
||||||
:Econtroller [{name}] Edit the specified or current controller.
|
|
||||||
|
|
||||||
*rails-:Eenvironment* *rails-:Renvironment*
|
|
||||||
:Eenvironment [{name}] Edit the config/environments file specified. With no
|
|
||||||
argument, defaults to editing config/application.rb
|
|
||||||
or config/environment.rb.
|
|
||||||
|
|
||||||
*rails-:Efixtures* *rails-:Rfixtures*
|
|
||||||
:Efixtures [{name}] Edit the fixtures for the given or current model. If
|
|
||||||
an argument is given, it must be pluralized, like the
|
|
||||||
final filename (this may change in the future). If
|
|
||||||
omitted, the current model is pluralized. An optional
|
|
||||||
extension can be given, to distinguish between YAML
|
|
||||||
and CSV fixtures.
|
|
||||||
|
|
||||||
*rails-:Efunctionaltest* *rails-:Rfunctionaltest*
|
|
||||||
:Efunctionaltest [{name}]
|
|
||||||
Edit the functional test or controller spec for the
|
|
||||||
specified or current controller.
|
|
||||||
|
|
||||||
*rails-:Ehelper* *rails-:Rhelper*
|
|
||||||
:Ehelper [{name}] Edit the helper for the specified name or current
|
|
||||||
controller.
|
|
||||||
|
|
||||||
*rails-:Einitializer* *rails-:Rinitializer*
|
|
||||||
:Einitializer [{name}] Edit the config/initializers file specified. With no
|
|
||||||
argument, defaults to editing config/routes.rb.
|
|
||||||
|
|
||||||
*rails-:Eintegrationtest* *rails-:Rintegrationtest*
|
|
||||||
:Eintegrationtest [{name}]
|
|
||||||
Edit the integration test, integration spec, or
|
|
||||||
cucumber feature specified. With no argument,
|
|
||||||
defaults to editing test/test_helper.rb.
|
|
||||||
|
|
||||||
*rails-:Ejavascript* *rails-:Rjavascript*
|
|
||||||
:Ejavascript [{name}] Edit the JavaScript for the specified name or current
|
|
||||||
controller. Also supports CoffeeScript in
|
|
||||||
app/scripts/.
|
|
||||||
|
|
||||||
*rails-:Elayout* *rails-:Rlayout*
|
|
||||||
:Elayout [{name}] Edit the specified layout. Defaults to the layout for
|
|
||||||
the current controller, or the application layout if
|
|
||||||
that cannot be found. A new layout will be created if
|
|
||||||
an extension is given.
|
|
||||||
|
|
||||||
*rails-:Elib* *rails-:Rlib*
|
|
||||||
:Elib [{name}] Edit the library from the lib directory for the
|
|
||||||
specified name. With no argument, defaults to editing
|
|
||||||
the application Gemfile (a task formally handled by
|
|
||||||
the defunct :Rplugin).
|
|
||||||
|
|
||||||
*rails-:Elocale* *rails-:Rlocale*
|
|
||||||
:Elocale [{name}] Edit the config/locale file specified, optionally
|
|
||||||
adding a yml or rb extension if none is given. With
|
|
||||||
no argument, checks config/environment.rb for the
|
|
||||||
default locale.
|
|
||||||
|
|
||||||
*rails-:Emailer* *rails-:Rmailer*
|
|
||||||
:Emailer [{name}] Edit the mailer specified. This looks in both
|
|
||||||
app/mailers for Rails 3 and app/models for older
|
|
||||||
versions of Rails but only tab completes the former.
|
|
||||||
|
|
||||||
*rails-:Emigration* *rails-:Rmigration*
|
|
||||||
:Emigration [{pattern}] If {pattern} is a number, find the migration for that
|
|
||||||
particular set of digits, zero-padding if necessary.
|
|
||||||
Otherwise, find the newest migration containing the
|
|
||||||
given pattern. Omitting the pattern selects the
|
|
||||||
latest migration. Give a numeric argument of 0 to edit
|
|
||||||
db/seeds.rb.
|
|
||||||
|
|
||||||
*rails-:Emodel* *rails-:Rmodel*
|
|
||||||
:Emodel [{name}] Edit the specified or current model.
|
|
||||||
|
|
||||||
*rails-:Espec* *rails-:Rspec*
|
|
||||||
:Espec [{name}] Edit the given spec. With no argument, defaults to
|
|
||||||
editing spec/spec_helper.rb (If you want to jump to
|
|
||||||
the spec for the given file, use |:A| instead). This
|
|
||||||
command is only defined if there is a spec folder in
|
|
||||||
the root of the application.
|
|
||||||
|
|
||||||
*rails-:Eschema* *rails-:Rschema*
|
|
||||||
:Eschema [{table}] Edit the schema and optionally jump to the specified
|
|
||||||
table.
|
|
||||||
|
|
||||||
*rails-:Estylesheet* *rails-:Rstylesheet*
|
|
||||||
:Estylesheet [{name}] Edit the stylesheet for the specified name or current
|
|
||||||
controller. Also supports Sass and SCSS.
|
|
||||||
|
|
||||||
*rails-:Etask* *rails-:Rtask*
|
|
||||||
:Etask [{name}] Edit the .rake file from lib/tasks for the specified
|
|
||||||
name. If no argument is given, the application
|
|
||||||
Rakefile is edited.
|
|
||||||
|
|
||||||
*rails-:Eunittest* *rails-:Runittest*
|
|
||||||
:Eunittest [{name}] Edit the unit test or model spec for the specified
|
|
||||||
name or current model.
|
|
||||||
|
|
||||||
*rails-:Eview* *rails-:Rview*
|
|
||||||
:Eview [[{controller}/]{view}]
|
|
||||||
Edit the specified view. The controller will default
|
|
||||||
sensibly, and the view name can be omitted when
|
|
||||||
editing a method of a controller. If a view name is
|
|
||||||
given with an extension, a new file will be created.
|
|
||||||
This is a quick way to create a new view.
|
|
||||||
|
|
||||||
Finally, one Vim feature that proves helpful in conjunction with all of the
|
|
||||||
above is |CTRL-^|. This keystroke edits the previous file, and is helpful to
|
|
||||||
back out of any of the above commands.
|
|
||||||
|
|
||||||
RAKE *rails-rake*
|
|
||||||
|
|
||||||
Rake integration happens through the :Rake command.
|
|
||||||
|
|
||||||
*rails-:Rake*
|
|
||||||
:[range]Rake {targets} Calls |:make!| {targets} (with 'makeprg' being rake,
|
|
||||||
or `bundle exec rake` if bundler.vim is active) and
|
|
||||||
opens the quickfix window if there were any errors.
|
|
||||||
An argument of "-" reruns the last task. If {targets}
|
|
||||||
are omitted, :Rake defaults to something sensible as
|
|
||||||
described below. Giving a line number argument may
|
|
||||||
affect that default.
|
|
||||||
|
|
||||||
*rails-:Rake!*
|
|
||||||
:[range]Rake! {targets} Called with a bang, :Rake will forgo opening the
|
|
||||||
quickfix window.
|
|
||||||
|
|
||||||
*rails-rake-defaults*
|
|
||||||
|
|
||||||
Generally, the default task is one that runs the test you'd expect. For
|
|
||||||
example, if you're in a view in an RSpec application, the view spec is run,
|
|
||||||
but if it's a Test::Unit application, the functional test for the
|
|
||||||
corresponding controller is run. The following table lists the most
|
|
||||||
interesting mappings:
|
|
||||||
|
|
||||||
File Task ~
|
|
||||||
unit test test:units TEST=...
|
|
||||||
functional test test:functionals TEST=...
|
|
||||||
integration test test:integration TEST=...
|
|
||||||
spec spec SPEC=...
|
|
||||||
feature cucumber FEATURE=...
|
|
||||||
model test:units TEST=... spec SPEC=...
|
|
||||||
controller test:functionals TEST=... spec SPEC=...
|
|
||||||
helper test:functionals TEST=... spec SPEC=...
|
|
||||||
view test:functionals TEST=... spec SPEC=...
|
|
||||||
fixtures db:fixtures:load FIXTURES=...
|
|
||||||
migration db:migrate VERSION=...
|
|
||||||
config/routes.rb routes
|
|
||||||
db/seeds.rb db:seed
|
|
||||||
|
|
||||||
Additionally, when :Rake is given a line number (e.g., :.Rake), the following
|
|
||||||
additional tasks can be invoked:
|
|
||||||
|
|
||||||
File Task ~
|
|
||||||
unit test test:units TEST=... TESTOPTS=-n...
|
|
||||||
functional test test:functionals TEST=... TESTOPTS=-n...
|
|
||||||
integration test test:integration TEST=... TESTOPTS=-n...
|
|
||||||
spec spec SPEC=...:...
|
|
||||||
feature cucumber FEATURE=...:...
|
|
||||||
controller routes CONTROLLER=...
|
|
||||||
fixtures db:fixtures:identify LABEL=...
|
|
||||||
migration in self.up db:migrate:up VERSION=...
|
|
||||||
migration in self.down db:migrate:down VERSION=...
|
|
||||||
migration elsewhere db:migrate:redo VERSION=...
|
|
||||||
task ... (try to guess currently edited declaration)
|
|
||||||
|
|
||||||
Finally, you can override the default task with a comment like "# rake ..."
|
|
||||||
before the method pointed to by [range] or at the top of the file.
|
|
||||||
|
|
||||||
SCRIPT WRAPPERS *rails-scripts*
|
|
||||||
|
|
||||||
The following commands are wrappers around the scripts in the script directory
|
|
||||||
of the Rails application. Most have extra features beyond calling the script.
|
|
||||||
A limited amount of completion with <Tab> is supported.
|
|
||||||
|
|
||||||
|
|
||||||
*rails-:Rails*
|
|
||||||
:Rails {command} [options]
|
|
||||||
Depending on the Rails version, invoke one of
|
|
||||||
"bin/rails {command}", "script/rails {command}", or
|
|
||||||
"script/{command}".
|
|
||||||
|
|
||||||
*rails-:Rscript*
|
|
||||||
:Rscript {command} [options]
|
|
||||||
Deprecated alias for |:Rails| {command}. Defaults to
|
|
||||||
calling |:Rails| console.
|
|
||||||
|
|
||||||
*rails-:Rrunner*
|
|
||||||
:[range]Rrunner [file] Run the given file or code with rails runner and load
|
|
||||||
:Rrunner {code} the results in to the quickfix list, using the error
|
|
||||||
parser from the "ruby" |:compiler|. If the file looks
|
|
||||||
like a test, spec, or cucumber feature, the
|
|
||||||
"rubyunit", "rspec", or "cucumber" |:compiler| will be
|
|
||||||
used instead. If provided, [range] is passed to the
|
|
||||||
test runner to restrict execution to a particular
|
|
||||||
line. With no argument, defaults to running the test
|
|
||||||
for the current file.
|
|
||||||
|
|
||||||
*rails-:Rp*
|
|
||||||
:[range]Rp {code} Use rails runner to execute "p begin {code} end" and
|
|
||||||
echo the result.
|
|
||||||
|
|
||||||
*rails-:Rpp*
|
|
||||||
:[range]Rpp {code} Like :Rp, but with pp (pretty print).
|
|
||||||
|
|
||||||
*rails-:Rgenerate*
|
|
||||||
:Rgenerate {options} Calls rails generate {options} and loads the
|
|
||||||
generated files into the quickfix list. Use ! to
|
|
||||||
surpress jumping to the first file.
|
|
||||||
|
|
||||||
*rails-:Rdestroy*
|
|
||||||
:Rdestroy {options} Calls rails destroy {options} and loads the destroyed
|
|
||||||
files into the quickfix list.
|
|
||||||
|
|
||||||
*rails-:Rserver*
|
|
||||||
:Rserver {options} Launches rails server {options} in the background.
|
|
||||||
On win32, this means |!start|. Otherwise, the
|
|
||||||
--daemon option is passed in.
|
|
||||||
|
|
||||||
*rails-:Rserver!*
|
|
||||||
:Rserver! {options} Kill the pid found in tmp/pids/server.pid and then
|
|
||||||
invoke |:Rserver|.
|
|
||||||
|
|
||||||
REFACTORING HELPERS *rails-refactoring*
|
|
||||||
|
|
||||||
A few features are dedicated to helping you refactor your code.
|
|
||||||
|
|
||||||
Partial Extraction ~
|
|
||||||
*rails-partials*
|
|
||||||
|
|
||||||
The :Rextract command can be used to extract part of a view to a partial, part
|
|
||||||
of a helper to another helper, or part of a model or controller to a concern.
|
|
||||||
|
|
||||||
*rails-:Rextract*
|
|
||||||
:[range]Rextract [{controller}/]{name}
|
|
||||||
Create a {name} partial from [range] lines (default:
|
|
||||||
current line). Only available in views.
|
|
||||||
|
|
||||||
:[range]Rextract {helper}
|
|
||||||
Create a {name} helper from [range] lines (default:
|
|
||||||
current line). Only available in helpers.
|
|
||||||
|
|
||||||
:[range]Rextract {concern}
|
|
||||||
Create a {name} concern from [range] lines (default:
|
|
||||||
current line). Only available in models and
|
|
||||||
controllers.
|
|
||||||
|
|
||||||
If this is your file, in app/views/blog/show.html.erb: >
|
|
||||||
|
|
||||||
1 <div>
|
|
||||||
2 <h2><%= @post.title %></h2>
|
|
||||||
3 <p><%= @post.body %></p>
|
|
||||||
4 </div>
|
|
||||||
|
|
||||||
And you issue this command: >
|
|
||||||
|
|
||||||
:2,3Rextract post
|
|
||||||
|
|
||||||
Your file will change to this: >
|
|
||||||
|
|
||||||
1 <div>
|
|
||||||
2 <%= render 'post' %>
|
|
||||||
3 </div>
|
|
||||||
|
|
||||||
And app/views/blog/_post.html.erb will now contain: >
|
|
||||||
|
|
||||||
1 <h2><%= @post.title %></h2>
|
|
||||||
2 <p><%= @post.body %></p>
|
|
||||||
<
|
|
||||||
The easiest way to choose what to extract is to use |linewise-visual| mode.
|
|
||||||
Then, a simple >
|
|
||||||
:'<,'>Rextract blog/post
|
|
||||||
will suffice. (Note the use of a controller name in this example.)
|
|
||||||
|
|
||||||
Migration Inversion ~
|
|
||||||
*rails-migrations* *rails-:Rinvert*
|
|
||||||
:Rinvert In a migration, rewrite the self.up method into a
|
|
||||||
self.down method. If self.up is empty, the process is
|
|
||||||
reversed. This chokes on more complicated
|
|
||||||
instructions, but works reasonably well for simple
|
|
||||||
calls to create_table, add_column, and the like.
|
|
||||||
Newer versions of Rails provide increasingly good
|
|
||||||
support for reversible migration definitions, so this
|
|
||||||
command is deprecated and no longer maintained.
|
|
||||||
|
|
||||||
INTEGRATION *rails-integration*
|
|
||||||
|
|
||||||
Having one foot in Rails and one in Vim, rails.vim has two worlds with which
|
|
||||||
to interact.
|
|
||||||
|
|
||||||
Integration with the Vim Universe ~
|
|
||||||
*rails-vim-integration*
|
|
||||||
|
|
||||||
A handful of Vim plugins are enhanced by rails.vim. All plugins mentioned can
|
|
||||||
be found at http://www.vim.org/.
|
|
||||||
|
|
||||||
*rails-:Rdbext* *rails-dbext*
|
|
||||||
:Rdbext [{environment}] This command is only provided when the |dbext| plugin
|
|
||||||
is installed. Loads the {environment} configuration
|
|
||||||
(defaults to $RAILS_ENV or development) from
|
|
||||||
config/database.yml and uses it to configure dbext.
|
|
||||||
The configuration is cached on a per application
|
|
||||||
basis. With dbext version 8.00 and newer, this
|
|
||||||
command is called automatically when needed. When
|
|
||||||
dbext is configured, you can execute SQL directly from
|
|
||||||
Vim: >
|
|
||||||
:Select * from posts order by id desc
|
|
||||||
:Update comments set author_id = 1
|
|
||||||
<
|
|
||||||
*rails-surround*
|
|
||||||
The |surround| plugin available from vim.org enables adding and removing
|
|
||||||
"surroundings" like parentheses, quotes, and HTML tags. Even by itself, it is
|
|
||||||
quite useful for Rails development, particularly eRuby editing. When coupled
|
|
||||||
with this plugin, a few additional replacement surroundings are available in
|
|
||||||
eRuby files. See the |surround| documentation for details on how to use them.
|
|
||||||
The table below uses ^ to represent the position of the surrounded text.
|
|
||||||
|
|
||||||
Key Surrounding ~
|
|
||||||
= <%= ^ %>
|
|
||||||
- <% ^ -%>
|
|
||||||
# <%# ^ %>
|
|
||||||
<C-E> <% ^ -%>\n<% end -%>
|
|
||||||
|
|
||||||
The last surrounding is particularly useful in insert mode with the following
|
|
||||||
map in one's vimrc. Use Alt+o to open a new line below the current one. This
|
|
||||||
works nicely even in a terminal (where most alt/meta maps will fail) because
|
|
||||||
most terminals send <M-o> as <Esc>o anyways.
|
|
||||||
>
|
|
||||||
imap <M-o> <Esc>o
|
|
||||||
<
|
|
||||||
One can also use the <C-E> surrounding in a plain Ruby file to append a bare
|
|
||||||
"end" on the following line.
|
|
||||||
|
|
||||||
*rails-abolish*
|
|
||||||
Among the many features of |abolish| on vim.org is the ability to change the
|
|
||||||
inflection of the word under the cursor. For example, one can hit crs to
|
|
||||||
change from MixedCase to snake_case. This plugin adds two additional
|
|
||||||
inflections: crl for alternating between the singular and plural, and crt for
|
|
||||||
altering between tableize and classify. The latter is useful in changing
|
|
||||||
constructs like BlogPost.all to current_user.blog_posts.all and vice versa.
|
|
||||||
|
|
||||||
*rails-rspec*
|
|
||||||
The presence of a spec directory causes several additional behaviors to
|
|
||||||
activate. :A knows about specs and will jump to them (but Test::Unit files
|
|
||||||
still get priority). The associated controller or model of a spec is
|
|
||||||
detected, so all navigation commands should work as expected inside a spec
|
|
||||||
file. :Rake in a spec runs just that spec, and in a model, controller, or
|
|
||||||
helper, runs the associated spec.
|
|
||||||
|
|
||||||
|:Eunittest| and |:Efunctionaltest| lead double lives, handling model/helper
|
|
||||||
and controller/mailer specs respectively. For view specs, you can use
|
|
||||||
|:Espec|, or define your own navigation commands:
|
|
||||||
>
|
|
||||||
Rnavcommand specview spec/views -glob=**/* -suffix=_spec.rb
|
|
||||||
<
|
|
||||||
ABBREVIATIONS *rails-abbreviations* *rails-snippets*
|
|
||||||
|
|
||||||
Abbreviations are "snippets lite". They may later be extracted into a
|
|
||||||
separate plugin, or removed entirely.
|
|
||||||
|
|
||||||
*rails-:Rabbrev*
|
|
||||||
:Rabbrev List all Rails abbreviations.
|
|
||||||
|
|
||||||
:Rabbrev {abbr} {expn} [{extra}]
|
|
||||||
Define a new Rails abbreviation. {extra} is permitted
|
|
||||||
if and only if {expn} ends with "(".
|
|
||||||
|
|
||||||
*rails-:Rabbrev!*
|
|
||||||
:Rabbrev! {abbr} Remove an abbreviation.
|
|
||||||
|
|
||||||
Rails abbreviations differ from regular abbreviations in that they only expand
|
|
||||||
after a <C-]> (see |i_CTRL-]|) or a <Tab> (if <Tab> does not work, it is
|
|
||||||
likely mapped by another plugin). If the abbreviation ends in certain
|
|
||||||
punctuation marks, additional expansions are possible. A few examples will
|
|
||||||
hopefully clear this up (all of the following are enabled by default in
|
|
||||||
appropriate file types).
|
|
||||||
|
|
||||||
Command Sequence typed Resulting text ~
|
|
||||||
Rabbrev rp( render :partial\ => rp( render(:partial =>
|
|
||||||
Rabbrev rp( render :partial\ => rp<Tab> render :partial =>
|
|
||||||
Rabbrev vs( validates_size_of vs( validates_size_of(
|
|
||||||
Rabbrev pa[ params pa[:id] params[:id]
|
|
||||||
Rabbrev pa[ params pa<C-]> params
|
|
||||||
Rabbrev pa[ params pa.inspect params.inspect
|
|
||||||
Rabbrev AR:: ActionRecord AR::Base ActiveRecord::Base
|
|
||||||
|
|
||||||
In short, ( expands on (, :: expands on . and :, and [ expands on . and [.
|
|
||||||
These trailing punctuation marks are NOT part of the final abbreviation, and
|
|
||||||
you cannot have two mappings that differ only by punctuation.
|
|
||||||
|
|
||||||
You must escape spaces in your expansion, either as "\ " or as "<Space>". For
|
|
||||||
an abbreviation ending with "(", you may define where to insert the
|
|
||||||
parenthesis by splitting the expansion into two parts (divided by an unescaped
|
|
||||||
space).
|
|
||||||
|
|
||||||
You can also define abbreviations as a hash in |g:rails_abbreviations| or by
|
|
||||||
using |rails-projection-abbreviations|:
|
|
||||||
>
|
|
||||||
let g:rails_abbreviations = {
|
|
||||||
\ "AE::": "ActiveResource",
|
|
||||||
\ "p[": "params",
|
|
||||||
\ "rj(": ["render", "json: "]}
|
|
||||||
<
|
|
||||||
Many abbreviations are provided by default: use :Rabbrev to list them. They
|
|
||||||
vary depending on the type of file (models have different abbreviations than
|
|
||||||
controllers).
|
|
||||||
|
|
||||||
SYNTAX HIGHLIGHTING *rails-syntax*
|
|
||||||
|
|
||||||
Syntax highlighting is by and large a transparent process. For the full
|
|
||||||
effect, however, you need a colorscheme which accentuates rails.vim
|
|
||||||
extensions. One such colorscheme is vividchalk, available from vim.org.
|
|
||||||
|
|
||||||
The following is a summary of the changes made by rails.vim to the standard
|
|
||||||
syntax highlighting.
|
|
||||||
|
|
||||||
*rails-syntax-keywords*
|
|
||||||
Rails specific keywords are highlighted in a filetype specific manner. For
|
|
||||||
example, in a model, has_many is highlighted, whereas in a controller,
|
|
||||||
before_filter is highlighted. A wide variety of syntax groups are used but
|
|
||||||
they all link by default to railsMethod.
|
|
||||||
|
|
||||||
*rails-syntax-classes*
|
|
||||||
Models, helpers, and controllers are given special highlighting. Depending on
|
|
||||||
the version of Vim installed, you may need a rails.vim aware colorscheme in
|
|
||||||
order to see this. Said colorscheme needs to provide highlighting for the
|
|
||||||
railsUserClass syntax group.
|
|
||||||
|
|
||||||
The class names are determined by camelizing filenames from certain
|
|
||||||
directories of your application. If app/models/line_item.rb exists, the class
|
|
||||||
"LineItem" will be highlighted.
|
|
||||||
|
|
||||||
The list of classes is refreshed automatically after certain commands like
|
|
||||||
|:Rgenerate|. Use |:Rrefresh| to trigger the process manually.
|
|
||||||
|
|
||||||
*rails-syntax-assertions*
|
|
||||||
If you define custom assertions in test_helper.rb, these will be highlighted
|
|
||||||
in your tests. These are found by scanning test_helper.rb for lines of the
|
|
||||||
form " def assert_..." and extracting the method name. The railsUserMethod
|
|
||||||
syntax group is used. The list of assertions can be refreshed with
|
|
||||||
|:Rrefresh|.
|
|
||||||
|
|
||||||
*rails-syntax-strings*
|
|
||||||
A string literal using %Q<> or %<> delimiters will have its contents
|
|
||||||
highlighted as HTML. This is sometimes useful when writing helpers. >
|
|
||||||
link = %<<a href="http://www.vim.org">Vim</a>>.html_safe
|
|
||||||
<
|
|
||||||
*rails-syntax-yaml*
|
|
||||||
YAML syntax highlighting has been extended to highlight eRuby, which can be
|
|
||||||
used in most Rails YAML files (including database.yml and fixtures).
|
|
||||||
|
|
||||||
MANAGED VIM OPTIONS *rails-options*
|
|
||||||
|
|
||||||
The following options are set local to buffers where the plugin is active.
|
|
||||||
|
|
||||||
*rails-'shiftwidth'* *rails-'sw'*
|
|
||||||
*rails-'softtabstop'* *rails-'sts'*
|
|
||||||
*rails-'expandtab'* *rails-'et'*
|
|
||||||
Indent settings are no longer adjusted by default. Install sleuth.vim, or try
|
|
||||||
this in your vimrc instead: >
|
|
||||||
autocmd FileType ruby set sw=2 sts=2 et
|
|
||||||
<
|
|
||||||
*rails-'path'* *rails-'pa'*
|
|
||||||
All the relevant directories from your application are added to your 'path'.
|
|
||||||
This makes it easy to access a buried file: >
|
|
||||||
:find blog_controller
|
|
||||||
<
|
|
||||||
*rails-'includeexpr'* *rails-'inex'*
|
|
||||||
The 'includeexpr' option is set to enable the magic described in |rails-gf|.
|
|
||||||
|
|
||||||
*rails-'filetype'* *rails-'ft'*
|
|
||||||
The 'filetype' is sometimes adjusted for Rails files. Most notably, *.rxml
|
|
||||||
and *.rjs are treated as Ruby files, and files that have been falsely
|
|
||||||
identified as Mason sources are changed back to eRuby files (but only when
|
|
||||||
they are part of a Rails application).
|
|
||||||
|
|
||||||
*rails-'completefunc'* *rails-'cfu'*
|
|
||||||
A 'completefunc' is provided (if not already set). It is very simple, as it
|
|
||||||
uses syntax highlighting to make its guess. See |i_CTRL-X_CTRL-U|.
|
|
||||||
|
|
||||||
PROJECTIONS *rails-config/projections.json* *rails-projections*
|
|
||||||
|
|
||||||
The bulk of rails.vim features support core Rails conventions and a just a
|
|
||||||
handful of popular additions (such as RSpec). Projections let you teach
|
|
||||||
rails.vim about app specific and gem specific behavior.
|
|
||||||
|
|
||||||
There are four primary ways to define projections:
|
|
||||||
|
|
||||||
1. Globally, in |g:rails_projections|.
|
|
||||||
2. Per app, in config/projections.json.
|
|
||||||
3. Per bundled gem, in |g:rails_gem_projections| (requires bundler.vim).
|
|
||||||
4. Inside a bundled gem, in lib/rails/projections.json (requires bundler.vim).
|
|
||||||
|
|
||||||
Vim syntax looks a lot like JSON, but with funky |line-continuation|:
|
|
||||||
>
|
|
||||||
let g:rails_projections = {
|
|
||||||
\ "app/uploaders/*_uploader.rb": {
|
|
||||||
\ "command": "uploader",
|
|
||||||
\ "template":
|
|
||||||
\ "class %SUploader < CarrierWave::Uploader::Base\nend",
|
|
||||||
\ "test": [
|
|
||||||
\ "test/unit/%s_uploader_test.rb",
|
|
||||||
\ "spec/models/%s_uploader_spec.rb"
|
|
||||||
\ ],
|
|
||||||
\ "keywords": "process version"
|
|
||||||
\ },
|
|
||||||
\ "features/support/*.rb": {"command": "support"},
|
|
||||||
\ "features/support/env.rb": {"command": "support"}}
|
|
||||||
|
|
||||||
Keys can be either literal file names or globs containing a single asterisk.
|
|
||||||
In the latter case, you can use placeholders in the values to plug in some
|
|
||||||
variant of the variable portion:
|
|
||||||
|
|
||||||
%s: original
|
|
||||||
%p: pluralized
|
|
||||||
%i: singularized
|
|
||||||
%S: camelized
|
|
||||||
%h: humanized
|
|
||||||
|
|
||||||
The full list of available options is as follows:
|
|
||||||
|
|
||||||
*rails-projection-alternate*
|
|
||||||
"alternate" ~
|
|
||||||
Determines the destination of the |rails-:A| command. If this is a
|
|
||||||
list, the first readable file will be used.
|
|
||||||
*rails-projection-related*
|
|
||||||
"related" ~
|
|
||||||
Determines the destination of the |rails-:R| and :.A commands. In
|
|
||||||
addition to the standard placeholders, %d can be used for the current
|
|
||||||
'define' match (typically a method).
|
|
||||||
*rails-projection-test*
|
|
||||||
"test" ~
|
|
||||||
Determines the default test file to run with |rails-:Rrunner| and
|
|
||||||
|rails-:Rake|. Also serves as a default for "alternate".
|
|
||||||
*rails-projection-task*
|
|
||||||
"task" ~
|
|
||||||
Determines the default rake task to run. Provide %l or %d to
|
|
||||||
substitute the current line or 'define' match (typically a method), or
|
|
||||||
just a bare % (like |:_%|) to substitute the current file name. If a
|
|
||||||
list with two tasks is provided, the first will be used when a line
|
|
||||||
number is given, and the second when it's omitted.
|
|
||||||
*rails-projection-compiler*
|
|
||||||
"compiler" ~
|
|
||||||
Determines the |:compiler| plugin to use with |rails-:Rrunner|.
|
|
||||||
*rails-projection-keywords*
|
|
||||||
"keywords" ~
|
|
||||||
Provides a whitespace delimited list of keywords to syntax highlight.
|
|
||||||
*rails-projection-abbreviations*
|
|
||||||
"abbreviations" ~
|
|
||||||
Provides a dictionary of abbreviations to define. See
|
|
||||||
|rails-abbreviations|. You might consider setting this in a "*"
|
|
||||||
projection.
|
|
||||||
*rails-projection-command*
|
|
||||||
"command" ~
|
|
||||||
Names a navigation command to be created. Use the same name on
|
|
||||||
multiple projections to combine them into a single command. Glob
|
|
||||||
keys are used when the command is given an argument, and literal file
|
|
||||||
keys are used when no argument is given. See the "features/support"
|
|
||||||
entries above for an example :Esupport that defaults to env.
|
|
||||||
*rails-projection-affinity*
|
|
||||||
"affinity" ~
|
|
||||||
Provide this if the root of your file name corresponds to either
|
|
||||||
a model or controller. The root of a helper generally corresponds to
|
|
||||||
a controller, for example, so a "helper" projection would have an
|
|
||||||
"affinity" of "controller". You can also provide "collection" if it
|
|
||||||
corresponds to a plural model (e.g., fixtures), or "resource" if it
|
|
||||||
corresponds to a singular controller. Providing this lets you use
|
|
||||||
other affiliated commands without an argument, and determines the
|
|
||||||
default if a command has no literal file name.
|
|
||||||
*rails-projection-template*
|
|
||||||
"template" ~
|
|
||||||
If you provide a ! after the argument to the navigation command (that
|
|
||||||
is, :Euploader foo!, NOT :Euploader! foo), and a new file is created,
|
|
||||||
this will be used as the body.
|
|
||||||
|
|
||||||
CONFIGURATION *rails-configuration*
|
|
||||||
|
|
||||||
In addition to projections (described above) and the crude hammer of global
|
|
||||||
settings (described below), rails.vim provides a few different mechanisms for
|
|
||||||
configuration.
|
|
||||||
|
|
||||||
*rails-:autocmd* *rails-autocommands*
|
|
||||||
If you would like to set your own custom Vim settings whenever a Rails file is
|
|
||||||
loaded, you can use an autocommand like the following in your vimrc: >
|
|
||||||
|
|
||||||
autocmd User Rails silent! Lcd
|
|
||||||
autocmd User Rails map <buffer> <F9> :Rake<CR>
|
|
||||||
|
|
||||||
There used to be autocommands that fire based on the "type" or file name of
|
|
||||||
the buffer, but they have been removed. If you still need to execute code for
|
|
||||||
certain file types only, use the bare User Rails event above and check
|
|
||||||
rails#buffer().relative() for the path relative to the Rails root.
|
|
||||||
|
|
||||||
*macros/rails.vim*
|
|
||||||
If you have several commands to run on initialization for all file types, they
|
|
||||||
can be placed in a "macros/rails.vim" file in the 'runtimepath' (for example,
|
|
||||||
"~/.vim/macros/rails.vim"). This file is sourced by rails.vim each time a
|
|
||||||
Rails file is loaded.
|
|
||||||
|
|
||||||
*config/rails.vim*
|
|
||||||
This file used to be sourced automatically from the root of the application,
|
|
||||||
but has been superseded by |rails-projections|.
|
|
||||||
|
|
||||||
*rails-:Rnavcommand*
|
|
||||||
:Rnavcommand This command has been superseded by
|
|
||||||
|rails-projections|.
|
|
||||||
|
|
||||||
*rails-:Rset*
|
|
||||||
:Rset This command has been superseded by
|
|
||||||
|rails-projections|.
|
|
||||||
|
|
||||||
GLOBAL SETTINGS *rails-global-settings*
|
|
||||||
|
|
||||||
When all else fails, set a global.
|
|
||||||
|
|
||||||
*g:rails_abbreviations*
|
|
||||||
Dictionary of additional abbreviations. See |rails-abbreviations|.
|
|
||||||
|
|
||||||
This variable was formerly used to globally disable abbreviations. Use
|
|
||||||
g:rails_no_abbreviations if you want to do that.
|
|
||||||
|
|
||||||
*g:rails_ctags_arguments*
|
|
||||||
Additional arguments to pass to ctags from |:Ctags|. Defaults to ignoring
|
|
||||||
JavaScript files, since ctags has a tendency to choke on those.
|
|
||||||
>
|
|
||||||
let g:rails_ctags_arguments = ['--languages=-javascript']
|
|
||||||
<
|
|
||||||
*g:rails_projections* >
|
|
||||||
Defines the set of globally available projections. See |rails-projections|.
|
|
||||||
Where possible, it is generally advisable to use |g:rails_gem_projections| or
|
|
||||||
|config/projections.json| instead.
|
|
||||||
|
|
||||||
*g:rails_gem_projections*
|
|
||||||
This is a dictionary where the keys are gem names and the values are
|
|
||||||
projection dictionaries. Projections are only used if the given gem is
|
|
||||||
bundled (requires bundler.vim).
|
|
||||||
>
|
|
||||||
let g:rails_gem_projections = {
|
|
||||||
\ "active_model_serializers": {
|
|
||||||
\ "app/serializers/*_serializer.rb": {
|
|
||||||
\ "command": "serializer",
|
|
||||||
\ "affinity": "model"}},
|
|
||||||
\ "fabrication": {
|
|
||||||
\ "spec/fabricators/*_fabricator.rb": {
|
|
||||||
\ "command": "fabricator",
|
|
||||||
\ "affinity": "model",
|
|
||||||
\ "alternate": "app/models/%s.rb",
|
|
||||||
\ "related": "db/schema.rb#%p",
|
|
||||||
\ "test": "spec/models/%s_spec.rb",
|
|
||||||
\ "template": "Fabricator :%s do\nend"}}}
|
|
||||||
<
|
|
||||||
See |rails-projections|. Generally, you should prefer these gem projections
|
|
||||||
over global projections to avoid getting a bunch of useless commands in every
|
|
||||||
single project.
|
|
||||||
|
|
||||||
Gem maintainers may also provide custom projections by placing them in
|
|
||||||
lib/rails/projections.json.
|
|
||||||
|
|
||||||
ABOUT *rails-about* *rails-plugin-author*
|
|
||||||
|
|
||||||
The latest stable version can be found at
|
|
||||||
http://www.vim.org/scripts/script.php?script_id=1567
|
|
||||||
|
|
||||||
Bugs can be reported and the very latest development version can be retrieved
|
|
||||||
from GitHub:
|
|
||||||
https://github.com/tpope/vim-rails >
|
|
||||||
git clone git://github.com/tpope/vim-rails.git
|
|
||||||
<
|
|
||||||
*rails-license*
|
|
||||||
Copyright (c) Tim Pope. Distributed under the same terms as Vim itself.
|
|
||||||
See |license|.
|
|
||||||
|
|
||||||
vim:tw=78:ts=8:ft=help:norl:
|
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
" rails.vim - Detect a rails application
|
|
||||||
" Author: Tim Pope <http://tpo.pe/>
|
|
||||||
" GetLatestVimScripts: 1567 1 :AutoInstall: rails.vim
|
|
||||||
|
|
||||||
" Install this file as plugin/rails.vim.
|
|
||||||
|
|
||||||
if exists('g:loaded_rails') || &cp || v:version < 700
|
|
||||||
finish
|
|
||||||
endif
|
|
||||||
let g:loaded_rails = 1
|
|
||||||
|
|
||||||
" Utility Functions {{{1
|
|
||||||
|
|
||||||
function! s:error(str)
|
|
||||||
echohl ErrorMsg
|
|
||||||
echomsg a:str
|
|
||||||
echohl None
|
|
||||||
let v:errmsg = a:str
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:autoload(...)
|
|
||||||
if !exists("g:autoloaded_rails") && v:version >= 700
|
|
||||||
runtime! autoload/rails.vim
|
|
||||||
endif
|
|
||||||
if exists("g:autoloaded_rails")
|
|
||||||
if a:0
|
|
||||||
exe a:1
|
|
||||||
endif
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
if !exists("g:rails_no_autoload_warning")
|
|
||||||
let g:rails_no_autoload_warning = 1
|
|
||||||
if v:version >= 700
|
|
||||||
call s:error("Disabling rails.vim: autoload/rails.vim is missing")
|
|
||||||
else
|
|
||||||
call s:error("Disabling rails.vim: Vim version 7 or higher required")
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return ""
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Detection {{{1
|
|
||||||
|
|
||||||
function! s:Detect(filename)
|
|
||||||
if exists('b:rails_root')
|
|
||||||
return s:BufInit(b:rails_root)
|
|
||||||
endif
|
|
||||||
let fn = substitute(fnamemodify(a:filename,":p"),'\c^file://','','')
|
|
||||||
let sep = matchstr(fn,'^[^\\/]\{3,\}\zs[\\/]')
|
|
||||||
if sep != ""
|
|
||||||
let fn = getcwd().sep.fn
|
|
||||||
endif
|
|
||||||
if isdirectory(fn)
|
|
||||||
let fn = fnamemodify(fn,':s?[\/]$??')
|
|
||||||
else
|
|
||||||
let fn = fnamemodify(fn,':s?\(.*\)[\/][^\/]*$?\1?')
|
|
||||||
endif
|
|
||||||
let ofn = ""
|
|
||||||
while fn != ofn
|
|
||||||
if filereadable(fn . "/config/environment.rb")
|
|
||||||
return s:BufInit(resolve(fn))
|
|
||||||
endif
|
|
||||||
let ofn = fn
|
|
||||||
let fn = fnamemodify(ofn,':h')
|
|
||||||
endwhile
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:BufInit(path)
|
|
||||||
if s:autoload()
|
|
||||||
return RailsBufInit(a:path)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" Initialization {{{1
|
|
||||||
|
|
||||||
augroup railsPluginDetect
|
|
||||||
autocmd!
|
|
||||||
autocmd BufNewFile,BufRead * call s:Detect(expand("<afile>:p"))
|
|
||||||
autocmd VimEnter * if expand("<amatch>") == "" && !exists("b:rails_root") | call s:Detect(getcwd()) | endif | if exists("b:rails_root") | silent doau User BufEnterRails | endif
|
|
||||||
autocmd FileType netrw if !exists("b:rails_root") | call s:Detect(expand("%:p")) | endif | if exists("b:rails_root") | silent doau User BufEnterRails | endif
|
|
||||||
autocmd BufEnter * if exists("b:rails_root")|silent doau User BufEnterRails|endif
|
|
||||||
autocmd BufLeave * if exists("b:rails_root")|silent doau User BufLeaveRails|endif
|
|
||||||
autocmd Syntax railslog if s:autoload()|call rails#log_syntax()|endif
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
command! -bar -bang -nargs=* -complete=dir Rails :if s:autoload()|execute rails#new_app_command(<bang>0,<f-args>)|endif
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" abolish.vim support {{{1
|
|
||||||
|
|
||||||
function! s:function(name)
|
|
||||||
return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
augroup railsPluginAbolish
|
|
||||||
autocmd!
|
|
||||||
autocmd VimEnter * call s:abolish_setup()
|
|
||||||
augroup END
|
|
||||||
|
|
||||||
function! s:abolish_setup()
|
|
||||||
if exists('g:Abolish') && has_key(g:Abolish,'Coercions')
|
|
||||||
if !has_key(g:Abolish.Coercions,'l')
|
|
||||||
let g:Abolish.Coercions.l = s:function('s:abolish_l')
|
|
||||||
endif
|
|
||||||
if !has_key(g:Abolish.Coercions,'t')
|
|
||||||
let g:Abolish.Coercions.t = s:function('s:abolish_t')
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:abolish_l(word)
|
|
||||||
let singular = rails#singularize(a:word)
|
|
||||||
return a:word ==? singular ? rails#pluralize(a:word) : singular
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:abolish_t(word)
|
|
||||||
if a:word =~# '\u'
|
|
||||||
return rails#pluralize(rails#underscore(a:word))
|
|
||||||
else
|
|
||||||
return rails#singularize(rails#camelize(a:word))
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" }}}1
|
|
||||||
" vim:set sw=2 sts=2:
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit d25c7ebb65a0ca3058d075158ce1b6605c954c82
|
|
||||||
1
vim/bundle/webapi-vim/.gitignore
vendored
1
vim/bundle/webapi-vim/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
doc/tags
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
all : webapi-vim.zip
|
|
||||||
|
|
||||||
remove-zip:
|
|
||||||
-rm -f doc/tags
|
|
||||||
-rm -f webapi-vim.zip
|
|
||||||
|
|
||||||
webapi-vim.zip: remove-zip
|
|
||||||
zip -r webapi-vim.zip autoload doc README
|
|
||||||
|
|
||||||
release: webapi-vim.zip
|
|
||||||
vimup update-script webapi.vim
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
webapi-vim: Vim Interface to Web API
|
|
||||||
|
|
||||||
Description:
|
|
||||||
Interface to WEB APIs.
|
|
||||||
Currently this library support following protocols.
|
|
||||||
|
|
||||||
* Basic HTTP
|
|
||||||
* OAuth
|
|
||||||
* Atompub
|
|
||||||
* SOAP (in progress)
|
|
||||||
* XMLRPC
|
|
||||||
* MetaWeblog API
|
|
||||||
|
|
||||||
This library contains:
|
|
||||||
XML Parser
|
|
||||||
HTML Parser(Hack Way)
|
|
||||||
JSON Praser
|
|
||||||
BASE64 Hash Algorism
|
|
||||||
SHA1 Hash Algorism
|
|
||||||
HMAC HASH Algorism
|
|
||||||
Bit Operation Library
|
|
||||||
Converter for "UTF-8 to Unicode"
|
|
||||||
|
|
||||||
Require:
|
|
||||||
|
|
||||||
curl command : http://curl.haxx.se/
|
|
||||||
|
|
||||||
Thanks To:
|
|
||||||
|
|
||||||
Yukihiro Nakadaira : http://sites.google.com/site/yukihironakadaira/
|
|
||||||
autoload/base64.vim (I added small changes)
|
|
||||||
autoload/hmac.vim
|
|
||||||
autoload/sha1.vim
|
|
||||||
|
|
||||||
|
|
@ -1,226 +0,0 @@
|
||||||
" atom
|
|
||||||
" Last Change: 2010-09-10
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
" http://tools.ietf.org/rfc/rfc5023.txt
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
let s:system = function(get(g:, 'webapi#system_function', 'system'))
|
|
||||||
|
|
||||||
let s:author_template = {
|
|
||||||
\ "name": "",
|
|
||||||
\}
|
|
||||||
|
|
||||||
let s:link_template = {
|
|
||||||
\ "rel": "",
|
|
||||||
\ "href": "",
|
|
||||||
\}
|
|
||||||
|
|
||||||
let s:category_template = {
|
|
||||||
\ "term": "",
|
|
||||||
\ "scheme": "",
|
|
||||||
\ "label": "",
|
|
||||||
\}
|
|
||||||
|
|
||||||
let s:feed_template = {
|
|
||||||
\ "id": "",
|
|
||||||
\ "icon": "",
|
|
||||||
\ "logo": "",
|
|
||||||
\ "title": "",
|
|
||||||
\ "link": [],
|
|
||||||
\ "category": [],
|
|
||||||
\ "author": [],
|
|
||||||
\ "contirubutor": [],
|
|
||||||
\ "entry": [],
|
|
||||||
\}
|
|
||||||
|
|
||||||
let s:entry_template = {
|
|
||||||
\ "id": "",
|
|
||||||
\ "icon": "",
|
|
||||||
\ "logo": "",
|
|
||||||
\ "title": "",
|
|
||||||
\ "link": [],
|
|
||||||
\ "category": [],
|
|
||||||
\ "author": [],
|
|
||||||
\ "contirubutor": [],
|
|
||||||
\ "copyright": "",
|
|
||||||
\ "content": "",
|
|
||||||
\ "content.type": "text/plain",
|
|
||||||
\ "content.mode": "escaped",
|
|
||||||
\ "summary": "",
|
|
||||||
\ "created": "",
|
|
||||||
\ "updated": "",
|
|
||||||
\}
|
|
||||||
|
|
||||||
for s:name in ['author', 'link', 'category', 'feed', 'entry']
|
|
||||||
for s:key in keys(eval('s:'.s:name.'_template'))
|
|
||||||
let key = substitute(s:key, '\.\(.\)', '\=toupper(submatch(1))', '')
|
|
||||||
exe "function s:".s:name."_template.set".toupper(key[0]).key[1:]."(v) dict\n"
|
|
||||||
\. " let self['".s:key."'] = a:v\n"
|
|
||||||
\. "endfunction\n"
|
|
||||||
exe "function s:".s:name."_template.get".toupper(key[0]).key[1:]."() dict\n"
|
|
||||||
\. " return self['".s:key."']\n"
|
|
||||||
\. "endfunction\n"
|
|
||||||
endfor
|
|
||||||
endfor
|
|
||||||
function s:entry_template.setContentFromFile(file) dict
|
|
||||||
let quote = &shellxquote == '"' ? "'" : '"'
|
|
||||||
let bits = substitute(s:system("xxd -ps ".quote.file.quote), "[ \n\r]", '', 'g')
|
|
||||||
let self['mode'] = "base64"
|
|
||||||
let self['content'] = webapi#base64#b64encodebin(bits)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
unlet s:name
|
|
||||||
unlet s:key
|
|
||||||
|
|
||||||
function! webapi#atom#newEntry()
|
|
||||||
return deepcopy(s:entry_template)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:createXml(entry)
|
|
||||||
let entry = webapi#xml#createElement("entry")
|
|
||||||
let entry.attr["xmlns"] = "http://purl.org/atom/ns#"
|
|
||||||
|
|
||||||
for key in keys(a:entry)
|
|
||||||
if type(a:entry[key]) == 1 && key !~ '\.'
|
|
||||||
let node = webapi#xml#createElement(key)
|
|
||||||
call node.value(a:entry[key])
|
|
||||||
if key == "content"
|
|
||||||
let node.attr["type"] = a:entry['content.type']
|
|
||||||
let node.attr["mode"] = a:entry['content.mode']
|
|
||||||
endif
|
|
||||||
call add(entry.child, node)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
let xml = '<?xml version="1.0" encoding="utf-8"?>' . entry.toString()
|
|
||||||
return iconv(xml, &encoding, "utf-8")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:createWsse(user, pass)
|
|
||||||
let now = localtime()
|
|
||||||
let nonce = webapi#sha1#sha1(now . " " . now)[0:28]
|
|
||||||
let created = strftime("%Y-%m-%dT%H:%M:%SZ", now)
|
|
||||||
let passworddigest = webapi#base64#b64encodebin(webapi#sha1#sha1(nonce.created.a:pass))
|
|
||||||
let nonce = webapi#base64#b64encode(nonce)
|
|
||||||
return 'UsernameToken Username="'.a:user.'", PasswordDigest="'.passworddigest.'", Nonce="'.nonce.'", Created="'.created.'"'
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#atom#deleteEntry(uri, user, pass)
|
|
||||||
let res = webapi#http#post(a:uri, "",
|
|
||||||
\ {
|
|
||||||
\ "Content-Type": "application/x.atom+xml",
|
|
||||||
\ "X-WSSE": s:createWsse(a:user, a:pass)
|
|
||||||
\ }, "DELETE")
|
|
||||||
return res
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#atom#updateEntry(uri, user, pass, entry, ...)
|
|
||||||
let headdata = a:0 > 0 ? a:000[0] : {}
|
|
||||||
let headdata["Content-Type"] = "application/x.atom+xml"
|
|
||||||
let headdata["X-WSSE"] = s:createWsse(a:user, a:pass)
|
|
||||||
let res = webapi#http#post(a:uri, s:createXml(a:entry), headdata, "PUT")
|
|
||||||
let location = filter(res.header, 'v:val =~ "^Location:"')
|
|
||||||
if len(location)
|
|
||||||
return split(location[0], '\s*:\s\+')[1]
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#atom#createEntry(uri, user, pass, entry, ...)
|
|
||||||
let headdata = a:0 > 0 ? a:000[0] : {}
|
|
||||||
let headdata["Content-Type"] = "application/x.atom+xml"
|
|
||||||
let headdata["X-WSSE"] = s:createWsse(a:user, a:pass)
|
|
||||||
let headdata["WWW-Authenticate"] = "WSSE profile=\"UsernameToken\""
|
|
||||||
let res = webapi#http#post(a:uri, s:createXml(a:entry), headdata, "POST")
|
|
||||||
let location = filter(res.header, 'v:val =~ "^Location:"')
|
|
||||||
if len(location)
|
|
||||||
return split(location[0], '\s*:\s\+')[1]
|
|
||||||
endif
|
|
||||||
return ''
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:parse_node(target, parent)
|
|
||||||
for node in a:parent.child
|
|
||||||
if type(node) != 4 || !has_key(a:target, node.name)
|
|
||||||
unlet node
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
if node.name == 'content'
|
|
||||||
let a:target[node.name] = node.value()
|
|
||||||
if has_key(node.attr, 'type')
|
|
||||||
let a:target['content.type'] = node.attr['type']
|
|
||||||
endif
|
|
||||||
if has_key(node.attr, 'type')
|
|
||||||
let a:target['content.type'] = node.attr['type']
|
|
||||||
endif
|
|
||||||
elseif node.name == 'link'
|
|
||||||
let link = deepcopy(s:link_template)
|
|
||||||
for attr in keys(node.attr)
|
|
||||||
if !has_key(link, attr)
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
let link[attr] = node.attr[attr]
|
|
||||||
endfor
|
|
||||||
call add(a:target.link, link)
|
|
||||||
elseif node.name == 'author'
|
|
||||||
let author = deepcopy(s:author_template)
|
|
||||||
for item in node.child
|
|
||||||
if type(item) == 4 && has_key(author, item.name)
|
|
||||||
let author[item.name] = item.value()
|
|
||||||
endif
|
|
||||||
unlet item
|
|
||||||
endfor
|
|
||||||
call add(a:target.author, author)
|
|
||||||
elseif node.name == 'entry'
|
|
||||||
let entry = deepcopy(s:entry_template)
|
|
||||||
call s:parse_node(entry, node)
|
|
||||||
call add(a:target.entry, entry)
|
|
||||||
elseif type(a:target[node.name]) == 3
|
|
||||||
call add(a:target[node.name], parent.value())
|
|
||||||
else
|
|
||||||
let a:target[node.name] = node.value()
|
|
||||||
endif
|
|
||||||
unlet node
|
|
||||||
endfor
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#atom#getFeed(uri, user, pass)
|
|
||||||
let headdata = {}
|
|
||||||
if len(a:user) > 0 && len(a:pass) > 0
|
|
||||||
let headdata["X-WSSE"] = s:createWsse(a:user, a:pass)
|
|
||||||
endif
|
|
||||||
let res = webapi#http#get(a:uri, {}, headdata)
|
|
||||||
let dom = webapi#xml#parse(res.content)
|
|
||||||
let feed = deepcopy(s:feed_template)
|
|
||||||
call s:parse_node(feed, dom)
|
|
||||||
return feed
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#atom#getService(uri, user, pass)
|
|
||||||
let headdata = {}
|
|
||||||
if len(a:user) > 0 && len(a:pass) > 0
|
|
||||||
let headdata["X-WSSE"] = s:createWsse(a:user, a:pass)
|
|
||||||
endif
|
|
||||||
let res = webapi#http#get(a:uri, {}, headdata)
|
|
||||||
return webapi#xml#parse(res.content)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#atom#getEntry(uri, user, pass)
|
|
||||||
let headdata = {}
|
|
||||||
if len(a:user) > 0 && len(a:pass) > 0
|
|
||||||
let headdata["X-WSSE"] = s:createWsse(a:user, a:pass)
|
|
||||||
endif
|
|
||||||
let res = webapi#http#get(a:uri, {}, headdata)
|
|
||||||
let dom = webapi#xml#parse(res.content)
|
|
||||||
let entry = deepcopy(s:entry_template)
|
|
||||||
call s:parse_node(entry, dom)
|
|
||||||
return entry
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
" base64 codec
|
|
||||||
" Last Change: 2010-07-25
|
|
||||||
" Maintainer: Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
" [The Base16, Base32, and Base64 Data Encodings]
|
|
||||||
" http://tools.ietf.org/rfc/rfc3548.txt
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! webapi#base64#b64encode(data)
|
|
||||||
let b64 = s:b64encode(s:str2bytes(a:data), s:standard_table, '=')
|
|
||||||
return join(b64, '')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#base64#b64encodebin(data)
|
|
||||||
let b64 = s:b64encode(s:binstr2bytes(a:data), s:standard_table, '=')
|
|
||||||
return join(b64, '')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#base64#b64decode(data)
|
|
||||||
let bytes = s:b64decode(split(a:data, '\zs'), s:standard_table, '=')
|
|
||||||
return s:bytes2str(bytes)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#base64#test()
|
|
||||||
if webapi#base64#b64encode("hello, world") ==# "aGVsbG8sIHdvcmxk"
|
|
||||||
echo "test1: ok"
|
|
||||||
else
|
|
||||||
echoerr "test1: failed"
|
|
||||||
endif
|
|
||||||
if webapi#base64#b64encode("hello, worldx") ==# "aGVsbG8sIHdvcmxkeA=="
|
|
||||||
echo "test2: ok"
|
|
||||||
else
|
|
||||||
echoerr "test2: failed"
|
|
||||||
endif
|
|
||||||
if webapi#base64#b64encode("hello, worldxx") ==# "aGVsbG8sIHdvcmxkeHg="
|
|
||||||
echo "test3: ok"
|
|
||||||
else
|
|
||||||
echoerr "test3: falied"
|
|
||||||
endif
|
|
||||||
if webapi#base64#b64encode("hello, worldxxx") ==# "aGVsbG8sIHdvcmxkeHh4"
|
|
||||||
echo "test4: ok"
|
|
||||||
else
|
|
||||||
echoerr "test4: falied"
|
|
||||||
endif
|
|
||||||
if webapi#base64#b64decode(webapi#base64#b64encode("hello, world")) ==# "hello, world"
|
|
||||||
echo "test5: ok"
|
|
||||||
else
|
|
||||||
echoerr "test5: failed"
|
|
||||||
endif
|
|
||||||
if webapi#base64#b64decode(webapi#base64#b64encode("hello, worldx")) ==# "hello, worldx"
|
|
||||||
echo "test6: ok"
|
|
||||||
else
|
|
||||||
echoerr "test6: failed"
|
|
||||||
endif
|
|
||||||
if webapi#base64#b64decode(webapi#base64#b64encode("hello, worldxx")) ==# "hello, worldxx"
|
|
||||||
echo "test7: ok"
|
|
||||||
else
|
|
||||||
echoerr "test7: failed"
|
|
||||||
endif
|
|
||||||
if webapi#base64#b64decode(webapi#base64#b64encode("hello, worldxxx")) ==# "hello, worldxxx"
|
|
||||||
echo "test8: ok"
|
|
||||||
else
|
|
||||||
echoerr "test8: failed"
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:standard_table = [
|
|
||||||
\ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
|
|
||||||
\ "Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f",
|
|
||||||
\ "g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v",
|
|
||||||
\ "w","x","y","z","0","1","2","3","4","5","6","7","8","9","+","/"]
|
|
||||||
|
|
||||||
let s:urlsafe_table = [
|
|
||||||
\ "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P",
|
|
||||||
\ "Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f",
|
|
||||||
\ "g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v",
|
|
||||||
\ "w","x","y","z","0","1","2","3","4","5","6","7","8","9","-","_"]
|
|
||||||
|
|
||||||
function! s:b64encode(bytes, table, pad)
|
|
||||||
let b64 = []
|
|
||||||
for i in range(0, len(a:bytes) - 1, 3)
|
|
||||||
let n = a:bytes[i] * 0x10000
|
|
||||||
\ + get(a:bytes, i + 1, 0) * 0x100
|
|
||||||
\ + get(a:bytes, i + 2, 0)
|
|
||||||
call add(b64, a:table[n / 0x40000])
|
|
||||||
call add(b64, a:table[n / 0x1000 % 0x40])
|
|
||||||
call add(b64, a:table[n / 0x40 % 0x40])
|
|
||||||
call add(b64, a:table[n % 0x40])
|
|
||||||
endfor
|
|
||||||
if len(a:bytes) % 3 == 1
|
|
||||||
let b64[-1] = a:pad
|
|
||||||
let b64[-2] = a:pad
|
|
||||||
endif
|
|
||||||
if len(a:bytes) % 3 == 2
|
|
||||||
let b64[-1] = a:pad
|
|
||||||
endif
|
|
||||||
return b64
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:b64decode(b64, table, pad)
|
|
||||||
let a2i = {}
|
|
||||||
for i in range(len(a:table))
|
|
||||||
let a2i[a:table[i]] = i
|
|
||||||
endfor
|
|
||||||
let bytes = []
|
|
||||||
for i in range(0, len(a:b64) - 1, 4)
|
|
||||||
let n = a2i[a:b64[i]] * 0x40000
|
|
||||||
\ + a2i[a:b64[i + 1]] * 0x1000
|
|
||||||
\ + (a:b64[i + 2] == a:pad ? 0 : a2i[a:b64[i + 2]]) * 0x40
|
|
||||||
\ + (a:b64[i + 3] == a:pad ? 0 : a2i[a:b64[i + 3]])
|
|
||||||
call add(bytes, n / 0x10000)
|
|
||||||
call add(bytes, n / 0x100 % 0x100)
|
|
||||||
call add(bytes, n % 0x100)
|
|
||||||
endfor
|
|
||||||
if a:b64[-1] == a:pad
|
|
||||||
unlet a:b64[-1]
|
|
||||||
endif
|
|
||||||
if a:b64[-2] == a:pad
|
|
||||||
unlet a:b64[-1]
|
|
||||||
endif
|
|
||||||
return bytes
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:binstr2bytes(str)
|
|
||||||
return map(range(len(a:str)/2), 'eval("0x".a:str[v:val*2 : v:val*2+1])')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:str2bytes(str)
|
|
||||||
return map(range(len(a:str)), 'char2nr(a:str[v:val])')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:bytes2str(bytes)
|
|
||||||
return eval('"' . join(map(copy(a:bytes), 'printf(''\x%02x'', v:val)'), '') . '"')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! webapi#bit#dec2bin(v)
|
|
||||||
let v = a:v
|
|
||||||
if v == 0 | return 0 | endif
|
|
||||||
let ret = ""
|
|
||||||
while v > 0
|
|
||||||
let i = v % 2
|
|
||||||
let ret = i . ret
|
|
||||||
let v = v / 2
|
|
||||||
endwhile
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#bit#bin2dec(v)
|
|
||||||
let v = a:v
|
|
||||||
if len(v) == 0 | return 0 | endif
|
|
||||||
let i = 1
|
|
||||||
let ret = ""
|
|
||||||
for n in reverse(split(v, '\zs'))
|
|
||||||
if n == 1
|
|
||||||
let ret = ret + i
|
|
||||||
endif
|
|
||||||
let i = i * 2
|
|
||||||
endfor
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#bit#or(a,b)
|
|
||||||
let a = webapi#bit#dec2bin(a:a)
|
|
||||||
let b = webapi#bit#dec2bin(a:b)
|
|
||||||
return webapi#bit#bin2dec(tr((a + b), '2', '1'))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#bit#and(a,b)
|
|
||||||
let a = webapi#bit#dec2bin(a:a)
|
|
||||||
let b = webapi#bit#dec2bin(a:b)
|
|
||||||
return webapi#bit#bin2dec(tr((a + b), '21', '10'))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#bit#shift(a,b)
|
|
||||||
let a = webapi#bit#dec2bin(a:a)
|
|
||||||
let a = repeat('0', 32-len(a)) . a
|
|
||||||
if a:b < 0
|
|
||||||
let a = (repeat('0', -a:b) . a[: a:b-1])[-32:]
|
|
||||||
elseif a:b > 0
|
|
||||||
let a = (a . repeat('0', a:b))[-32:]
|
|
||||||
endif
|
|
||||||
return webapi#bit#bin2dec(a)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! s:attr(node, name)
|
|
||||||
let n = a:node.childNode(a:name)
|
|
||||||
if empty(n)
|
|
||||||
return ""
|
|
||||||
endif
|
|
||||||
return n.value()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#feed#parseURL(url)
|
|
||||||
let dom = webapi#xml#parseURL(a:url)
|
|
||||||
let items = []
|
|
||||||
if dom.name == 'rss'
|
|
||||||
let channel = dom.childNode('channel')
|
|
||||||
for item in channel.childNodes('item')
|
|
||||||
call add(items, {
|
|
||||||
\ "title": s:attr(item, 'title'),
|
|
||||||
\ "link": s:attr(item, 'link'),
|
|
||||||
\ "content": s:attr(item, 'description'),
|
|
||||||
\ "id": s:attr(item, 'guid'),
|
|
||||||
\ "date": s:attr(item, 'pubDate'),
|
|
||||||
\})
|
|
||||||
endfor
|
|
||||||
elseif dom.name == 'rdf:RDF'
|
|
||||||
for item in dom.childNodes('item')
|
|
||||||
call add(items, {
|
|
||||||
\ "title": s:attr(item, 'title'),
|
|
||||||
\ "link": s:attr(item, 'link'),
|
|
||||||
\ "content": s:attr(item, 'description'),
|
|
||||||
\ "id": s:attr(item, 'guid'),
|
|
||||||
\ "date": s:attr(item, 'dc:date'),
|
|
||||||
\})
|
|
||||||
endfor
|
|
||||||
elseif dom.name == 'feed'
|
|
||||||
for item in dom.childNodes('entry')
|
|
||||||
call add(items, {
|
|
||||||
\ "title": s:attr(item, 'title'),
|
|
||||||
\ "link": item.childNode('link').attr['href'],
|
|
||||||
\ "content": s:attr(item, 'content'),
|
|
||||||
\ "id": s:attr(item, 'id'),
|
|
||||||
\ "date": s:attr(item, 'updated'),
|
|
||||||
\})
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
return items
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
" This is a port of rfc2104 hmac function.
|
|
||||||
" http://www.ietf.org/rfc/rfc2104.txt
|
|
||||||
" Last Change: 2010-02-13
|
|
||||||
" Maintainer: Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
|
|
||||||
" @param mixed key List or String
|
|
||||||
" @param mixed text List or String
|
|
||||||
" @param Funcref hash function digest_hex(key:List, text:List):String
|
|
||||||
" @param Number blocksize
|
|
||||||
function webapi#hmac#hmac(key, text, hash, blocksize)
|
|
||||||
let key = (type(a:key) == type("")) ? s:str2bytes(a:key) : a:key
|
|
||||||
let text = (type(a:text) == type("")) ? s:str2bytes(a:text) : a:text
|
|
||||||
return s:Hmac(key, text, a:hash, a:blocksize)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function webapi#hmac#md5(key, text)
|
|
||||||
return webapi#hmac#hmac(a:key, a:text, 'webapi#md5#md5bin', 64)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function webapi#hmac#sha1(key, text)
|
|
||||||
return webapi#hmac#hmac(a:key, a:text, 'webapi#sha1#sha1bin', 64)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" http://www.ietf.org/rfc/rfc2202.txt
|
|
||||||
" Test Cases for HMAC-MD5 and HMAC-SHA-1
|
|
||||||
function webapi#hmac#test()
|
|
||||||
" Test Cases for HMAC-MD5
|
|
||||||
call s:test("md5: 1", "webapi#hmac#md5",
|
|
||||||
\ repeat("\x0b", 16),
|
|
||||||
\ "Hi There",
|
|
||||||
\ "9294727a3638bb1c13f48ef8158bfc9d")
|
|
||||||
call s:test("md5: 2", "webapi#hmac#md5",
|
|
||||||
\ "Jefe",
|
|
||||||
\ "what do ya want for nothing?",
|
|
||||||
\ "750c783e6ab0b503eaa86e310a5db738")
|
|
||||||
call s:test("md5: 3", "webapi#hmac#md5",
|
|
||||||
\ repeat("\xaa", 16),
|
|
||||||
\ repeat("\xdd", 50),
|
|
||||||
\ "56be34521d144c88dbb8c733f0e8b3f6")
|
|
||||||
call s:test("md5: 4", "webapi#hmac#md5",
|
|
||||||
\ s:hex2bytes("0102030405060708090a0b0c0d0e0f10111213141516171819"),
|
|
||||||
\ repeat([0xcd], 50),
|
|
||||||
\ "697eaf0aca3a3aea3a75164746ffaa79")
|
|
||||||
call s:test("md5: 5", "webapi#hmac#md5",
|
|
||||||
\ repeat("\x0c", 16),
|
|
||||||
\ "Test With Truncation",
|
|
||||||
\ "56461ef2342edc00f9bab995690efd4c")
|
|
||||||
call s:test("md5: 6", "webapi#hmac#md5",
|
|
||||||
\ repeat("\xaa", 80),
|
|
||||||
\ "Test Using Larger Than Block-Size Key - Hash Key First",
|
|
||||||
\ "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd")
|
|
||||||
call s:test("md5: 7", "webapi#hmac#md5",
|
|
||||||
\ repeat("\xaa", 80),
|
|
||||||
\ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
|
|
||||||
\ "6f630fad67cda0ee1fb1f562db3aa53e")
|
|
||||||
|
|
||||||
" Test Cases for HMAC-SHA1
|
|
||||||
call s:test("sha1: 1", "webapi#hmac#sha1",
|
|
||||||
\ repeat("\x0b", 20),
|
|
||||||
\ "Hi There",
|
|
||||||
\ "b617318655057264e28bc0b6fb378c8ef146be00")
|
|
||||||
call s:test("sha1: 2", "webapi#hmac#sha1",
|
|
||||||
\ "Jefe",
|
|
||||||
\ "what do ya want for nothing?",
|
|
||||||
\ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79")
|
|
||||||
call s:test("sha1: 3", "webapi#hmac#sha1",
|
|
||||||
\ repeat("\xaa", 20),
|
|
||||||
\ repeat("\xdd", 50),
|
|
||||||
\ "125d7342b9ac11cd91a39af48aa17b4f63f175d3")
|
|
||||||
call s:test("sha1: 4", "webapi#hmac#sha1",
|
|
||||||
\ s:hex2bytes("0102030405060708090a0b0c0d0e0f10111213141516171819"),
|
|
||||||
\ repeat([0xcd], 50),
|
|
||||||
\ "4c9007f4026250c6bc8414f9bf50c86c2d7235da")
|
|
||||||
call s:test("sha1: 5", "webapi#hmac#sha1",
|
|
||||||
\ repeat("\x0c", 20),
|
|
||||||
\ "Test With Truncation",
|
|
||||||
\ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04")
|
|
||||||
call s:test("sha1: 6", "webapi#hmac#sha1",
|
|
||||||
\ repeat("\xaa", 80),
|
|
||||||
\ "Test Using Larger Than Block-Size Key - Hash Key First",
|
|
||||||
\ "aa4ae5e15272d00e95705637ce8a3b55ed402112")
|
|
||||||
call s:test("sha1: 7", "webapi#hmac#sha1",
|
|
||||||
\ repeat("\xaa", 80),
|
|
||||||
\ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
|
|
||||||
\ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91")
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function s:test(name, func, key, data, digest)
|
|
||||||
let result = call(a:func, [a:key, a:data])
|
|
||||||
echo "test_case:" a:name
|
|
||||||
echo "expect:" a:digest
|
|
||||||
echo "result:" result
|
|
||||||
if a:digest ==? result
|
|
||||||
echo "test: OK"
|
|
||||||
else
|
|
||||||
echohl Error
|
|
||||||
echo "test: NG"
|
|
||||||
echohl None
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
" @param List key
|
|
||||||
" @param List text
|
|
||||||
" @param Funcref hash
|
|
||||||
" @param Number blocksize
|
|
||||||
function! s:Hmac(key, text, hash, blocksize)
|
|
||||||
let key = a:key
|
|
||||||
if len(key) > a:blocksize
|
|
||||||
let key = s:hex2bytes(call(a:hash, [key]))
|
|
||||||
endif
|
|
||||||
let k_ipad = repeat([0], a:blocksize)
|
|
||||||
let k_opad = repeat([0], a:blocksize)
|
|
||||||
for i in range(a:blocksize)
|
|
||||||
let k_ipad[i] = s:bitwise_xor(get(key, i, 0), 0x36)
|
|
||||||
let k_opad[i] = s:bitwise_xor(get(key, i, 0), 0x5c)
|
|
||||||
endfor
|
|
||||||
let hash1 = s:hex2bytes(call(a:hash, [k_ipad + a:text]))
|
|
||||||
let hmac = call(a:hash, [k_opad + hash1])
|
|
||||||
return hmac
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:str2bytes(str)
|
|
||||||
return map(range(len(a:str)), 'char2nr(a:str[v:val])')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:hex2bytes(str)
|
|
||||||
return map(split(a:str, '..\zs'), 'str2nr(v:val, 16)')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:xor = [
|
|
||||||
\ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
|
|
||||||
\ [0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6, 0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE],
|
|
||||||
\ [0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5, 0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD],
|
|
||||||
\ [0x3, 0x2, 0x1, 0x0, 0x7, 0x6, 0x5, 0x4, 0xB, 0xA, 0x9, 0x8, 0xF, 0xE, 0xD, 0xC],
|
|
||||||
\ [0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB],
|
|
||||||
\ [0x5, 0x4, 0x7, 0x6, 0x1, 0x0, 0x3, 0x2, 0xD, 0xC, 0xF, 0xE, 0x9, 0x8, 0xB, 0xA],
|
|
||||||
\ [0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1, 0xE, 0xF, 0xC, 0xD, 0xA, 0xB, 0x8, 0x9],
|
|
||||||
\ [0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8],
|
|
||||||
\ [0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7],
|
|
||||||
\ [0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE, 0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6],
|
|
||||||
\ [0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD, 0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5],
|
|
||||||
\ [0xB, 0xA, 0x9, 0x8, 0xF, 0xE, 0xD, 0xC, 0x3, 0x2, 0x1, 0x0, 0x7, 0x6, 0x5, 0x4],
|
|
||||||
\ [0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3],
|
|
||||||
\ [0xD, 0xC, 0xF, 0xE, 0x9, 0x8, 0xB, 0xA, 0x5, 0x4, 0x7, 0x6, 0x1, 0x0, 0x3, 0x2],
|
|
||||||
\ [0xE, 0xF, 0xC, 0xD, 0xA, 0xB, 0x8, 0x9, 0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1],
|
|
||||||
\ [0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0]
|
|
||||||
\ ]
|
|
||||||
|
|
||||||
function! s:bitwise_xor(a, b)
|
|
||||||
let a = a:a < 0 ? a:a - 0x80000000 : a:a
|
|
||||||
let b = a:b < 0 ? a:b - 0x80000000 : a:b
|
|
||||||
let r = 0
|
|
||||||
let n = 1
|
|
||||||
while a || b
|
|
||||||
let r += s:xor[a % 0x10][b % 0x10] * n
|
|
||||||
let a = a / 0x10
|
|
||||||
let b = b / 0x10
|
|
||||||
let n = n * 0x10
|
|
||||||
endwhile
|
|
||||||
if (a:a < 0) != (a:b < 0)
|
|
||||||
let r += 0x80000000
|
|
||||||
endif
|
|
||||||
return r
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
" html
|
|
||||||
" Last Change: 2010-09-10
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
"
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! s:nr2byte(nr)
|
|
||||||
if a:nr < 0x80
|
|
||||||
return nr2char(a:nr)
|
|
||||||
elseif a:nr < 0x800
|
|
||||||
return nr2char(a:nr/64+192).nr2char(a:nr%64+128)
|
|
||||||
else
|
|
||||||
return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:nr2enc_char(charcode)
|
|
||||||
if &encoding == 'utf-8'
|
|
||||||
return nr2char(a:charcode)
|
|
||||||
endif
|
|
||||||
let char = s:nr2byte(a:charcode)
|
|
||||||
if strlen(char) > 1
|
|
||||||
let char = strtrans(iconv(char, 'utf-8', &encoding))
|
|
||||||
endif
|
|
||||||
return char
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#html#decodeEntityReference(str)
|
|
||||||
let str = a:str
|
|
||||||
let str = substitute(str, '>', '>', 'g')
|
|
||||||
let str = substitute(str, '<', '<', 'g')
|
|
||||||
let str = substitute(str, '"', '"', 'g')
|
|
||||||
let str = substitute(str, ''', "'", 'g')
|
|
||||||
let str = substitute(str, ' ', ' ', 'g')
|
|
||||||
let str = substitute(str, '¥', '\¥', 'g')
|
|
||||||
let str = substitute(str, '&#\(\d\+\);', '\=s:nr2enc_char(submatch(1))', 'g')
|
|
||||||
let str = substitute(str, '&', '\&', 'g')
|
|
||||||
let str = substitute(str, '»', '>', 'g')
|
|
||||||
let str = substitute(str, '«', '<', 'g')
|
|
||||||
return str
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#html#encodeEntityReference(str)
|
|
||||||
let str = a:str
|
|
||||||
let str = substitute(str, '&', '\&', 'g')
|
|
||||||
let str = substitute(str, '>', '\>', 'g')
|
|
||||||
let str = substitute(str, '<', '\<', 'g')
|
|
||||||
let str = substitute(str, "\n", '\
', 'g')
|
|
||||||
let str = substitute(str, '"', '\"', 'g')
|
|
||||||
let str = substitute(str, "'", '\'', 'g')
|
|
||||||
let str = substitute(str, ' ', '\ ', 'g')
|
|
||||||
return str
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#html#parse(html)
|
|
||||||
let html = substitute(a:html, '<\(area\|base\|basefont\|br\|nobr\|col\|frame\|hr\|img\|input\|isindex\|link\|meta\|param\|embed\|keygen\|command\)\([^>]*[^/]\|\)>', '<\1\2/>', 'g')
|
|
||||||
return webapi#xml#parse(html)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#html#parseFile(fname)
|
|
||||||
return webapi#html#parse(join(readfile(a:fname), "\n"))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#html#parseURL(url)
|
|
||||||
return webapi#html#parse(webapi#http#get(a:url).content)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
" http
|
|
||||||
" Last Change: 2010-09-10
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
let s:system = function(get(g:, 'webapi#system_function', 'system'))
|
|
||||||
|
|
||||||
function! s:nr2byte(nr)
|
|
||||||
if a:nr < 0x80
|
|
||||||
return nr2char(a:nr)
|
|
||||||
elseif a:nr < 0x800
|
|
||||||
return nr2char(a:nr/64+192).nr2char(a:nr%64+128)
|
|
||||||
elseif a:nr < 0x10000
|
|
||||||
return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
|
|
||||||
elseif a:nr < 0x200000
|
|
||||||
return nr2char(a:nr/262144%16+240).nr2char(a:nr/4096/16+128).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
|
|
||||||
elseif a:nr < 0x4000000
|
|
||||||
return nr2char(a:nr/16777216%16+248).nr2char(a:nr/262144%16+128).nr2char(a:nr/4096/16+128).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
|
|
||||||
else
|
|
||||||
return nr2char(a:nr/1073741824%16+252).nr2char(a:nr/16777216%16+128).nr2char(a:nr/262144%16+128).nr2char(a:nr/4096/16+128).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:nr2enc_char(charcode)
|
|
||||||
if &encoding == 'utf-8'
|
|
||||||
return nr2char(a:charcode)
|
|
||||||
endif
|
|
||||||
let char = s:nr2byte(a:charcode)
|
|
||||||
if strlen(char) > 1
|
|
||||||
let char = strtrans(iconv(char, 'utf-8', &encoding))
|
|
||||||
endif
|
|
||||||
return char
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:nr2hex(nr)
|
|
||||||
let n = a:nr
|
|
||||||
let r = ""
|
|
||||||
while n
|
|
||||||
let r = '0123456789ABCDEF'[n % 16] . r
|
|
||||||
let n = n / 16
|
|
||||||
endwhile
|
|
||||||
return r
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:urlencode_char(c)
|
|
||||||
let utf = iconv(a:c, &encoding, "utf-8")
|
|
||||||
if utf == ""
|
|
||||||
let utf = a:c
|
|
||||||
endif
|
|
||||||
let s = ""
|
|
||||||
for i in range(strlen(utf))
|
|
||||||
let s .= printf("%%%02X", char2nr(utf[i]))
|
|
||||||
endfor
|
|
||||||
return s
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#http#decodeURI(str)
|
|
||||||
let ret = a:str
|
|
||||||
let ret = substitute(ret, '+', ' ', 'g')
|
|
||||||
let ret = substitute(ret, '%\(\x\x\)', '\=printf("%c", str2nr(submatch(1), 16))', 'g')
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#http#escape(str)
|
|
||||||
return substitute(a:str, '[^a-zA-Z0-9_.~/-]', '\=s:urlencode_char(submatch(0))', 'g')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#http#encodeURI(items)
|
|
||||||
let ret = ''
|
|
||||||
if type(a:items) == 4
|
|
||||||
for key in sort(keys(a:items))
|
|
||||||
if strlen(ret) | let ret .= "&" | endif
|
|
||||||
let ret .= key . "=" . webapi#http#encodeURI(a:items[key])
|
|
||||||
endfor
|
|
||||||
elseif type(a:items) == 3
|
|
||||||
for item in sort(a:items)
|
|
||||||
if strlen(ret) | let ret .= "&" | endif
|
|
||||||
let ret .= item
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
let ret = substitute(a:items, '[^a-zA-Z0-9_.~-]', '\=s:urlencode_char(submatch(0))', 'g')
|
|
||||||
endif
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#http#encodeURIComponent(items)
|
|
||||||
let ret = ''
|
|
||||||
if type(a:items) == 4
|
|
||||||
for key in sort(keys(a:items))
|
|
||||||
if strlen(ret) | let ret .= "&" | endif
|
|
||||||
let ret .= key . "=" . webapi#http#encodeURIComponent(a:items[key])
|
|
||||||
endfor
|
|
||||||
elseif type(a:items) == 3
|
|
||||||
for item in sort(a:items)
|
|
||||||
if strlen(ret) | let ret .= "&" | endif
|
|
||||||
let ret .= item
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
let items = iconv(a:items, &enc, "utf-8")
|
|
||||||
let len = strlen(items)
|
|
||||||
let i = 0
|
|
||||||
while i < len
|
|
||||||
let ch = items[i]
|
|
||||||
if ch =~# '[0-9A-Za-z-._~!''()*]'
|
|
||||||
let ret .= ch
|
|
||||||
elseif ch == ' '
|
|
||||||
let ret .= '+'
|
|
||||||
else
|
|
||||||
let ret .= '%' . substitute('0' . s:nr2hex(char2nr(ch)), '^.*\(..\)$', '\1', '')
|
|
||||||
endif
|
|
||||||
let i = i + 1
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#http#get(url, ...)
|
|
||||||
let getdata = a:0 > 0 ? a:000[0] : {}
|
|
||||||
let headdata = a:0 > 1 ? a:000[1] : {}
|
|
||||||
let follow = a:0 > 2 ? a:000[2] : 1
|
|
||||||
let url = a:url
|
|
||||||
let getdatastr = webapi#http#encodeURI(getdata)
|
|
||||||
if strlen(getdatastr)
|
|
||||||
let url .= "?" . getdatastr
|
|
||||||
endif
|
|
||||||
if executable('curl')
|
|
||||||
let command = printf('curl %s -s -k -i', follow ? '-L' : '')
|
|
||||||
let quote = &shellxquote == '"' ? "'" : '"'
|
|
||||||
for key in keys(headdata)
|
|
||||||
if has('win32')
|
|
||||||
let command .= " -H " . quote . key . ": " . substitute(headdata[key], '"', '"""', 'g') . quote
|
|
||||||
else
|
|
||||||
let command .= " -H " . quote . key . ": " . headdata[key] . quote
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
let command .= " ".quote.url.quote
|
|
||||||
let res = s:system(command)
|
|
||||||
elseif executable('wget')
|
|
||||||
let command = printf('wget -O- --save-headers --server-response -q %s', follow ? '-L' : '')
|
|
||||||
let quote = &shellxquote == '"' ? "'" : '"'
|
|
||||||
for key in keys(headdata)
|
|
||||||
if has('win32')
|
|
||||||
let command .= " --header=" . quote . key . ": " . substitute(headdata[key], '"', '"""', 'g') . quote
|
|
||||||
else
|
|
||||||
let command .= " --header=" . quote . key . ": " . headdata[key] . quote
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
let command .= " ".quote.url.quote
|
|
||||||
let res = s:system(command)
|
|
||||||
else
|
|
||||||
throw "require `curl` or `wget` command"
|
|
||||||
endif
|
|
||||||
if follow != 0
|
|
||||||
while res =~ '^HTTP/1.\d 3' || res =~ '^HTTP/1\.\d 200 Connection established' || res =~ '^HTTP/1\.\d 100 Continue'
|
|
||||||
let pos = stridx(res, "\r\n\r\n")
|
|
||||||
if pos != -1
|
|
||||||
let res = strpart(res, pos+4)
|
|
||||||
else
|
|
||||||
let pos = stridx(res, "\n\n")
|
|
||||||
let res = strpart(res, pos+2)
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
let pos = stridx(res, "\r\n\r\n")
|
|
||||||
if pos != -1
|
|
||||||
let content = strpart(res, pos+4)
|
|
||||||
else
|
|
||||||
let pos = stridx(res, "\n\n")
|
|
||||||
let content = strpart(res, pos+2)
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ "header" : split(res[:pos-1], '\r\?\n'),
|
|
||||||
\ "content" : content
|
|
||||||
\}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#http#post(url, ...)
|
|
||||||
let postdata = a:0 > 0 ? a:000[0] : {}
|
|
||||||
let headdata = a:0 > 1 ? a:000[1] : {}
|
|
||||||
let method = a:0 > 2 ? a:000[2] : "POST"
|
|
||||||
let follow = a:0 > 3 ? a:000[3] : 1
|
|
||||||
let url = a:url
|
|
||||||
if type(postdata) == 4
|
|
||||||
let postdatastr = webapi#http#encodeURI(postdata)
|
|
||||||
else
|
|
||||||
let postdatastr = postdata
|
|
||||||
endif
|
|
||||||
let file = tempname()
|
|
||||||
if executable('curl')
|
|
||||||
let command = printf('curl %s -s -k -i -X %s', (follow ? '-L' : ''), len(method) ? method : 'POST')
|
|
||||||
let quote = &shellxquote == '"' ? "'" : '"'
|
|
||||||
for key in keys(headdata)
|
|
||||||
if has('win32')
|
|
||||||
let command .= " -H " . quote . key . ": " . substitute(headdata[key], '"', '"""', 'g') . quote
|
|
||||||
else
|
|
||||||
let command .= " -H " . quote . key . ": " . headdata[key] . quote
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
let command .= " ".quote.url.quote
|
|
||||||
call writefile(split(postdatastr, "\n"), file, "b")
|
|
||||||
let res = s:system(command . " --data-binary @" . quote.file.quote)
|
|
||||||
elseif executable('wget')
|
|
||||||
let command = printf('wget -O- --save-headers --server-response -q %s', follow ? '-L' : '')
|
|
||||||
let headdata['X-HTTP-Method-Override'] = method
|
|
||||||
let quote = &shellxquote == '"' ? "'" : '"'
|
|
||||||
for key in keys(headdata)
|
|
||||||
if has('win32')
|
|
||||||
let command .= " --header=" . quote . key . ": " . substitute(headdata[key], '"', '"""', 'g') . quote
|
|
||||||
else
|
|
||||||
let command .= " --header=" . quote . key . ": " . headdata[key] . quote
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
let command .= " ".quote.url.quote
|
|
||||||
call writefile(split(postdatastr, "\n"), file, "b")
|
|
||||||
let res = s:system(command . " --post-data @" . quote.file.quote)
|
|
||||||
else
|
|
||||||
throw "require `curl` or `wget` command"
|
|
||||||
endif
|
|
||||||
call delete(file)
|
|
||||||
if follow != 0
|
|
||||||
while res =~ '^HTTP/1.\d 3' || res =~ '^HTTP/1\.\d 200 Connection established' || res =~ '^HTTP/1\.\d 100 Continue'
|
|
||||||
let pos = stridx(res, "\r\n\r\n")
|
|
||||||
if pos != -1
|
|
||||||
let res = strpart(res, pos+4)
|
|
||||||
else
|
|
||||||
let pos = stridx(res, "\n\n")
|
|
||||||
let res = strpart(res, pos+2)
|
|
||||||
endif
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
let pos = stridx(res, "\r\n\r\n")
|
|
||||||
if pos != -1
|
|
||||||
let content = strpart(res, pos+4)
|
|
||||||
else
|
|
||||||
let pos = stridx(res, "\n\n")
|
|
||||||
let content = strpart(res, pos+2)
|
|
||||||
endif
|
|
||||||
return {
|
|
||||||
\ "header" : split(res[:pos-1], '\r\?\n'),
|
|
||||||
\ "content" : content
|
|
||||||
\}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,135 +0,0 @@
|
||||||
" json
|
|
||||||
" Last Change: 2012-03-08
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
"
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! webapi#json#null()
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#json#true()
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#json#false()
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:nr2byte(nr)
|
|
||||||
if a:nr < 0x80
|
|
||||||
return nr2char(a:nr)
|
|
||||||
elseif a:nr < 0x800
|
|
||||||
return nr2char(a:nr/64+192).nr2char(a:nr%64+128)
|
|
||||||
else
|
|
||||||
return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:nr2enc_char(charcode)
|
|
||||||
if &encoding == 'utf-8'
|
|
||||||
return nr2char(a:charcode)
|
|
||||||
endif
|
|
||||||
let char = s:nr2byte(a:charcode)
|
|
||||||
if strlen(char) > 1
|
|
||||||
let char = strtrans(iconv(char, 'utf-8', &encoding))
|
|
||||||
endif
|
|
||||||
return char
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:fixup(val, tmp)
|
|
||||||
if type(a:val) == 0
|
|
||||||
return a:val
|
|
||||||
elseif type(a:val) == 1
|
|
||||||
if a:val == a:tmp.'null'
|
|
||||||
return function('webapi#json#null')
|
|
||||||
elseif a:val == a:tmp.'true'
|
|
||||||
return function('webapi#json#true')
|
|
||||||
elseif a:val == a:tmp.'false'
|
|
||||||
return function('webapi#json#false')
|
|
||||||
endif
|
|
||||||
return a:val
|
|
||||||
elseif type(a:val) == 2
|
|
||||||
return a:val
|
|
||||||
elseif type(a:val) == 3
|
|
||||||
return map(a:val, 's:fixup(v:val, a:tmp)')
|
|
||||||
elseif type(a:val) == 4
|
|
||||||
return map(a:val, 's:fixup(v:val, a:tmp)')
|
|
||||||
else
|
|
||||||
return string(a:val)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#json#decode(json)
|
|
||||||
let json = iconv(a:json, "utf-8", &encoding)
|
|
||||||
if get(g:, 'webapi#json#parse_strict', 1) == 1 && substitute(substitute(substitute(
|
|
||||||
\ json,
|
|
||||||
\ '\\\%(["\\/bfnrt]\|u[0-9a-fA-F]\{4}\)', '\@', 'g'),
|
|
||||||
\ '"[^\"\\\n\r]*\"\|true\|false\|null\|-\?\d\+'
|
|
||||||
\ . '\%(\.\d*\)\?\%([eE][+\-]\{-}\d\+\)\?', ']', 'g'),
|
|
||||||
\ '\%(^\|:\|,\)\%(\s*\[\)\+', '', 'g') !~ '^[\],:{} \t\n]*$'
|
|
||||||
throw json
|
|
||||||
endif
|
|
||||||
let json = substitute(json, '\n', '', 'g')
|
|
||||||
let json = substitute(json, '\\u34;', '\\"', 'g')
|
|
||||||
if v:version >= 703 && has('patch780')
|
|
||||||
let json = substitute(json, '\\u\(\x\x\x\x\)', '\=iconv(nr2char(str2nr(submatch(1), 16), 1), "utf-8", &encoding)', 'g')
|
|
||||||
else
|
|
||||||
let json = substitute(json, '\\u\(\x\x\x\x\)', '\=s:nr2enc_char("0x".submatch(1))', 'g')
|
|
||||||
endif
|
|
||||||
if get(g:, 'webapi#json#allow_nil', 0) != 0
|
|
||||||
let tmp = '__WEBAPI_JSON__'
|
|
||||||
while 1
|
|
||||||
if stridx(json, tmp) == -1
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
let tmp .= '_'
|
|
||||||
endwhile
|
|
||||||
let [null,true,false] = [
|
|
||||||
\ tmp.'null',
|
|
||||||
\ tmp.'true',
|
|
||||||
\ tmp.'false']
|
|
||||||
sandbox let ret = eval(json)
|
|
||||||
call s:fixup(ret, tmp)
|
|
||||||
else
|
|
||||||
let [null,true,false] = [0,1,0]
|
|
||||||
sandbox let ret = eval(json)
|
|
||||||
endif
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#json#encode(val)
|
|
||||||
if type(a:val) == 0
|
|
||||||
return a:val
|
|
||||||
elseif type(a:val) == 1
|
|
||||||
let json = '"' . escape(a:val, '\"') . '"'
|
|
||||||
let json = substitute(json, "\r", '\\r', 'g')
|
|
||||||
let json = substitute(json, "\n", '\\n', 'g')
|
|
||||||
let json = substitute(json, "\t", '\\t', 'g')
|
|
||||||
let json = substitute(json, '\([[:cntrl:]]\)', '\=printf("\x%02d", char2nr(submatch(1)))', 'g')
|
|
||||||
return iconv(json, &encoding, "utf-8")
|
|
||||||
elseif type(a:val) == 2
|
|
||||||
let s = string(a:val)
|
|
||||||
if s == "function('webapi#json#null')"
|
|
||||||
return 'null'
|
|
||||||
elseif s == "function('webapi#json#true')"
|
|
||||||
return 'true'
|
|
||||||
elseif s == "function('webapi#json#false')"
|
|
||||||
return 'false'
|
|
||||||
endif
|
|
||||||
elseif type(a:val) == 3
|
|
||||||
return '[' . join(map(copy(a:val), 'webapi#json#encode(v:val)'), ',') . ']'
|
|
||||||
elseif type(a:val) == 4
|
|
||||||
return '{' . join(map(keys(a:val), 'webapi#json#encode(v:val).":".webapi#json#encode(a:val[v:val])'), ',') . '}'
|
|
||||||
else
|
|
||||||
return string(a:val)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
" jsonrpc
|
|
||||||
" Last Change: 2012-03-08
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
" http://tools.ietf.org/rfc/rfc4627.txt
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! webapi#jsonrpc#call(uri, func, args)
|
|
||||||
let data = webapi#json#encode({
|
|
||||||
\ 'jsonrpc': '2.0',
|
|
||||||
\ 'method': a:func,
|
|
||||||
\ 'params': a:args,
|
|
||||||
\})
|
|
||||||
let res = webapi#http#post(a:uri, data, {"Content-Type": "application/json"})
|
|
||||||
let obj = webapi#json#decode(res.content)
|
|
||||||
if has_key(obj, 'error')
|
|
||||||
if type(obj.error) == 0 && obj.error != 0
|
|
||||||
throw obj.error
|
|
||||||
elseif type(obj.error) == 1 && obj.error != ''
|
|
||||||
throw obj.error
|
|
||||||
elseif type(obj.error) == 2 && string(obj.error) != "function('webapi#json#null')"
|
|
||||||
throw obj.error
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if has_key(obj, 'result')
|
|
||||||
return obj.result
|
|
||||||
endif
|
|
||||||
throw "Parse Error"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#jsonrpc#wrap(contexts)
|
|
||||||
let api = {}
|
|
||||||
for context in a:contexts
|
|
||||||
let target = api
|
|
||||||
let namespaces = split(context.name, '\.')[:-2]
|
|
||||||
if len(namespaces) > 0
|
|
||||||
for ns in namespaces
|
|
||||||
if !has_key(target, ns)
|
|
||||||
let target[ns] = {".uri": context.uri}
|
|
||||||
endif
|
|
||||||
let target = target[ns]
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if !has_key(context, 'argnames')
|
|
||||||
let context['argnames'] = ['args']
|
|
||||||
let arglist = 'a:args'
|
|
||||||
else
|
|
||||||
if len(context.argnames) && context.argnames[-1] == '...'
|
|
||||||
let arglist = '[' . join(map(copy(context.argnames[:-2]),'"a:".v:val'),',') . ']+a:000'
|
|
||||||
else
|
|
||||||
let arglist = '[' . join(map(copy(context.argnames),'"a:".v:val'),',') . ']'
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
if has_key(context, 'alias')
|
|
||||||
exe "function api.".context.alias."(".join(context.argnames,",").") dict\n"
|
|
||||||
\. " return webapi#jsonrpc#call(self['.uri'], '".context.name."', ".arglist.")\n"
|
|
||||||
\. "endfunction\n"
|
|
||||||
else
|
|
||||||
exe "function api.".context.name."(".join(context.argnames,",").") dict\n"
|
|
||||||
\. " return webapi#jsonrpc#call('".context.uri."', '".context.name."', ".arglist.")\n"
|
|
||||||
\. "endfunction\n"
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return api
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
" metaweblog
|
|
||||||
" Last Change: 2010-09-10
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
" http://tools.ietf.org/rfc/rfc3529.txt
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
let s:template = {"uri" : ""}
|
|
||||||
|
|
||||||
function! s:template.newPost(blogid, username, password, content, publish) dict
|
|
||||||
return webapi#xmlrpc#call(self.uri, 'metaWeblog.newPost', [a:blogid, a:username, a:password, a:content, a:publish])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.editPost(postid, username, password, content, publish) dict
|
|
||||||
return webapi#xmlrpc#call(self.uri, 'metaWeblog.editPost', [a:postid, a:username, a:password, a:content, a:publish])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.getPost(postid, username, password) dict
|
|
||||||
return webapi#xmlrpc#call(self.uri, 'metaWeblog.getPost', [a:postid, a:username, a:password])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.getRecentPosts(blogid, username, password, numberOfPosts) dict
|
|
||||||
return webapi#xmlrpc#call(self.uri, 'metaWeblog.getRecentPosts', [a:blogid, a:username, a:password, a:numberOfPosts])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.deletePost(appkey, postid, username, password, ...) dict
|
|
||||||
return webapi#xmlrpc#call(self.uri, 'blogger.deletePost', [a:apikey, a:postid, a:username, a:password])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.newMediaObject(blogid, username, password, file) dict
|
|
||||||
return webapi#xmlrpc#call(self.uri, 'metaWeblog.newMediaObject', [a:blogid, a:username, a:password, a:file])
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#metaWeblog#proxy(uri)
|
|
||||||
let ctx = deepcopy(s:template)
|
|
||||||
let ctx.uri = a:uri
|
|
||||||
return ctx
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,162 +0,0 @@
|
||||||
" oauth
|
|
||||||
" Last Change: 2010-09-10
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
" http://tools.ietf.org/rfc/rfc5849.txt
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! webapi#oauth#request_token(url, ctx, ...)
|
|
||||||
let params = a:0 > 0 ? a:000[0] : {}
|
|
||||||
let query = {}
|
|
||||||
let time_stamp = localtime()
|
|
||||||
let nonce = time_stamp . " " . time_stamp
|
|
||||||
let nonce = webapi#sha1#sha1(nonce)[0:28]
|
|
||||||
let query["oauth_consumer_key"] = a:ctx.consumer_key
|
|
||||||
let query["oauth_nonce"] = nonce
|
|
||||||
let query["oauth_request_method"] = "POST"
|
|
||||||
let query["oauth_signature_method"] = "HMAC-SHA1"
|
|
||||||
let query["oauth_timestamp"] = time_stamp
|
|
||||||
let query["oauth_version"] = "1.0"
|
|
||||||
for key in keys(params)
|
|
||||||
let query[key] = params[key]
|
|
||||||
endfor
|
|
||||||
let query_string = "POST&"
|
|
||||||
let query_string .= webapi#http#encodeURI(a:url)
|
|
||||||
let query_string .= "&"
|
|
||||||
let query_string .= webapi#http#encodeURI(webapi#http#encodeURI(query))
|
|
||||||
let hmacsha1 = webapi#hmac#sha1(webapi#http#encodeURI(a:ctx.consumer_secret) . "&", query_string)
|
|
||||||
let query["oauth_signature"] = webapi#base64#b64encodebin(hmacsha1)
|
|
||||||
let res = webapi#http#post(a:url, query, {})
|
|
||||||
let a:ctx.request_token = webapi#http#decodeURI(substitute(filter(split(res.content, "&"), "v:val =~ '^oauth_token='")[0], '^[^=]*=', '', ''))
|
|
||||||
let a:ctx.request_token_secret = webapi#http#decodeURI(substitute(filter(split(res.content, "&"), "v:val =~ '^oauth_token_secret='")[0], '^[^=]*=', '', ''))
|
|
||||||
return a:ctx
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#oauth#access_token(url, ctx, ...)
|
|
||||||
let params = a:0 > 0 ? a:000[0] : {}
|
|
||||||
let query = {}
|
|
||||||
let time_stamp = localtime()
|
|
||||||
let nonce = time_stamp . " " . time_stamp
|
|
||||||
let nonce = webapi#sha1#sha1(nonce)[0:28]
|
|
||||||
let query["oauth_consumer_key"] = a:ctx.consumer_key
|
|
||||||
let query["oauth_nonce"] = nonce
|
|
||||||
let query["oauth_request_method"] = "POST"
|
|
||||||
let query["oauth_signature_method"] = "HMAC-SHA1"
|
|
||||||
let query["oauth_timestamp"] = time_stamp
|
|
||||||
let query["oauth_token"] = a:ctx.request_token
|
|
||||||
let query["oauth_token_secret"] = a:ctx.request_token_secret
|
|
||||||
let query["oauth_version"] = "1.0"
|
|
||||||
for key in keys(params)
|
|
||||||
let query[key] = params[key]
|
|
||||||
endfor
|
|
||||||
let query_string = "POST&"
|
|
||||||
let query_string .= webapi#http#encodeURI(a:url)
|
|
||||||
let query_string .= "&"
|
|
||||||
let query_string .= webapi#http#encodeURI(webapi#http#encodeURI(query))
|
|
||||||
let hmacsha1 = webapi#hmac#sha1(webapi#http#encodeURI(a:ctx.consumer_secret) . "&" . webapi#http#encodeURI(a:ctx.request_token_secret), query_string)
|
|
||||||
let query["oauth_signature"] = webapi#base64#b64encodebin(hmacsha1)
|
|
||||||
let res = webapi#http#post(a:url, query, {})
|
|
||||||
let a:ctx.access_token = webapi#http#decodeURI(substitute(filter(split(res.content, "&"), "v:val =~ '^oauth_token='")[0], '^[^=]*=', '', ''))
|
|
||||||
let a:ctx.access_token_secret = webapi#http#decodeURI(substitute(filter(split(res.content, "&"), "v:val =~ '^oauth_token_secret='")[0], '^[^=]*=', '', ''))
|
|
||||||
return a:ctx
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#oauth#get(url, ctx, ...)
|
|
||||||
let params = a:0 > 0 ? a:000[0] : {}
|
|
||||||
let getdata = a:0 > 1 ? a:000[1] : {}
|
|
||||||
let headdata = a:0 > 2 ? a:000[2] : {}
|
|
||||||
let query = {}
|
|
||||||
let time_stamp = localtime()
|
|
||||||
let nonce = time_stamp . " " . time_stamp
|
|
||||||
let nonce = webapi#sha1#sha1(nonce)[0:28]
|
|
||||||
let query["oauth_consumer_key"] = a:ctx.consumer_key
|
|
||||||
let query["oauth_nonce"] = nonce
|
|
||||||
let query["oauth_request_method"] = "GET"
|
|
||||||
let query["oauth_signature_method"] = "HMAC-SHA1"
|
|
||||||
let query["oauth_timestamp"] = time_stamp
|
|
||||||
let query["oauth_token"] = a:ctx.access_token
|
|
||||||
let query["oauth_version"] = "1.0"
|
|
||||||
if type(params) == 4
|
|
||||||
for key in keys(params)
|
|
||||||
let query[key] = params[key]
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if type(getdata) == 4
|
|
||||||
for key in keys(getdata)
|
|
||||||
let query[key] = getdata[key]
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let query_string = query["oauth_request_method"] . "&"
|
|
||||||
let query_string .= webapi#http#encodeURI(a:url)
|
|
||||||
let query_string .= "&"
|
|
||||||
let query_string .= webapi#http#encodeURI(webapi#http#encodeURI(query))
|
|
||||||
let hmacsha1 = webapi#hmac#sha1(webapi#http#encodeURI(a:ctx.consumer_secret) . "&" . webapi#http#encodeURI(a:ctx.access_token_secret), query_string)
|
|
||||||
let query["oauth_signature"] = webapi#base64#b64encodebin(hmacsha1)
|
|
||||||
if type(getdata) == 4
|
|
||||||
for key in keys(getdata)
|
|
||||||
call remove(query, key)
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let auth = 'OAuth '
|
|
||||||
for key in sort(keys(query))
|
|
||||||
let auth .= key . '="' . webapi#http#encodeURI(query[key]) . '", '
|
|
||||||
endfor
|
|
||||||
let auth = auth[:-3]
|
|
||||||
let headdata["Authorization"] = auth
|
|
||||||
let res = webapi#http#get(a:url, getdata, headdata)
|
|
||||||
return res
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#oauth#post(url, ctx, ...)
|
|
||||||
let params = a:0 > 0 ? a:000[0] : {}
|
|
||||||
let postdata = a:0 > 1 ? a:000[1] : {}
|
|
||||||
let headdata = a:0 > 2 ? a:000[2] : {}
|
|
||||||
let query = {}
|
|
||||||
let time_stamp = localtime()
|
|
||||||
let nonce = time_stamp . " " . time_stamp
|
|
||||||
let nonce = webapi#sha1#sha1(nonce)[0:28]
|
|
||||||
let query["oauth_consumer_key"] = a:ctx.consumer_key
|
|
||||||
let query["oauth_nonce"] = nonce
|
|
||||||
let query["oauth_request_method"] = "POST"
|
|
||||||
let query["oauth_signature_method"] = "HMAC-SHA1"
|
|
||||||
let query["oauth_timestamp"] = time_stamp
|
|
||||||
let query["oauth_token"] = a:ctx.access_token
|
|
||||||
let query["oauth_version"] = "1.0"
|
|
||||||
if type(params) == 4
|
|
||||||
for key in keys(params)
|
|
||||||
let query[key] = params[key]
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if type(postdata) == 4
|
|
||||||
for key in keys(postdata)
|
|
||||||
let query[key] = postdata[key]
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let query_string = query["oauth_request_method"] . "&"
|
|
||||||
let query_string .= webapi#http#encodeURI(a:url)
|
|
||||||
let query_string .= "&"
|
|
||||||
let query_string .= webapi#http#encodeURI(webapi#http#encodeURI(query))
|
|
||||||
let hmacsha1 = webapi#hmac#sha1(webapi#http#encodeURI(a:ctx.consumer_secret) . "&" . webapi#http#encodeURI(a:ctx.access_token_secret), query_string)
|
|
||||||
let query["oauth_signature"] = webapi#base64#b64encodebin(hmacsha1)
|
|
||||||
if type(postdata) == 4
|
|
||||||
for key in keys(postdata)
|
|
||||||
call remove(query, key)
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
let auth = 'OAuth '
|
|
||||||
for key in sort(keys(query))
|
|
||||||
let auth .= webapi#http#escape(key) . '="' . webapi#http#escape(query[key]) . '",'
|
|
||||||
endfor
|
|
||||||
let auth = auth[:-2]
|
|
||||||
let headdata["Authorization"] = auth
|
|
||||||
let res = webapi#http#post(a:url, postdata, headdata)
|
|
||||||
return res
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,746 +0,0 @@
|
||||||
" sha1 digest calculator
|
|
||||||
" This is a port of rfc3174 sha1 function.
|
|
||||||
" http://www.ietf.org/rfc/rfc3174.txt
|
|
||||||
" Last Change: 2010-02-13
|
|
||||||
" Maintainer: Yukihiro Nakadaira <yukihiro.nakadaira@gmail.com>
|
|
||||||
" Original Copyright:
|
|
||||||
" Copyright (C) The Internet Society (2001). All Rights Reserved.
|
|
||||||
"
|
|
||||||
" This document and translations of it may be copied and furnished to
|
|
||||||
" others, and derivative works that comment on or otherwise explain it
|
|
||||||
" or assist in its implementation may be prepared, copied, published
|
|
||||||
" and distributed, in whole or in part, without restriction of any
|
|
||||||
" kind, provided that the above copyright notice and this paragraph are
|
|
||||||
" included on all such copies and derivative works. However, this
|
|
||||||
" document itself may not be modified in any way, such as by removing
|
|
||||||
" the copyright notice or references to the Internet Society or other
|
|
||||||
" Internet organizations, except as needed for the purpose of
|
|
||||||
" developing Internet standards in which case the procedures for
|
|
||||||
" copyrights defined in the Internet Standards process must be
|
|
||||||
" followed, or as required to translate it into languages other than
|
|
||||||
" English.
|
|
||||||
"
|
|
||||||
" The limited permissions granted above are perpetual and will not be
|
|
||||||
" revoked by the Internet Society or its successors or assigns.
|
|
||||||
"
|
|
||||||
" This document and the information contained herein is provided on an
|
|
||||||
" "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
|
||||||
" TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
|
||||||
" BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
|
||||||
" HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
|
||||||
" MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! webapi#sha1#sha1(str)
|
|
||||||
return s:SHA1Digest(s:str2bytes(a:str))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#sha1#sha1bin(bin)
|
|
||||||
return s:SHA1Digest(a:bin)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#sha1#test()
|
|
||||||
call s:main()
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:SHA1Digest(bytes)
|
|
||||||
let sha = deepcopy(s:SHA1Context, 1)
|
|
||||||
let Message_Digest = repeat([0], 20)
|
|
||||||
|
|
||||||
let err = s:SHA1Reset(sha)
|
|
||||||
if err
|
|
||||||
throw printf("SHA1Reset Error %d", err)
|
|
||||||
endif
|
|
||||||
|
|
||||||
let err = s:SHA1Input(sha, a:bytes)
|
|
||||||
if err
|
|
||||||
throw printf("SHA1Input Error %d", err)
|
|
||||||
endif
|
|
||||||
|
|
||||||
let err = s:SHA1Result(sha, Message_Digest)
|
|
||||||
if err
|
|
||||||
throw printf("SHA1Result Error %d", err)
|
|
||||||
endif
|
|
||||||
|
|
||||||
return join(map(Message_Digest, 'printf("%02x", v:val)'), '')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
" sha1.h
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" This is the header file for code which implements the Secure
|
|
||||||
" Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
|
|
||||||
" April 17, 1995.
|
|
||||||
"
|
|
||||||
" Many of the variable names in this code, especially the
|
|
||||||
" single character names, were used because those were the names
|
|
||||||
" used in the publication.
|
|
||||||
"
|
|
||||||
" Please read the file sha1.c for more information.
|
|
||||||
|
|
||||||
"
|
|
||||||
" If you do not have the ISO standard stdint.h header file, then you
|
|
||||||
" must typdef the following:
|
|
||||||
" name meaning
|
|
||||||
" uint32_t unsigned 32 bit integer
|
|
||||||
" uint8_t unsigned 8 bit integer (i.e., unsigned char)
|
|
||||||
" int_least16_t integer of >= 16 bits
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
" enum
|
|
||||||
let s:shaSuccess = 0
|
|
||||||
let s:shaNull = 1 " Null pointer parameter
|
|
||||||
let s:shaInputTooLong = 2 " input data too long
|
|
||||||
let s:shaStateError = 3 " called Input after Result
|
|
||||||
|
|
||||||
" define
|
|
||||||
let s:SHA1HashSize = 20
|
|
||||||
|
|
||||||
"
|
|
||||||
" This structure will hold context information for the SHA-1
|
|
||||||
" hashing operation
|
|
||||||
"
|
|
||||||
" struct
|
|
||||||
let s:SHA1Context = {}
|
|
||||||
" uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
|
|
||||||
let s:SHA1Context.Intermediate_Hash = repeat([0], s:SHA1HashSize / 4)
|
|
||||||
" uint32_t Length_Low; /* Message length in bits */
|
|
||||||
let s:SHA1Context.Length_Low = 0
|
|
||||||
" uint32_t Length_High; /* Message length in bits */
|
|
||||||
let s:SHA1Context.Length_High = 0
|
|
||||||
" /* Index into message block array */
|
|
||||||
" int_least16_t Message_Block_Index;
|
|
||||||
let s:SHA1Context.Message_Block_Index = 0
|
|
||||||
" uint8_t Message_Block[64]; /* 512-bit message blocks */
|
|
||||||
let s:SHA1Context.Message_Block = repeat([0], 64)
|
|
||||||
" int Computed; /* Is the digest computed? */
|
|
||||||
let s:SHA1Context.Computed = 0
|
|
||||||
" int Corrupted; /* Is the message digest corrupted? */
|
|
||||||
let s:SHA1Context.Corrupted = 0
|
|
||||||
|
|
||||||
"
|
|
||||||
" sha1.c
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" This file implements the Secure Hashing Algorithm 1 as
|
|
||||||
" defined in FIPS PUB 180-1 published April 17, 1995.
|
|
||||||
"
|
|
||||||
" The SHA-1, produces a 160-bit message digest for a given
|
|
||||||
" data stream. It should take about 2**n steps to find a
|
|
||||||
" message with the same digest as a given message and
|
|
||||||
" 2**(n/2) to find any two messages with the same digest,
|
|
||||||
" when n is the digest size in bits. Therefore, this
|
|
||||||
" algorithm can serve as a means of providing a
|
|
||||||
" "fingerprint" for a message.
|
|
||||||
"
|
|
||||||
" Portability Issues:
|
|
||||||
" SHA-1 is defined in terms of 32-bit "words". This code
|
|
||||||
" uses <stdint.h> (included via "sha1.h" to define 32 and 8
|
|
||||||
" bit unsigned integer types. If your C compiler does not
|
|
||||||
" support 32 bit unsigned integers, this code is not
|
|
||||||
" appropriate.
|
|
||||||
"
|
|
||||||
" Caveats:
|
|
||||||
" SHA-1 is designed to work with messages less than 2^64 bits
|
|
||||||
" long. Although SHA-1 allows a message digest to be generated
|
|
||||||
" for messages of any number of bits less than 2^64, this
|
|
||||||
" implementation only works with messages with a length that is
|
|
||||||
" a multiple of the size of an 8-bit character.
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
" Define the SHA1 circular left shift macro
|
|
||||||
"
|
|
||||||
"#define SHA1CircularShift(bits,word) \
|
|
||||||
" (((word) << (bits)) | ((word) >> (32-(bits))))
|
|
||||||
function s:SHA1CircularShift(bits, word)
|
|
||||||
return s:bitwise_or(s:bitwise_lshift(a:word, a:bits), s:bitwise_rshift(a:word, 32 - a:bits))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
" SHA1Reset
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" This function will initialize the SHA1Context in preparation
|
|
||||||
" for computing a new SHA1 message digest.
|
|
||||||
"
|
|
||||||
" Parameters:
|
|
||||||
" context: [in/out]
|
|
||||||
" The context to reset.
|
|
||||||
"
|
|
||||||
" Returns:
|
|
||||||
" sha Error Code.
|
|
||||||
"
|
|
||||||
"
|
|
||||||
" int SHA1Reset(SHA1Context *context)
|
|
||||||
function s:SHA1Reset(context)
|
|
||||||
if empty(a:context)
|
|
||||||
return s:shaNull
|
|
||||||
endif
|
|
||||||
|
|
||||||
let a:context.Length_Low = 0
|
|
||||||
let a:context.Length_High = 0
|
|
||||||
let a:context.Message_Block_Index = 0
|
|
||||||
|
|
||||||
let a:context.Intermediate_Hash[0] = 0x67452301
|
|
||||||
let a:context.Intermediate_Hash[1] = 0xEFCDAB89
|
|
||||||
let a:context.Intermediate_Hash[2] = 0x98BADCFE
|
|
||||||
let a:context.Intermediate_Hash[3] = 0x10325476
|
|
||||||
let a:context.Intermediate_Hash[4] = 0xC3D2E1F0
|
|
||||||
|
|
||||||
let a:context.Computed = 0
|
|
||||||
let a:context.Corrupted = 0
|
|
||||||
|
|
||||||
return s:shaSuccess
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
" SHA1Result
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" This function will return the 160-bit message digest into the
|
|
||||||
" Message_Digest array provided by the caller.
|
|
||||||
" NOTE: The first octet of hash is stored in the 0th element,
|
|
||||||
" the last octet of hash in the 19th element.
|
|
||||||
"
|
|
||||||
" Parameters:
|
|
||||||
" context: [in/out]
|
|
||||||
" The context to use to calculate the SHA-1 hash.
|
|
||||||
" Message_Digest: [out]
|
|
||||||
" Where the digest is returned.
|
|
||||||
"
|
|
||||||
" Returns:
|
|
||||||
" sha Error Code.
|
|
||||||
"
|
|
||||||
"
|
|
||||||
"int SHA1Result( SHA1Context *context,
|
|
||||||
" uint8_t Message_Digest[SHA1HashSize])
|
|
||||||
function s:SHA1Result(context, Message_Digest)
|
|
||||||
if empty(a:context) || empty(a:Message_Digest)
|
|
||||||
return s:shaNull
|
|
||||||
endif
|
|
||||||
|
|
||||||
if a:context.Corrupted
|
|
||||||
return a:context.Corrupted
|
|
||||||
endif
|
|
||||||
|
|
||||||
if !a:context.Computed
|
|
||||||
call s:SHA1PadMessage(a:context)
|
|
||||||
for i in range(64)
|
|
||||||
" message may be sensitive, clear it out
|
|
||||||
let a:context.Message_Block[i] = 0
|
|
||||||
endfor
|
|
||||||
let a:context.Length_Low = 0 " and clear length
|
|
||||||
let a:context.Length_High = 0
|
|
||||||
let a:context.Computed = 1
|
|
||||||
endif
|
|
||||||
|
|
||||||
for i in range(s:SHA1HashSize)
|
|
||||||
let a:Message_Digest[i] = s:uint8(
|
|
||||||
\ s:bitwise_rshift(
|
|
||||||
\ a:context.Intermediate_Hash[s:bitwise_rshift(i, 2)],
|
|
||||||
\ 8 * (3 - s:bitwise_and(i, 0x03))
|
|
||||||
\ )
|
|
||||||
\ )
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return s:shaSuccess
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
" SHA1Input
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" This function accepts an array of octets as the next portion
|
|
||||||
" of the message.
|
|
||||||
"
|
|
||||||
" Parameters:
|
|
||||||
" context: [in/out]
|
|
||||||
" The SHA context to update
|
|
||||||
" message_array: [in]
|
|
||||||
" An array of characters representing the next portion of
|
|
||||||
" the message.
|
|
||||||
" length: [in]
|
|
||||||
" The length of the message in message_array
|
|
||||||
"
|
|
||||||
" Returns:
|
|
||||||
" sha Error Code.
|
|
||||||
"
|
|
||||||
"
|
|
||||||
"int SHA1Input( SHA1Context *context,
|
|
||||||
" const uint8_t *message_array,
|
|
||||||
" unsigned length)
|
|
||||||
function s:SHA1Input(context, message_array)
|
|
||||||
if !len(a:message_array)
|
|
||||||
return s:shaSuccess
|
|
||||||
endif
|
|
||||||
|
|
||||||
if empty(a:context) || empty(a:message_array)
|
|
||||||
return s:shaNull
|
|
||||||
endif
|
|
||||||
|
|
||||||
if a:context.Computed
|
|
||||||
let a:context.Corrupted = s:shaStateError
|
|
||||||
return s:shaStateError
|
|
||||||
endif
|
|
||||||
|
|
||||||
if a:context.Corrupted
|
|
||||||
return a:context.Corrupted
|
|
||||||
endif
|
|
||||||
|
|
||||||
for x in a:message_array
|
|
||||||
if a:context.Corrupted
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
let a:context.Message_Block[a:context.Message_Block_Index] = s:bitwise_and(x, 0xFF)
|
|
||||||
let a:context.Message_Block_Index += 1
|
|
||||||
|
|
||||||
let a:context.Length_Low += 8
|
|
||||||
if a:context.Length_Low == 0
|
|
||||||
let a:context.Length_High += 1
|
|
||||||
if a:context.Length_High == 0
|
|
||||||
" Message is too long
|
|
||||||
let a:context.Corrupted = 1
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
if a:context.Message_Block_Index == 64
|
|
||||||
call s:SHA1ProcessMessageBlock(a:context)
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
|
|
||||||
return s:shaSuccess
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
" SHA1ProcessMessageBlock
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" This function will process the next 512 bits of the message
|
|
||||||
" stored in the Message_Block array.
|
|
||||||
"
|
|
||||||
" Parameters:
|
|
||||||
" None.
|
|
||||||
"
|
|
||||||
" Returns:
|
|
||||||
" Nothing.
|
|
||||||
"
|
|
||||||
" Comments:
|
|
||||||
" Many of the variable names in this code, especially the
|
|
||||||
" single character names, were used because those were the
|
|
||||||
" names used in the publication.
|
|
||||||
"
|
|
||||||
"
|
|
||||||
"
|
|
||||||
" void SHA1ProcessMessageBlock(SHA1Context *context)
|
|
||||||
function s:SHA1ProcessMessageBlock(context)
|
|
||||||
" Constants defined in SHA-1
|
|
||||||
let K = [
|
|
||||||
\ 0x5A827999,
|
|
||||||
\ 0x6ED9EBA1,
|
|
||||||
\ 0x8F1BBCDC,
|
|
||||||
\ 0xCA62C1D6
|
|
||||||
\ ]
|
|
||||||
let t = 0 " Loop counter
|
|
||||||
let temp = 0 " Temporary word value
|
|
||||||
let W = repeat([0], 80) " Word sequence
|
|
||||||
let [A, B, C, D, E] = [0, 0, 0, 0, 0] " Word buffers
|
|
||||||
|
|
||||||
"
|
|
||||||
" Initialize the first 16 words in the array W
|
|
||||||
"
|
|
||||||
for t in range(16)
|
|
||||||
let W[t] = s:bitwise_lshift(a:context.Message_Block[t * 4], 24)
|
|
||||||
let W[t] = s:bitwise_or(W[t], s:bitwise_lshift(a:context.Message_Block[t * 4 + 1], 16))
|
|
||||||
let W[t] = s:bitwise_or(W[t], s:bitwise_lshift(a:context.Message_Block[t * 4 + 2], 8))
|
|
||||||
let W[t] = s:bitwise_or(W[t], a:context.Message_Block[t * 4 + 3])
|
|
||||||
endfor
|
|
||||||
|
|
||||||
for t in range(16, 79)
|
|
||||||
let W[t] = s:SHA1CircularShift(1, s:bitwise_xor(s:bitwise_xor(s:bitwise_xor(W[t-3], W[t-8]), W[t-14]), W[t-16]))
|
|
||||||
endfor
|
|
||||||
|
|
||||||
let A = a:context.Intermediate_Hash[0]
|
|
||||||
let B = a:context.Intermediate_Hash[1]
|
|
||||||
let C = a:context.Intermediate_Hash[2]
|
|
||||||
let D = a:context.Intermediate_Hash[3]
|
|
||||||
let E = a:context.Intermediate_Hash[4]
|
|
||||||
|
|
||||||
for t in range(20)
|
|
||||||
let temp = s:SHA1CircularShift(5,A) +
|
|
||||||
\ s:bitwise_or(s:bitwise_and(B, C), s:bitwise_and(s:bitwise_not(B), D)) +
|
|
||||||
\ E + W[t] + K[0]
|
|
||||||
let E = D
|
|
||||||
let D = C
|
|
||||||
let C = s:SHA1CircularShift(30,B)
|
|
||||||
let B = A
|
|
||||||
let A = temp
|
|
||||||
endfor
|
|
||||||
|
|
||||||
for t in range(20, 39)
|
|
||||||
let temp = s:SHA1CircularShift(5,A) + s:bitwise_xor(s:bitwise_xor(B, C), D) + E + W[t] + K[1]
|
|
||||||
let E = D
|
|
||||||
let D = C
|
|
||||||
let C = s:SHA1CircularShift(30,B)
|
|
||||||
let B = A
|
|
||||||
let A = temp
|
|
||||||
endfor
|
|
||||||
|
|
||||||
for t in range(40, 59)
|
|
||||||
let temp = s:SHA1CircularShift(5,A) +
|
|
||||||
\ s:bitwise_or(s:bitwise_or(s:bitwise_and(B, C), s:bitwise_and(B, D)), s:bitwise_and(C, D)) +
|
|
||||||
\ E + W[t] + K[2]
|
|
||||||
let E = D
|
|
||||||
let D = C
|
|
||||||
let C = s:SHA1CircularShift(30,B)
|
|
||||||
let B = A
|
|
||||||
let A = temp
|
|
||||||
endfor
|
|
||||||
|
|
||||||
for t in range(60, 79)
|
|
||||||
let temp = s:SHA1CircularShift(5,A) +
|
|
||||||
\ s:bitwise_xor(s:bitwise_xor(B, C), D) + E + W[t] + K[3]
|
|
||||||
let E = D
|
|
||||||
let D = C
|
|
||||||
let C = s:SHA1CircularShift(30,B)
|
|
||||||
let B = A
|
|
||||||
let A = temp
|
|
||||||
endfor
|
|
||||||
|
|
||||||
let a:context.Intermediate_Hash[0] += A
|
|
||||||
let a:context.Intermediate_Hash[1] += B
|
|
||||||
let a:context.Intermediate_Hash[2] += C
|
|
||||||
let a:context.Intermediate_Hash[3] += D
|
|
||||||
let a:context.Intermediate_Hash[4] += E
|
|
||||||
|
|
||||||
let a:context.Message_Block_Index = 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
|
|
||||||
"
|
|
||||||
" SHA1PadMessage
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" According to the standard, the message must be padded to an even
|
|
||||||
" 512 bits. The first padding bit must be a '1'. The last 64
|
|
||||||
" bits represent the length of the original message. All bits in
|
|
||||||
" between should be 0. This function will pad the message
|
|
||||||
" according to those rules by filling the Message_Block array
|
|
||||||
" accordingly. It will also call the ProcessMessageBlock function
|
|
||||||
" provided appropriately. When it returns, it can be assumed that
|
|
||||||
" the message digest has been computed.
|
|
||||||
"
|
|
||||||
" Parameters:
|
|
||||||
" context: [in/out]
|
|
||||||
" The context to pad
|
|
||||||
" ProcessMessageBlock: [in]
|
|
||||||
" The appropriate SHA*ProcessMessageBlock function
|
|
||||||
" Returns:
|
|
||||||
" Nothing.
|
|
||||||
"
|
|
||||||
"
|
|
||||||
" void SHA1PadMessage(SHA1Context *context)
|
|
||||||
function s:SHA1PadMessage(context)
|
|
||||||
"
|
|
||||||
" Check to see if the current message block is too small to hold
|
|
||||||
" the initial padding bits and length. If so, we will pad the
|
|
||||||
" block, process it, and then continue padding into a second
|
|
||||||
" block.
|
|
||||||
"
|
|
||||||
if a:context.Message_Block_Index > 55
|
|
||||||
let a:context.Message_Block[a:context.Message_Block_Index] = 0x80
|
|
||||||
let a:context.Message_Block_Index += 1
|
|
||||||
while a:context.Message_Block_Index < 64
|
|
||||||
let a:context.Message_Block[a:context.Message_Block_Index] = 0
|
|
||||||
let a:context.Message_Block_Index += 1
|
|
||||||
endwhile
|
|
||||||
|
|
||||||
call s:SHA1ProcessMessageBlock(a:context)
|
|
||||||
|
|
||||||
while a:context.Message_Block_Index < 56
|
|
||||||
let a:context.Message_Block[a:context.Message_Block_Index] = 0
|
|
||||||
let a:context.Message_Block_Index += 1
|
|
||||||
endwhile
|
|
||||||
else
|
|
||||||
let a:context.Message_Block[a:context.Message_Block_Index] = 0x80
|
|
||||||
let a:context.Message_Block_Index += 1
|
|
||||||
while a:context.Message_Block_Index < 56
|
|
||||||
let a:context.Message_Block[a:context.Message_Block_Index] = 0
|
|
||||||
let a:context.Message_Block_Index += 1
|
|
||||||
endwhile
|
|
||||||
endif
|
|
||||||
|
|
||||||
"
|
|
||||||
" Store the message length as the last 8 octets
|
|
||||||
"
|
|
||||||
let a:context.Message_Block[56] = s:uint8(s:bitwise_rshift(a:context.Length_High, 24))
|
|
||||||
let a:context.Message_Block[57] = s:uint8(s:bitwise_rshift(a:context.Length_High, 16))
|
|
||||||
let a:context.Message_Block[58] = s:uint8(s:bitwise_rshift(a:context.Length_High, 8))
|
|
||||||
let a:context.Message_Block[59] = s:uint8(a:context.Length_High)
|
|
||||||
let a:context.Message_Block[60] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 24))
|
|
||||||
let a:context.Message_Block[61] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 16))
|
|
||||||
let a:context.Message_Block[62] = s:uint8(s:bitwise_rshift(a:context.Length_Low, 8))
|
|
||||||
let a:context.Message_Block[63] = s:uint8(a:context.Length_Low)
|
|
||||||
|
|
||||||
call s:SHA1ProcessMessageBlock(a:context)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"
|
|
||||||
" sha1test.c
|
|
||||||
"
|
|
||||||
" Description:
|
|
||||||
" This file will exercise the SHA-1 code performing the three
|
|
||||||
" tests documented in FIPS PUB 180-1 plus one which calls
|
|
||||||
" SHA1Input with an exact multiple of 512 bits, plus a few
|
|
||||||
" error test checks.
|
|
||||||
"
|
|
||||||
" Portability Issues:
|
|
||||||
" None.
|
|
||||||
"
|
|
||||||
"
|
|
||||||
|
|
||||||
"
|
|
||||||
" Define patterns for testing
|
|
||||||
"
|
|
||||||
let s:TEST1 = "abc"
|
|
||||||
let s:TEST2a = "abcdbcdecdefdefgefghfghighijhi"
|
|
||||||
let s:TEST2b = "jkijkljklmklmnlmnomnopnopq"
|
|
||||||
let s:TEST2 = s:TEST2a . s:TEST2b
|
|
||||||
let s:TEST3 = "a"
|
|
||||||
let s:TEST4a = "01234567012345670123456701234567"
|
|
||||||
let s:TEST4b = "01234567012345670123456701234567"
|
|
||||||
" an exact multiple of 512 bits
|
|
||||||
let s:TEST4 = s:TEST4a . s:TEST4b
|
|
||||||
let s:testarray = [
|
|
||||||
\ s:TEST1,
|
|
||||||
\ s:TEST2,
|
|
||||||
\ s:TEST3,
|
|
||||||
\ s:TEST4
|
|
||||||
\ ]
|
|
||||||
let s:repeatcount = [1, 1, 1000000, 10]
|
|
||||||
let s:resultarray = [
|
|
||||||
\ "A9 99 3E 36 47 06 81 6A BA 3E 25 71 78 50 C2 6C 9C D0 D8 9D",
|
|
||||||
\ "84 98 3E 44 1C 3B D2 6E BA AE 4A A1 F9 51 29 E5 E5 46 70 F1",
|
|
||||||
\ "34 AA 97 3C D4 C4 DA A4 F6 1E EB 2B DB AD 27 31 65 34 01 6F",
|
|
||||||
\ "DE A3 56 A2 CD DD 90 C7 A7 EC ED C5 EB B5 63 93 4F 46 04 52"
|
|
||||||
\ ]
|
|
||||||
|
|
||||||
function s:main()
|
|
||||||
let sha = deepcopy(s:SHA1Context, 1)
|
|
||||||
let Message_Digest = repeat([0], 20)
|
|
||||||
|
|
||||||
"
|
|
||||||
" Perform SHA-1 tests
|
|
||||||
"
|
|
||||||
for j in range(len(s:testarray))
|
|
||||||
if j == 2
|
|
||||||
echo "Test 3 will take about 1 hour. Press CTRL-C to skip."
|
|
||||||
endif
|
|
||||||
echo ""
|
|
||||||
echo printf("Test %d: %d, '%s'",
|
|
||||||
\ j+1,
|
|
||||||
\ s:repeatcount[j],
|
|
||||||
\ s:testarray[j])
|
|
||||||
|
|
||||||
let err = s:SHA1Reset(sha)
|
|
||||||
if err
|
|
||||||
echo printf("SHA1Reset Error %d.", err )
|
|
||||||
break " out of for j loop
|
|
||||||
endif
|
|
||||||
|
|
||||||
try
|
|
||||||
for i in range(s:repeatcount[j])
|
|
||||||
let err = s:SHA1Input(sha, s:str2bytes(s:testarray[j]))
|
|
||||||
if err
|
|
||||||
echo printf("SHA1Input Error %d.", err )
|
|
||||||
break " out of for i loop */
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
catch /^Vim:Interrupt$/
|
|
||||||
echo "Skip ..."
|
|
||||||
while getchar(0) | endwhile
|
|
||||||
continue
|
|
||||||
endtry
|
|
||||||
|
|
||||||
let err = s:SHA1Result(sha, Message_Digest)
|
|
||||||
if err
|
|
||||||
echo printf("SHA1Result Error %d, could not compute message digest.", err)
|
|
||||||
else
|
|
||||||
echo "\t"
|
|
||||||
for i in range(20)
|
|
||||||
echon printf("%02X ", Message_Digest[i])
|
|
||||||
endfor
|
|
||||||
echo ""
|
|
||||||
endif
|
|
||||||
echo "Should match:"
|
|
||||||
echo printf("\t%s", s:resultarray[j])
|
|
||||||
endfor
|
|
||||||
|
|
||||||
" Test some error returns
|
|
||||||
let err = s:SHA1Input(sha, s:str2bytes(s:testarray[1][0:0]))
|
|
||||||
echo printf("\nError %d. Should be %d.", err, s:shaStateError)
|
|
||||||
let err = s:SHA1Reset(0)
|
|
||||||
echo printf("\nError %d. Should be %d.", err, s:shaNull)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"---------------------------------------------------------------------
|
|
||||||
" misc
|
|
||||||
function! s:str2bytes(str)
|
|
||||||
return map(range(len(a:str)), 'char2nr(a:str[v:val])')
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:cmp(a, b)
|
|
||||||
let a = printf("%08x", a:a)
|
|
||||||
let b = printf("%08x", a:b)
|
|
||||||
return a < b ? -1 : a > b ? 1 : 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:uint8(n)
|
|
||||||
return s:bitwise_and(a:n, 0xFF)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let s:k = [
|
|
||||||
\ 0x1, 0x2, 0x4, 0x8,
|
|
||||||
\ 0x10, 0x20, 0x40, 0x80,
|
|
||||||
\ 0x100, 0x200, 0x400, 0x800,
|
|
||||||
\ 0x1000, 0x2000, 0x4000, 0x8000,
|
|
||||||
\ 0x10000, 0x20000, 0x40000, 0x80000,
|
|
||||||
\ 0x100000, 0x200000, 0x400000, 0x800000,
|
|
||||||
\ 0x1000000, 0x2000000, 0x4000000, 0x8000000,
|
|
||||||
\ 0x10000000, 0x20000000, 0x40000000, 0x80000000,
|
|
||||||
\ ]
|
|
||||||
|
|
||||||
let s:and = [
|
|
||||||
\ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
|
|
||||||
\ [0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1],
|
|
||||||
\ [0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x2, 0x2],
|
|
||||||
\ [0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3],
|
|
||||||
\ [0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4],
|
|
||||||
\ [0x0, 0x1, 0x0, 0x1, 0x4, 0x5, 0x4, 0x5, 0x0, 0x1, 0x0, 0x1, 0x4, 0x5, 0x4, 0x5],
|
|
||||||
\ [0x0, 0x0, 0x2, 0x2, 0x4, 0x4, 0x6, 0x6, 0x0, 0x0, 0x2, 0x2, 0x4, 0x4, 0x6, 0x6],
|
|
||||||
\ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7],
|
|
||||||
\ [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8],
|
|
||||||
\ [0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x8, 0x9, 0x8, 0x9, 0x8, 0x9, 0x8, 0x9],
|
|
||||||
\ [0x0, 0x0, 0x2, 0x2, 0x0, 0x0, 0x2, 0x2, 0x8, 0x8, 0xA, 0xA, 0x8, 0x8, 0xA, 0xA],
|
|
||||||
\ [0x0, 0x1, 0x2, 0x3, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xA, 0xB, 0x8, 0x9, 0xA, 0xB],
|
|
||||||
\ [0x0, 0x0, 0x0, 0x0, 0x4, 0x4, 0x4, 0x4, 0x8, 0x8, 0x8, 0x8, 0xC, 0xC, 0xC, 0xC],
|
|
||||||
\ [0x0, 0x1, 0x0, 0x1, 0x4, 0x5, 0x4, 0x5, 0x8, 0x9, 0x8, 0x9, 0xC, 0xD, 0xC, 0xD],
|
|
||||||
\ [0x0, 0x0, 0x2, 0x2, 0x4, 0x4, 0x6, 0x6, 0x8, 0x8, 0xA, 0xA, 0xC, 0xC, 0xE, 0xE],
|
|
||||||
\ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF]
|
|
||||||
\ ]
|
|
||||||
|
|
||||||
let s:or = [
|
|
||||||
\ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
|
|
||||||
\ [0x1, 0x1, 0x3, 0x3, 0x5, 0x5, 0x7, 0x7, 0x9, 0x9, 0xB, 0xB, 0xD, 0xD, 0xF, 0xF],
|
|
||||||
\ [0x2, 0x3, 0x2, 0x3, 0x6, 0x7, 0x6, 0x7, 0xA, 0xB, 0xA, 0xB, 0xE, 0xF, 0xE, 0xF],
|
|
||||||
\ [0x3, 0x3, 0x3, 0x3, 0x7, 0x7, 0x7, 0x7, 0xB, 0xB, 0xB, 0xB, 0xF, 0xF, 0xF, 0xF],
|
|
||||||
\ [0x4, 0x5, 0x6, 0x7, 0x4, 0x5, 0x6, 0x7, 0xC, 0xD, 0xE, 0xF, 0xC, 0xD, 0xE, 0xF],
|
|
||||||
\ [0x5, 0x5, 0x7, 0x7, 0x5, 0x5, 0x7, 0x7, 0xD, 0xD, 0xF, 0xF, 0xD, 0xD, 0xF, 0xF],
|
|
||||||
\ [0x6, 0x7, 0x6, 0x7, 0x6, 0x7, 0x6, 0x7, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF],
|
|
||||||
\ [0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF],
|
|
||||||
\ [0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
|
|
||||||
\ [0x9, 0x9, 0xB, 0xB, 0xD, 0xD, 0xF, 0xF, 0x9, 0x9, 0xB, 0xB, 0xD, 0xD, 0xF, 0xF],
|
|
||||||
\ [0xA, 0xB, 0xA, 0xB, 0xE, 0xF, 0xE, 0xF, 0xA, 0xB, 0xA, 0xB, 0xE, 0xF, 0xE, 0xF],
|
|
||||||
\ [0xB, 0xB, 0xB, 0xB, 0xF, 0xF, 0xF, 0xF, 0xB, 0xB, 0xB, 0xB, 0xF, 0xF, 0xF, 0xF],
|
|
||||||
\ [0xC, 0xD, 0xE, 0xF, 0xC, 0xD, 0xE, 0xF, 0xC, 0xD, 0xE, 0xF, 0xC, 0xD, 0xE, 0xF],
|
|
||||||
\ [0xD, 0xD, 0xF, 0xF, 0xD, 0xD, 0xF, 0xF, 0xD, 0xD, 0xF, 0xF, 0xD, 0xD, 0xF, 0xF],
|
|
||||||
\ [0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF, 0xE, 0xF],
|
|
||||||
\ [0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF, 0xF]
|
|
||||||
\ ]
|
|
||||||
|
|
||||||
let s:xor = [
|
|
||||||
\ [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF],
|
|
||||||
\ [0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6, 0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE],
|
|
||||||
\ [0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5, 0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD],
|
|
||||||
\ [0x3, 0x2, 0x1, 0x0, 0x7, 0x6, 0x5, 0x4, 0xB, 0xA, 0x9, 0x8, 0xF, 0xE, 0xD, 0xC],
|
|
||||||
\ [0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3, 0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB],
|
|
||||||
\ [0x5, 0x4, 0x7, 0x6, 0x1, 0x0, 0x3, 0x2, 0xD, 0xC, 0xF, 0xE, 0x9, 0x8, 0xB, 0xA],
|
|
||||||
\ [0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1, 0xE, 0xF, 0xC, 0xD, 0xA, 0xB, 0x8, 0x9],
|
|
||||||
\ [0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0, 0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8],
|
|
||||||
\ [0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7],
|
|
||||||
\ [0x9, 0x8, 0xB, 0xA, 0xD, 0xC, 0xF, 0xE, 0x1, 0x0, 0x3, 0x2, 0x5, 0x4, 0x7, 0x6],
|
|
||||||
\ [0xA, 0xB, 0x8, 0x9, 0xE, 0xF, 0xC, 0xD, 0x2, 0x3, 0x0, 0x1, 0x6, 0x7, 0x4, 0x5],
|
|
||||||
\ [0xB, 0xA, 0x9, 0x8, 0xF, 0xE, 0xD, 0xC, 0x3, 0x2, 0x1, 0x0, 0x7, 0x6, 0x5, 0x4],
|
|
||||||
\ [0xC, 0xD, 0xE, 0xF, 0x8, 0x9, 0xA, 0xB, 0x4, 0x5, 0x6, 0x7, 0x0, 0x1, 0x2, 0x3],
|
|
||||||
\ [0xD, 0xC, 0xF, 0xE, 0x9, 0x8, 0xB, 0xA, 0x5, 0x4, 0x7, 0x6, 0x1, 0x0, 0x3, 0x2],
|
|
||||||
\ [0xE, 0xF, 0xC, 0xD, 0xA, 0xB, 0x8, 0x9, 0x6, 0x7, 0x4, 0x5, 0x2, 0x3, 0x0, 0x1],
|
|
||||||
\ [0xF, 0xE, 0xD, 0xC, 0xB, 0xA, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0]
|
|
||||||
\ ]
|
|
||||||
|
|
||||||
function! s:bitwise_lshift(a, n)
|
|
||||||
return a:a * s:k[a:n]
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:bitwise_rshift(a, n)
|
|
||||||
let a = a:a < 0 ? a:a - 0x80000000 : a:a
|
|
||||||
let a = a / s:k[a:n]
|
|
||||||
if a:a < 0
|
|
||||||
let a += 0x40000000 / s:k[a:n - 1]
|
|
||||||
endif
|
|
||||||
return a
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:bitwise_not(a)
|
|
||||||
return -a:a - 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:bitwise_and(a, b)
|
|
||||||
let a = a:a < 0 ? a:a - 0x80000000 : a:a
|
|
||||||
let b = a:b < 0 ? a:b - 0x80000000 : a:b
|
|
||||||
let r = 0
|
|
||||||
let n = 1
|
|
||||||
while a && b
|
|
||||||
let r += s:and[a % 0x10][b % 0x10] * n
|
|
||||||
let a = a / 0x10
|
|
||||||
let b = b / 0x10
|
|
||||||
let n = n * 0x10
|
|
||||||
endwhile
|
|
||||||
if (a:a < 0) && (a:b < 0)
|
|
||||||
let r += 0x80000000
|
|
||||||
endif
|
|
||||||
return r
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:bitwise_or(a, b)
|
|
||||||
let a = a:a < 0 ? a:a - 0x80000000 : a:a
|
|
||||||
let b = a:b < 0 ? a:b - 0x80000000 : a:b
|
|
||||||
let r = 0
|
|
||||||
let n = 1
|
|
||||||
while a || b
|
|
||||||
let r += s:or[a % 0x10][b % 0x10] * n
|
|
||||||
let a = a / 0x10
|
|
||||||
let b = b / 0x10
|
|
||||||
let n = n * 0x10
|
|
||||||
endwhile
|
|
||||||
if (a:a < 0) || (a:b < 0)
|
|
||||||
let r += 0x80000000
|
|
||||||
endif
|
|
||||||
return r
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:bitwise_xor(a, b)
|
|
||||||
let a = a:a < 0 ? a:a - 0x80000000 : a:a
|
|
||||||
let b = a:b < 0 ? a:b - 0x80000000 : a:b
|
|
||||||
let r = 0
|
|
||||||
let n = 1
|
|
||||||
while a || b
|
|
||||||
let r += s:xor[a % 0x10][b % 0x10] * n
|
|
||||||
let a = a / 0x10
|
|
||||||
let b = b / 0x10
|
|
||||||
let n = n * 0x10
|
|
||||||
endwhile
|
|
||||||
if (a:a < 0) != (a:b < 0)
|
|
||||||
let r += 0x80000000
|
|
||||||
endif
|
|
||||||
return r
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
" soap
|
|
||||||
" Last Change: 2010-09-10
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
" http://tools.ietf.org/rfc/rfc4743.txt
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
function! s:soap_call(url, func, ...)
|
|
||||||
let envelope = webapi#xml#createElement("soap:Envelope")
|
|
||||||
let envelope.attr["xmlns:soap"] = "http://schemas.xmlsoap.org/soap/envelope/"
|
|
||||||
let envelope.attr["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
|
|
||||||
let body = webapi#xml#createElement("soap:Body")
|
|
||||||
call add(envelope.child, body)
|
|
||||||
let func = webapi#xml#createElement(a:func)
|
|
||||||
call add(body.child, func)
|
|
||||||
|
|
||||||
let n = 1
|
|
||||||
for a in a:000
|
|
||||||
let arg = webapi#xml#createElement("param".n)
|
|
||||||
let arg.attr["xsi:type"] = "xsd:string"
|
|
||||||
call arg.value(a)
|
|
||||||
call add(func.child, arg)
|
|
||||||
let n += 1
|
|
||||||
endfor
|
|
||||||
|
|
||||||
let str = '<?xml version="1.0" encoding="UTF-8"?>' . envelope.toString()
|
|
||||||
let res = webapi#http#post(a:url, str)
|
|
||||||
let dom = webapi#xml#parse(res.content)
|
|
||||||
return s:parse_return(dom.find("return"))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:parse_return(node)
|
|
||||||
if a:node.attr["xsi:type"] =~ ":Array$"
|
|
||||||
let arr = []
|
|
||||||
for item in a:node.child
|
|
||||||
call add(ret, s:parse_return(item.child)
|
|
||||||
endfor
|
|
||||||
let ret = arr
|
|
||||||
elseif a:node.attr["xsi:type"] =~ ":Map$"
|
|
||||||
let ret = {}
|
|
||||||
for item in a:node.childNodes("item")
|
|
||||||
let val = item.childNode("value")
|
|
||||||
if val.attr["xsi:type"] =~ ":Map$"
|
|
||||||
let ret[item.childNode("key").value()] = s:parse_return(val)
|
|
||||||
else
|
|
||||||
let ret[item.childNode("key").value()] = item.childNode("value").value()
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
else
|
|
||||||
if len(a:node.child)
|
|
||||||
let arr = []
|
|
||||||
for item in a:node.child
|
|
||||||
call add(arr, s:parse_return(item)
|
|
||||||
endfor
|
|
||||||
let ret = arr
|
|
||||||
else
|
|
||||||
let ret = s:parse_return(a:node)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_convert_code(arg)
|
|
||||||
let code = ''
|
|
||||||
let arg = a:arg
|
|
||||||
if arg.type == "xsd:string"
|
|
||||||
let code .= "let ".arg.name." = a:".arg.name
|
|
||||||
elseif arg.type == "xsd:int"
|
|
||||||
let code .= "let ".arg.name." = 0+a:".arg.name
|
|
||||||
elseif arg.type == "xsd:boolean"
|
|
||||||
let code .= "let ".arg.name." = (0+a:".arg.name.") ? 'true' : 'false'"
|
|
||||||
elseif arg.type == "xsd:float"
|
|
||||||
let code .= "let ".arg.name." = nr2float(0+a:".arg.name.")"
|
|
||||||
elseif arg.type =~ ":Array$"
|
|
||||||
let code .= "let ".arg.name." = a:".arg.name
|
|
||||||
else
|
|
||||||
throw "unknown type:". arg.type
|
|
||||||
endif
|
|
||||||
return code
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#soap#proxy(url)
|
|
||||||
let dom = webapi#xml#parseURL(a:url)
|
|
||||||
let l:api = {}
|
|
||||||
let action = dom.childNode("service").find("soap:address").attr["location"]
|
|
||||||
let operations = dom.childNode("portType").childNodes("operation")
|
|
||||||
for operation in operations
|
|
||||||
let name = operation.attr["name"]
|
|
||||||
let inp = substitute(operation.childNode("input").attr["message"], "^tns:", "", "")
|
|
||||||
let out = substitute(operation.childNode("output").attr["message"], "^tns:", "", "")
|
|
||||||
let message = dom.childNode("message", {"name": inp})
|
|
||||||
let args = []
|
|
||||||
for part in message.childNodes("part")
|
|
||||||
call add(args, {"name": part.attr["name"], "type": part.attr["type"]})
|
|
||||||
endfor
|
|
||||||
let argnames = []
|
|
||||||
let code = ""
|
|
||||||
for arg in args
|
|
||||||
call add(argnames, arg.name)
|
|
||||||
let code .= " ".s:get_convert_code(arg)."\n"
|
|
||||||
endfor
|
|
||||||
let code .= " return s:soap_call(".string(action).", ".string(name).", ".join(argnames, ",").")\n"
|
|
||||||
let source = "function! l:api.".name."(".join(argnames, ",").") dict\n"
|
|
||||||
let source .= code
|
|
||||||
let source .= "endfunction\n"
|
|
||||||
exe source
|
|
||||||
endfor
|
|
||||||
return api
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
let s:utf8len = [
|
|
||||||
\ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
||||||
\ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
||||||
\ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
||||||
\ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
|
||||||
\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
\ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
||||||
\ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
|
||||||
\ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0,
|
|
||||||
\]
|
|
||||||
|
|
||||||
function! webapi#ucs#byte2nr(byte)
|
|
||||||
let p = a:byte
|
|
||||||
let n0 = char2nr(p[0])
|
|
||||||
if n0 < 0x80
|
|
||||||
return n0
|
|
||||||
endif
|
|
||||||
let l = s:utf8len[n0]
|
|
||||||
let n1 = char2nr(p[1])
|
|
||||||
if l > 1 && webapi#bit#and(n1, 0xc0) == 0x80
|
|
||||||
if l == 2
|
|
||||||
return webapi#bit#shift(webapi#bit#and(n0, 0x1f), 6) + webapi#bit#and(n1, 0x3f)
|
|
||||||
endif
|
|
||||||
let n2 = char2nr(p[2])
|
|
||||||
if webapi#bit#and(n2, 0xc0) == 0x80
|
|
||||||
if l == 3
|
|
||||||
return webapi#bit#shift(webapi#bit#and(n0, 0x0f), 12) + webapi#bit#shift(webapi#bit#and(n1, 0x3f), 6) + webapi#bit#and(n2, 0x3f)
|
|
||||||
endif
|
|
||||||
let n3 = char2nr(p[3])
|
|
||||||
if webapi#bit#and(n3, 0xc0) == 0x80
|
|
||||||
if l == 4
|
|
||||||
return webapi#bit#shift(webapi#bit#and(n0, 0x07), 18) + webapi#bit#shift(webapi#bit#and(n1, 0x3f), 12) + webapi#bit#shift(webapi#bit#and(n2, 0x3f), 6) + webapi#bit#and(n3, 0x3f)
|
|
||||||
endif
|
|
||||||
let n4 = char2nr(p[4])
|
|
||||||
if webapi#bit#and(n4, 0xc0) == 0x80
|
|
||||||
if (l == 5)
|
|
||||||
return webapi#bit#shift(webapi#bit#and(n0, 0x03), 24) + webapi#bit#shift(webapi#bit#and(n1, 0x3f), 18) + webapi#bit#shift(webapi#bit#and(n2, 0x3f), 12) + webapi#bit#shift(webapi#bit#and(n3 & 0x3f), 6) + webapi#bit#and(n4, 0x3f)
|
|
||||||
endif
|
|
||||||
let n5 = char2nr(p[5])
|
|
||||||
if webapi#bit#and(n5, 0xc0) == 0x80 && l == 6
|
|
||||||
return webapi#bit#shift(webapi#bit#and(n0, 0x01), 30) + webapi#bit#shift(webapi#bit#and(n1, 0x3f), 24) + webapi#bit#shift(webapi#bit#and(n2, 0x3f), 18) + webapi#bit#shift(webapi#bit#and(n3, 0x3f), 12) + webapi#bit#shift(webapi#bit#and(n4, 0x3f), 6) + webapi#bit#and(n5, 0x3f)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return n0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,320 +0,0 @@
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
let s:template = { 'name': '', 'attr': {}, 'child': [] }
|
|
||||||
|
|
||||||
function! s:nr2byte(nr)
|
|
||||||
if a:nr < 0x80
|
|
||||||
return nr2char(a:nr)
|
|
||||||
elseif a:nr < 0x800
|
|
||||||
return nr2char(a:nr/64+192).nr2char(a:nr%64+128)
|
|
||||||
else
|
|
||||||
return nr2char(a:nr/4096%16+224).nr2char(a:nr/64%64+128).nr2char(a:nr%64+128)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:nr2enc_char(charcode)
|
|
||||||
if &encoding == 'utf-8'
|
|
||||||
return nr2char(a:charcode)
|
|
||||||
endif
|
|
||||||
let char = s:nr2byte(a:charcode)
|
|
||||||
if strlen(char) > 1
|
|
||||||
let char = strtrans(iconv(char, 'utf-8', &encoding))
|
|
||||||
endif
|
|
||||||
return char
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:nr2hex(nr)
|
|
||||||
let n = a:nr
|
|
||||||
let r = ""
|
|
||||||
while n
|
|
||||||
let r = '0123456789ABCDEF'[n % 16] . r
|
|
||||||
let n = n / 16
|
|
||||||
endwhile
|
|
||||||
return r
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:decodeEntityReference(str)
|
|
||||||
let str = a:str
|
|
||||||
let str = substitute(str, '>', '>', 'g')
|
|
||||||
let str = substitute(str, '<', '<', 'g')
|
|
||||||
"let str = substitute(str, '"', '"', 'g')
|
|
||||||
"let str = substitute(str, ''', "'", 'g')
|
|
||||||
"let str = substitute(str, ' ', ' ', 'g')
|
|
||||||
"let str = substitute(str, '¥', '\¥', 'g')
|
|
||||||
let str = substitute(str, '&#x\([0-9a-fA-F]\+\);', '\=s:nr2enc_char("0x".submatch(1))', 'g')
|
|
||||||
let str = substitute(str, '&#\(\d\+\);', '\=s:nr2enc_char(submatch(1))', 'g')
|
|
||||||
let str = substitute(str, '&', '\&', 'g')
|
|
||||||
return str
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:encodeEntityReference(str)
|
|
||||||
let str = a:str
|
|
||||||
let str = substitute(str, '&', '\&', 'g')
|
|
||||||
let str = substitute(str, '>', '\>', 'g')
|
|
||||||
let str = substitute(str, '<', '\<', 'g')
|
|
||||||
let str = substitute(str, '"', '\"', 'g')
|
|
||||||
"let str = substitute(str, "\n", '\
', 'g')
|
|
||||||
"let str = substitute(str, '"', '"', 'g')
|
|
||||||
"let str = substitute(str, "'", ''', 'g')
|
|
||||||
"let str = substitute(str, ' ', ' ', 'g')
|
|
||||||
return str
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:matchNode(node, cond)
|
|
||||||
if type(a:cond) == 1 && a:node.name == a:cond
|
|
||||||
return 1
|
|
||||||
endif
|
|
||||||
if type(a:cond) == 2
|
|
||||||
return a:cond(a:node)
|
|
||||||
endif
|
|
||||||
if type(a:cond) == 3
|
|
||||||
let ret = 1
|
|
||||||
for l:R in a:cond
|
|
||||||
if !s:matchNode(a:node, l:R) | let ret = 0 | endif
|
|
||||||
unlet l:R
|
|
||||||
endfor
|
|
||||||
return ret
|
|
||||||
endif
|
|
||||||
if type(a:cond) == 4
|
|
||||||
for k in keys(a:cond)
|
|
||||||
if has_key(a:node.attr, k) && a:node.attr[k] == a:cond[k] | return 1 | endif
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.childNode(...) dict
|
|
||||||
for c in self.child
|
|
||||||
if type(c) == 4 && s:matchNode(c, a:000)
|
|
||||||
return c
|
|
||||||
endif
|
|
||||||
unlet c
|
|
||||||
endfor
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.childNodes(...) dict
|
|
||||||
let ret = []
|
|
||||||
for c in self.child
|
|
||||||
if type(c) == 4 && s:matchNode(c, a:000)
|
|
||||||
let ret += [c]
|
|
||||||
endif
|
|
||||||
unlet c
|
|
||||||
endfor
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.value(...) dict
|
|
||||||
if a:0
|
|
||||||
let self.child = a:000
|
|
||||||
return
|
|
||||||
endif
|
|
||||||
let ret = ''
|
|
||||||
for c in self.child
|
|
||||||
if type(c) <= 1 || type(c) == 5
|
|
||||||
let ret .= c
|
|
||||||
elseif type(c) == 4
|
|
||||||
let ret .= c.value()
|
|
||||||
endif
|
|
||||||
unlet c
|
|
||||||
endfor
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.find(...) dict
|
|
||||||
for c in self.child
|
|
||||||
if type(c) == 4
|
|
||||||
if s:matchNode(c, a:000)
|
|
||||||
return c
|
|
||||||
endif
|
|
||||||
unlet! ret
|
|
||||||
let ret = c.find(a:000)
|
|
||||||
if !empty(ret)
|
|
||||||
return ret
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
unlet c
|
|
||||||
endfor
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.findAll(...) dict
|
|
||||||
let ret = []
|
|
||||||
for c in self.child
|
|
||||||
if type(c) == 4
|
|
||||||
if s:matchNode(c, a:000)
|
|
||||||
call add(ret, c)
|
|
||||||
endif
|
|
||||||
let ret += c.findAll(a:000)
|
|
||||||
endif
|
|
||||||
unlet c
|
|
||||||
endfor
|
|
||||||
return ret
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:template.toString() dict
|
|
||||||
let xml = '<' . self.name
|
|
||||||
for attr in keys(self.attr)
|
|
||||||
let xml .= ' ' . attr . '="' . s:encodeEntityReference(self.attr[attr]) . '"'
|
|
||||||
endfor
|
|
||||||
if len(self.child)
|
|
||||||
let xml .= '>'
|
|
||||||
for c in self.child
|
|
||||||
if type(c) == 4
|
|
||||||
let xml .= c.toString()
|
|
||||||
elseif type(c) > 1
|
|
||||||
let xml .= s:encodeEntityReference(string(c))
|
|
||||||
else
|
|
||||||
let xml .= s:encodeEntityReference(c)
|
|
||||||
endif
|
|
||||||
unlet c
|
|
||||||
endfor
|
|
||||||
let xml .= '</' . self.name . '>'
|
|
||||||
else
|
|
||||||
let xml .= ' />'
|
|
||||||
endif
|
|
||||||
return xml
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#xml#createElement(name)
|
|
||||||
let node = deepcopy(s:template)
|
|
||||||
let node.name = a:name
|
|
||||||
return node
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:parse_tree(ctx, top)
|
|
||||||
let node = a:top
|
|
||||||
let stack = [a:top]
|
|
||||||
let pos = 0
|
|
||||||
" content accumulates the text only tags
|
|
||||||
let content = ""
|
|
||||||
let append_content_to_parent = 'if len(stack) && content != "" | call add(stack[-1].child, content) | let content ="" | endif'
|
|
||||||
|
|
||||||
let mx = '^\s*\(<?xml[^>]\+>\)'
|
|
||||||
if a:ctx['xml'] =~ mx
|
|
||||||
let match = matchstr(a:ctx['xml'], mx)
|
|
||||||
let a:ctx['xml'] = a:ctx['xml'][stridx(a:ctx['xml'], match) + len(match):]
|
|
||||||
let mx = 'encoding\s*=\s*["'']\{0,1}\([^"'' \t]\+\|[^"'']\+\)["'']\{0,1}'
|
|
||||||
let matches = matchlist(match, mx)
|
|
||||||
if len(matches)
|
|
||||||
let encoding = matches[1]
|
|
||||||
if len(encoding) && len(a:ctx['encoding']) == 0
|
|
||||||
let a:ctx['encoding'] = encoding
|
|
||||||
let a:ctx['xml'] = iconv(a:ctx['xml'], encoding, &encoding)
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
" this regex matches
|
|
||||||
" 1) the remaining until the next tag begins
|
|
||||||
" 2) maybe closing "/" of tag name
|
|
||||||
" 3) tagname
|
|
||||||
" 4) the attributes of the text (optional)
|
|
||||||
" 5) maybe closing "/" (end of tag name)
|
|
||||||
" or
|
|
||||||
" 6) CDATA or ''
|
|
||||||
" 7) text content of CDATA
|
|
||||||
" 8) the remaining text after the tag (rest)
|
|
||||||
" (These numbers correspond to the indexes in matched list m)
|
|
||||||
let tag_mx = '^\(\_.\{-}\)\%(\%(<\(/\?\)\([^!/>[:space:]]\+\)\(\%([[:space:]]*[^/>=[:space:]]\+[[:space:]]*=[[:space:]]*\%([^"'' >\t]\+\|"[^"]*"\|''[^'']*''\)\|[[:space:]]\+[^/>=[:space:]]\+[[:space:]]*\)*\)[[:space:]]*\(/\?\)>\)\|\%(<!\[\(CDATA\)\[\(.\{-}\)\]\]>\)\|\(<!--.\{-}-->\)\)\(.*\)'
|
|
||||||
|
|
||||||
while len(a:ctx['xml']) > 0
|
|
||||||
let m = matchlist(a:ctx.xml, tag_mx)
|
|
||||||
if empty(m) | break | endif
|
|
||||||
let is_end_tag = m[2] == '/' && m[5] == ''
|
|
||||||
let is_start_and_end_tag = m[2] == '' && m[5] == '/'
|
|
||||||
let tag_name = m[3]
|
|
||||||
let attrs = m[4]
|
|
||||||
|
|
||||||
if len(m[1])
|
|
||||||
let content .= s:decodeEntityReference(m[1])
|
|
||||||
endif
|
|
||||||
|
|
||||||
if is_end_tag
|
|
||||||
" closing tag: pop from stack and continue at upper level
|
|
||||||
exec append_content_to_parent
|
|
||||||
|
|
||||||
if len(stack) " TODO: checking whether opened tag is exist.
|
|
||||||
call remove(stack, -1)
|
|
||||||
endif
|
|
||||||
let a:ctx['xml'] = m[9]
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
|
|
||||||
" comment tag
|
|
||||||
if m[8] != ''
|
|
||||||
let a:ctx.xml = m[9]
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
|
|
||||||
" if element is a CDATA
|
|
||||||
if m[6] != ''
|
|
||||||
let content .= m[7]
|
|
||||||
let a:ctx.xml = m[9]
|
|
||||||
continue
|
|
||||||
endif
|
|
||||||
|
|
||||||
let node = deepcopy(s:template)
|
|
||||||
let node.name = tag_name
|
|
||||||
let attr_mx = '\([^=[:space:]]\+\)\s*\%(=\s*''\([^'']*\)''\|=\s*"\([^"]*\)"\|=\s*\(\w\+\)\|\)'
|
|
||||||
while len(attrs) > 0
|
|
||||||
let attr_match = matchlist(attrs, attr_mx)
|
|
||||||
if len(attr_match) == 0
|
|
||||||
break
|
|
||||||
endif
|
|
||||||
let name = attr_match[1]
|
|
||||||
let value = len(attr_match[2]) ? attr_match[2] : len(attr_match[3]) ? attr_match[3] : len(attr_match[4]) ? attr_match[4] : ""
|
|
||||||
if value == ""
|
|
||||||
let value = name
|
|
||||||
endif
|
|
||||||
let node.attr[name] = s:decodeEntityReference(value)
|
|
||||||
let attrs = attrs[stridx(attrs, attr_match[0]) + len(attr_match[0]):]
|
|
||||||
endwhile
|
|
||||||
|
|
||||||
exec append_content_to_parent
|
|
||||||
|
|
||||||
if len(stack)
|
|
||||||
call add(stack[-1].child, node)
|
|
||||||
endif
|
|
||||||
if !is_start_and_end_tag
|
|
||||||
" opening tag, continue parsing its contents
|
|
||||||
call add(stack, node)
|
|
||||||
endif
|
|
||||||
let a:ctx['xml'] = m[9]
|
|
||||||
endwhile
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#xml#parse(xml)
|
|
||||||
let top = deepcopy(s:template)
|
|
||||||
let oldmaxmempattern=&maxmempattern
|
|
||||||
let oldmaxfuncdepth=&maxfuncdepth
|
|
||||||
let &maxmempattern=2000000
|
|
||||||
let &maxfuncdepth=2000
|
|
||||||
"try
|
|
||||||
call s:parse_tree({'xml': a:xml, 'encoding': ''}, top)
|
|
||||||
for node in top.child
|
|
||||||
if type(node) == 4
|
|
||||||
return node
|
|
||||||
endif
|
|
||||||
unlet node
|
|
||||||
endfor
|
|
||||||
"catch /.*/
|
|
||||||
"endtry
|
|
||||||
let &maxmempattern=oldmaxmempattern
|
|
||||||
let &maxfuncdepth=oldmaxfuncdepth
|
|
||||||
throw "Parse Error"
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#xml#parseFile(fname)
|
|
||||||
return webapi#xml#parse(join(readfile(a:fname), "\n"))
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#xml#parseURL(url)
|
|
||||||
return webapi#xml#parse(webapi#http#get(a:url).content)
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,259 +0,0 @@
|
||||||
" xmlrpc
|
|
||||||
" Last Change: 2010-11-05
|
|
||||||
" Maintainer: Yasuhiro Matsumoto <mattn.jp@gmail.com>
|
|
||||||
" License: This file is placed in the public domain.
|
|
||||||
" Reference:
|
|
||||||
" http://tools.ietf.org/rfc/rfc3529.txt
|
|
||||||
|
|
||||||
let s:save_cpo = &cpo
|
|
||||||
set cpo&vim
|
|
||||||
|
|
||||||
let s:system = function(get(g:, 'webapi#system_function', 'system'))
|
|
||||||
|
|
||||||
function! webapi#xmlrpc#nil()
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#xmlrpc#true()
|
|
||||||
return 1
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#xmlrpc#false()
|
|
||||||
return 0
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:get_childNode(node)
|
|
||||||
let child = a:node.childNode('value').childNode()
|
|
||||||
if empty(child)
|
|
||||||
let child = a:node.childNode('value')
|
|
||||||
endif
|
|
||||||
return child
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:from_value(value)
|
|
||||||
let value = a:value
|
|
||||||
if value.name == 'methodResponse'
|
|
||||||
let param = value.childNode('params').childNodes('param')
|
|
||||||
if len(param) == 1
|
|
||||||
return s:from_value(s:get_childNode(param[0]))
|
|
||||||
else
|
|
||||||
let ret = []
|
|
||||||
for v in param
|
|
||||||
call add(ret, s:from_value(s:get_childNode(v)))
|
|
||||||
endfor
|
|
||||||
return ret
|
|
||||||
endif
|
|
||||||
elseif value.name == 'string'
|
|
||||||
return value.value()
|
|
||||||
elseif value.name == 'base64'
|
|
||||||
return value.value()
|
|
||||||
elseif value.name == 'dateTime.iso8601'
|
|
||||||
return value.value()
|
|
||||||
elseif value.name == 'boolean'
|
|
||||||
return 0+substitute(value.value(), "[ \n\r]", '', 'g')
|
|
||||||
elseif value.name == 'int'
|
|
||||||
return 0+substitute(value.value(), "[ \n\r]", '', 'g')
|
|
||||||
elseif value.name == 'i4'
|
|
||||||
return 0+substitute(value.value(), "[ \n\r]", '', 'g')
|
|
||||||
elseif value.name == 'double'
|
|
||||||
return str2float(substitute(value.value(), "[ \n\r]", '', 'g'))
|
|
||||||
elseif value.name == 'struct'
|
|
||||||
let ret = {}
|
|
||||||
for member in value.childNodes('member')
|
|
||||||
let ret[member.childNode('name').value()] = s:from_value(s:get_childNode(member))
|
|
||||||
endfor
|
|
||||||
return ret
|
|
||||||
elseif value.name == 'array'
|
|
||||||
let ret = []
|
|
||||||
for v in value.childNode('data').childNodes('value')
|
|
||||||
let child = v.childNode()
|
|
||||||
if !empty(child)
|
|
||||||
call add(ret, s:from_value(child))
|
|
||||||
else
|
|
||||||
call add(ret, v.value())
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return ret
|
|
||||||
elseif value.name == 'nil'
|
|
||||||
if get(g:, 'webapi#xmlrpc#allow_nil', 0) != 0
|
|
||||||
return function('webapi#xmlrpc#nil')
|
|
||||||
endif
|
|
||||||
return 0
|
|
||||||
elseif value.name == 'value'
|
|
||||||
return value.value()
|
|
||||||
else
|
|
||||||
throw "unknown type: ".value.name
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:to_value(content)
|
|
||||||
if type(a:content) == 4
|
|
||||||
if has_key(a:content, 'bits')
|
|
||||||
let struct = webapi#xml#createElement("struct")
|
|
||||||
|
|
||||||
let member = webapi#xml#createElement("member")
|
|
||||||
call add(struct.child, member)
|
|
||||||
let name = webapi#xml#createElement("name")
|
|
||||||
call add(member.child, name)
|
|
||||||
call name.value("name")
|
|
||||||
let value = webapi#xml#createElement("value")
|
|
||||||
call add(member.child, value)
|
|
||||||
call add(value.child, s:to_value(a:content["name"]))
|
|
||||||
|
|
||||||
let member = webapi#xml#createElement("member")
|
|
||||||
call add(struct.child, member)
|
|
||||||
let name = webapi#xml#createElement("name")
|
|
||||||
call name.value("bits")
|
|
||||||
call add(member.child, name)
|
|
||||||
let value = webapi#xml#createElement("value")
|
|
||||||
call add(member.child, value)
|
|
||||||
let base64 = webapi#xml#createElement("base64")
|
|
||||||
call add(value.child, base64)
|
|
||||||
if has_key(a:content, "bits") && len(a:content["bits"])
|
|
||||||
call base64.value(a:content["bits"])
|
|
||||||
elseif has_key(a:content, "path")
|
|
||||||
let quote = &shellxquote == '"' ? "'" : '"'
|
|
||||||
let bits = substitute(s:system("xxd -ps ".quote.a:content["path"].quote), "[ \n\r]", '', 'g')
|
|
||||||
call base64.value(webapi#base64#b64encodebin(bits))
|
|
||||||
endif
|
|
||||||
return struct
|
|
||||||
else
|
|
||||||
let struct = webapi#xml#createElement("struct")
|
|
||||||
for key in keys(a:content)
|
|
||||||
let member = webapi#xml#createElement("member")
|
|
||||||
let name = webapi#xml#createElement("name")
|
|
||||||
call name.value(key)
|
|
||||||
call add(member.child, name)
|
|
||||||
let value = webapi#xml#createElement("value")
|
|
||||||
call add(value.child, s:to_value(a:content[key]))
|
|
||||||
call add(member.child, value)
|
|
||||||
call add(struct.child, member)
|
|
||||||
endfor
|
|
||||||
return struct
|
|
||||||
endif
|
|
||||||
elseif type(a:content) == 3
|
|
||||||
let array = webapi#xml#createElement("array")
|
|
||||||
let data = webapi#xml#createElement("data")
|
|
||||||
for item in a:content
|
|
||||||
let value = webapi#xml#createElement("value")
|
|
||||||
call add(value.child, s:to_value(item))
|
|
||||||
call add(data.child, value)
|
|
||||||
endfor
|
|
||||||
call add(array.child, data)
|
|
||||||
return array
|
|
||||||
elseif type(a:content) == 2
|
|
||||||
if a:content == function('webapi#xmlrpc#true')
|
|
||||||
let true = webapi#xml#createElement("boolean")
|
|
||||||
call true.value('true')
|
|
||||||
return true
|
|
||||||
elseif a:content == function('webapi#xmlrpc#false')
|
|
||||||
let false = webapi#xml#createElement("boolean")
|
|
||||||
call false.value('false')
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
return webapi#xml#createElement("nil")
|
|
||||||
endif
|
|
||||||
elseif type(a:content) <= 1 || type(a:content) == 5
|
|
||||||
if type(a:content) == 0
|
|
||||||
let int = webapi#xml#createElement("int")
|
|
||||||
call int.value(a:content)
|
|
||||||
return int
|
|
||||||
elseif type(a:content) == 1
|
|
||||||
let str = webapi#xml#createElement("string")
|
|
||||||
call str.value(a:content)
|
|
||||||
return str
|
|
||||||
elseif type(a:content) == 5
|
|
||||||
let double = webapi#xml#createElement("double")
|
|
||||||
call double.value(a:content)
|
|
||||||
return double
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
return {}
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! s:to_fault(dom)
|
|
||||||
let struct = a:dom.find('struct')
|
|
||||||
let faultCode = ""
|
|
||||||
let faultString = ""
|
|
||||||
for member in struct.childNodes('member')
|
|
||||||
if member.childNode('name').value() == "faultCode"
|
|
||||||
let faultCode = member.childNode('value').value()
|
|
||||||
elseif member.childNode('name').value() == "faultString"
|
|
||||||
let faultString = member.childNode('value').value()
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return faultCode.":".faultString
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
"add_node_params
|
|
||||||
"Add list of args on the xml tree.
|
|
||||||
"input: list of args
|
|
||||||
"output: none
|
|
||||||
function! s:add_node_params(args)
|
|
||||||
let params = webapi#xml#createElement("params")
|
|
||||||
for Arg in a:args
|
|
||||||
let param = webapi#xml#createElement("param")
|
|
||||||
let value = webapi#xml#createElement("value")
|
|
||||||
call value.value(s:to_value(Arg))
|
|
||||||
call add(param.child, value)
|
|
||||||
call add(params.child, param)
|
|
||||||
unlet Arg
|
|
||||||
endfor
|
|
||||||
return params
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#xmlrpc#call(uri, func, args)
|
|
||||||
let methodCall = webapi#xml#createElement("methodCall")
|
|
||||||
let methodName = webapi#xml#createElement("methodName")
|
|
||||||
call methodName.value(a:func)
|
|
||||||
call add(methodCall.child, methodName)
|
|
||||||
if !empty(a:args)
|
|
||||||
call add(methodCall.child, s:add_node_params(a:args))
|
|
||||||
endif
|
|
||||||
let xml = '<?xml version="1.0" encoding="utf-8"?>'
|
|
||||||
let xml .= iconv(methodCall.toString(), &encoding, "utf-8")
|
|
||||||
let res = webapi#http#post(a:uri, xml, {"Content-Type": "text/xml"})
|
|
||||||
let dom = webapi#xml#parse(res.content)
|
|
||||||
if len(dom.find('fault'))
|
|
||||||
throw s:to_fault(dom)
|
|
||||||
else
|
|
||||||
return s:from_value(dom)
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
function! webapi#xmlrpc#wrap(contexts)
|
|
||||||
let api = {}
|
|
||||||
for context in a:contexts
|
|
||||||
let target = api
|
|
||||||
let namespaces = split(context.name, '\.')[:-2]
|
|
||||||
if len(namespaces) > 0
|
|
||||||
for ns in namespaces
|
|
||||||
if !has_key(target, ns)
|
|
||||||
let target[ns] = {".uri": context.uri}
|
|
||||||
endif
|
|
||||||
let target = target[ns]
|
|
||||||
let api['.uri'] = target['.uri']
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
if len(context.argnames) && context.argnames[-1] == '...'
|
|
||||||
let arglist = '[' . join(map(copy(context.argnames[:-2]),'"a:".v:val'),',') . ']+a:000'
|
|
||||||
else
|
|
||||||
let arglist = '[' . join(map(copy(context.argnames),'"a:".v:val'),',') . ']'
|
|
||||||
endif
|
|
||||||
if has_key(context, 'alias')
|
|
||||||
exe "function api.".context.alias."(".join(context.argnames,",").") dict\n"
|
|
||||||
\. " return webapi#xmlrpc#call(self['.uri'], '".context.name."', ".arglist.")\n"
|
|
||||||
\. "endfunction\n"
|
|
||||||
else
|
|
||||||
exe "function api.".context.name."(".join(context.argnames,",").") dict\n"
|
|
||||||
\. " return webapi#xmlrpc#call('".context.uri."', '".context.name."', ".arglist.")\n"
|
|
||||||
\. "endfunction\n"
|
|
||||||
endif
|
|
||||||
endfor
|
|
||||||
return api
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let &cpo = s:save_cpo
|
|
||||||
unlet s:save_cpo
|
|
||||||
|
|
||||||
" vim:set et:
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
*webapi-html.txt* HTML parser written in pure vimscript.
|
|
||||||
|
|
||||||
Maintainer: mattn <mattn.jp@gmail.com>
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
CONTENTS *webapi-html-contents*
|
|
||||||
|
|
||||||
INTRODUCTION |webapi-html-introduction|
|
|
||||||
INTERFACE |webapi-html-interface|
|
|
||||||
Functions |webapi-html-functions|
|
|
||||||
Structures |webapi-html-structures|
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTRODUCTION *webapi-html-introduction*
|
|
||||||
|
|
||||||
*webapi-html* is HTML parser Library.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTERFACE *webapi-html-interface*
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
FUNCTIONS *webapi-html-functions*
|
|
||||||
|
|
||||||
parse(content) *webapi-html.parse()*
|
|
||||||
Parse content into DOM object.
|
|
||||||
|
|
||||||
parseFile(file) *webapi-html.parseFile()*
|
|
||||||
Parse html file into DOM object.
|
|
||||||
|
|
||||||
parseURI(url) *webapi-html.parseURI()*
|
|
||||||
Get and parse html into DOM object.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
STRUCTURES *webapi-html-structures*
|
|
||||||
|
|
||||||
DOM object is structured as |Directory| like following.
|
|
||||||
>
|
|
||||||
{
|
|
||||||
"name": "a",
|
|
||||||
"attr": {
|
|
||||||
"href": "http://example.com",
|
|
||||||
"title": "example",
|
|
||||||
},
|
|
||||||
"child": [...]
|
|
||||||
}
|
|
||||||
<
|
|
||||||
==============================================================================
|
|
||||||
vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
*webapi-http.txt* simple HTTP client library.
|
|
||||||
|
|
||||||
Maintainer: mattn <mattn.jp@gmail.com>
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
CONTENTS *webapi-http-contents*
|
|
||||||
|
|
||||||
INTRODUCTION |webapi-http-introduction|
|
|
||||||
INTERFACE |webapi-http-interface|
|
|
||||||
Functions |webapi-http-functions|
|
|
||||||
Response |webapi-http-response|
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTRODUCTION *webapi-http-introduction*
|
|
||||||
|
|
||||||
*webapi-http* is HTTP Utilities Library. It provides simple HTTP client.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTERFACE *webapi-http-interface*
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
FUNCTIONS *webapi-http-functions*
|
|
||||||
|
|
||||||
get(url, param, header) *webapi-http.get()*
|
|
||||||
Send GET request to url.
|
|
||||||
|
|
||||||
post(url, param, header) *webapi-http.post()*
|
|
||||||
Send POST request to url.
|
|
||||||
|
|
||||||
encodeURI(param) *webapi-http.encodeURI()*
|
|
||||||
Encode params as URI query.
|
|
||||||
|
|
||||||
decodeURI(str) *webapi-http.decodeURI()*
|
|
||||||
Decode string as URI params.
|
|
||||||
|
|
||||||
encodeURIComponent(str) *webapi-http.encodeURIComponent()*
|
|
||||||
Encode param as URI components.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
RESPONSE *webapi-http-response*
|
|
||||||
|
|
||||||
|webapi-http.get| and |webapi-http.post| return data structure as
|
|
||||||
|Directory| like following.
|
|
||||||
>
|
|
||||||
{
|
|
||||||
"header": [
|
|
||||||
"Content-Type: text/html",
|
|
||||||
"Content-Length: 310"
|
|
||||||
],
|
|
||||||
"content": "<html> ....."
|
|
||||||
}
|
|
||||||
<
|
|
||||||
==============================================================================
|
|
||||||
vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
*webapi-json.txt* JSON parser written in pure vimscript.
|
|
||||||
|
|
||||||
Maintainer: mattn <mattn.jp@gmail.com>
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
CONTENTS *webapi-json-contents*
|
|
||||||
|
|
||||||
INTRODUCTION |webapi-json-introduction|
|
|
||||||
INTERFACE |webapi-json-interface|
|
|
||||||
Functions |webapi-json-functions|
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTRODUCTION *webapi-json-introduction*
|
|
||||||
|
|
||||||
*webapi-json* is JSON parser Library.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTERFACE *webapi-json-interface*
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
FUNCTIONS *webapi-json-functions*
|
|
||||||
|
|
||||||
encode(object) *webapi-json.encode()*
|
|
||||||
Encode object into JSON string.
|
|
||||||
|
|
||||||
decode(json) *webapi-json.decode()*
|
|
||||||
Decode JSON string into variable that vim can treat.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
*webapi-xml.txt* XML parser written in pure vimscript.
|
|
||||||
|
|
||||||
Maintainer: mattn <mattn.jp@gmail.com>
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
CONTENTS *webapi-xml-contents*
|
|
||||||
|
|
||||||
INTRODUCTION |webapi-xml-introduction|
|
|
||||||
INTERFACE |webapi-xml-interface|
|
|
||||||
Functions |webapi-xml-functions|
|
|
||||||
Structures |webapi-xml-structures|
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTRODUCTION *webapi-xml-introduction*
|
|
||||||
|
|
||||||
*webapi-xml* is XML parser Library.
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
INTERFACE *webapi-xml-interface*
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
FUNCTIONS *webapi-xml-functions*
|
|
||||||
|
|
||||||
parse(content) *webapi-xml.parse()*
|
|
||||||
Parse content into DOM object.
|
|
||||||
|
|
||||||
parseFile(file) *webapi-xml.parseFile()*
|
|
||||||
Parse html file into DOM object.
|
|
||||||
|
|
||||||
parseURI(url) *webapi-xml.parseURI()*
|
|
||||||
Get and parse html into DOM object.
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
|
||||||
STRUCTURES *webapi-xml-structures*
|
|
||||||
|
|
||||||
DOM object is structured as |Directory| like following.
|
|
||||||
>
|
|
||||||
{
|
|
||||||
"name": "a",
|
|
||||||
"attr": {
|
|
||||||
"href": "http://example.com",
|
|
||||||
"title": "example",
|
|
||||||
},
|
|
||||||
"child": [...]
|
|
||||||
}
|
|
||||||
<
|
|
||||||
==============================================================================
|
|
||||||
vim:tw=78:fo=tcq2mM:ts=8:ft=help:norl
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
function! s:dump(node, syntax)
|
|
||||||
let syntax = a:syntax
|
|
||||||
if type(a:node) == 1
|
|
||||||
if len(syntax) | exe "echohl ".syntax | endif
|
|
||||||
echon webapi#html#decodeEntityReference(a:node)
|
|
||||||
echohl None
|
|
||||||
elseif type(a:node) == 3
|
|
||||||
for n in a:node
|
|
||||||
call s:dump(n, syntax)
|
|
||||||
endfor
|
|
||||||
return
|
|
||||||
elseif type(a:node) == 4
|
|
||||||
"echo a:node.name
|
|
||||||
"echo a:node.attr
|
|
||||||
let syndef = {'kt' : 'Type', 'mi' : 'Number', 'nb' : 'Statement', 'kp' : 'Statement', 'nn' : 'Define', 'nc' : 'Constant', 'no' : 'Constant', 'k' : 'Include', 's' : 'String', 's1' : 'String', 'err': 'Error', 'kd' : 'StorageClass', 'c1' : 'Comment', 'ss' : 'Delimiter', 'vi' : 'Identifier'}
|
|
||||||
for a in keys(syndef)
|
|
||||||
if has_key(a:node.attr, 'class') && a:node.attr['class'] == a | let syntax = syndef[a] | endif
|
|
||||||
endfor
|
|
||||||
if has_key(a:node.attr, 'class') && a:node.attr['class'] == 'line' | echon "\n" | endif
|
|
||||||
for c in a:node.child
|
|
||||||
call s:dump(c, syntax)
|
|
||||||
unlet c
|
|
||||||
endfor
|
|
||||||
endif
|
|
||||||
endfunction
|
|
||||||
|
|
||||||
let no = 357275
|
|
||||||
let res = webapi#http#get(printf('http://gist.github.com/%d.json', no))
|
|
||||||
let obj = webapi#json#decode(res.content)
|
|
||||||
let dom = webapi#html#parse(obj.div)
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
for file in dom.childNodes('div')
|
|
||||||
unlet! meta
|
|
||||||
let meta = file.childNodes('div')
|
|
||||||
if len(meta) > 1
|
|
||||||
echo "URL:".meta[1].find('a').attr['href']
|
|
||||||
endif
|
|
||||||
echo "\n"
|
|
||||||
call s:dump(file.find('pre'), '')
|
|
||||||
echo "-------------------------------------------------"
|
|
||||||
endfor
|
|
||||||
|
|
||||||
" vim: set et:
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
set rtp+=.
|
|
||||||
|
|
||||||
let ctx = {}
|
|
||||||
let configfile = expand('~/.google-buzz-vim')
|
|
||||||
if filereadable(configfile)
|
|
||||||
let ctx = eval(join(readfile(configfile), ""))
|
|
||||||
else
|
|
||||||
let ctx.consumer_key = input("consumer_key:")
|
|
||||||
let ctx.consumer_secret = input("consumer_secret:")
|
|
||||||
let ctx.domain = input("domain:")
|
|
||||||
let ctx.callback = input("callback:")
|
|
||||||
|
|
||||||
let request_token_url = "https://www.google.com/accounts/OAuthGetRequestToken"
|
|
||||||
let auth_url = "https://www.google.com/accounts/OAuthAuthorizeToken"
|
|
||||||
let access_token_url = "https://www.google.com/accounts/OAuthGetAccessToken"
|
|
||||||
|
|
||||||
let ctx = webapi#oauth#request_token(request_token_url, ctx, {"scope": "https://www.googleapis.com/auth/buzz", "oauth_callback": ctx.callback})
|
|
||||||
if has("win32") || has("win64")
|
|
||||||
exe "!start rundll32 url.dll,FileProtocolHandler ".auth_url."?oauth_token=".ctx.request_token."&domain=".ctx.domain."&scope=https://www.googleapis.com/auth/buzz"
|
|
||||||
else
|
|
||||||
call system("xdg-open '".auth_url."?oauth_token=".ctx.request_token. "&domain=".ctx.domain."&scope=https://www.googleapis.com/auth/buzz'")
|
|
||||||
endif
|
|
||||||
let verifier = input("VERIFIER:")
|
|
||||||
let ctx = webapi#oauth#access_token(access_token_url, ctx, {"oauth_verifier": verifier})
|
|
||||||
call writefile([string(ctx)], configfile)
|
|
||||||
endif
|
|
||||||
|
|
||||||
let post_url = "https://www.googleapis.com/buzz/v1/activities/@me/@self"
|
|
||||||
let data = ''
|
|
||||||
\.'<entry xmlns:activity="http://activitystrea.ms/spec/1.0/"'
|
|
||||||
\.' xmlns:poco="http://portablecontacts.net/ns/1.0"'
|
|
||||||
\.' xmlns:georss="http://www.georss.org/georss"'
|
|
||||||
\.' xmlns:buzz="http://schemas.google.com/buzz/2010">'
|
|
||||||
\.' <activity:object>'
|
|
||||||
\.' <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>'
|
|
||||||
\.' <content>ばず! ばず!</content>'
|
|
||||||
\.' </activity:object>'
|
|
||||||
\.'</entry>'
|
|
||||||
let ret = webapi#oauth#post(post_url, ctx, {}, data, {"Content-Type": "application/atom+xml", "GData-Version": "2.0"})
|
|
||||||
echo ret
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user