From: Andy Wokula Date: Sat, 9 Mar 2013 00:00:00 +0000 (+0000) Subject: Version 0.5 X-Git-Url: https://git.madduck.net/etc/vim.git/commitdiff_plain/f96996df158d8c20be551ee728adf5618802d347?ds=inline Version 0.5 Bug fixes (accept more patterns): `\z(', `\z1', ..., `[foo'; added cases where `^', `*', `$' become literal; `[=a=]` in collections, a few more. --- diff --git a/autoload/explainpat.vim b/autoload/explainpat.vim index c0545ea..a45fa58 100644 --- a/autoload/explainpat.vim +++ b/autoload/explainpat.vim @@ -1,24 +1,19 @@ " File: explainpat.vim " Created: 2011 Nov 02 -" Last Change: 2012 Dec 19 -" Rev Days: 3 +" Last Change: 2013 Mar 09 +" Rev Days: 8 " Author: Andy Wokula " License: Vim License, see :h license -" Version: 0.2 +" Version: 0.5 " Implements :ExplainPattern [pattern] " TODO {{{ " - more testing, completeness check -" - detailed collections -" - \z +" ? detailed collections " ? literal string: also print the unescaped magic items " ? literal string: show leading/trailing spaces -" + start of "first" capturing group, start of 2nd ... -" + `\|' should get less indent than the branches, do we need to create an -" AST? ! no, keep it straight forward -" + \%[...] -" + \{, \{- +" "}}} " Init Folklore {{{ @@ -27,7 +22,9 @@ set cpo&vim let g:explainpat#loaded = 1 "}}} -func! explainpat#ExplainPattern(cmd_arg) "{{{ +func! explainpat#ExplainPattern(cmd_arg, ...) "{{{ + " {a:1} alternative help printer object (caution, no sanity check) + " (for test running) if a:cmd_arg == "" " let pattern_str = nwo#vis#Get() echo "(usage) :ExplainPattern [{register} | {pattern}]" @@ -45,11 +42,15 @@ func! explainpat#ExplainPattern(cmd_arg) "{{{ echo printf('Magic Pattern: %s', magicpat) endif - " hmm, we need state for \%[ ... ] + " we need state: + " set flag when in `\%[ ... ]' (optionally matched atoms): let s:in_opt_atoms = 0 + " counter for `\(': let s:capture_group_nr = 0 + " >=1 at pos 0 or after '\|', '\&', '\(', '\%(' or '\n'; else 0 or less: + let s:at_begin_of_pat = 1 - let hulit = s:NewHelpPrinter() + let hulit = a:0>=1 && type(a:1)==s:DICT ? a:1 : s:NewHelpPrinter() call hulit.AddIndent(' ') let bull = s:NewTokenBiter(magicpat, '') while !bull.AtEnd() @@ -62,7 +63,10 @@ func! explainpat#ExplainPattern(cmd_arg) "{{{ call hulit.Print(item, Doc) elseif type(Doc) == s:FUNCREF call call(Doc, [bull, hulit, item]) + elseif type(Doc) == s:LIST + call call(Doc[0], [bull, hulit, item, Doc[1]]) endif + let s:at_begin_of_pat -= 1 else echoerr printf('ExplainPattern: cannot parse "%s"', bull.Rest()) break @@ -76,9 +80,10 @@ endfunc "}}} let s:STRING = type("") let s:DICT = type({}) let s:FUNCREF = type(function("tr")) +let s:LIST = type([]) " }}} -let s:magic_item_pattern = '\C^\%(\\\%(@<.\|%[dxouU[(^$V#<>]\=\|z[1-9se(]\|{\|@[>=!]\|_[[^$.]\=\|.\)\|.\)' +let s:magic_item_pattern = '\C^\%(\\\%(@<.\|%[dxouU[(^$V#<>]\=\|z[1-9se(]\|@[>=!]\|_[[^$.]\=\|.\)\|.\)' let s:doc = {} " {{{ " this is all the help data ... @@ -87,23 +92,33 @@ let s:doc = {} " {{{ func! s:DocOrBranch(bull, hulit, item) "{{{ call a:hulit.RemIndent() - call a:hulit.Print(a:item, "OR branch") + call a:hulit.Print(a:item, "OR (separate alternatives)") call a:hulit.AddIndent(' ') + let s:at_begin_of_pat = 2 endfunc "}}} let s:doc['\|'] = function("s:DocOrBranch") -let s:doc['\&'] = "AND branch" + +func! s:DocBeginOfPat(bull, hulit, item, msg) "{{{ + call a:hulit.Print(a:item, a:msg) + let s:at_begin_of_pat = 2 +endfunc "}}} + +let s:doc['\&'] = [function("s:DocBeginOfPat"), "AND (separate concats, all must match)"] let s:ord = split('n first second third fourth fifth sixth seventh eighth ninth') func! s:DocGroupStart(bull, hulit, item) "{{{ if a:item == '\%(' call a:hulit.Print(a:item, "start of non-capturing group") - else " a:item == '\(' + elseif a:item == '\(' let s:capture_group_nr += 1 call a:hulit.Print(a:item, printf("start of %s capturing group", get(s:ord, s:capture_group_nr, '(invalid)'))) + else " a:item == '\z(' + call a:hulit.Print(a:item, 'start of "external" group (only usable in :syn-region)') endif call a:hulit.AddIndent('| ', ' ') + let s:at_begin_of_pat = 2 endfunc "}}} func! s:DocGroupEnd(bull, hulit, item) "{{{ call a:hulit.RemIndent(2) @@ -113,9 +128,21 @@ endfunc "}}} let s:doc['\('] = function("s:DocGroupStart") let s:doc['\%('] = function("s:DocGroupStart") let s:doc['\)'] = function("s:DocGroupEnd") +" let s:doc['\z('] = "only in syntax scripts" +let s:doc['\z('] = function("s:DocGroupStart") + +func! s:DocStar(bull, hulit, item) "{{{ + if s:at_begin_of_pat >= 1 + " call a:hulit.Print(a:item, "(at begin of pattern) literal `*'") + call a:hulit.AddLiteral(a:item) + else + call a:hulit.Print(a:item, "(multi) zero or more of the preceding atom") + endif +endfunc "}}} + +" let s:doc['*'] = "(multi) zero or more of the preceding atom" +let s:doc['*'] = function("s:DocStar") -let s:doc['\z('] = "only in syntax scripts" -let s:doc['*'] = "(multi) zero or more of the preceding atom" let s:doc['\+'] = "(multi) one or more of the preceding atom" let s:doc['\='] = "(multi) zero or one of the preceding atom" let s:doc['\?'] = "(multi) zero or one of the preceding atom" @@ -144,9 +171,36 @@ let s:doc['\@='] = "(assertion) require match for preceding atom" let s:doc['\@!'] = "(assertion) forbid match for preceding atom" let s:doc['\@<='] = "(assertion) require match for preceding atom to the left" let s:doc['\@= 1 + call a:hulit.Print(a:item, "(assertion) require match at start of line") + " after `^' is not at begin of pattern ... handle special case `^*' here: + if a:bull.Bite('^\*') == "*" + call a:hulit.AddLiteral("*") + endif + else + " call a:hulit.Print(a:item, "(not at begin of pattern) literal `^'") + call a:hulit.AddLiteral(a:item) + endif +endfunc "}}} + +" let s:doc['^'] = "(assertion) require match at start of line" +let s:doc['^'] = function("s:DocCircumFlex") + let s:doc['\_^'] = "(assertion) like `^', allowed anywhere in the pattern" -let s:doc['$'] = "(assertion) require match at end of line" + +func! s:DocDollar(bull, hulit, item) "{{{ + if a:bull.Rest() =~ '^$\|^\\[&|)n]' + call a:hulit.Print(a:item, "(assertion) require match at end of line") + else + call a:hulit.AddLiteral(a:item) + endif +endfunc "}}} + +" let s:doc['$'] = "(assertion) require match at end of line" +let s:doc['$'] = function("s:DocDollar") + let s:doc['\_$'] = "(assertion) like `$', allowed anywhere in the pattern" let s:doc['.'] = "match any character" let s:doc['\_.'] = "match any character or newline" @@ -266,7 +320,7 @@ let s:doc['\e'] = "match " let s:doc['\t'] = "match " let s:doc['\r'] = "match " let s:doc['\b'] = "match CTRL-H" -let s:doc['\n'] = "match a newline" +let s:doc['\n'] = [function("s:DocBeginOfPat"), "match a newline"] let s:doc['~'] = "match the last given substitute string" let s:doc['\1'] = "match first captured string" let s:doc['\2'] = "match second captured string" @@ -278,21 +332,31 @@ let s:doc['\7'] = "match seventh captured string" let s:doc['\8'] = "match eighth captured string" let s:doc['\9'] = "match ninth captured string" -" \z1 -" \z2 -" \z9 +let s:doc['\z1'] = 'match same string matched by first "external" group' +let s:doc['\z2'] = 'match same string matched by second "external" group' +let s:doc['\z3'] = 'match same string matched by third "external" group' +let s:doc['\z4'] = 'match same string matched by fourth "external" group ' +let s:doc['\z5'] = 'match same string matched by fifth "external" group' +let s:doc['\z6'] = 'match same string matched by sixth "external" group' +let s:doc['\z7'] = 'match same string matched by seventh "external" group' +let s:doc['\z8'] = 'match same string matched by eighth "external" group' +let s:doc['\z9'] = 'match same string matched by ninth "external" group' " from MakeMagic() " skip the rest of a collection -let s:coll_skip_pat = '^\^\=]\=\%(\%(\\[\^\]\-\\bertn]\|\[:\w\+:]\|[^\]]\)\@>\)*]' +let s:coll_skip_pat = '^\^\=]\=\%(\%(\\[\^\]\-\\bertn]\|\[:\w\+:]\|\[=.=]\|\[\..\.]\|[^\]]\)\@>\)*]' func! s:DocCollection(bull, hulit, item) "{{{ let collstr = a:bull.Bite(s:coll_skip_pat) - let inverse = collstr =~ '^\^' - let with_nl = a:item == '\_[' - let descr = inverse ? printf('collection not matching [%s', collstr[1:]) : 'collection' - let descr_nl = printf("%s%s", (inverse && with_nl ? ', but' : ''), (with_nl ? ' with end-of-line added' : '')) - call a:hulit.Print(a:item. collstr, descr. descr_nl) + if collstr != "" + let inverse = collstr =~ '^\^' + let with_nl = a:item == '\_[' + let descr = inverse ? printf('collection not matching [%s', collstr[1:]) : 'collection' + let descr_nl = printf("%s%s", (inverse && with_nl ? ', but' : ''), (with_nl ? ' with end-of-line added' : '')) + call a:hulit.Print(a:item. collstr, descr. descr_nl) + else + call a:hulit.AddLiteral('[') + endif endfunc "}}} let s:doc['['] = function("s:DocCollection") @@ -318,9 +382,15 @@ endfunc "}}} let s:doc['\%['] = function("s:DocOptAtoms") let s:doc[']'] = function("s:DocOptAtoms") -let s:doc['\c'] = "ignore case while matching the pattern" -let s:doc['\C'] = "match case while matching the pattern" -let s:doc['\Z'] = "ignore composing characters in the pattern" +func! s:DocAnywhere(bull, hulit, item, msg) "{{{ + call a:hulit.Print(a:item, a:msg) + " keep state: + let s:at_begin_of_pat += 1 +endfunc "}}} + +let s:doc['\c'] = [function("s:DocAnywhere"), "ignore case while matching the pattern"] +let s:doc['\C'] = [function("s:DocAnywhere"), "match case while matching the pattern"] +let s:doc['\Z'] = [function("s:DocAnywhere"), "ignore composing characters in the pattern"] " \%d 123 " \%x 2a @@ -466,7 +536,7 @@ func! s:NewTokenBiter(str, ...) "{{{ return bite endfunc "}}} - " get the unparsed rest of input + " get the unparsed rest of input (not consuming) func! obj.Rest() "{{{ return self.str endfunc "}}} diff --git a/autoload/nwo/magic.vim b/autoload/nwo/magic.vim index 3342102..557af82 100644 --- a/autoload/nwo/magic.vim +++ b/autoload/nwo/magic.vim @@ -1,10 +1,10 @@ " File: makemagic.vim " Created: 2011 Apr 18 -" Last Change: 2012 Dec 19 -" Rev Days: 4 +" Last Change: 2013 Mar 06 +" Rev Days: 6 " Author: Andy Wokula " License: Vim License, see :h license -" Version: 0.1 +" Version: 0.3 "" Comments {{{ @@ -18,6 +18,7 @@ " TODO " - recognize [#-\\]], with spaces: [ #-\ \] ] " (collection ends at second ']') +" + \v\z( => \z( " 2011 Nov 01 copied from asneeded\makemagic.vim " now asneeded\nwo\makemagic.vim (comments there!) @@ -108,7 +109,7 @@ endfunc "}}} " s:variables {{{ " pattern to match very magic items: -let s:vmagic_items_pat = '\\.\|%\%([#$(UV[\^cdlouvx]\|''.\|[<>]\%(''.\|[clv]\)\)\|[&()+<=>?|]\|@\%([!=>]\|<[!=]\)\|{' +let s:vmagic_items_pat = '\C\\\%(z(\|.\)\|%\%([#$(UV[\^cdlouvx]\|[<>]\=\%(''.\|\d\+[clv]\)\)\|[&()+<=>?|]\|@\%([!=>]\|<[!=]\)\|{' " not escaped - require an even number of '\' (zero or more) to the left: let s:not_escaped = '\%(\%(^\|[^\\]\)\%(\\\\\)*\)\@<=' @@ -129,7 +130,7 @@ let s:switchpat = { " skip over a collection (starting at '[' (same for all magic modes) or " starting at '\_[' (same for all modes)) -let s:collection_skip_pat = '^\%(\\_\)\=\[\^\=]\=\%(\%(\\[\^\]\-\\bertn]\|\[:\w\+:]\|[^\]]\)\@>\)*]' +let s:collection_skip_pat = '^\%(\\_\)\=\[\^\=]\=\%(\%(\\[\^\]\-\\bertn]\|\[:\w\+:]\|\[=.=]\|\[\..\.]\|[^\]]\)\@>\)*]' " }}} diff --git a/doc/explainpat.txt b/doc/explainpat.txt index e38bc62..f4500fa 100644 --- a/doc/explainpat.txt +++ b/doc/explainpat.txt @@ -1,20 +1,21 @@ *explainpat.txt* Give detailed help on a regexp pattern. - For Vim version 7.0. Last change: 2012 Dec 19 + For Vim version 7.0. Last change: 2013 Mar 09 By Andy Wokula *explainpat* *explainpat.vim* -When you want to inspect a given Vim regexp pattern, this script might save -you lots of help lookups. And it will make the structure of a regexp visible. -And it helps spotting mistakes. +ExplainPat is a plugin to inspect a Vim regexp pattern and show a line of help +for each found regexp item. -If you find that it explains something wrong, drop me an email. +If you find that it explains something wrong, please drop me an email. +URL http://vim.sourceforge.net/scripts/script.php?script_id=4364 ============================================================================== *:ExplainPattern* -:ExplainPattern [{pattern} | {register}] - parse the given Vim {pattern} and print a line of help - (with color) for each found pattern item. Nested +:ExplainPattern {pattern} +:ExplainPattern {register} + inspect the given Vim {pattern} and print a line of + help (with color) for each found pattern item. Nested items get extra indent. A single-char argument is used as {register} argument: @@ -23,8 +24,8 @@ If you find that it explains something wrong, drop me an email. a explain pattern from register a Notes: -The pattern is first converted into a purely magic pattern using -|nwo#magic#MakeMagic()|. This means that embedded |\V| |\M| |\m| |\V| +The pattern is first converted into a purely |magic| pattern using +|nwo#magic#MakeMagic()|. This means that embedded |/\V| |/\M| |/\m| |/\v| specifiers are effectively removed from the explanation. :ExplainPattern also accepts some invalid patterns: > @@ -32,5 +33,38 @@ specifiers are effectively removed from the explanation. Pattern: \) \) end of group +============================================================================== +History: + +v0.5 ++ BF `$\n^` ++ wording: `\|' is not an "OR branch" (it separates or branches) ++ NF added tests (not part of release) ++ NF accept custom help printer (for testing purpose, could also be used to + export HTML etc.) + +v0.4 ++ BF `[foo` is a literal string ++ BF for |/star|, |/^| and |/$|, distinguish position in the pattern + (sometimes these become literal); special cases: `^**', `^^', `\c^^', `$$', + `a\|^b', `a\&*b', `[ab', `\_[ab', ... + +v0.3 ++ BF accept `\z(...\)` and `\z[N]` ++ BF accept `[=a=]` and `[.a.]` in collections + +v0.2 ++ include vim_use suggestions [2012 Dec 19] + * for collections [^...], add "not matching [...]" + * fix `\%>'a1` + * more detailed `\%x31` + +v0.1 (initial version) ++ start of "first" capturing group, start of 2nd ... ++ `\|' should get less indent than the branches, do we need to create an + AST? ! no, keep it straight forward ++ \%[...] ++ \{, \{- + ============================================================================== vim:tw=78:fo=tcq2:sts=0:ts=8:sw=8:fdm=marker:fmr=^_\^,^\^:ft=help: diff --git a/plugin/explainpat.vim b/plugin/explainpat.vim index ebe9fb1..18dd574 100644 --- a/plugin/explainpat.vim +++ b/plugin/explainpat.vim @@ -1,10 +1,10 @@ " File: explainpat.vim " Created: 2011 Nov 02 -" Last Change: 2012 Dec 19 -" Rev Days: 3 +" Last Change: 2013 Mar 08 +" Rev Days: 7 " Author: Andy Wokula " License: Vim License, see :h license -" Version: 0.2 +" Version: 0.5 " :ExplainPattern [pattern] "