1
0
mirror of https://github.com/amix/vimrc synced 2025-02-28 14:12:51 +08:00
This commit is contained in:
Maksim Pecherskiy 2014-11-15 17:31:27 +00:00
commit 6009ead4ba
111 changed files with 15472 additions and 1818 deletions

View File

@ -1,5 +1,7 @@
# The Ultimate vimrc # The Ultimate vimrc
## Important -- set iterm profile -> terminal -> report terminal type: xterm-256
Over the last 8 years I have used and tweaked Vim. This is my Ultimate vimrc. Over the last 8 years I have used and tweaked Vim. This is my Ultimate vimrc.
There are two versions: There are two versions:

View File

@ -0,0 +1,114 @@
" set up pathogen, https://github.com/tpope/vim-pathogen
filetype on " without this vim emits a zero exit status, later, because of :ft off
filetype off
call pathogen#infect()
filetype plugin indent on
" don't bother with vi compatibility
set nocompatible
" enable syntax highlighting
syntax enable
set autoindent
set autoread " reload files when changed on disk, i.e. via `git checkout`
set backspace=2 " Fix broken backspace in some setups
set backupcopy=yes " see :help crontab
set clipboard=unnamed " yank and paste with the system clipboard
set directory-=. " don't store swapfiles in the current directory
set encoding=utf-8
set expandtab " expand tabs to spaces
set ignorecase " case-insensitive search
set incsearch " search as you type
set laststatus=2 " always show statusline
set list " show trailing whitespace
set listchars=tab:▸\ ,trail:▫
set number " show line numbers
set ruler " show where you are
set scrolloff=3 " show context above/below cursorline
set shiftwidth=2 " normal mode indentation commands use 2 spaces
set showcmd
set smartcase " case-sensitive search if any caps
set softtabstop=2 " insert mode tab and backspace use 2 spaces
set tabstop=8 " actual tabs occupy 8 characters
set wildignore=log/**,node_modules/**,target/**,tmp/**,*.rbc
set wildmenu " show a navigable menu for tab completion
set wildmode=longest,list,full
" Enable basic mouse behavior such as resizing buffers.
set mouse=a
if exists('$TMUX') " Support resizing in tmux
set ttymouse=xterm2
endif
" keyboard shortcuts
let mapleader = ','
map <C-h> <C-w>h
map <C-j> <C-w>j
map <C-k> <C-w>k
map <C-l> <C-w>l
map <leader>l :Align
nmap <leader>a :Ack
nmap <leader>b :CtrlPBuffer<CR>
nmap <leader>d :NERDTreeToggle<CR>
nmap <leader>f :NERDTreeFind<CR>
nmap <leader>t :CtrlP<CR>
nmap <leader>T :CtrlPClearCache<CR>:CtrlP<CR>
nmap <leader>] :TagbarToggle<CR>
nmap <leader><space> :call whitespace#strip_trailing()<CR>
nmap <leader>g :GitGutterToggle<CR>
nmap <leader>c <Plug>Kwbd
map <silent> <leader>V :source ~/.vimrc<CR>:filetype detect<CR>:exe ":echo 'vimrc reloaded'"<CR>
" plugin settings
let g:ctrlp_match_window = 'order:ttb,max:20'
let g:NERDSpaceDelims=1
let g:gitgutter_enabled = 0
" Use The Silver Searcher https://github.com/ggreer/the_silver_searcher
if executable('ag')
let g:ackprg = 'ag --nogroup --column'
" Use Ag over Grep
set grepprg=ag\ --nogroup\ --nocolor
" Use ag in CtrlP for listing files. Lightning fast and respects .gitignore
let g:ctrlp_user_command = 'ag %s -l --nocolor -g ""'
endif
" fdoc is yaml
autocmd BufRead,BufNewFile *.fdoc set filetype=yaml
" md is markdown
autocmd BufRead,BufNewFile *.md set filetype=markdown
" extra rails.vim help
autocmd User Rails silent! Rnavcommand decorator app/decorators -glob=**/* -suffix=_decorator.rb
autocmd User Rails silent! Rnavcommand observer app/observers -glob=**/* -suffix=_observer.rb
autocmd User Rails silent! Rnavcommand feature features -glob=**/* -suffix=.feature
autocmd User Rails silent! Rnavcommand job app/jobs -glob=**/* -suffix=_job.rb
autocmd User Rails silent! Rnavcommand mediator app/mediators -glob=**/* -suffix=_mediator.rb
autocmd User Rails silent! Rnavcommand stepdefinition features/step_definitions -glob=**/* -suffix=_steps.rb
" automatically rebalance windows on vim resize
autocmd VimResized * :wincmd =
" Fix Cursor in TMUX
if exists('$TMUX')
let &t_SI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=1\x7\<Esc>\\"
let &t_EI = "\<Esc>Ptmux;\<Esc>\<Esc>]50;CursorShape=0\x7\<Esc>\\"
else
let &t_SI = "\<Esc>]50;CursorShape=1\x7"
let &t_EI = "\<Esc>]50;CursorShape=0\x7"
endif
" Go crazy!
if filereadable(expand("~/.vimrc.local"))
" In your .vimrc.local, you might like:
"
" set autowrite
" set nocursorline
" set nowritebackup
" set whichwrap+=<,>,h,l,[,] " Wrap arrow keys between lines
"
" autocmd! bufwritepost .vimrc source ~/.vimrc
" noremap! jj <ESC>
source ~/.vimrc.local
endif

134
my_configs.vim Normal file
View File

@ -0,0 +1,134 @@
"Switch color schemes"
function! ColorSet(colorName)
if a:colorName == "default"
colorscheme molokai
set background=dark
let g:molokai_original=1
let g:airline_theme = 'molokai'
elseif a:colorName == "outside"
colorscheme solarized
set background=light
let g:airline_theme = 'molokai'
elseif a:colorName == "bluey"
colorscheme solarized
set background=dark
let g:airline_theme = 'molokai'
elseif a:colorName == "smyck"
colorscheme smyck
set background=dark
let g:airline_theme = 'molokai'
elseif a:colorName == "dracula"
colorscheme dracula
set background=dark
let g:airline_theme = 'molokai'
else
colorscheme molokai
set background=dark
let g:molokai_original=1
let g:airline_theme = 'molokai'
endif
endfunction
:command -nargs=1 ColorSet :call ColorSet(<f-args>)
if !empty($VIM_COLOR)
:call ColorSet($VIM_COLOR)
else
:call ColorSet("default")
endif
"set mouse=a
"set background=dark
"let g:molokai_original = 1
"colorscheme solarized
"syntax enable
"set background=dark
"set smartindent
"autocmd BufWritePre * :FixWhitespace
set timeoutlen=2000
set pastetoggle=<F6>
"inoremap jk <ESC>
"nnoremap ; :
#set colorcolumn=80
" Open Vim, be able to undo
"set undodir=$HOME/.vim/undo
"set undolevels=1000
"set undoreload=10000
" System wide copy paste
"set clipboard=unnamedplus
" Make Y behave like other capitals
"map Y y$
"
" " Start scrolling 3 lines before the border
set scrolloff=3
"
" " Automatically reread files that have been changed externally
"set autoread
"
" " Make ^e and ^y scroll 3 lines instead of 1
"nnoremap <C-e> 3<C-e>
"nnoremap <C-y> 3<C-y>
"
" " don't move the cursor after pasting
" " (by jumping to back start of previously changed text)
"noremap p p`[
"noremap P P`[
"
" " Reselect visual block after indent/outdent
"vnoremap < <gv
"vnoremap > >gv
" Turn off the christmas lights
"nnoremap <cr> :nohlsearch<cr>
" Allow saving as root by w!!
"cmap w!! %!sudo tee > /dev/null %
" Finde merge conflict markers
"nmap <silent> <leader>cf <ESC>/\v^[<=>]{7}( .*\|$)<CR>
" Use Marked.app to preview Markdown files...
"function! s:setupMarkup()
" nnoremap <leader>p :silent !open -a Marked.app '%:p'<cr>
"endfunction
" Navigate splits more easily
"map <C-h> <C-w>h
"map <C-j> <C-w>j
"map <C-k> <C-w>k
"map <C-l> <C-w>l
" " These makes j/k move up/down a screen line instead of a physical file line (for wrapped lines)
"nmap k gk
"nmap j gj
" autocmd BufEnter * if &modifiable | NERDTreeFind | wincmd p | endif
" Easymotion {{{
"let g:EasyMotion_do_mapping = 0
"nnoremap <silent> <Leader>f :call EasyMotion#F(0, 0)<CR>
"onoremap <silent> <Leader>f :call EasyMotion#F(0, 0)<CR>
"vnoremap <silent> <Leader>f :<C-U>call EasyMotion#F(1, 0)<CR>
"nnoremap <silent> <Leader>F :call EasyMotion#F(0, 1)<CR>
"onoremap <silent> <Leader>F :call EasyMotion#F(0, 1)<CR>
"vnoremap <silent> <Leader>F :<C-U>call EasyMotion#F(1, 1)<CR>
"onoremap <silent> <Leader>t :call EasyMotion#T(0, 0)<CR>
"onoremap <silent> <Leader>T :call EasyMotion#T(0, 1)<CR>
" }}}
"source ~/.vim_runtime/maximum_awesome_vimrc
"set tabstop=2
"set shiftwidth=2
"set expandtab
"set smartindentl:s
"
"

View File

@ -0,0 +1,116 @@
" Dracula Theme v0.7.0
"
" https://github.com/zenorocha/dracula-theme
"
" Copyright 2013, All rights reserved
"
" Code licensed under the MIT license
" http://zenorocha.mit-license.org
"
" @author Éverton Ribeiro <nuxlli@gmail.com>
" @author Zeno Rocha <hi@zenorocha.com>
set background=dark
highlight clear
if exists("syntax_on")
syntax reset
endif
let g:colors_name = "Dracula"
hi Cursor ctermfg=17 ctermbg=231 cterm=NONE guifg=#282a36 guibg=#f8f8f0 gui=NONE
hi Visual ctermfg=NONE ctermbg=236 cterm=NONE guifg=NONE guibg=#44475a gui=NONE
hi CursorLine ctermfg=NONE ctermbg=236 cterm=NONE guifg=NONE guibg=#3d3f49 gui=NONE
hi CursorColumn ctermfg=NONE ctermbg=236 cterm=NONE guifg=NONE guibg=#3d3f49 gui=NONE
hi ColorColumn ctermfg=NONE ctermbg=236 cterm=NONE guifg=NONE guibg=#3d3f49 gui=NONE
hi LineNr ctermfg=246 ctermbg=236 cterm=NONE guifg=#909194 guibg=#3d3f49 gui=NONE
hi VertSplit ctermfg=59 ctermbg=236 cterm=NONE guifg=#64666d guibg=#64666d gui=NONE
hi MatchParen ctermfg=212 ctermbg=NONE cterm=underline guifg=#ff79c6 guibg=NONE gui=underline
hi StatusLine ctermfg=231 ctermbg=236 cterm=bold guifg=#f8f8f2 guibg=#64666d gui=bold
hi StatusLineNC ctermfg=231 ctermbg=236 cterm=NONE guifg=#f8f8f2 guibg=#64666d gui=NONE
hi Pmenu ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
hi PmenuSel ctermfg=NONE ctermbg=236 cterm=NONE guifg=NONE guibg=#44475a gui=NONE
hi IncSearch ctermfg=17 ctermbg=228 cterm=NONE guifg=#282a36 guibg=#f1fa8c 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=#bd93f9 guibg=NONE gui=NONE
hi Folded ctermfg=61 ctermbg=235 cterm=NONE guifg=#6272a4 guibg=#282a36 gui=NONE
hi Normal ctermfg=231 ctermbg=235 cterm=NONE guifg=#f8f8f2 guibg=#282a36 gui=NONE
hi Boolean ctermfg=141 ctermbg=NONE cterm=NONE guifg=#bd93f9 guibg=NONE gui=NONE
hi Character ctermfg=141 ctermbg=NONE cterm=NONE guifg=#bd93f9 guibg=NONE gui=NONE
hi Comment ctermfg=61 ctermbg=NONE cterm=NONE guifg=#6272a4 guibg=NONE gui=NONE
hi Conditional ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi Constant ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
hi Define ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi DiffAdd ctermfg=231 ctermbg=64 cterm=bold guifg=#f8f8f2 guibg=#468410 gui=bold
hi DiffDelete ctermfg=88 ctermbg=NONE cterm=NONE guifg=#8b080b guibg=NONE gui=NONE
hi DiffChange ctermfg=231 ctermbg=23 cterm=NONE guifg=#f8f8f2 guibg=#243a5f gui=NONE
hi DiffText ctermfg=231 ctermbg=24 cterm=bold guifg=#f8f8f2 guibg=#204a87 gui=bold
hi ErrorMsg ctermfg=231 ctermbg=212 cterm=NONE guifg=#f8f8f0 guibg=#ff79c6 gui=NONE
hi WarningMsg ctermfg=231 ctermbg=212 cterm=NONE guifg=#f8f8f0 guibg=#ff79c6 gui=NONE
hi Float ctermfg=141 ctermbg=NONE cterm=NONE guifg=#bd93f9 guibg=NONE gui=NONE
hi Function ctermfg=84 ctermbg=NONE cterm=NONE guifg=#50fa7b guibg=NONE gui=NONE
hi Identifier ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=italic
hi Keyword ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi Label ctermfg=228 ctermbg=NONE cterm=NONE guifg=#f1fa8c guibg=NONE gui=NONE
hi NonText ctermfg=59 ctermbg=236 cterm=NONE guifg=#3b3a32 guibg=#32343f gui=NONE
hi Number ctermfg=141 ctermbg=NONE cterm=NONE guifg=#bd93f9 guibg=NONE gui=NONE
hi Operator ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi PreProc ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi Special ctermfg=231 ctermbg=NONE cterm=NONE guifg=#f8f8f2 guibg=NONE gui=NONE
hi SpecialKey ctermfg=59 ctermbg=236 cterm=NONE guifg=#3b3a32 guibg=#3d3f49 gui=NONE
hi Statement ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi StorageClass ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=italic
hi String ctermfg=228 ctermbg=NONE cterm=NONE guifg=#f1fa8c guibg=NONE gui=NONE
hi Tag ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi Title ctermfg=231 ctermbg=NONE cterm=bold guifg=#f8f8f2 guibg=NONE gui=bold
hi Todo ctermfg=61 ctermbg=NONE cterm=inverse,bold guifg=#6272a4 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=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi rubyFunction ctermfg=84 ctermbg=NONE cterm=NONE guifg=#50fa7b 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=#bd93f9 guibg=NONE gui=NONE
hi rubyConstant ctermfg=81 ctermbg=NONE cterm=NONE guifg=#66d9ef guibg=NONE gui=italic
hi rubyStringDelimiter ctermfg=228 ctermbg=NONE cterm=NONE guifg=#f1fa8c guibg=NONE gui=NONE
hi rubyBlockParameter ctermfg=215 ctermbg=NONE cterm=NONE guifg=#ffb86c guibg=NONE gui=italic
hi rubyInstanceVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
hi rubyInclude ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi rubyGlobalVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
hi rubyRegexp ctermfg=228 ctermbg=NONE cterm=NONE guifg=#f1fa8c guibg=NONE gui=NONE
hi rubyRegexpDelimiter ctermfg=228 ctermbg=NONE cterm=NONE guifg=#f1fa8c guibg=NONE gui=NONE
hi rubyEscape ctermfg=141 ctermbg=NONE cterm=NONE guifg=#bd93f9 guibg=NONE gui=NONE
hi rubyControl ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi rubyClassVariable ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
hi rubyOperator ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 guibg=NONE gui=NONE
hi rubyException ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 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=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=NONE
hi rubyRailsARMethod ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=NONE
hi rubyRailsRenderMethod ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=NONE
hi rubyRailsMethod ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=NONE
hi erubyDelimiter ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
hi erubyComment ctermfg=61 ctermbg=NONE cterm=NONE guifg=#6272a4 guibg=NONE gui=NONE
hi erubyRailsMethod ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd 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=#bd93f9 guibg=NONE gui=NONE
hi javaScriptFunction ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=italic
hi javaScriptRailsFunction ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=NONE
hi javaScriptBraces ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE
hi yamlKey ctermfg=212 ctermbg=NONE cterm=NONE guifg=#ff79c6 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=228 ctermbg=NONE cterm=NONE guifg=#f1fa8c guibg=NONE gui=NONE
hi cssURL ctermfg=215 ctermbg=NONE cterm=NONE guifg=#ffb86c guibg=NONE gui=italic
hi cssFunctionName ctermfg=117 ctermbg=NONE cterm=NONE guifg=#8be9fd guibg=NONE gui=NONE
hi cssColor ctermfg=141 ctermbg=NONE cterm=NONE guifg=#bd93f9 guibg=NONE gui=NONE
hi cssPseudoClassId ctermfg=84 ctermbg=NONE cterm=NONE guifg=#50fa7b guibg=NONE gui=NONE
hi cssClassName ctermfg=84 ctermbg=NONE cterm=NONE guifg=#50fa7b guibg=NONE gui=NONE
hi cssValueLength ctermfg=141 ctermbg=NONE cterm=NONE guifg=#bd93f9 guibg=NONE gui=NONE
hi cssCommonAttr ctermfg=81 ctermbg=NONE cterm=NONE guifg=#6be5fd guibg=NONE gui=NONE
hi cssBraces ctermfg=NONE ctermbg=NONE cterm=NONE guifg=NONE guibg=NONE gui=NONE

View File

@ -0,0 +1,24 @@
# Molokai Color Scheme for Vim
Molokai is a Vim port of the monokai theme for TextMate originally created by Wimer Hazenberg.
By default, it has a dark gray background based on the version created by Hamish Stuart Macpherson for the E editor.
![Gray Background](http://www.winterdom.com/weblog/content/binary/WindowsLiveWriter/MolokaiforVim_8602/molokai_normal_small_3.png)
![Molokai Original](http://www.winterdom.com/weblog/content/binary/WindowsLiveWriter/MolokaiforVim_8602/molokai_original_small_3.png)
256-Color terminals are also supported, though there are some differences with the Gui version. Only the dark gray background style is supported on terminal vim at this time.
## Installation
Copy the file on your .vim/colors folder.
If you prefer the scheme to match the original monokai background color, put this in your .vimrc file:
let g:molokai_original = 1
There is also an alternative sheme under development for color terminals which attempts to bring the 256 color version as close as possible to the the default (dark) GUI version. To access, add this to your .vimrc:
let g:rehash256 = 1
Note: when using the console version, add this command after enabling the colorscheme in your .vimrc:
set background=dark

View File

@ -0,0 +1,270 @@
" Vim color file
"
" Author: Tomas Restrepo <tomas@winterdom.com>
"
" Note: Based on the monokai theme for textmate
" by Wimer Hazenberg and its darker variant
" by Hamish Stuart Macpherson
"
hi clear
set background=dark
if version > 580
" no guarantees for version 5.8 and below, but this makes it stop
" complaining
hi clear
if exists("syntax_on")
syntax reset
endif
endif
let g:colors_name="molokai"
if exists("g:molokai_original")
let s:molokai_original = g:molokai_original
else
let s:molokai_original = 0
endif
hi Boolean guifg=#AE81FF
hi Character guifg=#E6DB74
hi Number guifg=#AE81FF
hi String guifg=#E6DB74
hi Conditional guifg=#F92672 gui=bold
hi Constant guifg=#AE81FF gui=bold
hi Cursor guifg=#000000 guibg=#F8F8F0
hi iCursor guifg=#000000 guibg=#F8F8F0
hi Debug guifg=#BCA3A3 gui=bold
hi Define guifg=#66D9EF
hi Delimiter guifg=#8F8F8F
hi DiffAdd guibg=#13354A
hi DiffChange guifg=#89807D guibg=#4C4745
hi DiffDelete guifg=#960050 guibg=#1E0010
hi DiffText guibg=#4C4745 gui=italic,bold
hi Directory guifg=#A6E22E gui=bold
hi Error guifg=#960050 guibg=#1E0010
hi ErrorMsg guifg=#F92672 guibg=#232526 gui=bold
hi Exception guifg=#A6E22E gui=bold
hi Float guifg=#AE81FF
hi FoldColumn guifg=#465457 guibg=#000000
hi Folded guifg=#465457 guibg=#000000
hi Function guifg=#A6E22E
hi Identifier guifg=#FD971F
hi Ignore guifg=#808080 guibg=bg
hi IncSearch guifg=#C4BE89 guibg=#000000
hi Keyword guifg=#F92672 gui=bold
hi Label guifg=#E6DB74 gui=none
hi Macro guifg=#C4BE89 gui=italic
hi SpecialKey guifg=#66D9EF gui=italic
hi MatchParen guifg=#000000 guibg=#FD971F gui=bold
hi ModeMsg guifg=#E6DB74
hi MoreMsg guifg=#E6DB74
hi Operator guifg=#F92672
" complete menu
hi Pmenu guifg=#66D9EF guibg=#000000
hi PmenuSel guibg=#808080
hi PmenuSbar guibg=#080808
hi PmenuThumb guifg=#66D9EF
hi PreCondit guifg=#A6E22E gui=bold
hi PreProc guifg=#A6E22E
hi Question guifg=#66D9EF
hi Repeat guifg=#F92672 gui=bold
hi Search guifg=#FFFFFF guibg=#455354
" marks
hi SignColumn guifg=#A6E22E guibg=#232526
hi SpecialChar guifg=#F92672 gui=bold
hi SpecialComment guifg=#7E8E91 gui=bold
hi Special guifg=#66D9EF guibg=bg gui=italic
if has("spell")
hi SpellBad guisp=#FF0000 gui=undercurl
hi SpellCap guisp=#7070F0 gui=undercurl
hi SpellLocal guisp=#70F0F0 gui=undercurl
hi SpellRare guisp=#FFFFFF gui=undercurl
endif
hi Statement guifg=#F92672 gui=bold
hi StatusLine guifg=#455354 guibg=fg
hi StatusLineNC guifg=#808080 guibg=#080808
hi StorageClass guifg=#FD971F gui=italic
hi Structure guifg=#66D9EF
hi Tag guifg=#F92672 gui=italic
hi Title guifg=#ef5939
hi Todo guifg=#FFFFFF guibg=bg gui=bold
hi Typedef guifg=#66D9EF
hi Type guifg=#66D9EF gui=none
hi Underlined guifg=#808080 gui=underline
hi VertSplit guifg=#808080 guibg=#080808 gui=bold
hi VisualNOS guibg=#403D3D
hi Visual guibg=#403D3D
hi WarningMsg guifg=#FFFFFF guibg=#333333 gui=bold
hi WildMenu guifg=#66D9EF guibg=#000000
if s:molokai_original == 1
hi Normal guifg=#F8F8F2 guibg=#272822
hi Comment guifg=#75715E
hi CursorLine guibg=#3E3D32
hi CursorLineNr guifg=#FD971F gui=none
hi CursorColumn guibg=#3E3D32
hi ColorColumn guibg=#3B3A32
hi LineNr guifg=#BCBCBC guibg=#3B3A32
hi NonText guifg=#75715E
hi SpecialKey guifg=#75715E
else
hi Normal guifg=#F8F8F2 guibg=#1B1D1E
hi Comment guifg=#7E8E91
hi CursorLine guibg=#293739
hi CursorLineNr guifg=#FD971F gui=none
hi CursorColumn guibg=#293739
hi ColorColumn guibg=#232526
hi LineNr guifg=#465457 guibg=#232526
hi NonText guifg=#465457
hi SpecialKey guifg=#465457
end
"
" Support for 256-color terminal
"
if &t_Co > 255
if s:molokai_original == 1
hi Normal ctermbg=234
hi CursorLine ctermbg=235 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
else
hi Normal ctermfg=252 ctermbg=233
hi CursorLine ctermbg=234 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
endif
hi Boolean ctermfg=135
hi Character ctermfg=144
hi Number ctermfg=135
hi String ctermfg=144
hi Conditional ctermfg=161 cterm=bold
hi Constant ctermfg=135 cterm=bold
hi Cursor ctermfg=16 ctermbg=253
hi Debug ctermfg=225 cterm=bold
hi Define ctermfg=81
hi Delimiter ctermfg=241
hi DiffAdd ctermbg=24
hi DiffChange ctermfg=181 ctermbg=239
hi DiffDelete ctermfg=162 ctermbg=53
hi DiffText ctermbg=102 cterm=bold
hi Directory ctermfg=118 cterm=bold
hi Error ctermfg=219 ctermbg=89
hi ErrorMsg ctermfg=199 ctermbg=16 cterm=bold
hi Exception ctermfg=118 cterm=bold
hi Float ctermfg=135
hi FoldColumn ctermfg=67 ctermbg=16
hi Folded ctermfg=67 ctermbg=16
hi Function ctermfg=118
hi Identifier ctermfg=208 cterm=none
hi Ignore ctermfg=244 ctermbg=232
hi IncSearch ctermfg=193 ctermbg=16
hi keyword ctermfg=161 cterm=bold
hi Label ctermfg=229 cterm=none
hi Macro ctermfg=193
hi SpecialKey ctermfg=81
hi MatchParen ctermfg=16 ctermbg=208 cterm=bold
hi ModeMsg ctermfg=229
hi MoreMsg ctermfg=229
hi Operator ctermfg=161
" complete menu
hi Pmenu ctermfg=81 ctermbg=16
hi PmenuSel ctermfg=253 ctermbg=244
hi PmenuSbar ctermbg=232
hi PmenuThumb ctermfg=81
hi PreCondit ctermfg=118 cterm=bold
hi PreProc ctermfg=118
hi Question ctermfg=81
hi Repeat ctermfg=161 cterm=bold
hi Search ctermfg=253 ctermbg=66
" marks column
hi SignColumn ctermfg=118 ctermbg=235
hi SpecialChar ctermfg=161 cterm=bold
hi SpecialComment ctermfg=245 cterm=bold
hi Special ctermfg=81
if has("spell")
hi SpellBad ctermbg=52
hi SpellCap ctermbg=17
hi SpellLocal ctermbg=17
hi SpellRare ctermfg=none ctermbg=none cterm=reverse
endif
hi Statement ctermfg=161 cterm=bold
hi StatusLine ctermfg=238 ctermbg=253
hi StatusLineNC ctermfg=244 ctermbg=232
hi StorageClass ctermfg=208
hi Structure ctermfg=81
hi Tag ctermfg=161
hi Title ctermfg=166
hi Todo ctermfg=231 ctermbg=232 cterm=bold
hi Typedef ctermfg=81
hi Type ctermfg=81 cterm=none
hi Underlined ctermfg=244 cterm=underline
hi VertSplit ctermfg=244 ctermbg=232 cterm=bold
hi VisualNOS ctermbg=238
hi Visual ctermbg=235
hi WarningMsg ctermfg=231 ctermbg=238 cterm=bold
hi WildMenu ctermfg=81 ctermbg=16
hi Comment ctermfg=59
hi CursorColumn ctermbg=234
hi ColorColumn ctermbg=234
hi LineNr ctermfg=250 ctermbg=234
hi NonText ctermfg=59
hi SpecialKey ctermfg=59
if exists("g:rehash256") && g:rehash256 == 1
hi Normal ctermfg=252 ctermbg=234
hi CursorLine ctermbg=236 cterm=none
hi CursorLineNr ctermfg=208 cterm=none
hi Boolean ctermfg=141
hi Character ctermfg=222
hi Number ctermfg=141
hi String ctermfg=222
hi Conditional ctermfg=197 cterm=bold
hi Constant ctermfg=141 cterm=bold
hi DiffDelete ctermfg=125 ctermbg=233
hi Directory ctermfg=154 cterm=bold
hi Error ctermfg=125 ctermbg=233
hi Exception ctermfg=154 cterm=bold
hi Float ctermfg=141
hi Function ctermfg=154
hi Identifier ctermfg=208
hi Keyword ctermfg=197 cterm=bold
hi Operator ctermfg=197
hi PreCondit ctermfg=154 cterm=bold
hi PreProc ctermfg=154
hi Repeat ctermfg=197 cterm=bold
hi Statement ctermfg=197 cterm=bold
hi Tag ctermfg=197
hi Title ctermfg=203
hi Visual ctermbg=238
hi Comment ctermfg=244
hi LineNr ctermfg=239 ctermbg=235
hi NonText ctermfg=239
hi SpecialKey ctermfg=239
endif
end

View File

@ -0,0 +1,95 @@
" ----------------------------------------------------------------------------
" Vim color file
" Maintainer: John-Paul Bader <contact@smyck.org>
" Last Change: 2012 April
" License: Beer Ware
" ----------------------------------------------------------------------------
" Reset Highlighting
hi clear
if exists("syntax_on")
syntax reset
endif
set background=dark
set linespace=3
let g:colors_name = "smyck"
hi Normal cterm=none ctermbg=none ctermfg=15 gui=none guibg=#282828 guifg=#F7F7F7
hi LineNr cterm=none ctermbg=none ctermfg=8 gui=none guibg=#282828 guifg=#8F8F8F
hi StatusLine cterm=none ctermbg=8 ctermfg=15 gui=none guibg=#5D5D5D guifg=#FBFBFB
hi StatusLineNC cterm=none ctermbg=15 ctermfg=8 gui=none guibg=#5D5D5D guifg=#FBFBFB
hi Search cterm=none ctermbg=6 ctermfg=15 gui=none guibg=#2EB5C1 guifg=#F7F7F7
hi IncSearch cterm=none ctermbg=3 ctermfg=8 gui=none guibg=#F6DC69 guifg=#8F8F8F
hi ColumnMargin cterm=none ctermbg=0 gui=none guibg=#000000
hi Error cterm=none ctermbg=1 ctermfg=15 gui=none guifg=#F7F7F7
hi ErrorMsg cterm=none ctermbg=1 ctermfg=15 gui=none guifg=#F7F7F7
hi Folded cterm=none ctermbg=none ctermfg=2 gui=none guibg=#3B3B3B guifg=#90AB41
hi FoldColumn cterm=none ctermbg=8 ctermfg=2 gui=none guibg=#3B3B3B guifg=#90AB41
hi NonText cterm=bold ctermbg=none ctermfg=8 gui=bold guifg=#8F8F8F
hi ModeMsg cterm=bold ctermbg=none ctermfg=10 gui=none
hi Pmenu cterm=none ctermbg=8 ctermfg=15 gui=none guibg=#8F8F8F guifg=#F7F7F7
hi PmenuSel cterm=none ctermbg=15 ctermfg=8 gui=none guibg=#F7F7F7 guifg=#8F8F8F
hi PmenuSbar cterm=none ctermbg=15 ctermfg=8 gui=none guibg=#F7F7F7 guifg=#8F8F8F
hi SpellBad cterm=none ctermbg=1 ctermfg=15 gui=none guifg=#F7F7F7
hi SpellCap cterm=none ctermbg=4 ctermfg=15 gui=none guifg=#F7F7F7
hi SpellRare cterm=none ctermbg=4 ctermfg=15 gui=none guifg=#F7F7F7
hi SpellLocal cterm=none ctermbg=4 ctermfg=15 gui=none guifg=#F7F7F7
hi Visual cterm=none ctermbg=15 ctermfg=8 gui=none guibg=#F7F7F7 guifg=#8F8F8F
hi Directory cterm=none ctermbg=none ctermfg=4 gui=none guibg=#242424 guifg=#88CCE7
hi SpecialKey cterm=none ctermbg=none ctermfg=8 gui=none guifg=#8F8F8F
hi DiffAdd cterm=bold ctermbg=2 ctermfg=15
hi DiffChange cterm=bold ctermbg=4 ctermfg=15
hi DiffDelete cterm=bold ctermbg=1 ctermfg=15
hi DiffText cterm=bold ctermbg=3 ctermfg=8
hi MatchParen cterm=none ctermbg=6 ctermfg=15 gui=none guibg=#2EB5C1 guifg=#F7F7F7
hi CursorLine cterm=none ctermbg=238 ctermfg=none gui=none guibg=#424242
hi CursorColumn cterm=none ctermbg=238 ctermfg=none gui=none guibg=#424242
hi Title cterm=none ctermbg=none ctermfg=4 gui=none guifg=#88CCE7
" ----------------------------------------------------------------------------
" Syntax Highlighting
" ----------------------------------------------------------------------------
hi Keyword cterm=none ctermbg=none ctermfg=10 gui=none guifg=#D1FA71
hi Comment cterm=none ctermbg=none ctermfg=8 gui=none guifg=#8F8F8F
hi Delimiter cterm=none ctermbg=none ctermfg=15 gui=none guifg=#F7F7F7
hi Identifier cterm=none ctermbg=none ctermfg=12 gui=none guifg=#96D9F1
hi Structure cterm=none ctermbg=none ctermfg=12 gui=none guifg=#9DEEF2
hi Ignore cterm=none ctermbg=none ctermfg=8 gui=none guifg=bg
hi Constant cterm=none ctermbg=none ctermfg=12 gui=none guifg=#96D9F1
hi PreProc cterm=none ctermbg=none ctermfg=10 gui=none guifg=#D1FA71
hi Type cterm=none ctermbg=none ctermfg=12 gui=none guifg=#96D9F1
hi Statement cterm=none ctermbg=none ctermfg=10 gui=none guifg=#D1FA71
hi Special cterm=none ctermbg=none ctermfg=6 gui=none guifg=#d7d7d7
hi String cterm=none ctermbg=none ctermfg=3 gui=none guifg=#F6DC69
hi Number cterm=none ctermbg=none ctermfg=3 gui=none guifg=#F6DC69
hi Underlined cterm=none ctermbg=none ctermfg=magenta gui=underline guibg=#272727
hi Symbol cterm=none ctermbg=none ctermfg=9 gui=none guifg=#FAB1AB
hi Method cterm=none ctermbg=none ctermfg=15 gui=none guifg=#F7F7F7
hi Interpolation cterm=none ctermbg=none ctermfg=6 gui=none guifg=#2EB5C1
" Erlang
hi link erlangAtom Keyword
hi link erlangBitType Keyword
hi link rubyBeginend Keyword
hi link rubyClass Keyword
hi link rubyModule Keyword
hi link rubyKeyword Keyword
hi link rubyOperator Method
hi link rubyIdentifier Keyword
hi link rubyClassVariable Symbol
hi link rubyInstanceVariable Constant
hi link rubyGlobalVariable Constant
hi link rubyClassVariable Method
hi link rubyConstant Constant
hi link rubySymbol Symbol
hi link rubyFunction Constant
hi link rubyControl Keyword
hi link rubyConditional Keyword
hi link rubyInterpolation Interpolation
hi link rubyInterpolationDelimiter Interpolation
hi link rubyRailsMethod Method

View File

@ -1,39 +0,0 @@
created by
---------
[jeff lanzarotta](http://www.vim.org/account/profile.php?user_id=97)
script type
----------
utility
description
-----------
With bufexplorer, you can quickly and easily switch between buffers by using the one of the default public interfaces:
'\be' (normal open) or
'\bs' (force horizontal split open) or
'\bv' (force vertical split open)
Once the bufexplorer window is open you can use the normal movement keys (hjkl) to move around and then use <Enter> or <Left-Mouse-Click> to select the buffer you would like to open. If you would like to have the selected buffer opened in a new tab, simply press either <Shift-Enter> or 't'. Please note that when opening a buffer in a tab, that if the buffer is already in another tab, bufexplorer can switch to that tab automatically for you if you would like. More about that in the supplied VIM help.
Bufexplorer also offers various options including:
* Display the list of buffers in various sort orders including:
* Most Recently Used (MRU) which is the default
* Buffer number
* File name
* File extension
* Full file path name
* Delete buffer from list
For more about options, sort orders, configuration options, etc. please see the supplied VIM help.
install details
---------------
Simply unzip bufexplorer.zip into a directory in your 'runtimepath', usually ~/.vim or c:\vimfiles, and restart Vim. This zip file contains plugin\bufexplorer.vim, and doc\bufexplorer.txt. See ':help add-local-help' on how to add bufexplorer.txt to vim's help system.
NOTE
----
Version 7.0.12 and above will ONLY work with 7.0 and above of Vim.
**IMPORTANT**: If you have a version prior to 7.1.2 that contains an autoload\bufexplorer.vim file, please REMOVE the autoload\bufexlorer.vim AND the plugin\bufexplorer.vim files before installing a new version.

View File

@ -1,513 +0,0 @@
*bufexplorer.txt* Buffer Explorer Last Change: 22 Oct 2010
Buffer Explorer *buffer-explorer* *bufexplorer*
Version 7.2.8
Plugin for easily exploring (or browsing) Vim |:buffers|.
|bufexplorer-installation| Installation
|bufexplorer-usage| Usage
|bufexplorer-windowlayout| Window Layout
|bufexplorer-customization| Customization
|bufexplorer-changelog| Change Log
|bufexplorer-todo| Todo
|bufexplorer-credits| Credits
For Vim version 7.0 and above.
This plugin is only available if 'compatible' is not set.
{Vi does not have any of this}
==============================================================================
INSTALLATION *bufexplorer-installation*
To install:
- Download the bufexplorer.zip.
- Extract the zip archive into your runtime directory.
The archive contains plugin/bufexplorer.vim, and doc/bufexplorer.txt.
- Start Vim or goto an existing instance of Vim.
- Execute the following command:
>
:helptag <your runtime directory>/doc
<
This will generate all the help tags for any file located in the doc
directory.
==============================================================================
USAGE *bufexplorer-usage*
To start exploring in the current window, use: >
\be or :BufExplorer
To start exploring in a newly split horizontal window, use: >
\bs or :BufExplorerHorizontalSplit
To start exploring in a newly split vertical window, use: >
\bv or :BufExplorerVerticalSplit
If you would like to use something other than '\', you may simply change the
leader (see |mapleader|).
Note: If the current buffer is modified when bufexplorer started, the current
window is always split and the new bufexplorer is displayed in that new
window.
Commands to use once exploring:
<F1> Toggle help information.
<enter> Opens the buffer that is under the cursor into the current
window.
<leftmouse> Opens the buffer that is under the cursor into the current
window.
<shift-enter> Opens the buffer that is under the cursor in another tab.
d |:delete|the buffer under the cursor from the list. The
buffer's 'buflisted' is cleared. This allows for the buffer to
be displayed again using the 'show unlisted' command.
R Toggles relative path/absolute path.
T Toggles to show only buffers for this tab or not.
D |:wipeout|the buffer under the cursor from the list. When a
buffers is wiped, it will not be shown when unlisted buffer are
displayed.
f Toggles whether you are taken to the active window when
selecting a buffer or not.
o Opens the buffer that is under the cursor into the current
window.
p Toggles the showing of a split filename/pathname.
q Quit exploring.
r Reverses the order the buffers are listed in.
s Selects the order the buffers are listed in. Either by buffer
number, file name, file extension, most recently used (MRU), or
full path.
t Opens the buffer that is under the cursor in another tab.
u Toggles the showing of "unlisted" buffers.
Once invoked, Buffer Explorer displays a sorted list (MRU is the default
sort method) of all the buffers that are currently opened. You are then
able to move the cursor to the line containing the buffer's name you are
wanting to act upon. Once you have selected the buffer you would like,
you can then either open it, close it(delete), resort the list, reverse
the sort, quit exploring and so on...
===============================================================================
WINDOW LAYOUT *bufexplorer-windowlayout*
-------------------------------------------------------------------------------
" Press <F1> for Help
" Sorted by mru | Locate buffer | Absolute Split path
"=
01 %a bufexplorer.txt C:\Vim\vimfiles\doc line 87
02 # bufexplorer.vim c:\Vim\vimfiles\plugin line 1
-------------------------------------------------------------------------------
| | | | |
| | | | +-- Current Line #.
| | | +-- Relative/Full Path
| | +-- Buffer Name.
| +-- Buffer Attributes. See|:buffers|for more information.
+-- Buffer Number. See|:buffers|for more information.
===============================================================================
CUSTOMIZATION *bufexplorer-customization*
*g:bufExplorerChgWin*
If set, bufexplorer will bring up the selected buffer in the window specified
by g:bufExplorerChgWin.
*g:bufExplorerDefaultHelp*
To control whether the default help is displayed or not, use: >
let g:bufExplorerDefaultHelp=0 " Do not show default help.
let g:bufExplorerDefaultHelp=1 " Show default help.
The default is to show the default help.
*g:bufExplorerDetailedHelp*
To control whether detailed help is display by, use: >
let g:bufExplorerDetailedHelp=0 " Do not show detailed help.
let g:bufExplorerDetailedHelp=1 " Show detailed help.
The default is NOT to show detailed help.
*g:bufExplorerFindActive*
To control whether you are taken to the active window when selecting a buffer,
use: >
let g:bufExplorerFindActive=0 " Do not go to active window.
let g:bufExplorerFindActive=1 " Go to active window.
The default is to be taken to the active window.
*g:bufExplorerFuncRef*
When a buffer is selected, the functions specified either singly or as a list
will be called.
*g:bufExplorerReverseSort*
To control whether to sort the buffer in reverse order or not, use: >
let g:bufExplorerReverseSort=0 " Do not sort in reverse order.
let g:bufExplorerReverseSort=1 " Sort in reverse order.
The default is NOT to sort in reverse order.
*g:bufExplorerShowDirectories*
Directories usually show up in the list from using a command like ":e .".
To control whether to show directories in the buffer list or not, use: >
let g:bufExplorerShowDirectories=1 " Show directories.
let g:bufExplorerShowDirectories=0 " Don't show directories.
The default is to show directories.
*g:bufExplorerShowRelativePath*
To control whether to show absolute paths or relative to the current
directory, use: >
let g:bufExplorerShowRelativePath=0 " Show absolute paths.
let g:bufExplorerShowRelativePath=1 " Show relative paths.
The default is to show absolute paths.
*g:bufExplorerShowTabBuffer*
To control weither or not to show buffers on for the specific tab or not, use: >
let g:bufExplorerShowTabBuffer=0 " No.
let g:bufExplorerShowTabBuffer=1 " Yes.
The default is not to show.
*g:bufExplorerShowUnlisted*
To control whether to show unlisted buffer or not, use: >
let g:bufExplorerShowUnlisted=0 " Do not show unlisted buffers.
let g:bufExplorerShowUnlisted=1 " Show unlisted buffers.
The default is to NOT show unlisted buffers.
*g:bufExplorerSortBy*
To control what field the buffers are sorted by, use: >
let g:bufExplorerSortBy='extension' " Sort by file extension.
let g:bufExplorerSortBy='fullpath' " Sort by full file path name.
let g:bufExplorerSortBy='mru' " Sort by most recently used.
let g:bufExplorerSortBy='name' " Sort by the buffer's name.
let g:bufExplorerSortBy='number' " Sort by the buffer's number.
The default is to sort by mru.
*g:bufExplorerSplitBelow*
To control where the new split window will be placed above or below the
current window, use: >
let g:bufExplorerSplitBelow=1 " Split new window below current.
let g:bufExplorerSplitBelow=0 " Split new window above current.
The default is to use what ever is set by the global &splitbelow
variable.
*g:bufExplorerSplitOutPathName*
To control whether to split out the path and file name or not, use: >
let g:bufExplorerSplitOutPathName=1 " Split the path and file name.
let g:bufExplorerSplitOutPathName=0 " Don't split the path and file
" name.
The default is to split the path and file name.
*g:bufExplorerSplitRight*
To control where the new vsplit window will be placed to the left or right of
current window, use: >
let g:bufExplorerSplitRight=0 " Split left.
let g:bufExplorerSplitRight=1 " Split right.
The default is to use the global &splitright.
===============================================================================
CHANGE LOG *bufexplorer-changelog*
7.2.8 - Enhancements:
* Thanks to Charles Campbell for integrating bufexplorer with GDBMGR.
http://mysite.verizon.net/astronaut/vim/index.html#GDBMGR
7.2.7 - Fix:
* My 1st attempt to fix the "cache" issue where buffers information
has changed but the cache/display does not reflect those changes.
More work still needs to be done.
7.2.6 - Fix:
* Thanks to Michael Henry for pointing out that I totally forgot to
update the inline help to reflect the previous change to the 'd'
and 'D' keys. Opps!
7.2.5 - Fix:
* Philip Morant suggested switching the command (bwipe) associated
with the 'd' key with the command (bdelete) associated with the 'D'
key. This made sense since the 'd' key is more likely to be used
compared to the 'D' key.
7.2.4 - Fix:
* I did not implement the patch provided by Godefroid Chapelle
correctly. I missed one line which happened to be the most
important one :)
7.2.3 - Enhancements:
* Thanks to David Fishburn for helping me out with a much needed
code overhaul as well as some awesome performance enhancements.
He also reworked the handling of tabs.
* Thanks to Vladimir Dobriakov for making the suggestions on
enhancing the documentation to include a better explaination of
what is contained in the main bufexplorer window.
* Thanks to Yuriy Ershov for added code that when the bufexplorer
window is opened, the cursor is now positioned at the line with the
active buffer (useful in non-MRU sort modes).
* Yuriy also added the abiltiy to cycle through the sort fields in
reverse order.
Fixes:
* Thanks to Michael Henry for supplying a patch that allows
bufexplorer to be opened even when there is one buffer or less.
* Thanks to Godefroid Chapelle for supplying a patch that fixed
MRU sort order after loading a session.
7.2.2 - Fixes:
* Thanks to David L. Dight for spotting and fixing an issue when
using ctrl^. bufexplorer would incorrectly handle the previous
buffer so that when ctrl^ was pressed the incorrect file was opened.
7.2.1 - Fixes:
* Thanks to Dimitar for spotting and fixing a feature that was
inadvertently left out of the previous version. The feature was
when bufexplorer was used together with WinManager, you could use
the tab key to open a buffer in a split window.
7.2.0 - Enhancements:
* For all those missing the \bs and \bv commands, these have now
returned. Thanks to Phil O'Connell for asking for the return of
these missing features and helping test out this version.
Fixes:
* Fixed problem with the bufExplorerFindActive code not working
correctly.
* Fixed an incompatibility between bufexplorer and netrw that caused
buffers to be incorrectly removed from the MRU list.
7.1.7 - Fixes:
* TaCahiroy fixed several issues related to opening a buffer in a
tab.
7.1.6 - Fixes:
* Removed ff=unix from modeline in bufexplorer.txt. Found by Bill
McCarthy.
7.1.5 - Fixes:
* Could not open unnamed buffers. Fixed by TaCahiroy.
7.1.4 - Fixes:
* Sometimes when a file's path has 'white space' in it, extra buffers
would be created containing each piece of the path. i.e:
opening c:\document and settings\test.txt would create a buffer
named "and" and a buffer named "Documents". This was reported and
fixed by TaCa Yoss.
7.1.3 - Fixes:
* Added code to allow only one instance of the plugin to run at a
time. Thanks Dennis Hostetler.
7.1.2 - Fixes:
* Fixed a jumplist issue spotted by JiangJun. I overlooked the
'jumplist' and with a couple calls to 'keepjumps', everything is
fine again.
* Went back to just having a plugin file, no autoload file. By having
the autoload, WinManager was no longer working and without really
digging into the cause, it was easier to go back to using just a
plugin file.
7.1.1 - Fixes:
* A problem spotted by Thomas Arendsen Hein.
When running Vim (7.1.94), error E493 was being thrown.
Enhancements:
* Added 'D' for 'delete' buffer as the 'd' command was a 'wipe'
buffer.
7.1.0 - Another 'major' update, some by Dave Larson, some by me.
* Making use of 'autoload' now to make the plugin load quicker.
* Removed '\bs' and '\bv'. These are now controlled by the user. The
user can issue a ':sp' or ':vs' to create a horizontal or vertical
split window and then issue a '\be'
* Added handling of tabs.
7.0.17 - Fixed issue with 'drop' command.
Various enhancements and improvements.
7.0.16 - Fixed issue reported by Liu Jiaping on non Windows systems, which was
...
Open file1, open file2, modify file1, open bufexplorer, you get the
following error:
--------8<--------
Error detected while processing function
<SNR>14_StartBufExplorer..<SNR>14_SplitOpen:
line 4:
E37: No write since last change (add ! to override)
But the worse thing is, when I want to save the current buffer and
type ':w', I get another error message:
E382: Cannot write, 'buftype' option is set
--------8<--------
7.0.15 - Thanks to Mark Smithfield for suggesting bufexplorer needed to handle
the ':args' command.
7.0.14 - Thanks to Randall Hansen for removing the requirement of terminal
versions to be recompiled with 'gui' support so the 'drop' command
would work. The 'drop' command is really not needed in terminal
versions.
7.0.13 - Fixed integration with WinManager.
Thanks to Dave Eggum for another update.
- Fix: The detailed help didn't display the mapping for toggling
the split type, even though the split type is displayed.
- Fixed incorrect description in the detailed help for toggling
relative or full paths.
- Deprecated s:ExtractBufferNbr(). Vim's str2nr() does the same
thing.
- Created a s:Set() function that sets a variable only if it hasn't
already been defined. It's useful for initializing all those
default settings.
- Removed checks for repetitive command definitions. They were
unnecessary.
- Made the help highlighting a little more fancy.
- Minor reverse compatibility issue: Changed ambiguous setting
names to be more descriptive of what they do (also makes the code
easier to follow):
Changed bufExplorerSortDirection to bufExplorerReverseSort
Changed bufExplorerSplitType to bufExplorerSplitVertical
Changed bufExplorerOpenMode to bufExplorerUseCurrentWindow
- When the BufExplorer window closes, all the file-local marks are
now deleted. This may have the benefit of cleaning up some of the
jumplist.
- Changed the name of the parameter for StartBufExplorer from
"split" to "open". The parameter is a string which specifies how
the buffer will be open, not if it is split or not.
- Deprecated DoAnyMoreBuffersExist() - it is a one line function
only used in one spot.
- Created four functions (SplitOpen(), RebuildBufferList(),
UpdateHelpStatus() and ReSortListing()) all with one purpose - to
reduce repeated code.
- Changed the name of AddHeader() to CreateHelp() to be more
descriptive of what it does. It now returns an array instead of
updating the window directly. This has the benefit of making the
code more efficient since the text the function returns is used a
little differently in the two places the function is called.
- Other minor simplifications.
7.0.12 - MAJOR Update.
This version will ONLY run with Vim version 7.0 or greater.
Dave Eggum has made some 'significant' updates to this latest
version:
- Added BufExplorerGetAltBuf() global function to be used in the
users rulerformat.
- Added g:bufExplorerSplitRight option.
- Added g:bufExplorerShowRelativePath option with mapping.
- Added current line highlighting.
- The split type can now be changed whether bufexplorer is opened
in split mode or not.
- Various major and minor bug fixes and speed improvements.
- Sort by extension.
Other improvements/changes:
- Changed the help key from '?' to <F1> to be more 'standard'.
- Fixed splitting of vertical bufexplorer window.
Hopefully I have not forgot something :)
7.0.11 - Fixed a couple of highlighting bugs, reported by David Eggum. He also
changed passive voice to active on a couple of warning messages.
7.0.10 - Fixed bug report by Xiangjiang Ma. If the 'ssl' option is set,
the slash character used when displaying the path was incorrect.
7.0.9 - Martin Grenfell found and eliminated an annoying bug in the
bufexplorer/winmanager integration. The bug was were an
annoying message would be displayed when a window was split or
a new file was opened in a new window. Thanks Martin!
7.0.8 - Thanks to Mike Li for catching a bug in the WinManager integration.
The bug was related to the incorrect displaying of the buffer
explorer's window title.
7.0.7 - Thanks to Jeremy Cowgar for adding a new enhancement. This
enhancement allows the user to press 'S', that is capital S, which
will open the buffer under the cursor in a newly created split
window.
7.0.6 - Thanks to Larry Zhang for finding a bug in the "split" buffer code.
If you force set g:bufExplorerSplitType='v' in your vimrc, and if you
tried to do a \bs to split the bufexplorer window, it would always
split horizontal, not vertical. He also found that I had a typeo in
that the variable g:bufExplorerSplitVertSize was all lower case in
the documentation which was incorrect.
7.0.5 - Thanks to Mun Johl for pointing out a bug that if a buffer was
modified, the '+' was not showing up correctly.
7.0.4 - Fixed a problem discovered first by Xiangjiang Ma. Well since I've
been using vim 7.0 and not 6.3, I started using a function (getftype)
that is not in 6.3. So for backward compatibility, I conditionaly use
this function now. Thus, the g:bufExplorerShowDirectories feature is
only available when using vim 7.0 and above.
7.0.3 - Thanks to Erwin Waterlander for finding a problem when the last
buffer was deleted. This issue got me to rewrite the buffer display
logic (which I've wanted to do for sometime now).
Also great thanks to Dave Eggum for coming up with idea for
g:bufExplorerShowDirectories. Read the above information about this
feature.
7.0.2 - Thanks to Thomas Arendsen Hein for finding a problem when a user
has the default help turned off and then brought up the explorer. An
E493 would be displayed.
7.0.1 - Thanks to Erwin Waterlander for finding a couple problems.
The first problem allowed a modified buffer to be deleted. Opps! The
second problem occurred when several files were opened, BufExplorer
was started, the current buffer was deleted using the 'd' option, and
then BufExplorer was exited. The deleted buffer was still visible
while it is not in the buffers list. Opps again!
7.0.0 - Thanks to Shankar R. for suggesting to add the ability to set
the fixed width (g:bufExplorerSplitVertSize) of a new window
when opening bufexplorer vertically and fixed height
(g:bufExplorerSplitHorzSize) of a new window when opening
bufexplorer horizontally. By default, the windows are normally
split to use half the existing width or height.
6.3.0 - Added keepjumps so that the jumps list would not get cluttered with
bufexplorer related stuff.
6.2.3 - Thanks to Jay Logan for finding a bug in the vertical split position
of the code. When selecting that the window was to be split
vertically by doing a '\bv', from then on, all splits, i.e. '\bs',
were split vertically, even though g:bufExplorerSplitType was not set
to 'v'.
6.2.2 - Thanks to Patrik Modesto for adding a small improvement. For some
reason his bufexplorer window was always showing up folded. He added
'setlocal nofoldenable' and it was fixed.
6.2.1 - Thanks goes out to Takashi Matsuo for added the 'fullPath' sorting
logic and option.
6.2.0 - Thanks goes out to Simon Johann-Ganter for spotting and fixing a
problem in that the last search pattern is overridden by the search
pattern for blank lines.
6.1.6 - Thanks to Artem Chuprina for finding a pesky bug that has been around
for sometime now. The <esc> key mapping was causing the buffer
explored to close prematurely when vim was run in an xterm. The <esc>
key mapping is now removed.
6.1.5 - Thanks to Khorev Sergey. Added option to show default help or not.
6.1.4 - Thanks goes out to Valery Kondakoff for suggesting the addition of
setlocal nonumber and foldcolumn=0. This allows for line numbering
and folding to be turned off temporarily while in the explorer.
6.1.3 - Added folding. Did some code cleanup. Added the ability to force the
newly split window to be temporarily vertical, which was suggested by
Thomas Glanzmann.
6.1.2 - Now pressing the <esc> key will quit, just like 'q'.
Added folds to hide winmanager configuration.
If anyone had the 'C' option in their cpoptions they would receive
a E10 error on startup of BufExplorer. cpo is now saved, updated and
restored. Thanks to Charles E Campbell, Jr.
Attempted to make sure there can only be one BufExplorer window open
at a time.
6.1.1 - Thanks to Brian D. Goodwin for adding toupper to FileNameCmp. This
way buffers sorted by name will be in the correct order regardless of
case.
6.0.16 - Thanks to Andre Pang for the original patch/idea to get bufexplorer
to work in insertmode/modeless mode (evim). Added Initialize
and Cleanup autocommands to handle commands that need to be
performed when starting or leaving bufexplorer.
6.0.15 - Srinath Avadhanulax added a patch for winmanager.vim.
6.0.14 - Fix a few more bug that I thought I already had fixed. Thanks
to Eric Bloodworth for adding 'Open Mode/Edit in Place'. Added
vertical splitting.
6.0.13 - Thanks to Charles E Campbell, Jr. for pointing out some embarrassing
typos that I had in the documentation. I guess I need to run
the spell checker more :o)
6.0.12 - Thanks to Madoka Machitani, for the tip on adding the augroup command
around the MRUList autocommands.
6.0.11 - Fixed bug report by Xiangjiang Ma. '"=' was being added to the
search history which messed up hlsearch.
6.0.10 - Added the necessary hooks so that the Srinath Avadhanula's
winmanager.vim script could more easily integrate with this script.
Tried to improve performance.
6.0.9 - Added MRU (Most Recently Used) sort ordering.
6.0.8 - Was not resetting the showcmd command correctly.
Added nifty help file.
6.0.7 - Thanks to Brett Carlane for some great enhancements. Some are added,
some are not, yet. Added highlighting of current and alternate
filenames. Added splitting of path/filename toggle. Reworked
ShowBuffers().
Changed my email address.
6.0.6 - Copyright notice added. Needed this so that it could be distributed
with Debian Linux. Fixed problem with the SortListing() function
failing when there was only one buffer to display.
6.0.5 - Fixed problems reported by David Pascoe, in that you where unable to
hit 'd' on a buffer that belonged to a files that no longer existed
and that the 'yank' buffer was being overridden by the help text when
the bufexplorer was opened.
6.0.4 - Thanks to Charles Campbell, Jr. for making this plugin more plugin
*compliant*, adding default keymappings of <Leader>be and <Leader>bs
as well as fixing the 'w:sortDirLabel not being defined' bug.
6.0.3 - Added sorting capabilities. Sort taken from explorer.vim.
6.0.2 - Can't remember. (2001-07-25)
6.0.1 - Initial release.
===============================================================================
TODO *bufexplorer-todo*
- Nothing as of now, buf if you have any suggestions, drop me an email.
===============================================================================
CREDITS *bufexplorer-credits*
Author: Jeff Lanzarotta <delux256-vim at yahoo dot com>
Credit must go out to Bram Moolenaar and all the Vim developers for
making the world's best editor (IMHO). I also want to thank everyone who
helped and gave me suggestions. I wouldn't want to leave anyone out so I
won't list names.
===============================================================================
vim:tw=78:noet:wrap:ts=8:ft=help:norl:

File diff suppressed because it is too large Load Diff

View File

View File

@ -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*

View File

@ -0,0 +1 @@
doc/tags

View File

@ -0,0 +1,52 @@
# Introduction
EasyMotion provides a much simpler way to use some motions in vim. It
takes the `<number>` out of `<number>w` or `<number>f{char}` by
highlighting all possible choices and allowing you to press one key to
jump directly to the target.
When one of the available motions is triggered, all visible text
preceding or following the cursor is faded, and motion targets are
highlighted.
EasyMotion is triggered by one of the provided mappings.
# Important notes about the default bindings
**The default leader has been changed to `<Leader><Leader>` to avoid
conflicts with other plugins you may have installed.** This can easily be
changed back to pre-1.3 behavior by rebinding the leader in your vimrc:
let g:EasyMotion_leader_key = '<Leader>'
All motions are now triggered with `<Leader><Leader>` by default, e.g.
`<Leader><Leader>t`, `<Leader><Leader>gE`.
## Usage example
Type `<Leader><Leader>w` to trigger the word motion `w`. When the motion is
triggered, the text is updated (no braces are actually added, the text
is highlighted in red by default):
<cursor>Lorem {a}psum {b}olor {c}it {d}met.
Press `c` to jump to the beginning of the word "sit":
Lorem ipsum dolor <cursor>sit amet.
Similarly, if you're looking for an "o", you can use the `f` motion.
Type `<Leader><Leader>fo`, and all "o" characters are highlighted:
<cursor>L{a}rem ipsum d{b}l{c}r sit amet.
Press `b` to jump to the second "o":
Lorem ipsum d<cursor>olor sit amet.
Jeffrey Way of Nettuts+ has also [written
a tutorial](http://net.tutsplus.com/tutorials/other/vim-essential-plugin-easymotion/)
about EasyMotion.
## Animated demonstration
![Animated demonstration](http://oi54.tinypic.com/2yysefm.jpg)

View File

@ -0,0 +1,573 @@
" EasyMotion - Vim motions on speed!
"
" Author: Kim Silkebækken <kim.silkebaekken+vim@gmail.com>
" Source repository: https://github.com/Lokaltog/vim-easymotion
" Default configuration functions {{{
function! EasyMotion#InitOptions(options) " {{{
for [key, value] in items(a:options)
if ! exists('g:EasyMotion_' . key)
exec 'let g:EasyMotion_' . key . ' = ' . string(value)
endif
endfor
endfunction " }}}
function! EasyMotion#InitHL(group, colors) " {{{
let group_default = a:group . 'Default'
" Prepare highlighting variables
let guihl = printf('guibg=%s guifg=%s gui=%s', a:colors.gui[0], a:colors.gui[1], a:colors.gui[2])
if !exists('g:CSApprox_loaded')
let ctermhl = &t_Co == 256
\ ? printf('ctermbg=%s ctermfg=%s cterm=%s', a:colors.cterm256[0], a:colors.cterm256[1], a:colors.cterm256[2])
\ : printf('ctermbg=%s ctermfg=%s cterm=%s', a:colors.cterm[0], a:colors.cterm[1], a:colors.cterm[2])
else
let ctermhl = ''
endif
" Create default highlighting group
execute printf('hi default %s %s %s', group_default, guihl, ctermhl)
" Check if the hl group exists
if hlexists(a:group)
redir => hlstatus | exec 'silent hi ' . a:group | redir END
" Return if the group isn't cleared
if hlstatus !~ 'cleared'
return
endif
endif
" No colors are defined for this group, link to defaults
execute printf('hi default link %s %s', a:group, group_default)
endfunction " }}}
function! EasyMotion#InitMappings(motions) "{{{
for motion in keys(a:motions)
call EasyMotion#InitOptions({ 'mapping_' . motion : g:EasyMotion_leader_key . motion })
endfor
if g:EasyMotion_do_mapping
for [motion, fn] in items(a:motions)
if empty(g:EasyMotion_mapping_{motion})
continue
endif
silent exec 'nnoremap <silent> ' . g:EasyMotion_mapping_{motion} . ' :call EasyMotion#' . fn.name . '(0, ' . fn.dir . ')<CR>'
silent exec 'onoremap <silent> ' . g:EasyMotion_mapping_{motion} . ' :call EasyMotion#' . fn.name . '(0, ' . fn.dir . ')<CR>'
silent exec 'vnoremap <silent> ' . g:EasyMotion_mapping_{motion} . ' :<C-U>call EasyMotion#' . fn.name . '(1, ' . fn.dir . ')<CR>'
endfor
endif
endfunction "}}}
" }}}
" Motion functions {{{
function! EasyMotion#F(visualmode, direction) " {{{
let char = s:GetSearchChar(a:visualmode)
if empty(char)
return
endif
let re = '\C' . escape(char, '.$^~')
call s:EasyMotion(re, a:direction, a:visualmode ? visualmode() : '', mode(1))
endfunction " }}}
function! EasyMotion#T(visualmode, direction) " {{{
let char = s:GetSearchChar(a:visualmode)
if empty(char)
return
endif
if a:direction == 1
let re = '\C' . escape(char, '.$^~') . '\zs.'
else
let re = '\C.' . escape(char, '.$^~')
endif
call s:EasyMotion(re, a:direction, a:visualmode ? visualmode() : '', mode(1))
endfunction " }}}
function! EasyMotion#WB(visualmode, direction) " {{{
call s:EasyMotion('\(\<.\|^$\)', a:direction, a:visualmode ? visualmode() : '', '')
endfunction " }}}
function! EasyMotion#WBW(visualmode, direction) " {{{
call s:EasyMotion('\(\(^\|\s\)\@<=\S\|^$\)', a:direction, a:visualmode ? visualmode() : '', '')
endfunction " }}}
function! EasyMotion#E(visualmode, direction) " {{{
call s:EasyMotion('\(.\>\|^$\)', a:direction, a:visualmode ? visualmode() : '', mode(1))
endfunction " }}}
function! EasyMotion#EW(visualmode, direction) " {{{
call s:EasyMotion('\(\S\(\s\|$\)\|^$\)', a:direction, a:visualmode ? visualmode() : '', mode(1))
endfunction " }}}
function! EasyMotion#JK(visualmode, direction) " {{{
call s:EasyMotion('^\(\w\|\s*\zs\|$\)', a:direction, a:visualmode ? visualmode() : '', '')
endfunction " }}}
function! EasyMotion#Search(visualmode, direction) " {{{
call s:EasyMotion(@/, a:direction, a:visualmode ? visualmode() : '', '')
endfunction " }}}
" }}}
" Helper functions {{{
function! s:Message(message) " {{{
echo 'EasyMotion: ' . a:message
endfunction " }}}
function! s:Prompt(message) " {{{
echohl Question
echo a:message . ': '
echohl None
endfunction " }}}
function! s:VarReset(var, ...) " {{{
if ! exists('s:var_reset')
let s:var_reset = {}
endif
let buf = bufname("")
if a:0 == 0 && has_key(s:var_reset, a:var)
" Reset var to original value
call setbufvar(buf, a:var, s:var_reset[a:var])
elseif a:0 == 1
let new_value = a:0 == 1 ? a:1 : ''
" Store original value
let s:var_reset[a:var] = getbufvar(buf, a:var)
" Set new var value
call setbufvar(buf, a:var, new_value)
endif
endfunction " }}}
function! s:SetLines(lines, key) " {{{
try
" Try to join changes with previous undo block
undojoin
catch
endtry
for [line_num, line] in a:lines
call setline(line_num, line[a:key])
endfor
endfunction " }}}
function! s:GetChar() " {{{
let char = getchar()
if char == 27
" Escape key pressed
redraw
call s:Message('Cancelled')
return ''
endif
return nr2char(char)
endfunction " }}}
function! s:GetSearchChar(visualmode) " {{{
call s:Prompt('Search for character')
let char = s:GetChar()
" Check that we have an input char
if empty(char)
" Restore selection
if ! empty(a:visualmode)
silent exec 'normal! gv'
endif
return ''
endif
return char
endfunction " }}}
" }}}
" Grouping algorithms {{{
let s:grouping_algorithms = {
\ 1: 'SCTree'
\ , 2: 'Original'
\ }
" Single-key/closest target priority tree {{{
" This algorithm tries to assign one-key jumps to all the targets closest to the cursor.
" It works recursively and will work correctly with as few keys as two.
function! s:GroupingAlgorithmSCTree(targets, keys)
" Prepare variables for working
let targets_len = len(a:targets)
let keys_len = len(a:keys)
let groups = {}
let keys = reverse(copy(a:keys))
" Semi-recursively count targets {{{
" We need to know exactly how many child nodes (targets) this branch will have
" in order to pass the correct amount of targets to the recursive function.
" Prepare sorted target count list {{{
" This is horrible, I know. But dicts aren't sorted in vim, so we need to
" work around that. That is done by having one sorted list with key counts,
" and a dict which connects the key with the keys_count list.
let keys_count = []
let keys_count_keys = {}
let i = 0
for key in keys
call add(keys_count, 0)
let keys_count_keys[key] = i
let i += 1
endfor
" }}}
let targets_left = targets_len
let level = 0
let i = 0
while targets_left > 0
" Calculate the amount of child nodes based on the current level
let childs_len = (level == 0 ? 1 : (keys_len - 1) )
for key in keys
" Add child node count to the keys_count array
let keys_count[keys_count_keys[key]] += childs_len
" Subtract the child node count
let targets_left -= childs_len
if targets_left <= 0
" Subtract the targets left if we added too many too
" many child nodes to the key count
let keys_count[keys_count_keys[key]] += targets_left
break
endif
let i += 1
endfor
let level += 1
endwhile
" }}}
" Create group tree {{{
let i = 0
let key = 0
call reverse(keys_count)
for key_count in keys_count
if key_count > 1
" We need to create a subgroup
" Recurse one level deeper
let groups[a:keys[key]] = s:GroupingAlgorithmSCTree(a:targets[i : i + key_count - 1], a:keys)
elseif key_count == 1
" Assign single target key
let groups[a:keys[key]] = a:targets[i]
else
" No target
continue
endif
let key += 1
let i += key_count
endfor
" }}}
" Finally!
return groups
endfunction
" }}}
" Original {{{
function! s:GroupingAlgorithmOriginal(targets, keys)
" Split targets into groups (1 level)
let targets_len = len(a:targets)
let keys_len = len(a:keys)
let groups = {}
let i = 0
let root_group = 0
try
while root_group < targets_len
let groups[a:keys[root_group]] = {}
for key in a:keys
let groups[a:keys[root_group]][key] = a:targets[i]
let i += 1
endfor
let root_group += 1
endwhile
catch | endtry
" Flatten the group array
if len(groups) == 1
let groups = groups[a:keys[0]]
endif
return groups
endfunction
" }}}
" Coord/key dictionary creation {{{
function! s:CreateCoordKeyDict(groups, ...)
" Dict structure:
" 1,2 : a
" 2,3 : b
let sort_list = []
let coord_keys = {}
let group_key = a:0 == 1 ? a:1 : ''
for [key, item] in items(a:groups)
let key = ( ! empty(group_key) ? group_key : key)
if type(item) == 3
" Destination coords
" The key needs to be zero-padded in order to
" sort correctly
let dict_key = printf('%05d,%05d', item[0], item[1])
let coord_keys[dict_key] = key
" We need a sorting list to loop correctly in
" PromptUser, dicts are unsorted
call add(sort_list, dict_key)
else
" Item is a dict (has children)
let coord_key_dict = s:CreateCoordKeyDict(item, key)
" Make sure to extend both the sort list and the
" coord key dict
call extend(sort_list, coord_key_dict[0])
call extend(coord_keys, coord_key_dict[1])
endif
unlet item
endfor
return [sort_list, coord_keys]
endfunction
" }}}
" }}}
" Core functions {{{
function! s:PromptUser(groups) "{{{
" If only one possible match, jump directly to it {{{
let group_values = values(a:groups)
if len(group_values) == 1
redraw
return group_values[0]
endif
" }}}
" Prepare marker lines {{{
let lines = {}
let hl_coords = []
let coord_key_dict = s:CreateCoordKeyDict(a:groups)
for dict_key in sort(coord_key_dict[0])
let target_key = coord_key_dict[1][dict_key]
let [line_num, col_num] = split(dict_key, ',')
let line_num = str2nr(line_num)
let col_num = str2nr(col_num)
" Add original line and marker line
if ! has_key(lines, line_num)
let current_line = getline(line_num)
let lines[line_num] = { 'orig': current_line, 'marker': current_line, 'mb_compensation': 0 }
endif
" Compensate for byte difference between marker
" character and target character
"
" This has to be done in order to match the correct
" column; \%c matches the byte column and not display
" column.
let target_char_len = strlen(matchstr(lines[line_num]['marker'], '\%' . col_num . 'c.'))
let target_key_len = strlen(target_key)
" Solve multibyte issues by matching the byte column
" number instead of the visual column
let col_num -= lines[line_num]['mb_compensation']
if strlen(lines[line_num]['marker']) > 0
" Substitute marker character if line length > 0
let lines[line_num]['marker'] = substitute(lines[line_num]['marker'], '\%' . col_num . 'c.', target_key, '')
else
" Set the line to the marker character if the line is empty
let lines[line_num]['marker'] = target_key
endif
" Add highlighting coordinates
call add(hl_coords, '\%' . line_num . 'l\%' . col_num . 'c')
" Add marker/target lenght difference for multibyte
" compensation
let lines[line_num]['mb_compensation'] += (target_char_len - target_key_len)
endfor
let lines_items = items(lines)
" }}}
" Highlight targets {{{
let target_hl_id = matchadd(g:EasyMotion_hl_group_target, join(hl_coords, '\|'), 1)
" }}}
try
" Set lines with markers
call s:SetLines(lines_items, 'marker')
redraw
" Get target character {{{
call s:Prompt('Target key')
let char = s:GetChar()
" }}}
finally
" Restore original lines
call s:SetLines(lines_items, 'orig')
" Un-highlight targets {{{
if exists('target_hl_id')
call matchdelete(target_hl_id)
endif
" }}}
redraw
endtry
" Check if we have an input char {{{
if empty(char)
throw 'Cancelled'
endif
" }}}
" Check if the input char is valid {{{
if ! has_key(a:groups, char)
throw 'Invalid target'
endif
" }}}
let target = a:groups[char]
if type(target) == 3
" Return target coordinates
return target
else
" Prompt for new target character
return s:PromptUser(target)
endif
endfunction "}}}
function! s:EasyMotion(regexp, direction, visualmode, mode) " {{{
let orig_pos = [line('.'), col('.')]
let targets = []
try
" Reset properties {{{
call s:VarReset('&scrolloff', 0)
call s:VarReset('&modified', 0)
call s:VarReset('&modifiable', 1)
call s:VarReset('&readonly', 0)
call s:VarReset('&spell', 0)
call s:VarReset('&virtualedit', '')
" }}}
" Find motion targets {{{
let search_direction = (a:direction == 1 ? 'b' : '')
let search_stopline = line(a:direction == 1 ? 'w0' : 'w$')
while 1
let pos = searchpos(a:regexp, search_direction, search_stopline)
" Reached end of search range
if pos == [0, 0]
break
endif
" Skip folded lines
if foldclosed(pos[0]) != -1
continue
endif
call add(targets, pos)
endwhile
let targets_len = len(targets)
if targets_len == 0
throw 'No matches'
endif
" }}}
let GroupingFn = function('s:GroupingAlgorithm' . s:grouping_algorithms[g:EasyMotion_grouping])
let groups = GroupingFn(targets, split(g:EasyMotion_keys, '\zs'))
" Shade inactive source {{{
if g:EasyMotion_do_shade
let shade_hl_pos = '\%' . orig_pos[0] . 'l\%'. orig_pos[1] .'c'
if a:direction == 1
" Backward
let shade_hl_re = '\%'. line('w0') .'l\_.*' . shade_hl_pos
else
" Forward
let shade_hl_re = shade_hl_pos . '\_.*\%'. line('w$') .'l'
endif
let shade_hl_id = matchadd(g:EasyMotion_hl_group_shade, shade_hl_re, 0)
endif
" }}}
" Prompt user for target group/character
let coords = s:PromptUser(groups)
" Update selection {{{
if ! empty(a:visualmode)
keepjumps call cursor(orig_pos[0], orig_pos[1])
exec 'normal! ' . a:visualmode
endif
" }}}
" Handle operator-pending mode {{{
if a:mode == 'no'
" This mode requires that we eat one more
" character to the right if we're using
" a forward motion
if a:direction != 1
let coords[1] += 1
endif
endif
" }}}
" Update cursor position
call cursor(orig_pos[0], orig_pos[1])
mark '
call cursor(coords[0], coords[1])
call s:Message('Jumping to [' . coords[0] . ', ' . coords[1] . ']')
catch
redraw
" Show exception message
call s:Message(v:exception)
" Restore original cursor position/selection {{{
if ! empty(a:visualmode)
silent exec 'normal! gv'
else
keepjumps call cursor(orig_pos[0], orig_pos[1])
endif
" }}}
finally
" Restore properties {{{
call s:VarReset('&scrolloff')
call s:VarReset('&modified')
call s:VarReset('&modifiable')
call s:VarReset('&readonly')
call s:VarReset('&spell')
call s:VarReset('&virtualedit')
" }}}
" Remove shading {{{
if g:EasyMotion_do_shade && exists('shade_hl_id')
call matchdelete(shade_hl_id)
endif
" }}}
endtry
endfunction " }}}
" }}}
" vim: fdm=marker:noet:ts=4:sw=4:sts=4

View File

@ -0,0 +1,319 @@
*easymotion.txt* Version 1.3. Last change: 2011 Nov 7
______ __ ___ __ _
/ ____/____ ________ __/ |/ /____ / /_(_)____ ____
/ __/ / __ `/ ___/ / / / /|_/ // __ \/ __/ // __ \/ __ \
/ /___ / /_/ (__ ) /_/ / / / // /_/ / /_/ // /_/ / / / /
/_____/ \__,_/____/\__, /_/ /_/ \____/\__/_/ \____/_/ /_/
/____/
- Vim motions on speed!
==============================================================================
CONTENTS *easymotion-contents*
1. Introduction ....................... |easymotion-introduction|
2. Usage .............................. |easymotion-usage|
2.1 Default mappings ............... |easymotion-default-mappings|
3. Requirements ....................... |easymotion-requirements|
4. Configuration ...................... |easymotion-configuration|
4.1 EasyMotion_keys ................ |EasyMotion_keys|
4.2 EasyMotion_do_shade ............ |EasyMotion_do_shade|
4.3 EasyMotion_do_mapping .......... |EasyMotion_do_mapping|
4.4 EasyMotion_grouping ............ |EasyMotion_grouping|
4.5 Custom highlighting ............ |easymotion-custom-hl|
4.6 Custom mappings ................ |easymotion-custom-mappings|
4.6.1 Leader key ............... |easymotion-leader-key|
4.6.2 Custom keys .............. |easymotion-custom-keys|
5. License ............................ |easymotion-license|
6. Known bugs ......................... |easymotion-known-bugs|
7. Contributing ....................... |easymotion-contributing|
8. Credits ............................ |easymotion-credits|
==============================================================================
1. Introduction *easymotion* *easymotion-introduction*
EasyMotion provides a much simpler way to use some motions in vim. It takes
the <number> out of <number>w or <number>f{char} by highlighting all possible
choices and allowing you to press one key to jump directly to the target.
When one of the available motions is triggered, all visible text preceding or
following the cursor is faded, and motion targets are highlighted.
==============================================================================
2. Usage *easymotion-usage*
EasyMotion is triggered by one of the provided mappings (see
|easymotion-default-mappings| for details).
Example: >
<cursor>Lorem ipsum dolor sit amet.
Type <Leader><Leader>w to trigger the word motion |w|. See
|easymotion-leader-key| for details about the leader key. When the
motion is triggered, the text is updated (no braces are actually added,
the text is highlighted in red by default): >
<cursor>Lorem {a}psum {b}olor {c}it {d}met.
Press "c" to jump to the beginning of the word "sit": >
Lorem ipsum dolor <cursor>sit amet.
Similarly, if you're looking for an "o", you can use the |f| motion.
Type <Leader><Leader>fo, and all "o" characters are highlighted: >
<cursor>L{a}rem ipsum d{b}l{c}r sit amet.
Press "b" to jump to the second "o": >
Lorem ipsum d<cursor>olor sit amet.
And that's it!
------------------------------------------------------------------------------
2.1 Default mappings *easymotion-default-mappings*
The default configuration defines the following mappings in normal,
visual and operator-pending mode:
Mapping | Details
------------------|----------------------------------------------
<Leader>f{char} | Find {char} to the right. See |f|.
<Leader>F{char} | Find {char} to the left. See |F|.
<Leader>t{char} | Till before the {char} to the right. See |t|.
<Leader>T{char} | Till after the {char} to the left. See |T|.
<Leader>w | Beginning of word forward. See |w|.
<Leader>W | Beginning of WORD forward. See |W|.
<Leader>b | Beginning of word backward. See |b|.
<Leader>B | Beginning of WORD backward. See |B|.
<Leader>e | End of word forward. See |e|.
<Leader>E | End of WORD forward. See |E|.
<Leader>ge | End of word backward. See |ge|.
<Leader>gE | End of WORD backward. See |gE|.
<Leader>j | Line downward. See |j|.
<Leader>k | Line upward. See |k|.
<Leader>n | Jump to latest "/" or "?" forward. See |n|.
<Leader>N | Jump to latest "/" or "?" backward. See |N|.
See |easymotion-leader-key| and |mapleader| for details about the leader key.
See |easymotion-custom-mappings| for customizing the default mappings.
==============================================================================
3. Requirements *easymotion-requirements*
EasyMotion has been developed and tested in vim 7.3, but it should run without
any problems in vim 7.2.
Vi-compatible mode must be disabled.
==============================================================================
4. Configuration *easymotion-configuration*
EasyMotion will work fine without any configuration, but you can override the
default behavior by setting configuration variables globally in your |vimrc|
file.
Example (this will change the target keys and disable shading): >
let g:EasyMotion_keys = '1234567890'
let g:EasyMotion_do_shade = 0
------------------------------------------------------------------------------
4.1 EasyMotion_keys *EasyMotion_keys*
Set the keys which will be used for motion targets. Add as many keys as you
want. There's a lower chance that the motion targets will be grouped if many
keys are available.
Default: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
------------------------------------------------------------------------------
4.2 EasyMotion_do_shade *EasyMotion_do_shade*
The default behavior is to shade the text following the cursor (forward
motions) or preceding the cursor (backward motions) to make the motion targets
more visible. Set this option to 0 if you want to disable text shading.
Default: 1
------------------------------------------------------------------------------
4.3 EasyMotion_do_mapping *EasyMotion_do_mapping*
Set this option to 0 if you want to disable the default mappings. See
|easymotion-default-mappings| for details about the default mappings.
Note: If you disable this option, you'll have to map the motions yourself. See
the plugin source code for mapping details. You usually shouldn't need to do
this, see |easymotion-custom-mappings| for customizing the default mappings.
Default: 1
------------------------------------------------------------------------------
4.4 EasyMotion_grouping *EasyMotion_grouping*
When there are too many possible targets on the screen, the results have to be
grouped. This configuration option lets you change which grouping algorithm
you want to use. There are two grouping algorithms available:
* Single-key priority (value: 1)
-------------------
This algorithm prioritizes single-key jumps for the targets closest to
the cursor and only groups the last jump targets to maximize the amount
of single-key jumps.
This algorithm works recursively and will work with as few keys as two.
Example (with |EasyMotion_keys| = "abcdef"): >
x x x x x x x x x
<
The |w| motion is triggered: >
a b c d e f f f f
^ ^ ^ ^ ^ Direct jump to target
^ ^ ^ ^ Enter group "f"
<
* Original (value: 2)
--------
This is the original algorithm which always groups all targets if there
are too many possible motion targets.
Example (with |EasyMotion_keys| = "abcdef"): >
x x x x x x x x x
<
The |w| motion is triggered: >
a a a a a a b b b
^ ^ ^ ^ ^ ^ Enter group "a"
^ ^ ^ Enter group "b"
Default: 1
------------------------------------------------------------------------------
4.5 Custom highlighting *easymotion-custom-hl*
The default EasyMotion configuration uses two highlighting groups that link
to groups with default values. The highlighting groups are:
* EasyMotionTarget
Highlights motion targets, the default value is bold red
* EasyMotionShade
Highlights shaded text, the default value is dark gray
There are two ways to override the default colors:
1) Set the highlighting in your color scheme
This will only affect a single color scheme. The default red/gray colors
will be used if you change the color scheme to one that doesn't assign
any EasyMotion colors.
Example: >
hi EasyMotionTarget ctermbg=none ctermfg=green
hi EasyMotionShade ctermbg=none ctermfg=blue
<
2) Set the highlighting in your vimrc
This is ideal if you want to link the colors to highlighting groups that
are available in almost every color scheme, e.g. |ErrorMsg| (usually
bright red) and Comment (usually faded). You can be sure that the
color scheme's colors will be used instead of the default red/gray
if you choose this option.
Example: >
hi link EasyMotionTarget ErrorMsg
hi link EasyMotionShade Comment
<
------------------------------------------------------------------------------
4.6 Custom mappings *easymotion-custom-mappings*
EasyMotion allows you to customize all default mappings to avoid conflicts
with existing mappings. It is possible to change the default leader key
of all mappings to another key or sequence. It is also possible to fine
tune the plugin to your need by changing every single sequence.
4.6.1 Leader key *EasyMotion_leader_key* *easymotion-leader-key*
The default leader key can be changed with the configuration option
|EasyMotion_leader_key|.
Set this option to the key sequence to use as the prefix of the mappings
described in |easymotion-default-mappings|.
Note: The default leader key has been changed to '<Leader><Leader>' to
avoid conflicts with other plugins. You can revert to the original
leader by setting this option in your vimrc: >
let g:EasyMotion_leader_key = '<Leader>'
<
Default: '<Leader><Leader>'
4.6.2 Custom Keys *easymotion-custom-keys*
All custom mappings follow the same variable format: >
EasyMotion_mapping_{motion} = {mapping}
<
Example: >
let g:EasyMotion_mapping_f = '_f'
let g:EasyMotion_mapping_T = '<C-T>'
<
See |easymotion-default-mappings| for a table of motions that can be mapped
and their default values.
Note: The leader key defined by |EasyMotion_leader_key| is not prepended to
your customized mappings! You have to provide full key sequences when setting
these options.
==============================================================================
5. License *easymotion-license*
Creative Commons Attribution-ShareAlike 3.0 Unported
http://creativecommons.org/licenses/by-sa/3.0/
==============================================================================
6. Known bugs *easymotion-known-bugs*
None.
==============================================================================
7. Contributing *easymotion-contributing*
If you experience any bugs or have feature requests, please open an issue on
GitHub. Fork the source repository on GitHub and send a pull request if you
have any code improvements.
Author: Kim Silkebækken <kim.silkebaekken+vim@gmail.com>
Source repository: https://github.com/Lokaltog/vim-easymotion
==============================================================================
8. Credits *easymotion-credits*
- Ben Boeckel: ge and WORD motions
- Drew Neil: operator-pending mappings
- Rob O'Dwyer: customizable mappings without giving up all defaults
- Michel D'Hooge: customizable leader
- Maxime Bourget: search motion, improved JK motion behavior
- Kearn Holliday: fix jumplist issues
- Shougo Matsushita: fix CSApprox issue
EasyMotion is based on Bartlomiej Podolak's great PreciseJump script, which
can be downloaded here:
http://www.vim.org/scripts/script.php?script_id=3437
==============================================================================
vim:tw=78:sw=4:ts=8:ft=help:norl:

View File

@ -0,0 +1,73 @@
" EasyMotion - Vim motions on speed!
"
" Author: Kim Silkebækken <kim.silkebaekken+vim@gmail.com>
" Source repository: https://github.com/Lokaltog/vim-easymotion
" Script initialization {{{
if exists('g:EasyMotion_loaded') || &compatible || version < 702
finish
endif
let g:EasyMotion_loaded = 1
" }}}
" Default configuration {{{
" Default options {{{
call EasyMotion#InitOptions({
\ 'leader_key' : '<Leader><Leader>'
\ , 'keys' : 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
\ , 'do_shade' : 1
\ , 'do_mapping' : 1
\ , 'grouping' : 1
\
\ , 'hl_group_target' : 'EasyMotionTarget'
\ , 'hl_group_shade' : 'EasyMotionShade'
\ })
" }}}
" Default highlighting {{{
let s:target_hl_defaults = {
\ 'gui' : ['NONE', '#ff0000' , 'bold']
\ , 'cterm256': ['NONE', '196' , 'bold']
\ , 'cterm' : ['NONE', 'red' , 'bold']
\ }
let s:shade_hl_defaults = {
\ 'gui' : ['NONE', '#777777' , 'NONE']
\ , 'cterm256': ['NONE', '242' , 'NONE']
\ , 'cterm' : ['NONE', 'grey' , 'NONE']
\ }
call EasyMotion#InitHL(g:EasyMotion_hl_group_target, s:target_hl_defaults)
call EasyMotion#InitHL(g:EasyMotion_hl_group_shade, s:shade_hl_defaults)
" Reset highlighting after loading a new color scheme {{{
augroup EasyMotionInitHL
autocmd!
autocmd ColorScheme * call EasyMotion#InitHL(g:EasyMotion_hl_group_target, s:target_hl_defaults)
autocmd ColorScheme * call EasyMotion#InitHL(g:EasyMotion_hl_group_shade, s:shade_hl_defaults)
augroup end
" }}}
" }}}
" Default key mapping {{{
call EasyMotion#InitMappings({
\ 'f' : { 'name': 'F' , 'dir': 0 }
\ , 'F' : { 'name': 'F' , 'dir': 1 }
\ , 't' : { 'name': 'T' , 'dir': 0 }
\ , 'T' : { 'name': 'T' , 'dir': 1 }
\ , 'w' : { 'name': 'WB' , 'dir': 0 }
\ , 'W' : { 'name': 'WBW', 'dir': 0 }
\ , 'b' : { 'name': 'WB' , 'dir': 1 }
\ , 'B' : { 'name': 'WBW', 'dir': 1 }
\ , 'e' : { 'name': 'E' , 'dir': 0 }
\ , 'E' : { 'name': 'EW' , 'dir': 0 }
\ , 'ge': { 'name': 'E' , 'dir': 1 }
\ , 'gE': { 'name': 'EW' , 'dir': 1 }
\ , 'j' : { 'name': 'JK' , 'dir': 0 }
\ , 'k' : { 'name': 'JK' , 'dir': 1 }
\ , 'n' : { 'name': 'Search' , 'dir': 0 }
\ , 'N' : { 'name': 'Search' , 'dir': 1 }
\ })
" }}}
" }}}
" vim: fdm=marker:noet:ts=4:sw=4:sts=4

View File

@ -0,0 +1,19 @@
# vim-jade #
Vim syntax highlighting for Jade templates.
Installation
------------
I prefer to install plugins using Tim Pope's
[pathogen.vim](https://github.com/tpope/vim-pathogen). Installation using
pathogen is quite simple.
cd ~/.vim/bundle
git clone git://github.com/digitaltoad/vim-jade.git
If you do not want to use pathogen. You can always install vim-jade in the
normal manner by copying each directory to your ~/.vim directory. Make sure
not to overwrite any existing directory of the same name and instead copy only
the contents of the source directory to the directory of the same name in your
~/.vim directory.

View File

@ -0,0 +1,2 @@
" Jade
autocmd BufNewFile,BufReadPost *.jade set filetype=jade

View File

@ -0,0 +1,55 @@
" Vim filetype plugin
" Language: Jade
" Maintainer: Joshua Borton
" Credits: Tim Pope
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
finish
endif
let s:save_cpo = &cpo
set cpo-=C
" Define some defaults in case the included ftplugins don't set them.
let s:undo_ftplugin = ""
let s:browsefilter = "All Files (*.*)\t*.*\n"
let s:match_words = ""
runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim
unlet! b:did_ftplugin
" Override our defaults if these were set by an included ftplugin.
if exists("b:undo_ftplugin")
let s:undo_ftplugin = b:undo_ftplugin
unlet b:undo_ftplugin
endif
if exists("b:browsefilter")
let s:browsefilter = b:browsefilter
unlet b:browsefilter
endif
if exists("b:match_words")
let s:match_words = b:match_words
unlet b:match_words
endif
" Change the browse dialog on Win32 to show mainly Haml-related files
if has("gui_win32")
let b:browsefilter="Jade Files (*.jade)\t*.jade\n" . s:browsefilter
endif
" Load the combined list of match_words for matchit.vim
if exists("loaded_matchit")
let b:match_words = s:match_words
endif
setlocal comments=://-,:// commentstring=//\ %s
setlocal suffixesadd+=.jade
let b:undo_ftplugin = "setl cms< com< "
\ " | unlet! b:browsefilter b:match_words | " . s:undo_ftplugin
let &cpo = s:save_cpo
" vim:set sw=2:

View File

@ -0,0 +1,70 @@
" Vim indent file
" Language: Jade
" Maintainer: Joshua Borton
" Credits: Tim Pope (vim-jade)
" Last Change: 2010 Sep 22
if exists("b:did_indent")
finish
endif
unlet! b:did_indent
let b:did_indent = 1
setlocal autoindent
setlocal indentexpr=GetJadeIndent()
setlocal indentkeys=o,O,*<Return>,},],0),!^F
" Only define the function once.
if exists("*GetJadeIndent")
finish
endif
let s:attributes = '\%((.\{-\})\)'
let s:tag = '\([%.#][[:alnum:]_-]\+\|'.s:attributes.'\)*[<>]*'
if !exists('g:jade_self_closing_tags')
let g:jade_self_closing_tags = 'meta|link|img|hr|br|input'
endif
setlocal formatoptions+=r
setlocal comments+=n:\|
function! GetJadeIndent()
let lnum = prevnonblank(v:lnum-1)
if lnum == 0
return 0
endif
let line = substitute(getline(lnum),'\s\+$','','')
let cline = substitute(substitute(getline(v:lnum),'\s\+$','',''),'^\s\+','','')
let lastcol = strlen(line)
let line = substitute(line,'^\s\+','','')
let indent = indent(lnum)
let cindent = indent(v:lnum)
let increase = indent + &sw
if indent == indent(lnum)
let indent = cindent <= indent ? -1 : increase
endif
let group = synIDattr(synID(lnum,lastcol,1),'name')
if line =~ '^!!!'
return indent
elseif line =~ '^/\%(\[[^]]*\]\)\=$'
return increase
elseif line =~ '^\%(if\|else\|unless\|for\|each\|block\|mixin\|append\|case\|when\)'
return increase
elseif line =~ '^'.s:tag.'[&!]\=[=~-].*,\s*$'
return increase
elseif line == '-#'
return increase
elseif line =~? '^\v%('.g:jade_self_closing_tags.')>'
return indent
elseif group =~? '\v^%(jadeAttributesDelimiter|jadeClass|jadeId|htmlTagName|htmlSpecialTagName|jadeFilter)$'
return increase
else
return indent
endif
endfunction
" vim:set sw=2:

View File

@ -0,0 +1,87 @@
" Vim syntax file
" Language: Jade
" Maintainer: Joshua Borton
" Credits: Tim Pope
" Filenames: *.jade
if exists("b:current_syntax")
finish
endif
if !exists("main_syntax")
let main_syntax = 'jade'
endif
silent! syntax include @htmlCoffeescript syntax/coffee.vim
unlet! b:current_syntax
silent! syntax include @htmlStylus syntax/stylus.vim
unlet! b:current_syntax
silent! syntax include @htmlMarkdown syntax/markdown.vim
unlet! b:current_syntax
syn case match
syn region javascriptParenthesisBlock start="(" end=")" contains=@htmlJavascript contained keepend
syn cluster htmlJavascript add=javascriptParenthesisBlock
syn region jadeJavascript matchgroup=jadeJavascriptOutputChar start="[!&]\==\|\~" skip=",\s*$" end="$" contained contains=@htmlJavascript keepend
syn region jadeJavascript matchgroup=jadeJavascriptChar start="-" skip=",\s*$" end="$" contained contains=@htmlJavascript keepend
syn cluster jadeTop contains=jadeBegin,jadeComment,jadeHtmlComment,jadeJavascript
syn match jadeBegin "^\s*\%([<>]\|&[^=~ ]\)\@!" nextgroup=jadeTag,jadeClassChar,jadeIdChar,jadePlainChar,jadeJavascript,jadeScriptConditional,jadeScriptStatement
syn match jadeTag "+\?\w\+\%(:\w\+\)\=" contained contains=htmlTagName,htmlSpecialTagName nextgroup=@jadeComponent
syn cluster jadeComponent contains=jadeAttributes,jadeIdChar,jadeBlockExpansionChar,jadeClassChar,jadePlainChar,jadeJavascript
syn match jadeComment '\s*\/\/.*$'
syn region jadeHtmlComment start="^\z(\s*\)/" end="^\%(\z1\s\|\s*$\)\@!"
syn region jadeAttributes matchgroup=jadeAttributesDelimiter start="(" end=")" contained contains=@htmlJavascript,jadeHtmlArg,htmlArg,htmlEvent,htmlCssDefinition nextgroup=@jadeComponent
syn match jadeClassChar "\." contained nextgroup=jadeClass
syn match jadeBlockExpansionChar ":\s" contained nextgroup=jadeTag
syn match jadeIdChar "#{\@!" contained nextgroup=jadeId
syn match jadeClass "\%(\w\|-\)\+" contained nextgroup=@jadeComponent
syn match jadeId "\%(\w\|-\)\+" contained nextgroup=@jadeComponent
syn region jadeDocType start="^\s*\(!!!\|doctype\)" end="$"
" Unless I'm mistaken, syntax/html.vim requires
" that the = sign be present for these matches.
" This adds the matches back for jade.
syn keyword jadeHtmlArg contained href title
syn match jadePlainChar "\\" contained
syn region jadeInterpolation matchgroup=jadeInterpolationDelimiter start="#{" end="}" contains=@htmlJavascript
syn match jadeInterpolationEscape "\\\@<!\%(\\\\\)*\\\%(\\\ze#{\|#\ze{\)"
syn region jadeJavascriptFilter matchgroup=jadeFilter start="^\z(\s*\):javascript\s*$" end="^\%(\z1\s\|\s*$\)\@!" contains=@htmlJavascript
syn region jadeCoffeescriptFilter matchgroup=jadeFilter start="^\z(\s*\):coffeescript\s*$" end="^\%(\z1\s\|\s*$\)\@!" contains=@htmlCoffeescript
syn region jadeMarkdownFilter matchgroup=jadeFilter start=/^\z(\s*\):markdown\s*$/ end=/^\%(\z1\s\|\s*$\)\@!/ contains=@htmlMarkdown
syn region jadeStylusFilter matchgroup=jadeFilter start="^\z(\s*\):stylus\s*$" end="^\%(\z1\s\|\s*$\)\@!" contains=@htmlStylus
syn region jadePlainFilter matchgroup=jadeFilter start="^\z(\s*\):\%(sass\|less\|cdata\)\s*$" end="^\%(\z1\s\|\s*$\)\@!"
syn match jadeScriptConditional "\<\%(if\|else\|unless\|while\|for\|until\|case\|when\|default\)\>[?!]\@!"
syn match jadeScriptStatement "\<\%(each\|block\|prepend\|append\|mixin\|extends\|include\)\>[?!]\@!"
syn region jadeJavascript start="^\z(\s*\)script\%(:\w\+\)\=" end="^\%(\z1\s\|\s*$\)\@!" contains=@htmlJavascript,jadeJavascriptTag keepend
syn region jadeJavascriptTag contained start="^\z(\s*\)script\%(:\w\+\)\=" end="$" contains=jadeBegin,jadeTag
syn region jadeCssBlock start="^\z(\s*\)style" nextgroup=@jadeComponent,jadeError end="^\%(\z1\s\|\s*$\)\@!" contains=@jadeTop,@htmlCss keepend
syn match jadeError "\$" contained
hi def link jadePlainChar Special
hi def link jadeScriptConditional PreProc
hi def link jadeScriptStatement PreProc
hi def link jadeHtmlArg htmlArg
hi def link jadeAttributeString String
hi def link jadeAttributesDelimiter Identifier
hi def link jadeIdChar Special
hi def link jadeClassChar Special
hi def link jadeBlockExpansionChar Special
hi def link jadeId Identifier
hi def link jadeClass Type
hi def link jadeInterpolationDelimiter Delimiter
hi def link jadeFilter PreProc
hi def link jadeDocType PreProc
hi def link jadeComment Comment
hi def link jadeHtmlComment jadeComment
let b:current_syntax = "jade"
if main_syntax == "jade"
unlet main_syntax
endif

View File

@ -0,0 +1,22 @@
# marked.vim
Open the current Markdown buffer in [Marked.app](http://markedapp.com/).
## Usage
This plugin adds the following commands to Markdown buffers:
:MarkedOpen[!] Open the current Markdown buffer in Marked.app.
Call with a bang to prevent Marked.app from stealing
focus from Vim.
:MarkedQuit Close the current Markdown buffer in Marked.app.
Quit Marked.app if no other documents are open.
If you run `:MarkedOpen`, the document in Marked.app will be automatically
closed when Vim exists, and Marked.app will quit if no other documents are
open.
## License
Same as Vim itself, see `:help license`.

View File

@ -0,0 +1,55 @@
" marked.vim
" Author: Joshua Priddle <jpriddle@me.com>
" URL: https://github.com/itspriddle/vim-marked
" Version: 0.4.0
" License: Same as Vim itself (see :help license)
if &cp || exists("g:marked_loaded") && g:marked_loaded
finish
endif
let g:marked_loaded = 1
let s:save_cpo = &cpo
set cpo&vim
function s:OpenMarked(background)
let l:filename = expand("%:p")
silent exe "!open -a Marked.app ".(a:background ? '-g' : '')." '".l:filename."'"
silent exe "augroup marked_autoclose_".l:filename
autocmd!
silent exe 'autocmd VimLeavePre * call s:QuitMarked("'.l:filename.'")'
augroup END
redraw!
endfunction
function s:QuitMarked(path)
silent exe "augroup marked_autoclose_".a:path
autocmd!
augroup END
silent exe "augroup! marked_autoclose_".a:path
let cmd = " -e 'try'"
let cmd .= " -e 'if application \"Marked\" is running then'"
let cmd .= " -e 'tell application \"Marked\"'"
let cmd .= " -e 'close (first document whose path is equal to \"".a:path."\")'"
let cmd .= " -e 'if count of every window is equal to 0 then'"
let cmd .= " -e 'quit'"
let cmd .= " -e 'end if'"
let cmd .= " -e 'end tell'"
let cmd .= " -e 'end if'"
let cmd .= " -e 'end try'"
silent exe "!osascript ".cmd
redraw!
endfunction
augroup marked_commands
autocmd!
autocmd FileType markdown,mkd command! -buffer -bang MarkedOpen :call s:OpenMarked(<bang>0)
autocmd FileType markdown,mkd command! -buffer MarkedQuit :call s:QuitMarked(expand('%:p'))
augroup END
let &cpo = s:save_cpo
unlet s:save_cpo
" vim:ft=vim:fdm=marker:ts=2:sw=2:sts=2:et

View File

@ -0,0 +1 @@
doc/tags

View File

@ -0,0 +1,672 @@
# Miscellaneous auto-load Vim scripts
The vim-misc plug-in contains Vim scripts that are used by most of the [Vim
plug-ins I've written] [plugins] yet don't really belong with any single one of
the plug-ins. Basically it's an extended standard library of Vim script
functions that I wrote during the development of my Vim profile and plug-ins.
In the past these scripts were bundled with each plug-in, however that turned
out to be a maintenance nightmare for me. That's why the miscellaneous scripts
are now a proper plug-in with their own page on Vim Online.
Because the miscellaneous scripts are no longer bundled with my Vim plug-ins,
users are now required to install the miscellaneous scripts separately. This is
unfortunate for users who are upgrading from a previous release that did bundle
the miscellaneous scripts, but I don't see any way around this. Sorry!
## Installation
Unzip the most recent [ZIP archive] [] file inside your Vim profile
directory (usually this is `~/.vim` on UNIX and `%USERPROFILE%\vimfiles` on
Windows), restart Vim and execute the command `:helptags ~/.vim/doc` (use
`:helptags ~\vimfiles\doc` instead on Windows).
If you prefer you can also use [Pathogen] [], [Vundle] [] or a similar tool to
install & update the plug-in using a local clone of the git repository.
## Function documentation
Below is the documentation for the functions included in the miscellaneous
scripts. Anyone is free to use these functions in their own Vim profile and/or
plug-ins. I care about backwards compatibility so won't break it without a good
reason to do so.
For those who are curious: The function descriptions given below were extracted
from the source code of the miscellaneous scripts using the Python module
`vimdoctool.py` included in [vim-tools] [].
<!-- Start of generated documentation -->
The documentation of the 80 functions below was extracted from
15 Vim scripts on July 20, 2013 at 10:41.
### Handling of special buffers
The functions defined here make it easier to deal with special Vim buffers
that contain text generated by a Vim plug-in. For example my [vim-notes
plug-in] [vim-notes] generates several such buffers:
- [:RecentNotes] [RecentNotes] lists recently modified notes
- [:ShowTaggedNotes] [ShowTaggedNotes] lists notes grouped by tags
- etc.
Because the text in these buffers is generated, Vim shouldn't bother with
swap files and it should never prompt the user whether to save changes to
the generated text.
[vim-notes]: http://peterodding.com/code/vim/notes/
[RecentNotes]: http://peterodding.com/code/vim/notes/#recentnotes_command
[ShowTaggedNotes]: http://peterodding.com/code/vim/notes/#showtaggednotes_command
#### The `xolox#misc#buffer#is_empty()` function
Checks if the current buffer is an empty, unchanged buffer which can be
reused. Returns 1 if an empty buffer is found, 0 otherwise.
#### The `xolox#misc#buffer#prepare()` function
Open a special buffer, i.e. a buffer that will hold generated contents,
not directly edited by the user. The buffer can be customized by passing a
dictionary with the following key/value pairs as the first argument:
- **name** (required): The base name of the buffer (i.e. the base name of
the file loaded in the buffer, even though it isn't really a file and
nothing is really 'loaded' :-)
- **path** (required): The pathname of the buffer. May be relevant if
[:lcd] [lcd] or ['autochdir'] [acd] is being used.
[lcd]: http://vimdoc.sourceforge.net/htmldoc/editing.html#:lcd
[acd]: http://vimdoc.sourceforge.net/htmldoc/options.html#'autochdir'
#### The `xolox#misc#buffer#lock()` function
Lock a special buffer so that its contents can no longer be edited.
#### The `xolox#misc#buffer#unlock()` function
Unlock a special buffer so that its content can be updated.
### Tab completion for user defined commands
#### The `xolox#misc#complete#keywords()` function
This function can be used to perform keyword completion for user defined
Vim commands based on the contents of the current buffer. Here's an
example of how you would use it:
:command -nargs=* -complete=customlist,xolox#misc#complete#keywords MyCmd call s:MyCmd(<f-args>)
### String escaping functions
#### The `xolox#misc#escape#pattern()` function
Takes a single string argument and converts it into a [:substitute]
[subcmd] / [substitute()] [subfun] pattern string that matches the given
string literally.
[subfun]: http://vimdoc.sourceforge.net/htmldoc/eval.html#substitute()
[subcmd]: http://vimdoc.sourceforge.net/htmldoc/change.html#:substitute
#### The `xolox#misc#escape#substitute()` function
Takes a single string argument and converts it into a [:substitute]
[subcmd] / [substitute()] [subfun] replacement string that inserts the
given string literally.
#### The `xolox#misc#escape#shell()` function
Takes a single string argument and converts it into a quoted command line
argument.
I was going to add a long rant here about Vim's ['shellslash' option]
[shellslash], but really, it won't make any difference. Let's just suffice
to say that I have yet to encounter a single person out there who uses
this option for its intended purpose (running a UNIX style shell on
Microsoft Windows).
[shellslash]: http://vimdoc.sourceforge.net/htmldoc/options.html#'shellslash'
### Human friendly string formatting for Vim
#### The `xolox#misc#format#pluralize()` function
Concatenate a counter (the first argument, expected to be an integer) with
a singular or plural label (the second and third arguments, both expected
to be strings).
#### The `xolox#misc#format#timestamp()` function
Format a time stamp (a string containing a formatted floating point
number) into a human friendly format, for example 70 seconds is phrased as
"1 minute and 10 seconds".
### List handling functions
#### The `xolox#misc#list#unique()` function
Remove duplicate values from the given list in-place (preserves order).
#### The `xolox#misc#list#binsert()` function
Performs in-place binary insertion, which depending on your use case can
be more efficient than calling Vim's [sort()] [sort] function after each
insertion (in cases where a single, final sort is not an option). Expects
three arguments:
1. A list
2. A value to insert
3. 1 (true) when case should be ignored, 0 (false) otherwise
[sort]: http://vimdoc.sourceforge.net/htmldoc/eval.html#sort()
### Functions to interact with the user
#### The `xolox#misc#msg#info()` function
Show a formatted informational message to the user.
This function has the same argument handling as Vim's [printf()] []
function with one notable difference: Any arguments which are not numbers
or strings are coerced to strings using Vim's [string()] [] function.
In the case of `xolox#misc#msg#info()`, automatic string coercion simply
makes the function a bit easier to use.
[printf()]: http://vimdoc.sourceforge.net/htmldoc/eval.html#printf()
[string()]: http://vimdoc.sourceforge.net/htmldoc/eval.html#string()
#### The `xolox#misc#msg#warn()` function
Show a formatted warning message to the user.
This function has the same argument handling as the
`xolox#misc#msg#info()` function.
#### The `xolox#misc#msg#debug()` function
Show a formatted debugging message to the user, *if the user has enabled
increased verbosity by setting Vim's ['verbose'] [] option to one
(1) or higher*.
This function has the same argument handling as the
`xolox#misc#msg#info()` function.
In the case of `xolox#misc#msg#debug()`, automatic string coercion
provides lazy evaluation in the sense that complex data structures are
only converted to strings when the user has enabled increased verbosity.
['verbose']: http://vimdoc.sourceforge.net/htmldoc/options.html#'verbose'
### Integration between Vim and its environment
#### The `xolox#misc#open#file()` function
Given a pathname or URL as the first argument, this opens the file with
the program associated with the file type. So for example a text file
might open in Vim, an `*.html` file would probably open in your web
browser and a media file would open in a media player.
This should work on Windows, Mac OS X and most Linux distributions. If
this fails to find a file association, you can pass one or more external
commands to try as additional arguments. For example:
:call xolox#misc#open#file('/path/to/my/file', 'firefox', 'google-chrome')
This generally shouldn't be necessary but it might come in handy now and
then.
#### The `xolox#misc#open#url()` function
Given a URL as the first argument, this opens the URL in your preferred or
best available web browser:
- In GUI environments a graphical web browser will open (or a new tab will
be created in an existing window)
- In console Vim without a GUI environment, when you have any of `lynx`,
`links` or `w3m` installed it will launch a command line web browser in
front of Vim (temporarily suspending Vim)
### Vim and plug-in option handling
#### The `xolox#misc#option#get()` function
Expects one or two arguments: 1. The name of a variable and 2. the default
value if the variable does not exist.
Returns the value of the variable from a buffer local variable, global
variable or the default value, depending on which is defined.
This is used by some of my Vim plug-ins for option handling, so that users
can customize options for specific buffers.
#### The `xolox#misc#option#split()` function
Given a multi-value Vim option like ['runtimepath'] [rtp] this returns a
list of strings. For example:
:echo xolox#misc#option#split(&runtimepath)
['/home/peter/Projects/Vim/misc',
'/home/peter/Projects/Vim/colorscheme-switcher',
'/home/peter/Projects/Vim/easytags',
...]
[rtp]: http://vimdoc.sourceforge.net/htmldoc/options.html#'runtimepath'
#### The `xolox#misc#option#join()` function
Given a list of strings like the ones returned by
`xolox#misc#option#split()`, this joins the strings together into a
single value that can be used to set a Vim option.
#### The `xolox#misc#option#split_tags()` function
Customized version of `xolox#misc#option#split()` with specialized
handling for Vim's ['tags' option] [tags].
[tags]: http://vimdoc.sourceforge.net/htmldoc/options.html#'tags'
#### The `xolox#misc#option#join_tags()` function
Customized version of `xolox#misc#option#join()` with specialized
handling for Vim's ['tags' option] [tags].
#### The `xolox#misc#option#eval_tags()` function
Evaluate Vim's ['tags' option] [tags] without looking at the file
system, i.e. this will report tags files that don't exist yet. Expects
the value of the ['tags' option] [tags] as the first argument. If the
optional second argument is 1 (true) only the first match is returned,
otherwise (so by default) a list with all matches is returned.
### Operating system interfaces
#### The `xolox#misc#os#is_mac()` function
Returns 1 (true) when on Mac OS X, 0 (false) otherwise. You would expect
this to simply check the Vim feature list, but for some obscure reason the
`/usr/bin/vim` included in Mac OS X (verified on version 10.7.5) returns 0
(false) in response to `has('mac')`, so we check the output of `uname`
to avoid false negatives.
#### The `xolox#misc#os#is_win()` function
Returns 1 (true) when on Microsoft Windows, 0 (false) otherwise.
#### The `xolox#misc#os#find_vim()` function
Returns the program name of Vim as a string. On Windows and UNIX this just
[v:progname] [] as an absolute pathname while on Mac OS X there is
some special magic to find MacVim's executable even though it's usually
not on the executable search path. If you want, you can override the
value returned from this function by setting the global variable
`g:xolox#misc#os#vim_progname`.
By default the choice of console Vim vs graphical Vim is made based on
the value of [v:progname] [], but if you have a preference you can pass
the string `vim` or `gvim` as the first and only argument.
[v:progname]: http://vimdoc.sourceforge.net/htmldoc/eval.html#v:progname
#### The `xolox#misc#os#exec()` function
Execute an external command (hiding the console on Microsoft Windows when
my [vim-shell plug-in] [vim-shell] is installed).
Expects a dictionary with the following key/value pairs as the first
argument:
- **command** (required): The command line to execute
- **async** (optional): set this to 1 (true) to execute the command in the
background (asynchronously)
- **stdin** (optional): a string or list of strings with the input for the
external command
- **check** (optional): set this to 0 (false) to disable checking of the
exit code of the external command (by default an exception will be
raised when the command fails)
Returns a dictionary with one or more of the following key/value pairs:
- **command** (always available): the generated command line that was used
to run the external command
- **exit_code** (only in synchronous mode): the exit status of the
external command (an integer, zero on success)
- **stdout** (only in synchronous mode): the output of the command on the
standard output stream (a list of strings, one for each line)
- **stderr** (only in synchronous mode): the output of the command on the
standard error stream (as a list of strings, one for each line)
[vim-shell]: http://peterodding.com/code/vim/shell/
#### The `xolox#misc#os#can_use_dll()` function
If a) we're on Microsoft Windows, b) the vim-shell plug-in is installed
and c) the compiled DLL included in vim-shell works, we can use the
vim-shell plug-in to execute external commands! Returns 1 (true)
if we can use the DLL, 0 (false) otherwise.
### Pathname manipulation functions
#### The `xolox#misc#path#which()` function
Scan the executable search path (`$PATH`) for one or more external
programs. Expects one or more string arguments with program names. Returns
a list with the absolute pathnames of all found programs. Here's an
example:
:echo xolox#misc#path#which('gvim', 'vim')
['/usr/local/bin/gvim',
'/usr/bin/gvim',
'/usr/local/bin/vim',
'/usr/bin/vim']
#### The `xolox#misc#path#split()` function
Split a pathname (the first and only argument) into a list of pathname
components.
On Windows, pathnames starting with two slashes or backslashes are UNC
paths where the leading slashes are significant... In this case we split
like this:
- Input: `'//server/share/directory'`
- Result: `['//server', 'share', 'directory']`
Everything except Windows is treated like UNIX until someone has a better
suggestion :-). In this case we split like this:
- Input: `'/foo/bar/baz'`
- Result: `['/', 'foo', 'bar', 'baz']`
To join a list of pathname components back into a single pathname string,
use the `xolox#misc#path#join()` function.
#### The `xolox#misc#path#join()` function
Join a list of pathname components (the first and only argument) into a
single pathname string. This is the counterpart to the
`xolox#misc#path#split()` function and it expects a list of pathname
components as returned by `xolox#misc#path#split()`.
#### The `xolox#misc#path#directory_separator()` function
Find the preferred directory separator for the platform and settings.
#### The `xolox#misc#path#absolute()` function
Canonicalize and resolve a pathname, *regardless of whether it exists*.
This is intended to support string comparison to determine whether two
pathnames point to the same directory or file.
#### The `xolox#misc#path#relative()` function
Make an absolute pathname (the first argument) relative to a directory
(the second argument).
#### The `xolox#misc#path#merge()` function
Join a directory pathname and filename into a single pathname.
#### The `xolox#misc#path#commonprefix()` function
Find the common prefix of path components in a list of pathnames.
#### The `xolox#misc#path#encode()` function
Encode a pathname so it can be used as a filename. This uses URL encoding
to encode special characters.
#### The `xolox#misc#path#decode()` function
Decode a pathname previously encoded with `xolox#misc#path#encode()`.
#### The `xolox#misc#path#is_relative()` function
Returns true (1) when the pathname given as the first argument is
relative, false (0) otherwise.
#### The `xolox#misc#path#tempdir()` function
Create a temporary directory and return the pathname of the directory.
### String handling
#### The `xolox#misc#str#slug()` function
Convert a string to a "slug" - something that can be safely used in
filenames and URLs without worrying about quoting/escaping of special
characters.
#### The `xolox#misc#str#ucfirst()` function
Uppercase the first character in a string (the first argument).
#### The `xolox#misc#str#compact()` function
Compact whitespace in a string (the first argument).
#### The `xolox#misc#str#trim()` function
Trim all whitespace from the start and end of a string (the first
argument).
#### The `xolox#misc#str#indent()` function
Indent all lines in a multi-line string (the first argument) with a
specific number of *space characters* (the second argument, an integer).
#### The `xolox#misc#str#dedent()` function
Remove common whitespace from a multi line string.
### Test runner & infrastructure for Vim plug-ins
The Vim auto-load script `autoload/xolox/misc/test.vim` contains
infrastructure that can be used to run an automated Vim plug-in test suite.
It provides a framework for running test functions, keeping track of the
test status, making assertions and reporting test results to the user.
#### The `xolox#misc#test#reset()` function
Reset counters for executed tests and passed/failed assertions.
#### The `xolox#misc#test#summarize()` function
Print a summary of test results, to be interpreted interactively.
#### The `xolox#misc#test#wrap()` function
Call a function in a try/catch block and prevent exceptions from bubbling.
The name of the function should be passed as the first and only argument;
it should be a string containing the name of a Vim auto-load function.
#### The `xolox#misc#test#passed()` function
Record a test which succeeded.
#### The `xolox#misc#test#failed()` function
Record a test which failed.
#### The `xolox#misc#test#assert_true()` function
Check whether an expression is true.
#### The `xolox#misc#test#assert_equals()` function
Check whether two values are the same.
#### The `xolox#misc#test#assert_same_type()` function
Check whether two values are of the same type.
### Tests for the miscellaneous Vim scripts
The Vim auto-load script `autoload/xolox/misc/tests.vim` contains the
automated test suite of the miscellaneous Vim scripts. Right now the
coverage is not very high yet, but this will improve over time.
#### The `xolox#misc#tests#run()` function
Run the automated test suite of the miscellaneous Vim scripts. To be used
interactively. Intended to be safe to execute irrespective of context.
#### The `xolox#misc#tests#pattern_escaping()` function
Test escaping of regular expression patterns with
`xolox#misc#escape#pattern()`.
#### The `xolox#misc#tests#substitute_escaping()` function
Test escaping of substitution strings with
`xolox#misc#escape#substitute()`.
#### The `xolox#misc#tests#shell_escaping()` function
Test escaping of shell arguments with `xolox#misc#escape#shell()`.
#### The `xolox#misc#tests#making_a_list_unique()` function
Test removing of duplicate values from lists with
`xolox#misc#list#unique()`.
#### The `xolox#misc#tests#binary_insertion()` function
Test the binary insertion algorithm implemented in
`xolox#misc#list#binsert()`.
#### The `xolox#misc#tests#getting_configuration_options()` function
Test getting of scoped plug-in configuration "options" with
`xolox#misc#option#get()`.
#### The `xolox#misc#tests#splitting_of_multi_valued_options()` function
Test splitting of multi-valued Vim options with
`xolox#misc#option#split()`.
#### The `xolox#misc#tests#joining_of_multi_valued_options()` function
Test joining of multi-valued Vim options with `xolox#misc#option#join()`.
#### The `xolox#misc#tests#finding_vim_on_the_search_path()` function
Test looking up Vim's executable on the search path using [v:progname] []
with `xolox#misc#os#find_vim()`.
[v:progname]: http://vimdoc.sourceforge.net/htmldoc/eval.html#v:progname
#### The `xolox#misc#tests#synchronous_command_execution()` function
Test basic functionality of synchronous command execution with
`xolox#misc#os#exec()`.
#### The `xolox#misc#tests#synchronous_command_execution_with_stderr()` function
Test basic functionality of synchronous command execution with
`xolox#misc#os#exec()` including the standard error stream (not available
on Windows when vim-shell is not installed).
#### The `xolox#misc#tests#synchronous_command_execution_with_raising_of_errors()` function
Test raising of errors during synchronous command execution with
`xolox#misc#os#exec()`.
#### The `xolox#misc#tests#synchronous_command_execution_without_raising_errors()` function
Test synchronous command execution without raising of errors with
`xolox#misc#os#exec()`.
#### The `xolox#misc#tests#asynchronous_command_execution()` function
Test the basic functionality of asynchronous command execution with
`xolox#misc#os#exec()`. This runs the external command `mkdir` and tests
that the side effect of creating the directory takes place. This might
seem like a peculiar choice, but it's one of the few 100% portable
commands (Windows + UNIX) that doesn't involve input/output streams.
#### The `xolox#misc#tests#string_case_transformation()` function
Test string case transformation with `xolox#misc#str#ucfirst()`.
#### The `xolox#misc#tests#string_whitespace_compaction()` function
Test compaction of whitespace in strings with `xolox#misc#str#compact()`.
#### The `xolox#misc#tests#string_whitespace_trimming()` function
Test trimming of whitespace in strings with `xolox#misc#str#trim()`.
#### The `xolox#misc#tests#multiline_string_dedent()` function
Test dedenting of multi-line strings with `xolox#misc#str#dedent()`.
#### The `xolox#misc#tests#version_string_parsing()` function
Test parsing of version strings with `xolox#misc#version#parse()`.
#### The `xolox#misc#tests#version_string_comparison()` function
Test comparison of version strings with `xolox#misc#version#at_least()`.
### Timing of long during operations
#### The `xolox#misc#timer#start()` function
Start a timer. This returns a list which can later be passed to
`xolox#misc#timer#stop()`.
#### The `xolox#misc#timer#stop()` function
Show a formatted debugging message to the user, if the user has enabled
increased verbosity by setting Vim's ['verbose'] [verbose] option to one
(1) or higher.
This function has the same argument handling as Vim's [printf()] [printf]
function with one difference: At the point where you want the elapsed time
to be embedded, you write `%s` and you pass the list returned by
`xolox#misc#timer#start()` as an argument.
[verbose]: http://vimdoc.sourceforge.net/htmldoc/options.html#'verbose'
[printf]: http://vimdoc.sourceforge.net/htmldoc/eval.html#printf()
#### The `xolox#misc#timer#force()` function
Show a formatted message to the user. This function has the same argument
handling as Vim's [printf()] [printf] function with one difference: At the
point where you want the elapsed time to be embedded, you write `%s` and
you pass the list returned by `xolox#misc#timer#start()` as an argument.
### Version string handling
#### The `xolox#misc#version#parse()` function
Convert a version string to a list of integers.
#### The `xolox#misc#version#at_least()` function
Check whether the second version string is equal to or greater than the
first version string. Returns 1 (true) when it is, 0 (false) otherwise.
<!-- End of generated documentation -->
## Contact
If you have questions, bug reports, suggestions, etc. the author can be
contacted at <peter@peterodding.com>. The latest version is available at
<http://peterodding.com/code/vim/misc> and <http://github.com/xolox/vim-misc>.
If you like the script please vote for it on [Vim Online] [].
## License
This software is licensed under the [MIT license] [].
© 2013 Peter Odding &lt;<peter@peterodding.com>&gt;.
[MIT license]: http://en.wikipedia.org/wiki/MIT_License
[Pathogen]: http://www.vim.org/scripts/script.php?script_id=2332
[plugins]: http://peterodding.com/code/vim/
[repository]: https://github.com/xolox/vim-misc
[Vim Online]: http://www.vim.org/scripts/script.php?script_id=4597
[vim-tools]: http://peterodding.com/code/vim/tools/
[Vundle]: https://github.com/gmarik/vundle
[ZIP archive]: http://peterodding.com/code/vim/downloads/misc.zip

View File

@ -0,0 +1 @@
{"vim_script_nr": 4597, "dependencies": {}, "homepage": "http://peterodding.com/code/vim/misc", "name": "vim-misc"}

View File

@ -0,0 +1,7 @@
" The version of my miscellaneous scripts.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: July 20, 2013
" URL: http://peterodding.com/code/vim/misc/
let g:xolox#misc#version = '1.8.5'

View File

@ -0,0 +1,80 @@
" Handling of special buffers
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: May 19, 2013
" URL: http://peterodding.com/code/vim/misc/
"
" The functions defined here make it easier to deal with special Vim buffers
" that contain text generated by a Vim plug-in. For example my [vim-notes
" plug-in] [vim-notes] generates several such buffers:
"
" - [:RecentNotes] [RecentNotes] lists recently modified notes
" - [:ShowTaggedNotes] [ShowTaggedNotes] lists notes grouped by tags
" - etc.
"
" Because the text in these buffers is generated, Vim shouldn't bother with
" swap files and it should never prompt the user whether to save changes to
" the generated text.
"
" [vim-notes]: http://peterodding.com/code/vim/notes/
" [RecentNotes]: http://peterodding.com/code/vim/notes/#recentnotes_command
" [ShowTaggedNotes]: http://peterodding.com/code/vim/notes/#showtaggednotes_command
function! xolox#misc#buffer#is_empty() " {{{1
" Checks if the current buffer is an empty, unchanged buffer which can be
" reused. Returns 1 if an empty buffer is found, 0 otherwise.
return !&modified && expand('%') == '' && line('$') <= 1 && getline(1) == ''
endfunction
function! xolox#misc#buffer#prepare(...) " {{{1
" Open a special buffer, i.e. a buffer that will hold generated contents,
" not directly edited by the user. The buffer can be customized by passing a
" dictionary with the following key/value pairs as the first argument:
"
" - **name** (required): The base name of the buffer (i.e. the base name of
" the file loaded in the buffer, even though it isn't really a file and
" nothing is really 'loaded' :-)
" - **path** (required): The pathname of the buffer. May be relevant if
" [:lcd] [lcd] or ['autochdir'] [acd] is being used.
"
" [lcd]: http://vimdoc.sourceforge.net/htmldoc/editing.html#:lcd
" [acd]: http://vimdoc.sourceforge.net/htmldoc/options.html#'autochdir'
if a:0 == 1 && type(a:1) == type('')
" Backwards compatibility with old interface.
let options = {'name': a:1, 'path': a:1}
elseif type(a:1) == type({})
let options = a:1
else
throw "Invalid arguments"
endif
let winnr = 1
let found = 0
for bufnr in tabpagebuflist()
if xolox#misc#path#equals(options['path'], bufname(bufnr))
execute winnr . 'wincmd w'
let found = 1
break
else
let winnr += 1
endif
endfor
if !(found || xolox#misc#buffer#is_empty())
vsplit
endif
silent execute 'edit' fnameescape(options['path'])
lcd " clear working directory
setlocal buftype=nofile bufhidden=hide noswapfile
let &l:statusline = '[' . options['name'] . ']'
call xolox#misc#buffer#unlock()
silent %delete
endfunction
function! xolox#misc#buffer#lock() " {{{1
" Lock a special buffer so that its contents can no longer be edited.
setlocal readonly nomodifiable nomodified
endfunction
function! xolox#misc#buffer#unlock() " {{{1
" Unlock a special buffer so that its content can be updated.
setlocal noreadonly modifiable
endfunction

View File

@ -0,0 +1,22 @@
" Tab completion for user defined commands.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: May 19, 2013
" URL: http://peterodding.com/code/vim/misc/
function! xolox#misc#complete#keywords(arglead, cmdline, cursorpos)
" This function can be used to perform keyword completion for user defined
" Vim commands based on the contents of the current buffer. Here's an
" example of how you would use it:
"
" :command -nargs=* -complete=customlist,xolox#misc#complete#keywords MyCmd call s:MyCmd(<f-args>)
let words = {}
for line in getline(1, '$')
for word in split(line, '\W\+')
let words[word] = 1
endfor
endfor
return sort(keys(filter(words, 'v:key =~# a:arglead')))
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,56 @@
" String escaping functions.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: May 19, 2013
" URL: http://peterodding.com/code/vim/misc/
function! xolox#misc#escape#pattern(string) " {{{1
" Takes a single string argument and converts it into a [:substitute]
" [subcmd] / [substitute()] [subfun] pattern string that matches the given
" string literally.
"
" [subfun]: http://vimdoc.sourceforge.net/htmldoc/eval.html#substitute()
" [subcmd]: http://vimdoc.sourceforge.net/htmldoc/change.html#:substitute
if type(a:string) == type('')
let string = escape(a:string, '^$.*\~[]')
return substitute(string, '\n', '\\n', 'g')
endif
return ''
endfunction
function! xolox#misc#escape#substitute(string) " {{{1
" Takes a single string argument and converts it into a [:substitute]
" [subcmd] / [substitute()] [subfun] replacement string that inserts the
" given string literally.
if type(a:string) == type('')
let string = escape(a:string, '\&~%')
return substitute(string, '\n', '\\r', 'g')
endif
return ''
endfunction
function! xolox#misc#escape#shell(string) " {{{1
" Takes a single string argument and converts it into a quoted command line
" argument.
"
" I was going to add a long rant here about Vim's ['shellslash' option]
" [shellslash], but really, it won't make any difference. Let's just suffice
" to say that I have yet to encounter a single person out there who uses
" this option for its intended purpose (running a UNIX style shell on
" Microsoft Windows).
"
" [shellslash]: http://vimdoc.sourceforge.net/htmldoc/options.html#'shellslash'
if xolox#misc#os#is_win()
try
let ssl_save = &shellslash
set noshellslash
return shellescape(a:string)
finally
let &shellslash = ssl_save
endtry
else
return shellescape(a:string)
endif
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,46 @@
" Human friendly string formatting for Vim.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 2, 2013
" URL: http://peterodding.com/code/vim/misc/
function! xolox#misc#format#pluralize(count, singular, plural) " {{{1
" Concatenate a counter (the first argument, expected to be an integer) with
" a singular or plural label (the second and third arguments, both expected
" to be strings).
if a:count == 0
return printf('no %s', a:plural)
else
return printf('%i %s', a:count, a:count == 1 ? a:singular : a:plural)
endif
endfunction
function! xolox#misc#format#timestamp(ts) " {{{1
" Format a time stamp (a string containing a formatted floating point
" number) into a human friendly format, for example 70 seconds is phrased as
" "1 minute and 10 seconds".
let seconds = a:ts + 0
" Fast common case with extra precision from reltime().
if seconds < 5
let extract = matchstr(a:ts, '^\d\+\(\.0*[1-9][1-9]\?\)\?')
if extract =~ '[123456789]'
return extract . ' second' . (extract != '1' ? 's' : '')
endif
endif
" Generic but slow code.
let result = []
for [name, size] in [['day', 60 * 60 * 24], ['hour', 60 * 60], ['minute', 60], ['second', 1]]
if seconds >= size
let counter = seconds / size
let seconds = seconds % size
let suffix = counter != 1 ? 's' : ''
call add(result, printf('%i %s%s', counter, name, suffix))
endif
endfor
" Format the resulting text?
if len(result) == 1
return result[0]
else
return join(result[0:-2], ', ') . ' and ' . result[-1]
endif
endfunction

View File

@ -0,0 +1,42 @@
" List handling functions.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 2, 2013
" URL: http://peterodding.com/code/vim/misc/
function! xolox#misc#list#unique(list) " {{{1
" Remove duplicate values from the given list in-place (preserves order).
call reverse(a:list)
call filter(a:list, 'count(a:list, v:val) == 1')
return reverse(a:list)
endfunction
function! xolox#misc#list#binsert(list, value, ...) " {{{1
" Performs in-place binary insertion, which depending on your use case can
" be more efficient than calling Vim's [sort()] [sort] function after each
" insertion (in cases where a single, final sort is not an option). Expects
" three arguments:
"
" 1. A list
" 2. A value to insert
" 3. 1 (true) when case should be ignored, 0 (false) otherwise
"
" [sort]: http://vimdoc.sourceforge.net/htmldoc/eval.html#sort()
let idx = s:binsert_r(a:list, 0, len(a:list), a:value, exists('a:1') && a:1)
return insert(a:list, a:value, idx)
endfunction
function! s:binsert_r(list, low, high, value, ignorecase)
let mid = a:low + (a:high - a:low) / 2
if a:low == a:high
return a:low
elseif a:ignorecase ? a:value >? a:list[mid] : a:value > a:list[mid]
return s:binsert_r(a:list, mid + 1, a:high, a:value, a:ignorecase)
elseif a:ignorecase ? a:value <? a:list[mid] : a:value < a:list[mid]
return s:binsert_r(a:list, a:low, mid, a:value, a:ignorecase)
else
return mid
endif
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,119 @@
" Functions to interact with the user.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 2, 2013
" URL: http://peterodding.com/code/vim/misc/
if !exists('g:xolox_message_buffer')
" For when I lose my :messages history :-\
let g:xolox_message_buffer = 100
endif
if !exists('g:xolox_messages')
let g:xolox_messages = []
endif
function! xolox#misc#msg#info(...) " {{{1
" Show a formatted informational message to the user.
"
" This function has the same argument handling as Vim's [printf()] []
" function with one notable difference: Any arguments which are not numbers
" or strings are coerced to strings using Vim's [string()] [] function.
"
" In the case of `xolox#misc#msg#info()`, automatic string coercion simply
" makes the function a bit easier to use.
"
" [printf()]: http://vimdoc.sourceforge.net/htmldoc/eval.html#printf()
" [string()]: http://vimdoc.sourceforge.net/htmldoc/eval.html#string()
call s:show_message('title', a:000)
endfunction
function! xolox#misc#msg#warn(...) " {{{1
" Show a formatted warning message to the user.
"
" This function has the same argument handling as the
" `xolox#misc#msg#info()` function.
call s:show_message('warningmsg', a:000)
endfunction
function! xolox#misc#msg#debug(...) " {{{1
" Show a formatted debugging message to the user, *if the user has enabled
" increased verbosity by setting Vim's ['verbose'] [] option to one
" (1) or higher*.
"
" This function has the same argument handling as the
" `xolox#misc#msg#info()` function.
"
" In the case of `xolox#misc#msg#debug()`, automatic string coercion
" provides lazy evaluation in the sense that complex data structures are
" only converted to strings when the user has enabled increased verbosity.
"
" ['verbose']: http://vimdoc.sourceforge.net/htmldoc/options.html#'verbose'
if &vbs >= 1
call s:show_message('question', a:000)
endif
endfunction
function! s:show_message(hlgroup, args) " {{{1
" The implementation of info() and warn().
let nargs = len(a:args)
if nargs == 1
let message = a:args[0]
elseif nargs >= 2
let args = map(copy(a:args), 's:coerce_argument(v:val)')
let message = call('printf', args)
endif
if exists('message')
try
" Temporarily disable Vim's |hit-enter| prompt and mode display.
if !exists('s:more_save')
let s:more_save = &more
let s:ruler_save = &ruler
let s:smd_save = &showmode
endif
set nomore noshowmode
if winnr('$') == 1 | set noruler | endif
augroup PluginXoloxHideMode
autocmd! CursorHold,CursorHoldI * call s:clear_message()
augroup END
execute 'echohl' a:hlgroup
" Redraw to avoid |hit-enter| prompt.
redraw
for line in split(message, "\n")
echomsg line
endfor
if g:xolox_message_buffer > 0
call add(g:xolox_messages, message)
if len(g:xolox_messages) > g:xolox_message_buffer
call remove(g:xolox_messages, 0)
endif
endif
finally
" Always clear message highlighting, even when interrupted by Ctrl-C.
echohl none
endtry
endif
endfunction
function! s:coerce_argument(value) " {{{1
" Callback to coerce printf() arguments into strings.
let value_type = type(a:value)
if value_type != type(0) && value_type != type('')
return string(a:value)
else
return a:value
endif
endfunction
function! s:clear_message() " {{{1
" Callback to clear message after some time has passed.
echo ''
let &more = s:more_save
let &showmode = s:smd_save
let &ruler = s:ruler_save
unlet s:more_save s:ruler_save s:smd_save
autocmd! PluginXoloxHideMode
augroup! PluginXoloxHideMode
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,100 @@
" Integration between Vim and its environment.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 19, 2013
" URL: http://peterodding.com/code/vim/misc/
let s:enoimpl = "vim-misc %s: %s() hasn't been implemented for your platform! If you have suggestions, please get in touch at https://github.com/xolox/vim-misc/issues"
let s:handlers = ['gnome-open', 'kde-open', 'exo-open', 'xdg-open']
function! xolox#misc#open#file(location, ...) " {{{1
" Given a pathname or URL as the first argument, this opens the file with
" the program associated with the file type. So for example a text file
" might open in Vim, an `*.html` file would probably open in your web
" browser and a media file would open in a media player.
"
" This should work on Windows, Mac OS X and most Linux distributions. If
" this fails to find a file association, you can pass one or more external
" commands to try as additional arguments. For example:
"
" :call xolox#misc#open#file('/path/to/my/file', 'firefox', 'google-chrome')
"
" This generally shouldn't be necessary but it might come in handy now and
" then.
if xolox#misc#os#is_win()
try
call xolox#shell#open_with_windows_shell(a:location)
catch /^Vim\%((\a\+)\)\=:E117/
let command = '!start CMD /C START "" %s'
silent execute printf(command, xolox#misc#escape#shell(a:location))
endtry
return
elseif xolox#misc#os#is_mac()
call xolox#misc#msg#debug("vim-misc %s: Detected Mac OS X, using 'open' command to open %s ..", g:xolox#misc#version, string(a:location))
let cmd = 'open ' . shellescape(a:location) . ' 2>&1'
call s:handle_error(cmd, system(cmd))
return
else
for handler in s:handlers + a:000
if executable(handler)
call xolox#misc#msg#debug("vim-misc %s: Using '%s' to open '%s'.", g:xolox#misc#version, handler, a:location)
let cmd = shellescape(handler) . ' ' . shellescape(a:location) . ' 2>&1'
call s:handle_error(cmd, system(cmd))
return
endif
endfor
endif
throw printf(s:enoimpl, g:xolox#misc#version, 'xolox#misc#open#file')
endfunction
function! xolox#misc#open#url(url) " {{{1
" Given a URL as the first argument, this opens the URL in your preferred or
" best available web browser:
"
" - In GUI environments a graphical web browser will open (or a new tab will
" be created in an existing window)
" - In console Vim without a GUI environment, when you have any of `lynx`,
" `links` or `w3m` installed it will launch a command line web browser in
" front of Vim (temporarily suspending Vim)
let url = a:url
if url !~ '^\w\+://'
call xolox#misc#msg#debug("vim-misc %s: The URL %s doesn't contain a scheme, improvising ..", g:xolox#misc#version, string(url))
if url !~ '@'
call xolox#misc#msg#debug("vim-misc %s: Defaulting to http:// URL scheme ..", g:xolox#misc#version)
let url = 'http://' . url
elseif url !~ '^mailto:'
call xolox#misc#msg#debug("vim-misc %s: Defaulting to mailto: URL scheme ..", g:xolox#misc#version)
let url = 'mailto:' . url
endif
endif
let on_unix = has('unix')
let not_on_mac = !xolox#misc#os#is_mac()
let no_gui_available = (has('gui_running') == 0 && $DISPLAY == '')
if on_unix && not_on_mac && no_gui_available
call xolox#misc#msg#debug("vim-misc %s: Using command line web browser because no GUI seems to be available ..", g:xolox#misc#version)
for browser in ['lynx', 'links', 'w3m']
call xolox#misc#msg#debug("vim-misc %s: Checking whether %s command line web browser is installed ..", g:xolox#misc#version, string(browser))
if executable(browser)
call xolox#misc#msg#debug("vim-misc %s: Found %s, using it to open %s ..", g:xolox#misc#version, string(browser), string(url))
execute '!' . browser fnameescape(url)
call s:handle_error(browser . ' ' . url, '')
return
endif
endfor
endif
call xolox#misc#msg#debug("vim-misc %s: Defaulting to GUI web browser to open %s ..", g:xolox#misc#version, string(url))
call xolox#misc#open#file(url, 'firefox', 'google-chrome')
endfunction
function! s:handle_error(cmd, output) " {{{1
if v:shell_error
let message = "vim-misc %s: Failed to execute program! (command line: %s%s)"
let output = strtrans(xolox#misc#str#trim(a:output))
if output != ''
let output = ", output: " . string(output)
endif
throw printf(message, g:xolox#misc#version, a:cmd, output)
endif
endfunction
" vim: et ts=2 sw=2 fdm=marker

View File

@ -0,0 +1,115 @@
" Vim and plug-in option handling.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 2, 2013
" URL: http://peterodding.com/code/vim/misc/
function! xolox#misc#option#get(name, ...) " {{{1
" Expects one or two arguments: 1. The name of a variable and 2. the default
" value if the variable does not exist.
"
" Returns the value of the variable from a buffer local variable, global
" variable or the default value, depending on which is defined.
"
" This is used by some of my Vim plug-ins for option handling, so that users
" can customize options for specific buffers.
if exists('b:' . a:name)
" Buffer local variable.
return eval('b:' . a:name)
elseif exists('g:' . a:name)
" Global variable.
return eval('g:' . a:name)
elseif exists('a:1')
" Default value.
return a:1
endif
endfunction
function! xolox#misc#option#split(value) " {{{1
" Given a multi-value Vim option like ['runtimepath'] [rtp] this returns a
" list of strings. For example:
"
" :echo xolox#misc#option#split(&runtimepath)
" ['/home/peter/Projects/Vim/misc',
" '/home/peter/Projects/Vim/colorscheme-switcher',
" '/home/peter/Projects/Vim/easytags',
" ...]
"
" [rtp]: http://vimdoc.sourceforge.net/htmldoc/options.html#'runtimepath'
let values = split(a:value, '[^\\]\zs,')
return map(values, 's:unescape(v:val)')
endfunction
function! s:unescape(s)
return substitute(a:s, '\\\([\\,]\)', '\1', 'g')
endfunction
function! xolox#misc#option#join(values) " {{{1
" Given a list of strings like the ones returned by
" `xolox#misc#option#split()`, this joins the strings together into a
" single value that can be used to set a Vim option.
let values = copy(a:values)
call map(values, 's:escape(v:val)')
return join(values, ',')
endfunction
function! s:escape(s)
return escape(a:s, ',\')
endfunction
function! xolox#misc#option#split_tags(value) " {{{1
" Customized version of `xolox#misc#option#split()` with specialized
" handling for Vim's ['tags' option] [tags].
"
" [tags]: http://vimdoc.sourceforge.net/htmldoc/options.html#'tags'
let values = split(a:value, '[^\\]\zs,')
return map(values, 's:unescape_tags(v:val)')
endfunction
function! s:unescape_tags(s)
return substitute(a:s, '\\\([\\, ]\)', '\1', 'g')
endfunction
function! xolox#misc#option#join_tags(values) " {{{1
" Customized version of `xolox#misc#option#join()` with specialized
" handling for Vim's ['tags' option] [tags].
let values = copy(a:values)
call map(values, 's:escape_tags(v:val)')
return join(values, ',')
endfunction
function! s:escape_tags(s)
return escape(a:s, ', ')
endfunction
function! xolox#misc#option#eval_tags(value, ...) " {{{1
" Evaluate Vim's ['tags' option] [tags] without looking at the file
" system, i.e. this will report tags files that don't exist yet. Expects
" the value of the ['tags' option] [tags] as the first argument. If the
" optional second argument is 1 (true) only the first match is returned,
" otherwise (so by default) a list with all matches is returned.
let pathnames = []
let first_only = exists('a:1') ? a:1 : 0
for pattern in xolox#misc#option#split_tags(a:value)
" Make buffer relative pathnames absolute.
if pattern =~ '^\./'
let suffix = matchstr(pattern, '^./\zs.*$')
let pattern = xolox#misc#path#merge(expand('%:p:h'), suffix)
endif
" Make working directory relative pathnames absolute.
if xolox#misc#path#is_relative(pattern)
let pattern = xolox#misc#path#merge(getcwd(), pattern)
endif
" Ignore the trailing `;' for recursive upwards searching because we
" always want the most specific pathname available.
let pattern = substitute(pattern, ';$', '', '')
" Expand the pattern.
call extend(pathnames, split(expand(pattern), "\n"))
if first_only && !empty(pathnames)
return pathnames[0]
endif
endfor
return first_only ? '' : pathnames
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,271 @@
" Operating system interfaces.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June , 2013
" URL: http://peterodding.com/code/vim/misc/
function! xolox#misc#os#is_mac() " {{{1
" Returns 1 (true) when on Mac OS X, 0 (false) otherwise. You would expect
" this to simply check the Vim feature list, but for some obscure reason the
" `/usr/bin/vim` included in Mac OS X (verified on version 10.7.5) returns 0
" (false) in response to `has('mac')`, so we check the output of `uname`
" to avoid false negatives.
if !exists('s:is_mac')
" By default we assume we are *not* on Mac OS X.
let s:is_mac = 0
if has('mac') || has('macunix') || has('gui_mac')
" If Vim's feature list indicates we are on Mac OS X, we have our answer :-).
let s:is_mac = 1
elseif !xolox#misc#os#is_win()
" Otherwise we check the output of `uname' to avoid false negatives.
let result = xolox#misc#os#exec({'command': 'uname', 'check': 0})
if result['exit_code'] == 0 && get(result['stdout'], 0, '') == 'Darwin'
let s:is_mac = 1
endif
endif
endif
return s:is_mac
endfunction
function! xolox#misc#os#is_win() " {{{1
" Returns 1 (true) when on Microsoft Windows, 0 (false) otherwise.
return has('win16') || has('win32') || has('win64')
endfunction
function! xolox#misc#os#find_vim(...) " {{{1
" Returns the program name of Vim as a string. On Windows and UNIX this just
" [v:progname] [] as an absolute pathname while on Mac OS X there is
" some special magic to find MacVim's executable even though it's usually
" not on the executable search path. If you want, you can override the
" value returned from this function by setting the global variable
" `g:xolox#misc#os#vim_progname`.
"
" By default the choice of console Vim vs graphical Vim is made based on
" the value of [v:progname] [], but if you have a preference you can pass
" the string `vim` or `gvim` as the first and only argument.
"
" [v:progname]: http://vimdoc.sourceforge.net/htmldoc/eval.html#v:progname
if exists('a:1')
let program_name = a:1
else
let program_name = v:progname
endif
if exists('g:xolox#misc#os#vim_progname')
let pathname = g:xolox#misc#os#vim_progname
else
let pathname = ''
endif
if empty(pathname) && xolox#misc#os#is_mac()
" Special handling for Mac OS X where MacVim is usually not on the $PATH.
" This always returns the "Vim" executable and not "MacVim" (regardless of
" the caller's preference) because "MacVim" has funky dock magic going on.
call xolox#misc#msg#debug("vim-misc %s: Trying MacVim workaround to find Vim executable ..", g:xolox#misc#version)
let segments = xolox#misc#path#split($VIMRUNTIME)
if segments[-3:] == ['Resources', 'vim', 'runtime']
let pathname = xolox#misc#path#join(segments[0:-4] + ['MacOS', 'Vim'])
call xolox#misc#msg#debug("vim-misc %s: The MacVim workaround resulted in the Vim executable %s.", g:xolox#misc#version, string(pathname))
endif
endif
if empty(pathname)
" Default logic.
call xolox#misc#msg#debug("vim-misc %s: Looking for Vim executable named %s on search path ..", g:xolox#misc#version, string(program_name))
let candidates = xolox#misc#path#which(program_name)
if !empty(candidates)
call xolox#misc#msg#debug("vim-misc %s: Found %i candidate(s) on search path: %s.", g:xolox#misc#version, len(candidates), string(candidates))
let pathname = candidates[0]
endif
endif
call xolox#misc#msg#debug("vim-misc %s: Reporting Vim executable %s.", g:xolox#misc#version, string(pathname))
return pathname
endfunction
function! xolox#misc#os#exec(options) " {{{1
" Execute an external command (hiding the console on Microsoft Windows when
" my [vim-shell plug-in] [vim-shell] is installed).
"
" Expects a dictionary with the following key/value pairs as the first
" argument:
"
" - **command** (required): The command line to execute
" - **async** (optional): set this to 1 (true) to execute the command in the
" background (asynchronously)
" - **stdin** (optional): a string or list of strings with the input for the
" external command
" - **check** (optional): set this to 0 (false) to disable checking of the
" exit code of the external command (by default an exception will be
" raised when the command fails)
"
" Returns a dictionary with one or more of the following key/value pairs:
"
" - **command** (always available): the generated command line that was used
" to run the external command
" - **exit_code** (only in synchronous mode): the exit status of the
" external command (an integer, zero on success)
" - **stdout** (only in synchronous mode): the output of the command on the
" standard output stream (a list of strings, one for each line)
" - **stderr** (only in synchronous mode): the output of the command on the
" standard error stream (as a list of strings, one for each line)
"
" [vim-shell]: http://peterodding.com/code/vim/shell/
try
" Unpack the options.
let cmd = a:options['command']
let async = get(a:options, 'async', 0)
" We need to know in a couple of places whether we are on Windows.
let is_win = xolox#misc#os#is_win()
" Use vim-shell so we don't pop up a console window on Windows? If the
" caller specifically asks us *not* to use vim-shell, we'll respect that
" choice; this is very useful for automated tests :-).
if get(a:options, 'use_dll', 1) == 0
let use_dll = 0
else
let use_dll = xolox#misc#os#can_use_dll()
endif
" Decide whether to redirect the standard output and standard error
" streams to temporary files.
let redirect_output = !async && (use_dll || !is_win)
" Write the input for the external command to a temporary file?
if has_key(a:options, 'stdin') && use_dll
let tempin = tempname()
if type(a:options['stdin']) == type([])
let lines = a:options['stdin']
else
let lines = split(a:options['stdin'], "\n")
endif
call writefile(lines, tempin)
let cmd .= ' < ' . xolox#misc#escape#shell(tempin)
endif
" Redirect the standard output and/or standard error streams of the
" external process to temporary files? (only in synchronous mode)
if redirect_output
let tempout = tempname()
let temperr = tempname()
let cmd = printf('(%s) 1>%s 2>%s', cmd, xolox#misc#escape#shell(tempout), xolox#misc#escape#shell(temperr))
endif
" Use vim-shell or system() to execute the external command?
if use_dll
call xolox#misc#msg#debug("vim-misc %s: Executing external command using compiled DLL: %s", g:xolox#misc#version, cmd)
let exit_code = xolox#shell#execute_with_dll(cmd, async)
else
" Enable asynchronous mode (very platform specific).
if async
if is_win
let cmd = printf('start /b %s', cmd)
elseif has('unix')
let cmd = printf('(%s) &', cmd)
else
call xolox#misc#msg#warn("vim-misc %s: I don't know how to execute the command %s asynchronously on your platform! Falling back to synchronous mode...", g:xolox#misc#version, cmd)
endif
endif
" On UNIX we explicitly execute the command line using 'sh' instead of
" the default shell, because we assume that standard output and standard
" error can be redirected separately, but (t)csh does not support this
" (and it might be the default shell).
if has('unix')
call xolox#misc#msg#debug("vim-misc %s: Generated shell expression: %s", g:xolox#misc#version, cmd)
let cmd = printf('sh -c %s', xolox#misc#escape#shell(cmd))
endif
" Let the user know what's happening (in case they're interested).
if async && is_win
call xolox#misc#msg#debug("vim-misc %s: Executing external command using !start command: %s", g:xolox#misc#version, cmd)
silent execute '!' . cmd
else
call xolox#misc#msg#debug("vim-misc %s: Executing external command using system() function: %s", g:xolox#misc#version, cmd)
let arguments = [cmd]
if has_key(a:options, 'stdin')
if type(a:options['stdin']) == type([])
call add(arguments, join(a:options['stdin'], "\n"))
else
call add(arguments, a:options['stdin'])
endif
endif
let stdout = call('system', arguments)
let exit_code = v:shell_error
endif
endif
" Return the results as a dictionary with one or more key/value pairs.
let result = {'command': cmd}
if !async
let result['exit_code'] = exit_code
" Get the standard output of the command.
if redirect_output
let result['stdout'] = s:readfile(tempout, 'standard output', a:options['command'])
elseif exists('stdout')
let result['stdout'] = split(stdout, "\n")
else
let result['stdout'] = []
endif
" Get the standard error of the command.
if exists('temperr')
let result['stderr'] = s:readfile(temperr, 'standard error', a:options['command'])
else
let result['stderr'] = []
endif
" If we just executed a synchronous command and the caller didn't
" specifically ask us *not* to check the exit code of the external
" command, we'll do so now. The idea here is that it should be easy
" to 'do the right thing'.
if get(a:options, 'check', 1) && exit_code != 0
" Prepare an error message with enough details so the user can investigate.
let msg = printf("vim-misc %s: External command failed with exit code %d!", g:xolox#misc#version, result['exit_code'])
let msg .= printf("\nCommand line: %s", result['command'])
" If the external command reported an error, we'll include it in our message.
if !empty(result['stderr'])
" This is where we would normally expect to find an error message.
let msg .= printf("\nOutput on standard output stream:\n%s", join(result['stderr'], "\n"))
elseif !empty(result['stdout'])
" Exuberant Ctags on Windows XP reports errors on standard output :-x.
let msg .= printf("\nOutput on standard error stream:\n%s", join(result['stdout'], "\n"))
endif
throw msg
endif
endif
return result
finally
" Cleanup any temporary files we created.
for name in ['tempin', 'tempout', 'temperr']
if exists(name)
call delete({name})
endif
endfor
endtry
endfunction
function! xolox#misc#os#can_use_dll() " {{{1
" If a) we're on Microsoft Windows, b) the vim-shell plug-in is installed
" and c) the compiled DLL included in vim-shell works, we can use the
" vim-shell plug-in to execute external commands! Returns 1 (true)
" if we can use the DLL, 0 (false) otherwise.
let can_use_dll = 0
try
let can_use_dll = xolox#shell#can_use_dll()
catch /^Vim\%((\a\+)\)\=:E117/
" Silence E117.
endtry
return can_use_dll
endfunction
function! s:readfile(fname, label, cmd) " {{{1
try
return readfile(a:fname)
catch
call xolox#misc#msg#warn("vim-misc %s: Failed to read temporary file (%s) with %s of external command: %s! (external command: %s)", g:xolox#misc#version, a:fname, a:label, v:exception, a:cmd)
return []
endtry
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,263 @@
" Pathname manipulation functions.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 25, 2013
" URL: http://peterodding.com/code/vim/misc/
let s:windows_compatible = xolox#misc#os#is_win()
let s:mac_os_x_compatible = xolox#misc#os#is_mac()
function! xolox#misc#path#which(...) " {{{1
" Scan the executable search path (`$PATH`) for one or more external
" programs. Expects one or more string arguments with program names. Returns
" a list with the absolute pathnames of all found programs. Here's an
" example:
"
" :echo xolox#misc#path#which('gvim', 'vim')
" ['/usr/local/bin/gvim',
" '/usr/bin/gvim',
" '/usr/local/bin/vim',
" '/usr/bin/vim']
let extensions = s:windows_compatible ? split($PATHEXT, ';') : ['']
let matches = []
let checked = {}
for program in a:000
for directory in split($PATH, s:windows_compatible ? ';' : ':')
let directory = xolox#misc#path#absolute(directory)
if isdirectory(directory)
let found = 0
for extension in extensions
let path = xolox#misc#path#merge(directory, program . extension)
if executable(path)
call add(matches, path)
let found = 1
endif
endfor
if s:windows_compatible && ! found
" Maybe the extension is already contained in program; try without
" $PATHEXT.
let path = xolox#misc#path#merge(directory, program)
if executable(path)
call add(matches, path)
endif
endif
endif
endfor
endfor
return xolox#misc#list#unique(matches)
endfunction
function! xolox#misc#path#split(path) " {{{1
" Split a pathname (the first and only argument) into a list of pathname
" components.
"
" On Windows, pathnames starting with two slashes or backslashes are UNC
" paths where the leading slashes are significant... In this case we split
" like this:
"
" - Input: `'//server/share/directory'`
" - Result: `['//server', 'share', 'directory']`
"
" Everything except Windows is treated like UNIX until someone has a better
" suggestion :-). In this case we split like this:
"
" - Input: `'/foo/bar/baz'`
" - Result: `['/', 'foo', 'bar', 'baz']`
"
" To join a list of pathname components back into a single pathname string,
" use the `xolox#misc#path#join()` function.
if type(a:path) == type('')
if s:windows_compatible
if a:path =~ '^[\/][\/]'
" UNC pathname.
return split(a:path, '\%>2c[\/]\+')
else
" If it's not a UNC path we can simply split on slashes & backslashes.
return split(a:path, '[\/]\+')
endif
else
" Everything else is treated as UNIX.
let absolute = (a:path =~ '^/')
let segments = split(a:path, '/\+')
return absolute ? insert(segments, '/') : segments
endif
endif
return []
endfunction
function! xolox#misc#path#join(parts) " {{{1
" Join a list of pathname components (the first and only argument) into a
" single pathname string. This is the counterpart to the
" `xolox#misc#path#split()` function and it expects a list of pathname
" components as returned by `xolox#misc#path#split()`.
if type(a:parts) == type([])
if s:windows_compatible
return join(a:parts, xolox#misc#path#directory_separator())
elseif get(a:parts, 0) == '/'
" Absolute path on UNIX (non-Windows).
return '/' . join(a:parts[1:], '/')
else
" Relative path on UNIX (non-Windows).
return join(a:parts, '/')
endif
endif
return ''
endfunction
function! xolox#misc#path#directory_separator() " {{{1
" Find the preferred directory separator for the platform and settings.
return exists('+shellslash') && &shellslash ? '/' : '\'
endfunction
function! xolox#misc#path#absolute(path) " {{{1
" Canonicalize and resolve a pathname, *regardless of whether it exists*.
" This is intended to support string comparison to determine whether two
" pathnames point to the same directory or file.
if type(a:path) == type('')
let path = a:path
" Make the pathname absolute.
if path =~ '^\~'
" Expand ~ to $HOME.
let path = $HOME . '/' . path[1:]
elseif xolox#misc#path#is_relative(path)
" Make relative pathnames absolute.
let path = getcwd() . '/' . path
endif
" Resolve symbolic links to find the canonical pathname. In my tests this
" also removes all symbolic pathname segments (`.' and `..'), even when
" the pathname does not exist. Also there used to be a bug in resolve()
" where it wouldn't resolve pathnames ending in a directory separator.
" Since it's not much trouble to work around, that's what we do.
let path = resolve(substitute(path, s:windows_compatible ? '[\/]\+$' : '/\+$', '', ''))
" Normalize directory separators (especially relevant on Windows).
let parts = xolox#misc#path#split(path)
if s:windows_compatible && parts[0] =~ '^[\/][\/]'
" Also normalize the two leading "directory separators" (I'm not
" sure what else to call them :-) in Windows UNC pathnames.
let parts[0] = repeat(xolox#misc#path#directory_separator(), 2) . parts[0][2:]
endif
return xolox#misc#path#join(parts)
endif
return ''
endfunction
function! xolox#misc#path#relative(path, base) " {{{1
" Make an absolute pathname (the first argument) relative to a directory
" (the second argument).
let path = xolox#misc#path#split(a:path)
let base = xolox#misc#path#split(a:base)
while path != [] && base != [] && path[0] == base[0]
call remove(path, 0)
call remove(base, 0)
endwhile
let distance = repeat(['..'], len(base))
return xolox#misc#path#join(distance + path)
endfunction
function! xolox#misc#path#merge(parent, child, ...) " {{{1
" Join a directory pathname and filename into a single pathname.
if type(a:parent) == type('') && type(a:child) == type('')
" TODO Use xolox#misc#path#is_relative()?
if s:windows_compatible
let parent = substitute(a:parent, '[\\/]\+$', '', '')
let child = substitute(a:child, '^[\\/]\+', '', '')
return parent . '\' . child
else
let parent = substitute(a:parent, '/\+$', '', '')
let child = substitute(a:child, '^/\+', '', '')
return parent . '/' . child
endif
endif
return ''
endfunction
function! xolox#misc#path#commonprefix(paths) " {{{1
" Find the common prefix of path components in a list of pathnames.
let common = xolox#misc#path#split(a:paths[0])
for path in a:paths
let index = 0
for segment in xolox#misc#path#split(path)
if len(common) <= index
break
elseif common[index] != segment
call remove(common, index, -1)
break
endif
let index += 1
endfor
endfor
return xolox#misc#path#join(common)
endfunction
function! xolox#misc#path#encode(path) " {{{1
" Encode a pathname so it can be used as a filename. This uses URL encoding
" to encode special characters.
if s:windows_compatible
let mask = '[*|\\/:"<>?%]'
elseif s:mac_os_x_compatible
let mask = '[\\/%:]'
else
let mask = '[\\/%]'
endif
return substitute(a:path, mask, '\=printf("%%%x", char2nr(submatch(0)))', 'g')
endfunction
function! xolox#misc#path#decode(encoded_path) " {{{1
" Decode a pathname previously encoded with `xolox#misc#path#encode()`.
return substitute(a:encoded_path, '%\(\x\x\?\)', '\=nr2char("0x" . submatch(1))', 'g')
endfunction
" xolox#misc#path#equals(a, b) - Check whether two pathnames point to the same file. {{{1
if s:windows_compatible
function! xolox#misc#path#equals(a, b)
return a:a ==? a:b || xolox#misc#path#absolute(a:a) ==? xolox#misc#path#absolute(a:b)
endfunction
else
function! xolox#misc#path#equals(a, b)
return a:a ==# a:b || xolox#misc#path#absolute(a:a) ==# xolox#misc#path#absolute(a:b)
endfunction
endif
function! xolox#misc#path#is_relative(path) " {{{1
" Returns true (1) when the pathname given as the first argument is
" relative, false (0) otherwise.
if a:path =~ '^\w\+://'
return 0
elseif s:windows_compatible
return a:path !~ '^\(\w:\|[\\/]\)'
else
return a:path !~ '^/'
endif
endfunction
function! xolox#misc#path#tempdir() " {{{1
" Create a temporary directory and return the pathname of the directory.
if !exists('s:tempdir_counter')
let s:tempdir_counter = 1
endif
if exists('*mkdir')
if s:windows_compatible
let template = $TMP . '\vim_tempdir_'
elseif filewritable('/tmp') == 2
let template = '/tmp/vim_tempdir_'
endif
endif
if !exists('template')
throw "xolox#misc#path#tempdir() hasn't been implemented on your platform!"
endif
while 1
let directory = template . s:tempdir_counter
try
call mkdir(directory, '', 0700)
return directory
catch /^Vim\%((\a\+)\)\=:E739/
" Keep looking for a non-existing directory.
endtry
let s:tempdir_counter += 1
endwhile
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,69 @@
" String handling.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 23, 2013
" URL: http://peterodding.com/code/vim/misc/
function! xolox#misc#str#slug(s) " {{{1
" Convert a string to a "slug" - something that can be safely used in
" filenames and URLs without worrying about quoting/escaping of special
" characters.
return join(split(tolower(a:s), '\W\+'), '-')
endfunction
function! xolox#misc#str#ucfirst(s) " {{{1
" Uppercase the first character in a string (the first argument).
return substitute(a:s, '^.', '\U\0', '')
endfunction
function! xolox#misc#str#compact(s) " {{{1
" Compact whitespace in a string (the first argument).
return join(split(a:s), " ")
endfunction
function! xolox#misc#str#trim(s) " {{{1
" Trim all whitespace from the start and end of a string (the first
" argument).
return substitute(a:s, '^\_s*\(.\{-}\)\_s*$', '\1', '')
endfunction
function! xolox#misc#str#indent(text, num_spaces) " {{{1
" Indent all lines in a multi-line string (the first argument) with a
" specific number of *space characters* (the second argument, an integer).
let lines = split(a:text, "\n")
let indent = repeat(' ', a:num_spaces)
let [idx, limit] = [0, len(lines)]
while idx < limit
if lines[idx] =~ '\S'
let lines[idx] = indent . lines[idx]
endif
let idx += 1
endwhile
return join(lines, "\n")
endfunction
function! xolox#misc#str#dedent(text) " {{{1
" Remove common whitespace from a multi line string.
let lines = split(a:text, "\n")
" First we need to determine the common indentation of all non-empty lines.
for line in lines
if line =~ '\S'
let indent = matchstr(line, '^\s*')
if !exists('common_indent')
let common_indent = indent
elseif len(indent) < len(common_indent)
let common_indent = indent
endif
endif
endfor
" Now we will strip the common indentation.
let [idx, limit] = [0, len(lines)]
let pattern = '^' . common_indent
while idx < limit
let lines[idx] = substitute(lines[idx], pattern, '', '')
let idx += 1
endwhile
return join(lines, "\n")
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,125 @@
" Test runner & infrastructure for Vim plug-ins.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 2, 2013
" URL: http://peterodding.com/code/vim/misc/
"
" The Vim auto-load script `autoload/xolox/misc/test.vim` contains
" infrastructure that can be used to run an automated Vim plug-in test suite.
" It provides a framework for running test functions, keeping track of the
" test status, making assertions and reporting test results to the user.
" The process handling tests cannot use the built-in "echo" command from the
" Windows shell because it has way too much idiosyncrasies for me to put up
" with. Seriously. Instead I'm using an "echo.exe" from the UnxUtils project.
if xolox#misc#os#is_win()
let g:xolox#misc#test#echo = xolox#misc#escape#shell(xolox#misc#path#merge(expand('<sfile>:p:h'), 'echo.exe'))
else
let g:xolox#misc#test#echo = 'echo'
endif
function! xolox#misc#test#reset() " {{{1
" Reset counters for executed tests and passed/failed assertions.
let s:num_executed = 0
let s:num_passed = 0
let s:num_failed = 0
let s:tests_started_at = xolox#misc#timer#start()
endfunction
function! xolox#misc#test#summarize() " {{{1
" Print a summary of test results, to be interpreted interactively.
call s:delimit_output()
call xolox#misc#timer#force("Took %s to run %s: %s passed, %s failed.",
\ s:tests_started_at,
\ xolox#misc#format#pluralize(s:num_executed, 'test', 'tests'),
\ xolox#misc#format#pluralize(s:num_passed, 'assertion', 'assertions'),
\ xolox#misc#format#pluralize(s:num_failed, 'assertion', 'assertions'))
endfunction
function! xolox#misc#test#wrap(function) " {{{1
" Call a function in a try/catch block and prevent exceptions from bubbling.
" The name of the function should be passed as the first and only argument;
" it should be a string containing the name of a Vim auto-load function.
let num_failed = s:num_failed
try
if s:num_passed + s:num_failed > 0
call s:delimit_output()
endif
let test_name = split(a:function, '#')[-1]
let test_name = substitute(test_name, '_', ' ', 'g')
let test_name = substitute(test_name, '^.', '\U\0', '')
call xolox#misc#msg#info("Running test #%i: %s", s:num_executed + 1, test_name)
call call(a:function, [])
catch
call xolox#misc#msg#warn("Test %s raised exception:", a:function)
call xolox#misc#msg#warn("%s", v:exception)
call xolox#misc#msg#warn("(at %s)", v:throwpoint)
if num_failed == s:num_failed
" Make sure exceptions are counted as failures, but don't inflate the
" number of failed assertions when it's not needed (it can produce
" confusing test output).
call xolox#misc#test#failed()
endif
endtry
let s:num_executed += 1
endfunction
function! xolox#misc#test#passed() " {{{1
" Record a test which succeeded.
let s:num_passed += 1
call s:print_feedback()
endfunction
function! xolox#misc#test#failed() " {{{1
" Record a test which failed.
let s:num_failed += 1
call s:print_feedback()
endfunction
function! s:delimit_output() " {{{1
" Print a delimiter between output of tests.
call xolox#misc#msg#info("%s", repeat("-", 40))
endfunction
function! s:print_feedback() " {{{1
" Let the user know the status of the test suite.
call xolox#misc#msg#info("Test status: %s passed, %s failed ..",
\ xolox#misc#format#pluralize(s:num_passed, 'assertion', 'assertions'),
\ xolox#misc#format#pluralize(s:num_failed, 'assertion', 'assertions'))
endfunction
function! xolox#misc#test#assert_true(expr) " {{{1
" Check whether an expression is true.
if a:expr
call xolox#misc#test#passed()
else
call xolox#misc#test#failed()
let msg = "Expected value to be true, got %s instead"
throw printf(msg, string(a:expr))
endif
endfunction
function! xolox#misc#test#assert_equals(expected, received) " {{{1
" Check whether two values are the same.
call xolox#misc#test#assert_same_type(a:expected, a:received)
if a:expected == a:received
call xolox#misc#test#passed()
else
call xolox#misc#test#failed()
let msg = "Expected value %s, received value %s!"
throw printf(msg, string(a:expected), string(a:received))
endif
endfunction
function! xolox#misc#test#assert_same_type(expected, received) " {{{1
" Check whether two values are of the same type.
if type(a:expected) == type(a:received)
call xolox#misc#test#passed()
else
call xolox#misc#test#failed()
let msg = "Expected value of same type as %s, got value %s!"
throw printf(msg, string(a:expected), string(a:received))
endif
endfunction
call xolox#misc#test#reset()

View File

@ -0,0 +1,301 @@
" Tests for the miscellaneous Vim scripts.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June , 2013
" URL: http://peterodding.com/code/vim/misc/
"
" The Vim auto-load script `autoload/xolox/misc/tests.vim` contains the
" automated test suite of the miscellaneous Vim scripts. Right now the
" coverage is not very high yet, but this will improve over time.
let s:use_dll = 0
let s:can_use_dll = xolox#misc#os#can_use_dll()
function! xolox#misc#tests#run() " {{{1
" Run the automated test suite of the miscellaneous Vim scripts. To be used
" interactively. Intended to be safe to execute irrespective of context.
call xolox#misc#test#reset()
" Run the tests.
call s:test_string_escaping()
call s:test_list_handling()
call s:test_option_handling()
call s:test_command_execution()
call s:test_string_handling()
call s:test_version_handling()
" Report a short summary to the user.
call xolox#misc#test#summarize()
endfunction
function! s:wrap_exec_test(function)
" Wrapper for tests that use xolox#misc#os#exec(). If we're on Windows and
" the vim-shell plug-in is installed, the test will be run twice: Once with
" vim-shell disabled and once with vim-shell enabled. This makes sure that
" all code paths are tested as much as possible.
call xolox#misc#msg#debug("vim-misc %s: Temporarily disabling vim-shell so we can test vim-misc ..", g:xolox#misc#version)
let s:use_dll = 0
call xolox#misc#test#wrap(a:function)
if s:can_use_dll
call xolox#misc#msg#debug("vim-misc %s: Re-enabling vim-shell so we can test that as well ..", g:xolox#misc#version)
let s:use_dll = 1
call xolox#misc#test#wrap(a:function)
endif
endfunction
" Tests for autoload/xolox/misc/escape.vim {{{1
function! s:test_string_escaping()
call xolox#misc#test#wrap('xolox#misc#tests#pattern_escaping')
call xolox#misc#test#wrap('xolox#misc#tests#substitute_escaping')
call s:wrap_exec_test('xolox#misc#tests#shell_escaping')
endfunction
function! xolox#misc#tests#pattern_escaping() " {{{2
" Test escaping of regular expression patterns with
" `xolox#misc#escape#pattern()`.
call xolox#misc#test#assert_equals('foo [qux] baz', substitute('foo [bar] baz', xolox#misc#escape#pattern('[bar]'), '[qux]', 'g'))
call xolox#misc#test#assert_equals('also very nasty', substitute('also ~ nasty', xolox#misc#escape#pattern('~'), 'very', 'g'))
endfunction
function! xolox#misc#tests#substitute_escaping() " {{{2
" Test escaping of substitution strings with
" `xolox#misc#escape#substitute()`.
call xolox#misc#test#assert_equals('nasty & tricky stuff', substitute('tricky stuff', 'tricky', xolox#misc#escape#substitute('nasty & tricky'), 'g'))
endfunction
function! xolox#misc#tests#shell_escaping() " {{{2
" Test escaping of shell arguments with `xolox#misc#escape#shell()`.
let expected_value = 'this < is > a | very " scary ^ string '' indeed'
let result = xolox#misc#os#exec({'command': g:xolox#misc#test#echo . ' ' . xolox#misc#escape#shell(expected_value), 'use_dll': s:use_dll})
call xolox#misc#test#assert_equals(0, result['exit_code'])
call xolox#misc#test#assert_equals(0, result['exit_code'])
call xolox#misc#test#assert_same_type([], result['stdout'])
call xolox#misc#test#assert_equals(1, len(result['stdout']))
" XXX On Windows using system() there's a trailing space I can't explain.
" However the point of this test was to show that all characters pass
" through unharmed, so for now I'll just ignore the space :-)
call xolox#misc#test#assert_equals(expected_value, xolox#misc#str#trim(result['stdout'][0]))
endfunction
" Tests for autoload/xolox/misc/list.vim {{{1
function! s:test_list_handling()
call xolox#misc#test#wrap('xolox#misc#tests#making_a_list_unique')
call xolox#misc#test#wrap('xolox#misc#tests#binary_insertion')
endfunction
function! xolox#misc#tests#making_a_list_unique() " {{{2
" Test removing of duplicate values from lists with
" `xolox#misc#list#unique()`.
call xolox#misc#test#assert_equals([1, 2, 3, 4, 5], xolox#misc#list#unique([1, 1, 2, 3, 3, 4, 5, 5]))
" Should work for strings just as well. And it should preserve order.
call xolox#misc#test#assert_equals(['a', 'b', 'c'], xolox#misc#list#unique(['a', 'a', 'b', 'b', 'c']))
" Just to make sure that lists without duplicate values pass through unharmed.
call xolox#misc#test#assert_equals([1, 2, 3, 4, 5], xolox#misc#list#unique([1, 2, 3, 4, 5]))
endfunction
function! xolox#misc#tests#binary_insertion() " {{{2
" Test the binary insertion algorithm implemented in
" `xolox#misc#list#binsert()`.
let list = ['a', 'B', 'e']
" Insert 'c' (should end up between 'B' and 'e').
call xolox#misc#list#binsert(list, 'c', 1)
call xolox#misc#test#assert_equals(['a', 'B', 'c', 'e'], list)
" Insert 'D' (should end up between 'c' and 'e').
call xolox#misc#list#binsert(list, 'D', 1)
call xolox#misc#test#assert_equals(['a', 'B', 'c', 'D', 'e'], list)
" Insert 'f' (should end up after 'e', at the end).
call xolox#misc#list#binsert(list, 'f', 1)
call xolox#misc#test#assert_equals(['a', 'B', 'c', 'D', 'e', 'f'], list)
endfunction
" Tests for autoload/xolox/misc/option.vim {{{1
function! s:test_option_handling()
call xolox#misc#test#wrap('xolox#misc#tests#getting_configuration_options')
call xolox#misc#test#wrap('xolox#misc#tests#splitting_of_multi_valued_options')
call xolox#misc#test#wrap('xolox#misc#tests#joining_of_multi_valued_options')
endfunction
function! xolox#misc#tests#getting_configuration_options() " {{{2
" Test getting of scoped plug-in configuration "options" with
" `xolox#misc#option#get()`.
let magic_name = 'a_variable_that_none_would_use'
call xolox#misc#test#assert_equals(0, xolox#misc#option#get(magic_name))
" Test custom default values.
call xolox#misc#test#assert_equals([], xolox#misc#option#get(magic_name, []))
" Set the option as a global variable.
let global_value = 'global variable'
let g:{magic_name} = global_value
call xolox#misc#test#assert_equals(global_value, xolox#misc#option#get(magic_name))
" Set the option as a buffer local variable, thereby shadowing the global.
let local_value = 'buffer local variable'
let b:{magic_name} = local_value
call xolox#misc#test#assert_equals(local_value, xolox#misc#option#get(magic_name))
" Sanity check that it's possible to unshadow as well.
unlet b:{magic_name}
call xolox#misc#test#assert_equals(global_value, xolox#misc#option#get(magic_name))
" Cleanup after ourselves.
unlet g:{magic_name}
call xolox#misc#test#assert_equals(0, xolox#misc#option#get(magic_name))
endfunction
function! xolox#misc#tests#splitting_of_multi_valued_options() " {{{2
" Test splitting of multi-valued Vim options with
" `xolox#misc#option#split()`.
call xolox#misc#test#assert_equals([], xolox#misc#option#split(''))
call xolox#misc#test#assert_equals(['just one value'], xolox#misc#option#split('just one value'))
call xolox#misc#test#assert_equals(['value 1', 'value 2'], xolox#misc#option#split('value 1,value 2'))
call xolox#misc#test#assert_equals(['value 1', 'value 2', 'tricky,value'], xolox#misc#option#split('value 1,value 2,tricky\,value'))
endfunction
function! xolox#misc#tests#joining_of_multi_valued_options() " {{{2
" Test joining of multi-valued Vim options with `xolox#misc#option#join()`.
call xolox#misc#test#assert_equals('', xolox#misc#option#join([]))
call xolox#misc#test#assert_equals('just one value', xolox#misc#option#join(['just one value']))
call xolox#misc#test#assert_equals('value 1,value 2', xolox#misc#option#join(['value 1', 'value 2']))
call xolox#misc#test#assert_equals('value 1,value 2,tricky\,value', xolox#misc#option#join(['value 1', 'value 2', 'tricky,value']))
endfunction
" Tests for autoload/xolox/misc/os.vim {{{1
function! s:test_command_execution()
call xolox#misc#test#wrap('xolox#misc#tests#finding_vim_on_the_search_path')
call s:wrap_exec_test('xolox#misc#tests#synchronous_command_execution')
call s:wrap_exec_test('xolox#misc#tests#synchronous_command_execution_with_stderr')
call s:wrap_exec_test('xolox#misc#tests#synchronous_command_execution_with_raising_of_errors')
call s:wrap_exec_test('xolox#misc#tests#synchronous_command_execution_without_raising_errors')
call s:wrap_exec_test('xolox#misc#tests#asynchronous_command_execution')
endfunction
function! xolox#misc#tests#finding_vim_on_the_search_path() " {{{2
" Test looking up Vim's executable on the search path using [v:progname] []
" with `xolox#misc#os#find_vim()`.
"
" [v:progname]: http://vimdoc.sourceforge.net/htmldoc/eval.html#v:progname
let pathname = xolox#misc#os#find_vim()
call xolox#misc#test#assert_same_type('', pathname)
call xolox#misc#test#assert_true(executable(pathname))
endfunction
function! xolox#misc#tests#synchronous_command_execution() " {{{2
" Test basic functionality of synchronous command execution with
" `xolox#misc#os#exec()`.
let result = xolox#misc#os#exec({'command': printf('%s output', g:xolox#misc#test#echo), 'use_dll': s:use_dll})
call xolox#misc#test#assert_same_type({}, result)
call xolox#misc#test#assert_equals(0, result['exit_code'])
call xolox#misc#test#assert_equals(['output'], result['stdout'])
endfunction
function! xolox#misc#tests#synchronous_command_execution_with_stderr() " {{{2
" Test basic functionality of synchronous command execution with
" `xolox#misc#os#exec()` including the standard error stream (not available
" on Windows when vim-shell is not installed).
if !(xolox#misc#os#is_win() && !s:use_dll)
let result = xolox#misc#os#exec({'command': printf('%s output && %s errors >&2', g:xolox#misc#test#echo, g:xolox#misc#test#echo), 'use_dll': s:use_dll})
call xolox#misc#test#assert_same_type({}, result)
call xolox#misc#test#assert_equals(0, result['exit_code'])
call xolox#misc#test#assert_equals(['output'], result['stdout'])
call xolox#misc#test#assert_equals(['errors'], result['stderr'])
endif
endfunction
function! xolox#misc#tests#synchronous_command_execution_with_raising_of_errors() " {{{2
" Test raising of errors during synchronous command execution with
" `xolox#misc#os#exec()`.
try
call xolox#misc#os#exec({'command': 'exit 1', 'use_dll': s:use_dll})
call xolox#misc#test#assert_true(0)
catch
call xolox#misc#test#assert_true(1)
endtry
endfunction
function! xolox#misc#tests#synchronous_command_execution_without_raising_errors() " {{{2
" Test synchronous command execution without raising of errors with
" `xolox#misc#os#exec()`.
try
let result = xolox#misc#os#exec({'command': 'exit 42', 'check': 0, 'use_dll': s:use_dll})
call xolox#misc#test#assert_true(1)
call xolox#misc#test#assert_equals(42, result['exit_code'])
catch
call xolox#misc#test#assert_true(0)
endtry
endfunction
function! xolox#misc#tests#asynchronous_command_execution() " {{{2
" Test the basic functionality of asynchronous command execution with
" `xolox#misc#os#exec()`. This runs the external command `mkdir` and tests
" that the side effect of creating the directory takes place. This might
" seem like a peculiar choice, but it's one of the few 100% portable
" commands (Windows + UNIX) that doesn't involve input/output streams.
let temporary_directory = xolox#misc#path#tempdir()
let random_name = printf('%i', localtime())
let expected_directory = xolox#misc#path#merge(temporary_directory, random_name)
let command = 'mkdir ' . xolox#misc#escape#shell(expected_directory)
let result = xolox#misc#os#exec({'command': command, 'async': 1, 'use_dll': s:use_dll})
call xolox#misc#test#assert_same_type({}, result)
" Make sure the command is really executed.
let timeout = localtime() + 30
while !isdirectory(expected_directory) && localtime() < timeout
sleep 500 m
endwhile
call xolox#misc#test#assert_true(isdirectory(expected_directory))
endfunction
" Tests for autoload/xolox/misc/str.vim {{{1
function! s:test_string_handling()
call xolox#misc#test#wrap('xolox#misc#tests#string_case_transformation')
call xolox#misc#test#wrap('xolox#misc#tests#string_whitespace_compaction')
call xolox#misc#test#wrap('xolox#misc#tests#string_whitespace_trimming')
call xolox#misc#test#wrap('xolox#misc#tests#multiline_string_dedent')
endfunction
function! xolox#misc#tests#string_case_transformation()
" Test string case transformation with `xolox#misc#str#ucfirst()`.
call xolox#misc#test#assert_equals('Foo', xolox#misc#str#ucfirst('foo'))
call xolox#misc#test#assert_equals('BAR', xolox#misc#str#ucfirst('BAR'))
endfunction
function! xolox#misc#tests#string_whitespace_compaction()
" Test compaction of whitespace in strings with `xolox#misc#str#compact()`.
call xolox#misc#test#assert_equals('foo bar baz', xolox#misc#str#compact(' foo bar baz '))
call xolox#misc#test#assert_equals('test', xolox#misc#str#compact("\ntest "))
endfunction
function! xolox#misc#tests#string_whitespace_trimming()
" Test trimming of whitespace in strings with `xolox#misc#str#trim()`.
call xolox#misc#test#assert_equals('foo bar baz', xolox#misc#str#trim("\nfoo bar baz "))
endfunction
function! xolox#misc#tests#multiline_string_dedent()
" Test dedenting of multi-line strings with `xolox#misc#str#dedent()`.
call xolox#misc#test#assert_equals('test', xolox#misc#str#dedent(' test'))
call xolox#misc#test#assert_equals("1\n\n2", xolox#misc#str#dedent(" 1\n\n 2"))
call xolox#misc#test#assert_equals("1\n\n 2", xolox#misc#str#dedent(" 1\n\n 2"))
endfunction
" Tests for autoload/xolox/misc/version.vim {{{1
function! s:test_version_handling()
call xolox#misc#test#wrap('xolox#misc#tests#version_string_parsing')
call xolox#misc#test#wrap('xolox#misc#tests#version_string_comparison')
endfunction
function! xolox#misc#tests#version_string_parsing() " {{{2
" Test parsing of version strings with `xolox#misc#version#parse()`.
call xolox#misc#test#assert_equals([1], xolox#misc#version#parse('1'))
call xolox#misc#test#assert_equals([1, 5], xolox#misc#version#parse('1.5'))
call xolox#misc#test#assert_equals([1, 22, 3333, 44444, 55555], xolox#misc#version#parse('1.22.3333.44444.55555'))
call xolox#misc#test#assert_equals([1, 5], xolox#misc#version#parse('1x.5y'))
endfunction
function! xolox#misc#tests#version_string_comparison() " {{{2
" Test comparison of version strings with `xolox#misc#version#at_least()`.
call xolox#misc#test#assert_true(xolox#misc#version#at_least('1', '1'))
call xolox#misc#test#assert_true(!xolox#misc#version#at_least('1', '0'))
call xolox#misc#test#assert_true(xolox#misc#version#at_least('1', '2'))
call xolox#misc#test#assert_true(xolox#misc#version#at_least('1.2.3', '1.2.3'))
call xolox#misc#test#assert_true(!xolox#misc#version#at_least('1.2.3', '1.2'))
call xolox#misc#test#assert_true(xolox#misc#version#at_least('1.2.3', '1.2.4'))
endfunction

View File

@ -0,0 +1,62 @@
" Timing of long during operations.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 2, 2013
" URL: http://peterodding.com/code/vim/misc/
if !exists('g:timer_enabled')
let g:timer_enabled = 0
endif
if !exists('g:timer_verbosity')
let g:timer_verbosity = 1
endif
let s:has_reltime = has('reltime')
let s:unique_marker = 'xolox#misc#timer#value'
function! xolox#misc#timer#start() " {{{1
" Start a timer. This returns a list which can later be passed to
" `xolox#misc#timer#stop()`.
return [s:unique_marker, s:has_reltime ? reltime() : localtime()]
endfunction
function! xolox#misc#timer#stop(...) " {{{1
" Show a formatted debugging message to the user, if the user has enabled
" increased verbosity by setting Vim's ['verbose'] [verbose] option to one
" (1) or higher.
"
" This function has the same argument handling as Vim's [printf()] [printf]
" function with one difference: At the point where you want the elapsed time
" to be embedded, you write `%s` and you pass the list returned by
" `xolox#misc#timer#start()` as an argument.
"
" [verbose]: http://vimdoc.sourceforge.net/htmldoc/options.html#'verbose'
" [printf]: http://vimdoc.sourceforge.net/htmldoc/eval.html#printf()
if (g:timer_enabled || &verbose >= g:timer_verbosity)
call call('xolox#misc#msg#info', map(copy(a:000), 's:convert_value(v:val)'))
endif
endfunction
function! xolox#misc#timer#force(...) " {{{1
" Show a formatted message to the user. This function has the same argument
" handling as Vim's [printf()] [printf] function with one difference: At the
" point where you want the elapsed time to be embedded, you write `%s` and
" you pass the list returned by `xolox#misc#timer#start()` as an argument.
call call('xolox#misc#msg#info', map(copy(a:000), 's:convert_value(v:val)'))
endfunction
function! s:convert_value(value) " {{{1
if type(a:value) == type([]) && len(a:value) == 2 && a:value[0] == s:unique_marker
if s:has_reltime
let ts = xolox#misc#str#trim(reltimestr(reltime(a:value[1])))
else
let ts = localtime() - a:value[1]
endif
return xolox#misc#format#timestamp(ts)
else
return a:value
endif
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,34 @@
" Version string handling.
"
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 22, 2013
" URL: http://peterodding.com/code/vim/misc/
function! xolox#misc#version#parse(version_string)
" Convert a version string to a list of integers.
let result = map(split(a:version_string, '\.'), 'v:val + 0')
call xolox#misc#msg#debug("vim-misc %s: Parsed version string %s into %s.", g:xolox#misc#version, string(a:version_string), string(result))
return result
endfunction
function! xolox#misc#version#at_least(expected_version, available_version)
" Check whether the second version string is equal to or greater than the
" first version string. Returns 1 (true) when it is, 0 (false) otherwise.
let expected_version = xolox#misc#version#parse(a:expected_version)
let available_version = xolox#misc#version#parse(a:available_version)
for idx in range(max([len(expected_version), len(available_version)]))
let expected_number = get(expected_version, idx, 0)
let available_number = get(available_version, idx, 0)
if available_number > expected_number
call xolox#misc#msg#debug("vim-misc %s: Available version (%s) is higher than expected version (%s).", g:xolox#misc#version, a:available_version, a:expected_version)
return 1
elseif available_number < expected_number
call xolox#misc#msg#debug("vim-misc %s: Available version (%s) is lower than expected version (%s).", g:xolox#misc#version, a:available_version, a:expected_version)
return 0
endif
endfor
call xolox#misc#msg#debug("vim-misc %s: Available version (%s) is equal to expected version (%s).", g:xolox#misc#version, a:available_version, a:expected_version)
return 1
endfunction
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,866 @@
*misc.txt* Miscellaneous auto-load Vim scripts
===============================================================================
Contents ~
1. Introduction |misc-introduction|
2. Installation |misc-installation|
3. Function documentation |misc-function-documentation|
1. Handling of special buffers |misc-handling-of-special-buffers|
1. The |xolox#misc#buffer#is_empty()| function
2. The |xolox#misc#buffer#prepare()| function
3. The |xolox#misc#buffer#lock()| function
4. The |xolox#misc#buffer#unlock()| function
2. Tab completion for user defined commands |misc-tab-completion-for-user-defined-commands|
1. The |xolox#misc#complete#keywords()| function
3. String escaping functions |misc-string-escaping-functions|
1. The |xolox#misc#escape#pattern()| function
2. The |xolox#misc#escape#substitute()| function
3. The |xolox#misc#escape#shell()| function
4. Human friendly string formatting for Vim |misc-human-friendly-string-formatting-for-vim|
1. The |xolox#misc#format#pluralize()| function
2. The |xolox#misc#format#timestamp()| function
5. List handling functions |misc-list-handling-functions|
1. The |xolox#misc#list#unique()| function
2. The |xolox#misc#list#binsert()| function
6. Functions to interact with the user |misc-functions-to-interact-with-user|
1. The |xolox#misc#msg#info()| function
2. The |xolox#misc#msg#warn()| function
3. The |xolox#misc#msg#debug()| function
7. Integration between Vim and its environment |misc-integration-between-vim-its-environment|
1. The |xolox#misc#open#file()| function
2. The |xolox#misc#open#url()| function
8. Vim and plug-in option handling |misc-vim-plug-in-option-handling|
1. The |xolox#misc#option#get()| function
2. The |xolox#misc#option#split()| function
3. The |xolox#misc#option#join()| function
4. The |xolox#misc#option#split_tags()| function
5. The |xolox#misc#option#join_tags()| function
6. The |xolox#misc#option#eval_tags()| function
9. Operating system interfaces |misc-operating-system-interfaces|
1. The |xolox#misc#os#is_mac()| function
2. The |xolox#misc#os#is_win()| function
3. The |xolox#misc#os#find_vim()| function
4. The |xolox#misc#os#exec()| function
5. The |xolox#misc#os#can_use_dll()| function
10. Pathname manipulation functions |misc-pathname-manipulation-functions|
1. The |xolox#misc#path#which()| function
2. The |xolox#misc#path#split()| function
3. The |xolox#misc#path#join()| function
4. The |xolox#misc#path#directory_separator()| function
5. The |xolox#misc#path#absolute()| function
6. The |xolox#misc#path#relative()| function
7. The |xolox#misc#path#merge()| function
8. The |xolox#misc#path#commonprefix()| function
9. The |xolox#misc#path#encode()| function
10. The |xolox#misc#path#decode()| function
11. The |xolox#misc#path#is_relative()| function
12. The |xolox#misc#path#tempdir()| function
11. String handling |misc-string-handling|
1. The |xolox#misc#str#slug()| function
2. The |xolox#misc#str#ucfirst()| function
3. The |xolox#misc#str#compact()| function
4. The |xolox#misc#str#trim()| function
5. The |xolox#misc#str#indent()| function
6. The |xolox#misc#str#dedent()| function
12. Test runner & infrastructure for Vim plug-ins |misc-test-runner-infrastructure-for-vim-plug-ins|
1. The |xolox#misc#test#reset()| function
2. The |xolox#misc#test#summarize()| function
3. The |xolox#misc#test#wrap()| function
4. The |xolox#misc#test#passed()| function
5. The |xolox#misc#test#failed()| function
6. The |xolox#misc#test#assert_true()| function
7. The |xolox#misc#test#assert_equals()| function
8. The |xolox#misc#test#assert_same_type()| function
13. Tests for the miscellaneous Vim scripts |tests-for-miscellaneous-vim-scripts|
1. The |xolox#misc#tests#run()| function
2. The |xolox#misc#tests#pattern_escaping()| function
3. The |xolox#misc#tests#substitute_escaping()| function
4. The |xolox#misc#tests#shell_escaping()| function
5. The |xolox#misc#tests#making_a_list_unique()| function
6. The |xolox#misc#tests#binary_insertion()| function
7. The |xolox#misc#tests#getting_configuration_options()| function
8. The |xolox#misc#tests#splitting_of_multi_valued_options()| function
9. The |xolox#misc#tests#joining_of_multi_valued_options()| function
10. The |xolox#misc#tests#finding_vim_on_the_search_path()| function
11. The |xolox#misc#tests#synchronous_command_execution()| function
12. The |xolox#misc#tests#synchronous_command_execution_with_stderr()| function
13. The |xolox#misc#tests#synchronous_command_execution_with_raising_of_errors()|
function
14. The |xolox#misc#tests#synchronous_command_execution_without_raising_errors()|
function
15. The |xolox#misc#tests#asynchronous_command_execution()| function
16. The |xolox#misc#tests#string_case_transformation()| function
17. The |xolox#misc#tests#string_whitespace_compaction()| function
18. The |xolox#misc#tests#string_whitespace_trimming()| function
19. The |xolox#misc#tests#multiline_string_dedent()| function
20. The |xolox#misc#tests#version_string_parsing()| function
21. The |xolox#misc#tests#version_string_comparison()| function
14. Timing of long during operations |misc-timing-of-long-during-operations|
1. The |xolox#misc#timer#start()| function
2. The |xolox#misc#timer#stop()| function
3. The |xolox#misc#timer#force()| function
15. Version string handling |misc-version-string-handling|
1. The |xolox#misc#version#parse()| function
2. The |xolox#misc#version#at_least()| function
4. Contact |misc-contact|
5. License |misc-license|
6. References |misc-references|
===============================================================================
*misc-introduction*
Introduction ~
The vim-misc plug-in contains Vim scripts that are used by most of the Vim
plug-ins I've written [1] yet don't really belong with any single one of the
plug-ins. Basically it's an extended standard library of Vim script functions
that I wrote during the development of my Vim profile and plug-ins.
In the past these scripts were bundled with each plug-in, however that turned
out to be a maintenance nightmare for me. That's why the miscellaneous scripts
are now a proper plug-in with their own page on Vim Online.
Because the miscellaneous scripts are no longer bundled with my Vim plug-ins,
users are now required to install the miscellaneous scripts separately. This is
unfortunate for users who are upgrading from a previous release that did bundle
the miscellaneous scripts, but I don't see any way around this. Sorry!
===============================================================================
*misc-installation*
Installation ~
Unzip the most recent ZIP archive [2] file inside your Vim profile directory
(usually this is '~/.vim' on UNIX and '%USERPROFILE%\vimfiles' on Windows),
restart Vim and execute the command ':helptags ~/.vim/doc' (use ':helptags
~\vimfiles\doc' instead on Windows).
If you prefer you can also use Pathogen [3], Vundle [4] or a similar tool to
install & update the plug-in using a local clone of the git repository.
===============================================================================
*misc-function-documentation*
Function documentation ~
Below is the documentation for the functions included in the miscellaneous
scripts. Anyone is free to use these functions in their own Vim profile and/or
plug-ins. I care about backwards compatibility so won't break it without a good
reason to do so.
For those who are curious: The function descriptions given below were extracted
from the source code of the miscellaneous scripts using the Python module
'vimdoctool.py' included in vim-tools [5].
The documentation of the 80 functions below was extracted from 15 Vim scripts
on July 20, 2013 at 10:41.
-------------------------------------------------------------------------------
*misc-handling-of-special-buffers*
Handling of special buffers ~
The functions defined here make it easier to deal with special Vim buffers that
contain text generated by a Vim plug-in. For example my vim-notes plug-in [6]
generates several such buffers:
- :RecentNotes [7] lists recently modified notes
- :ShowTaggedNotes [8] lists notes grouped by tags
- etc.
Because the text in these buffers is generated, Vim shouldn't bother with swap
files and it should never prompt the user whether to save changes to the
generated text.
-------------------------------------------------------------------------------
The *xolox#misc#buffer#is_empty()* function
Checks if the current buffer is an empty, unchanged buffer which can be reused.
Returns 1 if an empty buffer is found, 0 otherwise.
-------------------------------------------------------------------------------
The *xolox#misc#buffer#prepare()* function
Open a special buffer, i.e. a buffer that will hold generated contents, not
directly edited by the user. The buffer can be customized by passing a
dictionary with the following key/value pairs as the first argument:
- **name** (required): The base name of the buffer (i.e. the base name of the
file loaded in the buffer, even though it isn't really a file and nothing
is really 'loaded' :-)
- **path** (required): The pathname of the buffer. May be relevant if |:lcd|
or |'autochdir'| is being used.
-------------------------------------------------------------------------------
The *xolox#misc#buffer#lock()* function
Lock a special buffer so that its contents can no longer be edited.
-------------------------------------------------------------------------------
The *xolox#misc#buffer#unlock()* function
Unlock a special buffer so that its content can be updated.
-------------------------------------------------------------------------------
*misc-tab-completion-for-user-defined-commands*
Tab completion for user defined commands ~
-------------------------------------------------------------------------------
The *xolox#misc#complete#keywords()* function
This function can be used to perform keyword completion for user defined Vim
commands based on the contents of the current buffer. Here's an example of how
you would use it:
>
:command -nargs=* -complete=customlist,xolox#misc#complete#keywords MyCmd call s:MyCmd(<f-args>)
<
-------------------------------------------------------------------------------
*misc-string-escaping-functions*
String escaping functions ~
-------------------------------------------------------------------------------
The *xolox#misc#escape#pattern()* function
Takes a single string argument and converts it into a |:substitute| /
|substitute()| pattern string that matches the given string literally.
-------------------------------------------------------------------------------
The *xolox#misc#escape#substitute()* function
Takes a single string argument and converts it into a |:substitute| /
|substitute()| replacement string that inserts the given string literally.
-------------------------------------------------------------------------------
The *xolox#misc#escape#shell()* function
Takes a single string argument and converts it into a quoted command line
argument.
I was going to add a long rant here about Vim's |'shellslash'| option, but
really, it won't make any difference. Let's just suffice to say that I have yet
to encounter a single person out there who uses this option for its intended
purpose (running a UNIX style shell on Microsoft Windows).
-------------------------------------------------------------------------------
*misc-human-friendly-string-formatting-for-vim*
Human friendly string formatting for Vim ~
-------------------------------------------------------------------------------
The *xolox#misc#format#pluralize()* function
Concatenate a counter (the first argument, expected to be an integer) with a
singular or plural label (the second and third arguments, both expected to be
strings).
-------------------------------------------------------------------------------
The *xolox#misc#format#timestamp()* function
Format a time stamp (a string containing a formatted floating point number)
into a human friendly format, for example 70 seconds is phrased as "1 minute
and 10 seconds".
-------------------------------------------------------------------------------
*misc-list-handling-functions*
List handling functions ~
-------------------------------------------------------------------------------
The *xolox#misc#list#unique()* function
Remove duplicate values from the given list in-place (preserves order).
-------------------------------------------------------------------------------
The *xolox#misc#list#binsert()* function
Performs in-place binary insertion, which depending on your use case can be
more efficient than calling Vim's |sort()| function after each insertion (in
cases where a single, final sort is not an option). Expects three arguments:
1. A list
2. A value to insert
3. 1 (true) when case should be ignored, 0 (false) otherwise
-------------------------------------------------------------------------------
*misc-functions-to-interact-with-user*
Functions to interact with the user ~
-------------------------------------------------------------------------------
The *xolox#misc#msg#info()* function
Show a formatted informational message to the user.
This function has the same argument handling as Vim's |printf()| function with
one notable difference: Any arguments which are not numbers or strings are
coerced to strings using Vim's |string()| function.
In the case of |xolox#misc#msg#info()|, automatic string coercion simply makes
the function a bit easier to use.
-------------------------------------------------------------------------------
The *xolox#misc#msg#warn()* function
Show a formatted warning message to the user.
This function has the same argument handling as the |xolox#misc#msg#info()|
function.
-------------------------------------------------------------------------------
The *xolox#misc#msg#debug()* function
Show a formatted debugging message to the user, _if the user has enabled
increased verbosity by setting Vim's |'verbose'| option to one (1) or higher_.
This function has the same argument handling as the |xolox#misc#msg#info()|
function.
In the case of |xolox#misc#msg#debug()|, automatic string coercion provides
lazy evaluation in the sense that complex data structures are only converted to
strings when the user has enabled increased verbosity.
-------------------------------------------------------------------------------
*misc-integration-between-vim-its-environment*
Integration between Vim and its environment ~
-------------------------------------------------------------------------------
The *xolox#misc#open#file()* function
Given a pathname or URL as the first argument, this opens the file with the
program associated with the file type. So for example a text file might open in
Vim, an '*.html' file would probably open in your web browser and a media file
would open in a media player.
This should work on Windows, Mac OS X and most Linux distributions. If this
fails to find a file association, you can pass one or more external commands to
try as additional arguments. For example:
>
:call xolox#misc#open#file('/path/to/my/file', 'firefox', 'google-chrome')
<
This generally shouldn't be necessary but it might come in handy now and then.
-------------------------------------------------------------------------------
The *xolox#misc#open#url()* function
Given a URL as the first argument, this opens the URL in your preferred or best
available web browser:
- In GUI environments a graphical web browser will open (or a new tab will be
created in an existing window)
- In console Vim without a GUI environment, when you have any of 'lynx',
'links' or 'w3m' installed it will launch a command line web browser in
front of Vim (temporarily suspending Vim)
-------------------------------------------------------------------------------
*misc-vim-plug-in-option-handling*
Vim and plug-in option handling ~
-------------------------------------------------------------------------------
The *xolox#misc#option#get()* function
Expects one or two arguments: 1. The name of a variable and 2. the default
value if the variable does not exist.
Returns the value of the variable from a buffer local variable, global variable
or the default value, depending on which is defined.
This is used by some of my Vim plug-ins for option handling, so that users can
customize options for specific buffers.
-------------------------------------------------------------------------------
The *xolox#misc#option#split()* function
Given a multi-value Vim option like |'runtimepath'| this returns a list of
strings. For example:
>
:echo xolox#misc#option#split(&runtimepath)
['/home/peter/Projects/Vim/misc',
'/home/peter/Projects/Vim/colorscheme-switcher',
'/home/peter/Projects/Vim/easytags',
...]
<
-------------------------------------------------------------------------------
The *xolox#misc#option#join()* function
Given a list of strings like the ones returned by |xolox#misc#option#split()|,
this joins the strings together into a single value that can be used to set a
Vim option.
-------------------------------------------------------------------------------
The *xolox#misc#option#split_tags()* function
Customized version of |xolox#misc#option#split()| with specialized handling for
Vim's |'tags'| option.
-------------------------------------------------------------------------------
The *xolox#misc#option#join_tags()* function
Customized version of |xolox#misc#option#join()| with specialized handling for
Vim's |'tags'| option.
-------------------------------------------------------------------------------
The *xolox#misc#option#eval_tags()* function
Evaluate Vim's |'tags'| option without looking at the file system, i.e. this
will report tags files that don't exist yet. Expects the value of the |'tags'|
option as the first argument. If the optional second argument is 1 (true) only
the first match is returned, otherwise (so by default) a list with all matches
is returned.
-------------------------------------------------------------------------------
*misc-operating-system-interfaces*
Operating system interfaces ~
-------------------------------------------------------------------------------
The *xolox#misc#os#is_mac()* function
Returns 1 (true) when on Mac OS X, 0 (false) otherwise. You would expect this
to simply check the Vim feature list, but for some obscure reason the
'/usr/bin/vim' included in Mac OS X (verified on version 10.7.5) returns 0
(false) in response to "has('mac')", so we check the output of 'uname' to avoid
false negatives.
-------------------------------------------------------------------------------
The *xolox#misc#os#is_win()* function
Returns 1 (true) when on Microsoft Windows, 0 (false) otherwise.
-------------------------------------------------------------------------------
The *xolox#misc#os#find_vim()* function
Returns the program name of Vim as a string. On Windows and UNIX this just
|v:progname| as an absolute pathname while on Mac OS X there is some special
magic to find MacVim's executable even though it's usually not on the
executable search path. If you want, you can override the value returned from
this function by setting the global variable 'g:xolox#misc#os#vim_progname'.
By default the choice of console Vim vs graphical Vim is made based on the
value of |v:progname|, but if you have a preference you can pass the string
'vim' or 'gvim' as the first and only argument.
-------------------------------------------------------------------------------
The *xolox#misc#os#exec()* function
Execute an external command (hiding the console on Microsoft Windows when my
vim-shell plug-in [9] is installed).
Expects a dictionary with the following key/value pairs as the first argument:
- **command** (required): The command line to execute
- **async** (optional): set this to 1 (true) to execute the command in the
background (asynchronously)
- **stdin** (optional): a string or list of strings with the input for the
external command
- **check** (optional): set this to 0 (false) to disable checking of the exit
code of the external command (by default an exception will be raised when
the command fails)
Returns a dictionary with one or more of the following key/value pairs:
- **command** (always available): the generated command line that was used to
run the external command
- **exit_code** (only in synchronous mode): the exit status of the external
command (an integer, zero on success)
- **stdout** (only in synchronous mode): the output of the command on the
standard output stream (a list of strings, one for each line)
- **stderr** (only in synchronous mode): the output of the command on the
standard error stream (as a list of strings, one for each line)
-------------------------------------------------------------------------------
The *xolox#misc#os#can_use_dll()* function
If a) we're on Microsoft Windows, b) the vim-shell plug-in is installed and c)
the compiled DLL included in vim-shell works, we can use the vim-shell plug-in
to execute external commands! Returns 1 (true) if we can use the DLL, 0 (false)
otherwise.
-------------------------------------------------------------------------------
*misc-pathname-manipulation-functions*
Pathname manipulation functions ~
-------------------------------------------------------------------------------
The *xolox#misc#path#which()* function
Scan the executable search path ('$PATH') for one or more external programs.
Expects one or more string arguments with program names. Returns a list with
the absolute pathnames of all found programs. Here's an example:
>
:echo xolox#misc#path#which('gvim', 'vim')
['/usr/local/bin/gvim',
'/usr/bin/gvim',
'/usr/local/bin/vim',
'/usr/bin/vim']
<
-------------------------------------------------------------------------------
The *xolox#misc#path#split()* function
Split a pathname (the first and only argument) into a list of pathname
components.
On Windows, pathnames starting with two slashes or backslashes are UNC paths
where the leading slashes are significant... In this case we split like this:
- Input: "'//server/share/directory'"
- Result: "['//server', 'share', 'directory']"
Everything except Windows is treated like UNIX until someone has a better
suggestion :-). In this case we split like this:
- Input: "'/foo/bar/baz'"
- Result: "['/', 'foo', 'bar', 'baz']"
To join a list of pathname components back into a single pathname string, use
the |xolox#misc#path#join()| function.
-------------------------------------------------------------------------------
The *xolox#misc#path#join()* function
Join a list of pathname components (the first and only argument) into a single
pathname string. This is the counterpart to the |xolox#misc#path#split()|
function and it expects a list of pathname components as returned by
|xolox#misc#path#split()|.
-------------------------------------------------------------------------------
The *xolox#misc#path#directory_separator()* function
Find the preferred directory separator for the platform and settings.
-------------------------------------------------------------------------------
The *xolox#misc#path#absolute()* function
Canonicalize and resolve a pathname, _regardless of whether it exists_. This is
intended to support string comparison to determine whether two pathnames point
to the same directory or file.
-------------------------------------------------------------------------------
The *xolox#misc#path#relative()* function
Make an absolute pathname (the first argument) relative to a directory (the
second argument).
-------------------------------------------------------------------------------
The *xolox#misc#path#merge()* function
Join a directory pathname and filename into a single pathname.
-------------------------------------------------------------------------------
The *xolox#misc#path#commonprefix()* function
Find the common prefix of path components in a list of pathnames.
-------------------------------------------------------------------------------
The *xolox#misc#path#encode()* function
Encode a pathname so it can be used as a filename. This uses URL encoding to
encode special characters.
-------------------------------------------------------------------------------
The *xolox#misc#path#decode()* function
Decode a pathname previously encoded with |xolox#misc#path#encode()|.
-------------------------------------------------------------------------------
The *xolox#misc#path#is_relative()* function
Returns true (1) when the pathname given as the first argument is relative,
false (0) otherwise.
-------------------------------------------------------------------------------
The *xolox#misc#path#tempdir()* function
Create a temporary directory and return the pathname of the directory.
-------------------------------------------------------------------------------
*misc-string-handling*
String handling ~
-------------------------------------------------------------------------------
The *xolox#misc#str#slug()* function
Convert a string to a "slug" - something that can be safely used in filenames
and URLs without worrying about quoting/escaping of special characters.
-------------------------------------------------------------------------------
The *xolox#misc#str#ucfirst()* function
Uppercase the first character in a string (the first argument).
-------------------------------------------------------------------------------
The *xolox#misc#str#compact()* function
Compact whitespace in a string (the first argument).
-------------------------------------------------------------------------------
The *xolox#misc#str#trim()* function
Trim all whitespace from the start and end of a string (the first argument).
-------------------------------------------------------------------------------
The *xolox#misc#str#indent()* function
Indent all lines in a multi-line string (the first argument) with a specific
number of _space characters_ (the second argument, an integer).
-------------------------------------------------------------------------------
The *xolox#misc#str#dedent()* function
Remove common whitespace from a multi line string.
-------------------------------------------------------------------------------
*misc-test-runner-infrastructure-for-vim-plug-ins*
Test runner & infrastructure for Vim plug-ins ~
The Vim auto-load script 'autoload/xolox/misc/test.vim' contains infrastructure
that can be used to run an automated Vim plug-in test suite. It provides a
framework for running test functions, keeping track of the test status, making
assertions and reporting test results to the user.
-------------------------------------------------------------------------------
The *xolox#misc#test#reset()* function
Reset counters for executed tests and passed/failed assertions.
-------------------------------------------------------------------------------
The *xolox#misc#test#summarize()* function
Print a summary of test results, to be interpreted interactively.
-------------------------------------------------------------------------------
The *xolox#misc#test#wrap()* function
Call a function in a try/catch block and prevent exceptions from bubbling. The
name of the function should be passed as the first and only argument; it should
be a string containing the name of a Vim auto-load function.
-------------------------------------------------------------------------------
The *xolox#misc#test#passed()* function
Record a test which succeeded.
-------------------------------------------------------------------------------
The *xolox#misc#test#failed()* function
Record a test which failed.
-------------------------------------------------------------------------------
The *xolox#misc#test#assert_true()* function
Check whether an expression is true.
-------------------------------------------------------------------------------
The *xolox#misc#test#assert_equals()* function
Check whether two values are the same.
-------------------------------------------------------------------------------
The *xolox#misc#test#assert_same_type()* function
Check whether two values are of the same type.
-------------------------------------------------------------------------------
*tests-for-miscellaneous-vim-scripts*
Tests for the miscellaneous Vim scripts ~
The Vim auto-load script 'autoload/xolox/misc/tests.vim' contains the automated
test suite of the miscellaneous Vim scripts. Right now the coverage is not very
high yet, but this will improve over time.
-------------------------------------------------------------------------------
The *xolox#misc#tests#run()* function
Run the automated test suite of the miscellaneous Vim scripts. To be used
interactively. Intended to be safe to execute irrespective of context.
-------------------------------------------------------------------------------
The *xolox#misc#tests#pattern_escaping()* function
Test escaping of regular expression patterns with
|xolox#misc#escape#pattern()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#substitute_escaping()* function
Test escaping of substitution strings with |xolox#misc#escape#substitute()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#shell_escaping()* function
Test escaping of shell arguments with |xolox#misc#escape#shell()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#making_a_list_unique()* function
Test removing of duplicate values from lists with |xolox#misc#list#unique()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#binary_insertion()* function
Test the binary insertion algorithm implemented in |xolox#misc#list#binsert()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#getting_configuration_options()* function
Test getting of scoped plug-in configuration "options" with
|xolox#misc#option#get()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#splitting_of_multi_valued_options()* function
Test splitting of multi-valued Vim options with |xolox#misc#option#split()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#joining_of_multi_valued_options()* function
Test joining of multi-valued Vim options with |xolox#misc#option#join()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#finding_vim_on_the_search_path()* function
Test looking up Vim's executable on the search path using |v:progname| with
|xolox#misc#os#find_vim()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#synchronous_command_execution()* function
Test basic functionality of synchronous command execution with
|xolox#misc#os#exec()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#synchronous_command_execution_with_stderr()* function
Test basic functionality of synchronous command execution with
|xolox#misc#os#exec()| including the standard error stream (not available on
Windows when vim-shell is not installed).
-------------------------------------------------------------------------------
The *xolox#misc#tests#synchronous_command_execution_with_raising_of_errors()*
function
Test raising of errors during synchronous command execution with
|xolox#misc#os#exec()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#synchronous_command_execution_without_raising_errors()*
function
Test synchronous command execution without raising of errors with
|xolox#misc#os#exec()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#asynchronous_command_execution()* function
Test the basic functionality of asynchronous command execution with
|xolox#misc#os#exec()|. This runs the external command 'mkdir' and tests that
the side effect of creating the directory takes place. This might seem like a
peculiar choice, but it's one of the few 100% portable commands (Windows +
UNIX) that doesn't involve input/output streams.
-------------------------------------------------------------------------------
The *xolox#misc#tests#string_case_transformation()* function
Test string case transformation with |xolox#misc#str#ucfirst()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#string_whitespace_compaction()* function
Test compaction of whitespace in strings with |xolox#misc#str#compact()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#string_whitespace_trimming()* function
Test trimming of whitespace in strings with |xolox#misc#str#trim()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#multiline_string_dedent()* function
Test dedenting of multi-line strings with |xolox#misc#str#dedent()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#version_string_parsing()* function
Test parsing of version strings with |xolox#misc#version#parse()|.
-------------------------------------------------------------------------------
The *xolox#misc#tests#version_string_comparison()* function
Test comparison of version strings with |xolox#misc#version#at_least()|.
-------------------------------------------------------------------------------
*misc-timing-of-long-during-operations*
Timing of long during operations ~
-------------------------------------------------------------------------------
The *xolox#misc#timer#start()* function
Start a timer. This returns a list which can later be passed to
|xolox#misc#timer#stop()|.
-------------------------------------------------------------------------------
The *xolox#misc#timer#stop()* function
Show a formatted debugging message to the user, if the user has enabled
increased verbosity by setting Vim's |'verbose'| option to one (1) or higher.
This function has the same argument handling as Vim's |printf()| function with
one difference: At the point where you want the elapsed time to be embedded,
you write '%s' and you pass the list returned by |xolox#misc#timer#start()| as
an argument.
-------------------------------------------------------------------------------
The *xolox#misc#timer#force()* function
Show a formatted message to the user. This function has the same argument
handling as Vim's |printf()| function with one difference: At the point where
you want the elapsed time to be embedded, you write '%s' and you pass the list
returned by |xolox#misc#timer#start()| as an argument.
-------------------------------------------------------------------------------
*misc-version-string-handling*
Version string handling ~
-------------------------------------------------------------------------------
The *xolox#misc#version#parse()* function
Convert a version string to a list of integers.
-------------------------------------------------------------------------------
The *xolox#misc#version#at_least()* function
Check whether the second version string is equal to or greater than the first
version string. Returns 1 (true) when it is, 0 (false) otherwise.
===============================================================================
*misc-contact*
Contact ~
If you have questions, bug reports, suggestions, etc. the author can be
contacted at peter@peterodding.com. The latest version is available at
http://peterodding.com/code/vim/misc and http://github.com/xolox/vim-misc. If
you like the script please vote for it on Vim Online [10].
===============================================================================
*misc-license*
License ~
This software is licensed under the MIT license [11]. © 2013 Peter Odding
<peter@peterodding.com>.
===============================================================================
*misc-references*
References ~
[1] http://peterodding.com/code/vim/
[2] http://peterodding.com/code/vim/downloads/misc.zip
[3] http://www.vim.org/scripts/script.php?script_id=2332
[4] https://github.com/gmarik/vundle
[5] http://peterodding.com/code/vim/tools/
[6] http://peterodding.com/code/vim/notes/
[7] http://peterodding.com/code/vim/notes/#recentnotes_command
[8] http://peterodding.com/code/vim/notes/#showtaggednotes_command
[9] http://peterodding.com/code/vim/shell/
[10] http://www.vim.org/scripts/script.php?script_id=4597
[11] http://en.wikipedia.org/wiki/MIT_License
vim: ft=help

View File

@ -0,0 +1,5 @@
doc/tags
misc/notes/index.pickle
misc/notes/recent.txt
misc/notes/tags.txt
misc/notes/user/

View File

@ -0,0 +1,13 @@
*Please note that the vim-notes plug-in requires my vim-misc plug-in which is separately distributed.*
Unzip the most recent ZIP archives of the [vim-notes] [download-notes] and [vim-misc] [download-misc] plug-ins inside your Vim profile directory (usually this is `~/.vim` on UNIX and `%USERPROFILE%\vimfiles` on Windows), restart Vim and execute the command `:helptags ~/.vim/doc` (use `:helptags ~\vimfiles\doc` instead on Windows).
If you prefer you can also use [Pathogen] [pathogen], [Vundle] [vundle] or a similar tool to install & update the [vim-notes] [github-notes] and [vim-misc] [github-misc] plug-ins using a local clone of the git repository.
[download-misc]: http://peterodding.com/code/vim/downloads/misc.zip
[download-notes]: http://peterodding.com/code/vim/downloads/notes.zip
[github-misc]: http://github.com/xolox/vim-misc
[github-notes]: http://github.com/xolox/vim-notes
[pathogen]: http://www.vim.org/scripts/script.php?script_id=2332
[vundle]: https://github.com/gmarik/vundle

View File

@ -0,0 +1,360 @@
# Easy note taking in Vim
The vim-notes plug-in for the [Vim text editor] [vim] makes it easy to manage your notes in Vim:
* **Starting a new note:** Execute the `:Note` command to create a new buffer and load the appropriate file type and syntax
* You can also start a note with Vim commands like `:edit`, `:tabedit` and `:split` by starting the filename with `note:`, as in `:edit note:todo` (the part after `note:` doesn't have to be the complete note title and if it's empty a new note will be created)
* You can start a new note with the selected text as title in the current window using the `\en` mapping or `:NoteFromSelectedText` command (there are similar mappings and commands for opening split windows and tab pages)
* **Saving notes:** Just use Vim's [:write] [write] and [:update] [update] commands, you don't need to provide a filename because it will be set based on the title (first line) of your note (you also don't need to worry about special characters, they'll be escaped)
* **Editing existing notes:** Execute `:Note anything` to edit a note containing `anything` in its title (if no notes are found a new one is created with its title set to `anything`)
* The `:Note` and `:DeleteNote` commands support tab completion of note titles
* **Deleting notes:** The `:DeleteNote` command enables you to delete the current note
* **Searching notes:** `:SearchNotes keyword …` searches for keywords and `:SearchNotes /pattern/` searches for regular expressions
* The `:SearchNotes` command supports tab completion of keywords and sorts candidates by relevance ([Levenshtein distance] [levenshtein])
* **Smart defaults:** Without an argument `:SearchNotes` searches for the word under the cursor (if the word starts with `@` that character will be included in the search, this means you can easily search for *@tagged* notes)
* **Back-references:** The `:RelatedNotes` command find all notes referencing the current file
* A [Python 2] [python] script is included that accelerates keyword searches using a keyword index
* The `:RecentNotes` command lists your notes by modification date, starting with the most recently edited note
* **Navigating between notes:** The included syntax script highlights note names as hyper links and the file type plug-in redefines [gf] [gf] to jump between notes (the [Control-w f] [ctrlwf] mapping to jump to a note in a split window and the [Control-w gf] [ctrlwgf] mapping to jump to a note in a new tab page also work)
* **Writing aids:** The included file type plug-in contains mappings for automatic curly quotes, arrows and list bullets and supports completion of note titles using Control-X Control-U and completion of tags using Control-X Control-O
* **Embedded file types:** The included syntax script supports embedded highlighting using blocks marked with `{{{type … }}}` which allows you to embed highlighted code and configuration snippets in your notes
Here's a screen shot of the syntax mode using the [Slate] [slate] color scheme and the font [Monaco] [monaco]:
![Syntax mode screen shot](http://peterodding.com/code/vim/notes/syntax.png)
## Install & usage
*Please note that the vim-notes plug-in requires my vim-misc plug-in which is separately distributed.*
Unzip the most recent ZIP archives of the [vim-notes] [download-notes] and [vim-misc] [download-misc] plug-ins inside your Vim profile directory (usually this is `~/.vim` on UNIX and `%USERPROFILE%\vimfiles` on Windows), restart Vim and execute the command `:helptags ~/.vim/doc` (use `:helptags ~\vimfiles\doc` instead on Windows). To get started execute `:Note` or `:edit note:`, this will start a new note that contains instructions on how to continue from there (and how to use the plug-in in general).
If you prefer you can also use [Pathogen] [pathogen], [Vundle] [vundle] or a similar tool to install & update the [vim-notes] [github-notes] and [vim-misc] [github-misc] plug-ins using a local clone of the git repository.
## Options
All options have reasonable defaults so if the plug-in works after installation you don't need to change any options. The options are available for people who like to customize how the plug-in works. You can set these options in your [vimrc script] [vimrc] by including a line like this:
:let g:notes_directories = ['~/Documents/Notes', '~/Dropbox/Shared Notes']
Note that after changing an option in your [vimrc script] [vimrc] you have to restart Vim for the changes to take effect.
### The `g:notes_directories` option
Your notes are stored in one or more directories. This option defines where you want to store your notes. Its value should be a list (there's an example above) with one or more pathnames. The default is a single value which depends on circumstances but should work for most people:
* If the profile directory where the plug-in is installed is writable, the directory `misc/notes/user` under the profile directory is used. This is for compatibility with [Pathogen] [pathogen]; the notes will be stored inside the plug-in's bundle.
* If the above doesn't work out, the default depends on the platform: `~/vimfiles/misc/notes/user` on Windows and `~/.vim/misc/notes/user` on other platforms.
#### Backwards compatibility
In the past the notes plug-in only supported a single directory and the corresponding option was called `g:notes_directory`. When support for multiple notes directories was introduced the option was renamed to `g:notes_directories` to reflect that the value is now a list of directory pathnames.
For backwards compatibility with old configurations (all of them as of this writing :-) the notes plug-in still uses `g:notes_directory` when it is defined (its no longer defined by the plug-in). However when the plug-in warns you to change your configuration you probably should because this compatibility will be removed at some point.
### The `g:notes_suffix` option
The suffix to add to generated filenames. The plug-in generates filenames for your notes based on the title (first line) of each note and by default these filenames don't include an extension like `.txt`. You can use this option to make the plug-in automatically append an extension without having to embed the extension in the note's title, e.g.:
:let g:notes_suffix = '.txt'
### The `g:notes_title_sync` option
When you rename a file in your notes directory but don't change the title, the plug-in will notice this the next time you open the note in Vim. Likewise when you change the title in another text editor but don't rename the file. By default the plug-in will prompt you whether you want it to update the title of the note, rename the file on disk or dismiss the prompt without doing anything.
If you set this option to the string `'no'` this feature will be completely disabled. If you set it to `'change_title'` it will automatically change the title to match the filename. If you set it to `'rename_file'` it will automatically rename the file on disk to match the title.
### The `g:notes_smart_quotes` option
By default the notes plug-in automatically performs several substitutions on the text you type in insert mode, for example regular quote marks are replaced with curly quotes. The full list of substitutions can be found below in the documentation on mappings. If you don't want the plug-in to perform these substitutions, you can set this option to zero like this:
:let g:notes_smart_quotes = 0
### The `g:notes_ruler_text` option
The text of the ruler line inserted when you type `***` in quick succession. It defaults to three asterisks separated by spaces, center aligned to the text width.
### The `g:notes_list_bullets` option
A list of characters used as list bullets. When you're using a Unicode encoding this defaults to `['•', '◦', '▸', '▹', '▪', '▫']`, otherwise it defaults to `['*', '-', '+']`.
When you change the nesting level (indentation) of a line containing a bullet point using one of the mappings `Tab`, `Shift-Tab`, `Alt-Left` and `Alt-Right` the bullet point will be automatically changed to correspond to the new nesting level.
The first level of list items gets the first bullet point in `g:notes_list_bullets`, the second level gets the second, etc. When you're indenting a list item to a level where the `g:notes_list_bullets` doesn't have enough bullets, the plug-in starts again at the first bullet in the list (in other words the selection of bullets wraps around).
### The `g:notes_tab_indents` option
By default `Tab` is mapped to indent list items and `Shift-Tab` is mapped to dedent list items. You can disable these mappings by adding the following to your [vimrc script] [vimrc]:
:let g:notes_tab_indents = 0
### The `g:notes_alt_indents` option
By default `Alt-Right` is mapped to indent list items and `Alt-Left` is mapped to dedent list items. You can disable these mappings by adding the following to your [vimrc script] [vimrc]:
:let g:notes_alt_indents = 0
### The `g:notes_shadowdir` option
The notes plug-in comes with some default notes containing documentation about the plug-in. This option defines the path of the directory containing these notes.
### The `g:notes_indexfile` option
This option defines the pathname of the optional keyword index used by the `:SearchNotes` to perform accelerated keyword searching.
### The `g:notes_indexscript` option
This option defines the pathname of the Python script that's used to perform accelerated keyword searching with `:SearchNotes`.
### The `g:notes_tagsindex` option
This option defines the pathname of the text file that stores the list of known tags used for tag name completion and the `:ShowTaggedNotes` command. The text file is created automatically when it's first needed, after that you can recreate it manually by executing `:IndexTaggedNotes` (see below).
### The `g:notes_markdown_program` option
The `:NoteToHtml` command requires the [Markdown] [markdown] program. By default the name of this program is assumed to be simply `markdown`. If you want to use a different program for Markdown to HTML conversion, set this option to the name of the program.
## Commands
To edit one of your existing notes (or create a new one) you can use Vim commands such as [:edit] [edit], [:split] [split] and [:tabedit] [tabedit] with a filename that starts with *note:* followed by (part of) the title of one of your notes, e.g.:
:edit note:todo
This shortcut also works from the command line:
$ gvim note:todo
When you don't follow *note:* with anything a new note is created like when you execute `:Note` without any arguments.
### The `:Note` command
When executed without any arguments this command starts a new note in the current window. If you pass one or more arguments the command will edit an existing note containing the given words in the title. If more than one note is found you'll be asked which note you want to edit. If no notes are found a new note is started with the given word(s) as title.
This command will fail when changes have been made to the current buffer, unless you use `:Note!` which discards any changes.
When you are using multiple directories to store your notes and you run `:Note` while editing an existing note, a new note will inherit the directory of the note from which you started. Otherwise the note is created in the first directory in `g:notes_directories`.
*This command supports tab completion:* If you complete one word, all existing notes containing the given word somewhere in their title are suggested. If you type more than one word separated by spaces, the plug-in will complete only the missing words so that the resulting command line contains the complete note title and nothing more.
### The `:NoteFromSelectedText` command
Start a new note in the current window with the selected text as the title of the note. The name of this command isn't very well suited to daily use, that's because it's intended to be executed from a mapping. The default mapping for this command is `\en` (the backslash is actually the character defined by the [mapleader] [mapleader] variable).
When you are using multiple directories to store your notes and you run `:NoteFromSelectedText` while editing an existing note, the new note will inherit the directory of the note from which it was created.
### The `:SplitNoteFromSelectedText` command
Same as `:NoteFromSelectedText` but opens the new note in a vertical split window. The default mapping for this command is `\sn`.
### The `:TabNoteFromSelectedText` command
Same as `:NoteFromSelectedText` but opens the new note in a new tab page. The default mapping for this command is `\tn`.
### The `:DeleteNote` command
The `:DeleteNote` command deletes a note file, destroys the buffer and removes the note from the internal cache of filenames and note titles. If you pass a note name as an argument to `:DeleteNote` it will delete the given note, otherwise it will delete the current note. This fails when changes have been made to the buffer, unless you use `:DeleteNote!` which discards any changes.
### The `:SearchNotes` command
This command wraps [:vimgrep] [vimgrep] and enables you to search through your notes using one or more keywords or a regular expression pattern. To search for a pattern you pass a single argument that starts/ends with a slash:
:SearchNotes /TODO\|FIXME\|XXX/
To search for one or more keywords you can just omit the slashes, this matches notes containing all of the given keywords:
:SearchNotes syntax highlighting
#### `:SearchNotes` understands @tags
If you don't pass any arguments to the `:SearchNotes` command it will search for the word under the cursor. If the word under the cursor starts with '@' this character will be included in the search, which makes it possible to easily add *@tags* to your *@notes* and then search for those tags. To make searching for tags even easier you can create key mappings for the `:SearchNotes` command:
" Make the C-] combination search for @tags:
imap <C-]> <C-o>:SearchNotes<CR>
nmap <C-]> :SearchNotes<CR>
" Make double mouse click search for @tags. This is actually quite a lot of
" fun if you don't use the mouse for text selections anyway; you can click
" between notes as if you're in a web browser:
imap <2-LeftMouse> <C-o>:SearchNotes<CR>
nmap <2-LeftMouse> :SearchNotes<CR>
These mappings are currently not enabled by default because they conflict with already useful key mappings, but if you have any suggestions for alternatives feel free to contact me through GitHub or at <peter@peterodding.com>.
#### Accelerated searching with Python
After collecting a fair amount of notes (say more than 5 MB) you will probably start to get annoyed at how long it takes Vim to search through all of your notes. To make searching more scalable the notes plug-in includes a Python script which uses a persistent full text index of your notes stored in a file.
The first time the Python script is run it will need to build the complete index which can take a moment, but after the index has been initialized updates and searches should be more or less instantaneous.
### The `:RelatedNotes` command
This command makes it easy to find all notes related to the current file: If you are currently editing a note then a search for the note's title is done, otherwise this searches for the absolute path of the current file.
### The `:RecentNotes` command
If you execute the `:RecentNotes` command it will open a Vim buffer that lists all your notes grouped by the day they were edited, starting with your most recently edited note. If you pass an argument to `:RecentNotes` it will filter the list of notes by matching the title of each note against the argument which is interpreted as a Vim pattern.
### The `:MostRecentNote` command
This command edits your most recently edited note (whether you just opened the note or made changes to it). The plug-in will remember the most recent note between restarts of Vim and is shared between all instances of Vim.
### The `:ShowTaggedNotes` command
To show a list of all notes that contains *@tags* you can use the `:ShowTaggedNotes` command. If you pass a count to this command it will limit the list of tags to those that have been used at least this many times. For example the following two commands show tags that have been used at least ten times:
:10ShowTaggedNotes
:ShowTaggedNotes 10
### The `:IndexTaggedNotes` command
The notes plug-in defines an omni completion function that can be used to complete the names of tags. To trigger the omni completion you type Control-X Control-O. When you type `@` in insert mode the plug-in will automatically start omni completion.
The completion menu is populated from a text file listing all your tags, one on each line. The first time omni completion triggers, an index of tag names is generated and saved to the location set by `g:notes_tagsindex`. After this file is created, it will be updated automatically as you edit notes and add/remove tags.
If for any reason you want to recreate the list of tags you can execute the `:IndexTaggedNotes` command.
### The `:NoteToHtml` command
This command converts the current note to HTML. It works by first converting the current note to [Markdown] [markdown] and then using the `markdown` program to convert that to HTML. It requires an external program to convert Markdown to HTML. By default the program `markdown` is used, but you can change the name of the program using the `g:notes_markdown_program` option.
Note that this command can be a bit slow, because the parser for the note taking syntax is written in Vim script (for portability) and has not been optimized for speed (yet).
### The `:NoteToMarkdown` command
Convert the current note to a [Markdown document] [markdown]. The vim-notes syntax shares a lot of similarities with the Markdown text format, but there are some notable differences, which this command takes care of:
* The first line of a note is an implicit document title. In Markdown format it has to be marked with `#`. This also implies that the remaining headings should be shifted by one level.
* Preformatted blocks are marked very differently in notes and Markdown (`{{{` and `}}}` markers versus 4 space indentation).
* The markers and indentation of list items differ between notes and Markdown (dumb bullets vs Unicode bullets and 3 vs 4 spaces).
Note that this command can be a bit slow, because the parser for the note taking syntax is written in Vim script (for portability) and has not been optimized for speed (yet).
## Mappings
The following key mappings are defined inside notes.
### Insert mode mappings
* `@` automatically triggers tag completion
* `'` becomes `` or `` depending on where you type it
* `"` becomes `“` or `”` (same goes for these)
* `--` becomes `—`
* `->` becomes `→`
* `<-` becomes `←`
* the bullets `*`, `-` and `+` become `•`
* the three characters `***` in insert mode in quick succession insert a horizontal ruler delimited by empty lines
* `Tab` and `Alt-Right` increase indentation of list items (works on the current line and selected lines)
* `Shift-Tab` and `Alt-Left` decrease indentation of list items
* `Enter` on a line with only a list bullet removes the bullet and starts a new line below the current line
* `\en` executes `:NoteFromSelectedText`
* `\sn` executes `:SplitNoteFromSelectedText`
* `\tn` executes `:TabNoteFromSelectedText`
## Customizing the syntax highlighting of notes
The syntax mode for notes is written so you can override styles you don't like. To do so you can add lines such as the following to your [vimrc script] [vimrc]:
" Don't highlight single quoted strings.
highlight link notesSingleQuoted Normal
" Show double quoted strings in italic font.
highlight notesDoubleQuoted gui=italic
See the documentation of the [:highlight] [highlight] command for more information. Below are the names of the syntax items defined by the notes syntax mode:
* `notesName` - the names of other notes, usually highlighted as a hyperlink
* `notesTagName` - words preceded by an `@` character, also highlighted as a hyperlink
* `notesListBullet` - the bullet characters used for list items
* `notesListNumber` - numbers in front of list items
* `notesDoubleQuoted` - double quoted strings
* `notesSingleQuoted` - single quoted strings
* `notesItalic` - strings between two `_` characters
* `notesBold` - strings between two `*` characters
* `notesTextURL` - plain domain name (recognized by leading `www.`)
* `notesRealURL` - URLs (e.g. <http://vim.org/>)
* `notesEmailAddr` - e-mail addresses
* `notesUnixPath` - UNIX file paths (e.g. `~/.vimrc` and `/home/peter/.vimrc`)
* `notesPathLnum` - line number following a UNIX path
* `notesWindowsPath` - Windows file paths (e.g. `c:\users\peter\_vimrc`)
* `notesTodo` - `TODO` markers
* `notesXXX` - `XXX` markers
* `notesFixMe` - `FIXME` markers
* `notesInProgress` - `CURRENT`, `INPROGRESS`, `STARTED` and `WIP` markers
* `notesDoneItem` - lines containing the marker `DONE`, usually highlighted as a comment
* `notesDoneMarker` - `DONE` markers
* `notesVimCmd` - Vim commands, words preceded by an `:` character
* `notesTitle` - the first line of each note
* `notesShortHeading` - short sentences ending in a `:` character
* `notesAtxHeading` - lines preceded by one or more `#` characters
* `notesBlockQuote` - lines preceded by a `>` character
* `notesRule` - lines containing only whitespace and `* * *`
* `notesCodeStart` - the `{{{` markers that begin a block of code (including the syntax name)
* `notesCodeEnd` - the `}}}` markers that end a block of code
* `notesModeLine` - Vim [modeline] [modeline] in last line of notes
* `notesLastEdited` - last edited dates in `:ShowTaggedNotes` buffers
## Other plug-ins that work well with the notes plug-in
### utl.vim
The [utl.vim] [utl] universal text linking plug-in enables links between your notes, other local files and remote resources like web pages.
### shell.vim
My [shell.vim] [shell] plug-in also enables easy navigation between your notes and environment like local files and directories, web pages and e-mail addresses by providing key mappings and commands to e.g. open the file/URL under the text cursor. This plug-in can also change Vim to full screen which can be really nice for large notes.
### VOoM
The [VOoM] [voom] outlining plug-in should work well for notes if you use the Markdown style headers starting with `#`, however it has been reported that this combination may not always work so well in practice (sometimes losing notes!)
### Txtfmt
If the text formatting supported by the notes plug-in is not enough for you, consider trying the [Txtfmt] [txtfmt] (The Vim Highlighter) plug-in. To use the two plug-ins together, create the file `after/ftplugin/notes.vim` inside your Vim profile with the following contents:
" Enable Txtfmt formatting inside notes.
setlocal filetype=notes.txtfmt
## Contact
If you have questions, bug reports, suggestions, etc. the author can be contacted at <peter@peterodding.com>. The latest version is available at <http://peterodding.com/code/vim/notes/> and <http://github.com/xolox/vim-notes>. If you like the script please vote for it on [Vim Online] [vim_online].
## License
This software is licensed under the [MIT license] [mit].
© 2013 Peter Odding &lt;<peter@peterodding.com>&gt;.
[ctrlwf]: http://vimdoc.sourceforge.net/htmldoc/windows.html#CTRL-W_f
[ctrlwgf]: http://vimdoc.sourceforge.net/htmldoc/windows.html#CTRL-W_gf
[download-misc]: http://peterodding.com/code/vim/downloads/misc.zip
[download-notes]: http://peterodding.com/code/vim/downloads/notes.zip
[edit]: http://vimdoc.sourceforge.net/htmldoc/editing.html#:edit
[gf]: http://vimdoc.sourceforge.net/htmldoc/editing.html#gf
[github-misc]: http://github.com/xolox/vim-misc
[github-notes]: http://github.com/xolox/vim-notes
[highlight]: http://vimdoc.sourceforge.net/htmldoc/syntax.html#:highlight
[levenshtein]: http://en.wikipedia.org/wiki/Levenshtein_distance
[mapleader]: http://vimdoc.sourceforge.net/htmldoc/map.html#mapleader
[markdown]: http://en.wikipedia.org/wiki/Markdown
[mit]: http://en.wikipedia.org/wiki/MIT_License
[modeline]: http://vimdoc.sourceforge.net/htmldoc/options.html#modeline
[monaco]: http://en.wikipedia.org/wiki/Monaco_(typeface)
[pathogen]: http://www.vim.org/scripts/script.php?script_id=2332
[python]: http://python.org/
[shell]: http://www.vim.org/scripts/script.php?script_id=3123
[slate]: http://code.google.com/p/vim/source/browse/runtime/colors/slate.vim
[split]: http://vimdoc.sourceforge.net/htmldoc/windows.html#:split
[tabedit]: http://vimdoc.sourceforge.net/htmldoc/tabpage.html#:tabedit
[txtfmt]: http://www.vim.org/scripts/script.php?script_id=2208
[update]: http://vimdoc.sourceforge.net/htmldoc/editing.html#:update
[utl]: http://www.vim.org/scripts/script.php?script_id=293
[vim]: http://www.vim.org/
[vim_online]: http://www.vim.org/scripts/script.php?script_id=3375
[vimgrep]: http://vimdoc.sourceforge.net/htmldoc/quickfix.html#:vimgrep
[vimrc]: http://vimdoc.sourceforge.net/htmldoc/starting.html#vimrc
[voom]: http://www.vim.org/scripts/script.php?script_id=2657
[vundle]: https://github.com/gmarik/vundle
[write]: http://vimdoc.sourceforge.net/htmldoc/editing.html#:write

View File

@ -0,0 +1,15 @@
# To-do list for the `notes.vim` plug-in
* The note name highlighting uses word boundaries so that 'git' inside 'fugitive' is not highlighted, however this breaks highlighting of note names ending in punctuation (or more generically ending in non-word characters).
* The `ftplugin/notes.vim` script used to clear the [matchpairs] [matchpairs] option so that pairs of characters are not highlighted in notes (the irrelevant highlighting was starting to annoy me). Several people have since complained that Vim rings a bell or flashes the screen for every key press in insert mode when editing notes. I've now removed the matchpairs manipulation from the plug-in but I suspect that this may actually be a bug in Vim; to be investigated. See also [issue 10 on GitHub] [issue_10].
* Override `<F1>` to show a quick reference of available commands?
* Define aliases of the available commands that start with `Note` (to help people getting started with the plug-in).
* Add a key mapping to toggle text folding (currently in my `~/.vimrc`)
* Add a key mapping or command to toggle the visibility of `{{{ … }}}` code markers?
* Find a good way to support notes with generates contents, e.g. *'all notes'*.
* When renaming a note, also update references to the note in other notes? (make this optional of course!)
* Improve highlighting of lines below a line with a `DONE` marker; when navigating over such lines, the highlighting will sometimes disappear (except on the first line). See also [issue #2 on GitHub] [issue_2].
[issue_2]: https://github.com/xolox/vim-notes/issues/2
[issue_10]: https://github.com/xolox/vim-notes/issues/10
[matchpairs]: http://vimdoc.sourceforge.net/htmldoc/options.html#%27matchpairs%27

View File

@ -0,0 +1 @@
{"vim_script_nr": 3375, "dependencies": {"vim-misc": {}}, "homepage": "http://peterodding.com/code/vim/notes", "name": "vim-notes"}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
" Vim auto-load script
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 23, 2013
" URL: http://peterodding.com/code/vim/notes/
if !exists('g:notes_markdown_program')
let g:notes_markdown_program = 'markdown'
endif
function! xolox#notes#html#view() " {{{1
" Convert the current note to a web page and show the web page in a browser.
" Requires [Markdown] [markdown] to be installed; you'll get a warning if it
" isn't.
"
" [markdown]: http://en.wikipedia.org/wiki/Markdown
try
" Convert the note's text to HTML using Markdown.
let starttime = xolox#misc#timer#start()
let note_title = xolox#notes#current_title()
let filename = xolox#notes#title_to_fname(note_title)
let note_text = join(getline(1, '$'), "\n")
let raw_html = xolox#notes#html#convert_note(note_text)
let styled_html = xolox#notes#html#apply_template({
\ 'encoding': &encoding,
\ 'title': note_title,
\ 'content': raw_html,
\ 'version': g:xolox#notes#version,
\ 'date': strftime('%A %B %d, %Y at %H:%M'),
\ 'filename': fnamemodify(filename, ':~'),
\ })
let filename = s:create_temporary_file(note_title)
if writefile(split(styled_html, "\n"), filename) != 0
throw printf("Failed to write HTML file! (%s)", filename)
endif
" Open the generated HTML in a web browser.
call xolox#misc#open#url('file://' . filename)
call xolox#misc#timer#stop("notes.vim %s: Rendered HTML preview in %s.", g:xolox#notes#version, starttime)
catch
call xolox#misc#msg#warn("notes.vim %s: %s at %s", g:xolox#notes#version, v:exception, v:throwpoint)
endtry
endfunction
function! xolox#notes#html#convert_note(note_text) " {{{1
" Convert a note's text to a web page (HTML) using the [Markdown text
" format] [markdown] as an intermediate format. This function takes the text
" of a note (the first argument) and converts it to HTML, returning a
" string.
if !executable(g:notes_markdown_program)
throw "HTML conversion requires the `markdown' program! On Debian/Ubuntu you can install it by executing `sudo apt-get install markdown'."
endif
let markdown = xolox#notes#markdown#convert_note(a:note_text)
let result = xolox#misc#os#exec({'command': g:notes_markdown_program, 'stdin': markdown})
let html = join(result['stdout'], "\n")
return html
endfunction
function! xolox#notes#html#apply_template(variables) " {{{1
" The vim-notes plug-in contains a web page template that's used to provide
" a bit of styling when a note is converted to a web page and presented to
" the user. This function takes the original HTML produced by [Markdown]
" [markdown] (the first argument) and wraps it in the configured template,
" returning the final HTML as a string.
let filename = expand(g:notes_html_template)
call xolox#misc#msg#debug("notes.vim %s: Reading web page template from %s ..", g:xolox#notes#version, filename)
let template = join(readfile(filename), "\n")
let output = substitute(template, '{{\(.\{-}\)}}', '\= s:template_callback(a:variables)', 'g')
return output
endfunction
function! s:template_callback(variables) " {{{1
" Callback for xolox#notes#html#apply_template().
let key = xolox#misc#str#trim(submatch(1))
return get(a:variables, key, '')
endfunction
function! s:create_temporary_file(note_title) " {{{1
" Create a temporary filename for a note converted to an HTML document,
" based on the title of the note.
if !exists('s:temporary_directory')
let s:temporary_directory = xolox#misc#path#tempdir()
endif
let filename = xolox#misc#str#slug(a:note_title) . '.html'
return xolox#misc#path#merge(s:temporary_directory, filename)
endfunction

View File

@ -0,0 +1,94 @@
" Vim auto-load script
" Author: Peter Odding <peter@peterodding.com>
" Last Change: June 23, 2013
" URL: http://peterodding.com/code/vim/notes/
function! xolox#notes#markdown#view() " {{{1
" Convert the current note to a Markdown document and show the converted text.
let note_text = join(getline(1, '$'), "\n")
let markdown_text = xolox#notes#markdown#convert_note(note_text)
vnew
call setline(1, split(markdown_text, "\n"))
setlocal filetype=markdown
endfunction
function! xolox#notes#markdown#convert_note(note_text) " {{{1
" Convert a note's text to the [Markdown text format] [markdown]. The syntax
" used by vim-notes has a lot of similarities with Markdown, but there are
" some notable differences like the note title and the way code blocks are
" represented. This function takes the text of a note (the first argument)
" and converts it to the Markdown format, returning a string.
"
" [markdown]: http://en.wikipedia.org/wiki/Markdown
let starttime = xolox#misc#timer#start()
let blocks = xolox#notes#parser#parse_note(a:note_text)
call map(blocks, 'xolox#notes#markdown#convert_block(v:val)')
let markdown = join(blocks, "\n\n")
call xolox#misc#timer#stop("notes.vim %s: Converted note to Markdown in %s.", g:xolox#notes#version, starttime)
return markdown
endfunction
function! xolox#notes#markdown#convert_block(block) " {{{1
" Convert a single block produced by `xolox#misc#notes#parser#parse_note()`
" (the first argument, expected to be a dictionary) to the [Markdown text
" format] [markdown]. Returns a string.
if a:block.type == 'title'
let text = s:make_urls_explicit(a:block.text)
return printf("# %s", text)
elseif a:block.type == 'heading'
let marker = repeat('#', 1 + a:block.level)
let text = s:make_urls_explicit(a:block.text)
return printf("%s %s", marker, text)
elseif a:block.type == 'code'
let comment = "<!-- An innocent comment to force Markdown out of list parsing mode. See also http://meta.stackoverflow.com/a/99637 -->"
let text = xolox#misc#str#indent(xolox#misc#str#dedent(a:block.text), 4)
return join([comment, text], "\n\n")
elseif a:block.type == 'divider'
return '* * *'
elseif a:block.type == 'list'
let items = []
if a:block.ordered
let counter = 1
for item in a:block.items
let indent = repeat(' ', item.indent * 4)
let text = s:make_urls_explicit(item.text)
call add(items, printf("%s%d. %s", indent, counter, text))
let counter += 1
endfor
else
for item in a:block.items
let indent = repeat(' ', item.indent * 4)
let text = s:make_urls_explicit(item.text)
call add(items, printf("%s- %s", indent, text))
endfor
endif
return join(items, "\n\n")
elseif a:block.type == 'block-quote'
let lines = []
for line in a:block.lines
let prefix = repeat('>', line.level)
call add(lines, printf('%s %s', prefix, line.text))
endfor
return join(lines, "\n")
elseif a:block.type == 'paragraph'
let text = s:make_urls_explicit(a:block.text)
if len(text) <= 50 && text =~ ':$'
let text = printf('**%s**', text)
endif
return text
else
let msg = "Encountered unsupported block: %s!"
throw printf(msg, string(a:block))
endif
endfunction
function! s:make_urls_explicit(text) " {{{1
" In the vim-notes syntax, URLs are implicitly hyperlinks.
" In Markdown syntax they have to be wrapped in <markers>.
return substitute(a:text, g:xolox#notes#url_pattern, '\= s:url_callback(submatch(0))', 'g')
endfunction
function! s:url_callback(url)
let label = substitute(a:url, '^\w\+:\(//\)\?', '', '')
return printf('[%s](%s)', label, a:url)
endfunction

View File

@ -0,0 +1,333 @@
" Vim auto-load script
" Author: Peter Odding <peter@peterodding.com>
" Last Change: July 18, 2013
" URL: http://peterodding.com/code/vim/notes/
function! xolox#notes#parser#parse_note(text) " {{{1
" Parser for the note taking syntax used by vim-notes.
let starttime = xolox#misc#timer#start()
let context = s:create_parse_context(a:text)
let note_title = context.next_line()
let blocks = [{'type': 'title', 'text': note_title}]
while context.has_more()
let chr = context.peek(1)
if chr == "\n"
" Ignore empty lines.
call context.next(1)
continue
elseif chr == '#'
let block = s:parse_heading(context)
elseif chr == '>'
let block = s:parse_block_quote(context)
elseif chr == '{' && context.peek(3) == "\{\{\{"
let block = s:parse_code_block(context)
else
let lookahead = s:match_bullet_or_divider(context, 0)
if !empty(lookahead)
if lookahead.type =~ 'list'
let block = s:parse_list(context)
elseif lookahead.type == 'divider'
let block = s:parse_divider(context)
else
let msg = "Programming error! Unsupported lookahead: %s."
throw printf(msg, string(lookahead))
endif
else
let block = s:parse_paragraph(context)
endif
endif
" Don't include empty blocks in the output.
if !empty(block)
call add(blocks, block)
endif
endwhile
call xolox#misc#timer#stop("notes.vim %s: Parsed note into %i blocks in %s.", g:xolox#notes#version, len(blocks), starttime)
return blocks
endfunction
function! xolox#notes#parser#view_parse_nodes() " {{{1
" Parse the current note and show the parse nodes in a temporary buffer.
let note_text = join(getline(1, '$'), "\n")
let parse_nodes = xolox#notes#parser#parse_note(note_text)
vnew
call setline(1, map(parse_nodes, 'string(v:val)'))
setlocal filetype=vim nomodified nowrap
endfunction
function! s:create_parse_context(text) " {{{1
" Create an object to encapsulate the lowest level of parser state.
let context = {'text': a:text, 'index': 0}
" The has_more() method returns 1 (true) when more input is available, 0
" (false) otherwise.
function context.has_more()
return self.index < len(self.text)
endfunction
" The peek() method returns the next character without consuming it.
function context.peek(n)
if self.has_more()
return self.text[self.index : self.index + (a:n - 1)]
endif
return ''
endfunction
" The next() method returns the next character and consumes it.
function context.next(n)
let result = self.peek(a:n)
let self.index += a:n
return result
endfunction
" The next_line() method returns the current line and consumes it.
function context.next_line()
let line = ''
while self.has_more()
let chr = self.next(1)
if chr == "\n" || chr == ""
" We hit the end of line or input.
return line
else
" The line continues.
let line .= chr
endif
endwhile
return line
endfunction
return context
endfunction
function! s:match_bullet_or_divider(context, consume_lookahead) " {{{1
" Check whether the current line starts with a list bullet.
let result = {}
let context = copy(a:context)
let line = context.next_line()
let bullet = matchstr(line, s:bullet_pattern)
if !empty(bullet)
" Disambiguate list bullets from horizontal dividers.
if line =~ '^\s\+\*\s\*\s\*$'
let result.type = 'divider'
else
" We matched a bullet! Now we still need to distinguish ordered from
" unordered list items.
if bullet =~ '\d'
let result.type = 'ordered-list'
else
let result.type = 'unordered-list'
endif
let indent = matchstr(bullet, '^\s*')
let result.indent = len(indent)
" Since we already skipped the whitespace and matched the bullet, it's
" very little work to mark our position for the benefit of the caller.
if a:consume_lookahead
let a:context.index += len(bullet)
endif
endif
endif
return result
endfunction
function! s:match_line(context) " {{{1
" Get the text of the current line, stopping at end of the line or just
" before the start of a code block marker, whichever comes first.
let line = ''
while a:context.has_more()
let chr = a:context.peek(1)
if chr == '{' && a:context.peek(3) == "\{\{\{"
" XXX The start of a code block implies the end of whatever came before.
" The marker above contains back slashes so that Vim doesn't apply
" folding because of the marker :-).
return line
elseif chr == "\n"
call a:context.next(1)
return line . "\n"
else
let line .= a:context.next(1)
endif
endwhile
" We hit the end of the input.
return line
endfunction
function! s:parse_heading(context) " {{{1
" Parse the upcoming heading in the input stream.
let level = 0
while a:context.peek(1) == '#'
let level += 1
call a:context.next(1)
endwhile
let text = xolox#misc#str#trim(s:match_line(a:context))
return {'type': 'heading', 'level': level, 'text': text}
endfunction
function! s:parse_block_quote(context) " {{{1
" Parse the upcoming block quote in the input stream.
let lines = []
while a:context.has_more()
if a:context.peek(1) != '>'
break
endif
let line = s:match_line(a:context)
let level = len(matchstr(line, '^>\+'))
let text = matchstr(line, '^>\+\s*\zs.\{-}\ze\_s*$')
call add(lines, {'level': level, 'text': text})
endwhile
return {'type': 'block-quote', 'lines': lines}
endfunction
function! s:parse_code_block(context) " {{{1
" Parse the upcoming code block in the input stream.
let language = ''
let text = ''
" Skip the start marker.
call a:context.next(3)
" Get the optional language name.
while a:context.peek(1) =~ '\w'
let language .= a:context.next(1)
endwhile
" Skip the whitespace separating the start marker and/or language name from
" the text.
while a:context.peek(1) =~ '[ \t]'
call a:context.next(1)
endwhile
" Get the text inside the code block.
while a:context.has_more()
let chr = a:context.next(1)
if chr == '}' && a:context.peek(2) == '}}'
call a:context.next(2)
break
endif
let text .= chr
endwhile
" Strip trailing whitespace.
let text = substitute(text, '\_s\+$', '', '')
return {'type': 'code', 'language': language, 'text': text}
endfunction
function! s:parse_divider(context) " {{{1
" Parse the upcoming horizontal divider in the input stream.
call a:context.next_line()
return {'type': 'divider'}
endfunction
function! s:parse_list(context) " {{{1
" Parse the upcoming sequence of list items in the input stream.
let list_type = 'unknown'
let items = []
let lines = []
let indent = 0
" Outer loop to consume one or more list items.
while a:context.has_more()
let lookahead = s:match_bullet_or_divider(a:context, 1)
if !empty(lookahead)
" Save the previous list item with the old indent level.
call s:save_item(items, lines, indent)
let lines = []
" Set the new indent level (three spaces -> one level).
let indent = lookahead.indent / 3
" The current line starts with a list bullet.
if list_type == 'unknown'
" The first bullet determines the type of list.
let list_type = lookahead.type
endif
endif
let line = s:match_line(a:context)
call add(lines, line)
if line[-1:] != "\n"
" XXX When match_line() returns a line that doesn't end in a newline
" character, it means either we hit the end of the input or the current
" line continues in a code block (which is not ours to parse :-).
break
elseif line =~ '^\_s*$'
" For now an empty line terminates the list item.
" TODO Add support for list items with multiple paragraphs of text.
break
endif
endwhile
call s:save_item(items, lines, indent)
return {'type': 'list', 'ordered': (list_type == 'ordered-list'), 'items': items}
endfunction
function! s:save_item(items, lines, indent)
let text = join(a:lines, "\n")
if text =~ '\S'
let text = xolox#misc#str#compact(text)
call add(a:items, {'text': text, 'indent': a:indent})
endif
endfunction
function! s:parse_paragraph(context) " {{{1
" Parse the upcoming paragraph in the input stream.
let lines = []
while a:context.has_more()
if !empty(s:match_bullet_or_divider(a:context, 0))
" If the next line starts with a list bullet it shouldn't
" be included in the paragraph we're currently parsing.
break
else
let line = s:match_line(a:context)
call add(lines, line)
if line =~ '^\_s*$'
" An empty line marks the end of the paragraph.
break
elseif line[-1:] != "\n"
" XXX When match_line() returns a line that doesn't end in a newline
" character, it means either we hit the end of the input or the current
" line continues in a code block (which is not ours to parse :-).
break
endif
endif
endwhile
" Don't include empty paragraphs in the output.
let text = join(lines, "\n")
if text =~ '\S'
return {'type': 'paragraph', 'text': xolox#misc#str#compact(text)}
else
return {}
endif
endfunction
function! s:generate_list_item_bullet_pattern() " {{{1
" Generate a regular expression that matches any kind of list bullet.
let choices = copy(g:notes_unicode_bullets)
for bullet in g:notes_ascii_bullets
call add(choices, xolox#misc#escape#pattern(bullet))
endfor
call add(choices, '\d\+[[:punct:]]\?')
return join(choices, '\|')
endfunction
let s:bullet_pattern = '^\s*\(' . s:generate_list_item_bullet_pattern() . '\)\s\+'
function! xolox#notes#parser#run_tests() " {{{1
" Tests for the note taking syntax parser.
call xolox#misc#test#reset()
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_note_titles')
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_headings')
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_paragraphs')
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_code_blocks')
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_list_items')
call xolox#misc#test#wrap('xolox#notes#parser#test_parsing_of_block_quotes')
call xolox#misc#test#summarize()
endfunction
function! xolox#notes#parser#test_parsing_of_note_titles()
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}], xolox#notes#parser#parse_note('Just the title'))
endfunction
function! xolox#notes#parser#test_parsing_of_headings()
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'heading', 'level': 1, 'text': 'This is a heading'}], xolox#notes#parser#parse_note("Just the title\n\n# This is a heading"))
endfunction
function! xolox#notes#parser#test_parsing_of_paragraphs()
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'paragraph', 'text': 'This is a paragraph'}], xolox#notes#parser#parse_note("Just the title\n\nThis is a paragraph"))
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'paragraph', 'text': 'This is a paragraph'}, {'type': 'paragraph', 'text': "And here's another paragraph!"}], xolox#notes#parser#parse_note("Just the title\n\nThis is a paragraph\n\n\n\nAnd here's another paragraph!"))
endfunction
function! xolox#notes#parser#test_parsing_of_code_blocks()
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'code', 'language': '', 'text': "This is a code block\nwith two lines"}], xolox#notes#parser#parse_note("Just the title\n\n{{{ This is a code block\nwith two lines }}}"))
endfunction
function! xolox#notes#parser#test_parsing_of_list_items()
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'list', 'ordered': 1, 'items': [{'indent': 0, 'text': 'item one'}, {'indent': 0, 'text': 'item two'}, {'indent': 0, 'text': 'item three'}]}], xolox#notes#parser#parse_note("Just the title\n\n1. item one\n2. item two\n3. item three"))
endfunction
function! xolox#notes#parser#test_parsing_of_block_quotes()
call xolox#misc#test#assert_equals([{'type': 'title', 'text': 'Just the title'}, {'type': 'block-quote', 'lines': [{'level': 1, 'text': 'block'}, {'level': 2, 'text': 'quoted'}, {'level': 1, 'text': 'text'}]}], xolox#notes#parser#parse_note("Just the title\n\n> block\n>> quoted\n> text"))
endfunction

View File

@ -0,0 +1,100 @@
" Vim auto-load script
" Author: Peter Odding <peter@peterodding.com>
" Last Change: May 16, 2013
" URL: http://peterodding.com/code/vim/notes/
function! xolox#notes#recent#show(bang, title_filter) " {{{1
call xolox#misc#msg#info("notes.vim %s: Generating overview of recent notes ..", g:xolox#notes#version)
" Show generated note listing all notes by last modified time.
let starttime = xolox#misc#timer#start()
let bufname = '[Recent Notes]'
" Prepare a buffer to hold the list of recent notes.
call xolox#misc#buffer#prepare({
\ 'name': bufname,
\ 'path': xolox#misc#path#merge($HOME, bufname)})
" Filter notes by pattern (argument)?
let notes = []
let title_filter = '\v' . a:title_filter
for [fname, title] in items(xolox#notes#get_fnames_and_titles(0))
if title =~? title_filter
call add(notes, [getftime(fname), title])
endif
endfor
" Start note with "You have N note(s) [matching filter]".
let readme = "You have "
if empty(notes)
let readme .= "no notes"
elseif len(notes) == 1
let readme .= "one note"
else
let readme .= len(notes) . " notes"
endif
if a:title_filter != ''
let quote_format = xolox#notes#unicode_enabled() ? '%s' : "`%s'"
let readme .= " matching " . printf(quote_format, a:title_filter)
endif
" Explain the sorting of the notes.
if empty(notes)
let readme .= "."
elseif len(notes) == 1
let readme .= ", it's listed below."
else
let readme .= ". They're listed below grouped by the day they were edited, starting with your most recently edited note."
endif
" Add the generated text to the buffer.
call setline(1, ["Recent notes", "", readme])
" Reformat the text in the buffer to auto-wrap.
normal Ggqq
" Sort, group and format the list of (matching) notes.
let last_date = ''
let list_item_format = xolox#notes#unicode_enabled() ? ' • %s' : ' * %s'
call sort(notes)
call reverse(notes)
let lines = []
for [ftime, title] in notes
let date = xolox#notes#friendly_date(ftime)
if date != last_date
call add(lines, '')
call add(lines, substitute(date, '^\w', '\u\0', '') . ':')
let last_date = date
endif
call add(lines, printf(list_item_format, title))
endfor
" Add the formatted list of notes to the buffer.
call setline(line('$') + 1, lines)
" Load the notes file type.
call xolox#notes#set_filetype()
let &l:statusline = bufname
" Change the status line
" Lock the buffer contents.
call xolox#misc#buffer#lock()
" And we're done!
call xolox#misc#timer#stop("notes.vim %s: Generated %s in %s.", g:xolox#notes#version, bufname, starttime)
endfunction
function! xolox#notes#recent#track() " {{{1
let fname = expand('%:p')
let indexfile = expand(g:notes_recentindex)
call xolox#misc#msg#debug("notes.vim %s: Recording '%s' as most recent note in %s ..", g:xolox#notes#version, fname, indexfile)
if writefile([fname], indexfile) == -1
call xolox#misc#msg#warn("notes.vim %s: Failed to record most recent note in %s!", g:xolox#notes#version, indexfile)
endif
endfunction
function! xolox#notes#recent#edit(bang) " {{{1
" Edit the most recently edited (not necessarily changed) note.
let indexfile = expand(g:notes_recentindex)
call xolox#misc#msg#debug("notes.vim %s: Recalling most recent note from %s ..", g:xolox#notes#version, indexfile)
try
let fname = readfile(indexfile)[0]
if empty(fname)
throw "The index of recent notes is empty?!"
endif
catch
call xolox#misc#msg#warn("notes.vim %s: Failed to recall most recent note from %s: %s", g:xolox#notes#version, indexfile, v:exception)
return
endtry
call xolox#misc#msg#info("notes.vim %s: Editing most recent note '%s' ..", g:xolox#notes#version, fname)
execute 'edit' . a:bang fnameescape(fname)
call xolox#notes#set_filetype()
endfunction

View File

@ -0,0 +1,201 @@
" Vim auto-load script
" Author: Peter Odding <peter@peterodding.com>
" Last Change: May 5, 2013
" URL: http://peterodding.com/code/vim/notes/
if !exists('s:currently_tagged_notes')
let s:currently_tagged_notes = {} " The in-memory representation of tags and the notes in which they're used.
let s:previously_tagged_notes = {} " Copy of index as it is / should be now on disk (to detect changes).
let s:last_disk_sync = 0 " Whether the on-disk representation of the tags has been read.
let s:buffer_name = 'Tagged Notes' " The buffer name for the list of tagged notes.
let s:loading_index = 0
endif
function! xolox#notes#tags#load_index() " {{{1
if s:loading_index
" Guard against recursive calls.
return s:currently_tagged_notes
endif
let starttime = xolox#misc#timer#start()
let indexfile = expand(g:notes_tagsindex)
let lastmodified = getftime(indexfile)
if lastmodified == -1
let s:loading_index = 1
call xolox#notes#tags#create_index()
let s:loading_index = 0
elseif lastmodified > s:last_disk_sync
let s:currently_tagged_notes = {}
for line in readfile(indexfile)
let filenames = split(line, "\t")
if len(filenames) > 1
let tagname = remove(filenames, 0)
let s:currently_tagged_notes[tagname] = filenames
endif
endfor
let s:previously_tagged_notes = deepcopy(s:currently_tagged_notes)
let s:last_disk_sync = lastmodified
call xolox#misc#timer#stop("notes.vim %s: Loaded tags index in %s.", g:xolox#notes#version, starttime)
endif
return s:currently_tagged_notes
endfunction
function! xolox#notes#tags#create_index() " {{{1
let exists = filereadable(expand(g:notes_tagsindex))
let starttime = xolox#misc#timer#start()
let filenames = xolox#notes#get_fnames(0)
let s:currently_tagged_notes = {}
for idx in range(len(filenames))
if filereadable(filenames[idx])
let title = xolox#notes#fname_to_title(filenames[idx])
call xolox#misc#msg#info("notes.vim %s: Scanning note %i/%i: %s", g:xolox#notes#version, idx + 1, len(filenames), title)
call xolox#notes#tags#scan_note(title, join(readfile(filenames[idx]), "\n"))
endif
endfor
if xolox#notes#tags#save_index()
let s:previously_tagged_notes = deepcopy(s:currently_tagged_notes)
call xolox#misc#timer#stop('notes.vim %s: %s tags index in %s.', g:xolox#notes#version, exists ? "Updated" : "Created", starttime)
else
call xolox#misc#msg#warn("notes.vim %s: Failed to save tags index as %s!", g:xolox#notes#version, g:notes_tagsindex)
endif
endfunction
function! xolox#notes#tags#save_index() " {{{1
let indexfile = expand(g:notes_tagsindex)
let existingfile = filereadable(indexfile)
let nothingchanged = (s:currently_tagged_notes == s:previously_tagged_notes)
if existingfile && nothingchanged
call xolox#misc#msg#debug("notes.vim %s: Index not dirty so not saved.", g:xolox#notes#version)
return 1 " Nothing to be done
else
let lines = []
for [tagname, filenames] in items(s:currently_tagged_notes)
call add(lines, join([tagname] + filenames, "\t"))
endfor
let status = writefile(lines, indexfile) == 0
if status
call xolox#misc#msg#debug("notes.vim %s: Index saved to %s.", g:xolox#notes#version, g:notes_tagsindex)
let s:last_disk_sync = getftime(indexfile)
else
call xolox#misc#msg#debug("notes.vim %s: Failed to save index to %s.", g:xolox#notes#version, g:notes_tagsindex)
endif
return status
endif
endfunction
function! xolox#notes#tags#scan_note(title, text) " {{{1
" Add a note to the tags index.
call xolox#notes#tags#load_index()
" Don't scan tags inside code blocks.
let text = substitute(a:text, '{{{\w\+\_.\{-}}}}', '', 'g')
" Split everything on whitespace.
for token in split(text)
" Match words that start with @ and don't contain { (BibTeX entries).
if token =~ '^@\w' && token !~ '{'
" Strip any trailing punctuation.
let token = substitute(token[1:], '[[:punct:]]*$', '', '')
if token != ''
if !has_key(s:currently_tagged_notes, token)
let s:currently_tagged_notes[token] = [a:title]
elseif index(s:currently_tagged_notes[token], a:title) == -1
" Keep the tags sorted.
call xolox#misc#list#binsert(s:currently_tagged_notes[token], a:title, 1)
endif
endif
endif
endfor
endfunction
function! xolox#notes#tags#forget_note(title) " {{{1
" Remove a note from the tags index.
call xolox#notes#tags#load_index()
for tagname in keys(s:currently_tagged_notes)
call filter(s:currently_tagged_notes[tagname], "v:val != a:title")
if empty(s:currently_tagged_notes[tagname])
unlet s:currently_tagged_notes[tagname]
endif
endfor
endfunction
function! xolox#notes#tags#show_tags(minsize) " {{{1
" TODO Mappings to "zoom" in/out (show only big tags).
let starttime = xolox#misc#timer#start()
call xolox#notes#tags#load_index()
let lines = [s:buffer_name, '']
if empty(s:currently_tagged_notes)
call add(lines, "You haven't used any tags yet!")
else
" Create a dictionary with note titles as keys.
let unmatched = {}
for title in xolox#notes#get_titles(0)
let unmatched[title] = 1
endfor
let totalnotes = len(unmatched)
" Group matching notes and remove them from the dictionary.
let grouped_notes = []
let numtags = 0
for tagname in sort(keys(s:currently_tagged_notes), 1)
let numnotes = len(s:currently_tagged_notes[tagname])
if numnotes >= a:minsize
let matched_notes = s:currently_tagged_notes[tagname]
for title in matched_notes
if has_key(unmatched, title)
unlet unmatched[title]
endif
endfor
call add(grouped_notes, {'name': tagname, 'notes': matched_notes})
let numtags += 1
endif
endfor
" Add a "fake tag" with all unmatched notes.
if !empty(unmatched)
call add(grouped_notes, {'name': "Unmatched notes", 'notes': keys(unmatched)})
endif
" Format the results as a note.
let bullet = xolox#notes#get_bullet('*')
for group in grouped_notes
let tagname = group['name']
let friendly_name = xolox#notes#tags#friendly_name(tagname)
let numnotes = len(group['notes'])
if numnotes >= a:minsize
call extend(lines, ['', printf('# %s (%i note%s)', friendly_name, numnotes, numnotes == 1 ? '' : 's'), ''])
for title in group['notes']
let lastmodified = xolox#notes#friendly_date(getftime(xolox#notes#title_to_fname(title)))
call add(lines, ' ' . bullet . ' ' . title . ' (last edited ' . lastmodified . ')')
endfor
endif
endfor
if a:minsize <= 1
let message = printf("You've used %i %s in %i %s",
\ numtags, numtags == 1 ? "tag" : "tags",
\ totalnotes, totalnotes == 1 ? "note" : "notes")
else
let message = printf("There %s %i %s that %s been used at least %s times",
\ numtags == 1 ? "is" : "are", numtags,
\ numtags == 1 ? "tag" : "tags",
\ numtags == 1 ? "has" : "have", a:minsize)
endif
let message .= ", " . (numtags == 1 ? "it's" : "they're")
let message .= " listed below. Tags and notes are sorted alphabetically and after each note is the date when it was last modified."
if !empty(unmatched)
if a:minsize <= 1
let message .= " At the bottom is a list of untagged notes."
else
let message .= " At the bottom is a list of unmatched notes."
endif
endif
if numtags > 1 && !(&foldmethod == 'expr' && &foldenable)
let message .= " You can enable text folding to get an overview of just the tag names and how many times they've been used."
endif
call insert(lines, message, 2)
endif
call xolox#misc#buffer#prepare(s:buffer_name)
call setline(1, lines)
call xolox#misc#buffer#lock()
call xolox#notes#set_filetype()
setlocal nospell wrap
call xolox#misc#timer#stop('notes.vim %s: Generated [%s] in %s.', g:xolox#notes#version, s:buffer_name, starttime)
endfunction
function! xolox#notes#tags#friendly_name(tagname) " {{{1
return substitute(a:tagname, '\(\U\)\(\u\)', '\1 \2', 'g')
endfunction

View File

@ -0,0 +1,677 @@
*notes.txt* Easy note taking in Vim
===============================================================================
Contents ~
1. Introduction |notes-introduction|
2. Install & usage |notes-install-usage|
3. Options |notes-options|
1. The |g:notes_directories| option
1. Backwards compatibility |notes-backwards-compatibility|
2. The |g:notes_suffix| option
3. The |g:notes_title_sync| option
4. The |g:notes_smart_quotes| option
5. The |g:notes_ruler_text| option
6. The |g:notes_list_bullets| option
7. The |g:notes_tab_indents| option
8. The |g:notes_alt_indents| option
9. The |g:notes_shadowdir| option
10. The |g:notes_indexfile| option
11. The |g:notes_indexscript| option
12. The |g:notes_tagsindex| option
13. The |g:notes_markdown_program| option
4. Commands |notes-commands|
1. The |:Note| command
2. The |:NoteFromSelectedText| command
3. The |:SplitNoteFromSelectedText| command
4. The |:TabNoteFromSelectedText| command
5. The |:DeleteNote| command
6. The |:SearchNotes| command
1. |:SearchNotes| understands @tags |searchnotes-understands-tags|
2. Accelerated searching with Python |notes-accelerated-searching-with-python|
7. The |:RelatedNotes| command
8. The |:RecentNotes| command
9. The |:MostRecentNote| command
10. The |:ShowTaggedNotes| command
11. The |:IndexTaggedNotes| command
12. The |:NoteToHtml| command
13. The |:NoteToMarkdown| command
5. Mappings |notes-mappings|
1. Insert mode mappings |notes-insert-mode-mappings|
6. Customizing the syntax highlighting of notes |customizing-syntax-highlighting-of-notes|
7. Other plug-ins that work well with the notes plug-in |other-plug-ins-that-work-well-with-notes-plug-in|
1. utl.vim |notes-utl.vim|
2. shell.vim |notes-shell.vim|
3. VOoM |notes-voom|
4. Txtfmt |notes-txtfmt|
8. Contact |notes-contact|
9. License |notes-license|
10. References |notes-references|
===============================================================================
*notes-introduction*
Introduction ~
The vim-notes plug-in for the Vim text editor makes it easy to manage your
notes in Vim:
- **Starting a new note:** Execute the |:Note| command to create a new buffer
and load the appropriate file type and syntax
- You can also start a note with Vim commands like ':edit', ':tabedit' and
':split' by starting the filename with 'note:', as in ':edit note:todo'
(the part after 'note:' doesn't have to be the complete note title and if
it's empty a new note will be created)
- You can start a new note with the selected text as title in the current
window using the '\en' mapping or |:NoteFromSelectedText| command (there
are similar mappings and commands for opening split windows and tab pages)
- **Saving notes:** Just use Vim's |:write| and |:update| commands, you don't
need to provide a filename because it will be set based on the title (first
line) of your note (you also don't need to worry about special characters,
they'll be escaped)
- **Editing existing notes:** Execute ':Note anything' to edit a note
containing 'anything' in its title (if no notes are found a new one is
created with its title set to 'anything')
- The |:Note| and |:DeleteNote| commands support tab completion of note
titles
- **Deleting notes:** The |:DeleteNote| command enables you to delete the
current note
- **Searching notes:**':SearchNotes keyword …' searches for keywords and
':SearchNotes /pattern/' searches for regular expressions
- The |:SearchNotes| command supports tab completion of keywords and sorts
candidates by relevance (Levenshtein distance [1])
- **Smart defaults:** Without an argument |:SearchNotes| searches for the
word under the cursor (if the word starts with '@' that character will be
included in the search, this means you can easily search for _@tagged_
notes)
- **Back-references:** The |:RelatedNotes| command find all notes referencing
the current file
- A Python 2 [2] script is included that accelerates keyword searches using a
keyword index
- The |:RecentNotes| command lists your notes by modification date, starting
with the most recently edited note
- **Navigating between notes:** The included syntax script highlights note
names as hyper links and the file type plug-in redefines |gf| to jump
between notes (the Control-w f (see |CTRL-W_f|) mapping to jump to a note
in a split window and the Control-w gf (see |CTRL-W_gf|) mapping to jump to
a note in a new tab page also work)
- **Writing aids:** The included file type plug-in contains mappings for
automatic curly quotes, arrows and list bullets and supports completion of
note titles using Control-X Control-U and completion of tags using
Control-X Control-O
- **Embedded file types:** The included syntax script supports embedded
highlighting using blocks marked with '{{{type … }}}' which allows you to
embed highlighted code and configuration snippets in your notes
Here's a screen shot of the syntax mode using the Slate [3] color scheme and
the font Monaco [4]:
Image: Syntax mode screen shot (see reference [5])
===============================================================================
*notes-install-usage*
Install & usage ~
_Please note that the vim-notes plug-in requires my vim-misc plug-in which is
separately distributed._
Unzip the most recent ZIP archives of the vim-notes [6] and vim-misc [7] plug-
ins inside your Vim profile directory (usually this is '~/.vim' on UNIX and
'%USERPROFILE%\vimfiles' on Windows), restart Vim and execute the command
':helptags ~/.vim/doc' (use ':helptags ~\vimfiles\doc' instead on Windows). To
get started execute |:Note| or ':edit note:', this will start a new note that
contains instructions on how to continue from there (and how to use the plug-in
in general).
If you prefer you can also use Pathogen [8], Vundle [9] or a similar tool to
install & update the vim-notes [10] and vim-misc [11] plug-ins using a local
clone of the git repository.
===============================================================================
*notes-options*
Options ~
All options have reasonable defaults so if the plug-in works after installation
you don't need to change any options. The options are available for people who
like to customize how the plug-in works. You can set these options in your
|vimrc| script by including a line like this:
>
:let g:notes_directories = ['~/Documents/Notes', '~/Dropbox/Shared Notes']
<
Note that after changing an option in your |vimrc| script you have to restart
Vim for the changes to take effect.
-------------------------------------------------------------------------------
The *g:notes_directories* option
Your notes are stored in one or more directories. This option defines where you
want to store your notes. Its value should be a list (there's an example above)
with one or more pathnames. The default is a single value which depends on
circumstances but should work for most people:
- If the profile directory where the plug-in is installed is writable, the
directory 'misc/notes/user' under the profile directory is used. This is
for compatibility with Pathogen [8]; the notes will be stored inside the
plug-in's bundle.
- If the above doesn't work out, the default depends on the platform:
'~/vimfiles/misc/notes/user' on Windows and '~/.vim/misc/notes/user' on
other platforms.
-------------------------------------------------------------------------------
*notes-backwards-compatibility*
Backwards compatibility ~
In the past the notes plug-in only supported a single directory and the
corresponding option was called 'g:notes_directory'. When support for multiple
notes directories was introduced the option was renamed to
|g:notes_directories| to reflect that the value is now a list of directory
pathnames.
For backwards compatibility with old configurations (all of them as of this
writing :-) the notes plug-in still uses 'g:notes_directory' when it is defined
(its no longer defined by the plug-in). However when the plug-in warns you to
change your configuration you probably should because this compatibility will
be removed at some point.
-------------------------------------------------------------------------------
The *g:notes_suffix* option
The suffix to add to generated filenames. The plug-in generates filenames for
your notes based on the title (first line) of each note and by default these
filenames don't include an extension like '.txt'. You can use this option to
make the plug-in automatically append an extension without having to embed the
extension in the note's title, e.g.:
>
:let g:notes_suffix = '.txt'
<
-------------------------------------------------------------------------------
The *g:notes_title_sync* option
When you rename a file in your notes directory but don't change the title, the
plug-in will notice this the next time you open the note in Vim. Likewise when
you change the title in another text editor but don't rename the file. By
default the plug-in will prompt you whether you want it to update the title of
the note, rename the file on disk or dismiss the prompt without doing anything.
If you set this option to the string "'no'" this feature will be completely
disabled. If you set it to "'change_title'" it will automatically change the
title to match the filename. If you set it to "'rename_file'" it will
automatically rename the file on disk to match the title.
-------------------------------------------------------------------------------
The *g:notes_smart_quotes* option
By default the notes plug-in automatically performs several substitutions on
the text you type in insert mode, for example regular quote marks are replaced
with curly quotes. The full list of substitutions can be found below in the
documentation on mappings. If you don't want the plug-in to perform these
substitutions, you can set this option to zero like this:
>
:let g:notes_smart_quotes = 0
<
-------------------------------------------------------------------------------
The *g:notes_ruler_text* option
The text of the ruler line inserted when you type '***' in quick succession. It
defaults to three asterisks separated by spaces, center aligned to the text
width.
-------------------------------------------------------------------------------
The *g:notes_list_bullets* option
A list of characters used as list bullets. When you're using a Unicode encoding
this defaults to "['•', '◦', '▸', '▹', '▪', '▫']", otherwise it defaults to
"['*', '-', '+']".
When you change the nesting level (indentation) of a line containing a bullet
point using one of the mappings 'Tab', 'Shift-Tab', 'Alt-Left' and 'Alt-Right'
the bullet point will be automatically changed to correspond to the new nesting
level.
The first level of list items gets the first bullet point in
|g:notes_list_bullets|, the second level gets the second, etc. When you're
indenting a list item to a level where the |g:notes_list_bullets| doesn't have
enough bullets, the plug-in starts again at the first bullet in the list (in
other words the selection of bullets wraps around).
-------------------------------------------------------------------------------
The *g:notes_tab_indents* option
By default 'Tab' is mapped to indent list items and 'Shift-Tab' is mapped to
dedent list items. You can disable these mappings by adding the following to
your |vimrc| script:
>
:let g:notes_tab_indents = 0
<
-------------------------------------------------------------------------------
The *g:notes_alt_indents* option
By default 'Alt-Right' is mapped to indent list items and 'Alt-Left' is mapped
to dedent list items. You can disable these mappings by adding the following to
your |vimrc| script:
>
:let g:notes_alt_indents = 0
<
-------------------------------------------------------------------------------
The *g:notes_shadowdir* option
The notes plug-in comes with some default notes containing documentation about
the plug-in. This option defines the path of the directory containing these
notes.
-------------------------------------------------------------------------------
The *g:notes_indexfile* option
This option defines the pathname of the optional keyword index used by the
|:SearchNotes| to perform accelerated keyword searching.
-------------------------------------------------------------------------------
The *g:notes_indexscript* option
This option defines the pathname of the Python script that's used to perform
accelerated keyword searching with |:SearchNotes|.
-------------------------------------------------------------------------------
The *g:notes_tagsindex* option
This option defines the pathname of the text file that stores the list of known
tags used for tag name completion and the |:ShowTaggedNotes| command. The text
file is created automatically when it's first needed, after that you can
recreate it manually by executing |:IndexTaggedNotes| (see below).
-------------------------------------------------------------------------------
The *g:notes_markdown_program* option
The |:NoteToHtml| command requires the Markdown [12] program. By default the
name of this program is assumed to be simply 'markdown'. If you want to use a
different program for Markdown to HTML conversion, set this option to the name
of the program.
===============================================================================
*notes-commands*
Commands ~
To edit one of your existing notes (or create a new one) you can use Vim
commands such as |:edit|, |:split| and |:tabedit| with a filename that starts
with _note:_ followed by (part of) the title of one of your notes, e.g.:
>
:edit note:todo
<
This shortcut also works from the command line:
>
$ gvim note:todo
<
When you don't follow _note:_ with anything a new note is created like when you
execute |:Note| without any arguments.
-------------------------------------------------------------------------------
The *:Note* command
When executed without any arguments this command starts a new note in the
current window. If you pass one or more arguments the command will edit an
existing note containing the given words in the title. If more than one note is
found you'll be asked which note you want to edit. If no notes are found a new
note is started with the given word(s) as title.
This command will fail when changes have been made to the current buffer,
unless you use ':Note!' which discards any changes.
When you are using multiple directories to store your notes and you run |:Note|
while editing an existing note, a new note will inherit the directory of the
note from which you started. Otherwise the note is created in the first
directory in |g:notes_directories|.
_This command supports tab completion:_ If you complete one word, all existing
notes containing the given word somewhere in their title are suggested. If you
type more than one word separated by spaces, the plug-in will complete only the
missing words so that the resulting command line contains the complete note
title and nothing more.
-------------------------------------------------------------------------------
The *:NoteFromSelectedText* command
Start a new note in the current window with the selected text as the title of
the note. The name of this command isn't very well suited to daily use, that's
because it's intended to be executed from a mapping. The default mapping for
this command is '\en' (the backslash is actually the character defined by the
|mapleader| variable).
When you are using multiple directories to store your notes and you run
|:NoteFromSelectedText| while editing an existing note, the new note will
inherit the directory of the note from which it was created.
-------------------------------------------------------------------------------
The *:SplitNoteFromSelectedText* command
Same as |:NoteFromSelectedText| but opens the new note in a vertical split
window. The default mapping for this command is '\sn'.
-------------------------------------------------------------------------------
The *:TabNoteFromSelectedText* command
Same as |:NoteFromSelectedText| but opens the new note in a new tab page. The
default mapping for this command is '\tn'.
-------------------------------------------------------------------------------
The *:DeleteNote* command
The |:DeleteNote| command deletes a note file, destroys the buffer and removes
the note from the internal cache of filenames and note titles. If you pass a
note name as an argument to |:DeleteNote| it will delete the given note,
otherwise it will delete the current note. This fails when changes have been
made to the buffer, unless you use ':DeleteNote!' which discards any changes.
-------------------------------------------------------------------------------
The *:SearchNotes* command
This command wraps |:vimgrep| and enables you to search through your notes
using one or more keywords or a regular expression pattern. To search for a
pattern you pass a single argument that starts/ends with a slash:
>
:SearchNotes /TODO\|FIXME\|XXX/
<
To search for one or more keywords you can just omit the slashes, this matches
notes containing all of the given keywords:
>
:SearchNotes syntax highlighting
<
-------------------------------------------------------------------------------
*searchnotes-understands-tags*
:SearchNotes understands @tags ~
If you don't pass any arguments to the |:SearchNotes| command it will search
for the word under the cursor. If the word under the cursor starts with '@'
this character will be included in the search, which makes it possible to
easily add _@tags_ to your _@notes_ and then search for those tags. To make
searching for tags even easier you can create key mappings for the
|:SearchNotes| command:
>
" Make the C-] combination search for @tags:
imap <C-]> <C-o>:SearchNotes<CR>
nmap <C-]> :SearchNotes<CR>
" Make double mouse click search for @tags. This is actually quite a lot of
" fun if you don't use the mouse for text selections anyway; you can click
" between notes as if you're in a web browser:
imap <2-LeftMouse> <C-o>:SearchNotes<CR>
nmap <2-LeftMouse> :SearchNotes<CR>
<
These mappings are currently not enabled by default because they conflict with
already useful key mappings, but if you have any suggestions for alternatives
feel free to contact me through GitHub or at peter@peterodding.com.
-------------------------------------------------------------------------------
*notes-accelerated-searching-with-python*
Accelerated searching with Python ~
After collecting a fair amount of notes (say more than 5 MB) you will probably
start to get annoyed at how long it takes Vim to search through all of your
notes. To make searching more scalable the notes plug-in includes a Python
script which uses a persistent full text index of your notes stored in a file.
The first time the Python script is run it will need to build the complete
index which can take a moment, but after the index has been initialized updates
and searches should be more or less instantaneous.
-------------------------------------------------------------------------------
The *:RelatedNotes* command
This command makes it easy to find all notes related to the current file: If
you are currently editing a note then a search for the note's title is done,
otherwise this searches for the absolute path of the current file.
-------------------------------------------------------------------------------
The *:RecentNotes* command
If you execute the |:RecentNotes| command it will open a Vim buffer that lists
all your notes grouped by the day they were edited, starting with your most
recently edited note. If you pass an argument to |:RecentNotes| it will filter
the list of notes by matching the title of each note against the argument which
is interpreted as a Vim pattern.
-------------------------------------------------------------------------------
The *:MostRecentNote* command
This command edits your most recently edited note (whether you just opened the
note or made changes to it). The plug-in will remember the most recent note
between restarts of Vim and is shared between all instances of Vim.
-------------------------------------------------------------------------------
The *:ShowTaggedNotes* command
To show a list of all notes that contains _@tags_ you can use the
|:ShowTaggedNotes| command. If you pass a count to this command it will limit
the list of tags to those that have been used at least this many times. For
example the following two commands show tags that have been used at least ten
times:
>
:10ShowTaggedNotes
:ShowTaggedNotes 10
<
-------------------------------------------------------------------------------
The *:IndexTaggedNotes* command
The notes plug-in defines an omni completion function that can be used to
complete the names of tags. To trigger the omni completion you type Control-X
Control-O. When you type '@' in insert mode the plug-in will automatically
start omni completion.
The completion menu is populated from a text file listing all your tags, one on
each line. The first time omni completion triggers, an index of tag names is
generated and saved to the location set by |g:notes_tagsindex|. After this file
is created, it will be updated automatically as you edit notes and add/remove
tags.
If for any reason you want to recreate the list of tags you can execute the
|:IndexTaggedNotes| command.
-------------------------------------------------------------------------------
The *:NoteToHtml* command
This command converts the current note to HTML. It works by first converting
the current note to Markdown [12] and then using the 'markdown' program to
convert that to HTML. It requires an external program to convert Markdown to
HTML. By default the program 'markdown' is used, but you can change the name of
the program using the |g:notes_markdown_program| option.
Note that this command can be a bit slow, because the parser for the note
taking syntax is written in Vim script (for portability) and has not been
optimized for speed (yet).
-------------------------------------------------------------------------------
The *:NoteToMarkdown* command
Convert the current note to a Markdown document [12]. The vim-notes syntax
shares a lot of similarities with the Markdown text format, but there are some
notable differences, which this command takes care of:
- The first line of a note is an implicit document title. In Markdown format
it has to be marked with '#'. This also implies that the remaining headings
should be shifted by one level.
- Preformatted blocks are marked very differently in notes and Markdown
('{{{' and '}}}' markers versus 4 space indentation).
- The markers and indentation of list items differ between notes and Markdown
(dumb bullets vs Unicode bullets and 3 vs 4 spaces).
Note that this command can be a bit slow, because the parser for the note
taking syntax is written in Vim script (for portability) and has not been
optimized for speed (yet).
===============================================================================
*notes-mappings*
Mappings ~
The following key mappings are defined inside notes.
-------------------------------------------------------------------------------
*notes-insert-mode-mappings*
Insert mode mappings ~
- '@' automatically triggers tag completion
- "'" becomes '' or '' depending on where you type it
- '"' becomes '“' or '”' (same goes for these)
- '--' becomes '—'
- '->' becomes '→'
- '<-' becomes '←'
- the bullets '*', '-' and '+' become '•'
- the three characters '***' in insert mode in quick succession insert a
horizontal ruler delimited by empty lines
- 'Tab' and 'Alt-Right' increase indentation of list items (works on the
current line and selected lines)
- 'Shift-Tab' and 'Alt-Left' decrease indentation of list items
- 'Enter' on a line with only a list bullet removes the bullet and starts a
new line below the current line
- '\en' executes |:NoteFromSelectedText|
- '\sn' executes |:SplitNoteFromSelectedText|
- '\tn' executes |:TabNoteFromSelectedText|
===============================================================================
*customizing-syntax-highlighting-of-notes*
Customizing the syntax highlighting of notes ~
The syntax mode for notes is written so you can override styles you don't like.
To do so you can add lines such as the following to your |vimrc| script:
>
" Don't highlight single quoted strings.
highlight link notesSingleQuoted Normal
" Show double quoted strings in italic font.
highlight notesDoubleQuoted gui=italic
<
See the documentation of the |:highlight| command for more information. Below
are the names of the syntax items defined by the notes syntax mode:
- 'notesName' - the names of other notes, usually highlighted as a hyperlink
- 'notesTagName' - words preceded by an '@' character, also highlighted as a
hyperlink
- 'notesListBullet' - the bullet characters used for list items
- 'notesListNumber' - numbers in front of list items
- 'notesDoubleQuoted' - double quoted strings
- 'notesSingleQuoted' - single quoted strings
- 'notesItalic' - strings between two '_' characters
- 'notesBold' - strings between two '*' characters
- 'notesTextURL' - plain domain name (recognized by leading 'www.')
- 'notesRealURL' - URLs (e.g. http://vim.org/)
- 'notesEmailAddr' - e-mail addresses
- 'notesUnixPath' - UNIX file paths (e.g. '~/.vimrc' and
'/home/peter/.vimrc')
- 'notesPathLnum' - line number following a UNIX path
- 'notesWindowsPath' - Windows file paths (e.g. 'c:\users\peter\_vimrc')
- 'notesTodo' - 'TODO' markers
- 'notesXXX' - 'XXX' markers
- 'notesFixMe' - 'FIXME' markers
- 'notesInProgress' - 'CURRENT', 'INPROGRESS', 'STARTED' and 'WIP' markers
- 'notesDoneItem' - lines containing the marker 'DONE', usually highlighted
as a comment
- 'notesDoneMarker' - 'DONE' markers
- 'notesVimCmd' - Vim commands, words preceded by an ':' character
- 'notesTitle' - the first line of each note
- 'notesShortHeading' - short sentences ending in a ':' character
- 'notesAtxHeading' - lines preceded by one or more '#' characters
- 'notesBlockQuote' - lines preceded by a '>' character
- 'notesRule' - lines containing only whitespace and '* * *'
- 'notesCodeStart' - the '{{{' markers that begin a block of code (including
the syntax name)
- 'notesCodeEnd' - the '}}}' markers that end a block of code
- 'notesModeLine' - Vim |modeline| in last line of notes
- 'notesLastEdited' - last edited dates in |:ShowTaggedNotes| buffers
===============================================================================
*other-plug-ins-that-work-well-with-notes-plug-in*
Other plug-ins that work well with the notes plug-in ~
-------------------------------------------------------------------------------
*notes-utl.vim*
utl.vim ~
The utl.vim [13] universal text linking plug-in enables links between your
notes, other local files and remote resources like web pages.
-------------------------------------------------------------------------------
*notes-shell.vim*
shell.vim ~
My shell.vim [14] plug-in also enables easy navigation between your notes and
environment like local files and directories, web pages and e-mail addresses by
providing key mappings and commands to e.g. open the file/URL under the text
cursor. This plug-in can also change Vim to full screen which can be really
nice for large notes.
-------------------------------------------------------------------------------
*notes-voom*
VOoM ~
The VOoM [15] outlining plug-in should work well for notes if you use the
Markdown style headers starting with '#', however it has been reported that
this combination may not always work so well in practice (sometimes losing
notes!)
-------------------------------------------------------------------------------
*notes-txtfmt*
Txtfmt ~
If the text formatting supported by the notes plug-in is not enough for you,
consider trying the Txtfmt [16] (The Vim Highlighter) plug-in. To use the two
plug-ins together, create the file 'after/ftplugin/notes.vim' inside your Vim
profile with the following contents:
>
" Enable Txtfmt formatting inside notes.
setlocal filetype=notes.txtfmt
<
===============================================================================
*notes-contact*
Contact ~
If you have questions, bug reports, suggestions, etc. the author can be
contacted at peter@peterodding.com. The latest version is available at
http://peterodding.com/code/vim/notes/ and http://github.com/xolox/vim-notes.
If you like the script please vote for it on Vim Online [17].
===============================================================================
*notes-license*
License ~
This software is licensed under the MIT license [18]. © 2013 Peter Odding
<peter@peterodding.com>.
===============================================================================
*notes-references*
References ~
[1] http://en.wikipedia.org/wiki/Levenshtein_distance
[2] http://python.org/
[3] http://code.google.com/p/vim/source/browse/runtime/colors/slate.vim
[4] http://en.wikipedia.org/wiki/Monaco_(typeface)
[5] http://peterodding.com/code/vim/notes/syntax.png
[6] http://peterodding.com/code/vim/downloads/notes.zip
[7] http://peterodding.com/code/vim/downloads/misc.zip
[8] http://www.vim.org/scripts/script.php?script_id=2332
[9] https://github.com/gmarik/vundle
[10] http://github.com/xolox/vim-notes
[11] http://github.com/xolox/vim-misc
[12] http://en.wikipedia.org/wiki/Markdown
[13] http://www.vim.org/scripts/script.php?script_id=293
[14] http://www.vim.org/scripts/script.php?script_id=3123
[15] http://www.vim.org/scripts/script.php?script_id=2657
[16] http://www.vim.org/scripts/script.php?script_id=2208
[17] http://www.vim.org/scripts/script.php?script_id=3375
[18] http://en.wikipedia.org/wiki/MIT_License
vim: ft=help

View File

@ -0,0 +1,141 @@
" Vim file type plug-in
" Author: Peter Odding <peter@peterodding.com>
" Last Change: May 16, 2013
" URL: http://peterodding.com/code/vim/notes/
if exists('b:did_ftplugin')
finish
else
let b:did_ftplugin = 1
endif
" Copy indent from previous line. {{{1
setlocal autoindent
let b:undo_ftplugin = 'set autoindent<'
" Set &tabstop and &shiftwidth options for bulleted lists. {{{1
setlocal tabstop=3 shiftwidth=3 expandtab
let b:undo_ftplugin .= ' | set tabstop< shiftwidth< expandtab<'
" Automatic formatting for bulleted lists. {{{1
let &l:comments = xolox#notes#get_comments_option()
setlocal formatoptions=tcron
let b:undo_ftplugin .= ' | set comments< formatoptions<'
" Automatic text folding based on headings. {{{1
setlocal foldmethod=expr
setlocal foldexpr=xolox#notes#foldexpr()
setlocal foldtext=xolox#notes#foldtext()
let b:undo_ftplugin .= ' | set foldmethod< foldexpr< foldtext<'
" Enable concealing of notes syntax markers? {{{1
if has('conceal')
setlocal conceallevel=3
let b:undo_ftplugin .= ' | set conceallevel<'
endif
" Change <cfile> to jump to notes by name. {{{1
setlocal includeexpr=xolox#notes#include_expr(v:fname)
let b:undo_ftplugin .= ' | set includeexpr<'
" Enable completion of note titles using C-x C-u. {{{1
setlocal completefunc=xolox#notes#user_complete
let b:undo_ftplugin .= ' | set completefunc<'
" Enable completion of tag names using C-x C-o. {{{1
setlocal omnifunc=xolox#notes#omni_complete
let b:undo_ftplugin .= ' | set omnifunc<'
" Automatic completion of tag names after typing "@". {{{1
inoremap <buffer> <silent> @ @<C-x><C-o>
let b:undo_ftplugin .= ' | execute "iunmap <buffer> @"'
" Automatic completion of tag names should not interrupt the flow of typing,
" for this we have to change the (unfortunately) global option &completeopt.
set completeopt+=longest
" Change double-dash to em-dash as it is typed. {{{1
if g:notes_smart_quotes && xolox#notes#unicode_enabled()
inoremap <buffer> --
let b:undo_ftplugin .= ' | execute "iunmap <buffer> --"'
endif
" Change plain quotes to curly quotes as they're typed. {{{1
if g:notes_smart_quotes
inoremap <buffer> <expr> ' xolox#notes#insert_quote(1)
inoremap <buffer> <expr> " xolox#notes#insert_quote(2)
let b:undo_ftplugin .= ' | execute "iunmap <buffer> ''"'
let b:undo_ftplugin .= ' | execute ''iunmap <buffer> "'''
endif
" Change ASCII style arrows to Unicode arrows. {{{1
if g:notes_smart_quotes && xolox#notes#unicode_enabled()
inoremap <buffer> ->
inoremap <buffer> <-
let b:undo_ftplugin .= ' | execute "iunmap <buffer> ->"'
let b:undo_ftplugin .= ' | execute "iunmap <buffer> <-"'
endif
" Convert ASCII list bullets to Unicode bullets. {{{1
if g:notes_smart_quotes
inoremap <buffer> <expr> * xolox#notes#insert_bullet('*')
inoremap <buffer> <expr> - xolox#notes#insert_bullet('-')
inoremap <buffer> <expr> + xolox#notes#insert_bullet('+')
let b:undo_ftplugin .= ' | execute "iunmap <buffer> *"'
let b:undo_ftplugin .= ' | execute "iunmap <buffer> -"'
let b:undo_ftplugin .= ' | execute "iunmap <buffer> +"'
endif
" Format three asterisks as a horizontal ruler. {{{1
inoremap <buffer> *** <C-o>:call xolox#notes#insert_ruler()<CR>
let b:undo_ftplugin .= ' | execute "iunmap <buffer> ***"'
" Indent list items using <Tab> and <Shift-Tab>? {{{1
if g:notes_tab_indents
inoremap <buffer> <silent> <Tab> <C-o>:call xolox#notes#indent_list(1, line('.'), line('.'))<CR>
snoremap <buffer> <silent> <Tab> <C-o>:<C-u>call xolox#notes#indent_list(1, line("'<"), line("'>"))<CR><C-o>gv
let b:undo_ftplugin .= ' | execute "iunmap <buffer> <Tab>"'
let b:undo_ftplugin .= ' | execute "sunmap <buffer> <Tab>"'
inoremap <buffer> <silent> <S-Tab> <C-o>:call xolox#notes#indent_list(-1, line('.'), line('.'))<CR>
snoremap <buffer> <silent> <S-Tab> <C-o>:<C-u>call xolox#notes#indent_list(-1, line("'<"), line("'>"))<CR><C-o>gv
let b:undo_ftplugin .= ' | execute "iunmap <buffer> <S-Tab>"'
let b:undo_ftplugin .= ' | execute "sunmap <buffer> <S-Tab>"'
endif
" Indent list items using <Alt-Left> and <Alt-Right>? {{{1
if g:notes_alt_indents
inoremap <buffer> <silent> <A-Right> <C-o>:call xolox#notes#indent_list(1, line('.'), line('.'))<CR>
snoremap <buffer> <silent> <A-Right> <C-o>:<C-u>call xolox#notes#indent_list(1, line("'<"), line("'>"))<CR><C-o>gv
let b:undo_ftplugin .= ' | execute "iunmap <buffer> <A-Right>"'
let b:undo_ftplugin .= ' | execute "sunmap <buffer> <A-Right>"'
inoremap <buffer> <silent> <A-Left> <C-o>:call xolox#notes#indent_list(-1, line('.'), line('.'))<CR>
snoremap <buffer> <silent> <A-Left> <C-o>:<C-u>call xolox#notes#indent_list(-1, line("'<"), line("'>"))<CR><C-o>gv
let b:undo_ftplugin .= ' | execute "iunmap <buffer> <A-Left>"'
let b:undo_ftplugin .= ' | execute "sunmap <buffer> <A-Left>"'
endif
" Automatically remove empty list items on Enter. {{{1
inoremap <buffer> <silent> <expr> <CR> xolox#notes#cleanup_list()
let b:undo_ftplugin .= ' | execute "iunmap <buffer> <CR>"'
" Shortcuts to create new notes from the selected text. {{{1
vnoremap <buffer> <silent> <Leader>en :NoteFromSelectedText<CR>
let b:undo_ftplugin .= ' | execute "vunmap <buffer> <Leader>en"'
vnoremap <buffer> <silent> <Leader>sn :SplitNoteFromSelectedText<CR>
let b:undo_ftplugin .= ' | execute "vunmap <buffer> <Leader>sn"'
vnoremap <buffer> <silent> <Leader>tn :TabNoteFromSelectedText<CR>
let b:undo_ftplugin .= ' | execute "vunmap <buffer> <Leader>tn"'
" }}}1
" This is currently the only place where a command is guaranteed to be
" executed when the user edits a note. Maybe I shouldn't abuse this (it
" doesn't feel right ;-) but for now it will do.
call xolox#notes#recent#track()
call xolox#notes#check_sync_title()
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,312 @@
#!/usr/bin/env python
# Python script for fast text file searching using keyword index on disk.
#
# Author: Peter Odding <peter@peterodding.com>
# Last Change: September 2, 2013
# URL: http://peterodding.com/code/vim/notes/
# License: MIT
#
# This Python script can be used by the notes.vim plug-in to perform fast
# keyword searches in the user's notes. It has two advantages over just
# using Vim's internal :vimgrep command to search all of the user's notes:
#
# - Very large notes don't slow searching down so much;
# - Hundreds of notes can be searched in less than a second.
#
# The keyword index is a Python dictionary that's persisted using the pickle
# module. The structure of the dictionary may seem very naive but it's quite
# fast. Also the pickle protocol makes sure repeating strings are stored only
# once, so it's not as bad as it may appear at first sight :-).
#
# For more information about the Vim plug-in see http://peterodding.com/code/vim/notes/.
"""
Usage: search-notes.py [OPTIONS] KEYWORD...
Search one or more directories of plain text files using a full text index,
updated automatically during each invocation of the program.
Valid options include:
-i, --ignore-case ignore case of keyword(s)
-l, --list=SUBSTR list keywords matching substring
-d, --database=FILE set path to keywords index file
-n, --notes=DIR set directory with user notes (can be repeated)
-e, --encoding=NAME set character encoding of notes
-v, --verbose make more noise
-h, --help show this message and exit
For more information see http://peterodding.com/code/vim/notes/
"""
# Standard library modules.
import fnmatch
import getopt
import logging
import os
import re
import sys
import time
# Load the faster C variant of the pickle module where possible, but
# fall back to the Python implementation that's always available.
try:
import cPickle as pickle
except ImportError:
import pickle
# Try to import the Levenshtein module, don't error out if it's not installed.
try:
import Levenshtein
levenshtein_supported = True
except ImportError:
levenshtein_supported = False
# The version of the index format that's supported by this revision of the
# `search-notes.py' script; if an existing index file is found with an
# unsupported version, the script knows that it should rebuild the index.
INDEX_VERSION = 2
class NotesIndex:
def __init__(self):
''' Entry point to the notes search. '''
global_timer = Timer()
self.init_logging()
keywords = self.parse_args()
self.load_index()
self.update_index()
if self.dirty:
self.save_index()
print "Python works fine!"
if self.keyword_filter is not None:
self.list_keywords(self.keyword_filter)
self.logger.debug("Finished listing keywords in %s", global_timer)
else:
matches = self.search_index(keywords)
if matches:
print '\n'.join(sorted(matches))
self.logger.debug("Finished searching index in %s", global_timer)
def init_logging(self):
''' Initialize the logging subsystem. '''
self.logger = logging.getLogger('search-notes')
self.logger.addHandler(logging.StreamHandler(sys.stderr))
if os.isatty(0):
self.logger.setLevel(logging.INFO)
def parse_args(self):
''' Parse the command line arguments. '''
try:
opts, keywords = getopt.getopt(sys.argv[1:], 'il:d:n:e:vh',
['ignore-case', 'list=', 'database=', 'notes=', 'encoding=', 'verbose', 'help'])
except getopt.GetoptError, error:
print str(error)
self.usage()
sys.exit(2)
# Define the command line option defaults.
self.database_file = '~/.vim/misc/notes/index.pickle'
self.user_directories = ['~/.vim/misc/notes/user/']
self.character_encoding = 'UTF-8'
self.case_sensitive = True
self.keyword_filter = None
# Map command line options to variables.
for opt, arg in opts:
if opt in ('-i', '--ignore-case'):
self.case_sensitive = False
self.logger.debug("Disabling case sensitivity")
elif opt in ('-l', '--list'):
self.keyword_filter = arg.strip().lower()
elif opt in ('-d', '--database'):
self.database_file = arg
elif opt in ('-n', '--notes'):
self.user_directories.append(arg)
elif opt in ('-e', '--encoding'):
self.character_encoding = arg
elif opt in ('-v', '--verbose'):
self.logger.setLevel(logging.DEBUG)
elif opt in ('-h', '--help'):
self.usage()
sys.exit(0)
else:
assert False, "Unhandled option"
self.logger.debug("Index file: %s", self.database_file)
self.logger.debug("Notes directories: %r", self.user_directories)
self.logger.debug("Character encoding: %s", self.character_encoding)
if self.keyword_filter is not None:
self.keyword_filter = self.decode(self.keyword_filter)
# Canonicalize pathnames, check validity.
self.database_file = self.munge_path(self.database_file)
self.user_directories = map(self.munge_path, self.user_directories)
self.user_directories = filter(os.path.isdir, self.user_directories)
if not any(os.path.isdir(p) for p in self.user_directories):
sys.stderr.write("None of the notes directories exist!\n")
sys.exit(1)
# Return tokenized keyword arguments.
return [self.normalize(k) for k in self.tokenize(' '.join(keywords))]
def load_index(self):
''' Load the keyword index or start with an empty one. '''
try:
load_timer = Timer()
self.logger.debug("Loading index from %s ..", self.database_file)
with open(self.database_file) as handle:
self.index = pickle.load(handle)
self.logger.debug("Format version of index loaded from disk: %i", self.index['version'])
assert self.index['version'] == INDEX_VERSION, "Incompatible index format detected!"
self.first_use = False
self.dirty = False
self.logger.debug("Loaded %i notes from index in %s", len(self.index['files']), load_timer)
except Exception, e:
self.logger.warn("Failed to load index from file: %s", e)
self.first_use = True
self.dirty = True
self.index = {'keywords': {}, 'files': {}, 'version': INDEX_VERSION}
def save_index(self):
''' Save the keyword index to disk. '''
save_timer = Timer()
with open(self.database_file, 'w') as handle:
pickle.dump(self.index, handle)
self.logger.debug("Saved index to disk in %s", save_timer)
def update_index(self):
''' Update the keyword index by scanning the notes directory. '''
update_timer = Timer()
# First we find the filenames and last modified times of the notes on disk.
notes_on_disk = {}
last_count = 0
for directory in self.user_directories:
for filename in os.listdir(directory):
# Vim swap files are ignored.
if (filename != '.swp' and not fnmatch.fnmatch(filename, '.s??')
and not fnmatch.fnmatch(filename, '.*.s??')):
abspath = os.path.join(directory, filename)
if os.path.isfile(abspath):
notes_on_disk[abspath] = os.path.getmtime(abspath)
self.logger.info("Found %i notes in %s ..", len(notes_on_disk) - last_count, directory)
last_count = len(notes_on_disk)
# Check for updated and/or deleted notes since the last run?
if not self.first_use:
for filename in self.index['files'].keys():
if filename not in notes_on_disk:
# Forget a deleted note.
self.delete_note(filename)
else:
# Check whether previously seen note has changed?
last_modified_on_disk = notes_on_disk[filename]
last_modified_in_db = self.index['files'][filename]
if last_modified_on_disk > last_modified_in_db:
self.delete_note(filename)
self.add_note(filename, last_modified_on_disk)
# Already checked this note, we can forget about it.
del notes_on_disk[filename]
# Add new notes to index.
for filename, last_modified in notes_on_disk.iteritems():
self.add_note(filename, last_modified)
self.logger.debug("Updated index in %s", update_timer)
def add_note(self, filename, last_modified):
''' Add a note to the index (assumes the note is not already indexed). '''
self.logger.info("Adding file to index: %s", filename)
self.index['files'][filename] = last_modified
with open(filename) as handle:
for kw in self.tokenize(handle.read()):
if kw not in self.index['keywords']:
self.index['keywords'][kw] = [filename]
else:
self.index['keywords'][kw].append(filename)
self.dirty = True
def delete_note(self, filename):
''' Remove a note from the index. '''
self.logger.info("Removing file from index: %s", filename)
del self.index['files'][filename]
for kw in self.index['keywords']:
self.index['keywords'][kw] = [x for x in self.index['keywords'][kw] if x != filename]
self.dirty = True
def search_index(self, keywords):
''' Return names of files containing all of the given keywords. '''
matches = None
normalized_db_keywords = [(k, self.normalize(k)) for k in self.index['keywords']]
for usr_kw in keywords:
submatches = set()
for original_db_kw, normalized_db_kw in normalized_db_keywords:
# Yes I'm using a nested for loop over all keywords in the index. If
# I really have to I'll probably come up with something more
# efficient, but really it doesn't seem to be needed -- I have over
# 850 notes (about 8 MB) and 25000 keywords and it's plenty fast.
if usr_kw in normalized_db_kw:
submatches.update(self.index['keywords'][original_db_kw])
if matches is None:
matches = submatches
else:
matches &= submatches
return list(matches) if matches else []
def list_keywords(self, substring, limit=25):
''' Print all (matching) keywords to standard output. '''
decorated = []
substring = self.normalize(substring)
for kw, filenames in self.index['keywords'].iteritems():
normalized_kw = self.normalize(kw)
if substring in normalized_kw:
if levenshtein_supported:
decorated.append((Levenshtein.distance(normalized_kw, substring), -len(filenames), kw))
else:
decorated.append((-len(filenames), kw))
decorated.sort()
selection = [d[-1] for d in decorated[:limit]]
print self.encode(u'\n'.join(selection))
def tokenize(self, text):
''' Tokenize a string into a list of normalized, unique keywords. '''
words = set()
text = self.decode(text)
for word in re.findall(r'\w+', text, re.UNICODE):
word = word.strip()
if word != '' and not word.isspace() and len(word) >= 2:
words.add(word)
return words
def normalize(self, keyword):
''' Normalize the case of a keyword if configured to do so. '''
return keyword if self.case_sensitive else keyword.lower()
def encode(self, text):
''' Encode a string in the user's preferred character encoding. '''
return text.encode(self.character_encoding, 'ignore')
def decode(self, text):
''' Decode a string in the user's preferred character encoding. '''
return text.decode(self.character_encoding, 'ignore')
def munge_path(self, path):
''' Canonicalize user-defined path, making it absolute. '''
return os.path.abspath(os.path.expanduser(path))
def usage(self):
print __doc__.strip()
class Timer:
"""
Easy to use timer to keep track of long during operations.
"""
def __init__(self):
self.start_time = time.time()
def __str__(self):
return "%.2f seconds" % self.elapsed_time
@property
def elapsed_time(self):
return time.time() - self.start_time
if __name__ == '__main__':
NotesIndex()
# vim: ts=2 sw=2 et

View File

@ -0,0 +1,13 @@
New note
To get started enter a title for your note above. When youre ready to save
your note just use Vims :write or :update commands, a filename will be picked
automatically based on the title.
* * *
The notes plug-in comes with self hosting documentation. To jump to these notes
position your cursor on the highlighted name and press gf in normal mode:
• Note taking syntax
• Note taking commands

View File

@ -0,0 +1,94 @@
Note taking commands
To edit existing notes you can use Vim commands such as :edit, :split and
:tabedit with a filename that starts with note: followed by (part of) the
title of one of your notes, e.g.:
{{{vim
:edit note:todo
}}}
When you dont follow note: with anything a new note is created.
The following commands can be used to manage your notes:
# :Note starts new notes and edits existing ones
If you dont pass any arguments to the :Note command it will start editing a
new note. If you pass (part of) of the title of one of your existing notes that
note will be edited. If no notes match the given argument then a new note is
created with its title set to the text you passed to :Note. This command will
fail when changes have been made to the current buffer, unless you use :Note!
which discards any changes.
To start a new note and use the currently selected text as the title for the
note you can use the :NoteFromSelectedText command. The name of this command
isnt very well suited to daily use, however the idea is that users will define
their own mapping to invoke this command. For example:
{{{vim
" Map \ns in visual mode to start new note with selected text as title.
vmap <Leader>ns :NoteFromSelectedText<CR>
}}}
# :DeleteNote deletes the current note
The :DeleteNote command deletes the current note, destroys the buffer and
removes the note from the internal cache of filenames and note titles. This
fails when changes have been made to the current buffer, unless you use
:DeleteNote! which discards any changes.
# :SearchNotes searches your notes
This command wraps :vimgrep and enables you to search through your notes using
a regular expression pattern or keywords. To search for a pattern you pass a
single argument that starts & ends with a slash:
:SearchNotes /TODO\|FIXME\|XXX/
To search for one or more keywords you can just omit the slashes, this matches
notes containing all of the given keywords:
:SearchNotes syntax highlighting
## :SearchNotes understands @tags
If you dont pass any arguments to the :SearchNotes command it will search for
the word under the cursor. If the word under the cursor starts with @ this
character will be included in the search, which makes it possible to easily
add @tags to your @notes and then search for those tags. To make searching for
tags even easier you can create key mappings for the :SearchNotes command:
{{{vim
" Make the C-] combination search for @tags:
imap <C-]> <C-o>:SearchNotes<CR>
nmap <C-]> :SearchNotes<CR>
" Make double mouse click search for @tags. This is actually quite a lot of
" fun if you dont use the mouse for text selections anyway; you can click
" between notes as if youre in a web browser:
imap <2-LeftMouse> <C-o>:SearchNotes<CR>
nmap <2-LeftMouse> :SearchNotes<CR>
}}}
These mappings are currently not enabled by default because they conflict with
already useful key mappings, but if you have any suggestions for alternatives
feel free to contact me through GitHub or at peter@peterodding.com.
## Accelerated searching with Python
After collecting a fair amount of notes (say >= 5 MB) you will probably start
to get annoyed at how long it takes Vim to search through all of your notes. To
make searching more scalable the notes plug-in includes a Python script which
uses a persistent keyword index of your notes stored in a file.
The first time the Python script is run it will need to build the complete
index which can take a moment, but after the index has been initialized
updates and searches should be more or less instantaneous.
# :RelatedNotes finds related notes
This command makes it easy to find all notes related to the current file: If
you are currently editing a note then a search for the notes title is done,
otherwise this searches for the absolute path of the current file.
# :RecentNotes lists notes by modification date
If you execute the :RecentNotes command it will open a Vim buffer that lists
all your notes grouped by the day they were edited, starting with your most
recently edited note. If you pass an argument to :RecentNotes it will filter
the list of notes by matching the title of each note against the argument which
is interpreted as a Vim pattern.

View File

@ -0,0 +1,54 @@
Note taking syntax
This note contains examples of the syntax highlighting styles supported by the
notes plug-in. When your Vim configuration supports concealing of text, the
markers which enable the syntax highlighting wont be visible. In this case you
can make the markers visible by selecting the text.
# Headings
Lines prefixed with one or more # symbols are headings which can be used for
automatic text folding. Theres also an alternative heading format which isnt
folded, it consists of a line shorter than 60 letters that starts with an
uppercase letter and ends in a colon (the hard wrapping in this paragraph
illustrates why the “starts with uppercase” rule is needed):
# Inline formatting
Text styles:
• _italic text_
• *bold text*
Hyper links and such:
• Hyper links: http://www.vim.org/, sftp://server/file
• Domain names: www.python.org
• E-mail addresses: user@host.ext
• UNIX filenames: ~/relative/to/home, /absolute/path
• Windows filenames: ~\relative\to\home, c:\absolute\path, \\server\share
# Lists
Bulleted lists can be used for to-do lists:
• DONE Publish my notes.vim plug-in
• TODO Write an indent script for atx headings
• XXX This one is really important
Numbered lists are also supported:
1. And You can
2) use any type
3/ of marker
# Block quotes
> Quotes are written using
> the convention from e-mail
# Embedded syntax highlighting
If you type three { characters followed by the name of a Vim file type, all
text until the three closing } characters will be highlighted using the
indicated file type. Here are some examples of the Fibonacci sequence:
Lua: {{{lua function fib(n) return n < 2 and n or fib(n - 1) + fib(n - 2) end }}}
Vim script: {{{vim function fib(n) | return n < 2 ? n : fib(n - 1) + fib(n - 2) | endfunction }}}
Python: {{{python def fib(n): return n < 2 and n or fib(n - 1) + fib(n - 2) }}}

View File

@ -0,0 +1,40 @@
<!doctype html>
<html>
<head>
<meta charset="{{ encoding }}">
<title>{{ title }}</title>
<!-- jQuery from the Google CDN. -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<!-- Bootstrap CSS & JS from the Bootstrap CDN. -->
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" >
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<style type="text/css">
body {
margin: 2.5em auto 10em auto;
width: 50em;
max-width: 90%;
}
h2 { margin-top: 1.5em; }
h3 { margin-top: 1.25em; }
h4 { margin-top: 1em; }
h5 { margin-top: 0.75em; }
h6 { margin-top: 0.5em; }
hr { margin: 5em 0; }
#footer {
margin-top: 5em;
opacity: 0.5;
line-height: 2.5em;
}
#footer:hover { opacity: 1.0; }
</style>
</head>
<body>
<div id="content">
{{ content }}
</div>
<div id="footer">
Exported by <a href="http://peterodding.com/code/vim/notes/" class="btn">vim-notes {{ version }}</a>
on {{ date }} based on the note <code>{{ filename }}</code>.
</div>
</body>
</html>

View File

@ -0,0 +1,79 @@
" Vim plug-in
" Author: Peter Odding <peter@peterodding.com>
" Last Change: August 19, 2013
" URL: http://peterodding.com/code/vim/notes/
" Support for automatic update using the GLVS plug-in.
" GetLatestVimScripts: 3375 1 :AutoInstall: notes.zip
" Don't source the plug-in when it's already been loaded or &compatible is set.
if &cp || exists('g:loaded_notes')
finish
endif
" Make sure vim-misc is installed.
try
" The point of this code is to do something completely innocent while making
" sure the vim-misc plug-in is installed. We specifically don't use Vim's
" exists() function because it doesn't load auto-load scripts that haven't
" already been loaded yet (last tested on Vim 7.3).
call type(g:xolox#misc#version)
catch
echomsg "Warning: The vim-notes plug-in requires the vim-misc plug-in which seems not to be installed! For more information please review the installation instructions in the readme (also available on the homepage and on GitHub). The vim-notes plug-in will now be disabled."
let g:loaded_notes = 1
finish
endtry
" Initialize the configuration defaults.
call xolox#notes#init()
" User commands to create, delete and search notes.
command! -bar -bang -nargs=? -complete=customlist,xolox#notes#cmd_complete Note call xolox#notes#edit(<q-bang>, <q-args>)
command! -bar -bang -nargs=? -complete=customlist,xolox#notes#cmd_complete DeleteNote call xolox#notes#delete(<q-bang>, <q-args>)
command! -bang -nargs=? -complete=customlist,xolox#notes#keyword_complete SearchNotes call xolox#notes#search(<q-bang>, <q-args>)
command! -bar -bang RelatedNotes call xolox#notes#related(<q-bang>)
command! -bar -bang -nargs=? RecentNotes call xolox#notes#recent#show(<q-bang>, <q-args>)
command! -bar -bang MostRecentNote call xolox#notes#recent#edit(<q-bang>)
command! -bar -count=1 ShowTaggedNotes call xolox#notes#tags#show_tags(<count>)
command! -bar IndexTaggedNotes call xolox#notes#tags#create_index()
command! -bar NoteToMarkdown call xolox#notes#markdown#view()
command! -bar NoteToHtml call xolox#notes#html#view()
" TODO Generalize this so we have one command + modifiers (like :tab)?
command! -bar -bang -range NoteFromSelectedText call xolox#notes#from_selection(<q-bang>, 'edit')
command! -bar -bang -range SplitNoteFromSelectedText call xolox#notes#from_selection(<q-bang>, 'vsplit')
command! -bar -bang -range TabNoteFromSelectedText call xolox#notes#from_selection(<q-bang>, 'tabnew')
" Automatic commands to enable the :edit note:… shortcut and load the notes file type.
augroup PluginNotes
autocmd!
au SwapExists * call xolox#notes#swaphack()
au BufUnload * call xolox#notes#unload_from_cache()
au BufReadPost,BufWritePost * call xolox#notes#refresh_syntax()
au InsertEnter,InsertLeave * call xolox#notes#refresh_syntax()
au CursorHold,CursorHoldI * call xolox#notes#refresh_syntax()
" NB: "nested" is used here so that SwapExists automatic commands apply
" to notes (which is IMHO better than always showing the E325 prompt).
au BufReadCmd note:* nested call xolox#notes#shortcut()
" Automatic commands to read/write notes (used for automatic renaming).
exe 'au BufReadCmd' xolox#notes#autocmd_pattern(g:notes_shadowdir, 0) 'call xolox#notes#edit_shadow()'
for s:directory in xolox#notes#find_directories(0)
exe 'au BufWriteCmd' xolox#notes#autocmd_pattern(s:directory, 1) 'call xolox#notes#save()'
endfor
unlet s:directory
augroup END
augroup filetypedetect
let s:template = 'au BufNewFile,BufRead %s if &bt == "" | setl ft=notes | end'
for s:directory in xolox#notes#find_directories(0)
execute printf(s:template, xolox#notes#autocmd_pattern(s:directory, 1))
endfor
unlet s:directory
execute printf(s:template, xolox#notes#autocmd_pattern(g:notes_shadowdir, 0))
augroup END
" Make sure the plug-in is only loaded once.
let g:loaded_notes = 1
" vim: ts=2 sw=2 et

View File

@ -0,0 +1,162 @@
" Vim syntax script
" Author: Peter Odding <peter@peterodding.com>
" Last Change: July 16, 2013
" URL: http://peterodding.com/code/vim/notes/
" Note: This file is encoded in UTF-8 including a byte order mark so
" that Vim loads the script using the right encoding transparently.
" Quit when a syntax file was already loaded.
if exists('b:current_syntax')
finish
endif
" Check for spelling errors in all text.
syntax spell toplevel
" Inline elements. {{{1
" Cluster of elements which never contain a newline character.
syntax cluster notesInline contains=notesName
" Default highlighting style for notes syntax markers.
highlight def link notesHiddenMarker Ignore
" Highlight note names as hyperlinks. {{{2
call xolox#notes#highlight_names(1)
syntax cluster notesInline add=notesName
highlight def link notesName Underlined
" Highlight @tags as hyperlinks. {{{2
syntax match notesTagName /\(^\|\s\)\@<=@\k\+/
highlight def link notesTagName Underlined
" Highlight list bullets and numbers. {{{2
execute 'syntax match notesListBullet /' . escape(xolox#notes#leading_bullet_pattern(), '/') . '/'
highlight def link notesListBullet Comment
syntax match notesListNumber /^\s*\zs\d\+[[:punct:]]\?\ze\s/
highlight def link notesListNumber Comment
" Highlight quoted fragments. {{{2
if xolox#notes#unicode_enabled()
syntax match notesDoubleQuoted /“.\{-}”/
syntax match notesSingleQuoted /.\{-}/
else
syntax match notesDoubleQuoted /".\{-}"/
syntax match notesSingleQuoted /`.\{-}'/
endif
highlight def link notesSingleQuoted Special
highlight def link notesDoubleQuoted String
" Highlight text emphasized in italic font. {{{2
if has('conceal')
syntax region notesItalic matchgroup=notesItalicMarker start=/\<_\k\@=/ end=/_\>\|\n/ contains=@Spell concealends
highlight link notesItalicMarker notesHiddenMarker
else
syntax match notesItalic /\<_\k[^_]*\k_\>/
endif
syntax cluster notesInline add=notesItalic
highlight notesItalic gui=italic cterm=italic
" Highlight text emphasized in bold font. {{{2
if has('conceal')
syntax region notesBold matchgroup=notesBoldMarker start=/\*\k\@=/ end=/\S\@<=\*/ contains=@Spell concealends
highlight link notesBoldMarker notesHiddenMarker
else
syntax match notesBold /\*\k[^*]*\k\*/
endif
syntax cluster notesInline add=notesBold
highlight notesBold gui=bold cterm=bold
" Highlight domain names, URLs, e-mail addresses and filenames. {{{2
" FIXME This setting is lost once the user switches color scheme!
highlight notesSubtleURL gui=underline guifg=fg
syntax match notesTextURL @\<www\.\(\S*\w\)\+/\?@
syntax cluster notesInline add=notesTextURL
highlight def link notesTextURL notesSubtleURL
execute printf('syntax match notesRealURL @%s@', g:xolox#notes#url_pattern)
syntax cluster notesInline add=notesRealURL
highlight def link notesRealURL notesSubtleURL
if has('conceal')
syntax match notesUrlScheme @\(mailto:\|javascript:\|\w\{3,}://\)@ contained containedin=notesRealURL conceal
highlight def link notesUrlScheme notesRealURL
endif
syntax match notesEmailAddr /\<\w[^@ \t\r]*\w@\w[^@ \t\r]\+\w\>/
syntax cluster notesInline add=notesEmailAddr
highlight def link notesEmailAddr notesSubtleURL
syntax match notesUnixPath /\k\@<![\/~]\S\+\(\/\|[^ [:punct:]]\)/
syntax cluster notesInline add=notesUnixPath
highlight def link notesUnixPath Directory
syntax match notesPathLnum /:\d\+/ contained containedin=notesUnixPath
highlight def link notesPathLnum Comment
syntax match notesWindowsPath /\k\@<![A-Za-z]:\S\+\([\\/]\|[^ [:punct:]]\)/
syntax cluster notesInline add=notesWindowsPath
highlight def link notesWindowsPath Directory
" Highlight TODO, DONE, FIXME and XXX markers. {{{2
syntax match notesTodo /\<TODO\>/
syntax match notesXXX /\<XXX\>/
syntax match notesFixMe /\<FIXME\>/
syntax match notesInProgress /\<\(CURRENT\|INPROGRESS\|STARTED\|WIP\)\>/
syntax match notesDoneItem /^\(\s\+\).*\<DONE\>.*\(\n\1\s.*\)*/ contains=@notesInline
syntax match notesDoneMarker /\<DONE\>/ containedin=notesDoneItem
highlight def link notesTodo WarningMsg
highlight def link notesXXX WarningMsg
highlight def link notesFixMe WarningMsg
highlight def link notesDoneItem Comment
highlight def link notesDoneMarker Question
highlight def link notesInProgress Directory
" Highlight Vim command names in :this notation. {{{2
syntax match notesVimCmd /:\w\+\(!\|\>\)/ contains=ALLBUT,@Spell
syntax cluster notesInline add=notesVimCmd
highlight def link notesVimCmd Special
" Block level elements. {{{1
" The first line of each note contains the title. {{{2
syntax match notesTitle /^.*\%1l.*$/ contains=@notesInline
highlight def link notesTitle ModeMsg
" Short sentences ending in a colon are considered headings. {{{2
syntax match notesShortHeading /^\s*\zs\u.\{1,50}\k:\ze\(\s\|$\)/ contains=@notesInline
highlight def link notesShortHeading Title
" Atx style headings are also supported. {{{2
syntax match notesAtxHeading /^#\+.*/ contains=notesAtxMarker,@notesInline
highlight def link notesAtxHeading Title
syntax match notesAtxMarker /^#\+/ contained
highlight def link notesAtxMarker Comment
" E-mail style block quotes are highlighted as comments. {{{2
syntax match notesBlockQuote /\(^\s*>.*\n\)\+/ contains=@notesInline
highlight def link notesBlockQuote Comment
" Horizontal rulers. {{{2
syntax match notesRule /\(^\s\+\)\zs\*\s\*\s\*$/
highlight def link notesRule Comment
" Highlight embedded blocks of source code, log file messages, basically anything Vim can highlight. {{{2
" NB: I've escaped these markers so that Vim doesn't interpret them when editing this file…
syntax match notesCodeStart /{{[{]\w*/
syntax match notesCodeEnd /}}[}]/
highlight def link notesCodeStart Ignore
highlight def link notesCodeEnd Ignore
call xolox#notes#highlight_sources(1)
" Hide mode line at end of file. {{{2
syntax match notesModeLine /\_^vim:.*\_s*\%$/
highlight def link notesModeLine LineNr
" Last edited dates in :ShowTaggedNotes buffers.
syntax match notesLastEdited /(last edited \(today\|yesterday\|\w\+, \w\+ \d\+, \d\+\))/
highlight def link notesLastEdited LineNr
" }}}1
" Set the currently loaded syntax mode.
let b:current_syntax = 'notes'
" vim: ts=2 sw=2 et bomb fdl=1

View File

@ -0,0 +1 @@
doc/tags

View File

@ -0,0 +1 @@
--color

View File

@ -0,0 +1,18 @@
Maintainers:
Mark Guzman <segfault@hasno.info>
Doug Kearns <dougkearns@gmail.com>
Tim Pope <vim@NOSPAMtpope.org>
Andrew Radev <andrey.radev@gmail.com>
Nikolai Weibull <now@bitwi.se>
Other contributors:
Michael Brailsford <brailsmt@yahoo.com>
Sean Flanagan <sdflanagan@ozemail.com.au>
Tim Hammerquist <timh@rubyforge.org>
Ken Miller <ken.miller@gmail.com>
Hugh Sasse <hgs@dmu.ac.uk>
Tilman Sauerbeck <tilman@code-monkey.de>
Bertram Scharpf <info@bertram-scharpf.de>
Gavin Sinclair <gsinclair@gmail.com>
Aaron Son <aaronson@uiuc.edu>
Ned Konz <ned@bike-nomad.com>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,251 @@
*vim-ruby.txt* *vim-ruby* *vim-ruby-faq*
VIM/RUBY CONFIGURATION FILES
The vim-ruby Project FAQ
https://github.com/vim-ruby/vim-ruby
The vim-ruby project maintains Ruby-related configuration files for Vim. This
FAQ contains all you need to know about it.
*** TOC ***
==============================================================================
*vim-ruby-faq-X* What is the vim-ruby project?
It maintains all the configuration files that help Vim edit Ruby code. By
installing these files, Vim will properly highlight and indent Ruby files, and
will be able to run them and go directly to the location of any errors.
Rakefiles, ERB files, and unit tests are also identified and supported.
If you make use of this project, make sure you read the installation and
configuration instructions in this FAQ.
*vim-ruby-faq-X* Doesn't Vim include these files?
Yes it does. You should only want to download and install this project if it
has changed since you last installed your version of Vim. Read the "News"
section of the |vim-ruby-homepage| to see when the most recent release was
made.
*vim-ruby-faq-X* How do you get it?
The easiest way is to run: >
gem install vim-ruby
(This really only downloads it. See installation instructions
|vim-ruby-install| below.)
If you don't have RubyGems, download a tarball from: >
https://github.com/vim-ruby/vim-ruby/downloads
Again, see installation instructions below.
*vim-ruby-faq-X* How do you install it? *vim-ruby-install*
If you obtained the vim-ruby files via RubyGems, run: >
vim-ruby-install.rb
If you downloaded a tarball, unpack it, change to the created directory, and
run: >
ruby bin/vim-ruby-install.rb
Whichever way you run it, the effect is the same. The installer will:
- Search for a Vim config directory to put its files and ask you to confirm.
- Copy the configuration files to the appropriate places underneath the
directory you selected.
Here is an example installation transcript:
Possible Vim installation directories: ~
1) D:/Gavin/vimfiles ~
2) E:/Vim/vimfiles ~
~
Please select one (or anything else to specify another directory): 2 ~
autoload/rubycomplete.vim -> E:/Vim/vimfiles/autoload/rubycomplete.vim ~
compiler/eruby.vim -> E:/Vim/vimfiles/compiler/eruby.vim ~
compiler/ruby.vim -> E:/Vim/vimfiles/compiler/ruby.vim ~
compiler/rubyunit.vim -> E:/Vim/vimfiles/compiler/rubyunit.vim ~
ftdetect/ruby.vim -> E:/Vim/vimfiles/ftdetect/ruby.vim ~
ftplugin/eruby.vim -> E:/Vim/vimfiles/ftplugin/eruby.vim ~
ftplugin/ruby.vim -> E:/Vim/vimfiles/ftplugin/ruby.vim ~
indent/eruby.vim -> E:/Vim/vimfiles/indent/eruby.vim ~
indent/ruby.vim -> E:/Vim/vimfiles/indent/ruby.vim ~
syntax/eruby.vim -> E:/Vim/vimfiles/syntax/eruby.vim ~
syntax/ruby.vim -> E:/Vim/vimfiles/syntax/ruby.vim ~
Existing files are overwritten. This is safe, because it's a slow-maturing
project, so new files are better than old ones. However, if you had edited the
files, you will have lost your changes. Better make your changes in, for
instance:
~/.vim/after/ftplugin/ruby.vim ~
This file will be loaded _after_ the regular config files are loaded, so your
customisations will definitely take effect.
*vim-ruby-faq-X* What Vim config do I need? *vim-ruby-config*
Without the following lines in your .vimrc, _vimrc, or other startup file, the
files in the vim-ruby project will be largely useless. >
set nocompatible " We're running Vim, not Vi!
syntax on " Enable syntax highlighting
filetype on " Enable filetype detection
filetype indent on " Enable filetype-specific indenting
filetype plugin on " Enable filetype-specific plugins
compiler ruby " Enable compiler support for ruby
See |.vimrc| for more information about this important Vim configuration file.
See |matchit-install| for instructions on installing "matchit", which will
allow you to use |%| to bounce between Ruby keywords (class, def, while, ...)
and their respective "end" keywords.
*vim-ruby-faq-X* How do I know that everything's working?
If you've run the installer and added the configuration |vim-ruby-config|
above, everything should be fine when you restart Vim. To test this:
- Edit a Ruby file with Vim (make sure it has a .rb extension).
- The code should be syntax highlighted.
- Type in some code. When you start a new line, it should be automatically
indented to the correct spot.
- Add or remove some space from the beginning of a line of code and hit ==.
That line should be reindented.
- Put the cursor on a "class" or "def" keyword and hit %. The cursor should
now be on the matching "end" keyword.
- TODO: what else?
*vim-ruby-faq-X* How do I use it?
TODO: write.
*vim-ruby-faq-X* How do I customise it? *vim-ruby-customize*
The most important customisation for editing Ruby code is the amount of space to
indent. The following is a typical setup. Look up the various options to read
about them. >
set expandtab
set tabstop=2 shiftwidth=2 softtabstop=2
set autoindent
TODO: is autoindent necessary? What other options should go here? What about
Ruby comments?
FIXME: Autoindent is good. maybe mention |i_CTRL_D| and |i_CTRL_T| for
moving lines about in this context?
COMMENT: I never use ^D and ^T in insert mode, though I always knew what they
do. Might try them!
*vim-ruby-faq-X* I want feature X. Will you include it?
The idea of the vim-ruby project is to maintain configuration files that are
actually distributed with Vim. Therefore all functionality should be helpful to
all Vim/Ruby users. So the project does not deal with people's individual
tastes.
That said, we are considering creating a separate configuration file for less
universal features, whose features users can pick and choose. So don't hesitate
to send us your suggestions.
*vim-ruby-faq-X* What are some other cool Ruby-related Vim tricks I can use?
An example is the following (put it in ~/.vimrc/ftplugin/ruby_extra.vim or
similar): [similar? |$VIMRUNTIME| or what?] >
if !exists( "*EndToken" )
function EndToken()
let current_line = getline( '.' )
let braces_at_end = '{\s*\(|\(,\|\s\|\w\)*|\s*\)\?$'
if match( current_line, braces_at_end ) >= 0
return '}'
else
return 'end'
endif
endfunction
endif
imap <S-CR> <ESC>:execute 'normal o' . EndToken()<CR>O
This will help you create ruby blocks of code, by inserting "}" or "end" as
appropriate. Try creating these lines of code and hitting SHIFT-ENTER:
array.map { |elem| ~
def fibonacci(n) ~
For other suggestions, search the web or look at: >
https://github.com/vim-ruby/vim-ruby/wiki/VimRubySupport
*vim-ruby-faq-X* How can I report a bug? *vim-ruby-bug-reporting*
Bug reports are most welcome. In order of preference:
- submit a bug at https://github.com/vim-ruby/vim-ruby/issues
- send an email to the mailing list (see below)
- email the maintainer (email address appears in each configuration file)
*vim-ruby-list*
*vim-ruby-faq-X* Does the project have a mailing list?
Yes: vim-ruby-devel@rubyforge.org. Only subscribers can post. To join, visit:
>
http://rubyforge.org/mailman/listinfo/vim-ruby-devel
The list is mirrored at: >
http://news.gmane.org/gmane.comp.editors.vim.vim%2druby.devel
*vim-ruby-faq-X* Why is this project separate from Vim?
We can't use Vim's CVS to keep track of these files, so we organise it ourselves
and give Bram the latest files in time for each release of Vim. By keeping the
Ruby stuff together, we can release it all at once and people can update it
independently of Vim.
*vim-ruby-faq-X* I have another question...
The mailing list or the file maintainer is a good place to ask. Or perhaps
comp.lang.ruby, but please make sure you've read the FAQ thoroughly before
asking there.
*vim-ruby-faq-X* Can you repeat all the web pages listed in this FAQ?
Homepage *vim-ruby-homepage* : >
https://github.com/vim-ruby/vim-ruby/
Bug tracker: >
https://github.com/vim-ruby/vim-ruby/issues
Relevant Wiki page: >
https://github.com/vim-ruby/vim-ruby/wiki
Mailing list archives: >
http://news.gmane.org/gmane.comp.editors.vim.vim%2druby.devel
http://rubyforge.org/pipermail/vim-ruby-devel/
Mailing list join: >
http://rubyforge.org/mailman/listinfo/vim-ruby-devel
vim: ft=help tw=78 noet :

View File

@ -0,0 +1,4 @@
source 'http://rubygems.org'
gem 'rspec'
gem 'vimrunner'

View File

@ -0,0 +1,20 @@
GEM
remote: http://rubygems.org/
specs:
diff-lcs (1.1.3)
rspec (2.11.0)
rspec-core (~> 2.11.0)
rspec-expectations (~> 2.11.0)
rspec-mocks (~> 2.11.0)
rspec-core (2.11.1)
rspec-expectations (2.11.2)
diff-lcs (~> 1.1.3)
rspec-mocks (2.11.2)
vimrunner (0.1.1)
PLATFORMS
ruby
DEPENDENCIES
rspec
vimrunner

View File

@ -0,0 +1,36 @@
Installation
============
In general, your favorite method works. Here are some options.
With pathogen.vim
-----------------
Install [pathogen.vim](https://github.com/tpope/vim-pathogen),
then copy and paste:
git clone git://github.com/vim-ruby/vim-ruby.git ~/.vim/bundle/vim-ruby
With Vundle
-----------
Install [Vundle](https://github.com/gmarik/vundle), then add the
following to your vimrc:
Bundle 'vim-ruby/vim-ruby'
With patience
-------------
Wait for an upgrade to Vim and install it. Vim ships with the latest
version of vim-ruby at the time of its release. (Remember this when
choosing another installation method. The version you download will
supersede the version that ships with Vim, so you will now be
responsible for keeping it up-to-date.)
Manually
--------
[Download](https://github.com/vim-ruby/vim-ruby/archives/master) and
extract an archive, and run `bin/vim-ruby-install.rb` to copy the
relevant files to `~/.vim`.

View File

@ -0,0 +1,243 @@
This file is no longer maintained. Consult the Git log for newer changes.
= 2008.07.XX
== Filetype Detection
The IRB RC file (.irbrc) is now detected as being a Ruby file.
= 2007.05.07
== Ruby Syntax Highlighting
Highlight OPTIMIZE alongside FIXME and TODO.
Multiline array literals can now be folded.
== Ruby Filetype Support
Added mappings for [[, ]], [], ][, [m, ]m, [M, and ]M. The first four bounce
between class and module declarations, and the last four between method
declarations.
== eRuby Syntax Highlighting
Tim Pope has taken over maintenance of the eRuby syntax file. The subtype of
the file is now determined dynamically from the filename, rather than being
hardwired to HTML. It can be overridden with b:eruby_subtype.
== eRuby Filetype Support
Tim Pope has taken over maintenance of the eRuby filetype plugin. Like with
the syntax file, the subtype is now determined dynamically.
== eRuby Indenting
As with the syntax file and filetype plugin, the subtype is now determined
dynamically.
== Bug Fixes
Ruby syntax file
- when ruby_operators is set, highlight scope and range operators, and don't
match '>' in =>'
- regexp literals are highlighted after the 'else' keyword
- don't match [!=?] as part of a sigil prefixed symbol name
- allow text to appear after, and on the same line, as '=begin' in
rubyDocumentation regions
- highlight %s() ans a symbol, not a string
- eliminated some false positves for here docs, symbols, ASCII codes, and
conditionals as statement modifiers
- added "neus" to regexp flags
- Highlight punctuation variables in string interpolation, and flag invalid
ones as errors
- removed : from rubyOptionalDoLine (falsely matches on symbols)
Ruby filetype plugin
- eliminated some false positives with the matchit patterns
Ruby indent plugin
- ignore instance, class, and global variables named "end"
= 2007.03.02
== Omni Completion
Fall back to syntax highlighting completion if Vim lacks the Ruby interface.
RubyGems is now loaded by default if available.
Classes are detected using ObjectSpace. Kernel methods are included in method
completion.
Added completion in Rails views. Rails helpers are included. Rails migrations
now have completion.
== Ruby Syntax Highlighting
Ruby code is highlighted inside interpolation regions.
Symbols are now highlighted with the Constant highlight group; Constants and
class names with the Type highlight group.
Symbol names specified with a string recognise interpolation and escape
sequences.
Alias statements receive special highlighting similar to other 'definitions'.
== Ruby Filetype Support
Matchit support has been improved to include (), {}, and [] in the list of
patterns so that these will be appropriately skipped when included in comments.
ri has been added as the 'keywordprg' and 'balloonexpr' is set to return the
output of ri.
== eRuby Indenting
Tim Pope has taken over maintenance of the eRuby indent file. Ruby code is now
indented appropriately.
== Bug Fixes
Ruby syntax file
- trailing whitespace is no longer included with the def, class, module
keywords.
- escaped interpolation regions should now be ignored in all cases.
- conditional and loop statements are now highlighted correctly in more
locations (where they're used as expressions).
eRuby syntax file
- '-' trim mode block delimiters are now recognised.
Omni Completion
- more robustness; failure to parse buffer no longer errors or prevents
completion.
= 2006.07.11
== Omni Completion
A new omni completion function is now included which offers IntelliSense-like
functionality. See :help ft-ruby-omni for further information.
Note: This will only work with Vim 7.x, compiled with the Ruby interface
(+ruby), and Ruby 1.8.x
== Ruby Filetype Support
Matchit support has been improved to include (), {}, and [] in the list of
patterns meaning these will be appropriately skipped when included in comments.
== Ruby Syntax Highlighting
Operators can now be highlighted by defining the Vim global variable
"ruby_operators".
Multiline comments will now be folded. This can be disabled by defining the
"ruby_no_comment_fold" Vim variable.
== Filetype Detection
RJS and RXML templates are now detected as being 'filetype=ruby'.
== FAQ
There is a new FAQ document included. This is a work in progress and any
feedback would be appreciated.
== Bug Fixes
Ruby syntax file - if/unless modifiers after a method name ending with [?!=]
should now be highlighted correctly.
= 2005.10.07
== Vim 6.4
This release is included in Vim 6.4.
== Bug Fixes
Ruby filetype plugin - symbols were incorrectly being matched as match_words
causing the matchit motion command to jump to an incorrect location in some
circumstances.
= 2005.10.05
== Bug Fixes
Ruby syntax file - allow for comments directly after module/class/def lines
without intervening whitespace (fold markers were breaking syntax highlighting).
Ruby filetype plugin - improve ordering of 'path' elements.
eRuby syntax file - make use of ruby_no_expensive local to the buffer.
= 2005.09.24
== Filetype Detection
The eruby filetype is now detected solely based on the file's extension. This
was being overridden by the scripts.vim detection script.
Note: Only files ending in *.rhtml are detected as filetype eruby since these
are currently assumed to be Ruby embedded in (X)HTML only. Other filetypes
could be supported if requested.
== eRuby Indent File
There is a new eRuby indent file which simply sources the HTML indent file for
now.
== eRuby Compiler Plugin
This now supports erb as the default 'makeprg'. To use eruby set the
eruby_compiler variable to "eruby" in your .vimrc
== Test::Unit Compiler Plugin
This has been improved and should now display messages similar to, though more
detailed than, the GUI test runners.
== Bug Fixes
A few minor bugs have been fixed in the Ruby syntax and indent files.
= 2005.09.15
== eRuby Support
There are new syntax, compiler, and ftplugin files for eRuby. This support is
incomplete and we're keen to hear of any problems or suggestions you may have
to improve it.
== Ruby Filetype Support
The Ruby filetype plugin has been improved to include as many useful settings
as possible without intruding too much on an individual user's preferences.
Matchit support has been improved, and the following options are now set to
appropriate values: comments, commentstring, formatoptions, include,
includeexpr, path, and suffixesadd
== Filetype Detection
The new ftdetect mechanism of Vim 6.3 is being utilized to enable filetype
detection of eRuby files until this is officially added to the next release of
Vim.
== Installation Directories
The installer script now, where possible, automatically determines both the
user and system-wide preferences directory.
== Bug Fixes
A large number of bugs have been fixed in the Ruby syntax and indent files.

View File

@ -0,0 +1,74 @@
+---------------------------------+
| vim-ruby github project README |
+---------------------------------+
Summary:
This project contains Vim configuration files for editing and compiling Ruby
within Vim. See the project homepage for more details.
Web links:
Homepage: https://github.com/vim-ruby
Explanation: https://github.com/vim-ruby/vim-ruby/wiki
For regular users:
- The project page should have two tarballs for download:
- vim-ruby-YYYY.MM.DD.tar.gz (the current stable release)
- vim-ruby-devel-YYYY.MM.DD.tar.gz (cutting-edge features we'd like you
to test)
- Please give feedback through the bug tracking and feature request features
of github.
- Feel free to join discussions on the vim-ruby-devel mailing list:
http://rubyforge.org/mail/?group_id=16
For would-be contributors:
- Please get the latest from Git.
- Please join the mailing list and discuss changes, submit patches, etc.
- Thank you very much for taking an interest.
Contents of the project:
- The autoload, compiler, ftdetect, ftplugin, indent and syntax directories
contain the ruby*.vim files that are to be copied to a location somewhere
in the Vim 'runtimepath'.
- vim-ruby-install.rb performs this copying.
How you get these files into Vim:
- By downloading the project via a snapshot or Git, you can keep up with
the latest, make changes, and install the files to a Vim directory.
- By downloading one of the tarballs, you can easily install the latest
stable or development version wherever you like on your machine. No
README, no vim-ruby-install.rb, just Vim files. You would typically
install these into either $VIM/vimfiles, for system-wide use, or $HOME/.vim
($HOME/vimfiles on Windows) for personal use.
- Remember that when you install Vim in the first place, all of these files
are present. The purpose of downloading and installing them from
github is to get the latest version of them.
Git topics:
- Project was migrated from CVS in August, 2008.
- Files are tagged according to which version of Vim they are released in.
- The project was initiated in July 2003, when the current version of Vim
was 6.2. Thus every file began its life tagged as vim6.2.
- Modifications to the files are made in the expectation that they need to
be tested by interested users. They therefore (probably) don't have a
tag, and are available via "git pull --rebase", or a development snapshot.
- When a modification is considered stable, it is given a tag.
Everything that is stable gets released in vim-ruby-YYY.MM.DD.tar.gz files.
- When a new version of Vim is about to be released, the stable tarball is
contributed to it. After it has been released, the files are tagged
accordingly.
- MORAL OF THE STORY: modifications are committed to the head of the tree;
when they are ready for release into userland, they are tagged "stable".
Any questions or suggestions?
- If there's something about the project or its concepts that you don't
understand, send an email to the release coordinator, Doug Kearns
(dougkearns at gmail.com).
- To ask about the contents of the configuration files, open a GitHub issue
or ask on the mailing list, as different people maintain the different
files.
Project gossip:
- While the individual effort to maintain these files has a long history,
this actual project began in late July 2003.
--= End of Document =--

View File

@ -0,0 +1,42 @@
require 'rubygems'
require 'rake/gempackagetask'
PACKAGE_NAME = 'vim-ruby'
RELEASE_FILES = FileList[
'ChangeLog', 'CONTRIBUTORS', 'FAQ', 'INSTALL', 'NEWS', 'README', 'bin/*.rb',
'doc/*.txt','{autoload,compiler,ftdetect,ftplugin,indent,syntax}/*.vim'
]
PACKAGE_VERSION = Time.now.gmtime.strftime('%Y.%m.%d')
desc "Build all the packages"
task :default => :package
def gemspec
Gem::Specification.new do |s|
s.name = PACKAGE_NAME
s.version = PACKAGE_VERSION
s.files = RELEASE_FILES.to_a
s.summary = "Ruby configuration files for Vim. Run 'vim-ruby-install.rb' to complete installation."
s.description = s.summary + "\n\nThis package doesn't contain a Ruby library."
s.requirements << 'RubyGems 0.8+' << 'Vim 6.0+'
s.required_ruby_version = '>= 1.8.0'
s.require_path = '.'
s.bindir = 'bin'
s.executables = ['vim-ruby-install.rb']
s.author = 'Gavin Sinclair et al.'
s.email = 'gsinclair@soyabean.com.au'
s.homepage = 'https://github.com/vim-ruby/vim-ruby'
s.has_rdoc = false
end
end
Rake::GemPackageTask.new(gemspec) do |t|
t.package_dir = 'etc/package'
t.need_tar = true
t.need_zip = true
end
# Supporting methods
# vim: nowrap sw=2 sts=2 ts=8 ff=unix ft=ruby:

View File

@ -0,0 +1,805 @@
" Vim completion script
" Language: Ruby
" Maintainer: Mark Guzman <segfault@hasno.info>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
" Maintainer Version: 0.8.1
" ----------------------------------------------------------------------------
"
" Ruby IRB/Complete author: Keiju ISHITSUKA(keiju@ishitsuka.com)
" ----------------------------------------------------------------------------
" {{{ requirement checks
function! s:ErrMsg(msg)
echohl ErrorMsg
echo a:msg
echohl None
endfunction
if !has('ruby')
call s:ErrMsg( "Error: Rubycomplete requires vim compiled with +ruby" )
call s:ErrMsg( "Error: falling back to syntax completion" )
" lets fall back to syntax completion
setlocal omnifunc=syntaxcomplete#Complete
finish
endif
if version < 700
call s:ErrMsg( "Error: Required vim >= 7.0" )
finish
endif
" }}} requirement checks
" {{{ configuration failsafe initialization
if !exists("g:rubycomplete_rails")
let g:rubycomplete_rails = 0
endif
if !exists("g:rubycomplete_classes_in_global")
let g:rubycomplete_classes_in_global = 0
endif
if !exists("g:rubycomplete_buffer_loading")
let g:rubycomplete_buffer_loading = 0
endif
if !exists("g:rubycomplete_include_object")
let g:rubycomplete_include_object = 0
endif
if !exists("g:rubycomplete_include_objectspace")
let g:rubycomplete_include_objectspace = 0
endif
" }}} configuration failsafe initialization
" {{{ vim-side support functions
let s:rubycomplete_debug = 0
function! s:dprint(msg)
if s:rubycomplete_debug == 1
echom a:msg
endif
endfunction
function! s:GetBufferRubyModule(name, ...)
if a:0 == 1
let [snum,enum] = s:GetBufferRubyEntity(a:name, "module", a:1)
else
let [snum,enum] = s:GetBufferRubyEntity(a:name, "module")
endif
return snum . '..' . enum
endfunction
function! s:GetBufferRubyClass(name, ...)
if a:0 >= 1
let [snum,enum] = s:GetBufferRubyEntity(a:name, "class", a:1)
else
let [snum,enum] = s:GetBufferRubyEntity(a:name, "class")
endif
return snum . '..' . enum
endfunction
function! s:GetBufferRubySingletonMethods(name)
endfunction
function! s:GetBufferRubyEntity( name, type, ... )
let lastpos = getpos(".")
let lastline = lastpos
if (a:0 >= 1)
let lastline = [ 0, a:1, 0, 0 ]
call cursor( a:1, 0 )
endif
let stopline = 1
let crex = '^\s*\<' . a:type . '\>\s*\<' . a:name . '\>\s*\(<\s*.*\s*\)\?'
let [lnum,lcol] = searchpos( crex, 'w' )
"let [lnum,lcol] = searchpairpos( crex . '\zs', '', '\(end\|}\)', 'w' )
if lnum == 0 && lcol == 0
call cursor(lastpos[1], lastpos[2])
return [0,0]
endif
let curpos = getpos(".")
let [enum,ecol] = searchpairpos( crex, '', '\(end\|}\)', 'wr' )
call cursor(lastpos[1], lastpos[2])
if lnum > enum
return [0,0]
endif
" we found a the class def
return [lnum,enum]
endfunction
function! s:IsInClassDef()
return s:IsPosInClassDef( line('.') )
endfunction
function! s:IsPosInClassDef(pos)
let [snum,enum] = s:GetBufferRubyEntity( '.*', "class" )
let ret = 'nil'
if snum < a:pos && a:pos < enum
let ret = snum . '..' . enum
endif
return ret
endfunction
function! s:GetRubyVarType(v)
let stopline = 1
let vtp = ''
let pos = getpos('.')
let sstr = '^\s*#\s*@var\s*'.escape(a:v, '*').'\>\s\+[^ \t]\+\s*$'
let [lnum,lcol] = searchpos(sstr,'nb',stopline)
if lnum != 0 && lcol != 0
call setpos('.',pos)
let str = getline(lnum)
let vtp = substitute(str,sstr,'\1','')
return vtp
endif
call setpos('.',pos)
let ctors = '\(now\|new\|open\|get_instance'
if exists('g:rubycomplete_rails') && g:rubycomplete_rails == 1 && s:rubycomplete_rails_loaded == 1
let ctors = ctors.'\|find\|create'
else
endif
let ctors = ctors.'\)'
let fstr = '=\s*\([^ \t]\+.' . ctors .'\>\|[\[{"''/]\|%[xwQqr][(\[{@]\|[A-Za-z0-9@:\-()\.]\+...\?\|lambda\|&\)'
let sstr = ''.a:v.'\>\s*[+\-*/]*'.fstr
let [lnum,lcol] = searchpos(sstr,'nb',stopline)
if lnum != 0 && lcol != 0
let str = matchstr(getline(lnum),fstr,lcol)
let str = substitute(str,'^=\s*','','')
call setpos('.',pos)
if str == '"' || str == '''' || stridx(tolower(str), '%q[') != -1
return 'String'
elseif str == '[' || stridx(str, '%w[') != -1
return 'Array'
elseif str == '{'
return 'Hash'
elseif str == '/' || str == '%r{'
return 'Regexp'
elseif strlen(str) >= 4 && stridx(str,'..') != -1
return 'Range'
elseif stridx(str, 'lambda') != -1 || str == '&'
return 'Proc'
elseif strlen(str) > 4
let l = stridx(str,'.')
return str[0:l-1]
end
return ''
endif
call setpos('.',pos)
return ''
endfunction
"}}} vim-side support functions
"{{{ vim-side completion function
function! rubycomplete#Init()
execute "ruby VimRubyCompletion.preload_rails"
endfunction
function! rubycomplete#Complete(findstart, base)
"findstart = 1 when we need to get the text length
if a:findstart
let line = getline('.')
let idx = col('.')
while idx > 0
let idx -= 1
let c = line[idx-1]
if c =~ '\w'
continue
elseif ! c =~ '\.'
idx = -1
break
else
break
endif
endwhile
return idx
"findstart = 0 when we need to return the list of completions
else
let g:rubycomplete_completions = []
execute "ruby VimRubyCompletion.get_completions('" . a:base . "')"
return g:rubycomplete_completions
endif
endfunction
"}}} vim-side completion function
"{{{ ruby-side code
function! s:DefRuby()
ruby << RUBYEOF
# {{{ ruby completion
begin
require 'rubygems' # let's assume this is safe...?
rescue Exception
#ignore?
end
class VimRubyCompletion
# {{{ constants
@@debug = false
@@ReservedWords = [
"BEGIN", "END",
"alias", "and",
"begin", "break",
"case", "class",
"def", "defined", "do",
"else", "elsif", "end", "ensure",
"false", "for",
"if", "in",
"module",
"next", "nil", "not",
"or",
"redo", "rescue", "retry", "return",
"self", "super",
"then", "true",
"undef", "unless", "until",
"when", "while",
"yield",
]
@@Operators = [ "%", "&", "*", "**", "+", "-", "/",
"<", "<<", "<=", "<=>", "==", "===", "=~", ">", ">=", ">>",
"[]", "[]=", "^", ]
# }}} constants
# {{{ buffer analysis magic
def load_requires
buf = VIM::Buffer.current
enum = buf.line_number
nums = Range.new( 1, enum )
nums.each do |x|
ln = buf[x]
begin
eval( "require %s" % $1 ) if /.*require\s*(.*)$/.match( ln )
rescue Exception
#ignore?
end
end
end
def load_buffer_class(name)
dprint "load_buffer_class(%s) START" % name
classdef = get_buffer_entity(name, 's:GetBufferRubyClass("%s")')
return if classdef == nil
pare = /^\s*class\s*(.*)\s*<\s*(.*)\s*\n/.match( classdef )
load_buffer_class( $2 ) if pare != nil && $2 != name # load parent class if needed
mixre = /.*\n\s*(include|prepend)\s*(.*)\s*\n/.match( classdef )
load_buffer_module( $2 ) if mixre != nil && $2 != name # load mixins if needed
begin
eval classdef
rescue Exception
VIM::evaluate( "s:ErrMsg( 'Problem loading class \"%s\", was it already completed?' )" % name )
end
dprint "load_buffer_class(%s) END" % name
end
def load_buffer_module(name)
dprint "load_buffer_module(%s) START" % name
classdef = get_buffer_entity(name, 's:GetBufferRubyModule("%s")')
return if classdef == nil
begin
eval classdef
rescue Exception
VIM::evaluate( "s:ErrMsg( 'Problem loading module \"%s\", was it already completed?' )" % name )
end
dprint "load_buffer_module(%s) END" % name
end
def get_buffer_entity(name, vimfun)
loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
return nil if loading_allowed.to_i.zero?
return nil if /(\"|\')+/.match( name )
buf = VIM::Buffer.current
nums = eval( VIM::evaluate( vimfun % name ) )
return nil if nums == nil
return nil if nums.min == nums.max && nums.min == 0
dprint "get_buffer_entity START"
visited = []
clscnt = 0
bufname = VIM::Buffer.current.name
classdef = ""
cur_line = VIM::Buffer.current.line_number
while (nums != nil && !(nums.min == 0 && nums.max == 0) )
dprint "visited: %s" % visited.to_s
break if visited.index( nums )
visited << nums
nums.each do |x|
if x != cur_line
next if x == 0
ln = buf[x]
if /^\s*(module|class|def|include)\s+/.match(ln)
clscnt += 1 if $1 == "class"
#dprint "\$1$1
classdef += "%s\n" % ln
classdef += "end\n" if /def\s+/.match(ln)
dprint ln
end
end
end
nm = "%s(::.*)*\", %s, \"" % [ name, nums.last ]
nums = eval( VIM::evaluate( vimfun % nm ) )
dprint "nm: \"%s\"" % nm
dprint "vimfun: %s" % (vimfun % nm)
dprint "got nums: %s" % nums.to_s
end
if classdef.length > 1
classdef += "end\n"*clscnt
# classdef = "class %s\n%s\nend\n" % [ bufname.gsub( /\/|\\/, "_" ), classdef ]
end
dprint "get_buffer_entity END"
dprint "classdef====start"
lns = classdef.split( "\n" )
lns.each { |x| dprint x }
dprint "classdef====end"
return classdef
end
def get_var_type( receiver )
if /(\"|\')+/.match( receiver )
"String"
else
VIM::evaluate("s:GetRubyVarType('%s')" % receiver)
end
end
def dprint( txt )
print txt if @@debug
end
def escape_vim_singlequote_string(str)
str.to_s.gsub(/'/,"\\'")
end
def get_buffer_entity_list( type )
# this will be a little expensive.
loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
allow_aggressive_load = VIM::evaluate("exists('g:rubycomplete_classes_in_global') && g:rubycomplete_classes_in_global")
return [] if allow_aggressive_load.to_i.zero? || loading_allowed.to_i.zero?
buf = VIM::Buffer.current
eob = buf.length
ret = []
rg = 1..eob
re = eval( "/^\s*%s\s*([A-Za-z0-9_:-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*/" % type )
rg.each do |x|
if re.match( buf[x] )
next if type == "def" && eval( VIM::evaluate("s:IsPosInClassDef(%s)" % x) ) != nil
ret.push $1
end
end
return ret
end
def get_buffer_modules
return get_buffer_entity_list( "modules" )
end
def get_buffer_methods
return get_buffer_entity_list( "def" )
end
def get_buffer_classes
return get_buffer_entity_list( "class" )
end
def load_rails
allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
return if allow_rails.to_i.zero?
buf_path = VIM::evaluate('expand("%:p")')
file_name = VIM::evaluate('expand("%:t")')
vim_dir = VIM::evaluate('getcwd()')
file_dir = buf_path.gsub( file_name, '' )
file_dir.gsub!( /\\/, "/" )
vim_dir.gsub!( /\\/, "/" )
vim_dir << "/"
dirs = [ vim_dir, file_dir ]
sdirs = [ "", "./", "../", "../../", "../../../", "../../../../" ]
rails_base = nil
dirs.each do |dir|
sdirs.each do |sub|
trail = "%s%s" % [ dir, sub ]
tcfg = "%sconfig" % trail
if File.exists?( tcfg )
rails_base = trail
break
end
end
break if rails_base
end
return if rails_base == nil
$:.push rails_base unless $:.index( rails_base )
rails_config = rails_base + "config/"
rails_lib = rails_base + "lib/"
$:.push rails_config unless $:.index( rails_config )
$:.push rails_lib unless $:.index( rails_lib )
bootfile = rails_config + "boot.rb"
envfile = rails_config + "environment.rb"
if File.exists?( bootfile ) && File.exists?( envfile )
begin
require bootfile
require envfile
begin
require 'console_app'
require 'console_with_helpers'
rescue Exception
dprint "Rails 1.1+ Error %s" % $!
# assume 1.0
end
#eval( "Rails::Initializer.run" ) #not necessary?
VIM::command('let s:rubycomplete_rails_loaded = 1')
dprint "rails loaded"
rescue Exception
dprint "Rails Error %s" % $!
VIM::evaluate( "s:ErrMsg('Error loading rails environment')" )
end
end
end
def get_rails_helpers
allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
buf_path = VIM::evaluate('expand("%:p")')
buf_path.gsub!( /\\/, "/" )
path_elm = buf_path.split( "/" )
dprint "buf_path: %s" % buf_path
types = [ "app", "db", "lib", "test", "components", "script" ]
i = nil
ret = []
type = nil
types.each do |t|
i = path_elm.index( t )
break if i
end
type = path_elm[i]
type.downcase!
dprint "type: %s" % type
case type
when "app"
i += 1
subtype = path_elm[i]
subtype.downcase!
dprint "subtype: %s" % subtype
case subtype
when "views"
ret += ActionView::Base.instance_methods
ret += ActionView::Base.methods
when "controllers"
ret += ActionController::Base.instance_methods
ret += ActionController::Base.methods
when "models"
ret += ActiveRecord::Base.instance_methods
ret += ActiveRecord::Base.methods
end
when "db"
ret += ActiveRecord::ConnectionAdapters::SchemaStatements.instance_methods
ret += ActiveRecord::ConnectionAdapters::SchemaStatements.methods
end
return ret
end
def add_rails_columns( cls )
allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
begin
eval( "#{cls}.establish_connection" )
return [] unless eval( "#{cls}.ancestors.include?(ActiveRecord::Base).to_s" )
col = eval( "#{cls}.column_names" )
return col if col
rescue
dprint "add_rails_columns err: (cls: %s) %s" % [ cls, $! ]
return []
end
return []
end
def clean_sel(sel, msg)
ret = sel.reject{|x|x.nil?}.uniq
ret = ret.grep(/^#{Regexp.quote(msg)}/) if msg != nil
ret
end
def get_rails_view_methods
allow_rails = VIM::evaluate("exists('g:rubycomplete_rails') && g:rubycomplete_rails")
rails_loaded = VIM::evaluate('s:rubycomplete_rails_loaded')
return [] if allow_rails.to_i.zero? || rails_loaded.to_i.zero?
buf_path = VIM::evaluate('expand("%:p")')
buf_path.gsub!( /\\/, "/" )
pelm = buf_path.split( "/" )
idx = pelm.index( "views" )
return [] unless idx
idx += 1
clspl = pelm[idx].camelize.pluralize
cls = clspl.singularize
ret = []
begin
ret += eval( "#{cls}.instance_methods" )
ret += eval( "#{clspl}Helper.instance_methods" )
rescue Exception
dprint "Error: Unable to load rails view helpers for %s: %s" % [ cls, $! ]
end
return ret
end
# }}} buffer analysis magic
# {{{ main completion code
def self.preload_rails
a = VimRubyCompletion.new
require 'Thread'
Thread.new(a) do |b|
begin
b.load_rails
rescue
end
end
a.load_rails
rescue
end
def self.get_completions(base)
b = VimRubyCompletion.new
b.get_completions base
end
def get_completions(base)
loading_allowed = VIM::evaluate("exists('g:rubycomplete_buffer_loading') && g:rubycomplete_buffer_loading")
if loading_allowed.to_i == 1
load_requires
load_rails
end
input = VIM::Buffer.current.line
cpos = VIM::Window.current.cursor[1] - 1
input = input[0..cpos]
input += base
input.sub!(/.*[ \t\n\"\\'`><=;|&{(]/, '') # Readline.basic_word_break_characters
input.sub!(/self\./, '')
input.sub!(/.*((\.\.[\[(]?)|([\[(]))/, '')
dprint 'input %s' % input
message = nil
receiver = nil
methods = []
variables = []
classes = []
constants = []
case input
when /^(\/[^\/]*\/)\.([^.]*)$/ # Regexp
receiver = $1
message = Regexp.quote($2)
methods = Regexp.instance_methods(true)
when /^([^\]]*\])\.([^.]*)$/ # Array
receiver = $1
message = Regexp.quote($2)
methods = Array.instance_methods(true)
when /^([^\}]*\})\.([^.]*)$/ # Proc or Hash
receiver = $1
message = Regexp.quote($2)
methods = Proc.instance_methods(true) | Hash.instance_methods(true)
when /^(:[^:.]*)$/ # Symbol
dprint "symbol"
if Symbol.respond_to?(:all_symbols)
receiver = $1
message = $1.sub( /:/, '' )
methods = Symbol.all_symbols.collect{|s| s.id2name}
methods.delete_if { |c| c.match( /'/ ) }
end
when /^::([A-Z][^:\.\(]*)$/ # Absolute Constant or class methods
dprint "const or cls"
receiver = $1
methods = Object.constants
methods.grep(/^#{receiver}/).collect{|e| "::" + e}
when /^(((::)?[A-Z][^:.\(]*)+?)::?([^:.]*)$/ # Constant or class methods
receiver = $1
message = Regexp.quote($4)
dprint "const or cls 2 [recv: \'%s\', msg: \'%s\']" % [ receiver, message ]
load_buffer_class( receiver )
begin
classes = eval("#{receiver}.constants")
#methods = eval("#{receiver}.methods")
rescue Exception
dprint "exception: %s" % $!
methods = []
end
methods.grep(/^#{message}/).collect{|e| receiver + "::" + e}
when /^(:[^:.]+)\.([^.]*)$/ # Symbol
dprint "symbol"
receiver = $1
message = Regexp.quote($2)
methods = Symbol.instance_methods(true)
when /^([0-9_]+(\.[0-9_]+)?(e[0-9]+)?)\.([^.]*)$/ # Numeric
dprint "numeric"
receiver = $1
message = Regexp.quote($4)
begin
methods = eval(receiver).methods
rescue Exception
methods = []
end
when /^(\$[^.]*)$/ #global
dprint "global"
methods = global_variables.grep(Regexp.new(Regexp.quote($1)))
when /^((\.?[^.]+)+?)\.([^.]*)$/ # variable
dprint "variable"
receiver = $1
message = Regexp.quote($3)
load_buffer_class( receiver )
cv = eval("self.class.constants")
vartype = get_var_type( receiver )
dprint "vartype: %s" % vartype
if vartype != ''
load_buffer_class( vartype )
begin
methods = eval("#{vartype}.instance_methods")
variables = eval("#{vartype}.instance_variables")
rescue Exception
dprint "load_buffer_class err: %s" % $!
end
elsif (cv).include?(receiver)
# foo.func and foo is local var.
methods = eval("#{receiver}.methods")
vartype = receiver
elsif /^[A-Z]/ =~ receiver and /\./ !~ receiver
vartype = receiver
# Foo::Bar.func
begin
methods = eval("#{receiver}.methods")
rescue Exception
end
else
# func1.func2
ObjectSpace.each_object(Module){|m|
next if m.name != "IRB::Context" and
/^(IRB|SLex|RubyLex|RubyToken)/ =~ m.name
methods.concat m.instance_methods(false)
}
end
variables += add_rails_columns( "#{vartype}" ) if vartype && vartype.length > 0
when /^\(?\s*[A-Za-z0-9:^@.%\/+*\(\)]+\.\.\.?[A-Za-z0-9:^@.%\/+*\(\)]+\s*\)?\.([^.]*)/
message = $1
methods = Range.instance_methods(true)
when /^\.([^.]*)$/ # unknown(maybe String)
message = Regexp.quote($1)
methods = String.instance_methods(true)
else
dprint "default/other"
inclass = eval( VIM::evaluate("s:IsInClassDef()") )
if inclass != nil
dprint "inclass"
classdef = "%s\n" % VIM::Buffer.current[ inclass.min ]
found = /^\s*class\s*([A-Za-z0-9_-]*)(\s*<\s*([A-Za-z0-9_:-]*))?\s*\n$/.match( classdef )
if found != nil
receiver = $1
message = input
load_buffer_class( receiver )
begin
methods = eval( "#{receiver}.instance_methods" )
variables += add_rails_columns( "#{receiver}" )
rescue Exception
found = nil
end
end
end
if inclass == nil || found == nil
dprint "inclass == nil"
methods = get_buffer_methods
methods += get_rails_view_methods
cls_const = Class.constants
constants = cls_const.select { |c| /^[A-Z_-]+$/.match( c ) }
classes = eval("self.class.constants") - constants
classes += get_buffer_classes
classes += get_buffer_modules
include_objectspace = VIM::evaluate("exists('g:rubycomplete_include_objectspace') && g:rubycomplete_include_objectspace")
ObjectSpace.each_object(Class) { |cls| classes << cls.to_s } if include_objectspace == "1"
message = receiver = input
end
methods += get_rails_helpers
methods += Kernel.public_methods
end
include_object = VIM::evaluate("exists('g:rubycomplete_include_object') && g:rubycomplete_include_object")
methods = clean_sel( methods, message )
methods = (methods-Object.instance_methods) if include_object == "0"
rbcmeth = (VimRubyCompletion.instance_methods-Object.instance_methods) # lets remove those rubycomplete methods
methods = (methods-rbcmeth)
variables = clean_sel( variables, message )
classes = clean_sel( classes, message ) - ["VimRubyCompletion"]
constants = clean_sel( constants, message )
valid = []
valid += methods.collect { |m| { :name => m.to_s, :type => 'm' } }
valid += variables.collect { |v| { :name => v.to_s, :type => 'v' } }
valid += classes.collect { |c| { :name => c.to_s, :type => 't' } }
valid += constants.collect { |d| { :name => d.to_s, :type => 'd' } }
valid.sort! { |x,y| x[:name] <=> y[:name] }
outp = ""
rg = 0..valid.length
rg.step(150) do |x|
stpos = 0+x
enpos = 150+x
valid[stpos..enpos].each { |c| outp += "{'word':'%s','item':'%s','kind':'%s'}," % [ c[:name], c[:name], c[:type] ].map{|x|escape_vim_singlequote_string(x)} }
outp.sub!(/,$/, '')
VIM::command("call extend(g:rubycomplete_completions, [%s])" % outp)
outp = ""
end
end
# }}} main completion code
end # VimRubyCompletion
# }}} ruby completion
RUBYEOF
endfunction
let s:rubycomplete_rails_loaded = 0
call s:DefRuby()
"}}} ruby-side code
" vim:tw=78:sw=4:ts=8:et:fdm=marker:ft=vim:norl:

View File

@ -0,0 +1,455 @@
#!/usr/bin/env ruby
# vim-ruby-install: install the Vim config files for Ruby editing
#
# * scope out the target directory and get user to confirm
# * if no directory found, ask user
# * allow user to force a search for a Windows gvim installation
# * find source files from gem or from top level directory
# * copy to target directory, taking account of
# * line endings (NL for Unix-ish; CRLF for Windows)
# * permissions (755 for directories; 644 for files)
#
require 'rbconfig'
include RbConfig
require 'fileutils'
require 'optparse'
require 'pathname'
SOURCE_FILES = %w{
autoload/rubycomplete.vim
compiler/eruby.vim
compiler/rspec.vim
compiler/ruby.vim
compiler/rubyunit.vim
ftdetect/ruby.vim
ftplugin/eruby.vim
ftplugin/ruby.vim
indent/eruby.vim
indent/ruby.vim
syntax/eruby.vim
syntax/ruby.vim
}
#
# Miscellaneous functions in the user's environment.
#
class Env
#
# Returns :UNIX or :WINDOWS, according to CONFIG['host_os'] and $options[:windows].
#
def Env.determine_target_os
os = CONFIG['host_os']
if os =~ /mswin/ or $options[:windows]
return :WINDOWS
else
return :UNIX
end
end
#
# Returns the path to the directory where the vim configuration files will be copied from.
# The first preference is the directory above this script. If that fails, we look for the
# RubyGems package 'vim-ruby'. Failing that, we return +nil+.
#
def Env.determine_source_directory
# 1. Try the directory above this installation script.
vim_ruby_source_dir = File.expand_path(File.join(File.dirname($0), '..'))
return vim_ruby_source_dir if _valid_vim_ruby_dir(vim_ruby_source_dir)
# 2. Try the gem 'vim-ruby'.
begin
require 'rubygems'
raise "Need RubyGems 0.8+" if Gem::RubyGemsPackageVersion < '0.8'
rescue LoadError
return nil
end
#vim_ruby_gem_dir = Gem.latest_load_paths.grep(%r{gems/vim-ruby-\d{4}\.\d{2}\.\d{2}}).last
vim_ruby_gem_dir = Gem.all_load_paths.grep(%r{gems/vim-ruby-\d{4}\.\d{2}\.\d{2}}).sort.last
if vim_ruby_gem_dir and _valid_vim_ruby_dir(vim_ruby_gem_dir)
return vim_ruby_gem_dir
end
return nil
end
# Returns the Vim installation directory ($VIM).
# TODO: print warning if vim command not in PATH or appropriate key not in registry?
def Env.determine_vim_dir
installation_dir = ENV['VIM'] ||
case Env.determine_target_os
when :UNIX
IO.popen('vim --version 2>/dev/null') do |version|
dir = version.read[/fall-back for \$VIM: "(.*)"/, 1]
end
when :WINDOWS
begin
require 'win32/registry'
Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\Vim\Gvim') do |reg|
path = reg['path', Win32::Registry::REG_SZ]
dir = path.sub(/\\vim\d\d\\gvim.exe/i, '')
end
rescue Win32::Registry::Error
nil
end
end
return installation_dir
end
def Env.determine_home_dir
home_dir = ENV['HOME'] ||
case Env.determine_target_os
when :WINDOWS
ENV['HOMEDRIVE'] + ENV['HOMEPATH'] if ENV['HOMEDRIVE'] and ENV['HOMEPATH']
end
return home_dir
end
def Env.ask_user(message)
print message
gets.strip
end
private_class_method
def Env._valid_vim_ruby_dir(dir)
Dir.chdir(dir) do
return SOURCE_FILES.all? { |path| FileTest.file?(path) }
end
end
end # class Env
#
# A FileWriter writes files with pre-selected line endings and permissions.
#
# writer = FileWriter.new(:UNIX, 0664)
# writer.copy(source, target)
#
class FileWriter
LINE_ENDINGS = { :UNIX => "\n", :WINDOWS => "\r\n" }
def initialize(ending, file_permissions=0644, directory_permissions=0755)
@ending = LINE_ENDINGS[ending] or raise "No/invalid line ending given: #{ending}"
@permissions = {
:file => file_permissions,
:dir => directory_permissions
}
end
# Source and target paths assumed to be Pathname objects. Copy the source to the target,
# ensuring the right line endings.
def copy(source_path, target_path)
_ensure_directory_exists(target_path)
target_path.open('wb', @permissions[:file]) do |io|
lines = source_path.read.split("\n")
lines.each do |line|
io.write(line.chomp + @ending)
end
end
puts "#{source_path.to_s.ljust(25)} -> #{target_path}"
end
# Create the given directory with the correct directory permissions.
def mkpath(directory)
FileUtils.mkdir_p(directory.to_s, :mode => @permissions[:dir], :verbose => true)
end
def _ensure_directory_exists(path)
dir = path.dirname
unless dir.directory?
# <XXX> FileUtils.mkdir_p already checks if it exists and is a
# directory. What if it exists as a file? (HGS)</XXX>
mkpath(dir)
end
end
end # class FileWriter
#
# Represents the target base directory for installs. Handles writing the files through a
# given FileWriter.
#
class TargetDirectory
def self.finder
TargetDirectory::Finder.new
end
def initialize(directory, writer)
@directory = Pathname.new(directory)
@writer = writer # FileWriter
end
# Copies the given relative path from the current directory to the target.
def copy(path)
source_path = Pathname.new(path)
target_path = @directory + path
@writer.copy(source_path, target_path)
end
def [](path)
@directory + path
end
def path
@directory
end
end # class TargetDirectory
#
# Represents the target directory. Can find candidates, based on the operating system and
# user options; but is ultimately created with one in mind.
#
class TargetDirectory::Finder
# Guides the user through a selection process, ending in a chosen directory.
def find_target_directory
# 1. Was a directory specified using the --directory option?
if option_dir = $options[:target_dir]
return option_dir
end
# 2. Try the potentials (if there are any).
if dirs = _potential_directories and not dirs.empty?
puts
puts "Possible Vim installation directories:"
dirs.each_with_index do |dir, idx|
puts " #{idx+1}) #{dir}"
end
puts
r = Env.ask_user "Please select one (or anything else to specify another directory): "
if (1..dirs.size).include? r.to_i
chosen_directory = dirs[r.to_i - 1]
return chosen_directory
end
end
# 3. We didn't find any, or the user wants to enter another.
if dirs.empty?
puts
puts "Couldn't find any Vim installation directories."
end
entered_directory = Env.ask_user "Please enter the full path to your Vim installation directory: "
entered_directory = File.expand_path(entered_directory)
return entered_directory
end
private
# Return an array of _potential_ directories (i.e. they exist). Take the options into
# account.
def _potential_directories
dirs = []
dirs << _vim_user_dir
dirs << _vim_system_dir
return dirs.compact.map { |dir| File.expand_path(dir) }
end
# Return the Vim system preferences directory
def _vim_system_dir
vim_dir = Env.determine_vim_dir
system_dir = vim_dir + "/vimfiles" if vim_dir
return system_dir
end
# Return the Vim user preferences directory
def _vim_user_dir
platform_dir = { :UNIX => "/.vim", :WINDOWS => "/vimfiles" }
home_dir = Env.determine_home_dir
user_dir = home_dir + platform_dir[Env.determine_target_os] if home_dir
return user_dir
end
end # class TargetDirectory::Finder
#
# VimRubyInstaller is the class that copies the files from the source directory to the target
# directory, both of which are provided.
#
class VimRubyInstaller
# +source+ and +target+ are the base directories from and to which the configuration files
# will be copied. Both are strings.
def initialize(source, target)
unless FileTest.directory?(source)
raise "Automatically determined source directory ('#{source}') doesn't exist"
end
unless FileTest.directory?(target)
raise "Chosen target directory ('#{target}') doesn't exist"
end
@source_dir = source
file_writer = FileWriter.new(Env.determine_target_os)
@target_dir = TargetDirectory.new(target, file_writer)
end
# Since we know the source and target directories, all we have to do is copy the files
# across. If the --backup option was specified or the target file is
# _newer_ than the source file, we make a backup of it and report that to
# the user.
def install
backupdir = BackupDir.new("./vim-ruby-backup.#{Process.pid}")
Dir.chdir(@source_dir) do
SOURCE_FILES.each do |path|
source_path = Pathname.new(path)
target_path = @target_dir[path]
# FIXME: Backup everything for now
if $options[:backup] and target_path.file?
backupdir.backup(@target_dir, path)
elsif target_path.file? and target_path.mtime > source_path.mtime
# We're going to overwrite a newer file; back it up, unless they're the same.
unless _same_contents?(target_path, source_path)
backupdir.backup(@target_dir, path)
end
end
@target_dir.copy(path)
end
end
backups = backupdir.contents
unless backups.empty?
puts
puts "The following backups were made:"
backups.each do |path|
puts " * #{path}"
end
puts
puts "These backups are located in this directory: #{backupdir.path}"
end
end
private
# Test two files for equality of contents, ignoring line endings.
def _same_contents?(p1, p2)
contents1 = p1.read.split("\n").map { |line| line.chomp }
contents2 = p2.read.split("\n").map { |line| line.chomp }
contents1 == contents2
end
# A directory for holding backups of configuration files.
class BackupDir
def initialize(path)
@base = Pathname.new(path).expand_path
end
# Copy basedir/path to @path/path.
def backup(basedir, path)
@base.mkpath unless @base.directory?
source = basedir.path + path
target = @base + path
target.dirname.mkpath
FileUtils.cp(source.to_s, target.dirname.to_s, :verbose => true)
end
def [](path)
@base + path
end
def contents
return [] unless @base.directory?
results = []
Dir.chdir(@base) do
Pathname.new('.').find do |path|
results << path if path.file?
end
end
results
end
def path
@base
end
end # class VimRubyInstaller::BackupDir
end # class VimRubyInstaller
#
# * * * M A I N * * *
#
begin
$options = {
:backup => false,
:target_dir => nil,
:windows => false
}
op = OptionParser.new do |p|
p.banner = %{
vim-ruby-install.rb: Install the vim-ruby configuration files
About:
* Detects the Vim user and system-wide preferences directories
* User to confirm before proceeding
* User may specify other directory
* Takes config files from current directory or from vim-ruby gem
* Writes files with correct permissions and line endings
Usage:
direct: ruby bin/vim-ruby-install.rb [options]
gem: vim-ruby-install.rb [options]
Options:
}.gsub(/^ /, '')
p.on('-b', '--backup', 'Backup existing runtime files') do |value|
$options[:backup] = value
end
p.on('-d DIR', '--directory', 'Install into given directory') do |dir|
$options[:target_dir] = dir
end
p.on('-w', '--windows', 'Install into Windows directories') do |value|
$options[:windows] = value
end
p.on('-h', '--help', 'Show this message') do
puts p
exit
end
p.on_tail %{
Notes:
* "Direct" usage means unpacking a vim-ruby tarball and running this
program from the vim-ruby directory.
* The convenient alternative is to use RubyGems:
gem install vim-ruby
vim-ruby-install.rb
* The --windows option is designed for forcing an install into the
Windows (gvim) configuration directory; useful when running from
Cygwin or MinGW.
* This installer is quite new (2004-09-20). Please report bugs to
gsinclair@soyabean.com.au.
}.gsub(/^ /, '')
end
op.parse!(ARGV)
if not ARGV.empty?
raise "invalid argument: #{ARGV[0]}"
end
source_dir = Env.determine_source_directory
if source_dir.nil?
raise "Can't find source directory."
end
target_dir = TargetDirectory.finder.find_target_directory
if not File.directory?(target_dir)
puts
puts "Target directory '#{target_dir}' does not exist."
response = Env.ask_user "Do you want to create it? [Yn] "
response = "y" if response.empty?
if response.strip =~ /^y(es)?$/i
FileUtils.mkdir_p(target_dir, :verbose => true)
else
puts
puts "Installation aborted."
exit
end
end
VimRubyInstaller.new(source_dir, target_dir).install
rescue
raise if $DEBUG
$stderr.puts
$stderr.puts $!.message
$stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
exit 1
end
# vim: nowrap sw=2 sts=2 ts=8 ff=unix ft=ruby:

View File

@ -0,0 +1,39 @@
" Vim compiler file
" Language: eRuby
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
if exists("current_compiler")
finish
endif
let current_compiler = "eruby"
if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif
let s:cpo_save = &cpo
set cpo-=C
if exists("eruby_compiler") && eruby_compiler == "eruby"
CompilerSet makeprg=eruby
else
CompilerSet makeprg=erb
endif
CompilerSet errorformat=
\eruby:\ %f:%l:%m,
\%+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: nowrap sw=2 sts=2 ts=8:

View File

@ -0,0 +1,35 @@
" Vim compiler file
" Language: Rake
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
if exists("current_compiler")
finish
endif
let current_compiler = "rake"
if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif
let s:cpo_save = &cpo
set cpo-=C
CompilerSet makeprg=rake
CompilerSet errorformat=
\%D(in\ %f),
\%\\s%#from\ %f:%l:%m,
\%\\s%#from\ %f:%l:,
\%\\s%##\ %f:%l:%m,
\%\\s%##\ %f:%l,
\%\\s%#[%f:%l:\ %#%m,
\%\\s%#%f:%l:\ %#%m,
\%\\s%#%f:%l:,
\%m\ [%f:%l]:
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: nowrap sw=2 sts=2 ts=8:

View File

@ -0,0 +1,33 @@
" Vim compiler file
" Language: RSpec
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
if exists("current_compiler")
finish
endif
let current_compiler = "rspec"
if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif
let s:cpo_save = &cpo
set cpo-=C
CompilerSet makeprg=rspec
CompilerSet errorformat=
\%f:%l:\ %tarning:\ %m,
\%E%.%#:in\ `load':\ %f:%l:%m,
\%E%f:%l:in\ `%*[^']':\ %m,
\%-Z\ \ \ \ \ \#\ %f:%l:%.%#,
\%E\ \ %\\d%\\+)%.%#,
\%C\ \ \ \ \ %m,
\%-G%.%#
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: nowrap sw=2 sts=2 ts=8:

View File

@ -0,0 +1,45 @@
" Vim compiler file
" Language: Ruby
" Function: Syntax check and/or error reporting
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
" ----------------------------------------------------------------------------
if exists("current_compiler")
finish
endif
let current_compiler = "ruby"
if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif
let s:cpo_save = &cpo
set cpo-=C
" default settings runs script normally
" add '-c' switch to run syntax check only:
"
" CompilerSet makeprg=ruby\ -wc\ $*
"
" or add '-c' at :make command line:
"
" :make -c %<CR>
"
CompilerSet makeprg=ruby\ -w\ $*
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: nowrap sw=2 sts=2 ts=8:

View File

@ -0,0 +1,33 @@
" Vim compiler file
" Language: Test::Unit - Ruby Unit Testing Framework
" Maintainer: Doug Kearns <dougkearns@gmail.com>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
if exists("current_compiler")
finish
endif
let current_compiler = "rubyunit"
if exists(":CompilerSet") != 2 " older Vim always used :setlocal
command -nargs=* CompilerSet setlocal <args>
endif
let s:cpo_save = &cpo
set cpo-=C
CompilerSet makeprg=testrb
CompilerSet errorformat=\%W\ %\\+%\\d%\\+)\ Failure:,
\%C%m\ [%f:%l]:,
\%E\ %\\+%\\d%\\+)\ Error:,
\%C%m:,
\%C\ \ \ \ %f:%l:%.%#,
\%C%m,
\%Z\ %#,
\%-G%.%#
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: nowrap sw=2 sts=2 ts=8:

View File

@ -0,0 +1,40 @@
RUBY *ft-ruby-omni*
Completion of Ruby code requires that Vim be built with |+ruby|.
Ruby completion will parse your buffer on demand in order to provide a list of
completions. These completions will be drawn from modules loaded by "require"
and modules defined in the current buffer.
The completions provided by CTRL-X CTRL-O are sensitive to the context:
CONTEXT COMPLETIONS PROVIDED ~
1. Not inside a class definition Classes, constants and globals
2. Inside a class definition Methods or constants defined in the class
3. After '.', '::' or ':' Methods applicable to the object being
dereferenced
4. After ':' or ':foo' Symbol name (beginning with "foo")
Notes:
- Vim will load/evaluate code in order to provide completions. This may
cause some code execution, which may be a concern. This is no longer
enabled by default, to enable this feature add >
let g:rubycomplete_buffer_loading = 1
<- In context 1 above, Vim can parse the entire buffer to add a list of
classes to the completion results. This feature is turned off by default,
to enable it add >
let g:rubycomplete_classes_in_global = 1
< to your vimrc
- In context 2 above, anonymous classes are not supported.
- In context 3 above, Vim will attempt to determine the methods supported by
the object.
- Vim can detect and load the Rails environment for files within a rails
project. The feature is disabled by default, to enable it add >
let g:rubycomplete_rails = 1
< to your vimrc
vim:tw=78:sw=4:ts=8:ft=help:norl:

View File

@ -0,0 +1,64 @@
RUBY *ruby.vim* *ft-ruby-syntax*
There are a number of options to the Ruby syntax highlighting.
1. Ruby operators |ruby_operators|
2. Whitespace errors |ruby_space_errors|
3. Folds |ruby_fold|
4. Reducing expensive operations |ruby_no_expensive| |ruby_minlines|
1. Ruby operators *ruby_operators*
Ruby operators can be highlighted.
This is enabled by defining "ruby_operators": >
:let ruby_operators = 1
<
2. Whitespace errors *ruby_space_errors*
Whitespace errors can be highlighted by defining "ruby_space_errors": >
:let ruby_space_errors = 1
<
This will highlight trailing whitespace and tabs preceded by a space character
as errors. This can be refined by defining "ruby_no_trail_space_error" and
"ruby_no_tab_space_error" which will ignore trailing whitespace and tabs after
spaces respectively.
3. Folds *ruby_fold*
Folds can be enabled by defining "ruby_fold": >
:let ruby_fold = 1
<
This will set the value |foldmethod| to "syntax" locally to the current buffer
or window, which will enable syntax-based folding when editing Ruby filetypes.
4. Reducing expensive operations *ruby_no_expensive*
By default, the "end" keyword is colorized according to the opening statement
of the block it closes. While useful, this feature can be expensive; if you
experience slow redrawing (or you are on a terminal with poor color support)
you may want to turn it off by defining the "ruby_no_expensive" variable: >
:let ruby_no_expensive = 1
<
In this case the same color will be used for all control keywords.
*ruby_minlines*
If you do want this feature enabled, but notice highlighting errors while
scrolling backwards, which are fixed when redrawing with CTRL-L, try setting
the "ruby_minlines" variable to a value larger than 50: >
:let ruby_minlines = 100
<
Ideally, this value should be a number of lines large enough to embrace your
largest class or module.
vim:tw=78:sw=4:ts=8:ft=help:norl:

View File

@ -0,0 +1,61 @@
*vim-ruby.txt*
1. Ruby motions |ruby-motion|
2. Ruby text objects |ruby-text-objects|
==============================================================================
1. Ruby motions *ruby-motion*
Vim provides motions such as |[m| and |]m| for jumping to the start or end of
a method definition. Out of the box, these work for curly-bracket languages,
but not for ruby. The |vim-ruby| plugin enhances these motions, by making them
also work on ruby files.
*ruby-]m*
]m Go to start of next method definition.
*ruby-]M*
]M Go to end of next method definition.
*ruby-[m*
[m Go to start of previous method definition.
*ruby-[M*
[M Go to end of previous method definition.
*ruby-]]*
]] Go to start of next module or class definition.
*ruby-][*
][ Go to end of next module or class definition.
*ruby-[[*
[[ Go to start of previous module or class definition.
*ruby-[]*
[] Go to end of previous module or class definition.
==============================================================================
2. Ruby text objects *ruby-text-objects*
Vim's |text-objects| can be used to select or operate upon regions of text
that are defined by structure. The |vim-ruby| plugin adds text objects for
operating on methods and classes.
*ruby-v_am* *ruby-am*
am "a method", select from "def" until matching "end"
keyword.
*ruby-v_im* *ruby-im*
im "inner method", select contents of "def"/"end" block,
excluding the "def" and "end" themselves.
*ruby-v_aM* *ruby-aM*
aM "a class", select from "class" until matching "end"
keyword.
*ruby-v_iM* *ruby-iM*
iM "inner class", select contents of "class"/"end"
block, excluding the "class" and "end" themselves.
vim:tw=78:sw=4:ts=8:ft=help:norl:

View File

@ -0,0 +1,16 @@
[1, [2,
[3],
3],
4]
[1, [2,
3],
4]
[1, {2 =>
3},
4]
[1, f(2,
3),
4]

View File

@ -0,0 +1,62 @@
" Ruby
au BufNewFile,BufRead *.rb,*.rbw,*.gemspec set filetype=ruby
" Ruby on Rails
au BufNewFile,BufRead *.builder,*.rxml,*.rjs set filetype=ruby
" Rakefile
au BufNewFile,BufRead [rR]akefile,*.rake set filetype=ruby
" Rantfile
au BufNewFile,BufRead [rR]antfile,*.rant set filetype=ruby
" IRB config
au BufNewFile,BufRead .irbrc,irbrc set filetype=ruby
" Pry config
au BufNewFile,BufRead .pryrc set filetype=ruby
" Rackup
au BufNewFile,BufRead *.ru set filetype=ruby
" Capistrano
au BufNewFile,BufRead Capfile set filetype=ruby
" Bundler
au BufNewFile,BufRead Gemfile set filetype=ruby
" Guard
au BufNewFile,BufRead Guardfile,.Guardfile set filetype=ruby
" Chef
au BufNewFile,BufRead Cheffile set filetype=ruby
au BufNewFile,BufRead Berksfile set filetype=ruby
" Vagrant
au BufNewFile,BufRead [vV]agrantfile set filetype=ruby
" Autotest
au BufNewFile,BufRead .autotest set filetype=ruby
" eRuby
au BufNewFile,BufRead *.erb,*.rhtml set filetype=eruby
" Thor
au BufNewFile,BufRead [tT]horfile,*.thor set filetype=ruby
" Rabl
au BufNewFile,BufRead *.rabl set filetype=ruby
" Jbuilder
au BufNewFile,BufRead *.jbuilder set filetype=ruby
" Puppet librarian
au BufNewFile,BufRead Puppetfile set filetype=ruby
"
" Buildr Buildfile
au BufNewFile,BufRead [Bb]uildfile set filetype=ruby
" Appraisal
au BufNewFile,BufRead Appraisals set filetype=ruby
" vim: nowrap sw=2 sts=2 ts=8 noet:

View File

@ -0,0 +1,102 @@
" Vim filetype plugin
" Language: eRuby
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
" Only do this when not done yet for this buffer
if exists("b:did_ftplugin")
finish
endif
let s:save_cpo = &cpo
set cpo-=C
" Define some defaults in case the included ftplugins don't set them.
let s:undo_ftplugin = ""
let s:browsefilter = "All Files (*.*)\t*.*\n"
let s:match_words = ""
if !exists("g:eruby_default_subtype")
let g:eruby_default_subtype = "html"
endif
if &filetype =~ '^eruby\.'
let b:eruby_subtype = matchstr(&filetype,'^eruby\.\zs\w\+')
elseif !exists("b:eruby_subtype")
let s:lines = getline(1)."\n".getline(2)."\n".getline(3)."\n".getline(4)."\n".getline(5)."\n".getline("$")
let b:eruby_subtype = matchstr(s:lines,'eruby_subtype=\zs\w\+')
if b:eruby_subtype == ''
let b:eruby_subtype = matchstr(substitute(expand("%:t"),'\c\%(\.erb\|\.eruby\|\.erubis\)\+$','',''),'\.\zs\w\+$')
endif
if b:eruby_subtype == 'rhtml'
let b:eruby_subtype = 'html'
elseif b:eruby_subtype == 'rb'
let b:eruby_subtype = 'ruby'
elseif b:eruby_subtype == 'yml'
let b:eruby_subtype = 'yaml'
elseif b:eruby_subtype == 'js'
let b:eruby_subtype = 'javascript'
elseif b:eruby_subtype == 'txt'
" Conventional; not a real file type
let b:eruby_subtype = 'text'
elseif b:eruby_subtype == ''
let b:eruby_subtype = g:eruby_default_subtype
endif
endif
if exists("b:eruby_subtype") && b:eruby_subtype != ''
exe "runtime! ftplugin/".b:eruby_subtype.".vim ftplugin/".b:eruby_subtype."_*.vim ftplugin/".b:eruby_subtype."/*.vim"
else
runtime! ftplugin/html.vim ftplugin/html_*.vim ftplugin/html/*.vim
endif
unlet! b:did_ftplugin
" Override our defaults if these were set by an included ftplugin.
if exists("b:undo_ftplugin")
let s:undo_ftplugin = b:undo_ftplugin
unlet b:undo_ftplugin
endif
if exists("b:browsefilter")
let s:browsefilter = b:browsefilter
unlet b:browsefilter
endif
if exists("b:match_words")
let s:match_words = b:match_words
unlet b:match_words
endif
runtime! ftplugin/ruby.vim ftplugin/ruby_*.vim ftplugin/ruby/*.vim
let b:did_ftplugin = 1
" Combine the new set of values with those previously included.
if exists("b:undo_ftplugin")
let s:undo_ftplugin = b:undo_ftplugin . " | " . s:undo_ftplugin
endif
if exists ("b:browsefilter")
let s:browsefilter = substitute(b:browsefilter,'\cAll Files (\*\.\*)\t\*\.\*\n','','') . s:browsefilter
endif
if exists("b:match_words")
let s:match_words = b:match_words . ',' . s:match_words
endif
" Change the browse dialog on Win32 to show mainly eRuby-related files
if has("gui_win32")
let b:browsefilter="eRuby Files (*.erb, *.rhtml)\t*.erb;*.rhtml\n" . s:browsefilter
endif
" Load the combined list of match_words for matchit.vim
if exists("loaded_matchit")
let b:match_words = s:match_words
endif
" TODO: comments=
setlocal commentstring=<%#%s%>
let b:undo_ftplugin = "setl cms< "
\ " | unlet! b:browsefilter b:match_words | " . s:undo_ftplugin
let &cpo = s:save_cpo
unlet s:save_cpo
" vim: nowrap sw=2 sts=2 ts=8:

View File

@ -0,0 +1,395 @@
" Vim filetype plugin
" Language: Ruby
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
" ----------------------------------------------------------------------------
if (exists("b:did_ftplugin"))
finish
endif
let b:did_ftplugin = 1
let s:cpo_save = &cpo
set cpo&vim
if has("gui_running") && !has("gui_win32")
setlocal keywordprg=ri\ -T\ -f\ bs
else
setlocal keywordprg=ri
endif
" Matchit support
if exists("loaded_matchit") && !exists("b:match_words")
let b:match_ignorecase = 0
let b:match_words =
\ '\<\%(if\|unless\|case\|while\|until\|for\|do\|class\|module\|def\|begin\)\>=\@!' .
\ ':' .
\ '\<\%(else\|elsif\|ensure\|when\|rescue\|break\|redo\|next\|retry\)\>' .
\ ':' .
\ '\<end\>' .
\ ',{:},\[:\],(:)'
let b:match_skip =
\ "synIDattr(synID(line('.'),col('.'),0),'name') =~ '" .
\ "\\<ruby\\%(String\\|StringDelimiter\\|ASCIICode\\|Escape\\|" .
\ "Interpolation\\|NoInterpolation\\|Comment\\|Documentation\\|" .
\ "ConditionalModifier\\|RepeatModifier\\|OptionalDo\\|" .
\ "Function\\|BlockArgument\\|KeywordAsMethod\\|ClassVariable\\|" .
\ "InstanceVariable\\|GlobalVariable\\|Symbol\\)\\>'"
endif
setlocal formatoptions-=t formatoptions+=croql
setlocal include=^\\s*\\<\\(load\\>\\\|require\\>\\\|autoload\\s*:\\=[\"']\\=\\h\\w*[\"']\\=,\\)
setlocal includeexpr=substitute(substitute(v:fname,'::','/','g'),'$','.rb','')
setlocal suffixesadd=.rb
if exists("&ofu") && has("ruby")
setlocal omnifunc=rubycomplete#Complete
endif
" To activate, :set ballooneval
if has('balloon_eval') && exists('+balloonexpr')
setlocal balloonexpr=RubyBalloonexpr()
endif
" TODO:
"setlocal define=^\\s*def
setlocal comments=:#
setlocal commentstring=#\ %s
if !exists('g:ruby_version_paths')
let g:ruby_version_paths = {}
endif
function! s:query_path(root)
let code = "print $:.join %q{,}"
if &shell =~# 'sh' && $PATH !~# '\s'
let prefix = 'env PATH='.$PATH.' '
else
let prefix = ''
endif
if &shellxquote == "'"
let path_check = prefix.'ruby -e "' . code . '"'
else
let path_check = prefix."ruby -e '" . code . "'"
endif
let cd = haslocaldir() ? 'lcd' : 'cd'
let cwd = getcwd()
try
exe cd fnameescape(a:root)
let path = split(system(path_check),',')
exe cd fnameescape(cwd)
return path
finally
exe cd fnameescape(cwd)
endtry
endfunction
function! s:build_path(path)
let path = join(map(copy(a:path), 'v:val ==# "." ? "" : v:val'), ',')
if &g:path !~# '\v^\.%(,/%(usr|emx)/include)=,,$'
let path = substitute(&g:path,',,$',',','') . ',' . path
endif
return path
endfunction
if !exists('b:ruby_version') && !exists('g:ruby_path') && isdirectory(expand('%:p:h'))
let s:version_file = findfile('.ruby-version', '.;')
if !empty(s:version_file)
let b:ruby_version = get(readfile(s:version_file, '', 1), '')
if !has_key(g:ruby_version_paths, b:ruby_version)
let g:ruby_version_paths[b:ruby_version] = s:query_path(fnamemodify(s:version_file, ':p:h'))
endif
endif
endif
if exists("g:ruby_path")
let s:ruby_path = type(g:ruby_path) == type([]) ? join(g:ruby_path, ',') : g:ruby_path
elseif has_key(g:ruby_version_paths, get(b:, 'ruby_version', ''))
let s:ruby_paths = g:ruby_version_paths[b:ruby_version]
let s:ruby_path = s:build_path(s:ruby_paths)
else
if !exists('g:ruby_default_path')
if has("ruby") && has("win32")
ruby ::VIM::command( 'let g:ruby_default_path = split("%s",",")' % $:.join(%q{,}) )
elseif executable('ruby')
let g:ruby_default_path = s:query_path($HOME)
else
let g:ruby_default_path = map(split($RUBYLIB,':'), 'v:val ==# "." ? "" : v:val')
endif
endif
let s:ruby_paths = g:ruby_default_path
let s:ruby_path = s:build_path(s:ruby_paths)
endif
if stridx(&l:path, s:ruby_path) == -1
let &l:path = s:ruby_path
endif
if exists('s:ruby_paths') && stridx(&l:tags, join(map(copy(s:ruby_paths),'v:val."/tags"'),',')) == -1
let &l:tags = &tags . ',' . join(map(copy(s:ruby_paths),'v:val."/tags"'),',')
endif
if has("gui_win32") && !exists("b:browsefilter")
let b:browsefilter = "Ruby Source Files (*.rb)\t*.rb\n" .
\ "All Files (*.*)\t*.*\n"
endif
let b:undo_ftplugin = "setl fo< inc< inex< sua< def< com< cms< path< tags< kp<"
\."| unlet! b:browsefilter b:match_ignorecase b:match_words b:match_skip"
\."| if exists('&ofu') && has('ruby') | setl ofu< | endif"
\."| if has('balloon_eval') && exists('+bexpr') | setl bexpr< | endif"
if !exists("g:no_plugin_maps") && !exists("g:no_ruby_maps")
nnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>','rubyDefine','b','n')<CR>
nnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>','rubyDefine','','n')<CR>
nnoremap <silent> <buffer> [M :<C-U>call <SID>searchsyn('\<end\>','rubyDefine','b','n')<CR>
nnoremap <silent> <buffer> ]M :<C-U>call <SID>searchsyn('\<end\>','rubyDefine','','n')<CR>
xnoremap <silent> <buffer> [m :<C-U>call <SID>searchsyn('\<def\>','rubyDefine','b','v')<CR>
xnoremap <silent> <buffer> ]m :<C-U>call <SID>searchsyn('\<def\>','rubyDefine','','v')<CR>
xnoremap <silent> <buffer> [M :<C-U>call <SID>searchsyn('\<end\>','rubyDefine','b','v')<CR>
xnoremap <silent> <buffer> ]M :<C-U>call <SID>searchsyn('\<end\>','rubyDefine','','v')<CR>
nnoremap <silent> <buffer> [[ :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>','rubyModule\<Bar>rubyClass','b','n')<CR>
nnoremap <silent> <buffer> ]] :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>','rubyModule\<Bar>rubyClass','','n')<CR>
nnoremap <silent> <buffer> [] :<C-U>call <SID>searchsyn('\<end\>','rubyModule\<Bar>rubyClass','b','n')<CR>
nnoremap <silent> <buffer> ][ :<C-U>call <SID>searchsyn('\<end\>','rubyModule\<Bar>rubyClass','','n')<CR>
xnoremap <silent> <buffer> [[ :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>','rubyModule\<Bar>rubyClass','b','v')<CR>
xnoremap <silent> <buffer> ]] :<C-U>call <SID>searchsyn('\<\%(class\<Bar>module\)\>','rubyModule\<Bar>rubyClass','','v')<CR>
xnoremap <silent> <buffer> [] :<C-U>call <SID>searchsyn('\<end\>','rubyModule\<Bar>rubyClass','b','v')<CR>
xnoremap <silent> <buffer> ][ :<C-U>call <SID>searchsyn('\<end\>','rubyModule\<Bar>rubyClass','','v')<CR>
let b:undo_ftplugin = b:undo_ftplugin
\."| sil! exe 'unmap <buffer> [[' | sil! exe 'unmap <buffer> ]]' | sil! exe 'unmap <buffer> []' | sil! exe 'unmap <buffer> ]['"
\."| sil! exe 'unmap <buffer> [m' | sil! exe 'unmap <buffer> ]m' | sil! exe 'unmap <buffer> [M' | sil! exe 'unmap <buffer> ]M'"
if maparg('im','n') == ''
onoremap <silent> <buffer> im :<C-U>call <SID>wrap_i('[m',']M')<CR>
onoremap <silent> <buffer> am :<C-U>call <SID>wrap_a('[m',']M')<CR>
xnoremap <silent> <buffer> im :<C-U>call <SID>wrap_i('[m',']M')<CR>
xnoremap <silent> <buffer> am :<C-U>call <SID>wrap_a('[m',']M')<CR>
let b:undo_ftplugin = b:undo_ftplugin
\."| sil! exe 'ounmap <buffer> im' | sil! exe 'ounmap <buffer> am'"
\."| sil! exe 'xunmap <buffer> im' | sil! exe 'xunmap <buffer> am'"
endif
if maparg('iM','n') == ''
onoremap <silent> <buffer> iM :<C-U>call <SID>wrap_i('[[','][')<CR>
onoremap <silent> <buffer> aM :<C-U>call <SID>wrap_a('[[','][')<CR>
xnoremap <silent> <buffer> iM :<C-U>call <SID>wrap_i('[[','][')<CR>
xnoremap <silent> <buffer> aM :<C-U>call <SID>wrap_a('[[','][')<CR>
let b:undo_ftplugin = b:undo_ftplugin
\."| sil! exe 'ounmap <buffer> iM' | sil! exe 'ounmap <buffer> aM'"
\."| sil! exe 'xunmap <buffer> iM' | sil! exe 'xunmap <buffer> aM'"
endif
if maparg("\<C-]>",'n') == ''
nnoremap <silent> <buffer> <C-]> :<C-U>exe v:count1."tag <C-R>=RubyCursorIdentifier()<CR>"<CR>
nnoremap <silent> <buffer> g<C-]> :<C-U>exe "tjump <C-R>=RubyCursorIdentifier()<CR>"<CR>
nnoremap <silent> <buffer> g] :<C-U>exe "tselect <C-R>=RubyCursorIdentifier()<CR>"<CR>
nnoremap <silent> <buffer> <C-W>] :<C-U>exe v:count1."stag <C-R>=RubyCursorIdentifier()<CR>"<CR>
nnoremap <silent> <buffer> <C-W><C-]> :<C-U>exe v:count1."stag <C-R>=RubyCursorIdentifier()<CR>"<CR>
nnoremap <silent> <buffer> <C-W>g<C-]> :<C-U>exe "stjump <C-R>=RubyCursorIdentifier()<CR>"<CR>
nnoremap <silent> <buffer> <C-W>g] :<C-U>exe "stselect <C-R>=RubyCursorIdentifier()<CR>"<CR>
nnoremap <silent> <buffer> <C-W>} :<C-U>exe "ptag <C-R>=RubyCursorIdentifier()<CR>"<CR>
nnoremap <silent> <buffer> <C-W>g} :<C-U>exe "ptjump <C-R>=RubyCursorIdentifier()<CR>"<CR>
let b:undo_ftplugin = b:undo_ftplugin
\."| sil! exe 'nunmap <buffer> <C-]>'| sil! exe 'nunmap <buffer> g<C-]>'| sil! exe 'nunmap <buffer> g]'"
\."| sil! exe 'nunmap <buffer> <C-W>]'| sil! exe 'nunmap <buffer> <C-W><C-]>'"
\."| sil! exe 'nunmap <buffer> <C-W>g<C-]>'| sil! exe 'nunmap <buffer> <C-W>g]'"
\."| sil! exe 'nunmap <buffer> <C-W>}'| sil! exe 'nunmap <buffer> <C-W>g}'"
endif
if maparg("gf",'n') == ''
" By using findfile() rather than gf's normal behavior, we prevent
" erroneously editing a directory.
nnoremap <silent> <buffer> gf :<C-U>exe <SID>gf(v:count1,"gf",'edit')<CR>
nnoremap <silent> <buffer> <C-W>f :<C-U>exe <SID>gf(v:count1,"\<Lt>C-W>f",'split')<CR>
nnoremap <silent> <buffer> <C-W><C-F> :<C-U>exe <SID>gf(v:count1,"\<Lt>C-W>\<Lt>C-F>",'split')<CR>
nnoremap <silent> <buffer> <C-W>gf :<C-U>exe <SID>gf(v:count1,"\<Lt>C-W>gf",'tabedit')<CR>
let b:undo_ftplugin = b:undo_ftplugin
\."| sil! exe 'nunmap <buffer> gf' | sil! exe 'nunmap <buffer> <C-W>f' | sil! exe 'nunmap <buffer> <C-W><C-F>' | sil! exe 'nunmap <buffer> <C-W>gf'"
endif
endif
let &cpo = s:cpo_save
unlet s:cpo_save
if exists("g:did_ruby_ftplugin_functions")
finish
endif
let g:did_ruby_ftplugin_functions = 1
function! RubyBalloonexpr()
if !exists('s:ri_found')
let s:ri_found = executable('ri')
endif
if s:ri_found
let line = getline(v:beval_lnum)
let b = matchstr(strpart(line,0,v:beval_col),'\%(\w\|[:.]\)*$')
let a = substitute(matchstr(strpart(line,v:beval_col),'^\w*\%([?!]\|\s*=\)\?'),'\s\+','','g')
let str = b.a
let before = strpart(line,0,v:beval_col-strlen(b))
let after = strpart(line,v:beval_col+strlen(a))
if str =~ '^\.'
let str = substitute(str,'^\.','#','g')
if before =~ '\]\s*$'
let str = 'Array'.str
elseif before =~ '}\s*$'
" False positives from blocks here
let str = 'Hash'.str
elseif before =~ "[\"'`]\\s*$" || before =~ '\$\d\+\s*$'
let str = 'String'.str
elseif before =~ '\$\d\+\.\d\+\s*$'
let str = 'Float'.str
elseif before =~ '\$\d\+\s*$'
let str = 'Integer'.str
elseif before =~ '/\s*$'
let str = 'Regexp'.str
else
let str = substitute(str,'^#','.','')
endif
endif
let str = substitute(str,'.*\.\s*to_f\s*\.\s*','Float#','')
let str = substitute(str,'.*\.\s*to_i\%(nt\)\=\s*\.\s*','Integer#','')
let str = substitute(str,'.*\.\s*to_s\%(tr\)\=\s*\.\s*','String#','')
let str = substitute(str,'.*\.\s*to_sym\s*\.\s*','Symbol#','')
let str = substitute(str,'.*\.\s*to_a\%(ry\)\=\s*\.\s*','Array#','')
let str = substitute(str,'.*\.\s*to_proc\s*\.\s*','Proc#','')
if str !~ '^\w'
return ''
endif
silent! let res = substitute(system("ri -f rdoc -T \"".str.'"'),'\n$','','')
if res =~ '^Nothing known about' || res =~ '^Bad argument:' || res =~ '^More than one method'
return ''
endif
return res
else
return ""
endif
endfunction
function! s:searchsyn(pattern,syn,flags,mode)
norm! m'
if a:mode ==# 'v'
norm! gv
endif
let i = 0
let cnt = v:count ? v:count : 1
while i < cnt
let i = i + 1
let line = line('.')
let col = col('.')
let pos = search(a:pattern,'W'.a:flags)
while pos != 0 && s:synname() !~# a:syn
let pos = search(a:pattern,'W'.a:flags)
endwhile
if pos == 0
call cursor(line,col)
return
endif
endwhile
endfunction
function! s:synname()
return synIDattr(synID(line('.'),col('.'),0),'name')
endfunction
function! s:wrap_i(back,forward)
execute 'norm k'.a:forward
let line = line('.')
execute 'norm '.a:back
if line('.') == line - 1
return s:wrap_a(a:back,a:forward)
endif
execute 'norm jV'.a:forward.'k'
endfunction
function! s:wrap_a(back,forward)
execute 'norm '.a:forward
if line('.') < line('$') && getline(line('.')+1) ==# ''
let after = 1
endif
execute 'norm '.a:back
while getline(line('.')-1) =~# '^\s*#' && line('.')
-
endwhile
if exists('after')
execute 'norm V'.a:forward.'j'
elseif line('.') > 1 && getline(line('.')-1) =~# '^\s*$'
execute 'norm kV'.a:forward
else
execute 'norm V'.a:forward
endif
endfunction
function! RubyCursorIdentifier()
let asciicode = '\%(\w\|[]})\"'."'".']\)\@<!\%(?\%(\\M-\\C-\|\\C-\\M-\|\\M-\\c\|\\c\\M-\|\\c\|\\C-\|\\M-\)\=\%(\\\o\{1,3}\|\\x\x\{1,2}\|\\\=\S\)\)'
let number = '\%(\%(\w\|[]})\"'."'".']\s*\)\@<!-\)\=\%(\<[[:digit:]_]\+\%(\.[[:digit:]_]\+\)\=\%([Ee][[:digit:]_]\+\)\=\>\|\<0[xXbBoOdD][[:xdigit:]_]\+\>\)\|'.asciicode
let operator = '\%(\[\]\|<<\|<=>\|[!<>]=\=\|===\=\|[!=]\~\|>>\|\*\*\|\.\.\.\=\|=>\|[~^&|*/%+-]\)'
let method = '\%(\<[_a-zA-Z]\w*\>\%([?!]\|\s*=>\@!\)\=\)'
let global = '$\%([!$&"'."'".'*+,./:;<=>?@\`~]\|-\=\w\+\>\)'
let symbolizable = '\%(\%(@@\=\)\w\+\>\|'.global.'\|'.method.'\|'.operator.'\)'
let pattern = '\C\s*\%('.number.'\|\%(:\@<!:\)\='.symbolizable.'\)'
let [lnum, col] = searchpos(pattern,'bcn',line('.'))
let raw = matchstr(getline('.')[col-1 : ],pattern)
let stripped = substitute(substitute(raw,'\s\+=$','=',''),'^\s*:\=','','')
return stripped == '' ? expand("<cword>") : stripped
endfunction
function! s:gf(count,map,edit) abort
if getline('.') =~# '^\s*require_relative\s*\(["'']\).*\1\s*$'
let target = matchstr(getline('.'),'\(["'']\)\zs.\{-\}\ze\1')
return a:edit.' %:h/'.target.'.rb'
elseif getline('.') =~# '^\s*\%(require[( ]\|load[( ]\|autoload[( ]:\w\+,\)\s*\s*\%(::\)\=File\.expand_path(\(["'']\)\.\./.*\1,\s*__FILE__)\s*$'
let target = matchstr(getline('.'),'\(["'']\)\.\./\zs.\{-\}\ze\1')
return a:edit.' %:h/'.target.'.rb'
elseif getline('.') =~# '^\s*\%(require \|load \|autoload :\w\+,\)\s*\(["'']\).*\1\s*$'
let target = matchstr(getline('.'),'\(["'']\)\zs.\{-\}\ze\1')
else
let target = expand('<cfile>')
endif
let found = findfile(target, &path, a:count)
if found ==# ''
return 'norm! '.a:count.a:map
else
return a:edit.' '.fnameescape(found)
endif
endfunction
"
" Instructions for enabling "matchit" support:
"
" 1. Look for the latest "matchit" plugin at
"
" http://www.vim.org/scripts/script.php?script_id=39
"
" It is also packaged with Vim, in the $VIMRUNTIME/macros directory.
"
" 2. Copy "matchit.txt" into a "doc" directory (e.g. $HOME/.vim/doc).
"
" 3. Copy "matchit.vim" into a "plugin" directory (e.g. $HOME/.vim/plugin).
"
" 4. Ensure this file (ftplugin/ruby.vim) is installed.
"
" 5. Ensure you have this line in your $HOME/.vimrc:
" filetype plugin on
"
" 6. Restart Vim and create the matchit documentation:
"
" :helptags ~/.vim/doc
"
" Now you can do ":help matchit", and you should be able to use "%" on Ruby
" keywords. Try ":echo b:match_words" to be sure.
"
" Thanks to Mark J. Reed for the instructions. See ":help vimrc" for the
" locations of plugin directories, etc., as there are several options, and it
" differs on Windows. Email gsinclair@soyabean.com.au if you need help.
"
" vim: nowrap sw=2 sts=2 ts=8:

View File

@ -0,0 +1,82 @@
" Vim indent file
" Language: eRuby
" Maintainer: Tim Pope <vimNOSPAM@tpope.org>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
if exists("b:did_indent")
finish
endif
runtime! indent/ruby.vim
unlet! b:did_indent
setlocal indentexpr=
if exists("b:eruby_subtype")
exe "runtime! indent/".b:eruby_subtype.".vim"
else
runtime! indent/html.vim
endif
unlet! b:did_indent
if &l:indentexpr == ''
if &l:cindent
let &l:indentexpr = 'cindent(v:lnum)'
else
let &l:indentexpr = 'indent(prevnonblank(v:lnum-1))'
endif
endif
let b:eruby_subtype_indentexpr = &l:indentexpr
let b:did_indent = 1
setlocal indentexpr=GetErubyIndent()
setlocal indentkeys=o,O,*<Return>,<>>,{,},0),0],o,O,!^F,=end,=else,=elsif,=rescue,=ensure,=when
" Only define the function once.
if exists("*GetErubyIndent")
finish
endif
function! GetErubyIndent(...)
if a:0 && a:1 == '.'
let v:lnum = line('.')
elseif a:0 && a:1 =~ '^\d'
let v:lnum = a:1
endif
let vcol = col('.')
call cursor(v:lnum,1)
let inruby = searchpair('<%','','%>','W')
call cursor(v:lnum,vcol)
if inruby && getline(v:lnum) !~ '^<%\|^\s*[-=]\=%>'
let ind = GetRubyIndent(v:lnum)
else
exe "let ind = ".b:eruby_subtype_indentexpr
endif
let lnum = prevnonblank(v:lnum-1)
let line = getline(lnum)
let cline = getline(v:lnum)
if cline =~# '^\s*<%[-=]\=\s*\%(}\|end\|else\|\%(ensure\|rescue\|elsif\|when\).\{-\}\)\s*\%([-=]\=%>\|$\)'
let ind = ind - &sw
endif
if line =~# '\S\s*<%[-=]\=\s*\%(}\|end\).\{-\}\s*\%([-=]\=%>\|$\)'
let ind = ind - &sw
endif
if line =~# '\%({\|\<do\)\%(\s*|[^|]*|\)\=\s*[-=]\=%>'
let ind = ind + &sw
elseif line =~# '<%[-=]\=\s*\%(module\|class\|def\|if\|for\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure\|rescue\)\>.*%>'
let ind = ind + &sw
endif
if line =~# '^\s*<%[=#-]\=\s*$' && cline !~# '^\s*end\>'
let ind = ind + &sw
endif
if line !~# '^\s*<%' && line =~# '%>\s*$'
let ind = ind - &sw
endif
if cline =~# '^\s*[-=]\=%>\s*$'
let ind = ind - &sw
endif
return ind
endfunction
" vim:set sw=2 sts=2 ts=8 noet:

View File

@ -0,0 +1,537 @@
" Vim indent file
" Language: Ruby
" Maintainer: Nikolai Weibull <now at bitwi.se>
" URL: https://github.com/vim-ruby/vim-ruby
" Release Coordinator: Doug Kearns <dougkearns@gmail.com>
" 0. Initialization {{{1
" =================
" Only load this indent file when no other was loaded.
if exists("b:did_indent")
finish
endif
let b:did_indent = 1
setlocal nosmartindent
" Now, set up our indentation expression and keys that trigger it.
setlocal indentexpr=GetRubyIndent(v:lnum)
setlocal indentkeys=0{,0},0),0],!^F,o,O,e
setlocal indentkeys+==end,=else,=elsif,=when,=ensure,=rescue,==begin,==end
" Only define the function once.
if exists("*GetRubyIndent")
finish
endif
let s:cpo_save = &cpo
set cpo&vim
" 1. Variables {{{1
" ============
" Regex of syntax group names that are or delimit strings/symbols or are comments.
let s:syng_strcom = '\<ruby\%(Regexp\|RegexpDelimiter\|RegexpEscape' .
\ '\|Symbol\|String\|StringDelimiter\|StringEscape\|ASCIICode' .
\ '\|Interpolation\|NoInterpolation\|Comment\|Documentation\)\>'
" Regex of syntax group names that are strings.
let s:syng_string =
\ '\<ruby\%(String\|Interpolation\|NoInterpolation\|StringEscape\)\>'
" Regex of syntax group names that are strings or documentation.
let s:syng_stringdoc =
\'\<ruby\%(String\|Interpolation\|NoInterpolation\|StringEscape\|Documentation\)\>'
" Expression used to check whether we should skip a match with searchpair().
let s:skip_expr =
\ "synIDattr(synID(line('.'),col('.'),1),'name') =~ '".s:syng_strcom."'"
" Regex used for words that, at the start of a line, add a level of indent.
let s:ruby_indent_keywords = '^\s*\zs\<\%(module\|class\|def\|if\|for' .
\ '\|while\|until\|else\|elsif\|case\|when\|unless\|begin\|ensure' .
\ '\|rescue\):\@!\>' .
\ '\|\%([=,*/%+-]\|<<\|>>\|:\s\)\s*\zs' .
\ '\<\%(if\|for\|while\|until\|case\|unless\|begin\):\@!\>'
" Regex used for words that, at the start of a line, remove a level of indent.
let s:ruby_deindent_keywords =
\ '^\s*\zs\<\%(ensure\|else\|rescue\|elsif\|when\|end\):\@!\>'
" Regex that defines the start-match for the 'end' keyword.
"let s:end_start_regex = '\%(^\|[^.]\)\<\%(module\|class\|def\|if\|for\|while\|until\|case\|unless\|begin\|do\)\>'
" TODO: the do here should be restricted somewhat (only at end of line)?
let s:end_start_regex =
\ '\C\%(^\s*\|[=,*/%+\-|;{]\|<<\|>>\|:\s\)\s*\zs' .
\ '\<\%(module\|class\|def\|if\|for\|while\|until\|case\|unless\|begin\):\@!\>' .
\ '\|\%(^\|[^.:@$]\)\@<=\<do:\@!\>'
" Regex that defines the middle-match for the 'end' keyword.
let s:end_middle_regex = '\<\%(ensure\|else\|\%(\%(^\|;\)\s*\)\@<=\<rescue:\@!\>\|when\|elsif\):\@!\>'
" Regex that defines the end-match for the 'end' keyword.
let s:end_end_regex = '\%(^\|[^.:@$]\)\@<=\<end:\@!\>'
" Expression used for searchpair() call for finding match for 'end' keyword.
let s:end_skip_expr = s:skip_expr .
\ ' || (expand("<cword>") == "do"' .
\ ' && getline(".") =~ "^\\s*\\<\\(while\\|until\\|for\\):\\@!\\>")'
" Regex that defines continuation lines, not including (, {, or [.
let s:non_bracket_continuation_regex = '\%([\\.,:*/%+]\|\<and\|\<or\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)\s*\%(#.*\)\=$'
" Regex that defines continuation lines.
" TODO: this needs to deal with if ...: and so on
let s:continuation_regex =
\ '\%(%\@<![({[\\.,:*/%+]\|\<and\|\<or\|\%(<%\)\@<![=-]\|\W[|&?]\|||\|&&\)\s*\%(#.*\)\=$'
" Regex that defines bracket continuations
let s:bracket_continuation_regex = '%\@<!\%([({[]\)\s*\%(#.*\)\=$'
" Regex that defines the first part of a splat pattern
let s:splat_regex = '[[,(]\s*\*\s*\%(#.*\)\=$'
" Regex that defines blocks.
"
" Note that there's a slight problem with this regex and s:continuation_regex.
" Code like this will be matched by both:
"
" method_call do |(a, b)|
"
" The reason is that the pipe matches a hanging "|" operator.
"
let s:block_regex =
\ '\%(\<do:\@!\>\|%\@<!{\)\s*\%(|\s*(*\s*\%([*@&]\=\h\w*,\=\s*\)\%(,\s*(*\s*[*@&]\=\h\w*\s*)*\s*\)*|\)\=\s*\%(#.*\)\=$'
let s:block_continuation_regex = '^\s*[^])}\t ].*'.s:block_regex
" 2. Auxiliary Functions {{{1
" ======================
" Check if the character at lnum:col is inside a string, comment, or is ascii.
function s:IsInStringOrComment(lnum, col)
return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_strcom
endfunction
" Check if the character at lnum:col is inside a string.
function s:IsInString(lnum, col)
return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_string
endfunction
" Check if the character at lnum:col is inside a string or documentation.
function s:IsInStringOrDocumentation(lnum, col)
return synIDattr(synID(a:lnum, a:col, 1), 'name') =~ s:syng_stringdoc
endfunction
" Check if the character at lnum:col is inside a string delimiter
function s:IsInStringDelimiter(lnum, col)
return synIDattr(synID(a:lnum, a:col, 1), 'name') == 'rubyStringDelimiter'
endfunction
" Find line above 'lnum' that isn't empty, in a comment, or in a string.
function s:PrevNonBlankNonString(lnum)
let in_block = 0
let lnum = prevnonblank(a:lnum)
while lnum > 0
" Go in and out of blocks comments as necessary.
" If the line isn't empty (with opt. comment) or in a string, end search.
let line = getline(lnum)
if line =~ '^=begin'
if in_block
let in_block = 0
else
break
endif
elseif !in_block && line =~ '^=end'
let in_block = 1
elseif !in_block && line !~ '^\s*#.*$' && !(s:IsInStringOrComment(lnum, 1)
\ && s:IsInStringOrComment(lnum, strlen(line)))
break
endif
let lnum = prevnonblank(lnum - 1)
endwhile
return lnum
endfunction
" Find line above 'lnum' that started the continuation 'lnum' may be part of.
function s:GetMSL(lnum)
" Start on the line we're at and use its indent.
let msl = a:lnum
let msl_body = getline(msl)
let lnum = s:PrevNonBlankNonString(a:lnum - 1)
while lnum > 0
" If we have a continuation line, or we're in a string, use line as MSL.
" Otherwise, terminate search as we have found our MSL already.
let line = getline(lnum)
if s:Match(lnum, s:splat_regex)
" If the above line looks like the "*" of a splat, use the current one's
" indentation.
"
" Example:
" Hash[*
" method_call do
" something
"
return msl
elseif s:Match(line, s:non_bracket_continuation_regex) &&
\ s:Match(msl, s:non_bracket_continuation_regex)
" If the current line is a non-bracket continuation and so is the
" previous one, keep its indent and continue looking for an MSL.
"
" Example:
" method_call one,
" two,
" three
"
let msl = lnum
elseif s:Match(lnum, s:non_bracket_continuation_regex) &&
\ (s:Match(msl, s:bracket_continuation_regex) || s:Match(msl, s:block_continuation_regex))
" If the current line is a bracket continuation or a block-starter, but
" the previous is a non-bracket one, respect the previous' indentation,
" and stop here.
"
" Example:
" method_call one,
" two {
" three
"
return lnum
elseif s:Match(lnum, s:bracket_continuation_regex) &&
\ (s:Match(msl, s:bracket_continuation_regex) || s:Match(msl, s:block_continuation_regex))
" If both lines are bracket continuations (the current may also be a
" block-starter), use the current one's and stop here
"
" Example:
" method_call(
" other_method_call(
" foo
return msl
elseif s:Match(lnum, s:block_regex) &&
\ !s:Match(msl, s:continuation_regex) &&
\ !s:Match(msl, s:block_continuation_regex)
" If the previous line is a block-starter and the current one is
" mostly ordinary, use the current one as the MSL.
"
" Example:
" method_call do
" something
" something_else
return msl
else
let col = match(line, s:continuation_regex) + 1
if (col > 0 && !s:IsInStringOrComment(lnum, col))
\ || s:IsInString(lnum, strlen(line))
let msl = lnum
else
break
endif
endif
let msl_body = getline(msl)
let lnum = s:PrevNonBlankNonString(lnum - 1)
endwhile
return msl
endfunction
" Check if line 'lnum' has more opening brackets than closing ones.
function s:ExtraBrackets(lnum)
let opening = {'parentheses': [], 'braces': [], 'brackets': []}
let closing = {'parentheses': [], 'braces': [], 'brackets': []}
let line = getline(a:lnum)
let pos = match(line, '[][(){}]', 0)
" Save any encountered opening brackets, and remove them once a matching
" closing one has been found. If a closing bracket shows up that doesn't
" close anything, save it for later.
while pos != -1
if !s:IsInStringOrComment(a:lnum, pos + 1)
if line[pos] == '('
call add(opening.parentheses, {'type': '(', 'pos': pos})
elseif line[pos] == ')'
if empty(opening.parentheses)
call add(closing.parentheses, {'type': ')', 'pos': pos})
else
let opening.parentheses = opening.parentheses[0:-2]
endif
elseif line[pos] == '{'
call add(opening.braces, {'type': '{', 'pos': pos})
elseif line[pos] == '}'
if empty(opening.braces)
call add(closing.braces, {'type': '}', 'pos': pos})
else
let opening.braces = opening.braces[0:-2]
endif
elseif line[pos] == '['
call add(opening.brackets, {'type': '[', 'pos': pos})
elseif line[pos] == ']'
if empty(opening.brackets)
call add(closing.brackets, {'type': ']', 'pos': pos})
else
let opening.brackets = opening.brackets[0:-2]
endif
endif
endif
let pos = match(line, '[][(){}]', pos + 1)
endwhile
" Find the rightmost brackets, since they're the ones that are important in
" both opening and closing cases
let rightmost_opening = {'type': '(', 'pos': -1}
let rightmost_closing = {'type': ')', 'pos': -1}
for opening in opening.parentheses + opening.braces + opening.brackets
if opening.pos > rightmost_opening.pos
let rightmost_opening = opening
endif
endfor
for closing in closing.parentheses + closing.braces + closing.brackets
if closing.pos > rightmost_closing.pos
let rightmost_closing = closing
endif
endfor
return [rightmost_opening, rightmost_closing]
endfunction
function s:Match(lnum, regex)
let col = match(getline(a:lnum), '\C'.a:regex) + 1
return col > 0 && !s:IsInStringOrComment(a:lnum, col) ? col : 0
endfunction
function s:MatchLast(lnum, regex)
let line = getline(a:lnum)
let col = match(line, '.*\zs' . a:regex)
while col != -1 && s:IsInStringOrComment(a:lnum, col)
let line = strpart(line, 0, col)
let col = match(line, '.*' . a:regex)
endwhile
return col + 1
endfunction
" 3. GetRubyIndent Function {{{1
" =========================
function GetRubyIndent(...)
" 3.1. Setup {{{2
" ----------
" For the current line, use the first argument if given, else v:lnum
let clnum = a:0 ? a:1 : v:lnum
" Set up variables for restoring position in file. Could use clnum here.
let vcol = col('.')
" 3.2. Work on the current line {{{2
" -----------------------------
" Get the current line.
let line = getline(clnum)
let ind = -1
" If we got a closing bracket on an empty line, find its match and indent
" according to it. For parentheses we indent to its column - 1, for the
" others we indent to the containing line's MSL's level. Return -1 if fail.
let col = matchend(line, '^\s*[]})]')
if col > 0 && !s:IsInStringOrComment(clnum, col)
call cursor(clnum, col)
let bs = strpart('(){}[]', stridx(')}]', line[col - 1]) * 2, 2)
if searchpair(escape(bs[0], '\['), '', bs[1], 'bW', s:skip_expr) > 0
if line[col-1]==')' && col('.') != col('$') - 1
let ind = virtcol('.') - 1
else
let ind = indent(s:GetMSL(line('.')))
endif
endif
return ind
endif
" If we have a =begin or =end set indent to first column.
if match(line, '^\s*\%(=begin\|=end\)$') != -1
return 0
endif
" If we have a deindenting keyword, find its match and indent to its level.
" TODO: this is messy
if s:Match(clnum, s:ruby_deindent_keywords)
call cursor(clnum, 1)
if searchpair(s:end_start_regex, s:end_middle_regex, s:end_end_regex, 'bW',
\ s:end_skip_expr) > 0
let msl = s:GetMSL(line('.'))
let line = getline(line('.'))
if strpart(line, 0, col('.') - 1) =~ '=\s*$' &&
\ strpart(line, col('.') - 1, 2) !~ 'do'
let ind = virtcol('.') - 1
elseif getline(msl) =~ '=\s*\(#.*\)\=$'
let ind = indent(line('.'))
else
let ind = indent(msl)
endif
endif
return ind
endif
" If we are in a multi-line string or line-comment, don't do anything to it.
if s:IsInStringOrDocumentation(clnum, matchend(line, '^\s*') + 1)
return indent('.')
endif
" If we are at the closing delimiter of a "<<" heredoc-style string, set the
" indent to 0.
if line =~ '^\k\+\s*$'
\ && s:IsInStringDelimiter(clnum, 1)
\ && search('\V<<'.line, 'nbW') > 0
return 0
endif
" 3.3. Work on the previous line. {{{2
" -------------------------------
" Find a non-blank, non-multi-line string line above the current line.
let lnum = s:PrevNonBlankNonString(clnum - 1)
" If the line is empty and inside a string, use the previous line.
if line =~ '^\s*$' && lnum != prevnonblank(clnum - 1)
return indent(prevnonblank(clnum))
endif
" At the start of the file use zero indent.
if lnum == 0
return 0
endif
" Set up variables for the previous line.
let line = getline(lnum)
let ind = indent(lnum)
" If the previous line ended with a block opening, add a level of indent.
if s:Match(lnum, s:block_regex)
return indent(s:GetMSL(lnum)) + &sw
endif
" If the previous line ended with the "*" of a splat, add a level of indent
if line =~ s:splat_regex
return indent(lnum) + &sw
endif
" If the previous line contained unclosed opening brackets and we are still
" in them, find the rightmost one and add indent depending on the bracket
" type.
"
" If it contained hanging closing brackets, find the rightmost one, find its
" match and indent according to that.
if line =~ '[[({]' || line =~ '[])}]\s*\%(#.*\)\=$'
let [opening, closing] = s:ExtraBrackets(lnum)
if opening.pos != -1
if opening.type == '(' && searchpair('(', '', ')', 'bW', s:skip_expr) > 0
if col('.') + 1 == col('$')
return ind + &sw
else
return virtcol('.')
endif
else
let nonspace = matchend(line, '\S', opening.pos + 1) - 1
return nonspace > 0 ? nonspace : ind + &sw
endif
elseif closing.pos != -1
call cursor(lnum, closing.pos + 1)
normal! %
if s:Match(line('.'), s:ruby_indent_keywords)
return indent('.') + &sw
else
return indent('.')
endif
else
call cursor(clnum, vcol)
end
endif
" If the previous line ended with an "end", match that "end"s beginning's
" indent.
let col = s:Match(lnum, '\%(^\|[^.:@$]\)\<end\>\s*\%(#.*\)\=$')
if col > 0
call cursor(lnum, col)
if searchpair(s:end_start_regex, '', s:end_end_regex, 'bW',
\ s:end_skip_expr) > 0
let n = line('.')
let ind = indent('.')
let msl = s:GetMSL(n)
if msl != n
let ind = indent(msl)
end
return ind
endif
end
let col = s:Match(lnum, s:ruby_indent_keywords)
if col > 0
call cursor(lnum, col)
let ind = virtcol('.') - 1 + &sw
" TODO: make this better (we need to count them) (or, if a searchpair
" fails, we know that something is lacking an end and thus we indent a
" level
if s:Match(lnum, s:end_end_regex)
let ind = indent('.')
endif
return ind
endif
" 3.4. Work on the MSL line. {{{2
" --------------------------
" Set up variables to use and search for MSL to the previous line.
let p_lnum = lnum
let lnum = s:GetMSL(lnum)
" If the previous line wasn't a MSL and is continuation return its indent.
" TODO: the || s:IsInString() thing worries me a bit.
if p_lnum != lnum
if s:Match(p_lnum, s:non_bracket_continuation_regex) || s:IsInString(p_lnum,strlen(line))
return ind
endif
endif
" Set up more variables, now that we know we wasn't continuation bound.
let line = getline(lnum)
let msl_ind = indent(lnum)
" If the MSL line had an indenting keyword in it, add a level of indent.
" TODO: this does not take into account contrived things such as
" module Foo; class Bar; end
if s:Match(lnum, s:ruby_indent_keywords)
let ind = msl_ind + &sw
if s:Match(lnum, s:end_end_regex)
let ind = ind - &sw
endif
return ind
endif
" If the previous line ended with [*+/.,-=], but wasn't a block ending or a
" closing bracket, indent one extra level.
if s:Match(lnum, s:non_bracket_continuation_regex) && !s:Match(lnum, '^\s*\([\])}]\|end\)')
if lnum == p_lnum
let ind = msl_ind + &sw
else
let ind = msl_ind
endif
return ind
endif
" }}}2
return ind
endfunction
" }}}1
let &cpo = s:cpo_save
unlet s:cpo_save
" vim:set sw=2 sts=2 ts=8 et:

View File

@ -0,0 +1,24 @@
require 'spec_helper'
describe "Indenting" do
specify "multi-line arguments" do
assert_correct_indenting <<-EOF
User.new(
:first_name => 'Some',
:second_name => 'Guy'
)
EOF
assert_correct_indenting <<-EOF
User.new(:first_name => 'Some',
:second_name => 'Guy')
EOF
assert_correct_indenting <<-EOF
User.new(
:first_name => 'Some',
:second_name => 'Guy'
)
EOF
end
end

View File

@ -0,0 +1,42 @@
require 'spec_helper'
describe "Indenting" do
specify "if-clauses" do
assert_correct_indenting <<-EOF
if foo
bar
end
EOF
assert_correct_indenting <<-EOF
if foo
bar
else
baz
end
EOF
assert_correct_indenting <<-EOF
bar if foo
something_else
EOF
end
specify "heredocs" do
assert_correct_indenting <<-EOF
def one
two = <<-THREE
four
THREE
end
EOF
assert_correct_indenting <<-EOF
def one
two = <<THREE
four
THREE
end
EOF
end
end

View File

@ -0,0 +1,69 @@
require 'spec_helper'
describe "Indenting" do
specify "'do' indenting" do
assert_correct_indenting <<-EOF
do
something
end
EOF
assert_correct_indenting <<-EOF
def foo
a_hash = {:do => 'bar'}
end
EOF
assert_correct_indenting <<-EOF
def foo(job)
job.do!
end
EOF
end
specify "blocks with multiline parameters" do
assert_correct_indenting <<-EOF
def foo
opts.on('--coordinator host=HOST[,port=PORT]',
'Specify the HOST and the PORT of the coordinator') do |str|
h = sub_opts_to_hash(str)
puts h
end
end
EOF
end
specify "case-insensitive matching" do
@vim.set 'ignorecase'
assert_correct_indenting <<-EOF
module X
Class.new do
end
end
EOF
@vim.set 'ignorecase&'
end
specify "blocks with tuple arguments" do
assert_correct_indenting <<-EOF
proc do |(a, b)|
puts a
puts b
end
EOF
assert_correct_indenting <<-EOF
proc do |foo, (a, b), bar|
puts a
puts b
end
EOF
assert_correct_indenting <<-EOF
proc do |(a, (b, c)), d|
puts a, b
puts c, d
end
EOF
end
end

View File

@ -0,0 +1,142 @@
require 'spec_helper'
describe "Indenting" do
specify "arrays" do
assert_correct_indenting <<-EOF
foo = [one,
two,
three]
EOF
end
specify "tricky string interpolation" do
# See https://github.com/vim-ruby/vim-ruby/issues/75 for details
assert_correct_indenting <<-EOF
puts %{\#{}}
puts "OK"
EOF
assert_correct_indenting <<-EOF
while true
begin
puts %{\#{x}}
rescue ArgumentError
end
end
EOF
end
specify "continuations after round braces" do
assert_correct_indenting <<-EOF
opts.on('--coordinator host=HOST[,port=PORT]',
'Specify the HOST and the PORT of the coordinator') do |str|
h = sub_opts_to_hash(str)
puts h
end
EOF
end
specify "continuations after assignment" do
assert_correct_indenting <<-EOF
variable =
if condition?
1
else
2
end
EOF
assert_correct_indenting <<-EOF
variable = # evil comment
case something
when 'something'
something_else
else
other
end
EOF
end
specify "continuations after hanging comma" do
assert_correct_indenting <<-EOF
array = [
:one,
].each do |x|
puts x.to_s
end
EOF
end
specify "string interpolation" do
# See https://github.com/vim-ruby/vim-ruby/issues/93 for details
assert_correct_indenting <<-EOF
command = %|\#{file}|
settings.log.info("Returning: \#{command}")
EOF
end
specify "closing bracket not on its own line" do
# See https://github.com/vim-ruby/vim-ruby/issues/81 for details
assert_correct_indenting <<-EOF
one { two >>
three }
four
EOF
end
specify "lonesome single parenthesis in a method definition" do
# See https://github.com/vim-ruby/vim-ruby/issues/130 for details
assert_correct_indenting <<-EOF
def bar(
baz
)
return baz+1
end
EOF
end
specify "brackets on their own line, followed by a comma" do
# See https://github.com/vim-ruby/vim-ruby/issues/124 for details
assert_correct_indenting <<-EOF
bla = {
:one => [
{:bla => :blub}
],
:two => (
{:blub => :abc}
),
:three => {
:blub => :abc
},
:four => 'five'
}
EOF
end
specify "string with an and#" do
# See https://github.com/vim-ruby/vim-ruby/issues/108 for details
assert_correct_indenting <<-EOF
outside_block "and#" do
inside_block do
end
end
EOF
end
specify "continuation with a symbol at the end" do
# See https://github.com/vim-ruby/vim-ruby/issues/132 for details
assert_correct_indenting <<-EOF
foo = :+
# Next indents correctly
EOF
end
specify "continuation with a hanging comma" do
# See https://github.com/vim-ruby/vim-ruby/issues/139 for details
assert_correct_indenting <<-EOF
thing :foo
thing 'a',
'b'
EOF
end
end

View File

@ -0,0 +1,31 @@
require 'spec_helper'
describe "Indenting" do
specify "end constructs" do
assert_correct_indenting <<-EOF
f do
g { def h; end }
end
EOF
assert_correct_indenting <<-EOF
if foo
bar ; end
something_else
EOF
assert_correct_indenting <<-EOF
if bar ; end
something_else
EOF
assert_correct_indenting <<-EOF
foo do
foo = 3 . class
foo = lambda { class One; end }
foo = lambda { |args| class One; end }
foo = bar; class One; end
end
EOF
end
end

View File

@ -0,0 +1,66 @@
require 'spec_helper'
describe "Indenting" do
specify "nested blocks" do
assert_correct_indenting <<-EOF
var.func1(:param => 'value') do
var.func2(:param => 'value') do
puts "test"
end
end
EOF
assert_correct_indenting <<-EOF
var.func1(:param => 'value') {
var.func2(:param => 'value') {
foo({ bar => baz })
puts "test one"
puts "test two"
}
}
EOF
assert_correct_indenting <<-EOF
var.
func1(:param => 'value') {
var.func2(:param => 'value') {
puts "test"
}
}
EOF
end
specify "nested hashes" do
assert_correct_indenting <<-EOF
foo, bar = {
:bar => {
:one => 'two',
:five => 'six'
}
}
EOF
assert_correct_indenting <<-EOF
foo,
bar = {
:bar => {
:foo => { 'bar' => 'baz' },
:one => 'two',
:three => 'four'
}
}
EOF
end
specify "nested blocks with a continuation and function call inbetween" do
assert_correct_indenting <<-EOF
var.
func1(:param => 'value') {
func1_5(:param => 'value')
var.func2(:param => 'value') {
puts "test"
}
}
EOF
end
end

View File

@ -0,0 +1,46 @@
require 'spec_helper'
describe "Indenting" do
specify "splats with blocks in square brackets" do
assert_correct_indenting <<-EOF
x = Foo[*
y do
z
end
]
EOF
assert_correct_indenting <<-EOF
x = Foo[* # with a comment
y do
z
end
]
EOF
end
specify "splats with blocks in assignment" do
assert_correct_indenting <<-EOF
x = *
array.map do
3
end
EOF
end
specify "splats with blocks in round brackets" do
assert_correct_indenting <<-EOF
x = Foo(*y do
z
end)
EOF
assert_correct_indenting <<-EOF
x = Foo(
*y do
z
end
)
EOF
end
end

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