Skip to content

Instantly share code, notes, and snippets.

@nefigah
Created June 14, 2014 05:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nefigah/8270187bcb9ddfb5e9e3 to your computer and use it in GitHub Desktop.
Save nefigah/8270187bcb9ddfb5e9e3 to your computer and use it in GitHub Desktop.
Magic sub wrappers!
"
" Functions/Commands
"
" <SID>ShouldAbbreviateCmd() is a helper function for determining whether or
" not a cabbrev should be performed. It returns 1 (true) if:
" * The context is an ex command (as opposed to search mode), and either:
" * The abbreviation would occur at the beginning of the commandline, or
" * The abbreviation would occur following a simple :range specification.
function! s:ShouldAbbreviateCmd()
" Ensure we are in command mode, not search mode
if getcmdtype() != ":"
return 0
" No range case
elseif getcmdpos() == 1
return 1
else
let text = getcmdline()
" For efficiency, check the most common ranges directly
if text is "'<,'>" || text is '%' || text is '.'
return 1
endif
" Try to match the more straightforward line specifications.
" The /, ?, \/, \?, and \& specifiers are purposely omitted, as are
" multiple addition/subtraction clauses occuring in the same spec segment.
let text = strpart(text, 0, getcmdpos() - 1)
let lineSpec = '\v^%(\d+|\.|\$|\' . "'" . '\a)%([+-]\d*)?'
let sepOrEnd = '%($|[,;])'
let firstSpec = strlen(matchstr(text, lineSpec . sepOrEnd))
" Exit if we've already determined no match or exact match
if firstSpec == 0
return 0
elseif firstSpec == strlen(text)
return 1
endif
return strlen(matchstr(text, lineSpec . '$', firstSpec)) > 0
endif
endfunction
" <SID>MakeCmdAbbrev() is a helper function for creating guarded command
" aliases (cabbrevs). You don't want those buggers to be expanded just
" anywhere, especially if you want to use a nice short abbreviation.
function! s:MakeCmdAbbrev(abbreviation, expansion)
execute 'cnoreabbrev ' . a:abbreviation . " <C-R>=<SID>ShouldAbbreviateCmd()" .
\ ' ? "' . a:expansion . '" : "' . a:abbreviation . '"<CR>'
endfunction
" <SID>SubWrap is a function wrapper around the built-in :substitute command.
" It will interpret the provided search pattern in the context of the given
" 'magic' specifier (one of \m, \M, \v, or \V). The replacement will always be
" interpreted with 'nomagic'.
function! s:SubWrap(magicmode, startline, endline, argstring)
let delim = strpart(a:argstring, 0, 1)
let withmode = delim . a:magicmode . strpart(a:argstring, 1)
" Silly Vim doesn't allow a 'magic' specifier for the replacement
set nomagic
execute a:startline . ',' . a:endline . 'substitute' . withmode
set magic
endfunction
" Custom commands:
" VeryMagicSub (alias: :ss) (mnemonic: twice as good as :s)
" LiteralSub (alias :ssl) (for when you really need to search for [ and *)
" If you want the commands to default to the cursor line (like :s), instead of
" the whole file (like :g), replace -range=% with just -range in the commands
" below. In either case, you can always provide your own range on use.
command! -nargs=1 -range=% VeryMagicSub call s:SubWrap('\v', <line1>, <line2>, <q-args>)
call s:MakeCmdAbbrev('ss', 'VeryMagicSub')
command! -nargs=1 -range=% LiteralSub call s:SubWrap('\V', <line1>, <line2>, <q-args>)
call s:MakeCmdAbbrev('ssl', 'LiteralSub')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment