mirror of
https://github.com/inkarkat/vim-ingo-library.git
synced 2026-05-29 11:18:51 +02:00
262 lines
12 KiB
VimL
262 lines
12 KiB
VimL
" ingo/cmdargs/pattern.vim: Functions for parsing of pattern arguments of commands.
|
|
"
|
|
" DEPENDENCIES:
|
|
" - ingo/escape.vim autoload script
|
|
"
|
|
" Copyright: (C) 2013-2016 Ingo Karkat
|
|
" The VIM LICENSE applies to this script; see ':help copyright'.
|
|
"
|
|
" Maintainer: Ingo Karkat <ingo@karkat.de>
|
|
"
|
|
" REVISION DATE REMARKS
|
|
" 1.028.008 17-Oct-2016 BUG: Support of optional a:flagsMatchCount in
|
|
" ingo#cmdargs#pattern#ParseUnescaped() and
|
|
" ingo#cmdargs#pattern#ParseUnescapedWithLiteralWholeWord()
|
|
" broke no-flags String type return value by
|
|
" returning a one-element list.
|
|
" 1.028.007 06-Oct-2016 Add ingo#cmdargs#pattern#Render().
|
|
" 1.028.006 05-Oct-2016 ENH: Also support optional a:flagsMatchCount in
|
|
" ingo#cmdargs#pattern#ParseUnescaped() and
|
|
" ingo#cmdargs#pattern#ParseUnescapedWithLiteralWholeWord().
|
|
" Add missing
|
|
" ingo#cmdargs#pattern#ParseWithLiteralWholeWord()
|
|
" variant.
|
|
" 1.027.005 29-Sep-2016 ENH: ingo#cmdargs#pattern#Parse(): Add second
|
|
" optional a:flagsMatchCount argument, similar to
|
|
" what ingo#cmdargs#substitute#Parse() has in
|
|
" a:options.
|
|
" Add ingo#cmdargs#pattern#RawParse().
|
|
" 1.023.004 03-Jan-2015 Add ingo#cmdargs#pattern#IsDelimited().
|
|
" 1.020.003 29-May-2014 Use ingo#escape#Unescape() in
|
|
" ingo#cmdargs#pattern#Unescape().
|
|
" Add ingo#cmdargs#pattern#ParseUnescaped() to
|
|
" avoid the double and inefficient
|
|
" ingo#cmdargs#pattern#Unescape(ingo#cmdargs#pattern#Parse())
|
|
" Add
|
|
" ingo#cmdargs#pattern#ParseUnescapedWithLiteralWholeWord()
|
|
" for the common [/]{pattern}[/ behavior as
|
|
" built-in commands like |:djump|]. When the
|
|
" pattern isn't delimited by /.../, the returned
|
|
" pattern is modified so that only literal whole
|
|
" words are matched.
|
|
" so far used by many clients.
|
|
" 1.011.002 24-Jul-2013 FIX: Use the rules for the /pattern/ separator
|
|
" as stated in :help E146.
|
|
" 1.007.001 01-Jun-2013 file creation
|
|
|
|
function! s:Parse( arguments, ... )
|
|
return matchlist(a:arguments, '^\([[:alnum:]\\"|]\@![\x00-\xFF]\)\(.\{-}\)\%(\%(^\|[^\\]\)\%(\\\\\)*\\\)\@<!\1' . (a:0 ? a:1 : '') . '$')
|
|
endfunction
|
|
function! ingo#cmdargs#pattern#RawParse( arguments, returnValueOnNoMatch, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Parse a:arguments as a pattern delimited by non-optional /.../ (or similar)
|
|
" characters, and with optional following flags match.
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:arguments Command arguments to parse.
|
|
" a:returnValueOnNoMatch Value that will be returned when a:arguments are not
|
|
" a delimited pattern.
|
|
" a:flagsExpr Pattern that captures any optional part after the pattern.
|
|
" a:flagsMatchCount Number of capture groups returned from a:flagsExpr.
|
|
"* RETURN VALUES:
|
|
" a:returnValueOnNoMatch if no match
|
|
" [separator, escapedPattern]; if a:flagsExpr is given
|
|
" [separator, escapedPattern, flags, ...].
|
|
"******************************************************************************
|
|
let l:match = call('s:Parse', [a:arguments] + a:000)
|
|
if empty(l:match)
|
|
return a:returnValueOnNoMatch
|
|
else
|
|
return l:match[1: (a:0 ? (a:0 >= 2 ? a:2 + 2 : 3) : 2)]
|
|
endif
|
|
endfunction
|
|
function! ingo#cmdargs#pattern#Parse( arguments, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Parse a:arguments as a pattern delimited by optional /.../ (or similar)
|
|
" characters, and with optional following flags match.
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:arguments Command arguments to parse.
|
|
" a:flagsExpr Pattern that captures any optional part after the pattern.
|
|
" a:flagsMatchCount Number of capture groups returned from a:flagsExpr.
|
|
"* RETURN VALUES:
|
|
" [separator, escapedPattern]; if a:flagsExpr is given
|
|
" [separator, escapedPattern, flags, ...].
|
|
" In a:escapedPattern, the a:separator is consistently escaped (i.e. also when
|
|
" the original arguments haven't been enclosed in such).
|
|
"******************************************************************************
|
|
" Note: We could delegate to ingo#cmdargs#pattern#RawParse(), but let's
|
|
" duplicate this for now to avoid another redirection.
|
|
let l:match = call('s:Parse', [a:arguments] + a:000)
|
|
if empty(l:match)
|
|
return ['/', escape(a:arguments, '/')] + (a:0 ? repeat([''], a:0 >= 2 ? a:2 : 1) : [])
|
|
else
|
|
return l:match[1: (a:0 ? (a:0 >= 2 ? a:2 + 2 : 3) : 2)]
|
|
endif
|
|
endfunction
|
|
function! ingo#cmdargs#pattern#ParseWithLiteralWholeWord( arguments, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Parse a:arguments as a pattern delimited by optional /.../ (or similar)
|
|
" characters, and with optional following flags match. When the pattern isn't
|
|
" delimited by /.../, the returned pattern is modified so that only literal
|
|
" whole words are matched. Built-in commands like |:djump| also have this
|
|
" behavior: |:search-args|
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:arguments Command arguments to parse.
|
|
" a:flagsExpr Pattern that captures any optional part after the pattern.
|
|
" a:flagsMatchCount Number of capture groups returned from a:flagsExpr.
|
|
"* RETURN VALUES:
|
|
" [separator, escapedPattern]; if a:flagsExpr is given
|
|
" [separator, escapedPattern, flags, ...].
|
|
" In a:escapedPattern, the a:separator is consistently escaped (i.e. also when
|
|
" the original arguments haven't been enclosed in such).
|
|
"******************************************************************************
|
|
" Note: We could delegate to ingo#cmdargs#pattern#RawParse(), but let's
|
|
" duplicate this for now to avoid another redirection.
|
|
let l:match = call('s:Parse', [a:arguments] + a:000)
|
|
if empty(l:match)
|
|
let l:pattern = ingo#regexp#FromLiteralText(a:arguments, 1, '/')
|
|
return ['/', l:pattern] + (a:0 ? repeat([''], a:0 >= 2 ? a:2 : 1) : [])
|
|
else
|
|
return l:match[1: (a:0 ? (a:0 >= 2 ? a:2 + 2 : 3) : 2)]
|
|
endif
|
|
endfunction
|
|
function! ingo#cmdargs#pattern#ParseUnescaped( arguments, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Parse a:arguments as a pattern delimited by optional /.../ (or similar)
|
|
" characters, and with optional following flags match.
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:arguments Command arguments to parse.
|
|
" a:flagsExpr Pattern that captures any optional part after the pattern.
|
|
" a:flagsMatchCount Number of capture groups returned from a:flagsExpr.
|
|
"* RETURN VALUES:
|
|
" unescapedPattern (String); if a:flagsExpr is given instead List of
|
|
" [unescapedPattern, flags, ...]. In a:unescapedPattern, any separator used in
|
|
" a:arguments is unescaped.
|
|
"******************************************************************************
|
|
let l:match = call('s:Parse', [a:arguments] + a:000)
|
|
if empty(l:match)
|
|
return (a:0 ? [a:arguments] + repeat([''], a:0 >= 2 ? a:2 : 1) : a:arguments)
|
|
else
|
|
let l:unescapedPattern = ingo#escape#Unescape(l:match[2], l:match[1])
|
|
return (a:0 ? [l:unescapedPattern] + l:match[3: (a:0 >= 2 ? a:2 + 2 : 3)] : l:unescapedPattern)
|
|
endif
|
|
endfunction
|
|
function! ingo#cmdargs#pattern#ParseUnescapedWithLiteralWholeWord( arguments, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Parse a:arguments as a pattern delimited by optional /.../ (or similar)
|
|
" characters, and with optional following flags match. When the pattern isn't
|
|
" delimited by /.../, the returned pattern is modified so that only literal
|
|
" whole words are matched. Built-in commands like |:djump| also have this
|
|
" behavior: |:search-args|
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:arguments Command arguments to parse.
|
|
" a:flagsExpr Pattern that captures any optional part after the pattern.
|
|
" a:flagsMatchCount Number of capture groups returned from a:flagsExpr.
|
|
"* RETURN VALUES:
|
|
" unescapedPattern (String); if a:flagsExpr is given instead List of
|
|
" [unescapedPattern, flags, ...]. In a:unescapedPattern, any separator used in
|
|
" a:arguments is unescaped.
|
|
"******************************************************************************
|
|
let l:match = call('s:Parse', [a:arguments] + a:000)
|
|
if empty(l:match)
|
|
let l:unescapedPattern = ingo#regexp#FromLiteralText(a:arguments, 1, '')
|
|
return (a:0 ? [l:unescapedPattern] + repeat([''], a:0 >= 2 ? a:2 : 1) : l:unescapedPattern)
|
|
else
|
|
let l:unescapedPattern = ingo#escape#Unescape(l:match[2], l:match[1])
|
|
return (a:0 ? [l:unescapedPattern] + l:match[3: (a:0 >= 2 ? a:2 + 2 : 3)] : l:unescapedPattern)
|
|
endif
|
|
endfunction
|
|
|
|
function! ingo#cmdargs#pattern#Unescape( parsedArguments )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Unescape the use of the separator from the parsed pattern to yield a plain
|
|
" regular expression, e.g. for use in search().
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" ? List of any external variable, control, or other element whose state affects this procedure.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" ? List of the procedure's effect on each external variable, control, or other element.
|
|
"* INPUTS:
|
|
" a:parsedArguments List with at least two elements: [separator, pattern].
|
|
" separator may be empty; in that case; pattern is
|
|
" returned as-is.
|
|
" You're meant to directly pass the output of
|
|
" ingo#cmdargs#pattern#Parse() in here.
|
|
"* RETURN VALUES:
|
|
" If a:parsedArguments contains exactly two arguments: unescaped pattern.
|
|
" Else a List where the first element is the unescaped pattern, and all
|
|
" following elements are taken from the remainder of a:parsedArguments.
|
|
"******************************************************************************
|
|
" We don't need the /.../ separation here.
|
|
let l:separator = a:parsedArguments[0]
|
|
let l:unescapedPattern = (empty(l:separator) ?
|
|
\ a:parsedArguments[1] :
|
|
\ ingo#escape#Unescape(a:parsedArguments[1], l:separator)
|
|
\)
|
|
|
|
return (len(a:parsedArguments) > 2 ? [l:unescapedPattern] + a:parsedArguments[2:] : l:unescapedPattern)
|
|
endfunction
|
|
|
|
function! ingo#cmdargs#pattern#IsDelimited( arguments, ... )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Test whether a:arguments is delimited by pattern separators (and optionally
|
|
" appended flags).
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:arguments Command arguments to parse.
|
|
" a:flagsExpr Pattern that captures any optional part after the pattern.
|
|
"* RETURN VALUES:
|
|
" 1 if delimited by suitable, identical characters (plus any flags as
|
|
" specified by a:flagsExpr), else 0.
|
|
"******************************************************************************
|
|
let l:match = call('s:Parse', [a:arguments] + a:000)
|
|
return (! empty(l:match))
|
|
endfunction
|
|
|
|
function! ingo#cmdargs#pattern#Render( arguments )
|
|
"******************************************************************************
|
|
"* PURPOSE:
|
|
" Create a single string from the parsed pattern arguments.
|
|
"* ASSUMPTIONS / PRECONDITIONS:
|
|
" None.
|
|
"* EFFECTS / POSTCONDITIONS:
|
|
" None.
|
|
"* INPUTS:
|
|
" a:arguments Return value from any of the ...#Parse... methods defined here.
|
|
"* RETURN VALUES:
|
|
" String with separator-delimited pattern, followed by any additional flags,
|
|
" etc.
|
|
"******************************************************************************
|
|
return a:arguments[0] . a:arguments[1] . a:arguments[0] . join(a:arguments[2:], '')
|
|
endfunction
|
|
|
|
" vim: set ts=8 sts=4 sw=4 noexpandtab ff=unix fdm=syntax :
|