vimsuite/vimfiles/plugin/SrchRplcHiGrp.vim
2008-03-31 09:07:35 +00:00

489 lines
15 KiB
VimL

" SrchRplcHiGrp.vim - Search and Replace based on a highlight group
"
" Version: 4.0
" Author: David Fishburn <fishburn@ianywhere.com>
" Last Changed: Mon 21 Jan 2008 06:17:14 PM Eastern Standard Time
" Created: Tue Dec 02 2003 10:11:07 PM
" Description: Search and Replace based on a syntax highlight group
" Script: http://www.vim.org/script.php?script_id=848
" License: GPL (http://www.gnu.org/licenses/gpl.html)
"
" Command Help: {{{
" Ensure you have updated the help system:
" :helptags $VIM/vimfiles/doc (Windows)
" :helptags $VIM/.vim/doc (*nix)
"
" :h SRHiGrp
" }}}
" If syntax is not enabled, do not bother loading this plugin
if exists('g:loaded_srhg') || &cp || !exists("syntax_on")
finish
endif
let g:loaded_srhg = 1
" Default the highlight group to 0
let s:srhg_group_id = 0
let s:srhg_firstline = 0
let s:srhg_lastline = 0
" Functions: "{{{
" SRWarningMsg:
function! <SID>SRWarningMsg(msg) "{{{
echohl WarningMsg
echomsg a:msg
echohl None
endfunction "}}}
" SRDispHiGrp:
" Echos the currently selected highlight group name to the screen.
" If a parameter is supplied, it will display the message in the
" colour of the group name.
function! <SID>SRDispHiGrp(...) "{{{
if s:srhg_group_id != 0
if s:srhg_group_id < 0
let gid = -s:srhg_group_id
else
let gid = s:srhg_group_id
endif
if a:0 > 0 && strlen(a:1) > 0
let msg = a:1
else
let msg = "SRHiGrp - Group ID: " .gid . " Name: " . synIDattr(gid,"name")
endif
exec 'echohl ' . synIDattr(gid, "name")
exec "echomsg '" . msg . "'"
echohl None
else
echo "No highlight group has been choosen yet"
endif
endfunction "}}}
" SRChooseHiGrp:
" Sets the script variable s:srhg_group_id to the value
" of the highlight group underneath the current cursor
" position.
function! <SID>SRChooseHiGrp(use_top_level) "{{{
if(a:use_top_level == 1)
let cursynid = -synID(line("."),col("."),1)
else
let cursynid = synIDtrans(synID(line("."),col("."),1))
endif
if cursynid == 0
call s:SRWarningMsg(
\ 'There is no syntax group specified ' .
\ 'under the cursor'
\ )
else
let s:srhg_group_id = cursynid
call s:SRDispHiGrp()
endif
endfunction "}}}
" SRSetVisualRange:
" Redefines the visual range if the user called the functions
" with 1,5SR*
function! <SID>SRSetVisualRange() "{{{
" If the current line position is not at the beginning
" or the end of the visual region
if line(".") != line("'<") && line(".") != line("'>")
" Visually select the rows to ensure the correct
" range is operated on.
" This handles the case that SRHiGrp was run as:
" :SRHiGrp
" :1,5SRHiGrp
" instead of:
" :'<,'>SRHiGrp
exec 'normal! '.s:srhg_firstline."GV"
if s:srhg_lastline > s:srhg_firstline
exec "normal! " .
\ (s:srhg_lastline - s:srhg_firstline) .
\ "j"
endif
exec "normal! \<Esc>"
endif
return 1
endfunction "}}}
" SRPositionWord:
" Places the cursor on the next match following the
" previous line and column passed in.
function! <SID>SRPositionWord(prvline, prvcol, bfirsttime) "{{{
let prvline = a:prvline
let prvcol = a:prvcol
" echo 'L:'. col("'<") . ' R:' . col("'>")
" echo 'Visual Mode:'. visualmode()
if (prvline == 0) && (prvcol == 0)
call s:SRSetVisualRange()
let leftcol = col("'<") - 1
" exe 'norm! '.s:srhg_firstline."G\<bar>".leftcol.(leftcol>0 ? 'l' : '' )
call cursor(s:srhg_firstline,leftcol)
return 1
endif
while 1==1
if visualmode() ==# 'v'
if line(".") == s:srhg_firstline
" let leftcol = col("'<") - 1
let leftcol = col("'<")
else
let leftcol = 1
endif
if line(".") == s:srhg_lastline
let rightcol = col("'>")
else
let rightcol = col("$")
endif
elseif visualmode() ==# 'V'
let leftcol = 1
let rightcol = col("$")
elseif visualmode() ==# "\<C-V>"
let leftcol = col("'<") - 1
let leftcol = col("'<")
let rightcol = col("'>")
endif
" echo 'PrvLine:'.prvline.' prvcol:'.prvcol.
" \' L:'.leftcol.' R:'.rightcol.
" \' VL:'.leftcol.' VR:'.rightcol
" Position cursor on leftcol
" on each new line based on visual mode
if col(".") == leftcol && a:bfirsttime == 1
" The cursor is already at it starting position,
" do not move the cursor
elseif col(".") < leftcol
" exe 'norm! '.line(".")."G\<bar>".leftcol.(leftcol>0 ? 'l' : '' )
call cursor(line("."),leftcol)
else
normal! w
endif
" Add additional check to see if the cursor has
" moved after the above, if not, exit.
if (col(".") == prvcol) && (line(".") == prvline && a:bfirsttime != 1)
return -1
endif
if col(".") >= leftcol &&
\ col(".") <= rightcol &&
\ line(".") <= s:srhg_lastline
return 1
elseif col(".") > rightcol && line(".") < s:srhg_lastline
let prvline = prvline + 1
" Position the cursor on the next line and move
" to the start of the visual region
" exe 'norm! '.prvline."G\<bar>".leftcol.(leftcol>0 ? 'l' : '' )
call cursor(prvline,leftcol)
break
elseif col(".") < leftcol && line(".") <= s:srhg_lastline
" outside of visual area, move to next word
continue
else
return -1
endif
endwhile
return 1
endfunction "}}}
" SRHiGrp:
" Traverses the region selected and performs all search and
" replaces over the region for the selected highlight group.
function! <SID>SRHiGrp(...) range "{{{
let s:srhg_firstline = a:firstline
let s:srhg_lastline = a:lastline
if s:srhg_group_id == 0
call s:SRWarningMsg(
\ 'You must specify a syntax group name ' .
\ 'by placing the cursor on a character ' .
\ 'that is highlighted the way you want ' .
\ 'and execute :SRChooseHiGrp or ' .
\ ':SRChooseHiGrp!'
\ )
return
endif
let group_name = synIDattr(s:srhg_group_id, 'name')
if group_name == ''
let group_name = synIDattr(-s:srhg_group_id, 'name')
endif
if(a:0 > 0)
if( a:1 == 0 || a:1 == 1)
let match_group = a:1
endif
else
" Default to operate on syntax groups that match
let match_group = 1
endif
if(a:0 > 1)
let match_exp = a:2
else
let match_exp = '\(\w\+\>\)'
let dialog_msg = "Enter match expression (default word at cursor - " .
\ match_exp .
\ "): "
let l:var_val = inputdialog(dialog_msg, match_exp)
let response = 1
" Ok or Cancel result in an empty string
if l:var_val == ""
call s:SRWarningMsg(
\ 'You must provide a match expression which ' .
\ 'includes a submatch'
\ )
return
endif
let match_exp = l:var_val
endif
if(a:0 > 2)
let replace_exp = a:3
else
let replace_exp = '\U\1'
let dialog_msg = "Enter replacement expression for the submatch " .
\ "(ie capitalize word - \\U\\1): "
let l:var_val = inputdialog(dialog_msg, replace_exp)
let response = 1
" Ok or Cancel result in an empty string
if l:var_val == ""
" If empty, check if they want to leave it empty
" of skip this variable
let response = confirm("Your value is empty!"
\ , "&Use blank\n&Cancel", response)
endif
if response == 1
" Replace the variable with what was entered
let replace_exp = l:var_val
else
" Cancel
return
endif
endif
" let higrpid = synIDtrans(hlID(s:srhg_group_id))
let found = 0
let firsttime = 1
let lastline = line("$")
let orgline = line(".")
let orgcol = col(".")
let curline = line(".")
let curcol = col(".")
let fenkeep = &fen
let saveSearch = @/
let saveFoldEnable = &foldenable
setlocal nofoldenable
" Reset visual range if necessary
call s:SRSetVisualRange()
" Restore the cursor position since resetting
" the visual area could have moved the cursor
call cursor(orgline, orgcol)
if s:SRPositionWord(orgline,(orgcol-1), firsttime) == -1
call s:SRWarningMsg(
\ 'Please reselect the visual area (ie gv)'
\ )
return
endif
let firsttime = 0
let gid = s:srhg_group_id
if(gid < 0)
let gid = -s:srhg_group_id
endif
while line(".") <= a:lastline
let curcol = col(".")
let curline = line(".")
let cursynid = (s:srhg_group_id < 0) ?
\ -synID(line("."),col("."),1) :
\ synIDtrans(synID(line("."),col("."),1))
let cursynid = (s:srhg_group_id < 0) ? synID(line("."),col("."),1) : synIDtrans(synID(line("."),col("."),1))
" Useful debugging statement:
" echo col(".").':'.getline(".")[col(".")-1].':'.cursynid.':'.getline(".")
if line(".") == curline
if match_group == 1 && cursynid == gid
" Perform the subtitution, but do not report an error
" if the match fails
exec 's/\%#'.match_exp.'/'.replace_exp.'/e'
" Since this command can move the cursor, put the cursor
" back to its original position
" exe 'norm! '.curline."G\<bar>".(curcol-1)."l"
call cursor(curline,curcol)
let found = 1
elseif match_group == 0 && cursynid != gid
" Perform the subtitution, but do not report an error
" if the match fails
exec 's/\%#'.match_exp.'/'.replace_exp.'/e'
" Since this command can move the cursor, put the cursor
" back to its original position
exe 'norm! '.curline."G\<bar>".(curcol-1)."l"
endif
endif
let prvcol = curcol
let prvline = curline
if s:SRPositionWord(prvline, prvcol, firsttime) == -1
break
endif
endwhile
if found == 0
call s:SRWarningMsg('Did not find highlight group: "'.group_name.'"')
endif
" cleanup
let &fen = fenkeep
if foldlevel(".") > 0
norm! zO
endif
let &foldenable = saveFoldEnable
unlet curcol
" unlet higrpid
unlet lastline
let @/ = saveSearch
if exists("prvcol")
unlet prvcol
endif
endfunction "}}}
"}}}
" SRSearch:
" Finds the next occurrence of the highlight group within
" the range selected from the current cursor position.
function! <SID>SRSearch(fline, lline, ...) "{{{
let s:srhg_firstline = a:fline
let s:srhg_lastline = a:lline
if a:0 > 0 && strlen(a:1) > 0
let s:srhg_group_id = -hlID(a:1)
let group_name = a:1
else
let group_name = synIDattr(-s:srhg_group_id, 'name')
endif
if s:srhg_group_id == 0
call s:SRWarningMsg(
\ 'You must specify a syntax group name ' .
\ 'on the command line (<Tab> to complete) ' .
\ 'or by placing the cursor on a character ' .
\ 'that is highlighted the way you want ' .
\ 'and execute :SRChooseHiGrp or ' .
\ ':SRChooseHiGrp!'
\ )
return
endif
" let higrpid = synIDtrans(hlID(s:srhg_group_id))
let found = 0
let lastline = line("$")
let orgline = line(".")
let orgcol = col(".")
let curline = line(".")
let curcol = col(".")
let fenkeep = &fen
let saveSearch = @/
let saveFoldEnable = &foldenable
setlocal nofoldenable
" Set this to false, to force the search to move the cursor
" this prevents the user from having to manually move the
" cursor between recursive calls.
let firsttime = 0
" Reset visual range if necessary
call s:SRSetVisualRange()
" Restore the cursor position since resetting
" the visual area could have moved the cursor
call cursor(orgline, orgcol)
if s:SRPositionWord(orgline,orgcol,firsttime) == -1
call s:SRWarningMsg(
\ 'Please reselect the visual area (ie gv)'
\ )
return
endif
let gid = s:srhg_group_id
if(gid < 0)
let gid = -s:srhg_group_id
endif
while line(".") <= s:srhg_lastline
let curcol = col(".")
let curline = line(".")
let cursynid = (s:srhg_group_id < 0) ?
\ -synID(line("."),col("."),1) :
\ synIDtrans(synID(line("."),col("."),1))
let cursynid = (s:srhg_group_id < 0) ? synID(line("."),col("."),1) : synIDtrans(synID(line("."),col("."),1))
" Useful debugging statement:
" echo col(".").':'.getline(".")[col(".")-1].':'.cursynid.':'.getline(".")
if line(".") == curline
if cursynid == gid
call s:SRDispHiGrp( "SRSearch - Match found - Group ID: " .
\ gid . " Name: " . synIDattr(gid,"name")
\ )
let found = 1
break
endif
endif
let prvcol = curcol
let prvline = curline
if s:SRPositionWord(prvline, prvcol, firsttime) == -1
break
endif
endwhile
if found == 0
call s:SRDispHiGrp( "SRSearch - Match NOT found - Group ID: " .
\ gid . " Name: " . synIDattr(gid,"name")
\ )
call cursor(orgline, orgcol)
endif
" cleanup
let &fen = fenkeep
if foldlevel(".") > 0
norm! zO
endif
let &foldenable = saveFoldEnable
unlet curcol
" unlet higrpid
unlet lastline
let @/ = saveSearch
if exists("prvcol")
unlet prvcol
endif
endfunction "}}}
"}}}
" Commands: {{{
command! -range -bang -nargs=* SRHiGrp <line1>,<line2>call s:SRHiGrp(<bang>1,<args>)
command! -bang -nargs=0 SRChooseHiGrp :call s:SRChooseHiGrp(<bang>1)
command! -nargs=0 SRDispHiGrp :call s:SRDispHiGrp()
command! -range=% -nargs=? -complete=highlight SRSearch call s:SRSearch(<line1>,<line2>,<q-args>)
"}}}
" vim:fdm=marker:nowrap:ts=4: