" This program is free software: you can redistribute it and/or modify
" it under the terms of the GNU General Public License as published by
" the Free Software Foundation, either version 3 of the License, or
" (at your option) any later version.
"
" This program is distributed in the hope that it will be useful,
" but WITHOUT ANY WARRANTY; without even the implied warranty of
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
" GNU General Public License for more details.
"
" You should have received a copy of the GNU General Public License
" along with this program. If not, see .
" Vim plug-in for jumps over following pair shell commands
" 'do', 'done', 'if', 'then', 'else', 'elif', 'fi', 'case' , 'esac' and
" default behaviour for % if cursor stand at bracket or brace
" modes: normal, operator-pending, visual
" remapped: % [[ ]]
" path: ~/.vim/ftplugin/sh.vim
" global variables or functions: none
" tested for: Vim 7.3
"
" author: RM
" version 0.3 2015-04-23 01:37:48
"""""""""" HANDY commands
" and abbreviations for shell
" : (iabbrev) creates sceletons
iabbrev casein case inx) ;;*)esac<
iabbrev ifthen if thenelsefi?if\zs
:noh
iabbrev fordo for in dodone?for\zs
:noh
iabbrev whiledo while dodone?while\zs
:noh
"""""""""" JUMPS -script
" .---------------------.
" | jumps over sections |
" '---------------------'
" [ 'do', 'done', 'if', 'then', 'else', 'elif', 'fi' , 'case' , 'esac']
" - Commented lines are ignored!
let s:jumpSections='
\^[^#]*[ \t;]*\zsdo[ \t]*\%(#.*\)*$\|
\^[ \t]*\zsdone[ \t]*\%(#.*\)*$\|
\^[ \t]*\zsif\_.\{-}then[ \t]*\%(#.*\)*$\|
\^[ \t]*\zselif\_.\{-}then[ \t]*\%(#.*\)*$\|
\^[ \t]*\zselse[ \t]*\%(#.*\)*$\|
\^[ \t]*\zsfi[ \t]*\%(#.*\)*$\|
\^[ \t]*\zscase.\{-}in[ \t]*\%(#.*\)*$\|
\^[ \t]*\zsesac[ \t]*\%(#.*\)*$
\'
function! s:Search(direct)
call search(s:jumpSections, a:direct)
endfunction
noremap ]] :call Search('')
noremap [[ :call Search('b')
function! s:SearchVisual(direct)
if a:direct == 1
let dir='/'
else
let dir='?'
endif
let cmdheight_bckp=&cmdheight
set cmdheight=3 "prevent Hit ENTER to continue
execute 'silent normal! gv' . dir . s:jumpSections . "\r"
let &cmdheight=cmdheight_bckp
endfunction
vnoremap ]]
\ :call SearchVisual(1) \| normal! $zz
vnoremap [[
\ :call SearchVisual(0) \| normal! ^zz
" .--------------------------.
" | jumps over pair commands |
" '--------------------------'
" - pair commands: [ 'do', 'done' ] and ['if', 'then', 'else', 'elseif', 'fi', 'case' , 'esac']
" - Commented lines will be ignored!
" - If cursor is not at the following pair the command will be
" searched first!
" - if cursor stand at bracket or brace the jumps over pair will be done
" (brackets and braces must be in `matchpairs`)
nnoremap % :call SearchPair(0)
onoremap % :call SearchPair(1)
vnoremap % : call SearchPair(2)
"let b:bw='W' !!! wrong (update everytime if the buffer is active)
function! s:SearchPair(mode)
" visual mode only (it would be long story)
if a:mode == 2
normal! gv
endif
" get character under the cursor
let char_under_cursor=getline('.')[col('.')-1]
" jump over braces or brackets using dafault command % (using matchpairs)
if index(split(&matchpairs, ',\|:'), char_under_cursor) != -1
normal! %
return 0
endif
"" the same like previous condition; solution using search() and matchpairs
"" (just for inspiration)
"let matchpairs_list=split(&matchpairs, ',\|:')
"let pos_in_matchpairs=index(matchpairs_list, char_under_cursor)
"if pos_in_matchpairs != -1
"if pos_in_matchpairs % 2
"let pairchar=matchpairs_list[pos_in_matchpairs-1]
"let fwbw='bW'
"call searchpair(pairchar, '', char_under_cursor, fwbw)
"else
"let pairchar=matchpairs_list[pos_in_matchpairs+1]
"let fwbw='W'
"call searchpair(char_under_cursor, '', pairchar, fwbw)
"endif
"return 0
"endif
" jump at the beginning of line if keyword is not under the cursor
if expand('') !~ '^[^(]*)' &&
\ ( char_under_cursor == ' ' || char_under_cursor == '\t' ||
\ index( ['do', 'done', 'if', 'else', 'elif', 'fi', 'case', 'esac'], expand('') ) == -1 )
echom "d"
normal! ^
endif
" jump at the following pair command if it is still not under the cursor
" (jumps ahead over lines to the first pair command)
if getline('.') !~ '^[^(#]*)' &&
\ index( ['do', 'done', 'if', 'else', 'elif', 'fi', 'case', 'esac'], expand('') ) == -1
normal! 0
call search(s:jumpSections)
return 0
endif
" set right direction of jumps and pair command
if index( ['if'], expand('') ) != -1
let b:bw='W'
let pair=1
elseif index( ['else', 'elif'], expand('') ) != -1
let pair=1
if !exists("b:bw") " in new buffer if cursor at the command else or elif
let b:bw='W' " the variable is not defined yet
endif
elseif index( ['fi'], expand('') ) != -1
let b:bw='bW'
let pair=1
normal! ^
" normal fix the problem with cursor on the last letter
elseif index( ['do'], expand('') ) != -1
let b:bw='W'
let pair=0
elseif index( ['done'], expand('') ) != -1
let b:bw='bW'
let pair=0
normal! ^
" normal fix the problem with cursor on the last letter
elseif index( ['case'], expand('') ) != -1
let b:bw='W'
let pair=2
elseif expand('') =~ ')' && expand('') !~ '('
let pair=2
if !exists("b:bw") " in new buffer if cursor at the command else or elif
let b:bw='W' " the variable is not defined yet
endif
elseif index( ['esac'], expand('') ) != -1
let b:bw='bW'
let pair=2
normal! ^
" normal fix the problem with cursor on the last letter
endif
" regexp from each command (the same like s:jumpSections but split)
let jumpIf='
\^[ \t]*\zsif\_.\{-}then[ \t]*\%(#.*\)*$'
let jumpElifElse='
\^[ \t]*\zselif\_.\{-}then[ \t]*\%(#.*\)*$\|
\^[ \t]*\zselse[ \t]*\%(#.*\)*$'
let jumpFi='
\^[ \t]*\zsfi[ \t]*\%(#.*\)*$'
let jumpDo='
\^[^#]*[ \t;]*\zsdo[ \t]*\%(#.*\)*$'
let jumpDone='
\^[ \t]*\zsdone[ \t]*\%(#.*\)*$'
let jumpCase='
\^[ \t]*\zscase.\{-}in[ \t]*\%(#.*\)*$'
let jumpEsac='
\^[ \t]*\zsesac[ \t]*\%(#.*\)*$'
" execute jump at the pair command (function searchpair())
if pair == 0
call searchpair(jumpDo, '', jumpDone, b:bw)
elseif pair == 1
call searchpair(jumpIf, jumpElifElse, jumpFi, b:bw)
elseif pair == 2
call searchpair(jumpCase, '^[ \t]*[^(#]*\zs.)\_.\{-}\%(;;\|esac\)[ \t]*\%(#.*\)*$', jumpEsac, b:bw)
endif
" tune final movement for selection
if a:mode == 2 && b:bw == 'W' && ( pair != 2 || expand('') == 'esac' )
normal! e
elseif a:mode == 2 && b:bw == 'bW' && pair != 2
normal! ^
endif
return 0
endfunction