aboutsummaryrefslogtreecommitdiff
path: root/vim/autoload
diff options
context:
space:
mode:
authorBen Beltran <ben@freshout.us>2013-06-05 10:50:57 -0500
committerBen Beltran <ben@freshout.us>2013-06-05 10:50:57 -0500
commitfe337504f2fb3ded76326b1e3d4d02787a27d853 (patch)
treeb84891d78de37ae078ea9850a541799b5bca8085 /vim/autoload
parente23d7a9f7363bdc69e95a1df31e093db15459fcf (diff)
Aand that's all the plugins.
Diffstat (limited to 'vim/autoload')
-rw-r--r--vim/autoload/conque_term.vim1590
-rw-r--r--vim/autoload/rails.vim4560
-rw-r--r--vim/autoload/snipMate.vim435
-rw-r--r--vim/autoload/syntastic.vim24
-rw-r--r--vim/autoload/syntastic/c.vim171
-rw-r--r--vim/autoload/tagbar.vim3099
6 files changed, 0 insertions, 9879 deletions
diff --git a/vim/autoload/conque_term.vim b/vim/autoload/conque_term.vim
deleted file mode 100644
index 2780c7d..0000000
--- a/vim/autoload/conque_term.vim
+++ /dev/null
@@ -1,1590 +0,0 @@
-" FILE: plugin/conque_term.vim {{{
-"
-" AUTHOR: Nico Raffo <nicoraffo@gmail.com>
-" MODIFIED: 2010-05-27
-" VERSION: 1.1, for Vim 7.0
-" LICENSE:
-" Conque - pty interaction in Vim
-" Copyright (C) 2009-2010 Nico Raffo
-"
-" MIT License
-"
-" Permission is hereby granted, free of charge, to any person obtaining a copy
-" of this software and associated documentation files (the "Software"), to deal
-" in the Software without restriction, including without limitation the rights
-" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-" copies of the Software, and to permit persons to whom the Software is
-" furnished to do so, subject to the following conditions:
-"
-" The above copyright notice and this permission notice shall be included in
-" all copies or substantial portions of the Software.
-"
-" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-" THE SOFTWARE.
-" }}}
-
-
-" **********************************************************************************************************
-" **** VIM FUNCTIONS ***************************************************************************************
-" **********************************************************************************************************
-
-" launch conque
-function! conque_term#open(...) "{{{
- let command = get(a:000, 0, '')
- let hooks = get(a:000, 1, [])
-
- " bare minimum validation
- if has('python') != 1
- echohl WarningMsg | echomsg "Conque requires the Python interface to be installed" | echohl None
- return 0
- endif
- if empty(command)
- echohl WarningMsg | echomsg "No command found" | echohl None
- return 0
- else
- let l:cargs = split(command, '\s')
- if !executable(l:cargs[0])
- echohl WarningMsg | echomsg "Not an executable: " . l:cargs[0] | echohl None
- return 0
- endif
- endif
-
- " set buffer window options
- let g:ConqueTerm_BufName = substitute(command, ' ', '\\ ', 'g') . "\\ -\\ " . g:ConqueTerm_Idx
- call conque_term#set_buffer_settings(command, hooks)
- let b:ConqueTerm_Var = 'ConqueTerm_' . g:ConqueTerm_Idx
- let g:ConqueTerm_Var = 'ConqueTerm_' . g:ConqueTerm_Idx
- let g:ConqueTerm_Idx += 1
-
- " open command
- try
- let l:config = '{"color":' . string(g:ConqueTerm_Color) . ',"TERM":"' . g:ConqueTerm_TERM . '"}'
- execute 'python ' . b:ConqueTerm_Var . ' = Conque()'
- execute "python " . b:ConqueTerm_Var . ".open('" . conque_term#python_escape(command) . "', " . l:config . ")"
- catch
- echohl WarningMsg | echomsg "Unable to open command: " . command | echohl None
- return 0
- endtry
-
- " set buffer mappings and auto commands
- call conque_term#set_mappings('start')
-
- startinsert!
- return 1
-endfunction "}}}
-
-" set buffer options
-function! conque_term#set_buffer_settings(command, pre_hooks) "{{{
-
- " optional hooks to execute, e.g. 'split'
- for h in a:pre_hooks
- sil exe h
- endfor
- sil exe "edit " . g:ConqueTerm_BufName
-
- " buffer settings
- setlocal nocompatible " conque won't work in compatible mode
- setlocal nopaste " conque won't work in paste mode
- setlocal buftype=nofile " this buffer is not a file, you can't save it
- setlocal nonumber " hide line numbers
- setlocal foldcolumn=0 " reasonable left margin
- setlocal nowrap " default to no wrap (esp with MySQL)
- setlocal noswapfile " don't bother creating a .swp file
- setlocal updatetime=50 " trigger cursorhold event after 50ms / XXX - global
- setlocal scrolloff=0 " don't use buffer lines. it makes the 'clear' command not work as expected
- setlocal sidescrolloff=0 " don't use buffer lines. it makes the 'clear' command not work as expected
- setlocal sidescroll=1 " don't use buffer lines. it makes the 'clear' command not work as expected
- setlocal foldmethod=manual " don't fold on {{{}}} and stuff
- setlocal bufhidden=hide " when buffer is no longer displayed, don't wipe it out
- setfiletype conque_term " useful
- sil exe "setlocal syntax=" . g:ConqueTerm_Syntax
-
-endfunction " }}}
-
-" set key mappings and auto commands
-function! conque_term#set_mappings(action) "{{{
-
- " set action
- if a:action == 'toggle'
- if exists('b:conque_on') && b:conque_on == 1
- let l:action = 'stop'
- echohl WarningMsg | echomsg "Terminal is paused" | echohl None
- else
- let l:action = 'start'
- echohl WarningMsg | echomsg "Terminal is resumed" | echohl None
- endif
- else
- let l:action = a:action
- endif
-
- " if mappings are being removed, add 'un'
- let map_modifier = 'nore'
- if l:action == 'stop'
- let map_modifier = 'un'
- endif
-
- " remove all auto commands
- if l:action == 'stop'
- execute 'autocmd! ' . b:ConqueTerm_Var
-
- else
- execute 'augroup ' . b:ConqueTerm_Var
-
- " handle unexpected closing of shell, passes HUP to parent and all child processes
- execute 'autocmd ' . b:ConqueTerm_Var . ' BufUnload <buffer> python ' . b:ConqueTerm_Var . '.proc.signal(1)'
-
- " check for resized/scrolled buffer when entering buffer
- execute 'autocmd ' . b:ConqueTerm_Var . ' BufEnter <buffer> python ' . b:ConqueTerm_Var . '.update_window_size()'
- execute 'autocmd ' . b:ConqueTerm_Var . ' VimResized python ' . b:ConqueTerm_Var . '.update_window_size()'
-
- " set/reset updatetime on entering/exiting buffer
- autocmd BufEnter <buffer> set updatetime=50
- autocmd BufLeave <buffer> set updatetime=2000
-
- " check for resized/scrolled buffer when entering insert mode
- " XXX - messed up since we enter insert mode at each updatetime
- "execute 'autocmd InsertEnter <buffer> python ' . b:ConqueTerm_Var . '.screen.align()'
-
- " read more output when this isn't the current buffer
- if g:ConqueTerm_ReadUnfocused == 1
- execute 'autocmd ' . b:ConqueTerm_Var . ' CursorHold * call conque_term#read_all()'
- endif
-
- " poll for more output
- sil execute 'autocmd ' . b:ConqueTerm_Var . ' CursorHoldI <buffer> python ' . b:ConqueTerm_Var . '.auto_read()'
- endif
-
- " use F22 key to get more input
- if l:action == 'start'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <expr> <F22> "\<left>\<right>"'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <expr> <F23> "\<right>\<left>"'
- else
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <expr> <F22>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <expr> <F23>'
- endif
-
- " map ASCII 1-31
- for c in range(1, 31)
- " <Esc>
- if c == 27
- continue
- endif
- if l:action == 'start'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <C-' . nr2char(64 + c) . '> <C-o>:python ' . b:ConqueTerm_Var . '.write(chr(' . c . '))<CR>'
- else
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <C-' . nr2char(64 + c) . '>'
- endif
- endfor
- if l:action == 'start'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> <C-c> <C-o>:python ' . b:ConqueTerm_Var . '.write(chr(3))<CR>'
- else
- sil exe 'n' . map_modifier . 'map <silent> <buffer> <C-c>'
- endif
-
- " leave insert mode
- if !exists('g:ConqueTerm_EscKey') || g:ConqueTerm_EscKey == '<Esc>'
- " use <Esc><Esc> to send <Esc> to terminal
- if l:action == 'start'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Esc><Esc> <C-o>:python ' . b:ConqueTerm_Var . '.write(chr(27))<CR>'
- else
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Esc><Esc>'
- endif
- else
- " use <Esc> to send <Esc> to terminal
- if l:action == 'start'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> ' . g:ConqueTerm_EscKey . ' <Esc>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Esc> <C-o>:python ' . b:ConqueTerm_Var . '.write(chr(27))<CR>'
- else
- sil exe 'i' . map_modifier . 'map <silent> <buffer> ' . g:ConqueTerm_EscKey
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Esc>'
- endif
- endif
-
- " Map <C-w> in insert mode
- if exists('g:ConqueTerm_CWInsert') && g:ConqueTerm_CWInsert == 1
- inoremap <silent> <buffer> <C-w>j <Esc><C-w>j
- inoremap <silent> <buffer> <C-w>k <Esc><C-w>k
- inoremap <silent> <buffer> <C-w>h <Esc><C-w>h
- inoremap <silent> <buffer> <C-w>l <Esc><C-w>l
- inoremap <silent> <buffer> <C-w>w <Esc><C-w>w
- endif
-
- " map ASCII 33-127
- for i in range(33, 127)
- " <Bar>
- if i == 124
- if l:action == 'start'
- sil exe "i" . map_modifier . "map <silent> <buffer> <Bar> <C-o>:python " . b:ConqueTerm_Var . ".write(chr(124))<CR>"
- else
- sil exe "i" . map_modifier . "map <silent> <buffer> <Bar>"
- endif
- continue
- endif
- if l:action == 'start'
- sil exe "i" . map_modifier . "map <silent> <buffer> " . nr2char(i) . " <C-o>:python " . b:ConqueTerm_Var . ".write(chr(" . i . "))<CR>"
- else
- sil exe "i" . map_modifier . "map <silent> <buffer> " . nr2char(i)
- endif
- endfor
-
- " map ASCII 128-255
- for i in range(128, 255)
- if l:action == 'start'
- sil exe "i" . map_modifier . "map <silent> <buffer> " . nr2char(i) . " <C-o>:python " . b:ConqueTerm_Var . ".write('" . nr2char(i) . "')<CR>"
- else
- sil exe "i" . map_modifier . "map <silent> <buffer> " . nr2char(i)
- endif
- endfor
-
- " Special cases
- if l:action == 'start'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <BS> <C-o>:python ' . b:ConqueTerm_Var . '.write(u"\u0008")<CR>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Space> <C-o>:python ' . b:ConqueTerm_Var . '.write(" ")<CR>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Up> <C-o>:python ' . b:ConqueTerm_Var . '.write(u"\u001b[A")<CR>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Down> <C-o>:python ' . b:ConqueTerm_Var . '.write(u"\u001b[B")<CR>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Right> <C-o>:python ' . b:ConqueTerm_Var . '.write(u"\u001b[C")<CR>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Left> <C-o>:python ' . b:ConqueTerm_Var . '.write(u"\u001b[D")<CR>'
- else
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <BS>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Space>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Up>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Down>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Right>'
- sil exe 'i' . map_modifier . 'map <silent> <buffer> <Left>'
- endif
-
- " send selected text into conque
- if l:action == 'start'
- sil exe 'v' . map_modifier . 'map <silent> <F9> :<C-u>call conque_term#send_selected(visualmode())<CR>'
- else
- sil exe 'v' . map_modifier . 'map <silent> <F9>'
- endif
-
- " remap paste keys
- if l:action == 'start'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> p :python ' . b:ConqueTerm_Var . '.write(vim.eval("@@"))<CR>a'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> P :python ' . b:ConqueTerm_Var . '.write(vim.eval("@@"))<CR>a'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> ]p :python ' . b:ConqueTerm_Var . '.write(vim.eval("@@"))<CR>a'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> [p :python ' . b:ConqueTerm_Var . '.write(vim.eval("@@"))<CR>a'
- else
- sil exe 'n' . map_modifier . 'map <silent> <buffer> p'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> P'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> ]p'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> [p'
- endif
- if has('gui_running')
- if l:action == 'start'
- sil exe 'i' . map_modifier . 'map <buffer> <S-Insert> <Esc>:<C-u>python ' . b:ConqueTerm_Var . ".write(vim.eval('@+'))<CR>a"
- else
- sil exe 'i' . map_modifier . 'map <buffer> <S-Insert>'
- endif
- endif
-
- " disable other normal mode keys which insert text
- if l:action == 'start'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> r :echo "Replace mode disabled in shell."<CR>'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> R :echo "Replace mode disabled in shell."<CR>'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> c :echo "Change mode disabled in shell."<CR>'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> C :echo "Change mode disabled in shell."<CR>'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> s :echo "Change mode disabled in shell."<CR>'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> S :echo "Change mode disabled in shell."<CR>'
- else
- sil exe 'n' . map_modifier . 'map <silent> <buffer> r'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> R'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> c'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> C'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> s'
- sil exe 'n' . map_modifier . 'map <silent> <buffer> S'
- endif
-
- " set conque as on or off
- if l:action == 'start'
- let b:conque_on = 1
- else
- let b:conque_on = 0
- endif
-
- " map command to start stop the shell
- if a:action == 'start'
- nnoremap <F5> :<C-u>call conque_term#set_mappings('toggle')<CR>
- endif
-
-endfunction " }}}
-
-
-" send selected text from another buffer
-function! conque_term#send_selected(type) "{{{
- let reg_save = @@
-
- " save user's sb settings
- let sb_save = &switchbuf
- set switchbuf=usetab
-
- " yank current selection
- sil exe "normal! `<" . a:type . "`>y"
-
- " format yanked text
- let @@ = substitute(@@, '^[\r\n]*', '', '')
- let @@ = substitute(@@, '[\r\n]*$', '', '')
-
- " execute yanked text
- sil exe ":sb " . g:ConqueTerm_BufName
- sil exe 'python ' . g:ConqueTerm_Var . '.paste_selection()'
-
- " reset original values
- let @@ = reg_save
- sil exe 'set switchbuf=' . sb_save
-
- " scroll buffer left
- startinsert!
- normal 0zH
-endfunction "}}}
-
-" read from all known conque buffers
-function! conque_term#read_all() "{{{
- " don't run this if we're in a conque buffer
- if exists('b:ConqueTerm_Var')
- return
- endif
-
- try
- for i in range(1, g:ConqueTerm_Idx - 1)
- execute 'python ConqueTerm_' . string(i) . '.read(1)'
- endfor
- catch
- " probably a deleted buffer
- endtry
-
- " restart updatetime
- call feedkeys("f\e")
-endfunction "}}}
-
-" util function to add enough \s to pass a string to python
-function! conque_term#python_escape(input) "{{{
- let l:cleaned = a:input
- let l:cleaned = substitute(l:cleaned, '\\', '\\\\', 'g')
- let l:cleaned = substitute(l:cleaned, '\n', '\\n', 'g')
- let l:cleaned = substitute(l:cleaned, '\r', '\\r', 'g')
- let l:cleaned = substitute(l:cleaned, "'", "\\\\'", 'g')
- return l:cleaned
-endfunction "}}}
-
-" **********************************************************************************************************
-" **** PYTHON **********************************************************************************************
-" **********************************************************************************************************
-
-if has('python')
-
-python << EOF
-
-import vim, re, time, math
-
-# CONFIG CONSTANTS {{{
-
-CONQUE_CTL = {
- 7:'bel', # bell
- 8:'bs', # backspace
- 9:'tab', # tab
- 10:'nl', # new line
- 13:'cr' # carriage return
-}
-# 11 : 'vt', # vertical tab
-# 12 : 'ff', # form feed
-# 14 : 'so', # shift out
-# 15 : 'si' # shift in
-
-# Escape sequences
-CONQUE_ESCAPE = {
- 'm':'font',
- 'J':'clear_screen',
- 'K':'clear_line',
- '@':'add_spaces',
- 'A':'cursor_up',
- 'B':'cursor_down',
- 'C':'cursor_right',
- 'D':'cursor_left',
- 'G':'cursor_to_column',
- 'H':'cursor',
- 'P':'delete_chars',
- 'f':'cursor',
- 'g':'tab_clear',
- 'r':'set_coords',
- 'h':'set',
- 'l':'reset'
-}
-# 'L':'insert_lines',
-# 'M':'delete_lines',
-# 'd':'cusor_vpos',
-
-# Alternate escape sequences, no [
-CONQUE_ESCAPE_PLAIN = {
- 'D':'scroll_up',
- 'E':'next_line',
- 'H':'set_tab',
- 'M':'scroll_down'
-}
-# 'N':'single_shift_2',
-# 'O':'single_shift_3',
-# '=':'alternate_keypad',
-# '>':'numeric_keypad',
-# '7':'save_cursor',
-# '8':'restore_cursor',
-
-# Uber alternate escape sequences, with # or ?
-CONQUE_ESCAPE_QUESTION = {
- '1h':'new_line_mode',
- '3h':'132_cols',
- '4h':'smooth_scrolling',
- '5h':'reverse_video',
- '6h':'relative_origin',
- '7h':'set_auto_wrap',
- '8h':'set_auto_repeat',
- '9h':'set_interlacing_mode',
- '1l':'set_cursor_key',
- '2l':'set_vt52',
- '3l':'80_cols',
- '4l':'set_jump_scrolling',
- '5l':'normal_video',
- '6l':'absolute_origin',
- '7l':'reset_auto_wrap',
- '8l':'reset_auto_repeat',
- '9l':'reset_interlacing_mode'
-}
-
-CONQUE_ESCAPE_HASH = {
- '8':'screen_alignment_test'
-}
-# '3':'double_height_top',
-# '4':'double_height_bottom',
-# '5':'single_height_single_width',
-# '6':'single_height_double_width',
-
-# Font codes {{{
-CONQUE_FONT = {
- 0: {'description':'Normal (default)', 'attributes': {'cterm':'NONE','ctermfg':'NONE','ctermbg':'NONE','gui':'NONE','guifg':'NONE','guibg':'NONE'}, 'normal':True},
- 1: {'description':'Bold', 'attributes': {'cterm':'BOLD','gui':'BOLD'}, 'normal':False},
- 4: {'description':'Underlined', 'attributes': {'cterm':'UNDERLINE','gui':'UNDERLINE'}, 'normal':False},
- 5: {'description':'Blink (appears as Bold)', 'attributes': {'cterm':'BOLD','gui':'BOLD'}, 'normal':False},
- 7: {'description':'Inverse', 'attributes': {'cterm':'REVERSE','gui':'REVERSE'}, 'normal':False},
- 8: {'description':'Invisible (hidden)', 'attributes': {'ctermfg':'0','ctermbg':'0','guifg':'#000000','guibg':'#000000'}, 'normal':False},
- 22: {'description':'Normal (neither bold nor faint)', 'attributes': {'cterm':'NONE','gui':'NONE'}, 'normal':True},
- 24: {'description':'Not underlined', 'attributes': {'cterm':'NONE','gui':'NONE'}, 'normal':True},
- 25: {'description':'Steady (not blinking)', 'attributes': {'cterm':'NONE','gui':'NONE'}, 'normal':True},
- 27: {'description':'Positive (not inverse)', 'attributes': {'cterm':'NONE','gui':'NONE'}, 'normal':True},
- 28: {'description':'Visible (not hidden)', 'attributes': {'ctermfg':'NONE','ctermbg':'NONE','guifg':'NONE','guibg':'NONE'}, 'normal':True},
- 30: {'description':'Set foreground color to Black', 'attributes': {'ctermfg':'16','guifg':'#000000'}, 'normal':False},
- 31: {'description':'Set foreground color to Red', 'attributes': {'ctermfg':'1','guifg':'#ff0000'}, 'normal':False},
- 32: {'description':'Set foreground color to Green', 'attributes': {'ctermfg':'2','guifg':'#00ff00'}, 'normal':False},
- 33: {'description':'Set foreground color to Yellow', 'attributes': {'ctermfg':'3','guifg':'#ffff00'}, 'normal':False},
- 34: {'description':'Set foreground color to Blue', 'attributes': {'ctermfg':'4','guifg':'#0000ff'}, 'normal':False},
- 35: {'description':'Set foreground color to Magenta', 'attributes': {'ctermfg':'5','guifg':'#990099'}, 'normal':False},
- 36: {'description':'Set foreground color to Cyan', 'attributes': {'ctermfg':'6','guifg':'#009999'}, 'normal':False},
- 37: {'description':'Set foreground color to White', 'attributes': {'ctermfg':'7','guifg':'#ffffff'}, 'normal':False},
- 39: {'description':'Set foreground color to default (original)', 'attributes': {'ctermfg':'NONE','guifg':'NONE'}, 'normal':True},
- 40: {'description':'Set background color to Black', 'attributes': {'ctermbg':'16','guibg':'#000000'}, 'normal':False},
- 41: {'description':'Set background color to Red', 'attributes': {'ctermbg':'1','guibg':'#ff0000'}, 'normal':False},
- 42: {'description':'Set background color to Green', 'attributes': {'ctermbg':'2','guibg':'#00ff00'}, 'normal':False},
- 43: {'description':'Set background color to Yellow', 'attributes': {'ctermbg':'3','guibg':'#ffff00'}, 'normal':False},
- 44: {'description':'Set background color to Blue', 'attributes': {'ctermbg':'4','guibg':'#0000ff'}, 'normal':False},
- 45: {'description':'Set background color to Magenta', 'attributes': {'ctermbg':'5','guibg':'#990099'}, 'normal':False},
- 46: {'description':'Set background color to Cyan', 'attributes': {'ctermbg':'6','guibg':'#009999'}, 'normal':False},
- 47: {'description':'Set background color to White', 'attributes': {'ctermbg':'7','guibg':'#ffffff'}, 'normal':False},
- 49: {'description':'Set background color to default (original).', 'attributes': {'ctermbg':'NONE','guibg':'NONE'}, 'normal':True},
- 90: {'description':'Set foreground color to Black', 'attributes': {'ctermfg':'8','guifg':'#000000'}, 'normal':False},
- 91: {'description':'Set foreground color to Red', 'attributes': {'ctermfg':'9','guifg':'#ff0000'}, 'normal':False},
- 92: {'description':'Set foreground color to Green', 'attributes': {'ctermfg':'10','guifg':'#00ff00'}, 'normal':False},
- 93: {'description':'Set foreground color to Yellow', 'attributes': {'ctermfg':'11','guifg':'#ffff00'}, 'normal':False},
- 94: {'description':'Set foreground color to Blue', 'attributes': {'ctermfg':'12','guifg':'#0000ff'}, 'normal':False},
- 95: {'description':'Set foreground color to Magenta', 'attributes': {'ctermfg':'13','guifg':'#990099'}, 'normal':False},
- 96: {'description':'Set foreground color to Cyan', 'attributes': {'ctermfg':'14','guifg':'#009999'}, 'normal':False},
- 97: {'description':'Set foreground color to White', 'attributes': {'ctermfg':'15','guifg':'#ffffff'}, 'normal':False},
- 100: {'description':'Set background color to Black', 'attributes': {'ctermbg':'8','guibg':'#000000'}, 'normal':False},
- 101: {'description':'Set background color to Red', 'attributes': {'ctermbg':'9','guibg':'#ff0000'}, 'normal':False},
- 102: {'description':'Set background color to Green', 'attributes': {'ctermbg':'10','guibg':'#00ff00'}, 'normal':False},
- 103: {'description':'Set background color to Yellow', 'attributes': {'ctermbg':'11','guibg':'#ffff00'}, 'normal':False},
- 104: {'description':'Set background color to Blue', 'attributes': {'ctermbg':'12','guibg':'#0000ff'}, 'normal':False},
- 105: {'description':'Set background color to Magenta', 'attributes': {'ctermbg':'13','guibg':'#990099'}, 'normal':False},
- 106: {'description':'Set background color to Cyan', 'attributes': {'ctermbg':'14','guibg':'#009999'}, 'normal':False},
- 107: {'description':'Set background color to White', 'attributes': {'ctermbg':'15','guibg':'#ffffff'}, 'normal':False}
-}
-# }}}
-
-# regular expression matching (almost) all control sequences
-CONQUE_SEQ_REGEX = re.compile(ur"(\u001b\[?\??#?[0-9;]*[a-zA-Z@]|\u001b\][0-9];.*?\u0007|[\u0007-\u000f])", re.UNICODE)
-CONQUE_SEQ_REGEX_CTL = re.compile(ur"^[\u0007-\u000f]$", re.UNICODE)
-CONQUE_SEQ_REGEX_CSI = re.compile(ur"^\u001b\[", re.UNICODE)
-CONQUE_SEQ_REGEX_TITLE = re.compile(ur"^\u001b\]", re.UNICODE)
-CONQUE_SEQ_REGEX_HASH = re.compile(ur"^\u001b#", re.UNICODE)
-CONQUE_SEQ_REGEX_ESC = re.compile(ur"^\u001b", re.UNICODE)
-
-# match table output
-CONQUE_TABLE_OUTPUT = re.compile("^\s*\|\s.*\s\|\s*$|^\s*\+[=+-]+\+\s*$")
-
-# }}}
-
-###################################################################################################
-class Conque:
-
- # CLASS PROPERTIES {{{
-
- # screen object
- screen = None
-
- # subprocess object
- proc = None
-
- # terminal dimensions and scrolling region
- columns = 80 # same as $COLUMNS
- lines = 24 # same as $LINES
- working_columns = 80 # can be changed by CSI ? 3 l/h
- working_lines = 24 # can be changed by CSI r
-
- # top/bottom of the scroll region
- top = 1 # relative to top of screen
- bottom = 24 # relative to top of screen
-
- # cursor position
- l = 1 # current cursor line
- c = 1 # current cursor column
-
- # autowrap mode
- autowrap = True
-
- # absolute coordinate mode
- absolute_coords = True
-
- # tabstop positions
- tabstops = []
-
- # enable colors
- enable_colors = True
-
- # color changes
- color_changes = {}
-
- # color history
- color_history = {}
-
- # don't wrap table output
- unwrap_tables = True
-
- # wrap CUF/CUB around line breaks
- wrap_cursor = False
-
- # }}}
-
- # constructor
- def __init__(self): # {{{
- self.screen = ConqueScreen()
- # }}}
-
- # start program and initialize this instance
- def open(self, command, options): # {{{
-
- # int vars
- self.columns = vim.current.window.width
- self.lines = vim.current.window.height
- self.working_columns = vim.current.window.width
- self.working_lines = vim.current.window.height
- self.bottom = vim.current.window.height
-
- # init color
- self.enable_colors = options['color']
-
- # init tabstops
- self.init_tabstops()
-
- # open command
- self.proc = ConqueSubprocess()
- self.proc.open(command, { 'TERM' : options['TERM'], 'CONQUE' : '1', 'LINES' : str(self.lines), 'COLUMNS' : str(self.columns)})
- # }}}
-
- # write to pty
- def write(self, input): # {{{
-
-
- # check if window size has changed
- self.update_window_size()
-
- # write and read
- self.proc.write(input)
- self.read(1)
- # }}}
-
- # read from pty, and update buffer
- def read(self, timeout = 1): # {{{
- # read from subprocess
- output = self.proc.read(timeout)
- # and strip null chars
- output = output.replace(chr(0), '')
-
- if output == '':
- return
-
-
-
-
-
- chunks = CONQUE_SEQ_REGEX.split(output)
-
-
-
-
-
- # don't go through all the csi regex if length is one (no matches)
- if len(chunks) == 1:
-
- self.plain_text(chunks[0])
-
- else:
- for s in chunks:
- if s == '':
- continue
-
-
-
-
-
-
- # Check for control character match {{{
- if CONQUE_SEQ_REGEX_CTL.match(s[0]):
-
- nr = ord(s[0])
- if nr in CONQUE_CTL:
- getattr(self, 'ctl_' + CONQUE_CTL[nr])()
- else:
-
- pass
- # }}}
-
- # check for escape sequence match {{{
- elif CONQUE_SEQ_REGEX_CSI.match(s):
-
- if s[-1] in CONQUE_ESCAPE:
- csi = self.parse_csi(s[2:])
-
- getattr(self, 'csi_' + CONQUE_ESCAPE[s[-1]])(csi)
- else:
-
- pass
- # }}}
-
- # check for title match {{{
- elif CONQUE_SEQ_REGEX_TITLE.match(s):
-
- self.change_title(s[2], s[4:-1])
- # }}}
-
- # check for hash match {{{
- elif CONQUE_SEQ_REGEX_HASH.match(s):
-
- if s[-1] in CONQUE_ESCAPE_HASH:
- getattr(self, 'hash_' + CONQUE_ESCAPE_HASH[s[-1]])()
- else:
-
- pass
- # }}}
-
- # check for other escape match {{{
- elif CONQUE_SEQ_REGEX_ESC.match(s):
-
- if s[-1] in CONQUE_ESCAPE_PLAIN:
- getattr(self, 'esc_' + CONQUE_ESCAPE_PLAIN[s[-1]])()
- else:
-
- pass
- # }}}
-
- # else process plain text {{{
- else:
- self.plain_text(s)
- # }}}
-
- # set cursor position
- self.screen.set_cursor(self.l, self.c)
-
- vim.command('redraw')
-
-
- # }}}
-
- # for polling
- def auto_read(self): # {{{
- self.read(1)
- if self.c == 1:
- vim.command('call feedkeys("\<F23>", "t")')
- else:
- vim.command('call feedkeys("\<F22>", "t")')
- self.screen.set_cursor(self.l, self.c)
- # }}}
-
- ###############################################################################################
- # Plain text # {{{
-
- def plain_text(self, input):
-
- current_line = self.screen[self.l]
-
- if len(current_line) < self.working_columns:
- current_line = current_line + ' ' * (self.c - len(current_line))
-
- # if line is wider than screen
- if self.c + len(input) - 1 > self.working_columns:
- # Table formatting hack
- if self.unwrap_tables and CONQUE_TABLE_OUTPUT.match(input):
- self.screen[self.l] = current_line[ : self.c - 1] + input + current_line[ self.c + len(input) - 1 : ]
- self.apply_color(self.c, self.c + len(input))
- self.c += len(input)
- return
-
- diff = self.c + len(input) - self.working_columns - 1
- # if autowrap is enabled
- if self.autowrap:
- self.screen[self.l] = current_line[ : self.c - 1] + input[ : -1 * diff ]
- self.apply_color(self.c, self.working_columns)
- self.ctl_nl()
- self.ctl_cr()
- remaining = input[ -1 * diff : ]
-
- self.plain_text(remaining)
- else:
- self.screen[self.l] = current_line[ : self.c - 1] + input[ : -1 * diff - 1 ] + input[-1]
- self.apply_color(self.c, self.working_columns)
- self.c = self.working_columns
-
- # no autowrap
- else:
- self.screen[self.l] = current_line[ : self.c - 1] + input + current_line[ self.c + len(input) - 1 : ]
- self.apply_color(self.c, self.c + len(input))
- self.c += len(input)
-
- def apply_color(self, start, end):
-
-
- # stop here if coloration is disabled
- if not self.enable_colors:
- return
-
- real_line = self.screen.get_real_line(self.l)
-
- # check for previous overlapping coloration
-
- to_del = []
- if self.color_history.has_key(real_line):
- for i in range(len(self.color_history[real_line])):
- syn = self.color_history[real_line][i]
-
- if syn['start'] >= start and syn['start'] < end:
-
- vim.command('syn clear ' + syn['name'])
- to_del.append(i)
- # outside
- if syn['end'] > end:
-
- self.exec_highlight(real_line, end, syn['end'], syn['highlight'])
- elif syn['end'] > start and syn['end'] <= end:
-
- vim.command('syn clear ' + syn['name'])
- to_del.append(i)
- # outside
- if syn['start'] < start:
-
- self.exec_highlight(real_line, syn['start'], start, syn['highlight'])
-
- if len(to_del) > 0:
- to_del.reverse()
- for di in to_del:
- del self.color_history[real_line][di]
-
- # if there are no new colors
- if len(self.color_changes) == 0:
- return
-
- highlight = ''
- for attr in self.color_changes.keys():
- highlight = highlight + ' ' + attr + '=' + self.color_changes[attr]
-
- # execute the highlight
- self.exec_highlight(real_line, start, end, highlight)
-
- def exec_highlight(self, real_line, start, end, highlight):
- unique_key = str(self.proc.pid)
-
- syntax_name = 'EscapeSequenceAt_' + unique_key + '_' + str(self.l) + '_' + str(start) + '_' + str(len(self.color_history) + 1)
- syntax_options = ' contains=ALLBUT,ConqueString,MySQLString,MySQLKeyword oneline'
- syntax_region = 'syntax match ' + syntax_name + ' /\%' + str(real_line) + 'l\%>' + str(start - 1) + 'c.*\%<' + str(end + 1) + 'c/' + syntax_options
- syntax_highlight = 'highlight ' + syntax_name + highlight
-
- vim.command(syntax_region)
- vim.command(syntax_highlight)
-
- # add syntax name to history
- if not self.color_history.has_key(real_line):
- self.color_history[real_line] = []
-
- self.color_history[real_line].append({'name':syntax_name, 'start':start, 'end':end, 'highlight':highlight})
-
- # }}}
-
- ###############################################################################################
- # Control functions {{{
-
- def ctl_nl(self):
- # if we're in a scrolling region, scroll instead of moving cursor down
- if self.lines != self.working_lines and self.l == self.bottom:
- del self.screen[self.top]
- self.screen.insert(self.bottom, '')
- elif self.l == self.bottom:
- self.screen.append('')
- else:
- self.l += 1
-
- self.color_changes = {}
-
- def ctl_cr(self):
- self.c = 1
-
- self.color_changes = {}
-
- def ctl_bs(self):
- if self.c > 1:
- self.c += -1
-
- def ctl_bel(self):
- print 'BELL'
-
- def ctl_tab(self):
- # default tabstop location
- ts = self.working_columns
-
- # check set tabstops
- for i in range(self.c, len(self.tabstops)):
- if self.tabstops[i]:
- ts = i + 1
- break
-
-
-
- self.c = ts
-
- # }}}
-
- ###############################################################################################
- # CSI functions {{{
-
- def csi_font(self, csi): # {{{
- if not self.enable_colors:
- return
-
- # defaults to 0
- if len(csi['vals']) == 0:
- csi['vals'] = [0]
-
- # 256 xterm color foreground
- if len(csi['vals']) == 3 and csi['vals'][0] == 38 and csi['vals'][1] == 5:
- self.color_changes['ctermfg'] = str(csi['vals'][2])
- self.color_changes['guifg'] = '#' + self.xterm_to_rgb(csi['vals'][2])
-
- # 256 xterm color background
- elif len(csi['vals']) == 3 and csi['vals'][0] == 48 and csi['vals'][1] == 5:
- self.color_changes['ctermbg'] = str(csi['vals'][2])
- self.color_changes['guibg'] = '#' + self.xterm_to_rgb(csi['vals'][2])
-
- # 16 colors
- else:
- for val in csi['vals']:
- if CONQUE_FONT.has_key(val):
-
- # ignore starting normal colors
- if CONQUE_FONT[val]['normal'] and len(self.color_changes) == 0:
-
- continue
- # clear color changes
- elif CONQUE_FONT[val]['normal']:
-
- self.color_changes = {}
- # save these color attributes for next plain_text() call
- else:
-
- for attr in CONQUE_FONT[val]['attributes'].keys():
- if self.color_changes.has_key(attr) and (attr == 'cterm' or attr == 'gui'):
- self.color_changes[attr] += ',' + CONQUE_FONT[val]['attributes'][attr]
- else:
- self.color_changes[attr] = CONQUE_FONT[val]['attributes'][attr]
- # }}}
-
- def csi_clear_line(self, csi): # {{{
-
-
- # this escape defaults to 0
- if len(csi['vals']) == 0:
- csi['val'] = 0
-
-
-
-
- # 0 means cursor right
- if csi['val'] == 0:
- self.screen[self.l] = self.screen[self.l][0 : self.c - 1]
-
- # 1 means cursor left
- elif csi['val'] == 1:
- self.screen[self.l] = ' ' * (self.c) + self.screen[self.l][self.c : ]
-
- # clear entire line
- elif csi['val'] == 2:
- self.screen[self.l] = ''
-
- # clear colors
- if csi['val'] == 2 or (csi['val'] == 0 and self.c == 1):
- real_line = self.screen.get_real_line(self.l)
- if self.color_history.has_key(real_line):
- for syn in self.color_history[real_line]:
- vim.command('syn clear ' + syn['name'])
-
-
-
- # }}}
-
- def csi_cursor_right(self, csi): # {{{
- # we use 1 even if escape explicitly specifies 0
- if csi['val'] == 0:
- csi['val'] = 1
-
-
-
-
- if self.wrap_cursor and self.c + csi['val'] > self.working_columns:
- self.l += int(math.floor( (self.c + csi['val']) / self.working_columns ))
- self.c = (self.c + csi['val']) % self.working_columns
- return
-
- self.c = self.bound(self.c + csi['val'], 1, self.working_columns)
- # }}}
-
- def csi_cursor_left(self, csi): # {{{
- # we use 1 even if escape explicitly specifies 0
- if csi['val'] == 0:
- csi['val'] = 1
-
- if self.wrap_cursor and csi['val'] >= self.c:
- self.l += int(math.floor( (self.c - csi['val']) / self.working_columns ))
- self.c = self.working_columns - (csi['val'] - self.c) % self.working_columns
- return
-
- self.c = self.bound(self.c - csi['val'], 1, self.working_columns)
- # }}}
-
- def csi_cursor_to_column(self, csi): # {{{
- self.c = self.bound(csi['val'], 1, self.working_columns)
- # }}}
-
- def csi_cursor_up(self, csi): # {{{
- self.l = self.bound(self.l - csi['val'], self.top, self.bottom)
-
- self.color_changes = {}
- # }}}
-
- def csi_cursor_down(self, csi): # {{{
- self.l = self.bound(self.l + csi['val'], self.top, self.bottom)
-
- self.color_changes = {}
- # }}}
-
- def csi_clear_screen(self, csi): # {{{
- # default to 0
- if len(csi['vals']) == 0:
- csi['val'] = 0
-
- # 2 == clear entire screen
- if csi['val'] == 2:
- self.l = 1
- self.c = 1
- self.screen.clear()
-
- # 0 == clear down
- elif csi['val'] == 0:
- for l in range(self.bound(self.l + 1, 1, self.lines), self.lines + 1):
- self.screen[l] = ''
-
- # clear end of current line
- self.csi_clear_line(self.parse_csi('K'))
-
- # 1 == clear up
- elif csi['val'] == 1:
- for l in range(1, self.bound(self.l, 1, self.lines + 1)):
- self.screen[l] = ''
-
- # clear beginning of current line
- self.csi_clear_line(self.parse_csi('1K'))
-
- # clear coloration
- if csi['val'] == 2 or csi['val'] == 0:
- real_line = self.screen.get_real_line(self.l)
- for line in self.color_history.keys():
- if line >= real_line:
- for syn in self.color_history[line]:
- vim.command('syn clear ' + syn['name'])
-
- self.color_changes = {}
- # }}}
-
- def csi_delete_chars(self, csi): # {{{
- self.screen[self.l] = self.screen[self.l][ : self.c ] + self.screen[self.l][ self.c + csi['val'] : ]
- # }}}
-
- def csi_add_spaces(self, csi): # {{{
- self.screen[self.l] = self.screen[self.l][ : self.c - 1] + ' ' * csi['val'] + self.screen[self.l][self.c : ]
- # }}}
-
- def csi_cursor(self, csi): # {{{
- if len(csi['vals']) == 2:
- new_line = csi['vals'][0]
- new_col = csi['vals'][1]
- else:
- new_line = 1
- new_col = 1
-
- if self.absolute_coords:
- self.l = self.bound(new_line, 1, self.lines)
- else:
- self.l = self.bound(self.top + new_line - 1, self.top, self.bottom)
-
- self.c = self.bound(new_col, 1, self.working_columns)
- if self.c > len(self.screen[self.l]):
- self.screen[self.l] = self.screen[self.l] + ' ' * (self.c - len(self.screen[self.l]))
-
- # }}}
-
- def csi_set_coords(self, csi): # {{{
- if len(csi['vals']) == 2:
- new_start = csi['vals'][0]
- new_end = csi['vals'][1]
- else:
- new_start = 1
- new_end = vim.current.window.height
-
- self.top = new_start
- self.bottom = new_end
- self.working_lines = new_end - new_start + 1
-
- # if cursor is outside scrolling region, reset it
- if self.l < self.top:
- self.l = self.top
- elif self.l > self.bottom:
- self.l = self.bottom
-
- self.color_changes = {}
- # }}}
-
- def csi_tab_clear(self, csi): # {{{
- # this escape defaults to 0
- if len(csi['vals']) == 0:
- csi['val'] = 0
-
-
-
- if csi['val'] == 0:
- self.tabstops[self.c - 1] = False
- elif csi['val'] == 3:
- for i in range(0, self.columns + 1):
- self.tabstops[i] = False
- # }}}
-
- def csi_set(self, csi): # {{{
- # 132 cols
- if csi['val'] == 3:
- self.csi_clear_screen(self.parse_csi('2J'))
- self.working_columns = 132
-
- # relative_origin
- elif csi['val'] == 6:
- self.absolute_coords = False
-
- # set auto wrap
- elif csi['val'] == 7:
- self.autowrap = True
-
-
- self.color_changes = {}
- # }}}
-
- def csi_reset(self, csi): # {{{
- # 80 cols
- if csi['val'] == 3:
- self.csi_clear_screen(self.parse_csi('2J'))
- self.working_columns = 80
-
- # absolute origin
- elif csi['val'] == 6:
- self.absolute_coords = True
-
- # reset auto wrap
- elif csi['val'] == 7:
- self.autowrap = False
-
-
- self.color_changes = {}
- # }}}
-
- # }}}
-
- ###############################################################################################
- # ESC functions {{{
-
- def esc_scroll_up(self): # {{{
- self.ctl_nl()
-
- self.color_changes = {}
- # }}}
-
- def esc_next_line(self): # {{{
- self.ctl_nl()
- self.c = 1
- # }}}
-
- def esc_set_tab(self): # {{{
-
- if self.c <= len(self.tabstops):
- self.tabstops[self.c - 1] = True
- # }}}
-
- def esc_scroll_down(self): # {{{
- if self.l == self.top:
- del self.screen[self.bottom]
- self.screen.insert(self.top, '')
- else:
- self.l += -1
-
- self.color_changes = {}
- # }}}
-
- # }}}
-
- ###############################################################################################
- # HASH functions {{{
-
- def hash_screen_alignment_test(self): # {{{
- self.csi_clear_screen(self.parse_csi('2J'))
- self.working_lines = self.lines
- for l in range(1, self.lines + 1):
- self.screen[l] = 'E' * self.working_columns
- # }}}
-
- # }}}
-
- ###############################################################################################
- # Random stuff {{{
-
- def change_title(self, key, val):
-
-
- if key == '0' or key == '2':
-
- vim.command('setlocal statusline=' + re.escape(val))
-
- def paste(self):
- self.write(vim.eval('@@'))
- self.read(50)
-
- def paste_selection(self):
- self.write(vim.eval('@@'))
-
- def update_window_size(self):
- # resize if needed
- if vim.current.window.width != self.columns or vim.current.window.height != self.lines:
-
- # reset all window size attributes to default
- self.columns = vim.current.window.width
- self.lines = vim.current.window.height
- self.working_columns = vim.current.window.width
- self.working_lines = vim.current.window.height
- self.bottom = vim.current.window.height
-
- # reset screen object attributes
- self.l = self.screen.reset_size(self.l)
-
- # reset tabstops
- self.init_tabstops()
-
-
-
- # signal process that screen size has changed
- self.proc.window_resize(self.lines, self.columns)
-
- def init_tabstops(self):
- for i in range(0, self.columns + 1):
- if i % 8 == 0:
- self.tabstops.append(True)
- else:
- self.tabstops.append(False)
-
- # }}}
-
- ###############################################################################################
- # Utility {{{
-
- def parse_csi(self, s): # {{{
- attr = { 'key' : s[-1], 'flag' : '', 'val' : 1, 'vals' : [] }
-
- if len(s) == 1:
- return attr
-
- full = s[0:-1]
-
- if full[0] == '?':
- full = full[1:]
- attr['flag'] = '?'
-
- if full != '':
- vals = full.split(';')
- for val in vals:
-
- val = re.sub("\D", "", val)
-
- if val != '':
- attr['vals'].append(int(val))
-
- if len(attr['vals']) == 1:
- attr['val'] = int(attr['vals'][0])
-
- return attr
- # }}}
-
- def bound(self, val, min, max): # {{{
- if val > max:
- return max
-
- if val < min:
- return min
-
- return val
- # }}}
-
- def xterm_to_rgb(self, color_code): # {{{
- if color_code < 16:
- ascii_colors = ['000000', 'CD0000', '00CD00', 'CDCD00', '0000EE', 'CD00CD', '00CDCD', 'E5E5E5',
- '7F7F7F', 'FF0000', '00FF00', 'FFFF00', '5C5CFF', 'FF00FF', '00FFFF', 'FFFFFF']
- return ascii_colors[color_code]
-
- elif color_code < 232:
- cc = int(color_code) - 16
-
- p1 = "%02x" % (math.floor(cc / 36) * (255/5))
- p2 = "%02x" % (math.floor((cc % 36) / 6) * (255/5))
- p3 = "%02x" % (math.floor(cc % 6) * (255/5))
-
- return p1 + p2 + p3
- else:
- grey_tone = "%02x" % math.floor((255/24) * (color_code - 232))
- return grey_tone + grey_tone + grey_tone
- # }}}
-
- # }}}
-
-
-import os, signal, pty, tty, select, fcntl, termios, struct
-
-###################################################################################################
-class ConqueSubprocess:
-
- # process id
- pid = 0
-
- # stdout+stderr file descriptor
- fd = None
-
- # constructor
- def __init__(self): # {{{
- self.pid = 0
- # }}}
-
- # create the pty or whatever (whatever == windows)
- def open(self, command, env = {}): # {{{
- command_arr = command.split()
- executable = command_arr[0]
- args = command_arr
-
- try:
- self.pid, self.fd = pty.fork()
-
- except:
- pass
-
-
- # child proc, replace with command after altering terminal attributes
- if self.pid == 0:
-
- # set requested environment variables
- for k in env.keys():
- os.environ[k] = env[k]
-
- # set some attributes
- try:
- attrs = tty.tcgetattr(1)
- attrs[0] = attrs[0] ^ tty.IGNBRK
- attrs[0] = attrs[0] | tty.BRKINT | tty.IXANY | tty.IMAXBEL
- attrs[2] = attrs[2] | tty.HUPCL
- attrs[3] = attrs[3] | tty.ICANON | tty.ECHO | tty.ISIG | tty.ECHOKE
- attrs[6][tty.VMIN] = 1
- attrs[6][tty.VTIME] = 0
- tty.tcsetattr(1, tty.TCSANOW, attrs)
- except:
- pass
-
- os.execvp(executable, args)
-
- # else master, do nothing
- else:
- pass
-
- # }}}
-
- # read from pty
- # XXX - select.poll() doesn't work in OS X!!!!!!!
- def read(self, timeout = 1): # {{{
-
- output = ''
- read_timeout = float(timeout) / 1000
-
- try:
- # what, no do/while?
- while 1:
- s_read, s_write, s_error = select.select( [ self.fd ], [], [], read_timeout)
-
- lines = ''
- for s_fd in s_read:
- try:
- lines = os.read( self.fd, 32 )
- except:
- pass
- output = output + lines
-
- if lines == '':
- break
- except:
- pass
-
- return output
- # }}}
-
- # I guess this one's not bad
- def write(self, input): # {{{
- try:
- os.write(self.fd, input)
- except:
- pass
- # }}}
-
- # signal process
- def signal(self, signum): # {{{
- try:
- os.kill(self.pid, signum)
- except:
- pass
- # }}}
-
- # get process status
- def get_status(self): #{{{
-
- p_status = True
-
- try:
- if os.waitpid( self.pid, os.WNOHANG )[0]:
- p_status = False
- except:
- p_status = False
-
- return p_status
-
- # }}}
-
- # update window size in kernel, then send SIGWINCH to fg process
- def window_resize(self, lines, columns): # {{{
- try:
- fcntl.ioctl(self.fd, termios.TIOCSWINSZ, struct.pack("HHHH", lines, columns, 0, 0))
- os.kill(self.pid, signal.SIGWINCH)
- except:
- pass
-
- # }}}
-
-
-###################################################################################################
-# ConqueScreen is an extention of the vim.current.buffer object
-# It restricts the working indices of the buffer object to the scroll region which pty is expecting
-# It also uses 1-based indexes, to match escape sequence commands
-#
-# E.g.:
-# s = ConqueScreen()
-# ...
-# s[5] = 'Set 5th line in terminal to this line'
-# s.append('Add new line to terminal')
-# s[5] = 'Since previous append() command scrolled the terminal down, this is a different line than first cb[5] call'
-#
-
-import vim
-
-class ConqueScreen(object):
-
- # CLASS PROPERTIES {{{
-
- # the buffer
- buffer = None
-
- # screen and scrolling regions
- screen_top = 1
-
- # screen width
- screen_width = 80
- screen_height = 80
-
- # }}}
-
- def __init__(self): # {{{
- self.buffer = vim.current.buffer
-
- self.screen_top = 1
- self.screen_width = vim.current.window.width
- self.screen_height = vim.current.window.height
- # }}}
-
- ###############################################################################################
- # List overload {{{
- def __len__(self): # {{{
- return len(self.buffer)
- # }}}
-
- def __getitem__(self, key): # {{{
- real_line = self.get_real_idx(key)
-
- # if line is past buffer end, add lines to buffer
- if real_line >= len(self.buffer):
- for i in range(len(self.buffer), real_line + 1):
- self.append(' ' * self.screen_width)
-
- return self.buffer[ real_line ]
- # }}}
-
- def __setitem__(self, key, value): # {{{
- real_line = self.get_real_idx(key)
-
- # if line is past end of screen, append
- if real_line == len(self.buffer):
- self.buffer.append(value)
- else:
- self.buffer[ real_line ] = value
- # }}}
-
- def __delitem__(self, key): # {{{
- del self.buffer[ self.screen_top + key - 2 ]
- # }}}
-
- def append(self, value): # {{{
- if len(self.buffer) > self.screen_top + self.screen_height - 1:
- self.buffer[len(self.buffer) - 1] = value
- else:
- self.buffer.append(value)
-
- if len(self.buffer) > self.screen_top + self.screen_height - 1:
- self.screen_top += 1
- if vim.current.buffer.number == self.buffer.number:
- vim.command('normal G')
- # }}}
-
- def insert(self, line, value): # {{{
-
- l = self.screen_top + line - 2
- self.buffer[l:l] = [ value ]
-
- # }}}
- # }}}
-
- ###############################################################################################
- # Util {{{
- def get_top(self): # {{{
- return self.screen_top
- # }}}
-
- def get_real_idx(self, line): # {{{
- return (self.screen_top + line - 2)
- # }}}
-
- def get_real_line(self, line): # {{{
- return (self.screen_top + line - 1)
- # }}}
-
- def set_screen_width(self, width): # {{{
- self.screen_width = width
- # }}}
-
- # }}}
-
- ###############################################################################################
- def clear(self): # {{{
- self.buffer.append(' ')
- vim.command('normal Gzt')
- self.screen_top = len(self.buffer)
- # }}}
-
- def set_cursor(self, line, column): # {{{
- # figure out line
- real_line = self.screen_top + line - 1
- if real_line > len(self.buffer):
- for l in range(len(self.buffer) - 1, real_line):
- self.buffer.append('')
-
- # figure out column
- real_column = column
- if len(self.buffer[real_line - 1]) < real_column:
- self.buffer[real_line - 1] = self.buffer[real_line - 1] + ' ' * (real_column - len(self.buffer[real_line - 1]))
-
- # python version is occasionally grumpy
- try:
- vim.current.window.cursor = (real_line, real_column - 1)
- except:
- vim.command('call cursor(' + str(real_line) + ', ' + str(real_column) + ')')
- # }}}
-
- def reset_size(self, line): # {{{
-
-
-
-
- # save cursor line number
- real_line = self.screen_top + line
-
- # reset screen size
- self.screen_width = vim.current.window.width
- self.screen_height = vim.current.window.height
- self.screen_top = len(self.buffer) - vim.current.window.height + 1
- if self.screen_top < 1:
- self.screen_top = 1
-
-
- # align bottom of buffer to bottom of screen
- vim.command('normal ' + str(self.screen_height) + 'kG')
-
- # return new relative line number
- return (real_line - self.screen_top)
- # }}}
-
- def scroll_to_bottom(self): # {{{
- vim.current.window.cursor = (len(self.buffer) - 1, 1)
- # }}}
-
- def align(self): # {{{
- # align bottom of buffer to bottom of screen
- vim.command('normal ' + str(self.screen_height) + 'kG')
- # }}}
-
-
-EOF
-
-endif
-
diff --git a/vim/autoload/rails.vim b/vim/autoload/rails.vim
deleted file mode 100644
index ca36075..0000000
--- a/vim/autoload/rails.vim
+++ /dev/null
@@ -1,4560 +0,0 @@
-" autoload/rails.vim
-" Author: Tim Pope <http://tpo.pe/>
-
-" Install this file as autoload/rails.vim.
-
-if exists('g:autoloaded_rails') || &cp
- finish
-endif
-let g:autoloaded_rails = '4.4'
-
-let s:cpo_save = &cpo
-set cpo&vim
-
-" Utility Functions {{{1
-
-let s:app_prototype = {}
-let s:file_prototype = {}
-let s:buffer_prototype = {}
-let s:readable_prototype = {}
-
-function! s:add_methods(namespace, method_names)
- for name in a:method_names
- let s:{a:namespace}_prototype[name] = s:function('s:'.a:namespace.'_'.name)
- endfor
-endfunction
-
-function! s:function(name)
- return function(substitute(a:name,'^s:',matchstr(expand('<sfile>'), '<SNR>\d\+_'),''))
-endfunction
-
-function! s:sub(str,pat,rep)
- return substitute(a:str,'\v\C'.a:pat,a:rep,'')
-endfunction
-
-function! s:gsub(str,pat,rep)
- return substitute(a:str,'\v\C'.a:pat,a:rep,'g')
-endfunction
-
-function! s:startswith(string,prefix)
- return strpart(a:string, 0, strlen(a:prefix)) ==# a:prefix
-endfunction
-
-function! s:compact(ary)
- return s:sub(s:sub(s:gsub(a:ary,'\n\n+','\n'),'\n$',''),'^\n','')
-endfunction
-
-function! s:uniq(list)
- let seen = {}
- let i = 0
- while i < len(a:list)
- if has_key(seen,a:list[i])
- call remove(a:list, i)
- else
- let seen[a:list[i]] = 1
- let i += 1
- endif
- endwhile
- return a:list
-endfunction
-
-function! s:scrub(collection,item)
- " Removes item from a newline separated collection
- let col = "\n" . a:collection
- let idx = stridx(col,"\n".a:item."\n")
- let cnt = 0
- while idx != -1 && cnt < 100
- let col = strpart(col,0,idx).strpart(col,idx+strlen(a:item)+1)
- let idx = stridx(col,"\n".a:item."\n")
- let cnt += 1
- endwhile
- return strpart(col,1)
-endfunction
-
-function! s:escarg(p)
- return s:gsub(a:p,'[ !%#]','\\&')
-endfunction
-
-function! s:esccmd(p)
- return s:gsub(a:p,'[!%#]','\\&')
-endfunction
-
-function! s:rquote(str)
- " Imperfect but adequate for Ruby arguments
- if a:str =~ '^[A-Za-z0-9_/.:-]\+$'
- return a:str
- elseif &shell =~? 'cmd'
- return '"'.s:gsub(s:gsub(a:str,'\','\\'),'"','\\"').'"'
- else
- return "'".s:gsub(s:gsub(a:str,'\','\\'),"'","'\\\\''")."'"
- endif
-endfunction
-
-function! s:sname()
- return fnamemodify(s:file,':t:r')
-endfunction
-
-function! s:pop_command()
- if exists("s:command_stack") && len(s:command_stack) > 0
- exe remove(s:command_stack,-1)
- endif
-endfunction
-
-function! s:push_chdir(...)
- if !exists("s:command_stack") | let s:command_stack = [] | endif
- if exists("b:rails_root") && (a:0 ? getcwd() !=# rails#app().path() : !s:startswith(getcwd(), rails#app().path()))
- let chdir = exists("*haslocaldir") && haslocaldir() ? "lchdir " : "chdir "
- call add(s:command_stack,chdir.s:escarg(getcwd()))
- exe chdir.s:escarg(rails#app().path())
- else
- call add(s:command_stack,"")
- endif
-endfunction
-
-function! s:app_path(...) dict
- return join([self.root]+a:000,'/')
-endfunction
-
-function! s:app_has_file(file) dict
- return filereadable(self.path(a:file))
-endfunction
-
-function! s:app_find_file(name, ...) dict abort
- let trim = strlen(self.path())+1
- if a:0
- let path = s:pathjoin(map(s:pathsplit(a:1),'self.path(v:val)'))
- else
- let path = s:pathjoin([self.path()])
- endif
- let suffixesadd = s:pathjoin(get(a:000,1,&suffixesadd))
- let default = get(a:000,2,'')
- let oldsuffixesadd = &l:suffixesadd
- try
- let &suffixesadd = suffixesadd
- " Versions before 7.1.256 returned directories from findfile
- if type(default) == type(0) && (v:version < 702 || default == -1)
- let all = findfile(a:name,path,-1)
- if v:version < 702
- call filter(all,'!isdirectory(v:val)')
- endif
- call map(all,'s:gsub(strpart(fnamemodify(v:val,":p"),trim),"\\\\","/")')
- return default < 0 ? all : get(all,default-1,'')
- elseif type(default) == type(0)
- let found = findfile(a:name,path,default)
- else
- let i = 1
- let found = findfile(a:name,path)
- while v:version < 702 && found != "" && isdirectory(found)
- let i += 1
- let found = findfile(a:name,path,i)
- endwhile
- endif
- return found == "" ? default : s:gsub(strpart(fnamemodify(found,':p'),trim),'\\','/')
- finally
- let &l:suffixesadd = oldsuffixesadd
- endtry
-endfunction
-
-call s:add_methods('app',['path','has_file','find_file'])
-
-" Split a path into a list. From pathogen.vim
-function! s:pathsplit(path) abort
- if type(a:path) == type([]) | return copy(a:path) | endif
- let split = split(a:path,'\\\@<!\%(\\\\\)*\zs,')
- return map(split,'substitute(v:val,''\\\([\\, ]\)'',''\1'',"g")')
-endfunction
-
-" Convert a list to a path. From pathogen.vim
-function! s:pathjoin(...) abort
- let i = 0
- let path = ""
- while i < a:0
- if type(a:000[i]) == type([])
- let list = a:000[i]
- let j = 0
- while j < len(list)
- let escaped = substitute(list[j],'[\\, ]','\\&','g')
- if exists("+shellslash") && !&shellslash
- let escaped = substitute(escaped,'^\(\w:\\\)\\','\1','')
- endif
- let path .= ',' . escaped
- let j += 1
- endwhile
- else
- let path .= "," . a:000[i]
- endif
- let i += 1
- endwhile
- return substitute(path,'^,','','')
-endfunction
-
-function! s:readable_end_of(lnum) dict abort
- if a:lnum == 0
- return 0
- endif
- if self.name() =~# '\.yml$'
- return -1
- endif
- let cline = self.getline(a:lnum)
- let spc = matchstr(cline,'^\s*')
- let endpat = '\<end\>'
- if matchstr(self.getline(a:lnum+1),'^'.spc) && !matchstr(self.getline(a:lnum+1),'^'.spc.endpat) && matchstr(cline,endpat)
- return a:lnum
- endif
- let endl = a:lnum
- while endl <= self.line_count()
- let endl += 1
- if self.getline(endl) =~ '^'.spc.endpat
- return endl
- elseif self.getline(endl) =~ '^=begin\>'
- while self.getline(endl) !~ '^=end\>' && endl <= self.line_count()
- let endl += 1
- endwhile
- let endl += 1
- elseif self.getline(endl) !~ '^'.spc && self.getline(endl) !~ '^\s*\%(#.*\)\=$'
- return 0
- endif
- endwhile
- return 0
-endfunction
-
-function! s:endof(lnum)
- return rails#buffer().end_of(a:lnum)
-endfunction
-
-function! s:readable_last_opening_line(start,pattern,limit) dict abort
- let line = a:start
- while line > a:limit && self.getline(line) !~ a:pattern
- let line -= 1
- endwhile
- let lend = self.end_of(line)
- if line > a:limit && (lend < 0 || lend >= a:start)
- return line
- else
- return -1
- endif
-endfunction
-
-function! s:lastopeningline(pattern,limit,start)
- return rails#buffer().last_opening_line(a:start,a:pattern,a:limit)
-endfunction
-
-function! s:readable_define_pattern() dict abort
- if self.name() =~ '\.yml$'
- return '^\%(\h\k*:\)\@='
- endif
- let define = '^\s*def\s\+\(self\.\)\='
- if self.name() =~# '\.rake$'
- let define .= "\\\|^\\s*\\%(task\\\|file\\)\\s\\+[:'\"]"
- endif
- if self.name() =~# '/schema\.rb$'
- let define .= "\\\|^\\s*create_table\\s\\+[:'\"]"
- endif
- if self.type_name('test')
- let define .= '\|^\s*test\s*[''"]'
- endif
- return define
-endfunction
-
-function! s:readable_last_method_line(start) dict abort
- return self.last_opening_line(a:start,self.define_pattern(),0)
-endfunction
-
-function! s:lastmethodline(start)
- return rails#buffer().last_method_line(a:start)
-endfunction
-
-function! s:readable_last_method(start) dict abort
- let lnum = self.last_method_line(a:start)
- let line = self.getline(lnum)
- if line =~# '^\s*test\s*\([''"]\).*\1'
- let string = matchstr(line,'^\s*\w\+\s*\([''"]\)\zs.*\ze\1')
- return 'test_'.s:gsub(string,' +','_')
- elseif lnum
- return s:sub(matchstr(line,'\%('.self.define_pattern().'\)\zs\h\%(\k\|[:.]\)*[?!=]\='),':$','')
- else
- return ""
- endif
-endfunction
-
-function! s:lastmethod(...)
- return rails#buffer().last_method(a:0 ? a:1 : line("."))
-endfunction
-
-function! s:readable_last_format(start) dict abort
- if self.type_name('view')
- let format = fnamemodify(self.path(),':r:e')
- if format == ''
- return get({'rhtml': 'html', 'rxml': 'xml', 'rjs': 'js', 'haml': 'html'},fnamemodify(self.path(),':e'),'')
- else
- return format
- endif
- endif
- let rline = self.last_opening_line(a:start,'\C^\s*\%(mail\>.*\|respond_to\)\s*\%(\<do\|{\)\s*|\zs\h\k*\ze|',self.last_method_line(a:start))
- if rline
- let variable = matchstr(self.getline(rline),'\C^\s*\%(mail\>.*\|respond_to\)\s*\%(\<do\|{\)\s*|\zs\h\k*\ze|')
- let line = a:start
- while line > rline
- let match = matchstr(self.getline(line),'\C^\s*'.variable.'\s*\.\s*\zs\h\k*')
- if match != ''
- return match
- endif
- let line -= 1
- endwhile
- endif
- return ""
-endfunction
-
-function! s:lastformat(start)
- return rails#buffer().last_format(a:start)
-endfunction
-
-function! s:format(...)
- let format = rails#buffer().last_format(a:0 > 1 ? a:2 : line("."))
- return format ==# '' && a:0 ? a:1 : format
-endfunction
-
-call s:add_methods('readable',['end_of','last_opening_line','last_method_line','last_method','last_format','define_pattern'])
-
-let s:view_types = split('rhtml,erb,rxml,builder,rjs,mab,liquid,haml,dryml,mn,slim',',')
-
-function! s:viewspattern()
- return '\%('.join(s:view_types,'\|').'\)'
-endfunction
-
-function! s:controller(...)
- return rails#buffer().controller_name(a:0 ? a:1 : 0)
-endfunction
-
-function! s:readable_controller_name(...) dict abort
- let f = self.name()
- if has_key(self,'getvar') && self.getvar('rails_controller') != ''
- return self.getvar('rails_controller')
- elseif f =~ '\<app/views/layouts/'
- return s:sub(f,'.*<app/views/layouts/(.{-})\..*','\1')
- elseif f =~ '\<app/views/'
- return s:sub(f,'.*<app/views/(.{-})/\k+\.\k+%(\.\k+)=$','\1')
- elseif f =~ '\<app/helpers/.*_helper\.rb$'
- return s:sub(f,'.*<app/helpers/(.{-})_helper\.rb$','\1')
- elseif f =~ '\<app/controllers/.*\.rb$'
- return s:sub(f,'.*<app/controllers/(.{-})%(_controller)=\.rb$','\1')
- elseif f =~ '\<app/mailers/.*\.rb$'
- return s:sub(f,'.*<app/mailers/(.{-})\.rb$','\1')
- elseif f =~ '\<app/apis/.*_api\.rb$'
- return s:sub(f,'.*<app/apis/(.{-})_api\.rb$','\1')
- elseif f =~ '\<test/functional/.*_test\.rb$'
- return s:sub(f,'.*<test/functional/(.{-})%(_controller)=_test\.rb$','\1')
- elseif f =~ '\<test/unit/helpers/.*_helper_test\.rb$'
- return s:sub(f,'.*<test/unit/helpers/(.{-})_helper_test\.rb$','\1')
- elseif f =~ '\<spec/controllers/.*_spec\.rb$'
- return s:sub(f,'.*<spec/controllers/(.{-})%(_controller)=_spec\.rb$','\1')
- elseif f =~ '\<spec/helpers/.*_helper_spec\.rb$'
- return s:sub(f,'.*<spec/helpers/(.{-})_helper_spec\.rb$','\1')
- elseif f =~ '\<spec/views/.*/\w\+_view_spec\.rb$'
- return s:sub(f,'.*<spec/views/(.{-})/\w+_view_spec\.rb$','\1')
- elseif f =~ '\<components/.*_controller\.rb$'
- return s:sub(f,'.*<components/(.{-})_controller\.rb$','\1')
- elseif f =~ '\<components/.*\.'.s:viewspattern().'$'
- return s:sub(f,'.*<components/(.{-})/\k+\.\k+$','\1')
- elseif f =~ '\<app/models/.*\.rb$' && self.type_name('mailer')
- return s:sub(f,'.*<app/models/(.{-})\.rb$','\1')
- elseif f =~ '\<\%(public\|app/assets\)/stylesheets/.*\.css\%(\.\w\+\)\=$'
- return s:sub(f,'.*<%(public|app/assets)/stylesheets/(.{-})\.css%(\.\w+)=$','\1')
- elseif f =~ '\<\%(public\|app/assets\)/javascripts/.*\.js\%(\.\w\+\)\=$'
- return s:sub(f,'.*<%(public|app/assets)/javascripts/(.{-})\.js%(\.\w+)=$','\1')
- elseif a:0 && a:1
- return rails#pluralize(self.model_name())
- endif
- return ""
-endfunction
-
-function! s:model(...)
- return rails#buffer().model_name(a:0 ? a:1 : 0)
-endfunction
-
-function! s:readable_model_name(...) dict abort
- let f = self.name()
- if has_key(self,'getvar') && self.getvar('rails_model') != ''
- return self.getvar('rails_model')
- elseif f =~ '\<app/models/.*_observer.rb$'
- return s:sub(f,'.*<app/models/(.*)_observer\.rb$','\1')
- elseif f =~ '\<app/models/.*\.rb$'
- return s:sub(f,'.*<app/models/(.*)\.rb$','\1')
- elseif f =~ '\<test/unit/.*_observer_test\.rb$'
- return s:sub(f,'.*<test/unit/(.*)_observer_test\.rb$','\1')
- elseif f =~ '\<test/unit/.*_test\.rb$'
- return s:sub(f,'.*<test/unit/(.*)_test\.rb$','\1')
- elseif f =~ '\<spec/models/.*_spec\.rb$'
- return s:sub(f,'.*<spec/models/(.*)_spec\.rb$','\1')
- elseif f =~ '\<\%(test\|spec\)/fixtures/.*\.\w*\~\=$'
- return rails#singularize(s:sub(f,'.*<%(test|spec)/fixtures/(.*)\.\w*\~=$','\1'))
- elseif f =~ '\<\%(test\|spec\)/blueprints/.*\.rb$'
- return s:sub(f,'.*<%(test|spec)/blueprints/(.{-})%(_blueprint)=\.rb$','\1')
- elseif f =~ '\<\%(test\|spec\)/exemplars/.*_exemplar\.rb$'
- return s:sub(f,'.*<%(test|spec)/exemplars/(.*)_exemplar\.rb$','\1')
- elseif f =~ '\<\%(test/\|spec/\)\=factories/.*\.rb$'
- return s:sub(f,'.*<%(test/|spec/)=factories/(.{-})%(_factory)=\.rb$','\1')
- elseif f =~ '\<\%(test/\|spec/\)\=fabricators/.*\.rb$'
- return s:sub(f,'.*<%(test/|spec/)=fabricators/(.{-})%(_fabricator)=\.rb$','\1')
- elseif a:0 && a:1
- return rails#singularize(self.controller_name())
- endif
- return ""
-endfunction
-
-call s:add_methods('readable',['controller_name','model_name'])
-
-function! s:readfile(path,...)
- let nr = bufnr('^'.a:path.'$')
- if nr < 0 && exists('+shellslash') && ! &shellslash
- let nr = bufnr('^'.s:gsub(a:path,'/','\\').'$')
- endif
- if bufloaded(nr)
- return getbufline(nr,1,a:0 ? a:1 : '$')
- elseif !filereadable(a:path)
- return []
- elseif a:0
- return readfile(a:path,'',a:1)
- else
- return readfile(a:path)
- endif
-endfunction
-
-function! s:file_lines() dict abort
- let ftime = getftime(self.path)
- if ftime > get(self,last_lines_ftime,0)
- let self.last_lines = readfile(self.path())
- let self.last_lines_ftime = ftime
- endif
- return get(self,'last_lines',[])
-endfunction
-
-function! s:file_getline(lnum,...) dict abort
- if a:0
- return self.lines[lnum-1 : a:1-1]
- else
- return self.lines[lnum-1]
- endif
-endfunction
-
-function! s:buffer_lines() dict abort
- return self.getline(1,'$')
-endfunction
-
-function! s:buffer_getline(...) dict abort
- if a:0 == 1
- return get(call('getbufline',[self.number()]+a:000),0,'')
- else
- return call('getbufline',[self.number()]+a:000)
- endif
-endfunction
-
-function! s:readable_line_count() dict abort
- return len(self.lines())
-endfunction
-
-function! s:environment()
- if exists('$RAILS_ENV')
- return $RAILS_ENV
- else
- return "development"
- endif
-endfunction
-
-function! s:Complete_environments(...)
- return s:completion_filter(rails#app().environments(),a:0 ? a:1 : "")
-endfunction
-
-function! s:warn(str)
- echohl WarningMsg
- echomsg a:str
- echohl None
- " Sometimes required to flush output
- echo ""
- let v:warningmsg = a:str
-endfunction
-
-function! s:error(str)
- echohl ErrorMsg
- echomsg a:str
- echohl None
- let v:errmsg = a:str
-endfunction
-
-function! s:debug(str)
- if exists("g:rails_debug") && g:rails_debug
- echohl Debug
- echomsg a:str
- echohl None
- endif
-endfunction
-
-function! s:buffer_getvar(varname) dict abort
- return getbufvar(self.number(),a:varname)
-endfunction
-
-function! s:buffer_setvar(varname, val) dict abort
- return setbufvar(self.number(),a:varname,a:val)
-endfunction
-
-call s:add_methods('buffer',['getvar','setvar'])
-
-" }}}1
-" "Public" Interface {{{1
-
-" RailsRoot() is the only official public function
-
-function! rails#underscore(str)
- let str = s:gsub(a:str,'::','/')
- let str = s:gsub(str,'(\u+)(\u\l)','\1_\2')
- let str = s:gsub(str,'(\l|\d)(\u)','\1_\2')
- let str = tolower(str)
- return str
-endfunction
-
-function! rails#camelize(str)
- let str = s:gsub(a:str,'/(.=)','::\u\1')
- let str = s:gsub(str,'%([_-]|<)(.)','\u\1')
- return str
-endfunction
-
-function! rails#singularize(word)
- " Probably not worth it to be as comprehensive as Rails but we can
- " still hit the common cases.
- let word = a:word
- if word =~? '\.js$' || word == ''
- return word
- endif
- let word = s:sub(word,'eople$','ersons')
- let word = s:sub(word,'%([Mm]ov|[aeio])@<!ies$','ys')
- let word = s:sub(word,'xe[ns]$','xs')
- let word = s:sub(word,'ves$','fs')
- let word = s:sub(word,'ss%(es)=$','sss')
- let word = s:sub(word,'s$','')
- let word = s:sub(word,'%([nrt]ch|tatus|lias)\zse$','')
- let word = s:sub(word,'%(nd|rt)\zsice$','ex')
- return word
-endfunction
-
-function! rails#pluralize(word)
- let word = a:word
- if word == ''
- return word
- endif
- let word = s:sub(word,'[aeio]@<!y$','ie')
- let word = s:sub(word,'%(nd|rt)@<=ex$','ice')
- let word = s:sub(word,'%([osxz]|[cs]h)$','&e')
- let word = s:sub(word,'f@<!f$','ve')
- let word .= 's'
- let word = s:sub(word,'ersons$','eople')
- return word
-endfunction
-
-function! rails#app(...)
- let root = a:0 ? a:1 : RailsRoot()
- " TODO: populate dynamically
- " TODO: normalize path
- return get(s:apps,root,0)
-endfunction
-
-function! rails#buffer(...)
- return extend(extend({'#': bufnr(a:0 ? a:1 : '%')},s:buffer_prototype,'keep'),s:readable_prototype,'keep')
- endif
-endfunction
-
-function! s:buffer_app() dict abort
- if self.getvar('rails_root') != ''
- return rails#app(self.getvar('rails_root'))
- else
- return 0
- endif
-endfunction
-
-function! s:readable_app() dict abort
- return self._app
-endfunction
-
-function! RailsRevision()
- return 1000*matchstr(g:autoloaded_rails,'^\d\+')+matchstr(g:autoloaded_rails,'[1-9]\d*$')
-endfunction
-
-function! RailsRoot()
- if exists("b:rails_root")
- return b:rails_root
- else
- return ""
- endif
-endfunction
-
-function! s:app_file(name)
- return extend(extend({'_app': self, '_name': a:name}, s:file_prototype,'keep'),s:readable_prototype,'keep')
-endfunction
-
-function! s:file_path() dict abort
- return self.app().path(self._name)
-endfunction
-
-function! s:file_name() dict abort
- return self._name
-endfunction
-
-function! s:buffer_number() dict abort
- return self['#']
-endfunction
-
-function! s:buffer_path() dict abort
- return s:gsub(fnamemodify(bufname(self.number()),':p'),'\\ @!','/')
-endfunction
-
-function! s:buffer_name() dict abort
- let app = self.app()
- let f = s:gsub(resolve(fnamemodify(bufname(self.number()),':p')),'\\ @!','/')
- let f = s:sub(f,'/$','')
- let sep = matchstr(f,'^[^\\/]\{3,\}\zs[\\/]')
- if sep != ""
- let f = getcwd().sep.f
- endif
- if s:startswith(tolower(f),s:gsub(tolower(app.path()),'\\ @!','/')) || f == ""
- return strpart(f,strlen(app.path())+1)
- else
- if !exists("s:path_warn")
- let s:path_warn = 1
- call s:warn("File ".f." does not appear to be under the Rails root ".self.app().path().". Please report to the rails.vim author!")
- endif
- return f
- endif
-endfunction
-
-function! RailsFilePath()
- if !exists("b:rails_root")
- return ""
- else
- return rails#buffer().name()
- endif
-endfunction
-
-function! RailsFile()
- return RailsFilePath()
-endfunction
-
-function! RailsFileType()
- if !exists("b:rails_root")
- return ""
- else
- return rails#buffer().type_name()
- end
-endfunction
-
-function! s:readable_calculate_file_type() dict abort
- let f = self.name()
- let e = fnamemodify(f,':e')
- let r = "-"
- let full_path = self.path()
- let nr = bufnr('^'.full_path.'$')
- if nr < 0 && exists('+shellslash') && ! &shellslash
- let nr = bufnr('^'.s:gsub(full_path,'/','\\').'$')
- endif
- if f == ""
- let r = f
- elseif nr > 0 && getbufvar(nr,'rails_file_type') != ''
- return getbufvar(nr,'rails_file_type')
- elseif f =~ '_controller\.rb$' || f =~ '\<app/controllers/.*\.rb$'
- if join(s:readfile(full_path,50),"\n") =~ '\<wsdl_service_name\>'
- let r = "controller-api"
- else
- let r = "controller"
- endif
- elseif f =~ '_api\.rb'
- let r = "api"
- elseif f =~ '\<test/test_helper\.rb$'
- let r = "test"
- elseif f =~ '\<spec/spec_helper\.rb$'
- let r = "spec"
- elseif f =~ '_helper\.rb$'
- let r = "helper"
- elseif f =~ '\<app/metal/.*\.rb$'
- let r = "metal"
- elseif f =~ '\<app/mailers/.*\.rb'
- let r = "mailer"
- elseif f =~ '\<app/models/'
- let top = join(s:readfile(full_path,50),"\n")
- let class = matchstr(top,'\<Acti\w\w\u\w\+\%(::\h\w*\)\+\>')
- if class == "ActiveResource::Base"
- let class = "ares"
- let r = "model-ares"
- elseif class == 'ActionMailer::Base'
- let r = "mailer"
- elseif class != ''
- let class = tolower(s:gsub(class,'[^A-Z]',''))
- let r = "model-".class
- elseif f =~ '_mailer\.rb$'
- let r = "mailer"
- elseif top =~ '\<\%(validates_\w\+_of\|set_\%(table_name\|primary_key\)\|has_one\|has_many\|belongs_to\)\>'
- let r = "model-arb"
- else
- let r = "model"
- endif
- elseif f =~ '\<app/views/layouts\>.*\.'
- let r = "view-layout-" . e
- elseif f =~ '\<\%(app/views\|components\)/.*/_\k\+\.\k\+\%(\.\k\+\)\=$'
- let r = "view-partial-" . e
- elseif f =~ '\<app/views\>.*\.' || f =~ '\<components/.*/.*\.'.s:viewspattern().'$'
- let r = "view-" . e
- elseif f =~ '\<test/unit/.*_test\.rb$'
- let r = "test-unit"
- elseif f =~ '\<test/functional/.*_test\.rb$'
- let r = "test-functional"
- elseif f =~ '\<test/integration/.*_test\.rb$'
- let r = "test-integration"
- elseif f =~ '\<spec/lib/.*_spec\.rb$'
- let r = 'spec-lib'
- elseif f =~ '\<lib/.*\.rb$'
- let r = 'lib'
- elseif f =~ '\<spec/\w*s/.*_spec\.rb$'
- let r = s:sub(f,'.*<spec/(\w*)s/.*','spec-\1')
- elseif f =~ '\<features/.*\.feature$'
- let r = 'cucumber-feature'
- elseif f =~ '\<features/step_definitions/.*_steps\.rb$'
- let r = 'cucumber-steps'
- elseif f =~ '\<features/.*\.rb$'
- let r = 'cucumber'
- elseif f =~ '\<\%(test\|spec\)/fixtures\>'
- if e == "yml"
- let r = "fixtures-yaml"
- else
- let r = "fixtures" . (e == "" ? "" : "-" . e)
- endif
- elseif f =~ '\<test/.*_test\.rb'
- let r = "test"
- elseif f =~ '\<spec/.*_spec\.rb'
- let r = "spec"
- elseif f =~ '\<spec/support/.*\.rb'
- let r = "spec"
- elseif f =~ '\<db/migrate\>'
- let r = "db-migration"
- elseif f=~ '\<db/schema\.rb$'
- let r = "db-schema"
- elseif f =~ '\<vendor/plugins/.*/recipes/.*\.rb$' || f =~ '\.rake$' || f =~ '\<\%(Rake\|Cap\)file$' || f =~ '\<config/deploy\.rb$'
- let r = "task"
- elseif f =~ '\<log/.*\.log$'
- let r = "log"
- elseif e == "css" || e =~ "s[ac]ss" || e == "less"
- let r = "stylesheet-".e
- elseif e == "js"
- let r = "javascript"
- elseif e == "coffee"
- let r = "javascript-coffee"
- elseif e == "html"
- let r = e
- elseif f =~ '\<config/routes\>.*\.rb$'
- let r = "config-routes"
- elseif f =~ '\<config/'
- let r = "config"
- endif
- return r
-endfunction
-
-function! s:buffer_type_name(...) dict abort
- let type = getbufvar(self.number(),'rails_cached_file_type')
- if type == ''
- let type = self.calculate_file_type()
- endif
- return call('s:match_type',[type == '-' ? '' : type] + a:000)
-endfunction
-
-function! s:readable_type_name() dict abort
- let type = self.calculate_file_type()
- return call('s:match_type',[type == '-' ? '' : type] + a:000)
-endfunction
-
-function! s:match_type(type,...)
- if a:0
- return !empty(filter(copy(a:000),'a:type =~# "^".v:val."\\%(-\\|$\\)"'))
- else
- return a:type
- endif
-endfunction
-
-function! s:app_environments() dict
- if self.cache.needs('environments')
- call self.cache.set('environments',self.relglob('config/environments/','**/*','.rb'))
- endif
- return copy(self.cache.get('environments'))
-endfunction
-
-function! s:app_default_locale() dict abort
- if self.cache.needs('default_locale')
- let candidates = map(filter(s:readfile(self.path('config/environment.rb')),'v:val =~ "^ *config.i18n.default_locale = :[\"'']\\=[A-Za-z-]\\+[\"'']\\= *$"'),'matchstr(v:val,"[A-Za-z-]\\+[\"'']\\= *$")')
- call self.cache.set('default_locale',get(candidates,0,'en'))
- endif
- return self.cache.get('default_locale')
-endfunction
-
-function! s:app_has(feature) dict
- let map = {
- \'test': 'test/',
- \'spec': 'spec/',
- \'cucumber': 'features/',
- \'sass': 'public/stylesheets/sass/',
- \'lesscss': 'app/stylesheets/',
- \'coffee': 'app/scripts/'}
- if self.cache.needs('features')
- call self.cache.set('features',{})
- endif
- let features = self.cache.get('features')
- if !has_key(features,a:feature)
- let path = get(map,a:feature,a:feature.'/')
- let features[a:feature] = isdirectory(rails#app().path(path))
- endif
- return features[a:feature]
-endfunction
-
-" Returns the subset of ['test', 'spec', 'cucumber'] present on the app.
-function! s:app_test_suites() dict
- return filter(['test','spec','cucumber'],'self.has(v:val)')
-endfunction
-
-call s:add_methods('app',['default_locale','environments','file','has','test_suites'])
-call s:add_methods('file',['path','name','lines','getline'])
-call s:add_methods('buffer',['app','number','path','name','lines','getline','type_name'])
-call s:add_methods('readable',['app','calculate_file_type','type_name','line_count'])
-
-" }}}1
-" Ruby Execution {{{1
-
-function! s:app_ruby_shell_command(cmd) dict abort
- if self.path() =~ '://'
- return "ruby ".a:cmd
- else
- return "ruby -C ".s:rquote(self.path())." ".a:cmd
- endif
-endfunction
-
-function! s:app_script_shell_command(cmd) dict abort
- if self.has_file('script/rails') && a:cmd !~# '^rails\>'
- let cmd = 'script/rails '.a:cmd
- else
- let cmd = 'script/'.a:cmd
- endif
- return self.ruby_shell_command(cmd)
-endfunction
-
-function! s:app_background_script_command(cmd) dict abort
- let cmd = s:esccmd(self.script_shell_command(a:cmd))
- if has_key(self,'options') && has_key(self.options,'gnu_screen')
- let screen = self.options.gnu_screen
- else
- let screen = g:rails_gnu_screen
- endif
- if has("gui_win32")
- if &shellcmdflag == "-c" && ($PATH . &shell) =~? 'cygwin'
- silent exe "!cygstart -d ".s:rquote(self.path())." ruby ".a:cmd
- else
- exe "!start ".cmd
- endif
- elseif exists("$STY") && !has("gui_running") && screen && executable("screen")
- silent exe "!screen -ln -fn -t ".s:sub(s:sub(a:cmd,'\s.*',''),'^%(script|-rcommand)/','rails-').' '.cmd
- elseif exists("$TMUX") && !has("gui_running") && screen && executable("tmux")
- silent exe '!tmux new-window -d -n "'.s:sub(s:sub(a:cmd,'\s.*',''),'^%(script|-rcommand)/','rails-').'" "'.cmd.'"'
- else
- exe "!".cmd
- endif
- return v:shell_error
-endfunction
-
-function! s:app_execute_script_command(cmd) dict abort
- exe '!'.s:esccmd(self.script_shell_command(a:cmd))
- return v:shell_error
-endfunction
-
-function! s:app_lightweight_ruby_eval(ruby,...) dict abort
- let def = a:0 ? a:1 : ""
- if !executable("ruby")
- return def
- endif
- let args = '-e '.s:rquote('begin; require %{rubygems}; rescue LoadError; end; begin; require %{active_support}; rescue LoadError; end; '.a:ruby)
- let cmd = self.ruby_shell_command(args)
- " If the shell is messed up, this command could cause an error message
- silent! let results = system(cmd)
- return v:shell_error == 0 ? results : def
-endfunction
-
-function! s:app_eval(ruby,...) dict abort
- let def = a:0 ? a:1 : ""
- if !executable("ruby")
- return def
- endif
- let args = "-r./config/boot -r ".s:rquote(self.path("config/environment"))." -e ".s:rquote(a:ruby)
- let cmd = self.ruby_shell_command(args)
- " If the shell is messed up, this command could cause an error message
- silent! let results = system(cmd)
- return v:shell_error == 0 ? results : def
-endfunction
-
-call s:add_methods('app', ['ruby_shell_command','script_shell_command','execute_script_command','background_script_command','lightweight_ruby_eval','eval'])
-
-" }}}1
-" Commands {{{1
-
-function! s:prephelp()
- let fn = fnamemodify(s:file,':h:h').'/doc/'
- if filereadable(fn.'rails.txt')
- if !filereadable(fn.'tags') || getftime(fn.'tags') <= getftime(fn.'rails.txt')
- silent! helptags `=fn`
- endif
- endif
-endfunction
-
-function! RailsHelpCommand(...)
- call s:prephelp()
- let topic = a:0 ? a:1 : ""
- if topic == "" || topic == "-"
- return "help rails"
- elseif topic =~ '^g:'
- return "help ".topic
- elseif topic =~ '^-'
- return "help rails".topic
- else
- return "help rails-".topic
- endif
-endfunction
-
-function! s:BufCommands()
- call s:BufFinderCommands()
- call s:BufNavCommands()
- call s:BufScriptWrappers()
- command! -buffer -bar -nargs=? -bang -count -complete=customlist,s:Complete_rake Rake :call s:Rake(<bang>0,!<count> && <line1> ? -1 : <count>,<q-args>)
- command! -buffer -bar -nargs=? -bang -range -complete=customlist,s:Complete_preview Rpreview :call s:Preview(<bang>0,<line1>,<q-args>)
- command! -buffer -bar -nargs=? -bang -complete=customlist,s:Complete_environments Rlog :call s:Log(<bang>0,<q-args>)
- command! -buffer -bar -nargs=* -bang -complete=customlist,s:Complete_set Rset :call s:Set(<bang>0,<f-args>)
- command! -buffer -bar -nargs=0 Rtags :call rails#app().tags_command()
- " Embedding all this logic directly into the command makes the error
- " messages more concise.
- command! -buffer -bar -nargs=? -bang Rdoc :
- \ if <bang>0 || <q-args> =~ "^\\([:'-]\\|g:\\)" |
- \ exe RailsHelpCommand(<q-args>) |
- \ else | call s:Doc(<bang>0,<q-args>) | endif
- command! -buffer -bar -nargs=0 -bang Rrefresh :if <bang>0|unlet! g:autoloaded_rails|source `=s:file`|endif|call s:Refresh(<bang>0)
- if exists(":NERDTree")
- command! -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Rtree :NERDTree `=rails#app().path(<f-args>)`
- endif
- if exists("g:loaded_dbext")
- command! -buffer -bar -nargs=? -complete=customlist,s:Complete_environments Rdbext :call s:BufDatabase(2,<q-args>)|let b:dbext_buffer_defaulted = 1
- endif
- let ext = expand("%:e")
- if ext =~ s:viewspattern()
- " TODO: complete controller names with trailing slashes here
- command! -buffer -bar -bang -nargs=? -range -complete=customlist,s:controllerList Rextract :<line1>,<line2>call s:Extract(<bang>0,<f-args>)
- endif
- if RailsFilePath() =~ '\<db/migrate/.*\.rb$'
- command! -buffer -bar Rinvert :call s:Invert(<bang>0)
- endif
-endfunction
-
-function! s:Doc(bang, string)
- if a:string != ""
- if exists("g:rails_search_url")
- let query = substitute(a:string,'[^A-Za-z0-9_.~-]','\="%".printf("%02X",char2nr(submatch(0)))','g')
- let url = printf(g:rails_search_url, query)
- else
- return s:error("specify a g:rails_search_url with %s for a query placeholder")
- endif
- elseif isdirectory(rails#app().path("doc/api/classes"))
- let url = rails#app().path("/doc/api/index.html")
- elseif s:getpidfor("0.0.0.0","8808") > 0
- let url = "http://localhost:8808"
- else
- let url = "http://api.rubyonrails.org"
- endif
- call s:initOpenURL()
- if exists(":OpenURL")
- exe "OpenURL ".s:escarg(url)
- else
- return s:error("No :OpenURL command found")
- endif
-endfunction
-
-function! s:Log(bang,arg)
- if a:arg == ""
- let lf = "log/".s:environment().".log"
- else
- let lf = "log/".a:arg.".log"
- endif
- let size = getfsize(rails#app().path(lf))
- if size >= 1048576
- call s:warn("Log file is ".((size+512)/1024)."KB. Consider :Rake log:clear")
- endif
- if a:bang
- exe "cgetfile ".lf
- clast
- else
- if exists(":Tail")
- Tail `=rails#app().path(lf)`
- else
- pedit `=rails#app().path(lf)`
- endif
- endif
-endfunction
-
-function! rails#new_app_command(bang,...)
- if a:0 == 0
- let msg = "rails.vim ".g:autoloaded_rails
- if a:bang && exists('b:rails_root') && rails#buffer().type_name() == ''
- echo msg." (Rails)"
- elseif a:bang && exists('b:rails_root')
- echo msg." (Rails-".rails#buffer().type_name().")"
- elseif a:bang
- echo msg
- else
- !rails
- endif
- return
- endif
- let args = map(copy(a:000),'expand(v:val)')
- if a:bang
- let args = ['--force'] + args
- endif
- exe '!rails '.join(map(copy(args),'s:rquote(v:val)'),' ')
- for dir in args
- if dir !~# '^-' && filereadable(dir.'/'.g:rails_default_file)
- edit `=dir.'/'.g:rails_default_file`
- return
- endif
- endfor
-endfunction
-
-function! s:app_tags_command() dict
- if exists("g:Tlist_Ctags_Cmd")
- let cmd = g:Tlist_Ctags_Cmd
- elseif executable("exuberant-ctags")
- let cmd = "exuberant-ctags"
- elseif executable("ctags-exuberant")
- let cmd = "ctags-exuberant"
- elseif executable("ctags")
- let cmd = "ctags"
- elseif executable("ctags.exe")
- let cmd = "ctags.exe"
- else
- return s:error("ctags not found")
- endif
- exe '!'.cmd.' -f '.s:escarg(self.path("tmp/tags")).' -R --langmap="ruby:+.rake.builder.rjs" '.g:rails_ctags_arguments.' '.s:escarg(self.path())
-endfunction
-
-call s:add_methods('app',['tags_command'])
-
-function! s:Refresh(bang)
- if exists("g:rubycomplete_rails") && g:rubycomplete_rails && has("ruby") && exists('g:rubycomplete_completions')
- silent! ruby ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
- silent! ruby if defined?(ActiveSupport::Dependencies); ActiveSupport::Dependencies.clear; elsif defined?(Dependencies); Dependencies.clear; end
- if a:bang
- silent! ruby ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
- endif
- endif
- call rails#app().cache.clear()
- silent doautocmd User BufLeaveRails
- if a:bang
- for key in keys(s:apps)
- if type(s:apps[key]) == type({})
- call s:apps[key].cache.clear()
- endif
- call extend(s:apps[key],filter(copy(s:app_prototype),'type(v:val) == type(function("tr"))'),'force')
- endfor
- endif
- let i = 1
- let max = bufnr('$')
- while i <= max
- let rr = getbufvar(i,"rails_root")
- if rr != ""
- call setbufvar(i,"rails_refresh",1)
- endif
- let i += 1
- endwhile
- silent doautocmd User BufEnterRails
-endfunction
-
-function! s:RefreshBuffer()
- if exists("b:rails_refresh") && b:rails_refresh
- let oldroot = b:rails_root
- unlet! b:rails_root
- let b:rails_refresh = 0
- call RailsBufInit(oldroot)
- unlet! b:rails_refresh
- endif
-endfunction
-
-" }}}1
-" Rake {{{1
-
-function! s:app_rake_tasks() dict
- if self.cache.needs('rake_tasks')
- call s:push_chdir()
- try
- let lines = split(system("rake -T"),"\n")
- finally
- call s:pop_command()
- endtry
- if v:shell_error != 0
- return []
- endif
- call map(lines,'matchstr(v:val,"^rake\\s\\+\\zs\\S*")')
- call filter(lines,'v:val != ""')
- call self.cache.set('rake_tasks',lines)
- endif
- return self.cache.get('rake_tasks')
-endfunction
-
-call s:add_methods('app', ['rake_tasks'])
-
-let s:efm_backtrace='%D(in\ %f),'
- \.'%\\s%#from\ %f:%l:%m,'
- \.'%\\s%#from\ %f:%l:,'
- \.'%\\s#{RAILS_ROOT}/%f:%l:\ %#%m,'
- \.'%\\s%##\ %f:%l:%m,'
- \.'%\\s%##\ %f:%l,'
- \.'%\\s%#[%f:%l:\ %#%m,'
- \.'%\\s%#%f:%l:\ %#%m,'
- \.'%\\s%#%f:%l:,'
- \.'%m\ [%f:%l]:'
-
-function! s:makewithruby(arg,bang,...)
- let old_make = &makeprg
- try
- let &l:makeprg = rails#app().ruby_shell_command(a:arg)
- exe 'make'.(a:bang ? '!' : '')
- if !a:bang
- cwindow
- endif
- finally
- let &l:makeprg = old_make
- endtry
-endfunction
-
-function! s:Rake(bang,lnum,arg)
- let self = rails#app()
- let lnum = a:lnum < 0 ? 0 : a:lnum
- let old_makeprg = &l:makeprg
- let old_errorformat = &l:errorformat
- try
- if exists('b:bundler_root') && b:bundler_root ==# rails#app().path()
- let &l:makeprg = 'bundle exec rake'
- else
- let &l:makeprg = 'rake'
- endif
- let &l:errorformat = s:efm_backtrace
- let arg = a:arg
- if &filetype == "ruby" && arg == '' && g:rails_modelines
- let mnum = s:lastmethodline(lnum)
- let str = getline(mnum)."\n".getline(mnum+1)."\n".getline(mnum+2)."\n"
- let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|$\)'
- let mat = matchstr(str,'#\s*rake'.pat)
- let mat = s:sub(mat,'\s+$','')
- if mat != ""
- let arg = mat
- endif
- endif
- if arg == ''
- let opt = s:getopt('task','bl')
- if opt != ''
- let arg = opt
- else
- let arg = rails#buffer().default_rake_task(lnum)
- endif
- endif
- if !has_key(self,'options') | let self.options = {} | endif
- if arg == '-'
- let arg = get(self.options,'last_rake_task','')
- endif
- let self.options['last_rake_task'] = arg
- let withrubyargs = '-r ./config/boot -r '.s:rquote(self.path('config/environment')).' -e "puts \%((in \#{Dir.getwd}))" '
- if arg =~# '^notes\>'
- let &l:errorformat = '%-P%f:,\ \ *\ [%*[\ ]%l]\ [%t%*[^]]] %m,\ \ *\ [%*[\ ]%l] %m,%-Q'
- " %D to chdir is apparently incompatible with %P multiline messages
- call s:push_chdir(1)
- exe 'make! '.arg
- call s:pop_command()
- if !a:bang
- cwindow
- endif
- elseif arg =~# '^\%(stats\|routes\|secret\|time:zones\|db:\%(charset\|collation\|fixtures:identify\>.*\|migrate:status\|version\)\)\%([: ]\|$\)'
- let &l:errorformat = '%D(in\ %f),%+G%.%#'
- exe 'make! '.arg
- if !a:bang
- copen
- endif
- elseif arg =~ '^preview\>'
- exe (lnum == 0 ? '' : lnum).'R'.s:gsub(arg,':','/')
- elseif arg =~ '^runner:'
- let arg = s:sub(arg,'^runner:','')
- let root = matchstr(arg,'%\%(:\w\)*')
- let file = expand(root).matchstr(arg,'%\%(:\w\)*\zs.*')
- if file =~ '#.*$'
- let extra = " -- -n ".matchstr(file,'#\zs.*')
- let file = s:sub(file,'#.*','')
- else
- let extra = ''
- endif
- if self.has_file(file) || self.has_file(file.'.rb')
- call s:makewithruby(withrubyargs.'-r"'.file.'"'.extra,a:bang,file !~# '_\%(spec\|test\)\%(\.rb\)\=$')
- else
- call s:makewithruby(withrubyargs.'-e '.s:esccmd(s:rquote(arg)),a:bang)
- endif
- elseif arg == 'run' || arg == 'runner'
- call s:makewithruby(withrubyargs.'-r"'.RailsFilePath().'"',a:bang,RailsFilePath() !~# '_\%(spec\|test\)\%(\.rb\)\=$')
- elseif arg =~ '^run:'
- let arg = s:sub(arg,'^run:','')
- let arg = s:sub(arg,'^\%:h',expand('%:h'))
- let arg = s:sub(arg,'^%(\%|$|#@=)',expand('%'))
- let arg = s:sub(arg,'#(\w+[?!=]=)$',' -- -n\1')
- call s:makewithruby(withrubyargs.'-r'.arg,a:bang,arg !~# '_\%(spec\|test\)\.rb$')
- else
- exe 'make! '.arg
- if !a:bang
- cwindow
- endif
- endif
- finally
- let &l:errorformat = old_errorformat
- let &l:makeprg = old_makeprg
- endtry
-endfunction
-
-function! s:readable_default_rake_task(lnum) dict abort
- let app = self.app()
- let lnum = a:lnum < 0 ? 0 : a:lnum
- if self.getvar('&buftype') == 'quickfix'
- return '-'
- elseif self.getline(lnum) =~# '# rake '
- return matchstr(self.getline(lnum),'\C# rake \zs.*')
- elseif self.getline(self.last_method_line(lnum)-1) =~# '# rake '
- return matchstr(self.getline(self.last_method_line(lnum)-1),'\C# rake \zs.*')
- elseif self.getline(self.last_method_line(lnum)) =~# '# rake '
- return matchstr(self.getline(self.last_method_line(lnum)),'\C# rake \zs.*')
- elseif self.getline(1) =~# '# rake ' && !lnum
- return matchstr(self.getline(1),'\C# rake \zs.*')
- elseif self.type_name('config-routes')
- return 'routes'
- elseif self.type_name('fixtures-yaml') && lnum
- return "db:fixtures:identify LABEL=".self.last_method(lnum)
- elseif self.type_name('fixtures') && lnum == 0
- return "db:fixtures:load FIXTURES=".s:sub(fnamemodify(self.name(),':r'),'^.{-}/fixtures/','')
- elseif self.type_name('task')
- let mnum = self.last_method_line(lnum)
- let line = getline(mnum)
- " We can't grab the namespace so only run tasks at the start of the line
- if line =~# '^\%(task\|file\)\>'
- return self.last_method(a:lnum)
- else
- return matchstr(self.getline(1),'\C# rake \zs.*')
- endif
- elseif self.type_name('spec')
- if self.name() =~# '\<spec/spec_helper\.rb$'
- return 'spec'
- elseif lnum > 0
- return 'spec SPEC="'.self.path().'":'.lnum
- else
- return 'spec SPEC="'.self.path().'"'
- endif
- elseif self.type_name('test')
- let meth = self.last_method(lnum)
- if meth =~ '^test_'
- let call = " -n".meth.""
- else
- let call = ""
- endif
- if self.type_name('test-unit','test-functional','test-integration')
- return s:sub(s:gsub(self.type_name(),'-',':'),'unit$|functional$','&s').' TEST="'.self.path().'"'.s:sub(call,'^ ',' TESTOPTS=')
- elseif self.name() =~# '\<test/test_helper\.rb$'
- return 'test'
- else
- return 'test:recent TEST="'.self.path().'"'.s:sub(call,'^ ',' TESTOPTS=')
- endif
- elseif self.type_name('db-migration')
- let ver = matchstr(self.name(),'\<db/migrate/0*\zs\d*\ze_')
- if ver != ""
- let method = self.last_method(lnum)
- if method == "down" || lnum == 1
- return "db:migrate:down VERSION=".ver
- elseif method == "up" || lnum == line('$')
- return "db:migrate:up VERSION=".ver
- elseif lnum > 0
- return "db:migrate:down db:migrate:up VERSION=".ver
- else
- return "db:migrate VERSION=".ver
- endif
- else
- return 'db:migrate'
- endif
- elseif self.name() =~# '\<db/seeds\.rb$'
- return 'db:seed'
- elseif self.type_name('controller') && lnum
- let lm = self.last_method(lnum)
- if lm != ''
- " rake routes doesn't support ACTION... yet...
- return 'routes CONTROLLER='.self.controller_name().' ACTION='.lm
- else
- return 'routes CONTROLLER='.self.controller_name()
- endif
- elseif app.has('spec') && self.name() =~# '^app/.*\.\w\+$' && app.has_file(s:sub(self.name(),'^app/(.*)\.\w\+$','spec/\1_spec.rb'))
- return 'spec SPEC="'.fnamemodify(s:sub(self.name(),'<app/','spec/'),':p:r').'_spec.rb"'
- elseif app.has('spec') && self.name() =~# '^app/.*\.\w\+$' && app.has_file(s:sub(self.name(),'^app/(.*)$','spec/\1_spec.rb'))
- return 'spec SPEC="'.fnamemodify(s:sub(self.name(),'<app/','spec/'),':p').'_spec.rb"'
- elseif self.type_name('model')
- return 'test:units TEST="'.fnamemodify(s:sub(self.name(),'<app/models/','test/unit/'),':p:r').'_test.rb"'
- elseif self.type_name('api','mailer')
- return 'test:units TEST="'.fnamemodify(s:sub(self.name(),'<app/%(apis|mailers|models)/','test/functional/'),':p:r').'_test.rb"'
- elseif self.type_name('helper')
- return 'test:units TEST="'.fnamemodify(s:sub(self.name(),'<app/','test/unit/'),':p:r').'_test.rb"'
- elseif self.type_name('controller','helper','view')
- if self.name() =~ '\<app/' && s:controller() !~# '^\%(application\)\=$'
- return 'test:functionals TEST="'.s:escarg(app.path('test/functional/'.s:controller().'_controller_test.rb')).'"'
- else
- return 'test:functionals'
- endif
- elseif self.type_name('cucumber-feature')
- if lnum > 0
- return 'cucumber FEATURE="'.self.path().'":'.lnum
- else
- return 'cucumber FEATURE="'.self.path().'"'
- endif
- elseif self.type_name('cucumber')
- return 'cucumber'
- else
- return ''
- endif
-endfunction
-
-function! s:Complete_rake(A,L,P)
- return s:completion_filter(rails#app().rake_tasks(),a:A)
-endfunction
-
-call s:add_methods('readable',['default_rake_task'])
-
-" }}}1
-" Preview {{{1
-
-function! s:initOpenURL()
- if !exists(":OpenURL")
- if has("gui_mac") || has("gui_macvim") || exists("$SECURITYSESSIONID")
- command -bar -nargs=1 OpenURL :!open <args>
- elseif has("gui_win32")
- command -bar -nargs=1 OpenURL :!start cmd /cstart /b <args>
- elseif executable("sensible-browser")
- command -bar -nargs=1 OpenURL :!sensible-browser <args>
- endif
- endif
-endfunction
-
-function! s:scanlineforuris(line)
- let url = matchstr(a:line,"\\v\\C%(%(GET|PUT|POST|DELETE)\\s+|\\w+://[^/]*)/[^ \n\r\t<>\"]*[^] .,;\n\r\t<>\":]")
- if url =~ '\C^\u\+\s\+'
- let method = matchstr(url,'^\u\+')
- let url = matchstr(url,'\s\+\zs.*')
- if method !=? "GET"
- let url .= (url =~ '?' ? '&' : '?') . '_method='.tolower(method)
- endif
- endif
- if url != ""
- return [url]
- else
- return []
- endif
-endfunction
-
-function! s:readable_preview_urls(lnum) dict abort
- let urls = []
- let start = self.last_method_line(a:lnum) - 1
- while start > 0 && self.getline(start) =~ '^\s*\%(\%(-\=\|<%\)#.*\)\=$'
- let urls = s:scanlineforuris(self.getline(start)) + urls
- let start -= 1
- endwhile
- let start = 1
- while start < self.line_count() && self.getline(start) =~ '^\s*\%(\%(-\=\|<%\)#.*\)\=$'
- let urls += s:scanlineforuris(self.getline(start))
- let start += 1
- endwhile
- if has_key(self,'getvar') && self.getvar('rails_preview') != ''
- let url += [self.getvar('rails_preview')]
- end
- if self.name() =~ '^public/stylesheets/sass/'
- let urls = urls + [s:sub(s:sub(self.name(),'^public/stylesheets/sass/','/stylesheets/'),'\.s[ac]ss$','.css')]
- elseif self.name() =~ '^public/'
- let urls = urls + [s:sub(self.name(),'^public','')]
- elseif self.name() =~ '^app/assets/stylesheets/'
- let urls = urls + ['/assets/application.css']
- elseif self.name() =~ '^app/assets/javascripts/'
- let urls = urls + ['/assets/application.js']
- elseif self.name() =~ '^app/stylesheets/'
- let urls = urls + [s:sub(s:sub(self.name(),'^app/stylesheets/','/stylesheets/'),'\.less$','.css')]
- elseif self.name() =~ '^app/scripts/'
- let urls = urls + [s:sub(s:sub(self.name(),'^app/scripts/','/javascripts/'),'\.coffee$','.js')]
- elseif self.controller_name() != '' && self.controller_name() != 'application'
- if self.type_name('controller') && self.last_method(a:lnum) != ''
- let urls += ['/'.self.controller_name().'/'.self.last_method(a:lnum).'/']
- elseif self.type_name('controller','view-layout','view-partial')
- let urls += ['/'.self.controller_name().'/']
- elseif self.type_name('view')
- let urls += ['/'.s:controller().'/'.fnamemodify(self.name(),':t:r:r').'/']
- endif
- endif
- return urls
-endfunction
-
-call s:add_methods('readable',['preview_urls'])
-
-function! s:Preview(bang,lnum,arg)
- let root = s:getopt("root_url")
- if root == ''
- let root = s:getopt("url")
- endif
- let root = s:sub(root,'/$','')
- if a:arg =~ '://'
- let uri = a:arg
- elseif a:arg != ''
- let uri = root.'/'.s:sub(a:arg,'^/','')
- else
- let uri = get(rails#buffer().preview_urls(a:lnum),0,'')
- let uri = root.'/'.s:sub(s:sub(uri,'^/',''),'/$','')
- endif
- call s:initOpenURL()
- if exists(':OpenURL') && !a:bang
- exe 'OpenURL '.uri
- else
- " Work around bug where URLs ending in / get handled as FTP
- let url = uri.(uri =~ '/$' ? '?' : '')
- silent exe 'pedit '.url
- wincmd w
- if &filetype == ''
- if uri =~ '\.css$'
- setlocal filetype=css
- elseif uri =~ '\.js$'
- setlocal filetype=javascript
- elseif getline(1) =~ '^\s*<'
- setlocal filetype=xhtml
- endif
- endif
- call RailsBufInit(rails#app().path())
- map <buffer> <silent> q :bwipe<CR>
- wincmd p
- if !a:bang
- call s:warn("Define a :OpenURL command to use a browser")
- endif
- endif
-endfunction
-
-function! s:Complete_preview(A,L,P)
- return rails#buffer().preview_urls(a:L =~ '^\d' ? matchstr(a:L,'^\d\+') : line('.'))
-endfunction
-
-" }}}1
-" Script Wrappers {{{1
-
-function! s:BufScriptWrappers()
- command! -buffer -bar -nargs=* -complete=customlist,s:Complete_script Rscript :call rails#app().script_command(<bang>0,<f-args>)
- command! -buffer -bar -nargs=* -complete=customlist,s:Complete_generate Rgenerate :call rails#app().generate_command(<bang>0,<f-args>)
- command! -buffer -bar -nargs=* -complete=customlist,s:Complete_destroy Rdestroy :call rails#app().destroy_command(<bang>0,<f-args>)
- command! -buffer -bar -nargs=? -bang -complete=customlist,s:Complete_server Rserver :call rails#app().server_command(<bang>0,<q-args>)
- command! -buffer -bang -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Rrunner :call rails#app().runner_command(<bang>0 ? -2 : (<count>==<line2>?<count>:-1),<f-args>)
- command! -buffer -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Rp :call rails#app().runner_command(<count>==<line2>?<count>:-1,'p begin '.<f-args>.' end')
- command! -buffer -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Rpp :call rails#app().runner_command(<count>==<line2>?<count>:-1,'require %{pp}; pp begin '.<f-args>.' end')
- command! -buffer -nargs=1 -range=0 -complete=customlist,s:Complete_ruby Ry :call rails#app().runner_command(<count>==<line2>?<count>:-1,'y begin '.<f-args>.' end')
-endfunction
-
-function! s:app_generators() dict
- if self.cache.needs('generators')
- let generators = self.relglob("vendor/plugins/","*/generators/*")
- let generators += self.relglob("","lib/generators/*")
- call filter(generators,'v:val =~ "/$"')
- let generators += split(glob(expand("~/.rails/generators")."/*"),"\n")
- call map(generators,'s:sub(v:val,"^.*[\\\\/]generators[\\\\/]\\ze.","")')
- call map(generators,'s:sub(v:val,"[\\\\/]$","")')
- call self.cache.set('generators',generators)
- endif
- return sort(split(g:rails_generators,"\n") + self.cache.get('generators'))
-endfunction
-
-function! s:app_script_command(bang,...) dict
- let str = ""
- let cmd = a:0 ? a:1 : "console"
- let c = 2
- while c <= a:0
- let str .= " " . s:rquote(a:{c})
- let c += 1
- endwhile
- if cmd ==# "plugin"
- call self.cache.clear('generators')
- endif
- if a:bang || cmd =~# 'console'
- return self.background_script_command(cmd.str)
- else
- return self.execute_script_command(cmd.str)
- endif
-endfunction
-
-function! s:app_runner_command(count,args) dict
- if a:count == -2
- return self.script_command(a:bang,"runner",a:args)
- else
- let str = self.ruby_shell_command('-r./config/boot -e "require '."'commands/runner'".'" '.s:rquote(a:args))
- let res = s:sub(system(str),'\n$','')
- if a:count < 0
- echo res
- else
- exe a:count.'put =res'
- endif
- endif
-endfunction
-
-function! s:getpidfor(bind,port)
- if has("win32") || has("win64")
- let netstat = system("netstat -anop tcp")
- let pid = matchstr(netstat,'\<'.a:bind.':'.a:port.'\>.\{-\}LISTENING\s\+\zs\d\+')
- elseif executable('lsof')
- let pid = system("lsof -i 4tcp@".a:bind.':'.a:port."|grep LISTEN|awk '{print $2}'")
- let pid = s:sub(pid,'\n','')
- else
- let pid = ""
- endif
- return pid
-endfunction
-
-function! s:app_server_command(bang,arg) dict
- let port = matchstr(a:arg,'\%(-p\|--port=\=\)\s*\zs\d\+')
- if port == ''
- let port = "3000"
- endif
- " TODO: Extract bind argument
- let bind = "0.0.0.0"
- if a:bang && executable("ruby")
- let pid = s:getpidfor(bind,port)
- if pid =~ '^\d\+$'
- echo "Killing server with pid ".pid
- if !has("win32")
- call system("ruby -e 'Process.kill(:TERM,".pid.")'")
- sleep 100m
- endif
- call system("ruby -e 'Process.kill(9,".pid.")'")
- sleep 100m
- endif
- if a:arg == "-"
- return
- endif
- endif
- if has_key(self,'options') && has_key(self.options,'gnu_screen')
- let screen = self.options.gnu_screen
- else
- let screen = g:rails_gnu_screen
- endif
- if has("win32") || has("win64") || (exists("$STY") && !has("gui_running") && screen && executable("screen")) || (exists("$TMUX") && !has("gui_running") && screen && executable("tmux"))
- call self.background_script_command('server '.a:arg)
- else
- " --daemon would be more descriptive but lighttpd does not support it
- call self.execute_script_command('server '.a:arg." -d")
- endif
- call s:setopt('a:root_url','http://'.(bind=='0.0.0.0'?'localhost': bind).':'.port.'/')
-endfunction
-
-function! s:app_destroy_command(bang,...) dict
- if a:0 == 0
- return self.execute_script_command('destroy')
- elseif a:0 == 1
- return self.execute_script_command('destroy '.s:rquote(a:1))
- endif
- let str = ""
- let c = 1
- while c <= a:0
- let str .= " " . s:rquote(a:{c})
- let c += 1
- endwhile
- call self.execute_script_command('destroy'.str)
- call self.cache.clear('user_classes')
-endfunction
-
-function! s:app_generate_command(bang,...) dict
- if a:0 == 0
- return self.execute_script_command('generate')
- elseif a:0 == 1
- return self.execute_script_command('generate '.s:rquote(a:1))
- endif
- let cmd = join(map(copy(a:000),'s:rquote(v:val)'),' ')
- if cmd !~ '-p\>' && cmd !~ '--pretend\>'
- let execstr = self.script_shell_command('generate '.cmd.' -p -f')
- let res = system(execstr)
- let g:res = res
- let junk = '\%(\e\[[0-9;]*m\)\='
- let file = matchstr(res,junk.'\s\+\%(create\|force\)'.junk.'\s\+\zs\f\+\.rb\ze\n')
- if file == ""
- let file = matchstr(res,junk.'\s\+\%(identical\)'.junk.'\s\+\zs\f\+\.rb\ze\n')
- endif
- else
- let file = ""
- endif
- if !self.execute_script_command('generate '.cmd) && file != ''
- call self.cache.clear('user_classes')
- call self.cache.clear('features')
- if file =~ '^db/migrate/\d\d\d\d'
- let file = get(self.relglob('',s:sub(file,'\d+','[0-9]*[0-9]')),-1,file)
- endif
- edit `=self.path(file)`
- endif
-endfunction
-
-call s:add_methods('app', ['generators','script_command','runner_command','server_command','destroy_command','generate_command'])
-
-function! s:Complete_script(ArgLead,CmdLine,P)
- let cmd = s:sub(a:CmdLine,'^\u\w*\s+','')
- if cmd !~ '^[ A-Za-z0-9_=:-]*$'
- return []
- elseif cmd =~# '^\w*$'
- return s:completion_filter(rails#app().relglob("script/","**/*"),a:ArgLead)
- elseif cmd =~# '^\%(plugin\)\s\+'.a:ArgLead.'$'
- return s:completion_filter(["discover","list","install","update","remove","source","unsource","sources"],a:ArgLead)
- elseif cmd =~# '\%(plugin\)\s\+\%(install\|remove\)\s\+'.a:ArgLead.'$' || cmd =~ '\%(generate\|destroy\)\s\+plugin\s\+'.a:ArgLead.'$'
- return s:pluginList(a:ArgLead,a:CmdLine,a:P)
- elseif cmd =~# '^\%(generate\|destroy\)\s\+'.a:ArgLead.'$'
- return s:completion_filter(rails#app().generators(),a:ArgLead)
- elseif cmd =~# '^\%(generate\|destroy\)\s\+\w\+\s\+'.a:ArgLead.'$'
- let target = matchstr(cmd,'^\w\+\s\+\%(\w\+:\)\=\zs\w\+\ze\s\+')
- if target =~# '^\w*controller$'
- return filter(s:controllerList(a:ArgLead,"",""),'v:val !=# "application"')
- elseif target ==# 'generator'
- return s:completion_filter(map(rails#app().relglob('lib/generators/','*'),'s:sub(v:val,"/$","")'))
- elseif target ==# 'helper'
- return s:helperList(a:ArgLead,"","")
- elseif target ==# 'integration_test' || target ==# 'integration_spec' || target ==# 'feature'
- return s:integrationtestList(a:ArgLead,"","")
- elseif target ==# 'metal'
- return s:metalList(a:ArgLead,"","")
- elseif target ==# 'migration' || target ==# 'session_migration'
- return s:migrationList(a:ArgLead,"","")
- elseif target =~# '^\w*\%(model\|resource\)$' || target =~# '\w*scaffold\%(_controller\)\=$' || target ==# 'mailer'
- return s:modelList(a:ArgLead,"","")
- elseif target ==# 'observer'
- let observers = s:observerList("","","")
- let models = s:modelList("","","")
- if cmd =~# '^destroy\>'
- let models = []
- endif
- call filter(models,'index(observers,v:val) < 0')
- return s:completion_filter(observers + models,a:ArgLead)
- else
- return []
- endif
- elseif cmd =~# '^\%(generate\|destroy\)\s\+scaffold\s\+\w\+\s\+'.a:ArgLead.'$'
- return filter(s:controllerList(a:ArgLead,"",""),'v:val !=# "application"')
- return s:completion_filter(rails#app().environments())
- elseif cmd =~# '^\%(console\)\s\+\(--\=\w\+\s\+\)\='.a:ArgLead."$"
- return s:completion_filter(rails#app().environments()+["-s","--sandbox"],a:ArgLead)
- elseif cmd =~# '^\%(server\)\s\+.*-e\s\+'.a:ArgLead."$"
- return s:completion_filter(rails#app().environments(),a:ArgLead)
- elseif cmd =~# '^\%(server\)\s\+'
- if a:ArgLead =~# '^--environment='
- return s:completion_filter(map(copy(rails#app().environments()),'"--environment=".v:val'),a:ArgLead)
- else
- return filter(["-p","-b","-e","-m","-d","-u","-c","-h","--port=","--binding=","--environment=","--mime-types=","--daemon","--debugger","--charset=","--help"],'s:startswith(v:val,a:ArgLead)')
- endif
- endif
- return ""
-endfunction
-
-function! s:CustomComplete(A,L,P,cmd)
- let L = "Rscript ".a:cmd." ".s:sub(a:L,'^\h\w*\s+','')
- let P = a:P - strlen(a:L) + strlen(L)
- return s:Complete_script(a:A,L,P)
-endfunction
-
-function! s:Complete_server(A,L,P)
- return s:CustomComplete(a:A,a:L,a:P,"server")
-endfunction
-
-function! s:Complete_console(A,L,P)
- return s:CustomComplete(a:A,a:L,a:P,"console")
-endfunction
-
-function! s:Complete_generate(A,L,P)
- return s:CustomComplete(a:A,a:L,a:P,"generate")
-endfunction
-
-function! s:Complete_destroy(A,L,P)
- return s:CustomComplete(a:A,a:L,a:P,"destroy")
-endfunction
-
-function! s:Complete_ruby(A,L,P)
- return s:completion_filter(rails#app().user_classes()+["ActiveRecord::Base"],a:A)
-endfunction
-
-" }}}1
-" Navigation {{{1
-
-function! s:BufNavCommands()
- command! -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Rcd :cd `=rails#app().path(<q-args>)`
- command! -buffer -bar -nargs=? -complete=customlist,s:Complete_cd Rlcd :lcd `=rails#app().path(<q-args>)`
- command! -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find Rfind :call s:warn( 'Rfind has been deprecated in favor of :1R or :find' )|call s:Find(<count>,'<bang>' ,<f-args>)
- command! -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find REfind :call s:warn('REfind has been deprecated in favor of :1RE or :find')|call s:Find(<count>,'E<bang>',<f-args>)
- command! -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find RSfind :call s:warn('RSfind has been deprecated in favor of :1RS or :find')|call s:Find(<count>,'S<bang>',<f-args>)
- command! -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find RVfind :call s:warn('RVfind has been deprecated in favor of :1RV or :find')|call s:Find(<count>,'V<bang>',<f-args>)
- command! -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find RTfind :call s:warn('RTfind has been deprecated in favor of :1RT or :find')|call s:Find(<count>,'T<bang>',<f-args>)
- command! -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find Rsfind :call s:warn('Rsfind has been deprecated in favor of :1RS or :sfind')|<count>RSfind<bang> <args>
- command! -buffer -bar -nargs=* -count=1 -complete=customlist,s:Complete_find Rtabfind :call s:warn('Rtabfind has been deprecated in favor of :1RT or :tabfind')|<count>RTfind<bang> <args>
- command! -buffer -bar -nargs=* -bang -complete=customlist,s:Complete_edit Redit :call s:warn( 'Redit has been deprecated in favor of :R')|call s:Edit(<count>,'<bang>' ,<f-args>)
- command! -buffer -bar -nargs=* -bang -complete=customlist,s:Complete_edit REedit :call s:warn('REedit has been deprecated in favor of :RE')|call s:Edit(<count>,'E<bang>',<f-args>)
- command! -buffer -bar -nargs=* -bang -complete=customlist,s:Complete_edit RSedit :call s:warn('RSedit has been deprecated in favor of :RS')|call s:Edit(<count>,'S<bang>',<f-args>)
- command! -buffer -bar -nargs=* -bang -complete=customlist,s:Complete_edit RVedit :call s:warn('RVedit has been deprecated in favor of :RV')|call s:Edit(<count>,'V<bang>',<f-args>)
- command! -buffer -bar -nargs=* -bang -complete=customlist,s:Complete_edit RTedit :call s:warn('RTedit has been deprecated in favor of :RT')|call s:Edit(<count>,'T<bang>',<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_edit RDedit :call s:warn('RDedit has been deprecated in favor of :RD')|call s:Edit(<count>,'<line1>D<bang>',<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related A :call s:Alternate('<bang>', <line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AE :call s:Alternate('E<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AS :call s:Alternate('S<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AV :call s:Alternate('V<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AT :call s:Alternate('T<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AD :call s:Alternate('D<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related AN :call s:Related('<bang>' ,<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related R :call s:Related('<bang>' ,<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RE :call s:Related('E<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RS :call s:Related('S<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RV :call s:Related('V<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RT :call s:Related('T<bang>',<line1>,<line2>,<count>,<f-args>)
- command! -buffer -bar -nargs=* -range=0 -complete=customlist,s:Complete_related RD :call s:Related('D<bang>',<line1>,<line2>,<count>,<f-args>)
-endfunction
-
-function! s:djump(def)
- let def = s:sub(a:def,'^[#:]','')
- if def =~ '^\d\+$'
- exe def
- elseif def =~ '^!'
- if expand('%') !~ '://' && !isdirectory(expand('%:p:h'))
- call mkdir(expand('%:p:h'),'p')
- endif
- elseif def != ''
- let ext = matchstr(def,'\.\zs.*')
- let def = matchstr(def,'[^.]*')
- let v:errmsg = ''
- silent! exe "djump ".def
- if ext != '' && (v:errmsg == '' || v:errmsg =~ '^E387')
- let rpat = '\C^\s*\%(mail\>.*\|respond_to\)\s*\%(\<do\|{\)\s*|\zs\h\k*\ze|'
- let end = s:endof(line('.'))
- let rline = search(rpat,'',end)
- if rline > 0
- let variable = matchstr(getline(rline),rpat)
- let success = search('\C^\s*'.variable.'\s*\.\s*\zs'.ext.'\>','',end)
- if !success
- silent! exe "djump ".def
- endif
- endif
- endif
- endif
-endfunction
-
-function! s:Find(count,cmd,...)
- let str = ""
- if a:0
- let i = 1
- while i < a:0
- let str .= s:escarg(a:{i}) . " "
- let i += 1
- endwhile
- let file = a:{i}
- let tail = matchstr(file,'[#!].*$\|:\d*\%(:in\>.*\)\=$')
- if tail != ""
- let file = s:sub(file,'[#!].*$|:\d*%(:in>.*)=$','')
- endif
- if file != ""
- let file = s:RailsIncludefind(file)
- endif
- else
- let file = s:RailsFind()
- let tail = ""
- endif
- call s:findedit((a:count==1?'' : a:count).a:cmd,file.tail,str)
-endfunction
-
-function! s:Edit(count,cmd,...)
- if a:0
- let str = ""
- let i = 1
- while i < a:0
- let str .= "`=a:".i."` "
- let i += 1
- endwhile
- let file = a:{i}
- call s:findedit(s:editcmdfor(a:cmd),file,str)
- else
- exe s:editcmdfor(a:cmd)
- endif
-endfunction
-
-function! s:fuzzyglob(arg)
- return s:gsub(s:gsub(a:arg,'[^/.]','[&]*'),'%(/|^)\.@!|\.','&*')
-endfunction
-
-function! s:Complete_find(ArgLead, CmdLine, CursorPos)
- let paths = s:pathsplit(&l:path)
- let seen = {}
- for path in paths
- if s:startswith(path,rails#app().path()) && path !~ '[][*]'
- let path = path[strlen(rails#app().path()) + 1 : ]
- for file in rails#app().relglob(path == '' ? '' : path.'/',s:fuzzyglob(rails#underscore(a:ArgLead)), a:ArgLead =~# '\u' ? '.rb' : '')
- let seen[file] = 1
- endfor
- endif
- endfor
- return s:autocamelize(sort(keys(seen)),a:ArgLead)
-endfunction
-
-function! s:Complete_edit(ArgLead, CmdLine, CursorPos)
- return s:completion_filter(rails#app().relglob("",s:fuzzyglob(a:ArgLead)),a:ArgLead)
-endfunction
-
-function! s:Complete_cd(ArgLead, CmdLine, CursorPos)
- let all = rails#app().relglob("",a:ArgLead."*")
- call filter(all,'v:val =~ "/$"')
- return filter(all,'s:startswith(v:val,a:ArgLead)')
-endfunction
-
-function! RailsIncludeexpr()
- " Is this foolproof?
- if mode() =~ '[iR]' || expand("<cfile>") != v:fname
- return s:RailsIncludefind(v:fname)
- else
- return s:RailsIncludefind(v:fname,1)
- endif
-endfunction
-
-function! s:linepeak()
- let line = getline(line("."))
- let line = s:sub(line,'^(.{'.col(".").'}).*','\1')
- let line = s:sub(line,'([:"'."'".']|\%[qQ]=[[({<])=\f*$','')
- return line
-endfunction
-
-function! s:matchcursor(pat)
- let line = getline(".")
- let lastend = 0
- while lastend >= 0
- let beg = match(line,'\C'.a:pat,lastend)
- let end = matchend(line,'\C'.a:pat,lastend)
- if beg < col(".") && end >= col(".")
- return matchstr(line,'\C'.a:pat,lastend)
- endif
- let lastend = end
- endwhile
- return ""
-endfunction
-
-function! s:findit(pat,repl)
- let res = s:matchcursor(a:pat)
- if res != ""
- return substitute(res,'\C'.a:pat,a:repl,'')
- else
- return ""
- endif
-endfunction
-
-function! s:findamethod(func,repl)
- return s:findit('\s*\<\%('.a:func.'\)\s*(\=\s*[@:'."'".'"]\(\f\+\)\>.\=',a:repl)
-endfunction
-
-function! s:findasymbol(sym,repl)
- return s:findit('\s*\%(:\%('.a:sym.'\)\s*=>\|\<'.a:sym.':\)\s*(\=\s*[@:'."'".'"]\(\f\+\)\>.\=',a:repl)
-endfunction
-
-function! s:findfromview(func,repl)
- " ( ) ( ) ( \1 ) ( )
- return s:findit('\s*\%(<%\)\==\=\s*\<\%('.a:func.'\)\s*(\=\s*[@:'."'".'"]\(\f\+\)\>['."'".'"]\=\s*\%(%>\s*\)\=',a:repl)
-endfunction
-
-function! s:RailsFind()
- if filereadable(expand("<cfile>"))
- return expand("<cfile>")
- endif
-
- " UGH
- let buffer = rails#buffer()
- let format = s:format('html')
-
- let res = s:findit('\v\s*<require\s*\(=\s*File.dirname\(__FILE__\)\s*\+\s*[:'."'".'"](\f+)>.=',expand('%:h').'/\1')
- if res != ""|return res.(fnamemodify(res,':e') == '' ? '.rb' : '')|endif
-
- let res = s:findit('\v<File.dirname\(__FILE__\)\s*\+\s*[:'."'".'"](\f+)>['."'".'"]=',expand('%:h').'\1')
- if res != ""|return res|endif
-
- let res = rails#underscore(s:findit('\v\s*<%(include|extend)\(=\s*<([[:alnum:]_:]+)>','\1'))
- if res != ""|return res.".rb"|endif
-
- let res = s:findamethod('require','\1')
- if res != ""|return res.(fnamemodify(res,':e') == '' ? '.rb' : '')|endif
-
- let res = s:findamethod('belongs_to\|has_one\|composed_of\|validates_associated\|scaffold','app/models/\1.rb')
- if res != ""|return res|endif
-
- let res = rails#singularize(s:findamethod('has_many\|has_and_belongs_to_many','app/models/\1'))
- if res != ""|return res.".rb"|endif
-
- let res = rails#singularize(s:findamethod('create_table\|change_table\|drop_table\|add_column\|rename_column\|remove_column\|add_index','app/models/\1'))
- if res != ""|return res.".rb"|endif
-
- let res = rails#singularize(s:findasymbol('through','app/models/\1'))
- if res != ""|return res.".rb"|endif
-
- let res = s:findamethod('fixtures','fixtures/\1')
- if res != ""
- return RailsFilePath() =~ '\<spec/' ? 'spec/'.res : res
- endif
-
- let res = s:findamethod('\%(\w\+\.\)\=resources','app/controllers/\1_controller.rb')
- if res != ""|return res|endif
-
- let res = s:findamethod('\%(\w\+\.\)\=resource','app/controllers/\1')
- if res != ""|return rails#pluralize(res)."_controller.rb"|endif
-
- let res = s:findasymbol('to','app/controllers/\1')
- if res =~ '#'|return s:sub(res,'#','_controller.rb#')|endif
-
- let res = s:findamethod('root\s*\%(:to\s*=>\|\<to:\)\s*','app/controllers/\1')
- if res =~ '#'|return s:sub(res,'#','_controller.rb#')|endif
-
- let res = s:findamethod('\%(match\|get\|put\|post\|delete\|redirect\)\s*(\=\s*[:''"][^''"]*[''"]\=\s*\%(\%(,\s*:to\s*\)\==>\|,\s*to:\)\s*','app/controllers/\1')
- if res =~ '#'|return s:sub(res,'#','_controller.rb#')|endif
-
- let res = s:findamethod('layout','\=s:findlayout(submatch(1))')
- if res != ""|return res|endif
-
- let res = s:findasymbol('layout','\=s:findlayout(submatch(1))')
- if res != ""|return res|endif
-
- let res = s:findamethod('helper','app/helpers/\1_helper.rb')
- if res != ""|return res|endif
-
- let res = s:findasymbol('controller','app/controllers/\1_controller.rb')
- if res != ""|return res|endif
-
- let res = s:findasymbol('action','\1')
- if res != ""|return res|endif
-
- let res = s:findasymbol('template','app/views/\1')
- if res != ""|return res|endif
-
- let res = s:sub(s:sub(s:findasymbol('partial','\1'),'^/',''),'[^/]+$','_&')
- if res != ""|return res."\n".s:findview(res)|endif
-
- let res = s:sub(s:sub(s:findfromview('render\s*(\=\s*\%(:partial\s\+=>\|partial:\)\s*','\1'),'^/',''),'[^/]+$','_&')
- if res != ""|return res."\n".s:findview(res)|endif
-
- let res = s:findamethod('render\>\s*\%(:\%(template\|action\)\s\+=>\|template:\|action:\)\s*','\1.'.format.'\n\1')
- if res != ""|return res|endif
-
- let res = s:sub(s:findfromview('render','\1'),'^/','')
- if buffer.type_name('view') | let res = s:sub(res,'[^/]+$','_&') | endif
- if res != ""|return res."\n".s:findview(res)|endif
-
- let res = s:findamethod('redirect_to\s*(\=\s*\%\(:action\s\+=>\|\<action:\)\s*','\1')
- if res != ""|return res|endif
-
- let res = s:findfromview('stylesheet_link_tag','public/stylesheets/\1')
- if res != '' && fnamemodify(res, ':e') == '' " Append the default extension iff the filename doesn't already contains an extension
- let res .= '.css'
- end
- if res != ""|return res|endif
-
- let res = s:sub(s:findfromview('javascript_include_tag','public/javascripts/\1'),'/defaults>','/application')
- if res != '' && fnamemodify(res, ':e') == '' " Append the default extension iff the filename doesn't already contains an extension
- let res .= '.js'
- end
- if res != ""|return res|endif
-
- if buffer.type_name('controller')
- let contr = s:controller()
- let view = s:findit('\s*\<def\s\+\(\k\+\)\>(\=','/\1')
- let res = s:findview(contr.'/'.view)
- if res != ""|return res|endif
- endif
-
- let old_isfname = &isfname
- try
- set isfname=@,48-57,/,-,_,:,#
- " TODO: grab visual selection in visual mode
- let cfile = expand("<cfile>")
- finally
- let &isfname = old_isfname
- endtry
- let res = s:RailsIncludefind(cfile,1)
- return res
-endfunction
-
-function! s:app_named_route_file(route) dict
- call self.route_names()
- if self.cache.has("named_routes") && has_key(self.cache.get("named_routes"),a:route)
- return self.cache.get("named_routes")[a:route]
- endif
- return ""
-endfunction
-
-function! s:app_route_names() dict
- if self.cache.needs("named_routes")
- let exec = "ActionController::Routing::Routes.named_routes.each {|n,r| puts %{#{n} app/controllers/#{r.requirements[:controller]}_controller.rb##{r.requirements[:action]}}}"
- let string = self.eval(exec)
- let routes = {}
- for line in split(string,"\n")
- let route = split(line," ")
- let name = route[0]
- let routes[name] = route[1]
- endfor
- call self.cache.set("named_routes",routes)
- endif
-
- return keys(self.cache.get("named_routes"))
-endfunction
-
-call s:add_methods('app', ['route_names','named_route_file'])
-
-function! RailsNamedRoutes()
- return rails#app().route_names()
-endfunction
-
-function! s:RailsIncludefind(str,...)
- if a:str ==# "ApplicationController"
- return "application_controller.rb\napp/controllers/application.rb"
- elseif a:str ==# "Test::Unit::TestCase"
- return "test/unit/testcase.rb"
- endif
- let str = a:str
- if a:0 == 1
- " Get the text before the filename under the cursor.
- " We'll cheat and peak at this in a bit
- let line = s:linepeak()
- let line = s:sub(line,'([:"'."'".']|\%[qQ]=[[({<])=\f*$','')
- else
- let line = ""
- endif
- let str = s:sub(str,'^\s*','')
- let str = s:sub(str,'\s*$','')
- let str = s:sub(str,'^:=[:@]','')
- let str = s:sub(str,':0x\x+$','') " For #<Object:0x...> style output
- let str = s:gsub(str,"[\"']",'')
- if line =~# '\<\(require\|load\)\s*(\s*$'
- return str
- elseif str =~# '^\l\w*#\w\+$'
- return 'app/controllers/'.s:sub(str,'#','_controller.rb#')
- endif
- let str = rails#underscore(str)
- let fpat = '\(\s*\%("\f*"\|:\f*\|'."'\\f*'".'\)\s*,\s*\)*'
- if a:str =~# '\u'
- " Classes should always be in .rb files
- let str .= '.rb'
- elseif line =~# ':partial\s*=>\s*'
- let str = s:sub(str,'[^/]+$','_&')
- let str = s:findview(str)
- elseif line =~# '\<layout\s*(\=\s*' || line =~# ':layout\s*=>\s*'
- let str = s:findview(s:sub(str,'^/=','layouts/'))
- elseif line =~# ':controller\s*=>\s*'
- let str = 'app/controllers/'.str.'_controller.rb'
- elseif line =~# '\<helper\s*(\=\s*'
- let str = 'app/helpers/'.str.'_helper.rb'
- elseif line =~# '\<fixtures\s*(\='.fpat
- if RailsFilePath() =~# '\<spec/'
- let str = s:sub(str,'^/@!','spec/fixtures/')
- else
- let str = s:sub(str,'^/@!','test/fixtures/')
- endif
- elseif line =~# '\<stylesheet_\(link_tag\|path\)\s*(\='.fpat
- let str = s:sub(str,'^/@!','/stylesheets/')
- if str != '' && fnamemodify(str, ':e') == ''
- let str .= '.css'
- endif
- elseif line =~# '\<javascript_\(include_tag\|path\)\s*(\='.fpat
- if str ==# "defaults"
- let str = "application"
- endif
- let str = s:sub(str,'^/@!','/javascripts/')
- if str != '' && fnamemodify(str, ':e') == ''
- let str .= '.js'
- endif
- elseif line =~# '\<\(has_one\|belongs_to\)\s*(\=\s*'
- let str = 'app/models/'.str.'.rb'
- elseif line =~# '\<has_\(and_belongs_to_\)\=many\s*(\=\s*'
- let str = 'app/models/'.rails#singularize(str).'.rb'
- elseif line =~# '\<def\s\+' && expand("%:t") =~# '_controller\.rb'
- let str = s:findview(str)
- elseif str =~# '_\%(path\|url\)$' || (line =~# ':as\s*=>\s*$' && rails#buffer().type_name('config-routes'))
- if line !~# ':as\s*=>\s*$'
- let str = s:sub(str,'_%(path|url)$','')
- let str = s:sub(str,'^hash_for_','')
- endif
- let file = rails#app().named_route_file(str)
- if file == ""
- let str = s:sub(str,'^formatted_','')
- if str =~# '^\%(new\|edit\)_'
- let str = 'app/controllers/'.s:sub(rails#pluralize(str),'^(new|edit)_(.*)','\2_controller.rb#\1')
- elseif str ==# rails#singularize(str)
- " If the word can't be singularized, it's probably a link to the show
- " method. We should verify by checking for an argument, but that's
- " difficult the way things here are currently structured.
- let str = 'app/controllers/'.rails#pluralize(str).'_controller.rb#show'
- else
- let str = 'app/controllers/'.str.'_controller.rb#index'
- endif
- else
- let str = file
- endif
- elseif str !~ '/'
- " If we made it this far, we'll risk making it singular.
- let str = rails#singularize(str)
- let str = s:sub(str,'_id$','')
- endif
- if str =~ '^/' && !filereadable(str)
- let str = s:sub(str,'^/','')
- endif
- if str =~# '^lib/' && !filereadable(str)
- let str = s:sub(str,'^lib/','')
- endif
- return str
-endfunction
-
-" }}}1
-" File Finders {{{1
-
-function! s:addfilecmds(type)
- let l = s:sub(a:type,'^.','\l&')
- let cmds = 'ESVTD '
- let cmd = ''
- while cmds != ''
- let cplt = " -complete=customlist,".s:sid.l."List"
- exe "command! -buffer -bar ".(cmd == 'D' ? '-range=0 ' : '')."-nargs=*".cplt." R".cmd.l." :call s:".l.'Edit("'.(cmd == 'D' ? '<line1>' : '').cmd.'<bang>",<f-args>)'
- let cmd = strpart(cmds,0,1)
- let cmds = strpart(cmds,1)
- endwhile
-endfunction
-
-function! s:BufFinderCommands()
- command! -buffer -bar -nargs=+ Rnavcommand :call s:Navcommand(<bang>0,<f-args>)
- call s:addfilecmds("metal")
- call s:addfilecmds("model")
- call s:addfilecmds("view")
- call s:addfilecmds("controller")
- call s:addfilecmds("mailer")
- call s:addfilecmds("migration")
- call s:addfilecmds("observer")
- call s:addfilecmds("helper")
- call s:addfilecmds("layout")
- call s:addfilecmds("fixtures")
- call s:addfilecmds("locale")
- if rails#app().has('test') || rails#app().has('spec')
- call s:addfilecmds("unittest")
- call s:addfilecmds("functionaltest")
- endif
- if rails#app().has('test') || rails#app().has('spec') || rails#app().has('cucumber')
- call s:addfilecmds("integrationtest")
- endif
- if rails#app().has('spec')
- call s:addfilecmds("spec")
- endif
- call s:addfilecmds("stylesheet")
- call s:addfilecmds("javascript")
- call s:addfilecmds("plugin")
- call s:addfilecmds("task")
- call s:addfilecmds("lib")
- call s:addfilecmds("environment")
- call s:addfilecmds("initializer")
-endfunction
-
-function! s:completion_filter(results,A)
- let results = sort(type(a:results) == type("") ? split(a:results,"\n") : copy(a:results))
- call filter(results,'v:val !~# "\\~$"')
- let filtered = filter(copy(results),'s:startswith(v:val,a:A)')
- if !empty(filtered) | return filtered | endif
- let regex = s:gsub(a:A,'[^/]','[&].*')
- let filtered = filter(copy(results),'v:val =~# "^".regex')
- if !empty(filtered) | return filtered | endif
- let regex = s:gsub(a:A,'.','[&].*')
- let filtered = filter(copy(results),'v:val =~# regex')
- return filtered
-endfunction
-
-function! s:autocamelize(files,test)
- if a:test =~# '^\u'
- return s:completion_filter(map(copy(a:files),'rails#camelize(v:val)'),a:test)
- else
- return s:completion_filter(a:files,a:test)
- endif
-endfunction
-
-function! s:app_relglob(path,glob,...) dict
- if exists("+shellslash") && ! &shellslash
- let old_ss = &shellslash
- let &shellslash = 1
- endif
- let path = a:path
- if path !~ '^/' && path !~ '^\w:'
- let path = self.path(path)
- endif
- let suffix = a:0 ? a:1 : ''
- let full_paths = split(glob(path.a:glob.suffix),"\n")
- let relative_paths = []
- for entry in full_paths
- if suffix == '' && isdirectory(entry) && entry !~ '/$'
- let entry .= '/'
- endif
- let relative_paths += [entry[strlen(path) : -strlen(suffix)-1]]
- endfor
- if exists("old_ss")
- let &shellslash = old_ss
- endif
- return relative_paths
-endfunction
-
-call s:add_methods('app', ['relglob'])
-
-function! s:relglob(...)
- return join(call(rails#app().relglob,a:000,rails#app()),"\n")
-endfunction
-
-function! s:helperList(A,L,P)
- return s:autocamelize(rails#app().relglob("app/helpers/","**/*","_helper.rb"),a:A)
-endfunction
-
-function! s:controllerList(A,L,P)
- let con = rails#app().relglob("app/controllers/","**/*",".rb")
- call map(con,'s:sub(v:val,"_controller$","")')
- return s:autocamelize(con,a:A)
-endfunction
-
-function! s:mailerList(A,L,P)
- return s:autocamelize(rails#app().relglob("app/mailers/","**/*",".rb"),a:A)
-endfunction
-
-function! s:viewList(A,L,P)
- let c = s:controller(1)
- let top = rails#app().relglob("app/views/",s:fuzzyglob(a:A))
- call filter(top,'v:val !~# "\\~$"')
- if c != '' && a:A !~ '/'
- let local = rails#app().relglob("app/views/".c."/","*.*[^~]")
- return s:completion_filter(local+top,a:A)
- endif
- return s:completion_filter(top,a:A)
-endfunction
-
-function! s:layoutList(A,L,P)
- return s:completion_filter(rails#app().relglob("app/views/layouts/","*"),a:A)
-endfunction
-
-function! s:stylesheetList(A,L,P)
- let list = rails#app().relglob('app/assets/stylesheets/','**/*.*','')
- call map(list,'s:sub(v:val,"\\..*$","")')
- let list += rails#app().relglob('public/stylesheets/','**/*','.css')
- if rails#app().has('sass')
- call extend(list,rails#app().relglob('public/stylesheets/sass/','**/*','.s?ss'))
- call s:uniq(list)
- endif
- return s:completion_filter(list,a:A)
-endfunction
-
-function! s:javascriptList(A,L,P)
- let list = rails#app().relglob('app/assets/javascripts/','**/*.*','')
- call map(list,'s:sub(v:val,"\\..*$","")')
- let list += rails#app().relglob("public/javascripts/","**/*",".js")
- return s:completion_filter(list,a:A)
-endfunction
-
-function! s:metalList(A,L,P)
- return s:autocamelize(rails#app().relglob("app/metal/","**/*",".rb"),a:A)
-endfunction
-
-function! s:modelList(A,L,P)
- let models = rails#app().relglob("app/models/","**/*",".rb")
- call filter(models,'v:val !~# "_observer$"')
- return s:autocamelize(models,a:A)
-endfunction
-
-function! s:observerList(A,L,P)
- return s:autocamelize(rails#app().relglob("app/models/","**/*","_observer.rb"),a:A)
-endfunction
-
-function! s:fixturesList(A,L,P)
- return s:completion_filter(rails#app().relglob("test/fixtures/","**/*")+rails#app().relglob("spec/fixtures/","**/*"),a:A)
-endfunction
-
-function! s:localeList(A,L,P)
- return s:completion_filter(rails#app().relglob("config/locales/","**/*"),a:A)
-endfunction
-
-function! s:migrationList(A,L,P)
- if a:A =~ '^\d'
- let migrations = rails#app().relglob("db/migrate/",a:A."[0-9_]*",".rb")
- return map(migrations,'matchstr(v:val,"^[0-9]*")')
- else
- let migrations = rails#app().relglob("db/migrate/","[0-9]*[0-9]_*",".rb")
- call map(migrations,'s:sub(v:val,"^[0-9]*_","")')
- return s:autocamelize(migrations,a:A)
- endif
-endfunction
-
-function! s:unittestList(A,L,P)
- let found = []
- if rails#app().has('test')
- let found += rails#app().relglob("test/unit/","**/*","_test.rb")
- endif
- if rails#app().has('spec')
- let found += rails#app().relglob("spec/models/","**/*","_spec.rb")
- endif
- return s:autocamelize(found,a:A)
-endfunction
-
-function! s:functionaltestList(A,L,P)
- let found = []
- if rails#app().has('test')
- let found += rails#app().relglob("test/functional/","**/*","_test.rb")
- endif
- if rails#app().has('spec')
- let found += rails#app().relglob("spec/controllers/","**/*","_spec.rb")
- let found += rails#app().relglob("spec/mailers/","**/*","_spec.rb")
- endif
- return s:autocamelize(found,a:A)
-endfunction
-
-function! s:integrationtestList(A,L,P)
- if a:A =~# '^\u'
- return s:autocamelize(rails#app().relglob("test/integration/","**/*","_test.rb"),a:A)
- endif
- let found = []
- if rails#app().has('test')
- let found += rails#app().relglob("test/integration/","**/*","_test.rb")
- endif
- if rails#app().has('spec')
- let found += rails#app().relglob("spec/requests/","**/*","_spec.rb")
- let found += rails#app().relglob("spec/integration/","**/*","_spec.rb")
- endif
- if rails#app().has('cucumber')
- let found += rails#app().relglob("features/","**/*",".feature")
- endif
- return s:completion_filter(found,a:A)
-endfunction
-
-function! s:specList(A,L,P)
- return s:completion_filter(rails#app().relglob("spec/","**/*","_spec.rb"),a:A)
-endfunction
-
-function! s:pluginList(A,L,P)
- if a:A =~ '/'
- return s:completion_filter(rails#app().relglob('vendor/plugins/',matchstr(a:A,'.\{-\}/').'**/*'),a:A)
- else
- return s:completion_filter(rails#app().relglob('vendor/plugins/',"*","/init.rb"),a:A)
- endif
-endfunction
-
-" Task files, not actual rake tasks
-function! s:taskList(A,L,P)
- let all = rails#app().relglob("lib/tasks/","**/*",".rake")
- if RailsFilePath() =~ '\<vendor/plugins/.'
- let path = s:sub(RailsFilePath(),'<vendor/plugins/[^/]*/\zs.*','')
- let all = rails#app().relglob(path."tasks/","**/*",".rake")+rails#app().relglob(path."lib/tasks/","**/*",".rake")+all
- endif
- return s:autocamelize(all,a:A)
-endfunction
-
-function! s:libList(A,L,P)
- let all = rails#app().relglob('lib/',"**/*",".rb")
- if RailsFilePath() =~ '\<vendor/plugins/.'
- let path = s:sub(RailsFilePath(),'<vendor/plugins/[^/]*/\zs.*','lib/')
- let all = rails#app().relglob(path,"**/*",".rb") + all
- endif
- return s:autocamelize(all,a:A)
-endfunction
-
-function! s:environmentList(A,L,P)
- return s:completion_filter(rails#app().relglob("config/environments/","**/*",".rb"),a:A)
-endfunction
-
-function! s:initializerList(A,L,P)
- return s:completion_filter(rails#app().relglob("config/initializers/","**/*",".rb"),a:A)
-endfunction
-
-function! s:Navcommand(bang,...)
- let suffix = ".rb"
- let filter = "**/*"
- let prefix = ""
- let default = ""
- let name = ""
- let i = 0
- while i < a:0
- let i += 1
- let arg = a:{i}
- if arg =~# '^-suffix='
- let suffix = matchstr(arg,'-suffix=\zs.*')
- elseif arg =~# '^-default='
- let default = matchstr(arg,'-default=\zs.*')
- elseif arg =~# '^-\%(glob\|filter\)='
- let filter = matchstr(arg,'-\w*=\zs.*')
- elseif arg !~# '^-'
- " A literal '\n'. For evaluation below
- if name == ""
- let name = arg
- else
- let prefix .= "\\n".s:sub(arg,'/=$','/')
- endif
- endif
- endwhile
- let prefix = s:sub(prefix,'^\\n','')
- if name !~ '^[A-Za-z]\+$'
- return s:error("E182: Invalid command name")
- endif
- let cmds = 'ESVTD '
- let cmd = ''
- while cmds != ''
- exe 'command! -buffer -bar -bang -nargs=* -complete=customlist,'.s:sid.'CommandList R'.cmd.name." :call s:CommandEdit('".cmd."<bang>','".name."',\"".prefix."\",".string(suffix).",".string(filter).",".string(default).",<f-args>)"
- let cmd = strpart(cmds,0,1)
- let cmds = strpart(cmds,1)
- endwhile
-endfunction
-
-function! s:CommandList(A,L,P)
- let cmd = matchstr(a:L,'\CR[A-Z]\=\w\+')
- exe cmd." &"
- let lp = s:last_prefix . "\n"
- let res = []
- while lp != ""
- let p = matchstr(lp,'.\{-\}\ze\n')
- let lp = s:sub(lp,'.{-}\n','')
- let res += rails#app().relglob(p,s:last_filter,s:last_suffix)
- endwhile
- if s:last_camelize
- return s:autocamelize(res,a:A)
- else
- return s:completion_filter(res,a:A)
- endif
-endfunction
-
-function! s:CommandEdit(cmd,name,prefix,suffix,filter,default,...)
- if a:0 && a:1 == "&"
- let s:last_prefix = a:prefix
- let s:last_suffix = a:suffix
- let s:last_filter = a:filter
- let s:last_camelize = (a:suffix =~# '\.rb$')
- else
- if a:default == "both()"
- if s:model() != ""
- let default = s:model()
- else
- let default = s:controller()
- endif
- elseif a:default == "model()"
- let default = s:model(1)
- elseif a:default == "controller()"
- let default = s:controller(1)
- else
- let default = a:default
- endif
- call s:EditSimpleRb(a:cmd,a:name,a:0 ? a:1 : default,a:prefix,a:suffix)
- endif
-endfunction
-
-function! s:EditSimpleRb(cmd,name,target,prefix,suffix,...)
- let cmd = s:findcmdfor(a:cmd)
- if a:target == ""
- " Good idea to emulate error numbers like this?
- return s:error("E471: Argument required")
- endif
- let f = a:0 ? a:target : rails#underscore(a:target)
- let jump = matchstr(f,'[#!].*\|:\d*\%(:in\)\=$')
- let f = s:sub(f,'[#!].*|:\d*%(:in)=$','')
- if jump =~ '^!'
- let cmd = s:editcmdfor(cmd)
- endif
- if f == '.'
- let f = s:sub(f,'\.$','')
- else
- let f .= a:suffix.jump
- endif
- let f = s:gsub(a:prefix,'\n',f.'\n').f
- return s:findedit(cmd,f)
-endfunction
-
-function! s:app_migration(file) dict
- let arg = a:file
- if arg =~ '^0$\|^0\=[#:]'
- let suffix = s:sub(arg,'^0*','')
- if self.has_file('db/schema.rb')
- return 'db/schema.rb'.suffix
- elseif self.has_file('db/'.s:environment().'_structure.sql')
- return 'db/'.s:environment().'_structure.sql'.suffix
- else
- return 'db/schema.rb'.suffix
- endif
- elseif arg =~ '^\d$'
- let glob = '00'.arg.'_*.rb'
- elseif arg =~ '^\d\d$'
- let glob = '0'.arg.'_*.rb'
- elseif arg =~ '^\d\d\d$'
- let glob = ''.arg.'_*.rb'
- elseif arg == ''
- let glob = '*.rb'
- else
- let glob = '*'.rails#underscore(arg).'*rb'
- endif
- let files = split(glob(self.path('db/migrate/').glob),"\n")
- if arg == ''
- return get(files,-1,'')
- endif
- call map(files,'strpart(v:val,1+strlen(self.path()))')
- let keep = get(files,0,'')
- if glob =~# '^\*.*\*rb'
- let pattern = glob[1:-4]
- call filter(files,'v:val =~# ''db/migrate/\d\+_''.pattern.''\.rb''')
- let keep = get(files,0,keep)
- endif
- return keep
-endfunction
-
-call s:add_methods('app', ['migration'])
-
-function! s:migrationEdit(cmd,...)
- let cmd = s:findcmdfor(a:cmd)
- let arg = a:0 ? a:1 : ''
- let migr = arg == "." ? "db/migrate" : rails#app().migration(arg)
- if migr != ''
- call s:findedit(cmd,migr)
- else
- return s:error("Migration not found".(arg=='' ? '' : ': '.arg))
- endif
-endfunction
-
-function! s:fixturesEdit(cmd,...)
- if a:0
- let c = rails#underscore(a:1)
- else
- let c = rails#pluralize(s:model(1))
- endif
- if c == ""
- return s:error("E471: Argument required")
- endif
- let e = fnamemodify(c,':e')
- let e = e == '' ? e : '.'.e
- let c = fnamemodify(c,':r')
- let file = get(rails#app().test_suites(),0,'test').'/fixtures/'.c.e
- if file =~ '\.\w\+$' && rails#app().find_file(c.e,["test/fixtures","spec/fixtures"]) ==# ''
- call s:edit(a:cmd,file)
- else
- call s:findedit(a:cmd,rails#app().find_file(c.e,["test/fixtures","spec/fixtures"],[".yml",".csv"],file))
- endif
-endfunction
-
-function! s:localeEdit(cmd,...)
- let c = a:0 ? a:1 : rails#app().default_locale()
- if c =~# '\.'
- call s:edit(a:cmd,rails#app().find_file(c,'config/locales',[],'config/locales/'.c))
- else
- call s:findedit(a:cmd,rails#app().find_file(c,'config/locales',['.yml','.rb'],'config/locales/'.c))
- endif
-endfunction
-
-function! s:metalEdit(cmd,...)
- if a:0
- call s:EditSimpleRb(a:cmd,"metal",a:1,"app/metal/",".rb")
- else
- call s:EditSimpleRb(a:cmd,"metal",'config/boot',"",".rb")
- endif
-endfunction
-
-function! s:modelEdit(cmd,...)
- call s:EditSimpleRb(a:cmd,"model",a:0? a:1 : s:model(1),"app/models/",".rb")
-endfunction
-
-function! s:observerEdit(cmd,...)
- call s:EditSimpleRb(a:cmd,"observer",a:0? a:1 : s:model(1),"app/models/","_observer.rb")
-endfunction
-
-function! s:viewEdit(cmd,...)
- if a:0 && a:1 =~ '^[^!#:]'
- let view = matchstr(a:1,'[^!#:]*')
- elseif rails#buffer().type_name('controller','mailer')
- let view = s:lastmethod(line('.'))
- else
- let view = ''
- endif
- if view == ''
- return s:error("No view name given")
- elseif view == '.'
- return s:edit(a:cmd,'app/views')
- elseif view !~ '/' && s:controller(1) != ''
- let view = s:controller(1) . '/' . view
- endif
- if view !~ '/'
- return s:error("Cannot find view without controller")
- endif
- let file = "app/views/".view
- let found = s:findview(view)
- if found != ''
- let dir = fnamemodify(rails#app().path(found),':h')
- if !isdirectory(dir)
- if a:0 && a:1 =~ '!'
- call mkdir(dir,'p')
- else
- return s:error('No such directory')
- endif
- endif
- call s:edit(a:cmd,found)
- elseif file =~ '\.\w\+$'
- call s:findedit(a:cmd,file)
- else
- let format = s:format(rails#buffer().type_name('mailer') ? 'text' : 'html')
- if glob(rails#app().path(file.'.'.format).'.*[^~]') != ''
- let file .= '.' . format
- endif
- call s:findedit(a:cmd,file)
- endif
-endfunction
-
-function! s:findview(name)
- let self = rails#buffer()
- let name = a:name
- let pre = 'app/views/'
- if name !~# '/'
- let controller = self.controller_name(1)
- if controller != ''
- let name = controller.'/'.name
- endif
- endif
- if name =~# '\.\w\+\.\w\+$' || name =~# '\.'.s:viewspattern().'$'
- return pre.name
- else
- for format in ['.'.s:format('html'), '']
- for type in s:view_types
- if self.app().has_file(pre.name.format.'.'.type)
- return pre.name.format.'.'.type
- endif
- endfor
- endfor
- endif
- return ''
-endfunction
-
-function! s:findlayout(name)
- return s:findview("layouts/".(a:name == '' ? 'application' : a:name))
-endfunction
-
-function! s:layoutEdit(cmd,...)
- if a:0
- return s:viewEdit(a:cmd,"layouts/".a:1)
- endif
- let file = s:findlayout(s:controller(1))
- if file == ""
- let file = s:findlayout("application")
- endif
- if file == ""
- let file = "app/views/layouts/application.html.erb"
- endif
- call s:edit(a:cmd,s:sub(file,'^/',''))
-endfunction
-
-function! s:controllerEdit(cmd,...)
- let suffix = '.rb'
- if a:0 == 0
- let controller = s:controller(1)
- if rails#buffer().type_name() =~# '^view\%(-layout\|-partial\)\@!'
- let suffix .= '#'.expand('%:t:r')
- endif
- else
- let controller = a:1
- endif
- if rails#app().has_file("app/controllers/".controller."_controller.rb") || !rails#app().has_file("app/controllers/".controller.".rb")
- let suffix = "_controller".suffix
- endif
- return s:EditSimpleRb(a:cmd,"controller",controller,"app/controllers/",suffix)
-endfunction
-
-function! s:mailerEdit(cmd,...)
- return s:EditSimpleRb(a:cmd,"mailer",a:0? a:1 : s:controller(1),"app/mailers/\napp/models/",".rb")
-endfunction
-
-function! s:helperEdit(cmd,...)
- return s:EditSimpleRb(a:cmd,"helper",a:0? a:1 : s:controller(1),"app/helpers/","_helper.rb")
-endfunction
-
-function! s:stylesheetEdit(cmd,...)
- let name = a:0 ? a:1 : s:controller(1)
- if rails#app().has('sass') && rails#app().has_file('public/stylesheets/sass/'.name.'.sass')
- return s:EditSimpleRb(a:cmd,"stylesheet",name,"public/stylesheets/sass/",".sass",1)
- elseif rails#app().has('sass') && rails#app().has_file('public/stylesheets/sass/'.name.'.scss')
- return s:EditSimpleRb(a:cmd,"stylesheet",name,"public/stylesheets/sass/",".scss",1)
- elseif rails#app().has('lesscss') && rails#app().has_file('app/stylesheets/'.name.'.less')
- return s:EditSimpleRb(a:cmd,"stylesheet",name,"app/stylesheets/",".less",1)
- else
- let types = rails#app().relglob('app/assets/stylesheets/'.name,'.*','')
- if !empty(types)
- return s:EditSimpleRb(a:cmd,'stylesheet',name,'app/assets/stylesheets/',types[0],1)
- else
- return s:EditSimpleRb(a:cmd,'stylesheet',name,'public/stylesheets/','.css',1)
- endif
- endif
-endfunction
-
-function! s:javascriptEdit(cmd,...)
- let name = a:0 ? a:1 : s:controller(1)
- if rails#app().has('coffee') && rails#app().has_file('app/scripts/'.name.'.coffee')
- return s:EditSimpleRb(a:cmd,'javascript',name,'app/scripts/','.coffee',1)
- elseif rails#app().has('coffee') && rails#app().has_file('app/scripts/'.name.'.js')
- return s:EditSimpleRb(a:cmd,'javascript',name,'app/scripts/','.js',1)
- else
- let types = rails#app().relglob('app/assets/javascripts/'.name,'.*','')
- if !empty(types)
- return s:EditSimpleRb(a:cmd,'javascript',name,'app/assets/javascripts/',types[0],1)
- else
- return s:EditSimpleRb(a:cmd,'javascript',name,'public/javascripts/','.js',1)
- endif
- endif
-endfunction
-
-function! s:unittestEdit(cmd,...)
- let f = rails#underscore(a:0 ? matchstr(a:1,'[^!#:]*') : s:model(1))
- let jump = a:0 ? matchstr(a:1,'[!#:].*') : ''
- if jump =~ '!'
- let cmd = s:editcmdfor(a:cmd)
- else
- let cmd = s:findcmdfor(a:cmd)
- endif
- let mapping = {'test': ['test/unit/','_test.rb'], 'spec': ['spec/models/','_spec.rb']}
- let tests = map(filter(rails#app().test_suites(),'has_key(mapping,v:val)'),'get(mapping,v:val)')
- if empty(tests)
- let tests = [mapping['test']]
- endif
- for [prefix, suffix] in tests
- if !a:0 && rails#buffer().type_name('model-aro') && f != '' && f !~# '_observer$'
- if rails#app().has_file(prefix.f.'_observer'.suffix)
- return s:findedit(cmd,prefix.f.'_observer'.suffix.jump)
- endif
- endif
- endfor
- for [prefix, suffix] in tests
- if rails#app().has_file(prefix.f.suffix)
- return s:findedit(cmd,prefix.f.suffix.jump)
- endif
- endfor
- return s:EditSimpleRb(a:cmd,"unittest",f.jump,tests[0][0],tests[0][1],1)
-endfunction
-
-function! s:functionaltestEdit(cmd,...)
- let f = rails#underscore(a:0 ? matchstr(a:1,'[^!#:]*') : s:controller(1))
- let jump = a:0 ? matchstr(a:1,'[!#:].*') : ''
- if jump =~ '!'
- let cmd = s:editcmdfor(a:cmd)
- else
- let cmd = s:findcmdfor(a:cmd)
- endif
- let mapping = {'test': [['test/functional/'],['_test.rb','_controller_test.rb']], 'spec': [['spec/controllers/','spec/mailers/'],['_spec.rb','_controller_spec.rb']]}
- let tests = map(filter(rails#app().test_suites(),'has_key(mapping,v:val)'),'get(mapping,v:val)')
- if empty(tests)
- let tests = [mapping[tests]]
- endif
- for [prefixes, suffixes] in tests
- for prefix in prefixes
- for suffix in suffixes
- if rails#app().has_file(prefix.f.suffix)
- return s:findedit(cmd,prefix.f.suffix.jump)
- endif
- endfor
- endfor
- endfor
- return s:EditSimpleRb(a:cmd,"functionaltest",f.jump,tests[0][0][0],tests[0][1][0],1)
-endfunction
-
-function! s:integrationtestEdit(cmd,...)
- if !a:0
- return s:EditSimpleRb(a:cmd,"integrationtest","test/test_helper\nfeatures/support/env\nspec/spec_helper","",".rb")
- endif
- let f = rails#underscore(matchstr(a:1,'[^!#:]*'))
- let jump = matchstr(a:1,'[!#:].*')
- if jump =~ '!'
- let cmd = s:editcmdfor(a:cmd)
- else
- let cmd = s:findcmdfor(a:cmd)
- endif
- let tests = [['test/integration/','_test.rb'], [ 'spec/requests/','_spec.rb'], [ 'spec/integration/','_spec.rb'], [ 'features/','.feature']]
- call filter(tests, 'isdirectory(rails#app().path(v:val[0]))')
- if empty(tests)
- let tests = [['test/integration/','_test.rb']]
- endif
- for [prefix, suffix] in tests
- if rails#app().has_file(prefix.f.suffix)
- return s:findedit(cmd,prefix.f.suffix.jump)
- elseif rails#app().has_file(prefix.rails#underscore(f).suffix)
- return s:findedit(cmd,prefix.rails#underscore(f).suffix.jump)
- endif
- endfor
- return s:EditSimpleRb(a:cmd,"integrationtest",f.jump,tests[0][0],tests[0][1],1)
-endfunction
-
-function! s:specEdit(cmd,...)
- if a:0
- return s:EditSimpleRb(a:cmd,"spec",a:1,"spec/","_spec.rb")
- else
- call s:EditSimpleRb(a:cmd,"spec","spec_helper","spec/",".rb")
- endif
-endfunction
-
-function! s:pluginEdit(cmd,...)
- let cmd = s:findcmdfor(a:cmd)
- let plugin = ""
- let extra = ""
- if RailsFilePath() =~ '\<vendor/plugins/.'
- let plugin = matchstr(RailsFilePath(),'\<vendor/plugins/\zs[^/]*\ze')
- let extra = "vendor/plugins/" . plugin . "/\n"
- endif
- if a:0
- if a:1 =~ '^[^/.]*/\=$' && rails#app().has_file("vendor/plugins/".a:1."/init.rb")
- return s:EditSimpleRb(a:cmd,"plugin",s:sub(a:1,'/$',''),"vendor/plugins/","/init.rb")
- elseif plugin == ""
- call s:edit(cmd,"vendor/plugins/".s:sub(a:1,'\.$',''))
- elseif a:1 == "."
- call s:findedit(cmd,"vendor/plugins/".plugin)
- elseif isdirectory(rails#app().path("vendor/plugins/".matchstr(a:1,'^[^/]*')))
- call s:edit(cmd,"vendor/plugins/".a:1)
- else
- call s:findedit(cmd,"vendor/plugins/".a:1."\nvendor/plugins/".plugin."/".a:1)
- endif
- else
- call s:findedit(a:cmd,"Gemfile")
- endif
-endfunction
-
-function! s:taskEdit(cmd,...)
- let plugin = ""
- let extra = ""
- if RailsFilePath() =~ '\<vendor/plugins/.'
- let plugin = matchstr(RailsFilePath(),'\<vendor/plugins/[^/]*')
- let extra = plugin."/tasks/\n".plugin."/lib/tasks/\n"
- endif
- if a:0
- call s:EditSimpleRb(a:cmd,"task",a:1,extra."lib/tasks/",".rake")
- else
- call s:findedit(a:cmd,(plugin != "" ? plugin."/Rakefile\n" : "")."Rakefile")
- endif
-endfunction
-
-function! s:libEdit(cmd,...)
- let extra = ""
- if RailsFilePath() =~ '\<vendor/plugins/.'
- let extra = s:sub(RailsFilePath(),'<vendor/plugins/[^/]*/\zs.*','lib/')."\n"
- endif
- if a:0
- call s:EditSimpleRb(a:cmd,"lib",a:0? a:1 : "",extra."lib/",".rb")
- else
- call s:EditSimpleRb(a:cmd,"lib","seeds","db/",".rb")
- endif
-endfunction
-
-function! s:environmentEdit(cmd,...)
- if a:0 || rails#app().has_file('config/application.rb')
- return s:EditSimpleRb(a:cmd,"environment",a:0? a:1 : "../application","config/environments/",".rb")
- else
- return s:EditSimpleRb(a:cmd,"environment","environment","config/",".rb")
- endif
-endfunction
-
-function! s:initializerEdit(cmd,...)
- return s:EditSimpleRb(a:cmd,"initializer",a:0? a:1 : "../routes","config/initializers/",".rb")
-endfunction
-
-" }}}1
-" Alternate/Related {{{1
-
-function! s:findcmdfor(cmd)
- let bang = ''
- if a:cmd =~ '\!$'
- let bang = '!'
- let cmd = s:sub(a:cmd,'\!$','')
- else
- let cmd = a:cmd
- endif
- if cmd =~ '^\d'
- let num = matchstr(cmd,'^\d\+')
- let cmd = s:sub(cmd,'^\d+','')
- else
- let num = ''
- endif
- if cmd == '' || cmd == 'E' || cmd == 'F'
- return num.'find'.bang
- elseif cmd == 'S'
- return num.'sfind'.bang
- elseif cmd == 'V'
- return 'vert '.num.'sfind'.bang
- elseif cmd == 'T'
- return num.'tabfind'.bang
- elseif cmd == 'D'
- return num.'read'.bang
- else
- return num.cmd.bang
- endif
-endfunction
-
-function! s:editcmdfor(cmd)
- let cmd = s:findcmdfor(a:cmd)
- let cmd = s:sub(cmd,'<sfind>','split')
- let cmd = s:sub(cmd,'find>','edit')
- return cmd
-endfunction
-
-function! s:try(cmd) abort
- if !exists(":try")
- " I've seen at least one weird setup without :try
- exe a:cmd
- else
- try
- exe a:cmd
- catch
- call s:error(s:sub(v:exception,'^.{-}:\zeE',''))
- return 0
- endtry
- endif
- return 1
-endfunction
-
-function! s:findedit(cmd,files,...) abort
- let cmd = s:findcmdfor(a:cmd)
- let files = type(a:files) == type([]) ? copy(a:files) : split(a:files,"\n")
- if len(files) == 1
- let file = files[0]
- else
- let file = get(filter(copy(files),'rails#app().has_file(s:sub(v:val,"#.*|:\\d*$",""))'),0,get(files,0,''))
- endif
- if file =~ '[#!]\|:\d*\%(:in\)\=$'
- let djump = matchstr(file,'!.*\|#\zs.*\|:\zs\d*\ze\%(:in\)\=$')
- let file = s:sub(file,'[#!].*|:\d*%(:in)=$','')
- else
- let djump = ''
- endif
- if file == ''
- let testcmd = "edit"
- elseif isdirectory(rails#app().path(file))
- let arg = file == "." ? rails#app().path() : rails#app().path(file)
- let testcmd = s:editcmdfor(cmd).' '.(a:0 ? a:1 . ' ' : '').s:escarg(arg)
- exe testcmd
- return
- elseif rails#app().path() =~ '://' || cmd =~ 'edit' || cmd =~ 'split'
- if file !~ '^/' && file !~ '^\w:' && file !~ '://'
- let file = s:escarg(rails#app().path(file))
- endif
- let testcmd = s:editcmdfor(cmd).' '.(a:0 ? a:1 . ' ' : '').file
- else
- let testcmd = cmd.' '.(a:0 ? a:1 . ' ' : '').file
- endif
- if s:try(testcmd)
- call s:djump(djump)
- endif
-endfunction
-
-function! s:edit(cmd,file,...)
- let cmd = s:editcmdfor(a:cmd)
- let cmd .= ' '.(a:0 ? a:1 . ' ' : '')
- let file = a:file
- if file !~ '^/' && file !~ '^\w:' && file !~ '://'
- exe cmd."`=fnamemodify(rails#app().path(file),':.')`"
- else
- exe cmd.file
- endif
-endfunction
-
-function! s:Alternate(cmd,line1,line2,count,...)
- if a:0
- if a:count && a:cmd !~# 'D'
- return call('s:Find',[1,a:line1.a:cmd]+a:000)
- elseif a:count
- return call('s:Edit',[1,a:line1.a:cmd]+a:000)
- else
- return call('s:Edit',[1,a:cmd]+a:000)
- endif
- else
- let file = s:getopt(a:count ? 'related' : 'alternate', 'bl')
- if file == ''
- let file = rails#buffer().related(a:count)
- endif
- if file != ''
- call s:findedit(a:cmd,file)
- else
- call s:warn("No alternate file is defined")
- endif
- endif
-endfunction
-
-function! s:Related(cmd,line1,line2,count,...)
- if a:count == 0 && a:0 == 0
- return s:Alternate(a:cmd,a:line1,a:line1,a:line1)
- else
- return call('s:Alternate',[a:cmd,a:line1,a:line2,a:count]+a:000)
- endif
-endfunction
-
-function! s:Complete_related(A,L,P)
- if a:L =~# '^[[:alpha:]]'
- return s:Complete_edit(a:A,a:L,a:P)
- else
- return s:Complete_find(a:A,a:L,a:P)
- endif
-endfunction
-
-function! s:readable_related(...) dict abort
- let f = self.name()
- if a:0 && a:1
- let lastmethod = self.last_method(a:1)
- if self.type_name('controller','mailer') && lastmethod != ""
- let root = s:sub(s:sub(s:sub(f,'/application%(_controller)=\.rb$','/shared_controller.rb'),'/%(controllers|models|mailers)/','/views/'),'%(_controller)=\.rb$','/'.lastmethod)
- let format = self.last_format(a:1)
- if format == ''
- let format = self.type_name('mailer') ? 'text' : 'html'
- endif
- if glob(self.app().path().'/'.root.'.'.format.'.*[^~]') != ''
- return root . '.' . format
- else
- return root
- endif
- elseif f =~ '\<config/environments/'
- return "config/database.yml#". fnamemodify(f,':t:r')
- elseif f =~ '\<config/database\.yml$'
- if lastmethod != ""
- return "config/environments/".lastmethod.".rb"
- else
- return "config/application.rb\nconfig/environment.rb"
- endif
- elseif f =~ '\<config/routes\.rb$' | return "config/database.yml"
- elseif f =~ '\<config/\%(application\|environment\)\.rb$'
- return "config/routes.rb"
- elseif self.type_name('view-layout')
- return s:sub(s:sub(f,'/views/','/controllers/'),'/layouts/(\k+)\..*$','/\1_controller.rb')
- elseif self.type_name('view')
- let controller = s:sub(s:sub(f,'/views/','/controllers/'),'/(\k+%(\.\k+)=)\..*$','_controller.rb#\1')
- let controller2 = s:sub(s:sub(f,'/views/','/controllers/'),'/(\k+%(\.\k+)=)\..*$','.rb#\1')
- let mailer = s:sub(s:sub(f,'/views/','/mailers/'),'/(\k+%(\.\k+)=)\..*$','.rb#\1')
- let model = s:sub(s:sub(f,'/views/','/models/'),'/(\k+)\..*$','.rb#\1')
- if self.app().has_file(s:sub(controller,'#.{-}$',''))
- return controller
- elseif self.app().has_file(s:sub(controller2,'#.{-}$',''))
- return controller2
- elseif self.app().has_file(s:sub(mailer,'#.{-}$',''))
- return mailer
- elseif self.app().has_file(s:sub(model,'#.{-}$','')) || model =~ '_mailer\.rb#'
- return model
- else
- return controller
- endif
- elseif self.type_name('controller')
- return s:sub(s:sub(f,'/controllers/','/helpers/'),'%(_controller)=\.rb$','_helper.rb')
- " elseif self.type_name('helper')
- " return s:findlayout(s:controller())
- elseif self.type_name('model-arb')
- let table_name = matchstr(join(self.getline(1,50),"\n"),'\n\s*set_table_name\s*[:"'']\zs\w\+')
- if table_name == ''
- let table_name = rails#pluralize(s:gsub(s:sub(fnamemodify(f,':r'),'.{-}<app/models/',''),'/','_'))
- endif
- return self.app().migration('0#'.table_name)
- elseif self.type_name('model-aro')
- return s:sub(f,'_observer\.rb$','.rb')
- elseif self.type_name('db-schema')
- return self.app().migration(1)
- endif
- endif
- if f =~ '\<config/environments/'
- return "config/application.rb\nconfig/environment.rb"
- elseif f == 'README'
- return "config/database.yml"
- elseif f =~ '\<config/database\.yml$' | return "config/routes.rb"
- elseif f =~ '\<config/routes\.rb$'
- return "config/application.rb\nconfig/environment.rb"
- elseif f =~ '\<config/\%(application\|environment\)\.rb$'
- return "config/database.yml"
- elseif f ==# 'Gemfile'
- return 'Gemfile.lock'
- elseif f ==# 'Gemfile.lock'
- return 'Gemfile'
- elseif f =~ '\<db/migrate/'
- let migrations = sort(self.app().relglob('db/migrate/','*','.rb'))
- let me = matchstr(f,'\<db/migrate/\zs.*\ze\.rb$')
- if !exists('l:lastmethod') || lastmethod == 'down'
- let candidates = reverse(filter(copy(migrations),'v:val < me'))
- let migration = "db/migrate/".get(candidates,0,migrations[-1]).".rb"
- else
- let candidates = filter(copy(migrations),'v:val > me')
- let migration = "db/migrate/".get(candidates,0,migrations[0]).".rb"
- endif
- return migration . (exists('l:lastmethod') && lastmethod != '' ? '#'.lastmethod : '')
- elseif f =~ '\<application\.js$'
- return "app/helpers/application_helper.rb"
- elseif self.type_name('javascript')
- return "public/javascripts/application.js"
- elseif self.type_name('db/schema')
- return self.app().migration('')
- elseif self.type_name('view')
- let spec1 = fnamemodify(f,':s?\<app/?spec/?')."_spec.rb"
- let spec2 = fnamemodify(f,':r:s?\<app/?spec/?')."_spec.rb"
- let spec3 = fnamemodify(f,':r:r:s?\<app/?spec/?')."_spec.rb"
- if self.app().has_file(spec1)
- return spec1
- elseif self.app().has_file(spec2)
- return spec2
- elseif self.app().has_file(spec3)
- return spec3
- elseif self.app().has('spec')
- return spec2
- else
- if self.type_name('view-layout')
- let dest = fnamemodify(f,':r:s?/layouts\>??').'/layout.'.fnamemodify(f,':e')
- else
- let dest = f
- endif
- return s:sub(s:sub(dest,'<app/views/','test/functional/'),'/[^/]*$','_controller_test.rb')
- endif
- elseif self.type_name('controller-api')
- let api = s:sub(s:sub(f,'/controllers/','/apis/'),'_controller\.rb$','_api.rb')
- return api
- elseif self.type_name('api')
- return s:sub(s:sub(f,'/apis/','/controllers/'),'_api\.rb$','_controller.rb')
- elseif self.type_name('fixtures') && f =~ '\<spec/'
- let file = rails#singularize(fnamemodify(f,":t:r")).'_spec.rb'
- return file
- elseif self.type_name('fixtures')
- let file = rails#singularize(fnamemodify(f,":t:r")).'_test.rb'
- return file
- elseif f == ''
- call s:warn("No filename present")
- elseif f =~ '\<test/unit/routing_test\.rb$'
- return 'config/routes.rb'
- elseif self.type_name('spec-view')
- return s:sub(s:sub(f,'<spec/','app/'),'_spec\.rb$','')
- elseif fnamemodify(f,":e") == "rb"
- let file = fnamemodify(f,":r")
- if file =~ '_\%(test\|spec\)$'
- let file = s:sub(file,'_%(test|spec)$','.rb')
- else
- let file .= '_test.rb'
- endif
- if self.type_name('helper')
- return s:sub(file,'<app/helpers/','test/unit/helpers/')."\n".s:sub(s:sub(file,'_test\.rb$','_spec.rb'),'<app/helpers/','spec/helpers/')
- elseif self.type_name('model')
- return s:sub(file,'<app/models/','test/unit/')."\n".s:sub(s:sub(file,'_test\.rb$','_spec.rb'),'<app/models/','spec/models/')
- elseif self.type_name('controller')
- return s:sub(file,'<app/controllers/','test/functional/')."\n".s:sub(s:sub(file,'_test\.rb$','_spec.rb'),'app/controllers/','spec/controllers/')
- elseif self.type_name('mailer')
- return s:sub(file,'<app/m%(ailer|odel)s/','test/unit/')."\n".s:sub(s:sub(file,'_test\.rb$','_spec.rb'),'<app/','spec/')
- elseif self.type_name('test-unit')
- return s:sub(s:sub(file,'test/unit/helpers/','app/helpers/'),'test/unit/','app/models/')."\n".s:sub(file,'test/unit/','lib/')
- elseif self.type_name('test-functional')
- if file =~ '_api\.rb'
- return s:sub(file,'test/functional/','app/apis/')
- elseif file =~ '_controller\.rb'
- return s:sub(file,'test/functional/','app/controllers/')
- else
- return s:sub(file,'test/functional/','')
- endif
- elseif self.type_name('spec-lib')
- return s:sub(file,'<spec/','')
- elseif self.type_name('lib')
- return s:sub(f, '<lib/(.*)\.rb$', 'test/unit/\1_test.rb')."\n".s:sub(f, '<lib/(.*)\.rb$', 'spec/lib/\1_spec.rb')
- elseif self.type_name('spec')
- return s:sub(file,'<spec/','app/')
- elseif file =~ '\<vendor/.*/lib/'
- return s:sub(file,'<vendor/.{-}/\zslib/','test/')
- elseif file =~ '\<vendor/.*/test/'
- return s:sub(file,'<vendor/.{-}/\zstest/','lib/')
- else
- return fnamemodify(file,':t')."\n".s:sub(s:sub(f,'\.rb$','_spec.rb'),'^app/','spec/')
- endif
- else
- return ""
- endif
-endfunction
-
-call s:add_methods('readable',['related'])
-
-" }}}1
-" Partial Extraction {{{1
-
-function! s:Extract(bang,...) range abort
- if a:0 == 0 || a:0 > 1
- return s:error("Incorrect number of arguments")
- endif
- if a:1 =~ '[^a-z0-9_/.]'
- return s:error("Invalid partial name")
- endif
- let rails_root = rails#app().path()
- let ext = expand("%:e")
- let file = s:sub(a:1,'%(/|^)\zs_\ze[^/]*$','')
- let first = a:firstline
- let last = a:lastline
- let range = first.",".last
- if rails#buffer().type_name('view-layout')
- if RailsFilePath() =~ '\<app/views/layouts/application\>'
- let curdir = 'app/views/shared'
- if file !~ '/'
- let file = "shared/" .file
- endif
- else
- let curdir = s:sub(RailsFilePath(),'.*<app/views/layouts/(.*)%(\.\w*)$','app/views/\1')
- endif
- else
- let curdir = fnamemodify(RailsFilePath(),':h')
- endif
- let curdir = rails_root."/".curdir
- let dir = fnamemodify(file,":h")
- let fname = fnamemodify(file,":t")
- if fnamemodify(fname,":e") == ""
- let name = fname
- let fname .= ".".matchstr(expand("%:t"),'\.\zs.*')
- elseif fnamemodify(fname,":e") !~ '^'.s:viewspattern().'$'
- let name = fnamemodify(fname,":r")
- let fname .= ".".ext
- else
- let name = fnamemodify(fname,":r:r")
- endif
- let var = "@".name
- let collection = ""
- if dir =~ '^/'
- let out = (rails_root).dir."/_".fname
- elseif dir == "" || dir == "."
- let out = (curdir)."/_".fname
- elseif isdirectory(curdir."/".dir)
- let out = (curdir)."/".dir."/_".fname
- else
- let out = (rails_root)."/app/views/".dir."/_".fname
- endif
- if filereadable(out) && !a:bang
- return s:error('E13: File exists (add ! to override)')
- endif
- if !isdirectory(fnamemodify(out,':h'))
- if a:bang
- call mkdir(fnamemodify(out,':h'),'p')
- else
- return s:error('No such directory')
- endif
- endif
- " No tabs, they'll just complicate things
- if ext =~? '^\%(rhtml\|erb\|dryml\)$'
- let erub1 = '\<\%\s*'
- let erub2 = '\s*-=\%\>'
- else
- let erub1 = ''
- let erub2 = ''
- endif
- let spaces = matchstr(getline(first),"^ *")
- if getline(last+1) =~ '\v^\s*'.erub1.'end'.erub2.'\s*$'
- let fspaces = matchstr(getline(last+1),"^ *")
- if getline(first-1) =~ '\v^'.fspaces.erub1.'for\s+(\k+)\s+in\s+([^ %>]+)'.erub2.'\s*$'
- let collection = s:sub(getline(first-1),'^'.fspaces.erub1.'for\s+(\k+)\s+in\s+([^ >]+)'.erub2.'\s*$','\1>\2')
- elseif getline(first-1) =~ '\v^'.fspaces.erub1.'([^ %>]+)\.each\s+do\s+\|\s*(\k+)\s*\|'.erub2.'\s*$'
- let collection = s:sub(getline(first-1),'^'.fspaces.erub1.'([^ %>]+)\.each\s+do\s+\|\s*(\k+)\s*\|'.erub2.'\s*$','\2>\1')
- endif
- if collection != ''
- let var = matchstr(collection,'^\k\+')
- let collection = s:sub(collection,'^\k+\>','')
- let first -= 1
- let last += 1
- endif
- else
- let fspaces = spaces
- endif
- let renderstr = "render :partial => '".fnamemodify(file,":r:r")."'"
- if collection != ""
- let renderstr .= ", :collection => ".collection
- elseif "@".name != var
- let renderstr .= ", :object => ".var
- endif
- if ext =~? '^\%(rhtml\|erb\|dryml\)$'
- let renderstr = "<%= ".renderstr." %>"
- elseif ext == "rxml" || ext == "builder"
- let renderstr = "xml << ".s:sub(renderstr,"render ","render(").")"
- elseif ext == "rjs"
- let renderstr = "page << ".s:sub(renderstr,"render ","render(").")"
- elseif ext == "haml"
- let renderstr = "= ".renderstr
- elseif ext == "mn"
- let renderstr = "_".renderstr
- endif
- let buf = @@
- silent exe range."yank"
- let partial = @@
- let @@ = buf
- let old_ai = &ai
- try
- let &ai = 0
- silent exe "norm! :".first.",".last."change\<CR>".fspaces.renderstr."\<CR>.\<CR>"
- finally
- let &ai = old_ai
- endtry
- if renderstr =~ '<%'
- norm ^6w
- else
- norm ^5w
- endif
- let ft = &ft
- let shortout = fnamemodify(out,':.')
- silent split `=shortout`
- silent %delete
- let &ft = ft
- let @@ = partial
- silent put
- 0delete
- let @@ = buf
- if spaces != ""
- silent! exe '%substitute/^'.spaces.'//'
- endif
- silent! exe '%substitute?\%(\w\|[@:"'."'".'-]\)\@<!'.var.'\>?'.name.'?g'
- 1
-endfunction
-
-" }}}1
-" Migration Inversion {{{1
-
-function! s:mkeep(str)
- " Things to keep (like comments) from a migration statement
- return matchstr(a:str,' #[^{].*')
-endfunction
-
-function! s:mextargs(str,num)
- if a:str =~ '^\s*\w\+\s*('
- return s:sub(matchstr(a:str,'^\s*\w\+\s*\zs(\%([^,)]\+[,)]\)\{,'.a:num.'\}'),',$',')')
- else
- return s:sub(s:sub(matchstr(a:str,'\w\+\>\zs\s*\%([^,){ ]*[, ]*\)\{,'.a:num.'\}'),'[, ]*$',''),'^\s+',' ')
- endif
-endfunction
-
-function! s:migspc(line)
- return matchstr(a:line,'^\s*')
-endfunction
-
-function! s:invertrange(beg,end)
- let str = ""
- let lnum = a:beg
- while lnum <= a:end
- let line = getline(lnum)
- let add = ""
- if line == ''
- let add = ' '
- elseif line =~ '^\s*\(#[^{].*\)\=$'
- let add = line
- elseif line =~ '\<create_table\>'
- let add = s:migspc(line)."drop_table".s:mextargs(line,1).s:mkeep(line)
- let lnum = s:endof(lnum)
- elseif line =~ '\<drop_table\>'
- let add = s:sub(line,'<drop_table>\s*\(=\s*([^,){ ]*).*','create_table \1 do |t|'."\n".matchstr(line,'^\s*').'end').s:mkeep(line)
- elseif line =~ '\<add_column\>'
- let add = s:migspc(line).'remove_column'.s:mextargs(line,2).s:mkeep(line)
- elseif line =~ '\<remove_column\>'
- let add = s:sub(line,'<remove_column>','add_column')
- elseif line =~ '\<add_index\>'
- let add = s:migspc(line).'remove_index'.s:mextargs(line,1)
- let mat = matchstr(line,':name\s*=>\s*\zs[^ ,)]*')
- if mat != ''
- let add = s:sub(add,'\)=$',', :name => '.mat.'&')
- else
- let mat = matchstr(line,'\<add_index\>[^,]*,\s*\zs\%(\[[^]]*\]\|[:"'."'".']\w*["'."'".']\=\)')
- if mat != ''
- let add = s:sub(add,'\)=$',', :column => '.mat.'&')
- endif
- endif
- let add .= s:mkeep(line)
- elseif line =~ '\<remove_index\>'
- let add = s:sub(s:sub(line,'<remove_index','add_index'),':column\s*\=\>\s*','')
- elseif line =~ '\<rename_\%(table\|column\|index\)\>'
- let add = s:sub(line,'<rename_%(table\s*\(=\s*|%(column|index)\s*\(=\s*[^,]*,\s*)\zs([^,]*)(,\s*)([^,]*)','\3\2\1')
- elseif line =~ '\<change_column\>'
- let add = s:migspc(line).'change_column'.s:mextargs(line,2).s:mkeep(line)
- elseif line =~ '\<change_column_default\>'
- let add = s:migspc(line).'change_column_default'.s:mextargs(line,2).s:mkeep(line)
- elseif line =~ '\.update_all(\(["'."'".']\).*\1)$' || line =~ '\.update_all \(["'."'".']\).*\1$'
- " .update_all('a = b') => .update_all('b = a')
- let pre = matchstr(line,'^.*\.update_all[( ][}'."'".'"]')
- let post = matchstr(line,'["'."'".'])\=$')
- let mat = strpart(line,strlen(pre),strlen(line)-strlen(pre)-strlen(post))
- let mat = s:gsub(','.mat.',','%(,\s*)@<=([^ ,=]{-})(\s*\=\s*)([^,=]{-})%(\s*,)@=','\3\2\1')
- let add = pre.s:sub(s:sub(mat,'^,',''),',$','').post
- elseif line =~ '^s\*\%(if\|unless\|while\|until\|for\)\>'
- let lnum = s:endof(lnum)
- endif
- if lnum == 0
- return -1
- endif
- if add == ""
- let add = s:sub(line,'^\s*\zs.*','raise ActiveRecord::IrreversibleMigration')
- elseif add == " "
- let add = ""
- endif
- let str = add."\n".str
- let lnum += 1
- endwhile
- let str = s:gsub(str,'(\s*raise ActiveRecord::IrreversibleMigration\n)+','\1')
- return str
-endfunction
-
-function! s:Invert(bang)
- let err = "Could not parse method"
- let src = "up"
- let dst = "down"
- let beg = search('\%('.&l:define.'\).*'.src.'\>',"w")
- let end = s:endof(beg)
- if beg + 1 == end
- let src = "down"
- let dst = "up"
- let beg = search('\%('.&l:define.'\).*'.src.'\>',"w")
- let end = s:endof(beg)
- endif
- if !beg || !end
- return s:error(err)
- endif
- let str = s:invertrange(beg+1,end-1)
- if str == -1
- return s:error(err)
- endif
- let beg = search('\%('.&l:define.'\).*'.dst.'\>',"w")
- let end = s:endof(beg)
- if !beg || !end
- return s:error(err)
- endif
- if foldclosed(beg) > 0
- exe beg."foldopen!"
- endif
- if beg + 1 < end
- exe (beg+1).",".(end-1)."delete _"
- endif
- if str != ''
- exe beg.'put =str'
- exe 1+beg
- endif
-endfunction
-
-" }}}1
-" Cache {{{1
-
-let s:cache_prototype = {'dict': {}}
-
-function! s:cache_clear(...) dict
- if a:0 == 0
- let self.dict = {}
- elseif has_key(self,'dict') && has_key(self.dict,a:1)
- unlet! self.dict[a:1]
- endif
-endfunction
-
-function! rails#cache_clear(...)
- if exists('b:rails_root')
- return call(rails#app().cache.clear,a:000,rails#app().cache)
- endif
-endfunction
-
-function! s:cache_get(...) dict
- if a:0 == 1
- return self.dict[a:1]
- else
- return self.dict
- endif
-endfunction
-
-function! s:cache_has(key) dict
- return has_key(self.dict,a:key)
-endfunction
-
-function! s:cache_needs(key) dict
- return !has_key(self.dict,a:key)
-endfunction
-
-function! s:cache_set(key,value) dict
- let self.dict[a:key] = a:value
-endfunction
-
-call s:add_methods('cache', ['clear','needs','has','get','set'])
-
-let s:app_prototype.cache = s:cache_prototype
-
-" }}}1
-" Syntax {{{1
-
-function! s:resetomnicomplete()
- if exists("+completefunc") && &completefunc == 'syntaxcomplete#Complete'
- if exists("g:loaded_syntax_completion")
- " Ugly but necessary, until we have our own completion
- unlet g:loaded_syntax_completion
- silent! delfunction syntaxcomplete#Complete
- endif
- endif
-endfunction
-
-function! s:helpermethods()
- return ""
- \."action_name atom_feed audio_path audio_tag auto_discovery_link_tag "
- \."button_tag button_to button_to_function "
- \."cache capture cdata_section check_box check_box_tag collection_select concat content_for content_tag content_tag_for controller controller_name controller_path convert_to_model cookies csrf_meta_tag csrf_meta_tags current_cycle cycle "
- \."date_select datetime_select debug distance_of_time_in_words distance_of_time_in_words_to_now div_for dom_class dom_id "
- \."email_field email_field_tag escape_javascript escape_once excerpt "
- \."favicon_link_tag field_set_tag fields_for file_field file_field_tag flash form_for form_tag "
- \."grouped_collection_select grouped_options_for_select "
- \."headers hidden_field hidden_field_tag highlight "
- \."image_alt image_path image_submit_tag image_tag "
- \."j javascript_cdata_section javascript_include_tag javascript_path javascript_tag "
- \."l label label_tag link_to link_to_function link_to_if link_to_unless link_to_unless_current localize logger "
- \."mail_to "
- \."number_field number_field_tag number_to_currency number_to_human number_to_human_size number_to_percentage number_to_phone number_with_delimiter number_with_precision "
- \."option_groups_from_collection_for_select options_for_select options_from_collection_for_select "
- \."params password_field password_field_tag path_to_audio path_to_image path_to_javascript path_to_stylesheet path_to_video phone_field phone_field_tag pluralize provide "
- \."radio_button radio_button_tag range_field range_field_tag raw render request request_forgery_protection_token reset_cycle response "
- \."safe_concat safe_join sanitize sanitize_css search_field search_field_tag select select_date select_datetime select_day select_hour select_minute select_month select_second select_tag select_time select_year session simple_format strip_links strip_tags stylesheet_link_tag stylesheet_path submit_tag "
- \."t tag telephone_field telephone_field_tag text_area text_area_tag text_field text_field_tag time_ago_in_words time_select time_tag time_zone_options_for_select time_zone_select translate truncate "
- \."url_field url_field_tag url_for url_options "
- \."video_path video_tag "
- \."word_wrap"
-endfunction
-
-function! s:app_user_classes() dict
- if self.cache.needs("user_classes")
- let controllers = self.relglob("app/controllers/","**/*",".rb")
- call map(controllers,'v:val == "application" ? v:val."_controller" : v:val')
- let classes =
- \ self.relglob("app/models/","**/*",".rb") +
- \ controllers +
- \ self.relglob("app/helpers/","**/*",".rb") +
- \ self.relglob("lib/","**/*",".rb")
- call map(classes,'rails#camelize(v:val)')
- call self.cache.set("user_classes",classes)
- endif
- return self.cache.get('user_classes')
-endfunction
-
-function! s:app_user_assertions() dict
- if self.cache.needs("user_assertions")
- if self.has_file("test/test_helper.rb")
- let assertions = map(filter(s:readfile(self.path("test/test_helper.rb")),'v:val =~ "^ def assert_"'),'matchstr(v:val,"^ def \\zsassert_\\w\\+")')
- else
- let assertions = []
- endif
- call self.cache.set("user_assertions",assertions)
- endif
- return self.cache.get('user_assertions')
-endfunction
-
-call s:add_methods('app', ['user_classes','user_assertions'])
-
-function! s:BufSyntax()
- if (!exists("g:rails_syntax") || g:rails_syntax)
- let buffer = rails#buffer()
- let s:javascript_functions = "$ $$ $A $F $H $R $w jQuery"
- let classes = s:gsub(join(rails#app().user_classes(),' '),'::',' ')
- if &syntax == 'ruby'
- if classes != ''
- exe "syn keyword rubyRailsUserClass ".classes." containedin=rubyClassDeclaration,rubyModuleDeclaration,rubyClass,rubyModule"
- endif
- if buffer.type_name() == ''
- syn keyword rubyRailsMethod params request response session headers cookies flash
- endif
- if buffer.type_name('api')
- syn keyword rubyRailsAPIMethod api_method inflect_names
- endif
- if buffer.type_name() ==# 'model' || buffer.type_name('model-arb')
- syn keyword rubyRailsARMethod default_scope named_scope scope serialize
- syn keyword rubyRailsARAssociationMethod belongs_to has_one has_many has_and_belongs_to_many composed_of accepts_nested_attributes_for
- syn keyword rubyRailsARCallbackMethod before_create before_destroy before_save before_update before_validation before_validation_on_create before_validation_on_update
- syn keyword rubyRailsARCallbackMethod after_create after_destroy after_save after_update after_validation after_validation_on_create after_validation_on_update
- syn keyword rubyRailsARCallbackMethod around_create around_destroy around_save around_update
- syn keyword rubyRailsARCallbackMethod after_commit after_find after_initialize after_rollback after_touch
- syn keyword rubyRailsARClassMethod attr_accessible attr_protected attr_readonly establish_connection set_inheritance_column set_locking_column set_primary_key set_sequence_name set_table_name
- syn keyword rubyRailsARValidationMethod validate validates validate_on_create validate_on_update validates_acceptance_of validates_associated validates_confirmation_of validates_each validates_exclusion_of validates_format_of validates_inclusion_of validates_length_of validates_numericality_of validates_presence_of validates_size_of validates_uniqueness_of
- syn keyword rubyRailsMethod logger
- endif
- if buffer.type_name('model-aro')
- syn keyword rubyRailsARMethod observe
- endif
- if buffer.type_name('mailer')
- syn keyword rubyRailsMethod logger url_for polymorphic_path polymorphic_url
- syn keyword rubyRailsRenderMethod mail render
- syn keyword rubyRailsControllerMethod attachments default helper helper_attr helper_method
- endif
- if buffer.type_name('helper','view')
- syn keyword rubyRailsViewMethod polymorphic_path polymorphic_url
- exe "syn keyword rubyRailsHelperMethod ".s:gsub(s:helpermethods(),'<%(content_for|select)\s+','')
- syn match rubyRailsHelperMethod '\<select\>\%(\s*{\|\s*do\>\|\s*(\=\s*&\)\@!'
- syn match rubyRailsHelperMethod '\<\%(content_for?\=\|current_page?\)'
- syn match rubyRailsViewMethod '\.\@<!\<\(h\|html_escape\|u\|url_encode\)\>'
- if buffer.type_name('view-partial')
- syn keyword rubyRailsMethod local_assigns
- endif
- elseif buffer.type_name('controller')
- syn keyword rubyRailsMethod params request response session headers cookies flash
- syn keyword rubyRailsRenderMethod render
- syn keyword rubyRailsMethod logger polymorphic_path polymorphic_url
- syn keyword rubyRailsControllerMethod helper helper_attr helper_method filter layout url_for serialize exempt_from_layout filter_parameter_logging hide_action cache_sweeper protect_from_forgery caches_page cache_page caches_action expire_page expire_action rescue_from
- syn keyword rubyRailsRenderMethod head redirect_to render_to_string respond_with
- syn match rubyRailsRenderMethod '\<respond_to\>?\@!'
- syn keyword rubyRailsFilterMethod before_filter append_before_filter prepend_before_filter after_filter append_after_filter prepend_after_filter around_filter append_around_filter prepend_around_filter skip_before_filter skip_after_filter
- syn keyword rubyRailsFilterMethod verify
- endif
- if buffer.type_name('db-migration','db-schema')
- syn keyword rubyRailsMigrationMethod create_table change_table drop_table rename_table add_column rename_column change_column change_column_default remove_column add_index remove_index rename_index execute
- endif
- if buffer.type_name('test')
- if !empty(rails#app().user_assertions())
- exe "syn keyword rubyRailsUserMethod ".join(rails#app().user_assertions())
- endif
- syn keyword rubyRailsTestMethod add_assertion assert assert_block assert_equal assert_in_delta assert_instance_of assert_kind_of assert_match assert_nil assert_no_match assert_not_equal assert_not_nil assert_not_same assert_nothing_raised assert_nothing_thrown assert_operator assert_raise assert_respond_to assert_same assert_send assert_throws assert_recognizes assert_generates assert_routing flunk fixtures fixture_path use_transactional_fixtures use_instantiated_fixtures assert_difference assert_no_difference assert_valid
- syn keyword rubyRailsTestMethod test setup teardown
- if !buffer.type_name('test-unit')
- syn match rubyRailsTestControllerMethod '\.\@<!\<\%(get\|post\|put\|delete\|head\|process\|assigns\)\>'
- syn keyword rubyRailsTestControllerMethod get_via_redirect post_via_redirect put_via_redirect delete_via_redirect request_via_redirect
- syn keyword rubyRailsTestControllerMethod assert_response assert_redirected_to assert_template assert_recognizes assert_generates assert_routing assert_dom_equal assert_dom_not_equal assert_select assert_select_rjs assert_select_encoded assert_select_email assert_tag assert_no_tag
- endif
- elseif buffer.type_name('spec')
- syn keyword rubyRailsTestMethod describe context it its specify shared_examples_for it_should_behave_like before after around subject fixtures controller_name helper_name
- syn match rubyRailsTestMethod '\<let\>!\='
- syn keyword rubyRailsTestMethod violated pending expect double mock mock_model stub_model
- syn match rubyRailsTestMethod '\.\@<!\<stub\>!\@!'
- if !buffer.type_name('spec-model')
- syn match rubyRailsTestControllerMethod '\.\@<!\<\%(get\|post\|put\|delete\|head\|process\|assigns\)\>'
- syn keyword rubyRailsTestControllerMethod integrate_views
- syn keyword rubyRailsMethod params request response session flash
- syn keyword rubyRailsMethod polymorphic_path polymorphic_url
- endif
- endif
- if buffer.type_name('task')
- syn match rubyRailsRakeMethod '^\s*\zs\%(task\|file\|namespace\|desc\|before\|after\|on\)\>\%(\s*=\)\@!'
- endif
- if buffer.type_name('model-awss')
- syn keyword rubyRailsMethod member
- endif
- if buffer.type_name('config-routes')
- syn match rubyRailsMethod '\.\zs\%(connect\|named_route\)\>'
- syn keyword rubyRailsMethod match get put post delete redirect root resource resources collection member nested scope namespace controller constraints
- endif
- syn keyword rubyRailsMethod debugger
- syn keyword rubyRailsMethod alias_attribute alias_method_chain attr_accessor_with_default attr_internal attr_internal_accessor attr_internal_reader attr_internal_writer delegate mattr_accessor mattr_reader mattr_writer superclass_delegating_accessor superclass_delegating_reader superclass_delegating_writer
- syn keyword rubyRailsMethod cattr_accessor cattr_reader cattr_writer class_inheritable_accessor class_inheritable_array class_inheritable_array_writer class_inheritable_hash class_inheritable_hash_writer class_inheritable_option class_inheritable_reader class_inheritable_writer inheritable_attributes read_inheritable_attribute reset_inheritable_attributes write_inheritable_array write_inheritable_attribute write_inheritable_hash
- syn keyword rubyRailsInclude require_dependency
-
- syn region rubyString matchgroup=rubyStringDelimiter start=+\%(:order\s*=>\s*\)\@<="+ skip=+\\\\\|\\"+ end=+"+ contains=@rubyStringSpecial,railsOrderSpecial
- syn region rubyString matchgroup=rubyStringDelimiter start=+\%(:order\s*=>\s*\)\@<='+ skip=+\\\\\|\\'+ end=+'+ contains=@rubyStringSpecial,railsOrderSpecial
- syn match railsOrderSpecial +\c\<\%(DE\|A\)SC\>+ contained
- syn region rubyString matchgroup=rubyStringDelimiter start=+\%(:conditions\s*=>\s*\[\s*\)\@<="+ skip=+\\\\\|\\"+ end=+"+ contains=@rubyStringSpecial,railsConditionsSpecial
- syn region rubyString matchgroup=rubyStringDelimiter start=+\%(:conditions\s*=>\s*\[\s*\)\@<='+ skip=+\\\\\|\\'+ end=+'+ contains=@rubyStringSpecial,railsConditionsSpecial
- syn match railsConditionsSpecial +?\|:\h\w*+ contained
- syn cluster rubyNotTop add=railsOrderSpecial,railsConditionsSpecial
-
- " XHTML highlighting inside %Q<>
- unlet! b:current_syntax
- let removenorend = !exists("g:html_no_rendering")
- let g:html_no_rendering = 1
- syn include @htmlTop syntax/xhtml.vim
- if removenorend
- unlet! g:html_no_rendering
- endif
- let b:current_syntax = "ruby"
- " Restore syn sync, as best we can
- if !exists("g:ruby_minlines")
- let g:ruby_minlines = 50
- endif
- syn sync fromstart
- exe "syn sync minlines=" . g:ruby_minlines
- syn case match
- syn region rubyString matchgroup=rubyStringDelimiter start=+%Q\=<+ end=+>+ contains=@htmlTop,@rubyStringSpecial
- syn cluster htmlArgCluster add=@rubyStringSpecial
- syn cluster htmlPreProc add=@rubyStringSpecial
-
- elseif &syntax =~# '^eruby\>' || &syntax == 'haml'
- syn case match
- if classes != ''
- exe 'syn keyword '.&syntax.'RailsUserClass '.classes.' contained containedin=@'.&syntax.'RailsRegions'
- endif
- if &syntax == 'haml'
- exe 'syn cluster hamlRailsRegions contains=hamlRubyCodeIncluded,hamlRubyCode,hamlRubyHash,@hamlEmbeddedRuby,rubyInterpolation'
- else
- exe 'syn cluster erubyRailsRegions contains=erubyOneLiner,erubyBlock,erubyExpression,rubyInterpolation'
- endif
- exe 'syn keyword '.&syntax.'RailsHelperMethod '.s:gsub(s:helpermethods(),'<%(content_for|select)\s+','').' contained containedin=@'.&syntax.'RailsRegions'
- exe 'syn match '.&syntax.'RailsHelperMethod "\<select\>\%(\s*{\|\s*do\>\|\s*(\=\s*&\)\@!" contained containedin=@'.&syntax.'RailsRegions'
- exe 'syn match '.&syntax.'RailsHelperMethod "\<\%(content_for?\=\|current_page?\)" contained containedin=@'.&syntax.'RailsRegions'
- exe 'syn keyword '.&syntax.'RailsMethod debugger polymorphic_path polymorphic_url contained containedin=@'.&syntax.'RailsRegions'
- exe 'syn match '.&syntax.'RailsViewMethod "\.\@<!\<\(h\|html_escape\|u\|url_encode\)\>" contained containedin=@'.&syntax.'RailsRegions'
- if buffer.type_name('view-partial')
- exe 'syn keyword '.&syntax.'RailsMethod local_assigns contained containedin=@'.&syntax.'RailsRegions'
- endif
- exe 'syn keyword '.&syntax.'RailsRenderMethod render contained containedin=@'.&syntax.'RailsRegions'
- exe 'syn case match'
- set isk+=$
- exe 'syn keyword javascriptRailsFunction contained '.s:javascript_functions
- exe 'syn cluster htmlJavaScript add=javascriptRailsFunction'
- elseif &syntax == "yaml"
- syn case match
- " Modeled after syntax/eruby.vim
- unlet! b:current_syntax
- let g:main_syntax = 'eruby'
- syn include @rubyTop syntax/ruby.vim
- unlet g:main_syntax
- syn cluster yamlRailsRegions contains=yamlRailsOneLiner,yamlRailsBlock,yamlRailsExpression
- syn region yamlRailsOneLiner matchgroup=yamlRailsDelimiter start="^%%\@!" end="$" contains=@rubyRailsTop containedin=ALLBUT,@yamlRailsRegions,yamlRailsComment keepend oneline
- syn region yamlRailsBlock matchgroup=yamlRailsDelimiter start="<%%\@!" end="%>" contains=@rubyTop containedin=ALLBUT,@yamlRailsRegions,yamlRailsComment
- syn region yamlRailsExpression matchgroup=yamlRailsDelimiter start="<%=" end="%>" contains=@rubyTop containedin=ALLBUT,@yamlRailsRegions,yamlRailsComment
- syn region yamlRailsComment matchgroup=yamlRailsDelimiter start="<%#" end="%>" contains=rubyTodo,@Spell containedin=ALLBUT,@yamlRailsRegions,yamlRailsComment keepend
- syn match yamlRailsMethod '\.\@<!\<\(h\|html_escape\|u\|url_encode\)\>' contained containedin=@yamlRailsRegions
- if classes != ''
- exe "syn keyword yamlRailsUserClass ".classes." contained containedin=@yamlRailsRegions"
- endif
- let b:current_syntax = "yaml"
- elseif &syntax == "html"
- syn case match
- set isk+=$
- exe "syn keyword javascriptRailsFunction contained ".s:javascript_functions
- syn cluster htmlJavaScript add=javascriptRailsFunction
- elseif &syntax == "javascript" || &syntax == "coffee"
- " The syntax file included with Vim incorrectly sets syn case ignore.
- syn case match
- set isk+=$
- exe "syn keyword javascriptRailsFunction ".s:javascript_functions
-
- endif
- endif
- call s:HiDefaults()
-endfunction
-
-function! s:HiDefaults()
- hi def link rubyRailsAPIMethod rubyRailsMethod
- hi def link rubyRailsARAssociationMethod rubyRailsARMethod
- hi def link rubyRailsARCallbackMethod rubyRailsARMethod
- hi def link rubyRailsARClassMethod rubyRailsARMethod
- hi def link rubyRailsARValidationMethod rubyRailsARMethod
- hi def link rubyRailsARMethod rubyRailsMethod
- hi def link rubyRailsRenderMethod rubyRailsMethod
- hi def link rubyRailsHelperMethod rubyRailsMethod
- hi def link rubyRailsViewMethod rubyRailsMethod
- hi def link rubyRailsMigrationMethod rubyRailsMethod
- hi def link rubyRailsControllerMethod rubyRailsMethod
- hi def link rubyRailsFilterMethod rubyRailsMethod
- hi def link rubyRailsTestControllerMethod rubyRailsTestMethod
- hi def link rubyRailsTestMethod rubyRailsMethod
- hi def link rubyRailsRakeMethod rubyRailsMethod
- hi def link rubyRailsMethod railsMethod
- hi def link rubyRailsInclude rubyInclude
- hi def link rubyRailsUserClass railsUserClass
- hi def link rubyRailsUserMethod railsUserMethod
- hi def link erubyRailsHelperMethod erubyRailsMethod
- hi def link erubyRailsViewMethod erubyRailsMethod
- hi def link erubyRailsRenderMethod erubyRailsMethod
- hi def link erubyRailsMethod railsMethod
- hi def link erubyRailsUserMethod railsUserMethod
- hi def link erubyRailsUserClass railsUserClass
- hi def link hamlRailsHelperMethod hamlRailsMethod
- hi def link hamlRailsViewMethod hamlRailsMethod
- hi def link hamlRailsRenderMethod hamlRailsMethod
- hi def link hamlRailsMethod railsMethod
- hi def link hamlRailsUserMethod railsUserMethod
- hi def link hamlRailsUserClass railsUserClass
- hi def link railsUserMethod railsMethod
- hi def link yamlRailsDelimiter Delimiter
- hi def link yamlRailsMethod railsMethod
- hi def link yamlRailsComment Comment
- hi def link yamlRailsUserClass railsUserClass
- hi def link yamlRailsUserMethod railsUserMethod
- hi def link javascriptRailsFunction railsMethod
- hi def link railsUserClass railsClass
- hi def link railsMethod Function
- hi def link railsClass Type
- hi def link railsOrderSpecial railsStringSpecial
- hi def link railsConditionsSpecial railsStringSpecial
- hi def link railsStringSpecial Identifier
-endfunction
-
-function! rails#log_syntax()
- if has('conceal')
- syn match railslogEscape '\e\[[0-9;]*m' conceal
- syn match railslogEscapeMN '\e\[[0-9;]*m' conceal nextgroup=railslogModelNum,railslogEscapeMN skipwhite contained
- syn match railslogEscapeSQL '\e\[[0-9;]*m' conceal nextgroup=railslogSQL,railslogEscapeSQL skipwhite contained
- else
- syn match railslogEscape '\e\[[0-9;]*m'
- syn match railslogEscapeMN '\e\[[0-9;]*m' nextgroup=railslogModelNum,railslogEscapeMN skipwhite contained
- syn match railslogEscapeSQL '\e\[[0-9;]*m' nextgroup=railslogSQL,railslogEscapeSQL skipwhite contained
- endif
- syn match railslogRender '\%(^\s*\%(\e\[[0-9;]*m\)\=\)\@<=\%(Processing\|Rendering\|Rendered\|Redirected\|Completed\)\>'
- syn match railslogComment '^\s*# .*'
- syn match railslogModel '\%(^\s*\%(\e\[[0-9;]*m\)\=\)\@<=\u\%(\w\|:\)* \%(Load\%( Including Associations\| IDs For Limited Eager Loading\)\=\|Columns\|Count\|Create\|Update\|Destroy\|Delete all\)\>' skipwhite nextgroup=railslogModelNum,railslogEscapeMN
- syn match railslogModel '\%(^\s*\%(\e\[[0-9;]*m\)\=\)\@<=SQL\>' skipwhite nextgroup=railslogModelNum,railslogEscapeMN
- syn region railslogModelNum start='(' end=')' contains=railslogNumber contained skipwhite nextgroup=railslogSQL,railslogEscapeSQL
- syn match railslogSQL '\u[^\e]*' contained
- " Destroy generates multiline SQL, ugh
- syn match railslogSQL '\%(^ \%(\e\[[0-9;]*m\)\=\)\@<=\%(FROM\|WHERE\|ON\|AND\|OR\|ORDER\) .*$'
- syn match railslogNumber '\<\d\+\>%'
- syn match railslogNumber '[ (]\@<=\<\d\+\.\d\+\>\.\@!'
- syn region railslogString start='"' skip='\\"' end='"' oneline contained
- syn region railslogHash start='{' end='}' oneline contains=railslogHash,railslogString
- syn match railslogIP '\<\d\{1,3\}\%(\.\d\{1,3}\)\{3\}\>'
- syn match railslogTimestamp '\<\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\>'
- syn match railslogSessionID '\<\x\{32\}\>'
- syn match railslogIdentifier '^\s*\%(Session ID\|Parameters\)\ze:'
- syn match railslogSuccess '\<2\d\d \u[A-Za-z0-9 ]*\>'
- syn match railslogRedirect '\<3\d\d \u[A-Za-z0-9 ]*\>'
- syn match railslogError '\<[45]\d\d \u[A-Za-z0-9 ]*\>'
- syn match railslogError '^DEPRECATION WARNING\>'
- syn keyword railslogHTTP OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT
- syn region railslogStackTrace start=":\d\+:in `\w\+'$" end="^\s*$" keepend fold
- hi def link railslogEscapeMN railslogEscape
- hi def link railslogEscapeSQL railslogEscape
- hi def link railslogEscape Ignore
- hi def link railslogComment Comment
- hi def link railslogRender Keyword
- hi def link railslogModel Type
- hi def link railslogSQL PreProc
- hi def link railslogNumber Number
- hi def link railslogString String
- hi def link railslogSessionID Constant
- hi def link railslogIdentifier Identifier
- hi def link railslogRedirect railslogSuccess
- hi def link railslogSuccess Special
- hi def link railslogError Error
- hi def link railslogHTTP Special
-endfunction
-
-" }}}1
-" Mappings {{{1
-
-function! s:BufMappings()
- nnoremap <buffer> <silent> <Plug>RailsFind :<C-U>call <SID>Find(v:count1,'E')<CR>
- nnoremap <buffer> <silent> <Plug>RailsSplitFind :<C-U>call <SID>Find(v:count1,'S')<CR>
- nnoremap <buffer> <silent> <Plug>RailsVSplitFind :<C-U>call <SID>Find(v:count1,'V')<CR>
- nnoremap <buffer> <silent> <Plug>RailsTabFind :<C-U>call <SID>Find(v:count1,'T')<CR>
- if g:rails_mappings
- if !hasmapto("<Plug>RailsFind")
- nmap <buffer> gf <Plug>RailsFind
- endif
- if !hasmapto("<Plug>RailsSplitFind")
- nmap <buffer> <C-W>f <Plug>RailsSplitFind
- endif
- if !hasmapto("<Plug>RailsTabFind")
- nmap <buffer> <C-W>gf <Plug>RailsTabFind
- endif
- if exists("$CREAM")
- imap <buffer> <C-CR> <C-O><Plug>RailsFind
- imap <buffer> <M-[> <C-O><Plug>RailsAlternate
- imap <buffer> <M-]> <C-O><Plug>RailsRelated
- endif
- endif
- " SelectBuf you're a dirty hack
- let v:errmsg = ""
-endfunction
-
-" }}}1
-" Database {{{1
-
-function! s:extractdbvar(str,arg)
- return matchstr("\n".a:str."\n",'\n'.a:arg.'=\zs.\{-\}\ze\n')
-endfunction
-
-function! s:app_dbext_settings(environment) dict
- if self.cache.needs('dbext_settings')
- call self.cache.set('dbext_settings',{})
- endif
- let cache = self.cache.get('dbext_settings')
- if !has_key(cache,a:environment)
- let dict = {}
- if self.has_file("config/database.yml")
- let cmdb = 'require %{yaml}; File.open(%q{'.self.path().'/config/database.yml}) {|f| y = YAML::load(f); e = y[%{'
- let cmde = '}]; i=0; e=y[e] while e.respond_to?(:to_str) && (i+=1)<16; e.each{|k,v|puts k.to_s+%{=}+v.to_s}}'
- let out = self.lightweight_ruby_eval(cmdb.a:environment.cmde)
- let adapter = s:extractdbvar(out,'adapter')
- let adapter = get({'mysql2': 'mysql', 'postgresql': 'pgsql', 'sqlite3': 'sqlite', 'sqlserver': 'sqlsrv', 'sybase': 'asa', 'oracle': 'ora'},adapter,adapter)
- let dict['type'] = toupper(adapter)
- let dict['user'] = s:extractdbvar(out,'username')
- let dict['passwd'] = s:extractdbvar(out,'password')
- if dict['passwd'] == '' && adapter == 'mysql'
- " Hack to override password from .my.cnf
- let dict['extra'] = ' --password='
- else
- let dict['extra'] = ''
- endif
- let dict['dbname'] = s:extractdbvar(out,'database')
- if dict['dbname'] == ''
- let dict['dbname'] = s:extractdbvar(out,'dbfile')
- endif
- if dict['dbname'] != '' && dict['dbname'] !~ '^:' && adapter =~? '^sqlite'
- let dict['dbname'] = self.path(dict['dbname'])
- endif
- let dict['profile'] = ''
- if adapter == 'ora'
- let dict['srvname'] = s:extractdbvar(out,'database')
- else
- let dict['srvname'] = s:extractdbvar(out,'host')
- endif
- let dict['host'] = s:extractdbvar(out,'host')
- let dict['port'] = s:extractdbvar(out,'port')
- let dict['dsnname'] = s:extractdbvar(out,'dsn')
- if dict['host'] =~? '^\cDBI:'
- if dict['host'] =~? '\c\<Trusted[_ ]Connection\s*=\s*yes\>'
- let dict['integratedlogin'] = 1
- endif
- let dict['host'] = matchstr(dict['host'],'\c\<\%(Server\|Data Source\)\s*=\s*\zs[^;]*')
- endif
- call filter(dict,'v:val != ""')
- endif
- let cache[a:environment] = dict
- endif
- return cache[a:environment]
-endfunction
-
-function! s:BufDatabase(...)
- if exists("s:lock_database") || !exists('g:loaded_dbext') || !exists('b:rails_root')
- return
- endif
- let self = rails#app()
- let s:lock_database = 1
- if (a:0 && a:1 > 1)
- call self.cache.clear('dbext_settings')
- endif
- if (a:0 > 1 && a:2 != '')
- let env = a:2
- else
- let env = s:environment()
- endif
- if (!self.cache.has('dbext_settings') || !has_key(self.cache.get('dbext_settings'),env)) && (a:0 ? a:1 : 0) <= 0
- unlet! s:lock_database
- return
- endif
- let dict = self.dbext_settings(env)
- for key in ['type', 'profile', 'bin', 'user', 'passwd', 'dbname', 'srvname', 'host', 'port', 'dsnname', 'extra', 'integratedlogin']
- let b:dbext_{key} = get(dict,key,'')
- endfor
- if b:dbext_type == 'PGSQL'
- let $PGPASSWORD = b:dbext_passwd
- elseif exists('$PGPASSWORD')
- let $PGPASSWORD = ''
- endif
- unlet! s:lock_database
-endfunction
-
-call s:add_methods('app', ['dbext_settings'])
-
-" }}}1
-" Abbreviations {{{1
-
-function! s:selectiveexpand(pat,good,default,...)
- if a:0 > 0
- let nd = a:1
- else
- let nd = ""
- endif
- let c = nr2char(getchar(0))
- let good = a:good
- if c == "" " ^]
- return s:sub(good.(a:0 ? " ".a:1 : ''),'\s+$','')
- elseif c == "\t"
- return good.(a:0 ? " ".a:1 : '')
- elseif c =~ a:pat
- return good.c.(a:0 ? a:1 : '')
- else
- return a:default.c
- endif
-endfunction
-
-function! s:TheCWord()
- let l = s:linepeak()
- if l =~ '\<\%(find\|first\|last\|all\|paginate\)\>'
- return s:selectiveexpand('..',':conditions => ',':c')
- elseif l =~ '\<render\s*(\=\s*:partial\s*=>\s*'
- return s:selectiveexpand('..',':collection => ',':c')
- elseif l =~ '\<\%(url_for\|link_to\|form_tag\)\>' || l =~ ':url\s*=>\s*{\s*'
- return s:selectiveexpand('..',':controller => ',':c')
- else
- return s:selectiveexpand('..',':conditions => ',':c')
- endif
-endfunction
-
-function! s:AddSelectiveExpand(abbr,pat,expn,...)
- let expn = s:gsub(s:gsub(a:expn ,'[\"|]','\\&'),'\<','\\<Lt>')
- let expn2 = s:gsub(s:gsub(a:0 ? a:1 : '','[\"|]','\\&'),'\<','\\<Lt>')
- if a:0
- exe "inoreabbrev <buffer> <silent> ".a:abbr." <C-R>=<SID>selectiveexpand(".string(a:pat).",\"".expn."\",".string(a:abbr).",\"".expn2."\")<CR>"
- else
- exe "inoreabbrev <buffer> <silent> ".a:abbr." <C-R>=<SID>selectiveexpand(".string(a:pat).",\"".expn."\",".string(a:abbr).")<CR>"
- endif
-endfunction
-
-function! s:AddTabExpand(abbr,expn)
- call s:AddSelectiveExpand(a:abbr,'..',a:expn)
-endfunction
-
-function! s:AddBracketExpand(abbr,expn)
- call s:AddSelectiveExpand(a:abbr,'[[.]',a:expn)
-endfunction
-
-function! s:AddColonExpand(abbr,expn)
- call s:AddSelectiveExpand(a:abbr,'[:.]',a:expn)
-endfunction
-
-function! s:AddParenExpand(abbr,expn,...)
- if a:0
- call s:AddSelectiveExpand(a:abbr,'(',a:expn,a:1)
- else
- call s:AddSelectiveExpand(a:abbr,'(',a:expn,'')
- endif
-endfunction
-
-function! s:BufAbbreviations()
- command! -buffer -bar -nargs=* -bang Rabbrev :call s:Abbrev(<bang>0,<f-args>)
- " Some of these were cherry picked from the TextMate snippets
- if g:rails_abbreviations
- let buffer = rails#buffer()
- " Limit to the right filetypes. But error on the liberal side
- if buffer.type_name('controller','view','helper','test-functional','test-integration')
- Rabbrev pa[ params
- Rabbrev rq[ request
- Rabbrev rs[ response
- Rabbrev se[ session
- Rabbrev hd[ headers
- Rabbrev coo[ cookies
- Rabbrev fl[ flash
- Rabbrev rr( render
- Rabbrev ra( render :action\ =>\
- Rabbrev rc( render :controller\ =>\
- Rabbrev rf( render :file\ =>\
- Rabbrev ri( render :inline\ =>\
- Rabbrev rj( render :json\ =>\
- Rabbrev rl( render :layout\ =>\
- Rabbrev rp( render :partial\ =>\
- Rabbrev rt( render :text\ =>\
- Rabbrev rx( render :xml\ =>\
- endif
- if buffer.type_name('view','helper')
- Rabbrev dotiw distance_of_time_in_words
- Rabbrev taiw time_ago_in_words
- endif
- if buffer.type_name('controller')
- Rabbrev re( redirect_to
- Rabbrev rea( redirect_to :action\ =>\
- Rabbrev rec( redirect_to :controller\ =>\
- Rabbrev rst( respond_to
- endif
- if buffer.type_name() ==# 'model' || buffer.type_name('model-arb')
- Rabbrev bt( belongs_to
- Rabbrev ho( has_one
- Rabbrev hm( has_many
- Rabbrev habtm( has_and_belongs_to_many
- Rabbrev co( composed_of
- Rabbrev va( validates_associated
- Rabbrev vb( validates_acceptance_of
- Rabbrev vc( validates_confirmation_of
- Rabbrev ve( validates_exclusion_of
- Rabbrev vf( validates_format_of
- Rabbrev vi( validates_inclusion_of
- Rabbrev vl( validates_length_of
- Rabbrev vn( validates_numericality_of
- Rabbrev vp( validates_presence_of
- Rabbrev vu( validates_uniqueness_of
- endif
- if buffer.type_name('db-migration','db-schema')
- Rabbrev mac( add_column
- Rabbrev mrnc( rename_column
- Rabbrev mrc( remove_column
- Rabbrev mct( create_table
- Rabbrev mcht( change_table
- Rabbrev mrnt( rename_table
- Rabbrev mdt( drop_table
- Rabbrev mcc( t.column
- endif
- if buffer.type_name('test')
- Rabbrev ase( assert_equal
- Rabbrev asko( assert_kind_of
- Rabbrev asnn( assert_not_nil
- Rabbrev asr( assert_raise
- Rabbrev asre( assert_response
- Rabbrev art( assert_redirected_to
- endif
- Rabbrev :a :action\ =>\
- " hax
- Rabbrev :c :co________\ =>\
- inoreabbrev <buffer> <silent> :c <C-R>=<SID>TheCWord()<CR>
- Rabbrev :i :id\ =>\
- Rabbrev :o :object\ =>\
- Rabbrev :p :partial\ =>\
- Rabbrev logd( logger.debug
- Rabbrev logi( logger.info
- Rabbrev logw( logger.warn
- Rabbrev loge( logger.error
- Rabbrev logf( logger.fatal
- Rabbrev fi( find
- Rabbrev AR:: ActiveRecord
- Rabbrev AV:: ActionView
- Rabbrev AC:: ActionController
- Rabbrev AD:: ActionDispatch
- Rabbrev AS:: ActiveSupport
- Rabbrev AM:: ActionMailer
- Rabbrev AO:: ActiveModel
- Rabbrev AE:: ActiveResource
- endif
-endfunction
-
-function! s:Abbrev(bang,...) abort
- if !exists("b:rails_abbreviations")
- let b:rails_abbreviations = {}
- endif
- if a:0 > 3 || (a:bang && (a:0 != 1))
- return s:error("Rabbrev: invalid arguments")
- endif
- if a:0 == 0
- for key in sort(keys(b:rails_abbreviations))
- echo key . join(b:rails_abbreviations[key],"\t")
- endfor
- return
- endif
- let lhs = a:1
- let root = s:sub(lhs,'%(::|\(|\[)$','')
- if a:bang
- if has_key(b:rails_abbreviations,root)
- call remove(b:rails_abbreviations,root)
- endif
- exe "iunabbrev <buffer> ".root
- return
- endif
- if a:0 > 3 || a:0 < 2
- return s:error("Rabbrev: invalid arguments")
- endif
- let rhs = a:2
- if has_key(b:rails_abbreviations,root)
- call remove(b:rails_abbreviations,root)
- endif
- if lhs =~ '($'
- let b:rails_abbreviations[root] = ["(", rhs . (a:0 > 2 ? "\t".a:3 : "")]
- if a:0 > 2
- call s:AddParenExpand(root,rhs,a:3)
- else
- call s:AddParenExpand(root,rhs)
- endif
- return
- endif
- if a:0 > 2
- return s:error("Rabbrev: invalid arguments")
- endif
- if lhs =~ ':$'
- call s:AddColonExpand(root,rhs)
- elseif lhs =~ '\[$'
- call s:AddBracketExpand(root,rhs)
- elseif lhs =~ '\w$'
- call s:AddTabExpand(lhs,rhs)
- else
- return s:error("Rabbrev: unimplemented")
- endif
- let b:rails_abbreviations[root] = [matchstr(lhs,'\W*$'),rhs]
-endfunction
-
-" }}}1
-" Settings {{{1
-
-function! s:Set(bang,...)
- let c = 1
- let defscope = ''
- for arg in a:000
- if arg =~? '^<[abgl]\=>$'
- let defscope = (matchstr(arg,'<\zs.*\ze>'))
- elseif arg !~ '='
- if defscope != '' && arg !~ '^\w:'
- let arg = defscope.':'.opt
- endif
- let val = s:getopt(arg)
- if val == '' && !has_key(s:opts(),arg)
- call s:error("No such rails.vim option: ".arg)
- else
- echo arg."=".val
- endif
- else
- let opt = matchstr(arg,'[^=]*')
- let val = s:sub(arg,'^[^=]*\=','')
- if defscope != '' && opt !~ '^\w:'
- let opt = defscope.':'.opt
- endif
- call s:setopt(opt,val)
- endif
- endfor
-endfunction
-
-function! s:getopt(opt,...)
- let app = rails#app()
- let opt = a:opt
- if a:0
- let scope = a:1
- elseif opt =~ '^[abgl]:'
- let scope = tolower(matchstr(opt,'^\w'))
- let opt = s:sub(opt,'^\w:','')
- else
- let scope = 'abgl'
- endif
- let lnum = a:0 > 1 ? a:2 : line('.')
- if scope =~ 'l' && &filetype != 'ruby'
- let scope = s:sub(scope,'l','b')
- endif
- if scope =~ 'l'
- call s:LocalModelines(lnum)
- endif
- let var = s:sname().'_'.opt
- let lastmethod = s:lastmethod(lnum)
- if lastmethod == '' | let lastmethod = ' ' | endif
- " Get buffer option
- if scope =~ 'l' && exists('b:_'.var) && has_key(b:_{var},lastmethod)
- return b:_{var}[lastmethod]
- elseif exists('b:'.var) && (scope =~ 'b' || (scope =~ 'l' && lastmethod == ' '))
- return b:{var}
- elseif scope =~ 'a' && has_key(app,'options') && has_key(app.options,opt)
- return app.options[opt]
- elseif scope =~ 'g' && exists("g:".s:sname()."_".opt)
- return g:{var}
- else
- return ""
- endif
-endfunction
-
-function! s:setopt(opt,val)
- let app = rails#app()
- if a:opt =~? '[abgl]:'
- let scope = matchstr(a:opt,'^\w')
- let opt = s:sub(a:opt,'^\w:','')
- else
- let scope = ''
- let opt = a:opt
- endif
- let defscope = get(s:opts(),opt,'a')
- if scope == ''
- let scope = defscope
- endif
- if &filetype != 'ruby' && (scope ==# 'B' || scope ==# 'l')
- let scope = 'b'
- endif
- let var = s:sname().'_'.opt
- if opt =~ '\W'
- return s:error("Invalid option ".a:opt)
- elseif scope ==# 'B' && defscope == 'l'
- if !exists('b:_'.var) | let b:_{var} = {} | endif
- let b:_{var}[' '] = a:val
- elseif scope =~? 'b'
- let b:{var} = a:val
- elseif scope =~? 'a'
- if !has_key(app,'options') | let app.options = {} | endif
- let app.options[opt] = a:val
- elseif scope =~? 'g'
- let g:{var} = a:val
- elseif scope =~? 'l'
- if !exists('b:_'.var) | let b:_{var} = {} | endif
- let lastmethod = s:lastmethod(lnum)
- let b:_{var}[lastmethod == '' ? ' ' : lastmethod] = a:val
- else
- return s:error("Invalid scope for ".a:opt)
- endif
-endfunction
-
-function! s:opts()
- return {'alternate': 'b', 'controller': 'b', 'gnu_screen': 'a', 'model': 'b', 'preview': 'l', 'task': 'b', 'related': 'l', 'root_url': 'a'}
-endfunction
-
-function! s:Complete_set(A,L,P)
- if a:A =~ '='
- let opt = matchstr(a:A,'[^=]*')
- return [opt."=".s:getopt(opt)]
- else
- let extra = matchstr(a:A,'^[abgl]:')
- return filter(sort(map(keys(s:opts()),'extra.v:val')),'s:startswith(v:val,a:A)')
- endif
- return []
-endfunction
-
-function! s:BufModelines()
- if !g:rails_modelines
- return
- endif
- let lines = getline("$")."\n".getline(line("$")-1)."\n".getline(1)."\n".getline(2)."\n".getline(3)."\n"
- let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|%>\|-->\|$\)'
- let cnt = 1
- let mat = matchstr(lines,'\C\<Rset'.pat)
- let matend = matchend(lines,'\C\<Rset'.pat)
- while mat != "" && cnt < 10
- let mat = s:sub(mat,'\s+$','')
- let mat = s:gsub(mat,'\|','\\|')
- if mat != ''
- silent! exe "Rset <B> ".mat
- endif
- let mat = matchstr(lines,'\C\<Rset'.pat,matend)
- let matend = matchend(lines,'\C\<Rset'.pat,matend)
- let cnt += 1
- endwhile
-endfunction
-
-function! s:LocalModelines(lnum)
- if !g:rails_modelines
- return
- endif
- let lbeg = s:lastmethodline(a:lnum)
- let lend = s:endof(lbeg)
- if lbeg == 0 || lend == 0
- return
- endif
- let lines = "\n"
- let lnum = lbeg
- while lnum < lend && lnum < lbeg + 5
- let lines .= getline(lnum) . "\n"
- let lnum += 1
- endwhile
- let pat = '\s\+\zs.\{-\}\ze\%(\n\|\s\s\|#{\@!\|%>\|-->\|$\)'
- let cnt = 1
- let mat = matchstr(lines,'\C\<rset'.pat)
- let matend = matchend(lines,'\C\<rset'.pat)
- while mat != "" && cnt < 10
- let mat = s:sub(mat,'\s+$','')
- let mat = s:gsub(mat,'\|','\\|')
- if mat != ''
- silent! exe "Rset <l> ".mat
- endif
- let mat = matchstr(lines,'\C\<rset'.pat,matend)
- let matend = matchend(lines,'\C\<rset'.pat,matend)
- let cnt += 1
- endwhile
-endfunction
-
-" }}}1
-" Detection {{{1
-
-function! s:app_source_callback(file) dict
- if self.cache.needs('existence')
- call self.cache.set('existence',{})
- endif
- let cache = self.cache.get('existence')
- if !has_key(cache,a:file)
- let cache[a:file] = self.has_file(a:file)
- endif
- if cache[a:file]
- sandbox source `=self.path(a:file)`
- endif
-endfunction
-
-call s:add_methods('app',['source_callback'])
-
-function! RailsBufInit(path)
- let firsttime = !(exists("b:rails_root") && b:rails_root == a:path)
- let b:rails_root = a:path
- if !has_key(s:apps,a:path)
- let s:apps[a:path] = deepcopy(s:app_prototype)
- let s:apps[a:path].root = a:path
- endif
- let app = s:apps[a:path]
- let buffer = rails#buffer()
- " Apparently rails#buffer().calculate_file_type() can be slow if the
- " underlying file system is slow (even though it doesn't really do anything
- " IO related). This caching is a temporary hack; if it doesn't cause
- " problems it should probably be refactored.
- let b:rails_cached_file_type = buffer.calculate_file_type()
- if g:rails_history_size > 0
- if !exists("g:RAILS_HISTORY")
- let g:RAILS_HISTORY = ""
- endif
- let path = a:path
- let g:RAILS_HISTORY = s:scrub(g:RAILS_HISTORY,path)
- if has("win32")
- let g:RAILS_HISTORY = s:scrub(g:RAILS_HISTORY,s:gsub(path,'\\','/'))
- endif
- let path = fnamemodify(path,':p:~:h')
- let g:RAILS_HISTORY = s:scrub(g:RAILS_HISTORY,path)
- if has("win32")
- let g:RAILS_HISTORY = s:scrub(g:RAILS_HISTORY,s:gsub(path,'\\','/'))
- endif
- let g:RAILS_HISTORY = path."\n".g:RAILS_HISTORY
- let g:RAILS_HISTORY = s:sub(g:RAILS_HISTORY,'%(.{-}\n){,'.g:rails_history_size.'}\zs.*','')
- endif
- call app.source_callback("config/syntax.vim")
- if expand('%:t') =~ '\.yml\.example$'
- setlocal filetype=yaml
- elseif expand('%:e') =~ '^\%(rjs\|rxml\|builder\)$'
- setlocal filetype=ruby
- elseif firsttime
- " Activate custom syntax
- let &syntax = &syntax
- endif
- if expand('%:e') == 'log'
- nnoremap <buffer> <silent> R :checktime<CR>
- nnoremap <buffer> <silent> G :checktime<Bar>$<CR>
- nnoremap <buffer> <silent> q :bwipe<CR>
- setlocal modifiable filetype=railslog noswapfile autoread foldmethod=syntax
- if exists('+concealcursor')
- setlocal concealcursor=nc conceallevel=2
- else
- silent %s/\%(\e\[[0-9;]*m\|\r$\)//ge
- endif
- setlocal readonly nomodifiable
- $
- endif
- call s:BufSettings()
- call s:BufCommands()
- call s:BufAbbreviations()
- " snippetsEmu.vim
- if exists('g:loaded_snippet')
- silent! runtime! ftplugin/rails_snippets.vim
- " filetype snippets need to come last for higher priority
- exe "silent! runtime! ftplugin/".&filetype."_snippets.vim"
- endif
- let t = rails#buffer().type_name()
- let t = "-".t
- let f = '/'.RailsFilePath()
- if f =~ '[ !#$%\,]'
- let f = ''
- endif
- runtime! macros/rails.vim
- silent doautocmd User Rails
- if t != '-'
- exe "silent doautocmd User Rails".s:gsub(t,'-','.')
- endif
- if f != ''
- exe "silent doautocmd User Rails".f
- endif
- call app.source_callback("config/rails.vim")
- call s:BufModelines()
- call s:BufMappings()
- return b:rails_root
-endfunction
-
-function! s:SetBasePath()
- let self = rails#buffer()
- if self.app().path() =~ '://'
- return
- endif
- let transformed_path = s:pathsplit(s:pathjoin([self.app().path()]))[0]
- let add_dot = self.getvar('&path') =~# '^\.\%(,\|$\)'
- let old_path = s:pathsplit(s:sub(self.getvar('&path'),'^\.%(,|$)',''))
- call filter(old_path,'!s:startswith(v:val,transformed_path)')
-
- let path = ['app', 'app/models', 'app/controllers', 'app/helpers', 'config', 'lib', 'app/views']
- if self.controller_name() != ''
- let path += ['app/views/'.self.controller_name(), 'public']
- endif
- if self.app().has('test')
- let path += ['test', 'test/unit', 'test/functional', 'test/integration']
- endif
- if self.app().has('spec')
- let path += ['spec', 'spec/models', 'spec/controllers', 'spec/helpers', 'spec/views', 'spec/lib', 'spec/requests', 'spec/integration']
- endif
- let path += ['app/*', 'vendor', 'vendor/plugins/*/lib', 'vendor/plugins/*/test', 'vendor/rails/*/lib', 'vendor/rails/*/test']
- call map(path,'self.app().path(v:val)')
- call self.setvar('&path',(add_dot ? '.,' : '').s:pathjoin([self.app().path()],path,old_path))
-endfunction
-
-function! s:BufSettings()
- if !exists('b:rails_root')
- return ''
- endif
- let self = rails#buffer()
- call s:SetBasePath()
- let rp = s:gsub(self.app().path(),'[ ,]','\\&')
- if stridx(&tags,rp.'/tmp/tags') == -1
- let &l:tags = rp . '/tmp/tags,' . &tags . ',' . rp . '/tags'
- endif
- if has("gui_win32") || has("gui_running")
- let code = '*.rb;*.rake;Rakefile'
- let templates = '*.'.join(s:view_types,';*.')
- let fixtures = '*.yml;*.csv'
- let statics = '*.html;*.css;*.js;*.xml;*.xsd;*.sql;.htaccess;README;README_FOR_APP'
- let b:browsefilter = ""
- \."All Rails Files\t".code.';'.templates.';'.fixtures.';'.statics."\n"
- \."Source Code (*.rb, *.rake)\t".code."\n"
- \."Templates (*.rhtml, *.rxml, *.rjs)\t".templates."\n"
- \."Fixtures (*.yml, *.csv)\t".fixtures."\n"
- \."Static Files (*.html, *.css, *.js)\t".statics."\n"
- \."All Files (*.*)\t*.*\n"
- endif
- call self.setvar('&includeexpr','RailsIncludeexpr()')
- call self.setvar('&suffixesadd', ".rb,.".join(s:view_types,',.'))
- let ft = self.getvar('&filetype')
- if ft =~ '^\%(e\=ruby\|[yh]aml\|coffee\|css\|s[ac]ss\|lesscss\)$'
- call self.setvar('&shiftwidth',2)
- call self.setvar('&softtabstop',2)
- call self.setvar('&expandtab',1)
- if exists('+completefunc') && self.getvar('&completefunc') == ''
- call self.setvar('&completefunc','syntaxcomplete#Complete')
- endif
- endif
- if ft == 'ruby'
- call self.setvar('&define',self.define_pattern())
- " This really belongs in after/ftplugin/ruby.vim but we'll be nice
- if exists('g:loaded_surround') && self.getvar('surround_101') == ''
- call self.setvar('surround_5', "\r\nend")
- call self.setvar('surround_69', "\1expr: \1\rend")
- call self.setvar('surround_101', "\r\nend")
- endif
- elseif ft == 'yaml' || fnamemodify(self.name(),':e') == 'yml'
- call self.setvar('&define',self.define_pattern())
- elseif ft =~# '^eruby\>'
- if exists("g:loaded_allml")
- call self.setvar('allml_stylesheet_link_tag', "<%= stylesheet_link_tag '\r' %>")
- call self.setvar('allml_javascript_include_tag', "<%= javascript_include_tag '\r' %>")
- call self.setvar('allml_doctype_index', 10)
- endif
- if exists("g:loaded_ragtag")
- call self.setvar('ragtag_stylesheet_link_tag', "<%= stylesheet_link_tag '\r' %>")
- call self.setvar('ragtag_javascript_include_tag', "<%= javascript_include_tag '\r' %>")
- call self.setvar('ragtag_doctype_index', 10)
- endif
- elseif ft == 'haml'
- if exists("g:loaded_allml")
- call self.setvar('allml_stylesheet_link_tag', "= stylesheet_link_tag '\r'")
- call self.setvar('allml_javascript_include_tag', "= javascript_include_tag '\r'")
- call self.setvar('allml_doctype_index', 10)
- endif
- if exists("g:loaded_ragtag")
- call self.setvar('ragtag_stylesheet_link_tag', "= stylesheet_link_tag '\r'")
- call self.setvar('ragtag_javascript_include_tag', "= javascript_include_tag '\r'")
- call self.setvar('ragtag_doctype_index', 10)
- endif
- endif
- if ft =~# '^eruby\>' || ft ==# 'yaml'
- " surround.vim
- if exists("g:loaded_surround")
- " The idea behind the || part here is that one can normally define the
- " surrounding to omit the hyphen (since standard ERuby does not use it)
- " but have it added in Rails ERuby files. Unfortunately, this makes it
- " difficult if you really don't want a hyphen in Rails ERuby files. If
- " this is your desire, you will need to accomplish it via a rails.vim
- " autocommand.
- if self.getvar('surround_45') == '' || self.getvar('surround_45') == "<% \r %>" " -
- call self.setvar('surround_45', "<% \r -%>")
- endif
- if self.getvar('surround_61') == '' " =
- call self.setvar('surround_61', "<%= \r %>")
- endif
- if self.getvar("surround_35") == '' " #
- call self.setvar('surround_35', "<%# \r %>")
- endif
- if self.getvar('surround_101') == '' || self.getvar('surround_101')== "<% \r %>\n<% end %>" "e
- call self.setvar('surround_5', "<% \r -%>\n<% end -%>")
- call self.setvar('surround_69', "<% \1expr: \1 -%>\r<% end -%>")
- call self.setvar('surround_101', "<% \r -%>\n<% end -%>")
- endif
- endif
- endif
-endfunction
-
-" }}}1
-" Autocommands {{{1
-
-augroup railsPluginAuto
- autocmd!
- autocmd User BufEnterRails call s:RefreshBuffer()
- autocmd User BufEnterRails call s:resetomnicomplete()
- autocmd User BufEnterRails call s:BufDatabase(-1)
- autocmd User dbextPreConnection call s:BufDatabase(1)
- autocmd BufWritePost */config/database.yml call rails#cache_clear("dbext_settings")
- autocmd BufWritePost */test/test_helper.rb call rails#cache_clear("user_assertions")
- autocmd BufWritePost */config/routes.rb call rails#cache_clear("named_routes")
- autocmd BufWritePost */config/environment.rb call rails#cache_clear("default_locale")
- autocmd BufWritePost */config/environments/*.rb call rails#cache_clear("environments")
- autocmd BufWritePost */tasks/**.rake call rails#cache_clear("rake_tasks")
- autocmd BufWritePost */generators/** call rails#cache_clear("generators")
- autocmd FileType * if exists("b:rails_root") | call s:BufSettings() | endif
- autocmd Syntax ruby,eruby,yaml,haml,javascript,coffee,railslog if exists("b:rails_root") | call s:BufSyntax() | endif
- autocmd QuickFixCmdPre *make* call s:push_chdir()
- autocmd QuickFixCmdPost *make* call s:pop_command()
-augroup END
-
-" }}}1
-" Initialization {{{1
-
-map <SID>xx <SID>xx
-let s:sid = s:sub(maparg("<SID>xx"),'xx$','')
-unmap <SID>xx
-let s:file = expand('<sfile>:p')
-
-if !exists('s:apps')
- let s:apps = {}
-endif
-
-" }}}1
-
-let &cpo = s:cpo_save
-
-" vim:set sw=2 sts=2:
diff --git a/vim/autoload/snipMate.vim b/vim/autoload/snipMate.vim
deleted file mode 100644
index 0ad5a58..0000000
--- a/vim/autoload/snipMate.vim
+++ /dev/null
@@ -1,435 +0,0 @@
-fun! Filename(...)
- let filename = expand('%:t:r')
- if filename == '' | return a:0 == 2 ? a:2 : '' | endif
- return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g')
-endf
-
-fun s:RemoveSnippet()
- unl! g:snipPos s:curPos s:snipLen s:endCol s:endLine s:prevLen
- \ s:lastBuf s:oldWord
- if exists('s:update')
- unl s:startCol s:origWordLen s:update
- if exists('s:oldVars') | unl s:oldVars s:oldEndCol | endif
- endif
- aug! snipMateAutocmds
-endf
-
-fun snipMate#expandSnip(snip, col)
- let lnum = line('.') | let col = a:col
-
- let snippet = s:ProcessSnippet(a:snip)
- " Avoid error if eval evaluates to nothing
- if snippet == '' | return '' | endif
-
- " Expand snippet onto current position with the tab stops removed
- let snipLines = split(substitute(snippet, '$\d\+\|${\d\+.\{-}}', '', 'g'), "\n", 1)
-
- let line = getline(lnum)
- let afterCursor = strpart(line, col - 1)
- " Keep text after the cursor
- if afterCursor != "\t" && afterCursor != ' '
- let line = strpart(line, 0, col - 1)
- let snipLines[-1] .= afterCursor
- else
- let afterCursor = ''
- " For some reason the cursor needs to move one right after this
- if line != '' && col == 1 && &ve != 'all' && &ve != 'onemore'
- let col += 1
- endif
- endif
-
- call setline(lnum, line.snipLines[0])
-
- " Autoindent snippet according to previous indentation
- let indent = matchend(line, '^.\{-}\ze\(\S\|$\)') + 1
- call append(lnum, map(snipLines[1:], "'".strpart(line, 0, indent - 1)."'.v:val"))
-
- " Open any folds snippet expands into
- if &fen | sil! exe lnum.','.(lnum + len(snipLines) - 1).'foldopen' | endif
-
- let [g:snipPos, s:snipLen] = s:BuildTabStops(snippet, lnum, col - indent, indent)
-
- if s:snipLen
- aug snipMateAutocmds
- au CursorMovedI * call s:UpdateChangedSnip(0)
- au InsertEnter * call s:UpdateChangedSnip(1)
- aug END
- let s:lastBuf = bufnr(0) " Only expand snippet while in current buffer
- let s:curPos = 0
- let s:endCol = g:snipPos[s:curPos][1]
- let s:endLine = g:snipPos[s:curPos][0]
-
- call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
- let s:prevLen = [line('$'), col('$')]
- if g:snipPos[s:curPos][2] != -1 | return s:SelectWord() | endif
- else
- unl g:snipPos s:snipLen
- " Place cursor at end of snippet if no tab stop is given
- let newlines = len(snipLines) - 1
- call cursor(lnum + newlines, indent + len(snipLines[-1]) - len(afterCursor)
- \ + (newlines ? 0: col - 1))
- endif
- return ''
-endf
-
-" Prepare snippet to be processed by s:BuildTabStops
-fun s:ProcessSnippet(snip)
- let snippet = a:snip
- " Evaluate eval (`...`) expressions.
- " Backquotes prefixed with a backslash "\" are ignored.
- " Using a loop here instead of a regex fixes a bug with nested "\=".
- if stridx(snippet, '`') != -1
- while match(snippet, '\(^\|[^\\]\)`.\{-}[^\\]`') != -1
- let snippet = substitute(snippet, '\(^\|[^\\]\)\zs`.\{-}[^\\]`\ze',
- \ substitute(eval(matchstr(snippet, '\(^\|[^\\]\)`\zs.\{-}[^\\]\ze`')),
- \ "\n\\%$", '', ''), '')
- endw
- let snippet = substitute(snippet, "\r", "\n", 'g')
- let snippet = substitute(snippet, '\\`', '`', 'g')
- endif
-
- " Place all text after a colon in a tab stop after the tab stop
- " (e.g. "${#:foo}" becomes "${:foo}foo").
- " This helps tell the position of the tab stops later.
- let snippet = substitute(snippet, '${\d\+:\(.\{-}\)}', '&\1', 'g')
-
- " Update the a:snip so that all the $# become the text after
- " the colon in their associated ${#}.
- " (e.g. "${1:foo}" turns all "$1"'s into "foo")
- let i = 1
- while stridx(snippet, '${'.i) != -1
- let s = matchstr(snippet, '${'.i.':\zs.\{-}\ze}')
- if s != ''
- let snippet = substitute(snippet, '$'.i, s.'&', 'g')
- endif
- let i += 1
- endw
-
- if &et " Expand tabs to spaces if 'expandtab' is set.
- return substitute(snippet, '\t', repeat(' ', &sts ? &sts : &sw), 'g')
- endif
- return snippet
-endf
-
-" Counts occurences of haystack in needle
-fun s:Count(haystack, needle)
- let counter = 0
- let index = stridx(a:haystack, a:needle)
- while index != -1
- let index = stridx(a:haystack, a:needle, index+1)
- let counter += 1
- endw
- return counter
-endf
-
-" Builds a list of a list of each tab stop in the snippet containing:
-" 1.) The tab stop's line number.
-" 2.) The tab stop's column number
-" (by getting the length of the string between the last "\n" and the
-" tab stop).
-" 3.) The length of the text after the colon for the current tab stop
-" (e.g. "${1:foo}" would return 3). If there is no text, -1 is returned.
-" 4.) If the "${#:}" construct is given, another list containing all
-" the matches of "$#", to be replaced with the placeholder. This list is
-" composed the same way as the parent; the first item is the line number,
-" and the second is the column.
-fun s:BuildTabStops(snip, lnum, col, indent)
- let snipPos = []
- let i = 1
- let withoutVars = substitute(a:snip, '$\d\+', '', 'g')
- while stridx(a:snip, '${'.i) != -1
- let beforeTabStop = matchstr(withoutVars, '^.*\ze${'.i.'\D')
- let withoutOthers = substitute(withoutVars, '${\('.i.'\D\)\@!\d\+.\{-}}', '', 'g')
-
- let j = i - 1
- call add(snipPos, [0, 0, -1])
- let snipPos[j][0] = a:lnum + s:Count(beforeTabStop, "\n")
- let snipPos[j][1] = a:indent + len(matchstr(withoutOthers, '.*\(\n\|^\)\zs.*\ze${'.i.'\D'))
- if snipPos[j][0] == a:lnum | let snipPos[j][1] += a:col | endif
-
- " Get all $# matches in another list, if ${#:name} is given
- if stridx(withoutVars, '${'.i.':') != -1
- let snipPos[j][2] = len(matchstr(withoutVars, '${'.i.':\zs.\{-}\ze}'))
- let dots = repeat('.', snipPos[j][2])
- call add(snipPos[j], [])
- let withoutOthers = substitute(a:snip, '${\d\+.\{-}}\|$'.i.'\@!\d\+', '', 'g')
- while match(withoutOthers, '$'.i.'\(\D\|$\)') != -1
- let beforeMark = matchstr(withoutOthers, '^.\{-}\ze'.dots.'$'.i.'\(\D\|$\)')
- call add(snipPos[j][3], [0, 0])
- let snipPos[j][3][-1][0] = a:lnum + s:Count(beforeMark, "\n")
- let snipPos[j][3][-1][1] = a:indent + (snipPos[j][3][-1][0] > a:lnum
- \ ? len(matchstr(beforeMark, '.*\n\zs.*'))
- \ : a:col + len(beforeMark))
- let withoutOthers = substitute(withoutOthers, '$'.i.'\ze\(\D\|$\)', '', '')
- endw
- endif
- let i += 1
- endw
- return [snipPos, i - 1]
-endf
-
-fun snipMate#jumpTabStop(backwards)
- let leftPlaceholder = exists('s:origWordLen')
- \ && s:origWordLen != g:snipPos[s:curPos][2]
- if leftPlaceholder && exists('s:oldEndCol')
- let startPlaceholder = s:oldEndCol + 1
- endif
-
- if exists('s:update')
- call s:UpdatePlaceholderTabStops()
- else
- call s:UpdateTabStops()
- endif
-
- " Don't reselect placeholder if it has been modified
- if leftPlaceholder && g:snipPos[s:curPos][2] != -1
- if exists('startPlaceholder')
- let g:snipPos[s:curPos][1] = startPlaceholder
- else
- let g:snipPos[s:curPos][1] = col('.')
- let g:snipPos[s:curPos][2] = 0
- endif
- endif
-
- let s:curPos += a:backwards ? -1 : 1
- " Loop over the snippet when going backwards from the beginning
- if s:curPos < 0 | let s:curPos = s:snipLen - 1 | endif
-
- if s:curPos == s:snipLen
- let sMode = s:endCol == g:snipPos[s:curPos-1][1]+g:snipPos[s:curPos-1][2]
- call s:RemoveSnippet()
- return sMode ? "\<tab>" : TriggerSnippet()
- endif
-
- call cursor(g:snipPos[s:curPos][0], g:snipPos[s:curPos][1])
-
- let s:endLine = g:snipPos[s:curPos][0]
- let s:endCol = g:snipPos[s:curPos][1]
- let s:prevLen = [line('$'), col('$')]
-
- return g:snipPos[s:curPos][2] == -1 ? '' : s:SelectWord()
-endf
-
-fun s:UpdatePlaceholderTabStops()
- let changeLen = s:origWordLen - g:snipPos[s:curPos][2]
- unl s:startCol s:origWordLen s:update
- if !exists('s:oldVars') | return | endif
- " Update tab stops in snippet if text has been added via "$#"
- " (e.g., in "${1:foo}bar$1${2}").
- if changeLen != 0
- let curLine = line('.')
-
- for pos in g:snipPos
- if pos == g:snipPos[s:curPos] | continue | endif
- let changed = pos[0] == curLine && pos[1] > s:oldEndCol
- let changedVars = 0
- let endPlaceholder = pos[2] - 1 + pos[1]
- " Subtract changeLen from each tab stop that was after any of
- " the current tab stop's placeholders.
- for [lnum, col] in s:oldVars
- if lnum > pos[0] | break | endif
- if pos[0] == lnum
- if pos[1] > col || (pos[2] == -1 && pos[1] == col)
- let changed += 1
- elseif col < endPlaceholder
- let changedVars += 1
- endif
- endif
- endfor
- let pos[1] -= changeLen * changed
- let pos[2] -= changeLen * changedVars " Parse variables within placeholders
- " e.g., "${1:foo} ${2:$1bar}"
-
- if pos[2] == -1 | continue | endif
- " Do the same to any placeholders in the other tab stops.
- for nPos in pos[3]
- let changed = nPos[0] == curLine && nPos[1] > s:oldEndCol
- for [lnum, col] in s:oldVars
- if lnum > nPos[0] | break | endif
- if nPos[0] == lnum && nPos[1] > col
- let changed += 1
- endif
- endfor
- let nPos[1] -= changeLen * changed
- endfor
- endfor
- endif
- unl s:endCol s:oldVars s:oldEndCol
-endf
-
-fun s:UpdateTabStops()
- let changeLine = s:endLine - g:snipPos[s:curPos][0]
- let changeCol = s:endCol - g:snipPos[s:curPos][1]
- if exists('s:origWordLen')
- let changeCol -= s:origWordLen
- unl s:origWordLen
- endif
- let lnum = g:snipPos[s:curPos][0]
- let col = g:snipPos[s:curPos][1]
- " Update the line number of all proceeding tab stops if <cr> has
- " been inserted.
- if changeLine != 0
- let changeLine -= 1
- for pos in g:snipPos
- if pos[0] >= lnum
- if pos[0] == lnum | let pos[1] += changeCol | endif
- let pos[0] += changeLine
- endif
- if pos[2] == -1 | continue | endif
- for nPos in pos[3]
- if nPos[0] >= lnum
- if nPos[0] == lnum | let nPos[1] += changeCol | endif
- let nPos[0] += changeLine
- endif
- endfor
- endfor
- elseif changeCol != 0
- " Update the column of all proceeding tab stops if text has
- " been inserted/deleted in the current line.
- for pos in g:snipPos
- if pos[1] >= col && pos[0] == lnum
- let pos[1] += changeCol
- endif
- if pos[2] == -1 | continue | endif
- for nPos in pos[3]
- if nPos[0] > lnum | break | endif
- if nPos[0] == lnum && nPos[1] >= col
- let nPos[1] += changeCol
- endif
- endfor
- endfor
- endif
-endf
-
-fun s:SelectWord()
- let s:origWordLen = g:snipPos[s:curPos][2]
- let s:oldWord = strpart(getline('.'), g:snipPos[s:curPos][1] - 1,
- \ s:origWordLen)
- let s:prevLen[1] -= s:origWordLen
- if !empty(g:snipPos[s:curPos][3])
- let s:update = 1
- let s:endCol = -1
- let s:startCol = g:snipPos[s:curPos][1] - 1
- endif
- if !s:origWordLen | return '' | endif
- let l = col('.') != 1 ? 'l' : ''
- if &sel == 'exclusive'
- return "\<esc>".l.'v'.s:origWordLen."l\<c-g>"
- endif
- return s:origWordLen == 1 ? "\<esc>".l.'gh'
- \ : "\<esc>".l.'v'.(s:origWordLen - 1)."l\<c-g>"
-endf
-
-" This updates the snippet as you type when text needs to be inserted
-" into multiple places (e.g. in "${1:default text}foo$1bar$1",
-" "default text" would be highlighted, and if the user types something,
-" UpdateChangedSnip() would be called so that the text after "foo" & "bar"
-" are updated accordingly)
-"
-" It also automatically quits the snippet if the cursor is moved out of it
-" while in insert mode.
-fun s:UpdateChangedSnip(entering)
- if exists('g:snipPos') && bufnr(0) != s:lastBuf
- call s:RemoveSnippet()
- elseif exists('s:update') " If modifying a placeholder
- if !exists('s:oldVars') && s:curPos + 1 < s:snipLen
- " Save the old snippet & word length before it's updated
- " s:startCol must be saved too, in case text is added
- " before the snippet (e.g. in "foo$1${2}bar${1:foo}").
- let s:oldEndCol = s:startCol
- let s:oldVars = deepcopy(g:snipPos[s:curPos][3])
- endif
- let col = col('.') - 1
-
- if s:endCol != -1
- let changeLen = col('$') - s:prevLen[1]
- let s:endCol += changeLen
- else " When being updated the first time, after leaving select mode
- if a:entering | return | endif
- let s:endCol = col - 1
- endif
-
- " If the cursor moves outside the snippet, quit it
- if line('.') != g:snipPos[s:curPos][0] || col < s:startCol ||
- \ col - 1 > s:endCol
- unl! s:startCol s:origWordLen s:oldVars s:update
- return s:RemoveSnippet()
- endif
-
- call s:UpdateVars()
- let s:prevLen[1] = col('$')
- elseif exists('g:snipPos')
- if !a:entering && g:snipPos[s:curPos][2] != -1
- let g:snipPos[s:curPos][2] = -2
- endif
-
- let col = col('.')
- let lnum = line('.')
- let changeLine = line('$') - s:prevLen[0]
-
- if lnum == s:endLine
- let s:endCol += col('$') - s:prevLen[1]
- let s:prevLen = [line('$'), col('$')]
- endif
- if changeLine != 0
- let s:endLine += changeLine
- let s:endCol = col
- endif
-
- " Delete snippet if cursor moves out of it in insert mode
- if (lnum == s:endLine && (col > s:endCol || col < g:snipPos[s:curPos][1]))
- \ || lnum > s:endLine || lnum < g:snipPos[s:curPos][0]
- call s:RemoveSnippet()
- endif
- endif
-endf
-
-" This updates the variables in a snippet when a placeholder has been edited.
-" (e.g., each "$1" in "${1:foo} $1bar $1bar")
-fun s:UpdateVars()
- let newWordLen = s:endCol - s:startCol + 1
- let newWord = strpart(getline('.'), s:startCol, newWordLen)
- if newWord == s:oldWord || empty(g:snipPos[s:curPos][3])
- return
- endif
-
- let changeLen = g:snipPos[s:curPos][2] - newWordLen
- let curLine = line('.')
- let startCol = col('.')
- let oldStartSnip = s:startCol
- let updateTabStops = changeLen != 0
- let i = 0
-
- for [lnum, col] in g:snipPos[s:curPos][3]
- if updateTabStops
- let start = s:startCol
- if lnum == curLine && col <= start
- let s:startCol -= changeLen
- let s:endCol -= changeLen
- endif
- for nPos in g:snipPos[s:curPos][3][(i):]
- " This list is in ascending order, so quit if we've gone too far.
- if nPos[0] > lnum | break | endif
- if nPos[0] == lnum && nPos[1] > col
- let nPos[1] -= changeLen
- endif
- endfor
- if lnum == curLine && col > start
- let col -= changeLen
- let g:snipPos[s:curPos][3][i][1] = col
- endif
- let i += 1
- endif
-
- " "Very nomagic" is used here to allow special characters.
- call setline(lnum, substitute(getline(lnum), '\%'.col.'c\V'.
- \ escape(s:oldWord, '\'), escape(newWord, '\&'), ''))
- endfor
- if oldStartSnip != s:startCol
- call cursor(0, startCol + s:startCol - oldStartSnip)
- endif
-
- let s:oldWord = newWord
- let g:snipPos[s:curPos][2] = newWordLen
-endf
-" vim:noet:sw=4:ts=4:ft=vim
diff --git a/vim/autoload/syntastic.vim b/vim/autoload/syntastic.vim
deleted file mode 100644
index a477736..0000000
--- a/vim/autoload/syntastic.vim
+++ /dev/null
@@ -1,24 +0,0 @@
-
-function! syntastic#ErrorBalloonExpr()
- if !exists('b:syntastic_balloons') | return '' | endif
- return get(b:syntastic_balloons, v:beval_lnum, '')
-endfunction
-
-function! syntastic#HighlightErrors(errors, termfunc, ...)
- call clearmatches()
- let forcecb = a:0 && a:1
- for item in a:errors
- let group = item['type'] == 'E' ? 'SpellBad' : 'SpellCap'
- if item['col'] && !forcecb
- let lastcol = col([item['lnum'], '$'])
- let lcol = min([lastcol, item['col']])
- call matchadd(group, '\%'.item['lnum'].'l\%'.lcol.'c')
- else
- let term = a:termfunc(item)
- if len(term) > 0
- call matchadd(group, '\%' . item['lnum'] . 'l' . term)
- endif
- endif
- endfor
-endfunction
-
diff --git a/vim/autoload/syntastic/c.vim b/vim/autoload/syntastic/c.vim
deleted file mode 100644
index c7232df..0000000
--- a/vim/autoload/syntastic/c.vim
+++ /dev/null
@@ -1,171 +0,0 @@
-if exists("g:loaded_syntastic_c_autoload")
- finish
-endif
-let g:loaded_syntastic_c_autoload = 1
-
-let s:save_cpo = &cpo
-set cpo&vim
-
-" initialize c/cpp syntax checker handlers
-function! s:Init()
- let s:handlers = []
- let s:cflags = {}
-
- call s:RegHandler('gtk', 'syntastic#c#CheckPKG',
- \ ['gtk', 'gtk+-2.0', 'gtk+', 'glib-2.0', 'glib'])
- call s:RegHandler('glib', 'syntastic#c#CheckPKG',
- \ ['glib', 'glib-2.0', 'glib'])
- call s:RegHandler('glade', 'syntastic#c#CheckPKG',
- \ ['glade', 'libglade-2.0', 'libglade'])
- call s:RegHandler('libsoup', 'syntastic#c#CheckPKG',
- \ ['libsoup', 'libsoup-2.4', 'libsoup-2.2'])
- call s:RegHandler('webkit', 'syntastic#c#CheckPKG',
- \ ['webkit', 'webkit-1.0'])
- call s:RegHandler('cairo', 'syntastic#c#CheckPKG',
- \ ['cairo', 'cairo'])
- call s:RegHandler('pango', 'syntastic#c#CheckPKG',
- \ ['pango', 'pango'])
- call s:RegHandler('libxml', 'syntastic#c#CheckPKG',
- \ ['libxml', 'libxml-2.0', 'libxml'])
- call s:RegHandler('freetype', 'syntastic#c#CheckPKG',
- \ ['freetype', 'freetype2', 'freetype'])
- call s:RegHandler('SDL', 'syntastic#c#CheckPKG',
- \ ['sdl', 'sdl'])
- call s:RegHandler('opengl', 'syntastic#c#CheckPKG',
- \ ['opengl', 'gl'])
- call s:RegHandler('ruby', 'syntastic#c#CheckRuby', [])
- call s:RegHandler('Python\.h', 'syntastic#c#CheckPython', [])
- call s:RegHandler('php\.h', 'syntastic#c#CheckPhp', [])
-endfunction
-
-" search the first 100 lines for include statements that are
-" given in the handlers dictionary
-function! syntastic#c#SearchHeaders()
- let includes = ''
- let files = []
- let found = []
- let lines = filter(getline(1, 100), 'v:val =~# "#\s*include"')
-
- " search current buffer
- for line in lines
- let file = matchstr(line, '"\zs\S\+\ze"')
- if file != ''
- call add(files, file)
- continue
- endif
- for handler in s:handlers
- if line =~# handler["regex"]
- let includes .= call(handler["func"], handler["args"])
- call add(found, handler["regex"])
- break
- endif
- endfor
- endfor
-
- " search included headers
- for hfile in files
- if hfile != ''
- let filename = expand('%:p:h') . ((has('win32') || has('win64')) ?
- \ '\' : '/') . hfile
- try
- let lines = readfile(filename, '', 100)
- catch /E484/
- continue
- endtry
- let lines = filter(lines, 'v:val =~# "#\s*include"')
- for handler in s:handlers
- if index(found, handler["regex"]) != -1
- continue
- endif
- for line in lines
- if line =~# handler["regex"]
- let includes .= call(handler["func"], handler["args"])
- call add(found, handler["regex"])
- break
- endif
- endfor
- endfor
- endif
- endfor
-
- return includes
-endfunction
-
-" try to find library with 'pkg-config'
-" search possible libraries from first to last given
-" argument until one is found
-function! syntastic#c#CheckPKG(name, ...)
- if executable('pkg-config')
- if !has_key(s:cflags, a:name)
- for i in range(a:0)
- let l:cflags = system('pkg-config --cflags '.a:000[i])
- " since we cannot necessarily trust the pkg-config exit code
- " we have to check for an error output as well
- if v:shell_error == 0 && l:cflags !~? 'not found'
- let l:cflags = ' '.substitute(l:cflags, "\n", '', '')
- let s:cflags[a:name] = l:cflags
- return l:cflags
- endif
- endfor
- else
- return s:cflags[a:name]
- endif
- endif
- return ''
-endfunction
-
-" try to find PHP includes with 'php-config'
-function! syntastic#c#CheckPhp()
- if executable('php-config')
- if !exists('s:php_flags')
- let s:php_flags = system('php-config --includes')
- let s:php_flags = ' ' . substitute(s:php_flags, "\n", '', '')
- endif
- return s:php_flags
- endif
- return ''
-endfunction
-
-" try to find the ruby headers with 'rbconfig'
-function! syntastic#c#CheckRuby()
- if executable('ruby')
- if !exists('s:ruby_flags')
- let s:ruby_flags = system('ruby -r rbconfig -e '
- \ . '''puts Config::CONFIG["archdir"]''')
- let s:ruby_flags = substitute(s:ruby_flags, "\n", '', '')
- let s:ruby_flags = ' -I' . s:ruby_flags
- endif
- return s:ruby_flags
- endif
- return ''
-endfunction
-
-" try to find the python headers with distutils
-function! syntastic#c#CheckPython()
- if executable('python')
- if !exists('s:python_flags')
- let s:python_flags = system('python -c ''from distutils import '
- \ . 'sysconfig; import sys; sys.stdout.write(sysconfig.get_python_inc())''')
- let s:python_flags = substitute(s:python_flags, "\n", '', '')
- let s:python_flags = ' -I' . s:python_flags
- endif
- return s:python_flags
- endif
- return ''
-endfunction
-
-" return a handler dictionary object
-function! s:RegHandler(regex, function, args)
- let handler = {}
- let handler["regex"] = a:regex
- let handler["func"] = function(a:function)
- let handler["args"] = a:args
- call add(s:handlers, handler)
-endfunction
-
-call s:Init()
-
-let &cpo = s:save_cpo
-unlet s:save_cpo
-
-" vim: set et sts=4 sw=4:
diff --git a/vim/autoload/tagbar.vim b/vim/autoload/tagbar.vim
deleted file mode 100644
index 48ad320..0000000
--- a/vim/autoload/tagbar.vim
+++ /dev/null
@@ -1,3099 +0,0 @@
-" ============================================================================
-" File: tagbar.vim
-" Description: List the current file's tags in a sidebar, ordered by class etc
-" Author: Jan Larres <jan@majutsushi.net>
-" Licence: Vim licence
-" Website: http://majutsushi.github.com/tagbar/
-" Version: 2.3
-" Note: This plugin was heavily inspired by the 'Taglist' plugin by
-" Yegappan Lakshmanan and uses a small amount of code from it.
-"
-" Original taglist copyright notice:
-" Permission is hereby granted to use and distribute this code,
-" with or without modifications, provided that this copyright
-" notice is copied with it. Like anything else that's free,
-" taglist.vim is provided *as is* and comes with no warranty of
-" any kind, either expressed or implied. In no event will the
-" copyright holder be liable for any damamges resulting from the
-" use of this software.
-" ============================================================================
-
-scriptencoding utf-8
-
-" Initialization {{{1
-
-" Basic init {{{2
-
-if !exists('g:tagbar_ctags_bin')
- if executable('ctags-exuberant')
- let g:tagbar_ctags_bin = 'ctags-exuberant'
- elseif executable('exuberant-ctags')
- let g:tagbar_ctags_bin = 'exuberant-ctags'
- elseif executable('exctags')
- let g:tagbar_ctags_bin = 'exctags'
- elseif has('macunix') && executable('/usr/local/bin/ctags')
- " Homebrew default location
- let g:tagbar_ctags_bin = '/usr/local/bin/ctags'
- elseif has('macunix') && executable('/opt/local/bin/ctags')
- " Macports default location
- let g:tagbar_ctags_bin = '/opt/local/bin/ctags'
- elseif executable('ctags')
- let g:tagbar_ctags_bin = 'ctags'
- elseif executable('ctags.exe')
- let g:tagbar_ctags_bin = 'ctags.exe'
- elseif executable('tags')
- let g:tagbar_ctags_bin = 'tags'
- else
- echomsg 'Tagbar: Exuberant ctags not found, skipping plugin'
- finish
- endif
-else
- " reset 'wildignore' temporarily in case *.exe is included in it
- let wildignore_save = &wildignore
- set wildignore&
-
- let g:tagbar_ctags_bin = expand(g:tagbar_ctags_bin)
-
- let &wildignore = wildignore_save
-
- if !executable(g:tagbar_ctags_bin)
- echomsg 'Tagbar: Exuberant ctags not found in specified place,'
- \ 'skipping plugin'
- finish
- endif
-endif
-
-redir => s:ftype_out
-silent filetype
-redir END
-if s:ftype_out !~# 'detection:ON'
- echomsg 'Tagbar: Filetype detection is turned off, skipping plugin'
- unlet s:ftype_out
- finish
-endif
-unlet s:ftype_out
-
-let s:icon_closed = g:tagbar_iconchars[0]
-let s:icon_open = g:tagbar_iconchars[1]
-
-let s:type_init_done = 0
-let s:autocommands_done = 0
-let s:checked_ctags = 0
-let s:window_expanded = 0
-
-let s:access_symbols = {
- \ 'public' : '+',
- \ 'protected' : '#',
- \ 'private' : '-'
-\ }
-
-let g:loaded_tagbar = 1
-
-let s:last_highlight_tline = 0
-let s:debug = 0
-let s:debug_file = ''
-
-" s:Init() {{{2
-function! s:Init()
- if !s:type_init_done
- call s:InitTypes()
- endif
-
- if !s:checked_ctags
- if !s:CheckForExCtags()
- return
- endif
- endif
-endfunction
-
-" s:InitTypes() {{{2
-function! s:InitTypes()
- call s:LogDebugMessage('Initializing types')
-
- let s:known_types = {}
-
- " Ant {{{3
- let type_ant = {}
- let type_ant.ctagstype = 'ant'
- let type_ant.kinds = [
- \ {'short' : 'p', 'long' : 'projects', 'fold' : 0},
- \ {'short' : 't', 'long' : 'targets', 'fold' : 0}
- \ ]
- let s:known_types.ant = type_ant
- " Asm {{{3
- let type_asm = {}
- let type_asm.ctagstype = 'asm'
- let type_asm.kinds = [
- \ {'short' : 'm', 'long' : 'macros', 'fold' : 0},
- \ {'short' : 't', 'long' : 'types', 'fold' : 0},
- \ {'short' : 'd', 'long' : 'defines', 'fold' : 0},
- \ {'short' : 'l', 'long' : 'labels', 'fold' : 0}
- \ ]
- let s:known_types.asm = type_asm
- " ASP {{{3
- let type_aspvbs = {}
- let type_aspvbs.ctagstype = 'asp'
- let type_aspvbs.kinds = [
- \ {'short' : 'd', 'long' : 'constants', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 's', 'long' : 'subroutines', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0}
- \ ]
- let s:known_types.aspvbs = type_aspvbs
- " Awk {{{3
- let type_awk = {}
- let type_awk.ctagstype = 'awk'
- let type_awk.kinds = [
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- let s:known_types.awk = type_awk
- " Basic {{{3
- let type_basic = {}
- let type_basic.ctagstype = 'basic'
- let type_basic.kinds = [
- \ {'short' : 'c', 'long' : 'constants', 'fold' : 0},
- \ {'short' : 'g', 'long' : 'enumerations', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'l', 'long' : 'labels', 'fold' : 0},
- \ {'short' : 't', 'long' : 'types', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0}
- \ ]
- let s:known_types.basic = type_basic
- " BETA {{{3
- let type_beta = {}
- let type_beta.ctagstype = 'beta'
- let type_beta.kinds = [
- \ {'short' : 'f', 'long' : 'fragments', 'fold' : 0},
- \ {'short' : 's', 'long' : 'slots', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'patterns', 'fold' : 0}
- \ ]
- let s:known_types.beta = type_beta
- " C {{{3
- let type_c = {}
- let type_c.ctagstype = 'c'
- let type_c.kinds = [
- \ {'short' : 'd', 'long' : 'macros', 'fold' : 1},
- \ {'short' : 'p', 'long' : 'prototypes', 'fold' : 1},
- \ {'short' : 'g', 'long' : 'enums', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'enumerators', 'fold' : 0},
- \ {'short' : 't', 'long' : 'typedefs', 'fold' : 0},
- \ {'short' : 's', 'long' : 'structs', 'fold' : 0},
- \ {'short' : 'u', 'long' : 'unions', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'members', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- let type_c.sro = '::'
- let type_c.kind2scope = {
- \ 'g' : 'enum',
- \ 's' : 'struct',
- \ 'u' : 'union'
- \ }
- let type_c.scope2kind = {
- \ 'enum' : 'g',
- \ 'struct' : 's',
- \ 'union' : 'u'
- \ }
- let s:known_types.c = type_c
- " C++ {{{3
- let type_cpp = {}
- let type_cpp.ctagstype = 'c++'
- let type_cpp.kinds = [
- \ {'short' : 'd', 'long' : 'macros', 'fold' : 1},
- \ {'short' : 'p', 'long' : 'prototypes', 'fold' : 1},
- \ {'short' : 'g', 'long' : 'enums', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'enumerators', 'fold' : 0},
- \ {'short' : 't', 'long' : 'typedefs', 'fold' : 0},
- \ {'short' : 'n', 'long' : 'namespaces', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 's', 'long' : 'structs', 'fold' : 0},
- \ {'short' : 'u', 'long' : 'unions', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'members', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0}
- \ ]
- let type_cpp.sro = '::'
- let type_cpp.kind2scope = {
- \ 'g' : 'enum',
- \ 'n' : 'namespace',
- \ 'c' : 'class',
- \ 's' : 'struct',
- \ 'u' : 'union'
- \ }
- let type_cpp.scope2kind = {
- \ 'enum' : 'g',
- \ 'namespace' : 'n',
- \ 'class' : 'c',
- \ 'struct' : 's',
- \ 'union' : 'u'
- \ }
- let s:known_types.cpp = type_cpp
- " C# {{{3
- let type_cs = {}
- let type_cs.ctagstype = 'c#'
- let type_cs.kinds = [
- \ {'short' : 'd', 'long' : 'macros', 'fold' : 1},
- \ {'short' : 'f', 'long' : 'fields', 'fold' : 0},
- \ {'short' : 'g', 'long' : 'enums', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'enumerators', 'fold' : 0},
- \ {'short' : 't', 'long' : 'typedefs', 'fold' : 0},
- \ {'short' : 'n', 'long' : 'namespaces', 'fold' : 0},
- \ {'short' : 'i', 'long' : 'interfaces', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 's', 'long' : 'structs', 'fold' : 0},
- \ {'short' : 'E', 'long' : 'events', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'methods', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'properties', 'fold' : 0}
- \ ]
- let type_cs.sro = '.'
- let type_cs.kind2scope = {
- \ 'n' : 'namespace',
- \ 'i' : 'interface',
- \ 'c' : 'class',
- \ 's' : 'struct',
- \ 'g' : 'enum'
- \ }
- let type_cs.scope2kind = {
- \ 'namespace' : 'n',
- \ 'interface' : 'i',
- \ 'class' : 'c',
- \ 'struct' : 's',
- \ 'enum' : 'g'
- \ }
- let s:known_types.cs = type_cs
- " COBOL {{{3
- let type_cobol = {}
- let type_cobol.ctagstype = 'cobol'
- let type_cobol.kinds = [
- \ {'short' : 'd', 'long' : 'data items', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'file descriptions', 'fold' : 0},
- \ {'short' : 'g', 'long' : 'group items', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'paragraphs', 'fold' : 0},
- \ {'short' : 'P', 'long' : 'program ids', 'fold' : 0},
- \ {'short' : 's', 'long' : 'sections', 'fold' : 0}
- \ ]
- let s:known_types.cobol = type_cobol
- " DOS Batch {{{3
- let type_dosbatch = {}
- let type_dosbatch.ctagstype = 'dosbatch'
- let type_dosbatch.kinds = [
- \ {'short' : 'l', 'long' : 'labels', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0}
- \ ]
- let s:known_types.dosbatch = type_dosbatch
- " Eiffel {{{3
- let type_eiffel = {}
- let type_eiffel.ctagstype = 'eiffel'
- let type_eiffel.kinds = [
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'features', 'fold' : 0}
- \ ]
- let type_eiffel.sro = '.' " Not sure, is nesting even possible?
- let type_eiffel.kind2scope = {
- \ 'c' : 'class',
- \ 'f' : 'feature'
- \ }
- let type_eiffel.scope2kind = {
- \ 'class' : 'c',
- \ 'feature' : 'f'
- \ }
- let s:known_types.eiffel = type_eiffel
- " Erlang {{{3
- let type_erlang = {}
- let type_erlang.ctagstype = 'erlang'
- let type_erlang.kinds = [
- \ {'short' : 'm', 'long' : 'modules', 'fold' : 0},
- \ {'short' : 'd', 'long' : 'macro definitions', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'r', 'long' : 'record definitions', 'fold' : 0}
- \ ]
- let type_erlang.sro = '.' " Not sure, is nesting even possible?
- let type_erlang.kind2scope = {
- \ 'm' : 'module'
- \ }
- let type_erlang.scope2kind = {
- \ 'module' : 'm'
- \ }
- let s:known_types.erlang = type_erlang
- " Flex {{{3
- " Vim doesn't support Flex out of the box, this is based on rough
- " guesses and probably requires
- " http://www.vim.org/scripts/script.php?script_id=2909
- " Improvements welcome!
- let type_mxml = {}
- let type_mxml.ctagstype = 'flex'
- let type_mxml.kinds = [
- \ {'short' : 'v', 'long' : 'global variables', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'methods', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'properties', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'x', 'long' : 'mxtags', 'fold' : 0}
- \ ]
- let type_mxml.sro = '.'
- let type_mxml.kind2scope = {
- \ 'c' : 'class'
- \ }
- let type_mxml.scope2kind = {
- \ 'class' : 'c'
- \ }
- let s:known_types.mxml = type_mxml
- " Fortran {{{3
- let type_fortran = {}
- let type_fortran.ctagstype = 'fortran'
- let type_fortran.kinds = [
- \ {'short' : 'm', 'long' : 'modules', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'programs', 'fold' : 0},
- \ {'short' : 'k', 'long' : 'components', 'fold' : 0},
- \ {'short' : 't', 'long' : 'derived types and structures', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'common blocks', 'fold' : 0},
- \ {'short' : 'b', 'long' : 'block data', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'entry points', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 's', 'long' : 'subroutines', 'fold' : 0},
- \ {'short' : 'l', 'long' : 'labels', 'fold' : 0},
- \ {'short' : 'n', 'long' : 'namelists', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0}
- \ ]
- let type_fortran.sro = '.' " Not sure, is nesting even possible?
- let type_fortran.kind2scope = {
- \ 'm' : 'module',
- \ 'p' : 'program',
- \ 'f' : 'function',
- \ 's' : 'subroutine'
- \ }
- let type_fortran.scope2kind = {
- \ 'module' : 'm',
- \ 'program' : 'p',
- \ 'function' : 'f',
- \ 'subroutine' : 's'
- \ }
- let s:known_types.fortran = type_fortran
- " HTML {{{3
- let type_html = {}
- let type_html.ctagstype = 'html'
- let type_html.kinds = [
- \ {'short' : 'f', 'long' : 'JavaScript funtions', 'fold' : 0},
- \ {'short' : 'a', 'long' : 'named anchors', 'fold' : 0}
- \ ]
- let s:known_types.html = type_html
- " Java {{{3
- let type_java = {}
- let type_java.ctagstype = 'java'
- let type_java.kinds = [
- \ {'short' : 'p', 'long' : 'packages', 'fold' : 1},
- \ {'short' : 'f', 'long' : 'fields', 'fold' : 0},
- \ {'short' : 'g', 'long' : 'enum types', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'enum constants', 'fold' : 0},
- \ {'short' : 'i', 'long' : 'interfaces', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'methods', 'fold' : 0}
- \ ]
- let type_java.sro = '.'
- let type_java.kind2scope = {
- \ 'g' : 'enum',
- \ 'i' : 'interface',
- \ 'c' : 'class'
- \ }
- let type_java.scope2kind = {
- \ 'enum' : 'g',
- \ 'interface' : 'i',
- \ 'class' : 'c'
- \ }
- let s:known_types.java = type_java
- " JavaScript {{{3
- " JavaScript is weird -- it does have scopes, but ctags doesn't seem to
- " properly generate the information for them, instead it simply uses the
- " complete name. So ctags has to be fixed before I can do anything here.
- " Alternatively jsctags/doctorjs will be used if available.
- let type_javascript = {}
- let type_javascript.ctagstype = 'javascript'
- let jsctags = s:CheckFTCtags('jsctags', 'javascript')
- if jsctags != ''
- let type_javascript.kinds = [
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- let type_javascript.sro = '.'
- let type_javascript.kind2scope = {
- \ 'v' : 'namespace',
- \ 'f' : 'namespace'
- \ }
- let type_javascript.scope2kind = {
- \ 'namespace' : 'v'
- \ }
- let type_javascript.ctagsbin = jsctags
- let type_javascript.ctagsargs = '-f -'
- else
- let type_javascript.kinds = [
- \ {'short' : 'v', 'long' : 'global variables', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'properties', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'methods', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- endif
- let s:known_types.javascript = type_javascript
- " Lisp {{{3
- let type_lisp = {}
- let type_lisp.ctagstype = 'lisp'
- let type_lisp.kinds = [
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- let s:known_types.lisp = type_lisp
- " Lua {{{3
- let type_lua = {}
- let type_lua.ctagstype = 'lua'
- let type_lua.kinds = [
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- let s:known_types.lua = type_lua
- " Make {{{3
- let type_make = {}
- let type_make.ctagstype = 'make'
- let type_make.kinds = [
- \ {'short' : 'm', 'long' : 'macros', 'fold' : 0}
- \ ]
- let s:known_types.make = type_make
- " Matlab {{{3
- let type_matlab = {}
- let type_matlab.ctagstype = 'matlab'
- let type_matlab.kinds = [
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- let s:known_types.matlab = type_matlab
- " Ocaml {{{3
- let type_ocaml = {}
- let type_ocaml.ctagstype = 'ocaml'
- let type_ocaml.kinds = [
- \ {'short' : 'M', 'long' : 'modules or functors', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'global variables', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'C', 'long' : 'constructors', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'methods', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'exceptions', 'fold' : 0},
- \ {'short' : 't', 'long' : 'type names', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'r', 'long' : 'structure fields', 'fold' : 0}
- \ ]
- let type_ocaml.sro = '.' " Not sure, is nesting even possible?
- let type_ocaml.kind2scope = {
- \ 'M' : 'Module',
- \ 'c' : 'class',
- \ 't' : 'type'
- \ }
- let type_ocaml.scope2kind = {
- \ 'Module' : 'M',
- \ 'class' : 'c',
- \ 'type' : 't'
- \ }
- let s:known_types.ocaml = type_ocaml
- " Pascal {{{3
- let type_pascal = {}
- let type_pascal.ctagstype = 'pascal'
- let type_pascal.kinds = [
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'procedures', 'fold' : 0}
- \ ]
- let s:known_types.pascal = type_pascal
- " Perl {{{3
- let type_perl = {}
- let type_perl.ctagstype = 'perl'
- let type_perl.kinds = [
- \ {'short' : 'p', 'long' : 'packages', 'fold' : 1},
- \ {'short' : 'c', 'long' : 'constants', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'formats', 'fold' : 0},
- \ {'short' : 'l', 'long' : 'labels', 'fold' : 0},
- \ {'short' : 's', 'long' : 'subroutines', 'fold' : 0}
- \ ]
- let s:known_types.perl = type_perl
- " PHP {{{3
- let type_php = {}
- let type_php.ctagstype = 'php'
- let type_php.kinds = [
- \ {'short' : 'i', 'long' : 'interfaces', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'd', 'long' : 'constant definitions', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0},
- \ {'short' : 'j', 'long' : 'javascript functions', 'fold' : 0}
- \ ]
- let s:known_types.php = type_php
- " Python {{{3
- let type_python = {}
- let type_python.ctagstype = 'python'
- let type_python.kinds = [
- \ {'short' : 'i', 'long' : 'imports', 'fold' : 1},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'members', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0}
- \ ]
- let type_python.sro = '.'
- let type_python.kind2scope = {
- \ 'c' : 'class',
- \ 'f' : 'function',
- \ 'm' : 'function'
- \ }
- let type_python.scope2kind = {
- \ 'class' : 'c',
- \ 'function' : 'f'
- \ }
- let s:known_types.python = type_python
- " REXX {{{3
- let type_rexx = {}
- let type_rexx.ctagstype = 'rexx'
- let type_rexx.kinds = [
- \ {'short' : 's', 'long' : 'subroutines', 'fold' : 0}
- \ ]
- let s:known_types.rexx = type_rexx
- " Ruby {{{3
- let type_ruby = {}
- let type_ruby.ctagstype = 'ruby'
- let type_ruby.kinds = [
- \ {'short' : 'm', 'long' : 'modules', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'methods', 'fold' : 0},
- \ {'short' : 'F', 'long' : 'singleton methods', 'fold' : 0}
- \ ]
- let type_ruby.sro = '.'
- let type_ruby.kind2scope = {
- \ 'c' : 'class',
- \ 'm' : 'class'
- \ }
- let type_ruby.scope2kind = {
- \ 'class' : 'c'
- \ }
- let s:known_types.ruby = type_ruby
- " Scheme {{{3
- let type_scheme = {}
- let type_scheme.ctagstype = 'scheme'
- let type_scheme.kinds = [
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 's', 'long' : 'sets', 'fold' : 0}
- \ ]
- let s:known_types.scheme = type_scheme
- " Shell script {{{3
- let type_sh = {}
- let type_sh.ctagstype = 'sh'
- let type_sh.kinds = [
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- let s:known_types.sh = type_sh
- let s:known_types.csh = type_sh
- let s:known_types.zsh = type_sh
- " SLang {{{3
- let type_slang = {}
- let type_slang.ctagstype = 'slang'
- let type_slang.kinds = [
- \ {'short' : 'n', 'long' : 'namespaces', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0}
- \ ]
- let s:known_types.slang = type_slang
- " SML {{{3
- let type_sml = {}
- let type_sml.ctagstype = 'sml'
- let type_sml.kinds = [
- \ {'short' : 'e', 'long' : 'exception declarations', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'function definitions', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'functor definitions', 'fold' : 0},
- \ {'short' : 's', 'long' : 'signature declarations', 'fold' : 0},
- \ {'short' : 'r', 'long' : 'structure declarations', 'fold' : 0},
- \ {'short' : 't', 'long' : 'type definitions', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'value bindings', 'fold' : 0}
- \ ]
- let s:known_types.sml = type_sml
- " SQL {{{3
- " The SQL ctags parser seems to be buggy for me, so this just uses the
- " normal kinds even though scopes should be available. Improvements
- " welcome!
- let type_sql = {}
- let type_sql.ctagstype = 'sql'
- let type_sql.kinds = [
- \ {'short' : 'P', 'long' : 'packages', 'fold' : 1},
- \ {'short' : 'c', 'long' : 'cursors', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'F', 'long' : 'record fields', 'fold' : 0},
- \ {'short' : 'L', 'long' : 'block label', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'procedures', 'fold' : 0},
- \ {'short' : 's', 'long' : 'subtypes', 'fold' : 0},
- \ {'short' : 't', 'long' : 'tables', 'fold' : 0},
- \ {'short' : 'T', 'long' : 'triggers', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0},
- \ {'short' : 'i', 'long' : 'indexes', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'events', 'fold' : 0},
- \ {'short' : 'U', 'long' : 'publications', 'fold' : 0},
- \ {'short' : 'R', 'long' : 'services', 'fold' : 0},
- \ {'short' : 'D', 'long' : 'domains', 'fold' : 0},
- \ {'short' : 'V', 'long' : 'views', 'fold' : 0},
- \ {'short' : 'n', 'long' : 'synonyms', 'fold' : 0},
- \ {'short' : 'x', 'long' : 'MobiLink Table Scripts', 'fold' : 0},
- \ {'short' : 'y', 'long' : 'MobiLink Conn Scripts', 'fold' : 0}
- \ ]
- let s:known_types.sql = type_sql
- " Tcl {{{3
- let type_tcl = {}
- let type_tcl.ctagstype = 'tcl'
- let type_tcl.kinds = [
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'methods', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'procedures', 'fold' : 0}
- \ ]
- let s:known_types.tcl = type_tcl
- " LaTeX {{{3
- let type_tex = {}
- let type_tex.ctagstype = 'tex'
- let type_tex.kinds = [
- \ {'short' : 'p', 'long' : 'parts', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'chapters', 'fold' : 0},
- \ {'short' : 's', 'long' : 'sections', 'fold' : 0},
- \ {'short' : 'u', 'long' : 'subsections', 'fold' : 0},
- \ {'short' : 'b', 'long' : 'subsubsections', 'fold' : 0},
- \ {'short' : 'P', 'long' : 'paragraphs', 'fold' : 0},
- \ {'short' : 'G', 'long' : 'subparagraphs', 'fold' : 0}
- \ ]
- let s:known_types.tex = type_tex
- " Vera {{{3
- " Why are variables 'virtual'?
- let type_vera = {}
- let type_vera.ctagstype = 'vera'
- let type_vera.kinds = [
- \ {'short' : 'd', 'long' : 'macros', 'fold' : 1},
- \ {'short' : 'g', 'long' : 'enums', 'fold' : 0},
- \ {'short' : 'T', 'long' : 'typedefs', 'fold' : 0},
- \ {'short' : 'c', 'long' : 'classes', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'enumerators', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'members', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 't', 'long' : 'tasks', 'fold' : 0},
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'programs', 'fold' : 0}
- \ ]
- let type_vera.sro = '.' " Nesting doesn't seem to be possible
- let type_vera.kind2scope = {
- \ 'g' : 'enum',
- \ 'c' : 'class',
- \ 'v' : 'virtual'
- \ }
- let type_vera.scope2kind = {
- \ 'enum' : 'g',
- \ 'class' : 'c',
- \ 'virtual' : 'v'
- \ }
- let s:known_types.vera = type_vera
- " Verilog {{{3
- let type_verilog = {}
- let type_verilog.ctagstype = 'verilog'
- let type_verilog.kinds = [
- \ {'short' : 'c', 'long' : 'constants', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'events', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'modules', 'fold' : 0},
- \ {'short' : 'n', 'long' : 'net data types', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'ports', 'fold' : 0},
- \ {'short' : 'r', 'long' : 'register data types', 'fold' : 0},
- \ {'short' : 't', 'long' : 'tasks', 'fold' : 0}
- \ ]
- let s:known_types.verilog = type_verilog
- " VHDL {{{3
- " The VHDL ctags parser unfortunately doesn't generate proper scopes
- let type_vhdl = {}
- let type_vhdl.ctagstype = 'vhdl'
- let type_vhdl.kinds = [
- \ {'short' : 'P', 'long' : 'packages', 'fold' : 1},
- \ {'short' : 'c', 'long' : 'constants', 'fold' : 0},
- \ {'short' : 't', 'long' : 'types', 'fold' : 0},
- \ {'short' : 'T', 'long' : 'subtypes', 'fold' : 0},
- \ {'short' : 'r', 'long' : 'records', 'fold' : 0},
- \ {'short' : 'e', 'long' : 'entities', 'fold' : 0},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'p', 'long' : 'procedures', 'fold' : 0}
- \ ]
- let s:known_types.vhdl = type_vhdl
- " Vim {{{3
- let type_vim = {}
- let type_vim.ctagstype = 'vim'
- let type_vim.kinds = [
- \ {'short' : 'v', 'long' : 'variables', 'fold' : 1},
- \ {'short' : 'f', 'long' : 'functions', 'fold' : 0},
- \ {'short' : 'a', 'long' : 'autocommand groups', 'fold' : 1},
- \ {'short' : 'c', 'long' : 'commands', 'fold' : 0},
- \ {'short' : 'm', 'long' : 'maps', 'fold' : 1}
- \ ]
- let s:known_types.vim = type_vim
- " YACC {{{3
- let type_yacc = {}
- let type_yacc.ctagstype = 'yacc'
- let type_yacc.kinds = [
- \ {'short' : 'l', 'long' : 'labels', 'fold' : 0}
- \ ]
- let s:known_types.yacc = type_yacc
- " }}}3
-
- let user_defs = s:GetUserTypeDefs()
- for [key, value] in items(user_defs)
- if !has_key(s:known_types, key) ||
- \ (has_key(value, 'replace') && value.replace)
- let s:known_types[key] = value
- else
- call extend(s:known_types[key], value)
- endif
- endfor
-
- " Create a dictionary of the kind order for fast
- " access in sorting functions
- for type in values(s:known_types)
- let i = 0
- let type.kinddict = {}
- for kind in type.kinds
- let type.kinddict[kind.short] = i
- let i += 1
- endfor
- endfor
-
- let s:type_init_done = 1
-endfunction
-
-" s:GetUserTypeDefs() {{{2
-function! s:GetUserTypeDefs()
- call s:LogDebugMessage('Initializing user types')
-
- redir => defs
- silent execute 'let g:'
- redir END
-
- let deflist = split(defs, '\n')
- call map(deflist, 'substitute(v:val, ''^\S\+\zs.*'', "", "")')
- call filter(deflist, 'v:val =~ "^tagbar_type_"')
-
- let defdict = {}
- for defstr in deflist
- let type = substitute(defstr, '^tagbar_type_', '', '')
- execute 'let defdict["' . type . '"] = g:' . defstr
- endfor
-
- " If the user only specified one of kind2scope and scope2kind use it to
- " generate the other one
- " Also, transform the 'kind' definitions into dictionary format
- for def in values(defdict)
- if has_key(def, 'kinds')
- let kinds = def.kinds
- let def.kinds = []
- for kind in kinds
- let kindlist = split(kind, ':')
- let kinddict = {'short' : kindlist[0], 'long' : kindlist[1]}
- if len(kindlist) == 3
- let kinddict.fold = kindlist[2]
- else
- let kinddict.fold = 0
- endif
- call add(def.kinds, kinddict)
- endfor
- endif
-
- if has_key(def, 'kind2scope') && !has_key(def, 'scope2kind')
- let def.scope2kind = {}
- for [key, value] in items(def.kind2scope)
- let def.scope2kind[value] = key
- endfor
- elseif has_key(def, 'scope2kind') && !has_key(def, 'kind2scope')
- let def.kind2scope = {}
- for [key, value] in items(def.scope2kind)
- let def.kind2scope[value] = key
- endfor
- endif
- endfor
-
- return defdict
-endfunction
-
-" s:RestoreSession() {{{2
-" Properly restore Tagbar after a session got loaded
-function! s:RestoreSession()
- call s:LogDebugMessage('Restoring session')
-
- let tagbarwinnr = bufwinnr('__Tagbar__')
- if tagbarwinnr == -1
- " Tagbar wasn't open in the saved session, nothing to do
- return
- else
- let in_tagbar = 1
- if winnr() != tagbarwinnr
- execute tagbarwinnr . 'wincmd w'
- let in_tagbar = 0
- endif
- endif
-
- call s:Init()
-
- call s:InitWindow(g:tagbar_autoclose)
-
- " Leave the Tagbar window and come back so the update event gets triggered
- wincmd p
- execute tagbarwinnr . 'wincmd w'
-
- if !in_tagbar
- wincmd p
- endif
-endfunction
-
-" s:MapKeys() {{{2
-function! s:MapKeys()
- call s:LogDebugMessage('Mapping keys')
-
- nnoremap <script> <silent> <buffer> <2-LeftMouse>
- \ :call <SID>JumpToTag(0)<CR>
- nnoremap <script> <silent> <buffer> <LeftRelease>
- \ <LeftRelease>:call <SID>CheckMouseClick()<CR>
-
- inoremap <script> <silent> <buffer> <2-LeftMouse>
- \ <C-o>:call <SID>JumpToTag(0)<CR>
- inoremap <script> <silent> <buffer> <LeftRelease>
- \ <LeftRelease><C-o>:call <SID>CheckMouseClick()<CR>
-
- nnoremap <script> <silent> <buffer> <CR> :call <SID>JumpToTag(0)<CR>
- nnoremap <script> <silent> <buffer> p :call <SID>JumpToTag(1)<CR>
- nnoremap <script> <silent> <buffer> <Space> :call <SID>ShowPrototype()<CR>
-
- nnoremap <script> <silent> <buffer> + :call <SID>OpenFold()<CR>
- nnoremap <script> <silent> <buffer> <kPlus> :call <SID>OpenFold()<CR>
- nnoremap <script> <silent> <buffer> zo :call <SID>OpenFold()<CR>
- nnoremap <script> <silent> <buffer> - :call <SID>CloseFold()<CR>
- nnoremap <script> <silent> <buffer> <kMinus> :call <SID>CloseFold()<CR>
- nnoremap <script> <silent> <buffer> zc :call <SID>CloseFold()<CR>
- nnoremap <script> <silent> <buffer> o :call <SID>ToggleFold()<CR>
- nnoremap <script> <silent> <buffer> za :call <SID>ToggleFold()<CR>
-
- nnoremap <script> <silent> <buffer> * :call <SID>SetFoldLevel(99)<CR>
- nnoremap <script> <silent> <buffer> <kMultiply>
- \ :call <SID>SetFoldLevel(99)<CR>
- nnoremap <script> <silent> <buffer> zR :call <SID>SetFoldLevel(99)<CR>
- nnoremap <script> <silent> <buffer> = :call <SID>SetFoldLevel(0)<CR>
- nnoremap <script> <silent> <buffer> zM :call <SID>SetFoldLevel(0)<CR>
-
- nnoremap <script> <silent> <buffer> <C-N>
- \ :call <SID>GotoNextToplevelTag(1)<CR>
- nnoremap <script> <silent> <buffer> <C-P>
- \ :call <SID>GotoNextToplevelTag(-1)<CR>
-
- nnoremap <script> <silent> <buffer> s :call <SID>ToggleSort()<CR>
- nnoremap <script> <silent> <buffer> x :call <SID>ZoomWindow()<CR>
- nnoremap <script> <silent> <buffer> q :call <SID>CloseWindow()<CR>
- nnoremap <script> <silent> <buffer> <F1> :call <SID>ToggleHelp()<CR>
-endfunction
-
-" s:CreateAutocommands() {{{2
-function! s:CreateAutocommands()
- call s:LogDebugMessage('Creating autocommands')
-
- augroup TagbarAutoCmds
- autocmd!
- autocmd BufEnter __Tagbar__ nested call s:QuitIfOnlyWindow()
- autocmd BufUnload __Tagbar__ call s:CleanUp()
- autocmd CursorHold __Tagbar__ call s:ShowPrototype()
-
- autocmd BufWritePost *
- \ if line('$') < g:tagbar_updateonsave_maxlines |
- \ call s:AutoUpdate(fnamemodify(expand('<afile>'), ':p')) |
- \ endif
- autocmd BufEnter,CursorHold,FileType * call
- \ s:AutoUpdate(fnamemodify(expand('<afile>'), ':p'))
- autocmd BufDelete * call
- \ s:CleanupFileinfo(fnamemodify(expand('<afile>'), ':p'))
- augroup END
-
- let s:autocommands_done = 1
-endfunction
-
-" s:CheckForExCtags() {{{2
-" Test whether the ctags binary is actually Exuberant Ctags and not GNU ctags
-" (or something else)
-function! s:CheckForExCtags()
- call s:LogDebugMessage('Checking for Exuberant Ctags')
-
- let ctags_cmd = s:EscapeCtagsCmd(g:tagbar_ctags_bin, '--version')
- if ctags_cmd == ''
- return
- endif
-
- let ctags_output = s:ExecuteCtags(ctags_cmd)
-
- if v:shell_error || ctags_output !~# 'Exuberant Ctags'
- echoerr 'Tagbar: Ctags doesn''t seem to be Exuberant Ctags!'
- echomsg 'GNU ctags will NOT WORK.'
- \ 'Please download Exuberant Ctags from ctags.sourceforge.net'
- \ 'and install it in a directory in your $PATH'
- \ 'or set g:tagbar_ctags_bin.'
- echomsg 'Executed command: "' . ctags_cmd . '"'
- if !empty(ctags_output)
- echomsg 'Command output:'
- for line in split(ctags_output, '\n')
- echomsg line
- endfor
- endif
- return 0
- elseif !s:CheckExCtagsVersion(ctags_output)
- echoerr 'Tagbar: Exuberant Ctags is too old!'
- echomsg 'You need at least version 5.5 for Tagbar to work.'
- \ 'Please download a newer version from ctags.sourceforge.net.'
- echomsg 'Executed command: "' . ctags_cmd . '"'
- if !empty(ctags_output)
- echomsg 'Command output:'
- for line in split(ctags_output, '\n')
- echomsg line
- endfor
- endif
- return 0
- else
- let s:checked_ctags = 1
- return 1
- endif
-endfunction
-
-" s:CheckExCtagsVersion() {{{2
-function! s:CheckExCtagsVersion(output)
- call s:LogDebugMessage('Checking Exuberant Ctags version')
-
- if a:output =~ 'Exuberant Ctags Development'
- return 1
- endif
-
- let matchlist = matchlist(a:output, '\vExuberant Ctags (\d+)\.(\d+)')
- let major = matchlist[1]
- let minor = matchlist[2]
-
- return major >= 6 || (major == 5 && minor >= 5)
-endfunction
-
-" s:CheckFTCtags() {{{2
-function! s:CheckFTCtags(bin, ftype)
- if executable(a:bin)
- return a:bin
- endif
-
- if exists('g:tagbar_type_' . a:ftype)
- execute 'let userdef = ' . 'g:tagbar_type_' . a:ftype
- if has_key(userdef, 'ctagsbin')
- return userdef.ctagsbin
- else
- return ''
- endif
- endif
-
- return ''
-endfunction
-
-" Prototypes {{{1
-" Base tag {{{2
-let s:BaseTag = {}
-
-" s:BaseTag._init() {{{3
-function! s:BaseTag._init(name) dict
- let self.name = a:name
- let self.fields = {}
- let self.fields.line = 0
- let self.path = ''
- let self.fullpath = a:name
- let self.depth = 0
- let self.parent = {}
- let self.tline = -1
- let self.fileinfo = {}
-endfunction
-
-" s:BaseTag.isNormalTag() {{{3
-function! s:BaseTag.isNormalTag() dict
- return 0
-endfunction
-
-" s:BaseTag.isPseudoTag() {{{3
-function! s:BaseTag.isPseudoTag() dict
- return 0
-endfunction
-
-" s:BaseTag.isKindheader() {{{3
-function! s:BaseTag.isKindheader() dict
- return 0
-endfunction
-
-" s:BaseTag.getPrototype() {{{3
-function! s:BaseTag.getPrototype() dict
- return ''
-endfunction
-
-" s:BaseTag._getPrefix() {{{3
-function! s:BaseTag._getPrefix() dict
- let fileinfo = self.fileinfo
-
- if has_key(self, 'children') && !empty(self.children)
- if fileinfo.tagfolds[self.fields.kind][self.fullpath]
- let prefix = s:icon_closed
- else
- let prefix = s:icon_open
- endif
- else
- let prefix = ' '
- endif
- if has_key(self.fields, 'access')
- let prefix .= get(s:access_symbols, self.fields.access, ' ')
- else
- let prefix .= ' '
- endif
-
- return prefix
-endfunction
-
-" s:BaseTag.initFoldState() {{{3
-function! s:BaseTag.initFoldState() dict
- let fileinfo = self.fileinfo
-
- if s:known_files.has(fileinfo.fpath) &&
- \ has_key(fileinfo._tagfolds_old[self.fields.kind], self.fullpath)
- " The file has been updated and the tag was there before, so copy its
- " old fold state
- let fileinfo.tagfolds[self.fields.kind][self.fullpath] =
- \ fileinfo._tagfolds_old[self.fields.kind][self.fullpath]
- elseif self.depth >= fileinfo.foldlevel
- let fileinfo.tagfolds[self.fields.kind][self.fullpath] = 1
- else
- let fileinfo.tagfolds[self.fields.kind][self.fullpath] =
- \ fileinfo.kindfolds[self.fields.kind]
- endif
-endfunction
-
-" s:BaseTag.getClosedParentTline() {{{3
-function! s:BaseTag.getClosedParentTline() dict
- let tagline = self.tline
- let fileinfo = self.fileinfo
-
- let parent = self.parent
- while !empty(parent)
- if parent.isFolded()
- let tagline = parent.tline
- break
- endif
- let parent = parent.parent
- endwhile
-
- return tagline
-endfunction
-
-" s:BaseTag.isFoldable() {{{3
-function! s:BaseTag.isFoldable() dict
- return has_key(self, 'children') && !empty(self.children)
-endfunction
-
-" s:BaseTag.isFolded() {{{3
-function! s:BaseTag.isFolded() dict
- return self.fileinfo.tagfolds[self.fields.kind][self.fullpath]
-endfunction
-
-" s:BaseTag.openFold() {{{3
-function! s:BaseTag.openFold() dict
- if self.isFoldable()
- let self.fileinfo.tagfolds[self.fields.kind][self.fullpath] = 0
- endif
-endfunction
-
-" s:BaseTag.closeFold() {{{3
-function! s:BaseTag.closeFold() dict
- let newline = line('.')
-
- if !empty(self.parent) && self.parent.isKindheader()
- " Tag is child of generic 'kind'
- call self.parent.closeFold()
- let newline = self.parent.tline
- elseif self.isFoldable() && !self.isFolded()
- " Tag is parent of a scope and is not folded
- let self.fileinfo.tagfolds[self.fields.kind][self.fullpath] = 1
- let newline = self.tline
- elseif !empty(self.parent)
- " Tag is normal child, so close parent
- let parent = self.parent
- let self.fileinfo.tagfolds[parent.fields.kind][parent.fullpath] = 1
- let newline = parent.tline
- endif
-
- return newline
-endfunction
-
-" s:BaseTag.setFolded() {{{3
-function! s:BaseTag.setFolded(folded) dict
- let self.fileinfo.tagfolds[self.fields.kind][self.fullpath] = a:folded
-endfunction
-
-" s:BaseTag.openParents() {{{3
-function! s:BaseTag.openParents() dict
- let parent = self.parent
-
- while !empty(parent)
- call parent.openFold()
- let parent = parent.parent
- endwhile
-endfunction
-
-" Normal tag {{{2
-let s:NormalTag = copy(s:BaseTag)
-
-" s:NormalTag.New() {{{3
-function! s:NormalTag.New(name) dict
- let newobj = copy(self)
-
- call newobj._init(a:name)
-
- return newobj
-endfunction
-
-" s:NormalTag.isNormalTag() {{{3
-function! s:NormalTag.isNormalTag() dict
- return 1
-endfunction
-
-" s:NormalTag.str() {{{3
-function! s:NormalTag.str() dict
- let fileinfo = self.fileinfo
- let typeinfo = s:known_types[fileinfo.ftype]
-
- let suffix = get(self.fields, 'signature', '')
- if has_key(self.fields, 'type')
- let suffix .= ' : ' . self.fields.type
- elseif has_key(typeinfo, 'kind2scope') &&
- \ has_key(typeinfo.kind2scope, self.fields.kind)
- let suffix .= ' : ' . typeinfo.kind2scope[self.fields.kind]
- endif
-
- return self._getPrefix() . self.name . suffix . "\n"
-endfunction
-
-" s:NormalTag.getPrototype() {{{3
-function! s:NormalTag.getPrototype() dict
- return self.prototype
-endfunction
-
-" Pseudo tag {{{2
-let s:PseudoTag = copy(s:BaseTag)
-
-" s:PseudoTag.New() {{{3
-function! s:PseudoTag.New(name) dict
- let newobj = copy(self)
-
- call newobj._init(a:name)
-
- return newobj
-endfunction
-
-" s:PseudoTag.isPseudoTag() {{{3
-function! s:PseudoTag.isPseudoTag() dict
- return 1
-endfunction
-
-" s:PseudoTag.str() {{{3
-function! s:PseudoTag.str() dict
- let fileinfo = self.fileinfo
- let typeinfo = s:known_types[fileinfo.ftype]
-
- let suffix = get(self.fields, 'signature', '')
- if has_key(typeinfo.kind2scope, self.fields.kind)
- let suffix .= ' : ' . typeinfo.kind2scope[self.fields.kind]
- endif
-
- return self._getPrefix() . self.name . '*' . suffix
-endfunction
-
-" Kind header {{{2
-let s:KindheaderTag = copy(s:BaseTag)
-
-" s:KindheaderTag.New() {{{3
-function! s:KindheaderTag.New(name) dict
- let newobj = copy(self)
-
- call newobj._init(a:name)
-
- return newobj
-endfunction
-
-" s:KindheaderTag.isKindheader() {{{3
-function! s:KindheaderTag.isKindheader() dict
- return 1
-endfunction
-
-" s:KindheaderTag.getPrototype() {{{3
-function! s:KindheaderTag.getPrototype() dict
- return self.name . ': ' .
- \ self.numtags . ' ' . (self.numtags > 1 ? 'tags' : 'tag')
-endfunction
-
-" s:KindheaderTag.isFoldable() {{{3
-function! s:KindheaderTag.isFoldable() dict
- return 1
-endfunction
-
-" s:KindheaderTag.isFolded() {{{3
-function! s:KindheaderTag.isFolded() dict
- return self.fileinfo.kindfolds[self.short]
-endfunction
-
-" s:KindheaderTag.openFold() {{{3
-function! s:KindheaderTag.openFold() dict
- let self.fileinfo.kindfolds[self.short] = 0
-endfunction
-
-" s:KindheaderTag.closeFold() {{{3
-function! s:KindheaderTag.closeFold() dict
- let self.fileinfo.kindfolds[self.short] = 1
- return line('.')
-endfunction
-
-" s:KindheaderTag.toggleFold() {{{3
-function! s:KindheaderTag.toggleFold() dict
- let fileinfo = s:known_files.getCurrent()
-
- let fileinfo.kindfolds[self.short] = !fileinfo.kindfolds[self.short]
-endfunction
-
-" File info {{{2
-let s:FileInfo = {}
-
-" s:FileInfo.New() {{{3
-function! s:FileInfo.New(fname, ftype) dict
- let newobj = copy(self)
-
- " The complete file path
- let newobj.fpath = a:fname
-
- " File modification time
- let newobj.mtime = getftime(a:fname)
-
- " The vim file type
- let newobj.ftype = a:ftype
-
- " List of the tags that are present in the file, sorted according to the
- " value of 'g:tagbar_sort'
- let newobj.tags = []
-
- " Dictionary of the tags, indexed by line number in the file
- let newobj.fline = {}
-
- " Dictionary of the tags, indexed by line number in the tagbar
- let newobj.tline = {}
-
- " Dictionary of the folding state of 'kind's, indexed by short name
- let newobj.kindfolds = {}
- let typeinfo = s:known_types[a:ftype]
- " copy the default fold state from the type info
- for kind in typeinfo.kinds
- let newobj.kindfolds[kind.short] =
- \ g:tagbar_foldlevel == 0 ? 1 : kind.fold
- endfor
-
- " Dictionary of dictionaries of the folding state of individual tags,
- " indexed by kind and full path
- let newobj.tagfolds = {}
- for kind in typeinfo.kinds
- let newobj.tagfolds[kind.short] = {}
- endfor
-
- " The current foldlevel of the file
- let newobj.foldlevel = g:tagbar_foldlevel
-
- return newobj
-endfunction
-
-" s:FileInfo.reset() {{{3
-" Reset stuff that gets regenerated while processing a file and save the old
-" tag folds
-function! s:FileInfo.reset() dict
- let self.mtime = getftime(self.fpath)
- let self.tags = []
- let self.fline = {}
- let self.tline = {}
-
- let self._tagfolds_old = self.tagfolds
- let self.tagfolds = {}
-
- let typeinfo = s:known_types[self.ftype]
- for kind in typeinfo.kinds
- let self.tagfolds[kind.short] = {}
- endfor
-endfunction
-
-" s:FileInfo.clearOldFolds() {{{3
-function! s:FileInfo.clearOldFolds() dict
- if exists('self._tagfolds_old')
- unlet self._tagfolds_old
- endif
-endfunction
-
-" s:FileInfo.sortTags() {{{3
-function! s:FileInfo.sortTags() dict
- if has_key(s:compare_typeinfo, 'sort')
- if s:compare_typeinfo.sort
- call s:SortTags(self.tags, 's:CompareByKind')
- else
- call s:SortTags(self.tags, 's:CompareByLine')
- endif
- elseif g:tagbar_sort
- call s:SortTags(self.tags, 's:CompareByKind')
- else
- call s:SortTags(self.tags, 's:CompareByLine')
- endif
-endfunction
-
-" s:FileInfo.openKindFold() {{{3
-function! s:FileInfo.openKindFold(kind) dict
- let self.kindfolds[a:kind.short] = 0
-endfunction
-
-" s:FileInfo.closeKindFold() {{{3
-function! s:FileInfo.closeKindFold(kind) dict
- let self.kindfolds[a:kind.short] = 1
-endfunction
-
-" Known files {{{2
-let s:known_files = {
- \ '_current' : {},
- \ '_files' : {}
-\ }
-
-" s:known_files.getCurrent() {{{3
-function! s:known_files.getCurrent() dict
- return self._current
-endfunction
-
-" s:known_files.setCurrent() {{{3
-function! s:known_files.setCurrent(fileinfo) dict
- let self._current = a:fileinfo
-endfunction
-
-" s:known_files.get() {{{3
-function! s:known_files.get(fname) dict
- return get(self._files, a:fname, {})
-endfunction
-
-" s:known_files.put() {{{3
-" Optional second argument is the filename
-function! s:known_files.put(fileinfo, ...) dict
- if a:0 == 1
- let self._files[a:1] = a:fileinfo
- else
- let fname = a:fileinfo.fpath
- let self._files[fname] = a:fileinfo
- endif
-endfunction
-
-" s:known_files.has() {{{3
-function! s:known_files.has(fname) dict
- return has_key(self._files, a:fname)
-endfunction
-
-" s:known_files.rm() {{{3
-function! s:known_files.rm(fname) dict
- if s:known_files.has(a:fname)
- call remove(self._files, a:fname)
- endif
-endfunction
-
-" Window management {{{1
-" s:ToggleWindow() {{{2
-function! s:ToggleWindow()
- let tagbarwinnr = bufwinnr("__Tagbar__")
- if tagbarwinnr != -1
- call s:CloseWindow()
- return
- endif
-
- call s:OpenWindow('')
-endfunction
-
-" s:OpenWindow() {{{2
-function! s:OpenWindow(flags)
- let autofocus = a:flags =~# 'f'
- let jump = a:flags =~# 'j'
- let autoclose = a:flags =~# 'c'
-
- " If the tagbar window is already open check jump flag
- " Also set the autoclose flag if requested
- let tagbarwinnr = bufwinnr('__Tagbar__')
- if tagbarwinnr != -1
- if winnr() != tagbarwinnr && jump
- execute tagbarwinnr . 'wincmd w'
- if autoclose
- let w:autoclose = autoclose
- endif
- endif
- return
- endif
-
- call s:Init()
-
- " Expand the Vim window to accomodate for the Tagbar window if requested
- if g:tagbar_expand && !s:window_expanded && has('gui_running')
- let &columns += g:tagbar_width + 1
- let s:window_expanded = 1
- endif
-
- let eventignore_save = &eventignore
- set eventignore=all
-
- let openpos = g:tagbar_left ? 'topleft vertical ' : 'botright vertical '
- exe 'silent keepalt ' . openpos . g:tagbar_width . 'split ' . '__Tagbar__'
-
- let &eventignore = eventignore_save
-
- call s:InitWindow(autoclose)
-
- wincmd p
-
- " Jump back to the tagbar window if autoclose or autofocus is set. Can't
- " just stay in it since it wouldn't trigger the update event
- if g:tagbar_autoclose || autofocus || g:tagbar_autofocus
- let tagbarwinnr = bufwinnr('__Tagbar__')
- execute tagbarwinnr . 'wincmd w'
- endif
-endfunction
-
-" s:InitWindow() {{{2
-function! s:InitWindow(autoclose)
- setlocal noreadonly " in case the "view" mode is used
- setlocal buftype=nofile
- setlocal bufhidden=hide
- setlocal noswapfile
- setlocal nobuflisted
- setlocal nomodifiable
- setlocal filetype=tagbar
- setlocal nolist
- setlocal nonumber
- setlocal nowrap
- setlocal winfixwidth
- setlocal textwidth=0
- setlocal nocursorline
- setlocal nocursorcolumn
-
- if exists('+relativenumber')
- setlocal norelativenumber
- endif
-
- setlocal nofoldenable
- setlocal foldcolumn=0
- " Reset fold settings in case a plugin set them globally to something
- " expensive. Apparently 'foldexpr' gets executed even if 'foldenable' is
- " off, and then for every appended line (like with :put).
- setlocal foldmethod&
- setlocal foldexpr&
-
- " Earlier versions have a bug in local, evaluated statuslines
- if v:version > 701 || (v:version == 701 && has('patch097'))
- setlocal statusline=%!TagbarGenerateStatusline()
- else
- setlocal statusline=Tagbar
- endif
-
- " Script-local variable needed since compare functions can't
- " take extra arguments
- let s:compare_typeinfo = {}
-
- let s:is_maximized = 0
- let s:short_help = 1
-
- let w:autoclose = a:autoclose
-
- if has('balloon_eval')
- setlocal balloonexpr=TagbarBalloonExpr()
- set ballooneval
- endif
-
- let cpoptions_save = &cpoptions
- set cpoptions&vim
-
- if !hasmapto('JumpToTag', 'n')
- call s:MapKeys()
- endif
-
- if !s:autocommands_done
- call s:CreateAutocommands()
- endif
-
- let &cpoptions = cpoptions_save
-endfunction
-
-" s:CloseWindow() {{{2
-function! s:CloseWindow()
- let tagbarwinnr = bufwinnr('__Tagbar__')
- if tagbarwinnr == -1
- return
- endif
-
- let tagbarbufnr = winbufnr(tagbarwinnr)
-
- if winnr() == tagbarwinnr
- if winbufnr(2) != -1
- " Other windows are open, only close the tagbar one
- close
- wincmd p
- endif
- else
- " Go to the tagbar window, close it and then come back to the
- " original window
- let curbufnr = bufnr('%')
- execute tagbarwinnr . 'wincmd w'
- close
- " Need to jump back to the original window only if we are not
- " already in that window
- let winnum = bufwinnr(curbufnr)
- if winnr() != winnum
- exe winnum . 'wincmd w'
- endif
- endif
-
- " If the Vim window has been expanded, and Tagbar is not open in any other
- " tabpages, shrink the window again
- if s:window_expanded
- let tablist = []
- for i in range(tabpagenr('$'))
- call extend(tablist, tabpagebuflist(i + 1))
- endfor
-
- if index(tablist, tagbarbufnr) == -1
- let &columns -= g:tagbar_width + 1
- let s:window_expanded = 0
- endif
- endif
-endfunction
-
-" s:ZoomWindow() {{{2
-function! s:ZoomWindow()
- if s:is_maximized
- execute 'vert resize ' . g:tagbar_width
- let s:is_maximized = 0
- else
- vert resize
- let s:is_maximized = 1
- endif
-endfunction
-
-" Tag processing {{{1
-" s:ProcessFile() {{{2
-" Execute ctags and put the information into a 'FileInfo' object
-function! s:ProcessFile(fname, ftype)
- call s:LogDebugMessage('ProcessFile called on ' . a:fname)
-
- if !s:IsValidFile(a:fname, a:ftype)
- call s:LogDebugMessage('Not a valid file, returning')
- return
- endif
-
- let ctags_output = s:ExecuteCtagsOnFile(a:fname, a:ftype)
-
- if ctags_output == -1
- call s:LogDebugMessage('Ctags error when processing file')
- " put an empty entry into known_files so the error message is only
- " shown once
- call s:known_files.put({}, a:fname)
- return
- elseif ctags_output == ''
- call s:LogDebugMessage('Ctags output empty')
- return
- endif
-
- " If the file has only been updated preserve the fold states, otherwise
- " create a new entry
- if s:known_files.has(a:fname)
- let fileinfo = s:known_files.get(a:fname)
- call fileinfo.reset()
- else
- let fileinfo = s:FileInfo.New(a:fname, a:ftype)
- endif
-
- let typeinfo = s:known_types[a:ftype]
-
- " Parse the ctags output lines
- call s:LogDebugMessage('Parsing ctags output')
- let rawtaglist = split(ctags_output, '\n\+')
- for line in rawtaglist
- " skip comments
- if line =~# '^!_TAG_'
- continue
- endif
-
- let parts = split(line, ';"')
- if len(parts) == 2 " Is a valid tag line
- let taginfo = s:ParseTagline(parts[0], parts[1], typeinfo, fileinfo)
- let fileinfo.fline[taginfo.fields.line] = taginfo
- call add(fileinfo.tags, taginfo)
- endif
- endfor
-
- " Process scoped tags
- let processedtags = []
- if has_key(typeinfo, 'kind2scope')
- call s:LogDebugMessage('Processing scoped tags')
-
- let scopedtags = []
- let is_scoped = 'has_key(typeinfo.kind2scope, v:val.fields.kind) ||
- \ has_key(v:val, "scope")'
- let scopedtags += filter(copy(fileinfo.tags), is_scoped)
- call filter(fileinfo.tags, '!(' . is_scoped . ')')
-
- call s:AddScopedTags(scopedtags, processedtags, {}, 0,
- \ typeinfo, fileinfo)
-
- if !empty(scopedtags)
- echoerr 'Tagbar: ''scopedtags'' not empty after processing,'
- \ 'this should never happen!'
- \ 'Please contact the script maintainer with an example.'
- endif
- endif
- call s:LogDebugMessage('Number of top-level tags: ' . len(processedtags))
-
- " Create a placeholder tag for the 'kind' header for folding purposes
- for kind in typeinfo.kinds
-
- let curtags = filter(copy(fileinfo.tags),
- \ 'v:val.fields.kind ==# kind.short')
- call s:LogDebugMessage('Processing kind: ' . kind.short .
- \ ', number of tags: ' . len(curtags))
-
- if empty(curtags)
- continue
- endif
-
- let kindtag = s:KindheaderTag.New(kind.long)
- let kindtag.short = kind.short
- let kindtag.numtags = len(curtags)
- let kindtag.fileinfo = fileinfo
-
- for tag in curtags
- let tag.parent = kindtag
- endfor
- endfor
-
- if !empty(processedtags)
- call extend(fileinfo.tags, processedtags)
- endif
-
- " Clear old folding information from previous file version to prevent leaks
- call fileinfo.clearOldFolds()
-
- " Sort the tags
- let s:compare_typeinfo = typeinfo
- call fileinfo.sortTags()
-
- call s:known_files.put(fileinfo)
-endfunction
-
-" s:ExecuteCtagsOnFile() {{{2
-function! s:ExecuteCtagsOnFile(fname, ftype)
- call s:LogDebugMessage('ExecuteCtagsOnFile called on ' . a:fname)
-
- let typeinfo = s:known_types[a:ftype]
-
- if has_key(typeinfo, 'ctagsargs')
- let ctags_args = ' ' . typeinfo.ctagsargs . ' '
- else
- let ctags_args = ' -f - '
- let ctags_args .= ' --format=2 '
- let ctags_args .= ' --excmd=pattern '
- let ctags_args .= ' --fields=nksSa '
- let ctags_args .= ' --extra= '
- let ctags_args .= ' --sort=yes '
-
- " Include extra type definitions
- if has_key(typeinfo, 'deffile')
- let ctags_args .= ' --options=' . typeinfo.deffile . ' '
- endif
-
- let ctags_type = typeinfo.ctagstype
-
- let ctags_kinds = ''
- for kind in typeinfo.kinds
- let ctags_kinds .= kind.short
- endfor
-
- let ctags_args .= ' --language-force=' . ctags_type .
- \ ' --' . ctags_type . '-kinds=' . ctags_kinds . ' '
- endif
-
- if has_key(typeinfo, 'ctagsbin')
- " reset 'wildignore' temporarily in case *.exe is included in it
- let wildignore_save = &wildignore
- set wildignore&
- let ctags_bin = expand(typeinfo.ctagsbin)
- let &wildignore = wildignore_save
- else
- let ctags_bin = g:tagbar_ctags_bin
- endif
-
- let ctags_cmd = s:EscapeCtagsCmd(ctags_bin, ctags_args, a:fname)
- if ctags_cmd == ''
- return ''
- endif
-
- let ctags_output = s:ExecuteCtags(ctags_cmd)
-
- if v:shell_error || ctags_output =~ 'Warning: cannot open source file'
- echoerr 'Tagbar: Could not execute ctags for ' . a:fname . '!'
- echomsg 'Executed command: "' . ctags_cmd . '"'
- if !empty(ctags_output)
- call s:LogDebugMessage('Command output:')
- call s:LogDebugMessage(ctags_output)
- echomsg 'Command output:'
- for line in split(ctags_output, '\n')
- echomsg line
- endfor
- endif
- return -1
- endif
-
- call s:LogDebugMessage('Ctags executed successfully')
- return ctags_output
-endfunction
-
-" s:ParseTagline() {{{2
-" Structure of a tag line:
-" tagname<TAB>filename<TAB>expattern;"fields
-" fields: <TAB>name:value
-" fields that are always present: kind, line
-function! s:ParseTagline(part1, part2, typeinfo, fileinfo)
- let basic_info = split(a:part1, '\t')
-
- let taginfo = s:NormalTag.New(basic_info[0])
- let taginfo.file = basic_info[1]
-
- " the pattern can contain tabs and thus may have been split up, so join
- " the rest of the items together again
- let pattern = join(basic_info[2:], "\t")
- let start = 2 " skip the slash and the ^
- let end = strlen(pattern) - 1
- if pattern[end - 1] ==# '$'
- let end -= 1
- let dollar = '\$'
- else
- let dollar = ''
- endif
- let pattern = strpart(pattern, start, end - start)
- let taginfo.pattern = '\V\^\C' . pattern . dollar
- let prototype = substitute(pattern, '^[[:space:]]\+', '', '')
- let prototype = substitute(prototype, '[[:space:]]\+$', '', '')
- let taginfo.prototype = prototype
-
- let fields = split(a:part2, '\t')
- let taginfo.fields.kind = remove(fields, 0)
- for field in fields
- " can't use split() since the value can contain ':'
- let delimit = stridx(field, ':')
- let key = strpart(field, 0, delimit)
- let val = strpart(field, delimit + 1)
- if len(val) > 0
- let taginfo.fields[key] = val
- endif
- endfor
- " Needed for jsctags
- if has_key(taginfo.fields, 'lineno')
- let taginfo.fields.line = taginfo.fields.lineno
- endif
-
- " Make some information easier accessible
- if has_key(a:typeinfo, 'scope2kind')
- for scope in keys(a:typeinfo.scope2kind)
- if has_key(taginfo.fields, scope)
- let taginfo.scope = scope
- let taginfo.path = taginfo.fields[scope]
-
- let taginfo.fullpath = taginfo.path . a:typeinfo.sro .
- \ taginfo.name
- break
- endif
- endfor
- let taginfo.depth = len(split(taginfo.path, '\V' . a:typeinfo.sro))
- endif
-
- let taginfo.fileinfo = a:fileinfo
-
- " Needed for folding
- try
- call taginfo.initFoldState()
- catch /^Vim(\a\+):E716:/ " 'Key not present in Dictionary'
- " The tag has a 'kind' that doesn't exist in the type definition
- echoerr 'Your ctags and Tagbar configurations are out of sync!'
- \ 'Please read '':help tagbar-extend''.'
- endtry
-
- return taginfo
-endfunction
-
-" s:AddScopedTags() {{{2
-" Recursively process tags. Unfortunately there is a problem: not all tags in
-" a hierarchy are actually there. For example, in C++ a class can be defined
-" in a header file and implemented in a .cpp file (so the class itself doesn't
-" appear in the .cpp file and thus doesn't generate a tag). Another example
-" are anonymous structures like namespaces, structs, enums, and unions, that
-" also don't get a tag themselves. These tags are thus called 'pseudo-tags' in
-" Tagbar. Properly parsing them is quite tricky, so try not to think about it
-" too much.
-function! s:AddScopedTags(tags, processedtags, parent, depth,
- \ typeinfo, fileinfo)
- if !empty(a:parent)
- let curpath = a:parent.fullpath
- let pscope = a:typeinfo.kind2scope[a:parent.fields.kind]
- else
- let curpath = ''
- let pscope = ''
- endif
-
- let is_cur_tag = 'v:val.depth == a:depth'
-
- if !empty(curpath)
- " Check whether the tag is either a direct child at the current depth
- " or at least a proper grandchild with pseudo-tags in between. If it
- " is a direct child also check for matching scope.
- let is_cur_tag .= ' &&
- \ (v:val.path ==# curpath ||
- \ match(v:val.path, ''\V\^\C'' . curpath . a:typeinfo.sro) == 0) &&
- \ (v:val.path ==# curpath ? (v:val.scope ==# pscope) : 1)'
- endif
-
- let curtags = filter(copy(a:tags), is_cur_tag)
-
- if !empty(curtags)
- call filter(a:tags, '!(' . is_cur_tag . ')')
-
- let realtags = []
- let pseudotags = []
-
- while !empty(curtags)
- let tag = remove(curtags, 0)
-
- if tag.path != curpath
- " tag is child of a pseudo-tag, so create a new pseudo-tag and
- " add all its children to it
- let pseudotag = s:ProcessPseudoTag(curtags, tag, a:parent,
- \ a:typeinfo, a:fileinfo)
-
- call add(pseudotags, pseudotag)
- else
- call add(realtags, tag)
- endif
- endwhile
-
- " Recursively add the children of the tags on the current level
- for tag in realtags
- let tag.parent = a:parent
-
- if !has_key(a:typeinfo.kind2scope, tag.fields.kind)
- continue
- endif
-
- if !has_key(tag, 'children')
- let tag.children = []
- endif
-
- call s:AddScopedTags(a:tags, tag.children, tag, a:depth + 1,
- \ a:typeinfo, a:fileinfo)
- endfor
- call extend(a:processedtags, realtags)
-
- " Recursively add the children of the tags that are children of the
- " pseudo-tags on the current level
- for tag in pseudotags
- call s:ProcessPseudoChildren(a:tags, tag, a:depth, a:typeinfo,
- \ a:fileinfo)
- endfor
- call extend(a:processedtags, pseudotags)
- endif
-
- " Now we have to check if there are any pseudo-tags at the current level
- " so we have to check for real tags at a lower level, i.e. grandchildren
- let is_grandchild = 'v:val.depth > a:depth'
-
- if !empty(curpath)
- let is_grandchild .=
- \ ' && match(v:val.path, ''\V\^\C'' . curpath . a:typeinfo.sro) == 0'
- endif
-
- let grandchildren = filter(copy(a:tags), is_grandchild)
-
- if !empty(grandchildren)
- call s:AddScopedTags(a:tags, a:processedtags, a:parent, a:depth + 1,
- \ a:typeinfo, a:fileinfo)
- endif
-endfunction
-
-" s:ProcessPseudoTag() {{{2
-function! s:ProcessPseudoTag(curtags, tag, parent, typeinfo, fileinfo)
- let curpath = !empty(a:parent) ? a:parent.fullpath : ''
-
- let pseudoname = substitute(a:tag.path, curpath, '', '')
- let pseudoname = substitute(pseudoname, '\V\^' . a:typeinfo.sro, '', '')
- let pseudotag = s:CreatePseudoTag(pseudoname, a:parent, a:tag.scope,
- \ a:typeinfo, a:fileinfo)
- let pseudotag.children = [a:tag]
-
- " get all the other (direct) children of the current pseudo-tag
- let ispseudochild = 'v:val.path ==# a:tag.path && v:val.scope ==# a:tag.scope'
- let pseudochildren = filter(copy(a:curtags), ispseudochild)
- if !empty(pseudochildren)
- call filter(a:curtags, '!(' . ispseudochild . ')')
- call extend(pseudotag.children, pseudochildren)
- endif
-
- return pseudotag
-endfunction
-
-" s:ProcessPseudoChildren() {{{2
-function! s:ProcessPseudoChildren(tags, tag, depth, typeinfo, fileinfo)
- for childtag in a:tag.children
- let childtag.parent = a:tag
-
- if !has_key(a:typeinfo.kind2scope, childtag.fields.kind)
- continue
- endif
-
- if !has_key(childtag, 'children')
- let childtag.children = []
- endif
-
- call s:AddScopedTags(a:tags, childtag.children, childtag, a:depth + 1,
- \ a:typeinfo, a:fileinfo)
- endfor
-
- let is_grandchild = 'v:val.depth > a:depth &&
- \ match(v:val.path, ''^\C'' . a:tag.fullpath) == 0'
- let grandchildren = filter(copy(a:tags), is_grandchild)
- if !empty(grandchildren)
- call s:AddScopedTags(a:tags, a:tag.children, a:tag, a:depth + 1,
- \ a:typeinfo, a:fileinfo)
- endif
-endfunction
-
-" s:CreatePseudoTag() {{{2
-function! s:CreatePseudoTag(name, parent, scope, typeinfo, fileinfo)
- if !empty(a:parent)
- let curpath = a:parent.fullpath
- let pscope = a:typeinfo.kind2scope[a:parent.fields.kind]
- else
- let curpath = ''
- let pscope = ''
- endif
-
- let pseudotag = s:PseudoTag.New(a:name)
- let pseudotag.fields.kind = a:typeinfo.scope2kind[a:scope]
-
- let parentscope = substitute(curpath, a:name . '$', '', '')
- let parentscope = substitute(parentscope,
- \ '\V\^' . a:typeinfo.sro . '\$', '', '')
-
- if pscope != ''
- let pseudotag.fields[pscope] = parentscope
- let pseudotag.scope = pscope
- let pseudotag.path = parentscope
- let pseudotag.fullpath =
- \ pseudotag.path . a:typeinfo.sro . pseudotag.name
- endif
- let pseudotag.depth = len(split(pseudotag.path, '\V' . a:typeinfo.sro))
-
- let pseudotag.parent = a:parent
-
- let pseudotag.fileinfo = a:fileinfo
-
- call pseudotag.initFoldState()
-
- return pseudotag
-endfunction
-
-" Sorting {{{1
-" s:SortTags() {{{2
-function! s:SortTags(tags, comparemethod)
- call sort(a:tags, a:comparemethod)
-
- for tag in a:tags
- if has_key(tag, 'children')
- call s:SortTags(tag.children, a:comparemethod)
- endif
- endfor
-endfunction
-
-" s:CompareByKind() {{{2
-function! s:CompareByKind(tag1, tag2)
- let typeinfo = s:compare_typeinfo
-
- if typeinfo.kinddict[a:tag1.fields.kind] <#
- \ typeinfo.kinddict[a:tag2.fields.kind]
- return -1
- elseif typeinfo.kinddict[a:tag1.fields.kind] >#
- \ typeinfo.kinddict[a:tag2.fields.kind]
- return 1
- else
- " Ignore '~' prefix for C++ destructors to sort them directly under
- " the constructors
- if a:tag1.name[0] ==# '~'
- let name1 = a:tag1.name[1:]
- else
- let name1 = a:tag1.name
- endif
- if a:tag2.name[0] ==# '~'
- let name2 = a:tag2.name[1:]
- else
- let name2 = a:tag2.name
- endif
-
- if name1 <=# name2
- return -1
- else
- return 1
- endif
- endif
-endfunction
-
-" s:CompareByLine() {{{2
-function! s:CompareByLine(tag1, tag2)
- return a:tag1.fields.line - a:tag2.fields.line
-endfunction
-
-" s:ToggleSort() {{{2
-function! s:ToggleSort()
- let fileinfo = s:known_files.getCurrent()
- if empty(fileinfo)
- return
- endif
-
- let curline = line('.')
-
- match none
-
- let s:compare_typeinfo = s:known_types[fileinfo.ftype]
-
- if has_key(s:compare_typeinfo, 'sort')
- let s:compare_typeinfo.sort = !s:compare_typeinfo.sort
- else
- let g:tagbar_sort = !g:tagbar_sort
- endif
-
- call fileinfo.sortTags()
-
- call s:RenderContent()
-
- execute curline
-endfunction
-
-" Display {{{1
-" s:RenderContent() {{{2
-function! s:RenderContent(...)
- call s:LogDebugMessage('RenderContent called')
-
- if a:0 == 1
- let fileinfo = a:1
- else
- let fileinfo = s:known_files.getCurrent()
- endif
-
- if empty(fileinfo)
- call s:LogDebugMessage('Empty fileinfo, returning')
- return
- endif
-
- let tagbarwinnr = bufwinnr('__Tagbar__')
-
- if &filetype == 'tagbar'
- let in_tagbar = 1
- else
- let in_tagbar = 0
- let prevwinnr = winnr()
- execute tagbarwinnr . 'wincmd w'
- endif
-
- if !empty(s:known_files.getCurrent()) &&
- \ fileinfo.fpath ==# s:known_files.getCurrent().fpath
- " We're redisplaying the same file, so save the view
- call s:LogDebugMessage('Redisplaying file' . fileinfo.fpath)
- let saveline = line('.')
- let savecol = col('.')
- let topline = line('w0')
- endif
-
- let lazyredraw_save = &lazyredraw
- set lazyredraw
- let eventignore_save = &eventignore
- set eventignore=all
-
- setlocal modifiable
-
- silent %delete _
-
- call s:PrintHelp()
-
- let typeinfo = s:known_types[fileinfo.ftype]
-
- " Print tags
- call s:PrintKinds(typeinfo, fileinfo)
-
- " Delete empty lines at the end of the buffer
- for linenr in range(line('$'), 1, -1)
- if getline(linenr) =~ '^$'
- execute 'silent ' . linenr . 'delete _'
- else
- break
- endif
- endfor
-
- setlocal nomodifiable
-
- if !empty(s:known_files.getCurrent()) &&
- \ fileinfo.fpath ==# s:known_files.getCurrent().fpath
- let scrolloff_save = &scrolloff
- set scrolloff=0
-
- call cursor(topline, 1)
- normal! zt
- call cursor(saveline, savecol)
-
- let &scrolloff = scrolloff_save
- else
- " Make sure as much of the Tagbar content as possible is shown in the
- " window by jumping to the top after drawing
- execute 1
- call winline()
-
- " Invalidate highlight cache from old file
- let s:last_highlight_tline = 0
- endif
-
- let &lazyredraw = lazyredraw_save
- let &eventignore = eventignore_save
-
- if !in_tagbar
- execute prevwinnr . 'wincmd w'
- endif
-endfunction
-
-" s:PrintKinds() {{{2
-function! s:PrintKinds(typeinfo, fileinfo)
- call s:LogDebugMessage('PrintKinds called')
-
- let first_tag = 1
-
- for kind in a:typeinfo.kinds
- let curtags = filter(copy(a:fileinfo.tags),
- \ 'v:val.fields.kind ==# kind.short')
- call s:LogDebugMessage('Printing kind: ' . kind.short .
- \ ', number of (top-level) tags: ' . len(curtags))
-
- if empty(curtags)
- continue
- endif
-
- if has_key(a:typeinfo, 'kind2scope') &&
- \ has_key(a:typeinfo.kind2scope, kind.short)
- " Scoped tags
- for tag in curtags
- if g:tagbar_compact && first_tag && s:short_help
- silent 0put =tag.str()
- else
- silent put =tag.str()
- endif
-
- " Save the current tagbar line in the tag for easy
- " highlighting access
- let curline = line('.')
- let tag.tline = curline
- let a:fileinfo.tline[curline] = tag
-
- " Print children
- if tag.isFoldable() && !tag.isFolded()
- for ckind in a:typeinfo.kinds
- let childtags = filter(copy(tag.children),
- \ 'v:val.fields.kind ==# ckind.short')
- if len(childtags) > 0
- " Print 'kind' header of following children
- if !has_key(a:typeinfo.kind2scope, ckind.short)
- silent put =' [' . ckind.long . ']'
- let a:fileinfo.tline[line('.')] = tag
- endif
- for childtag in childtags
- call s:PrintTag(childtag, 1,
- \ a:fileinfo, a:typeinfo)
- endfor
- endif
- endfor
- endif
-
- if !g:tagbar_compact
- silent put _
- endif
-
- let first_tag = 0
- endfor
- else
- " Non-scoped tags
- let kindtag = curtags[0].parent
-
- if kindtag.isFolded()
- let foldmarker = s:icon_closed
- else
- let foldmarker = s:icon_open
- endif
-
- if g:tagbar_compact && first_tag && s:short_help
- silent 0put =foldmarker . ' ' . kind.long
- else
- silent put =foldmarker . ' ' . kind.long
- endif
-
- let curline = line('.')
- let kindtag.tline = curline
- let a:fileinfo.tline[curline] = kindtag
-
- if !kindtag.isFolded()
- for tag in curtags
- let str = tag.str()
- silent put =' ' . str
-
- " Save the current tagbar line in the tag for easy
- " highlighting access
- let curline = line('.')
- let tag.tline = curline
- let a:fileinfo.tline[curline] = tag
- let tag.depth = 1
- endfor
- endif
-
- if !g:tagbar_compact
- silent put _
- endif
-
- let first_tag = 0
- endif
- endfor
-endfunction
-
-" s:PrintTag() {{{2
-function! s:PrintTag(tag, depth, fileinfo, typeinfo)
- " Print tag indented according to depth
- silent put =repeat(' ', a:depth * 2) . a:tag.str()
-
- " Save the current tagbar line in the tag for easy
- " highlighting access
- let curline = line('.')
- let a:tag.tline = curline
- let a:fileinfo.tline[curline] = a:tag
-
- " Recursively print children
- if a:tag.isFoldable() && !a:tag.isFolded()
- for ckind in a:typeinfo.kinds
- let childtags = filter(copy(a:tag.children),
- \ 'v:val.fields.kind ==# ckind.short')
- if len(childtags) > 0
- " Print 'kind' header of following children
- if !has_key(a:typeinfo.kind2scope, ckind.short)
- silent put =' ' . repeat(' ', a:depth * 2) .
- \ '[' . ckind.long . ']'
- let a:fileinfo.tline[line('.')] = a:tag
- endif
- for childtag in childtags
- call s:PrintTag(childtag, a:depth + 1,
- \ a:fileinfo, a:typeinfo)
- endfor
- endif
- endfor
- endif
-endfunction
-
-" s:PrintHelp() {{{2
-function! s:PrintHelp()
- if !g:tagbar_compact && s:short_help
- silent 0put ='\" Press <F1> for help'
- silent put _
- elseif !s:short_help
- silent 0put ='\" Tagbar keybindings'
- silent put ='\"'
- silent put ='\" --------- General ---------'
- silent put ='\" <Enter> : Jump to tag definition'
- silent put ='\" <Space> : Display tag prototype'
- silent put ='\"'
- silent put ='\" ---------- Folds ----------'
- silent put ='\" +, zo : Open fold'
- silent put ='\" -, zc : Close fold'
- silent put ='\" o, za : Toggle fold'
- silent put ='\" *, zR : Open all folds'
- silent put ='\" =, zM : Close all folds'
- silent put ='\"'
- silent put ='\" ---------- Misc -----------'
- silent put ='\" s : Toggle sort'
- silent put ='\" x : Zoom window in/out'
- silent put ='\" q : Close window'
- silent put ='\" <F1> : Remove help'
- silent put _
- endif
-endfunction
-
-" s:RenderKeepView() {{{2
-" The gist of this function was taken from NERDTree by Martin Grenfell.
-function! s:RenderKeepView(...)
- if a:0 == 1
- let line = a:1
- else
- let line = line('.')
- endif
-
- let curcol = col('.')
- let topline = line('w0')
-
- call s:RenderContent()
-
- let scrolloff_save = &scrolloff
- set scrolloff=0
-
- call cursor(topline, 1)
- normal! zt
- call cursor(line, curcol)
-
- let &scrolloff = scrolloff_save
-
- redraw
-endfunction
-
-" User actions {{{1
-" s:HighlightTag() {{{2
-function! s:HighlightTag()
- let tagline = 0
-
- let tag = s:GetNearbyTag()
- if !empty(tag)
- let tagline = tag.tline
- endif
-
- " Don't highlight the tag again if it's the same one as last time.
- " This prevents the Tagbar window from jumping back after scrolling with
- " the mouse.
- if tagline == s:last_highlight_tline
- return
- else
- let s:last_highlight_tline = tagline
- endif
-
- let eventignore_save = &eventignore
- set eventignore=all
-
- let tagbarwinnr = bufwinnr('__Tagbar__')
- let prevwinnr = winnr()
- execute tagbarwinnr . 'wincmd w'
-
- match none
-
- " No tag above cursor position so don't do anything
- if tagline == 0
- execute prevwinnr . 'wincmd w'
- let &eventignore = eventignore_save
- redraw
- return
- endif
-
- if g:tagbar_autoshowtag
- call s:OpenParents(tag)
- endif
-
- " Check whether the tag is inside a closed fold and highlight the parent
- " instead in that case
- let tagline = tag.getClosedParentTline()
-
- " Go to the line containing the tag
- execute tagline
-
- " Make sure the tag is visible in the window
- call winline()
-
- let foldpat = '[' . s:icon_open . s:icon_closed . ' ]'
- let pattern = '/^\%' . tagline . 'l\s*' . foldpat . '[-+# ]\zs[^( ]\+\ze/'
- execute 'match TagbarHighlight ' . pattern
-
- execute prevwinnr . 'wincmd w'
-
- let &eventignore = eventignore_save
-
- redraw
-endfunction
-
-" s:JumpToTag() {{{2
-function! s:JumpToTag(stay_in_tagbar)
- let taginfo = s:GetTagInfo(line('.'), 1)
-
- let autoclose = w:autoclose
-
- if empty(taginfo) || has_key(taginfo, 'numtags')
- return
- endif
-
- let tagbarwinnr = winnr()
-
- let eventignore_save = &eventignore
- set eventignore=all
-
- " This elaborate construct will try to switch to the correct
- " buffer/window; if the buffer isn't currently shown in a window it will
- " open it in the first window with a non-special buffer in it
- wincmd p
- let filebufnr = bufnr(taginfo.fileinfo.fpath)
- if bufnr('%') != filebufnr
- let filewinnr = bufwinnr(filebufnr)
- if filewinnr != -1
- execute filewinnr . 'wincmd w'
- else
- for i in range(1, winnr('$'))
- execute i . 'wincmd w'
- if &buftype == ''
- execute 'buffer ' . filebufnr
- break
- endif
- endfor
- endif
- " To make ctrl-w_p work we switch between the Tagbar window and the
- " correct window once
- execute tagbarwinnr . 'wincmd w'
- wincmd p
- endif
-
- " Mark current position so it can be jumped back to
- mark '
-
- " Jump to the line where the tag is defined. Don't use the search pattern
- " since it doesn't take the scope into account and thus can fail if tags
- " with the same name are defined in different scopes (e.g. classes)
- execute taginfo.fields.line
-
- " If the file has been changed but not saved, the tag may not be on the
- " saved line anymore, so search for it in the vicinity of the saved line
- if match(getline('.'), taginfo.pattern) == -1
- let interval = 1
- let forward = 1
- while search(taginfo.pattern, 'W' . forward ? '' : 'b') == 0
- if !forward
- if interval > line('$')
- break
- else
- let interval = interval * 2
- endif
- endif
- let forward = !forward
- endwhile
- endif
-
- " If the tag is on a different line after unsaved changes update the tag
- " and file infos/objects
- let curline = line('.')
- if taginfo.fields.line != curline
- let taginfo.fields.line = curline
- let taginfo.fileinfo.fline[curline] = taginfo
- endif
-
- " Center the tag in the window
- normal! z.
-
- if foldclosed('.') != -1
- .foldopen!
- endif
-
- redraw
-
- let &eventignore = eventignore_save
-
- if a:stay_in_tagbar
- call s:HighlightTag()
- execute tagbarwinnr . 'wincmd w'
- elseif g:tagbar_autoclose || autoclose
- call s:CloseWindow()
- else
- call s:HighlightTag()
- endif
-endfunction
-
-" s:ShowPrototype() {{{2
-function! s:ShowPrototype()
- let taginfo = s:GetTagInfo(line('.'), 1)
-
- if empty(taginfo)
- return
- endif
-
- echo taginfo.getPrototype()
-endfunction
-
-" s:ToggleHelp() {{{2
-function! s:ToggleHelp()
- let s:short_help = !s:short_help
-
- " Prevent highlighting from being off after adding/removing the help text
- match none
-
- call s:RenderContent()
-
- execute 1
- redraw
-endfunction
-
-" s:GotoNextToplevelTag() {{{2
-function! s:GotoNextToplevelTag(direction)
- let curlinenr = line('.')
- let newlinenr = line('.')
-
- if a:direction == 1
- let range = range(line('.') + 1, line('$'))
- else
- let range = range(line('.') - 1, 1, -1)
- endif
-
- for tmplinenr in range
- let taginfo = s:GetTagInfo(tmplinenr, 0)
-
- if empty(taginfo)
- continue
- elseif empty(taginfo.parent)
- let newlinenr = tmplinenr
- break
- endif
- endfor
-
- if curlinenr != newlinenr
- execute newlinenr
- call winline()
- endif
-
- redraw
-endfunction
-
-" Folding {{{1
-" s:OpenFold() {{{2
-function! s:OpenFold()
- let fileinfo = s:known_files.getCurrent()
- if empty(fileinfo)
- return
- endif
-
- let curline = line('.')
-
- let tag = s:GetTagInfo(curline, 0)
- if empty(tag)
- return
- endif
-
- call tag.openFold()
-
- call s:RenderKeepView()
-endfunction
-
-" s:CloseFold() {{{2
-function! s:CloseFold()
- let fileinfo = s:known_files.getCurrent()
- if empty(fileinfo)
- return
- endif
-
- match none
-
- let curline = line('.')
-
- let curtag = s:GetTagInfo(curline, 0)
- if empty(curtag)
- return
- endif
-
- let newline = curtag.closeFold()
-
- call s:RenderKeepView(newline)
-endfunction
-
-" s:ToggleFold() {{{2
-function! s:ToggleFold()
- let fileinfo = s:known_files.getCurrent()
- if empty(fileinfo)
- return
- endif
-
- match none
-
- let curtag = s:GetTagInfo(line('.'), 0)
- if empty(curtag)
- return
- endif
-
- let newline = line('.')
-
- if curtag.isKindheader()
- call curtag.toggleFold()
- elseif curtag.isFoldable()
- if curtag.isFolded()
- call curtag.openFold()
- else
- let newline = curtag.closeFold()
- endif
- else
- let newline = curtag.closeFold()
- endif
-
- call s:RenderKeepView(newline)
-endfunction
-
-" s:SetFoldLevel() {{{2
-function! s:SetFoldLevel(level)
- if a:level < 0
- echoerr 'Foldlevel can''t be negative'
- return
- endif
-
- let fileinfo = s:known_files.getCurrent()
- if empty(fileinfo)
- return
- endif
-
- call s:SetFoldLevelRecursive(fileinfo, fileinfo.tags, a:level)
-
- let typeinfo = s:known_types[fileinfo.ftype]
-
- " Apply foldlevel to 'kind's
- if a:level == 0
- for kind in typeinfo.kinds
- call fileinfo.closeKindFold(kind)
- endfor
- else
- for kind in typeinfo.kinds
- call fileinfo.openKindFold(kind)
- endfor
- endif
-
- let fileinfo.foldlevel = a:level
-
- call s:RenderContent()
-endfunction
-
-" s:SetFoldLevelRecursive() {{{2
-" Apply foldlevel to normal tags
-function! s:SetFoldLevelRecursive(fileinfo, tags, level)
- for tag in a:tags
- if tag.depth >= a:level
- call tag.setFolded(1)
- else
- call tag.setFolded(0)
- endif
-
- if has_key(tag, 'children')
- call s:SetFoldLevelRecursive(a:fileinfo, tag.children, a:level)
- endif
- endfor
-endfunction
-
-" s:OpenParents() {{{2
-function! s:OpenParents(...)
- let tagline = 0
-
- if a:0 == 1
- let tag = a:1
- else
- let tag = s:GetNearbyTag()
- endif
-
- call tag.openParents()
-
- call s:RenderKeepView()
-endfunction
-
-" Helper functions {{{1
-" s:CleanUp() {{{2
-function! s:CleanUp()
- silent autocmd! TagbarAutoCmds
-
- unlet s:is_maximized
- unlet s:compare_typeinfo
- unlet s:short_help
-endfunction
-
-" s:CleanupFileinfo() {{{2
-function! s:CleanupFileinfo(fname)
- call s:known_files.rm(a:fname)
-endfunction
-
-" s:QuitIfOnlyWindow() {{{2
-function! s:QuitIfOnlyWindow()
- " Before quitting Vim, delete the tagbar buffer so that
- " the '0 mark is correctly set to the previous buffer.
- if winbufnr(2) == -1
- " Check if there is more than one tab page
- if tabpagenr('$') == 1
- bdelete
- quit
- else
- close
- endif
- endif
-endfunction
-
-" s:AutoUpdate() {{{2
-function! s:AutoUpdate(fname)
- call s:LogDebugMessage('AutoUpdate called on ' . a:fname)
-
- " Don't do anything if tagbar is not open or if we're in the tagbar window
- let tagbarwinnr = bufwinnr('__Tagbar__')
- if tagbarwinnr == -1 || &filetype == 'tagbar'
- call s:LogDebugMessage('Tagbar window not open or in Tagbar window')
- return
- endif
-
- " Only consider the main filetype in cases like 'python.django'
- let ftype = get(split(&filetype, '\.'), 0, '')
- call s:LogDebugMessage('Vim filetype: ' . &filetype .
- \ ', sanitized filetype: ' . ftype)
-
- " Don't do anything if the file isn't supported
- if !s:IsValidFile(a:fname, ftype)
- call s:LogDebugMessage('Not a valid file, stopping processing')
- return
- endif
-
- " Process the file if it's unknown or the information is outdated
- " Also test for entries that exist but are empty, which will be the case
- " if there was an error during the ctags execution
- if s:known_files.has(a:fname) && !empty(s:known_files.get(a:fname))
- if s:known_files.get(a:fname).mtime != getftime(a:fname)
- call s:LogDebugMessage('Filedata outdated, updating ' . a:fname)
- call s:ProcessFile(a:fname, ftype)
- endif
- elseif !s:known_files.has(a:fname)
- call s:LogDebugMessage('Unknown file, processing ' . a:fname)
- call s:ProcessFile(a:fname, ftype)
- endif
-
- let fileinfo = s:known_files.get(a:fname)
-
- " If we don't have an entry for the file by now something must have gone
- " wrong, so don't change the tagbar content
- if empty(fileinfo)
- call s:LogDebugMessage('fileinfo empty after processing: ' . a:fname)
- return
- endif
-
- " Display the tagbar content
- call s:RenderContent(fileinfo)
-
- " Call setCurrent after rendering so RenderContent can check whether the
- " same file is redisplayed
- if !empty(fileinfo)
- call s:LogDebugMessage('Setting current file to ' . a:fname)
- call s:known_files.setCurrent(fileinfo)
- endif
-
- call s:HighlightTag()
- call s:LogDebugMessage('AutoUpdate finished successfully')
-endfunction
-
-" s:IsValidFile() {{{2
-function! s:IsValidFile(fname, ftype)
- if a:fname == '' || a:ftype == ''
- call s:LogDebugMessage('Empty filename or type')
- return 0
- endif
-
- if !filereadable(a:fname)
- call s:LogDebugMessage('File not readable')
- return 0
- endif
-
- if !has_key(s:known_types, a:ftype)
- call s:LogDebugMessage('Unsupported filetype: ' . a:ftype)
- return 0
- endif
-
- return 1
-endfunction
-
-" s:EscapeCtagsCmd() {{{2
-" Assemble the ctags command line in a way that all problematic characters are
-" properly escaped and converted to the system's encoding
-" Optional third parameter is a file name to run ctags on
-function! s:EscapeCtagsCmd(ctags_bin, args, ...)
- call s:LogDebugMessage('EscapeCtagsCmd called')
- call s:LogDebugMessage('ctags_bin: ' . a:ctags_bin)
- call s:LogDebugMessage('ctags_args: ' . a:args)
-
- if exists('+shellslash')
- let shellslash_save = &shellslash
- set noshellslash
- endif
-
- if a:0 == 1
- let fname = shellescape(a:1)
- else
- let fname = ''
- endif
-
- let ctags_cmd = shellescape(a:ctags_bin) . ' ' . a:args . ' ' . fname
-
- if exists('+shellslash')
- let &shellslash = shellslash_save
- endif
-
- " Needed for cases where 'encoding' is different from the system's
- " encoding
- if g:tagbar_systemenc != &encoding
- let ctags_cmd = iconv(ctags_cmd, &encoding, g:tagbar_systemenc)
- elseif $LANG != ''
- let ctags_cmd = iconv(ctags_cmd, &encoding, $LANG)
- endif
-
- call s:LogDebugMessage('Escaped ctags command: ' . ctags_cmd)
-
- if ctags_cmd == ''
- echoerr 'Tagbar: Encoding conversion failed!'
- \ 'Please make sure your system is set up correctly'
- \ 'and that Vim is compiled with the "iconv" feature.'
- endif
-
- return ctags_cmd
-endfunction
-
-" s:ExecuteCtags() {{{2
-" Execute ctags with necessary shell settings
-" Partially based on the discussion at
-" http://vim.1045645.n5.nabble.com/bad-default-shellxquote-in-Widows-td1208284.html
-function! s:ExecuteCtags(ctags_cmd)
- if exists('+shellslash')
- let shellslash_save = &shellslash
- set noshellslash
- endif
-
- if &shell =~ 'cmd\.exe'
- let shellxquote_save = &shellxquote
- set shellxquote=\"
- let shellcmdflag_save = &shellcmdflag
- set shellcmdflag=/s\ /c
- endif
-
- let ctags_output = system(a:ctags_cmd)
-
- if &shell =~ 'cmd\.exe'
- let &shellxquote = shellxquote_save
- let &shellcmdflag = shellcmdflag_save
- endif
-
- if exists('+shellslash')
- let &shellslash = shellslash_save
- endif
-
- return ctags_output
-endfunction
-
-" s:GetTagInfo() {{{2
-" Return the info dictionary of the tag on the specified line. If the line
-" does not contain a valid tag (for example because it is empty or only
-" contains a pseudo-tag) return an empty dictionary.
-function! s:GetTagInfo(linenr, ignorepseudo)
- let fileinfo = s:known_files.getCurrent()
-
- if empty(fileinfo)
- return {}
- endif
-
- " Don't do anything in empty and comment lines
- let curline = getline(a:linenr)
- if curline =~ '^\s*$' || curline[0] == '"'
- return {}
- endif
-
- " Check if there is a tag on the current line
- if !has_key(fileinfo.tline, a:linenr)
- return {}
- endif
-
- let taginfo = fileinfo.tline[a:linenr]
-
- " Check if the current tag is not a pseudo-tag
- if a:ignorepseudo && taginfo.isPseudoTag()
- return {}
- endif
-
- return taginfo
-endfunction
-
-" s:GetNearbyTag() {{{2
-" Get the tag info for a file near the cursor in the current file
-function! s:GetNearbyTag()
- let fileinfo = s:known_files.getCurrent()
-
- let curline = line('.')
- let tag = {}
-
- " If a tag appears in a file more than once (for example namespaces in
- " C++) only one of them has a 'tline' entry and can thus be highlighted.
- " The only way to solve this would be to go over the whole tag list again,
- " making everything slower. Since this should be a rare occurence and
- " highlighting isn't /that/ important ignore it for now.
- for line in range(curline, 1, -1)
- if has_key(fileinfo.fline, line)
- let tag = fileinfo.fline[line]
- break
- endif
- endfor
-
- return tag
-endfunction
-
-" s:CheckMouseClick() {{{2
-function! s:CheckMouseClick()
- let line = getline('.')
- let curcol = col('.')
-
- if (match(line, s:icon_open . '[-+ ]') + 1) == curcol
- call s:CloseFold()
- elseif (match(line, s:icon_closed . '[-+ ]') + 1) == curcol
- call s:OpenFold()
- elseif g:tagbar_singleclick
- call s:JumpToTag(0)
- endif
-endfunction
-
-" s:DetermineFiletype() {{{2
-function! s:DetectFiletype(bufnr)
- " Filetype has already been detected for loaded buffers, but not
- " necessarily for unloaded ones
- let ftype = getbufvar(a:bufnr, '&filetype')
-
- if bufloaded(a:bufnr)
- return ftype
- endif
-
- if ftype != ''
- return ftype
- endif
-
- " Unloaded buffer with non-detected filetype, need to detect filetype
- " manually
- let bufname = bufname(a:bufnr)
-
- let eventignore_save = &eventignore
- set eventignore=FileType
- let filetype_save = &filetype
-
- exe 'doautocmd filetypedetect BufRead ' . bufname
- let ftype = &filetype
-
- let &filetype = filetype_save
- let &eventignore = eventignore_save
-
- return ftype
-endfunction
-
-
-" TagbarBalloonExpr() {{{2
-function! TagbarBalloonExpr()
- let taginfo = s:GetTagInfo(v:beval_lnum, 1)
-
- if empty(taginfo)
- return
- endif
-
- return taginfo.getPrototype()
-endfunction
-
-" TagbarGenerateStatusline() {{{2
-function! TagbarGenerateStatusline()
- if g:tagbar_sort
- let text = '[Name]'
- else
- let text = '[Order]'
- endif
-
- if !empty(s:known_files.getCurrent())
- let filename = fnamemodify(s:known_files.getCurrent().fpath, ':t')
- let text .= ' ' . filename
- endif
-
- return text
-endfunction
-
-" Debugging {{{1
-" s:StartDebug() {{{2
-function! s:StartDebug(filename)
- if empty(a:filename)
- let s:debug_file = 'tagbardebug.log'
- else
- let s:debug_file = a:filename
- endif
-
- " Empty log file
- exe 'redir! > ' . s:debug_file
- redir END
-
- " Check whether the log file could be created
- if !filewritable(s:debug_file)
- echomsg 'Tagbar: Unable to create log file ' . s:debug_file
- let s:debug_file = ''
- return
- endif
-
- let s:debug = 1
-endfunction
-
-" s:StopDebug() {{{2
-function! s:StopDebug()
- let s:debug = 0
- let s:debug_file = ''
-endfunction
-
-" s:LogDebugMessage() {{{2
-function! s:LogDebugMessage(msg)
- if s:debug
- exe 'redir >> ' . s:debug_file
- silent echon strftime('%H:%M:%S') . ': ' . a:msg . "\n"
- redir END
- endif
-endfunction
-
-" Autoload functions {{{1
-function! tagbar#ToggleWindow()
- call s:ToggleWindow()
-endfunction
-
-function! tagbar#OpenWindow(...)
- let flags = a:0 > 0 ? a:1 : ''
- call s:OpenWindow(flags)
-endfunction
-
-function! tagbar#CloseWindow()
- call s:CloseWindow()
-endfunction
-
-function! tagbar#SetFoldLevel(...)
- call s:SetFoldLevel(a:1)
-endfunction
-
-function! tagbar#OpenParents()
- call s:OpenParents()
-endfunction
-
-function! tagbar#StartDebug(...)
- let filename = a:0 > 0 ? a:1 : ''
- call s:StartDebug(filename)
-endfunction
-
-function! tagbar#StopDebug()
- call s:StopDebug()
-endfunction
-
-function! tagbar#RestoreSession()
- call s:RestoreSession()
-endfunction
-
-" Automatically open Tagbar if one of the open buffers contains a supported
-" file
-function! tagbar#autoopen()
- call s:Init()
-
- for bufnr in range(1, bufnr('$'))
- if buflisted(bufnr)
- let ftype = s:DetectFiletype(bufnr)
- if s:IsValidFile(bufname(bufnr), ftype)
- call s:OpenWindow('')
- return
- endif
- endif
- endfor
-endfunction
-
-" Modeline {{{1
-" vim: ts=8 sw=4 sts=4 et foldenable foldmethod=marker foldcolumn=1