diff options
Diffstat (limited to 'runtime/plugin/logiPat.vim')
-rw-r--r-- | runtime/plugin/logiPat.vim | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/runtime/plugin/logiPat.vim b/runtime/plugin/logiPat.vim new file mode 100644 index 0000000..47fabe9 --- /dev/null +++ b/runtime/plugin/logiPat.vim @@ -0,0 +1,339 @@ +" LogiPat: Boolean logical pattern matcher +" Author: Charles E. Campbell +" Date: Apr 04, 2016 +" Version: 4 +" Purpose: to do Boolean-logic based regular expression pattern matching +" Copyright: Copyright (C) 1999-2011 Charles E. Campbell {{{1 +" Permission is hereby granted to use and distribute this code, +" with or without modifications, provided that this copyright +" notice is copied with it. Like most anything else that's free, +" LogiPat.vim is provided *as is* and comes with no warranty +" of any kind, either expressed or implied. By using this +" plugin, you agree that in no event will the copyright +" holder be liable for any damages resulting from the use +" of this software. +" +" Usage: {{{1 +" :LogiPat ... +" +" Boolean logic supported: +" () grouping operators +" ! not the following pattern +" | logical or +" & logical and +" "..pattern.." +" Example: {{{1 +" :LogiPat !("january"|"february") +" would match all strings not containing the strings january +" or february +" GetLatestVimScripts: 1290 1 :AutoInstall: LogiPat.vim +" +" Behold, you will conceive in your womb, and bring forth a son, {{{1 +" and will call his name Jesus. He will be great, and will be +" called the Son of the Most High. The Lord God will give him the +" throne of his father, David, and he will reign over the house of +" Jacob forever. There will be no end to his kingdom. (Luke 1:31-33 WEB) + +" --------------------------------------------------------------------- +" Load Once: {{{1 +if &cp || exists("loaded_logiPat") + finish +endif +let g:loaded_logiPat = "v4" +let s:keepcpo = &cpo +set cpo&vim +"DechoRemOn + +" --------------------------------------------------------------------- +" Public Interface: {{{1 +com! -nargs=* LogiPat call LogiPat(<q-args>,1) +sil! com -nargs=* LP call LogiPat(<q-args>,1) +sil! com -nargs=* LPR call LogiPat(<q-args>,1,"r") +com! -nargs=+ LPE echomsg LogiPat(<q-args>) +com! -nargs=+ LogiPatFlags let s:LogiPatFlags="<args>" +sil! com -nargs=+ LPF let s:LogiPatFlags="<args>" + +" ===================================================================== +" Functions: {{{1 + +" --------------------------------------------------------------------- +" LogiPat: this function interprets the boolean-logic pattern {{{2 +fun! LogiPat(pat,...) +" call Dfunc("LogiPat(pat<".a:pat.">)") + + " LogiPat(pat,dosearch) + if a:0 > 0 + let dosearch= a:1 + else + let dosearch= 0 + endif + if a:0 >= 3 + let s:LogiPatFlags= a:3 + endif + + let s:npatstack = 0 + let s:nopstack = 0 + let s:preclvl = 0 + let expr = a:pat + + " Lexer/Parser + while expr != "" +" call Decho("expr<".expr.">") + + if expr =~ '^"' + " push a Pattern; accept "" as a single " in the pattern + let expr = substitute(expr,'^\s*"','','') + let pat = substitute(expr,'^\(\%([^"]\|\"\"\)\{-}\)"\([^"].*$\|$\)','\1','') + let pat = substitute(pat,'""','"','g') + let expr = substitute(expr,'^\(\%([^"]\|\"\"\)\{-}\)"\([^"].*$\|$\)','\2','') + let expr = substitute(expr,'^\s*','','') +" call Decho("pat<".pat."> expr<".expr.">") + + call s:LP_PatPush('.*'.pat.'.*') + + elseif expr =~ '^[!()|&]' + " push an operator + let op = strpart(expr,0,1) + let expr = strpart(expr,strlen(op)) + " allow for those who can't resist doubling their and/or operators + if op =~ '[|&]' && expr[0] == op + let expr = strpart(expr,strlen(op)) + endif + call s:LP_OpPush(op) + + elseif expr =~ '^\s' + " skip whitespace + let expr= strpart(expr,1) + + else + echoerr "operator<".strpart(expr,0,1)."> not supported (yet)" + let expr= strpart(expr,1) + endif + + endwhile + + " Final Execution + call s:LP_OpPush('Z') + + let result= s:LP_PatPop(1) +" call Decho("result=".result) + + " sanity checks and cleanup + if s:npatstack > 0 + echoerr s:npatstack." patterns left on stack!" + let s:npatstack= 0 + endif + if s:nopstack > 0 + echoerr s:nopstack." operators left on stack!" + let s:nopstack= 0 + endif + + " perform the indicated search + if dosearch + if exists("s:LogiPatFlags") && s:LogiPatFlags != "" +" call Decho("search(result<".result."> LogiPatFlags<".s:LogiPatFlags.">)") + call search(result,s:LogiPatFlags) + else +" call Decho("search(result<".result.">)") + call search(result) + endif + let @/= result + endif + +" call Dret("LogiPat ".result) + return result +endfun + +" --------------------------------------------------------------------- +" s:String: Vim6.4 doesn't have string() {{{2 +func! s:String(str) + return "'".escape(a:str, '"')."'" +endfunc + +" --------------------------------------------------------------------- +" LP_PatPush: {{{2 +fun! s:LP_PatPush(pat) +" call Dfunc("LP_PatPush(pat<".a:pat.">)") + let s:npatstack = s:npatstack + 1 + let s:patstack_{s:npatstack} = a:pat +" call s:StackLook("patpush") "Decho +" call Dret("LP_PatPush : npatstack=".s:npatstack) +endfun + +" --------------------------------------------------------------------- +" LP_PatPop: pop a number/variable from LogiPat's pattern stack {{{2 +fun! s:LP_PatPop(lookup) +" call Dfunc("LP_PatPop(lookup=".a:lookup.")") + if s:npatstack > 0 + let ret = s:patstack_{s:npatstack} + let s:npatstack = s:npatstack - 1 + else + let ret= "---error---" + echoerr "(LogiPat) invalid expression" + endif +" call s:StackLook("patpop") "Decho +" call Dret("LP_PatPop ".ret) + return ret +endfun + +" --------------------------------------------------------------------- +" LP_OpPush: {{{2 +fun! s:LP_OpPush(op) +" call Dfunc("LP_OpPush(op<".a:op.">)") + + " determine new operator's precedence level + if a:op == '(' + let s:preclvl= s:preclvl + 10 + let preclvl = s:preclvl + elseif a:op == ')' + let s:preclvl= s:preclvl - 10 + if s:preclvl < 0 + let s:preclvl= 0 + echoerr "too many )s" + endif + let preclvl= s:preclvl + elseif a:op =~ '|' + let preclvl= s:preclvl + 2 + elseif a:op =~ '&' + let preclvl= s:preclvl + 4 + elseif a:op == '!' + let preclvl= s:preclvl + 6 + elseif a:op == 'Z' + let preclvl= -1 + else + echoerr "expr<".expr."> not supported (yet)" + let preclvl= s:preclvl + endif +" call Decho("new operator<".a:op."> preclvl=".preclvl) + + " execute higher-precdence operators +" call Decho("execute higher-precedence operators") + call s:LP_Execute(preclvl) + + " push new operator onto operator-stack +" call Decho("push new operator<".a:op."> onto stack with preclvl=".preclvl." at nopstack=".(s:nopstack+1)) + if a:op =~ '!' + let s:nopstack = s:nopstack + 1 + let s:opprec_{s:nopstack} = preclvl + let s:opstack_{s:nopstack} = a:op + elseif a:op =~ '|' + let s:nopstack = s:nopstack + 1 + let s:opprec_{s:nopstack} = preclvl + let s:opstack_{s:nopstack} = a:op + elseif a:op == '&' + let s:nopstack = s:nopstack + 1 + let s:opprec_{s:nopstack} = preclvl + let s:opstack_{s:nopstack} = a:op + endif + +" call s:StackLook("oppush") "Decho +" call Dret("LP_OpPush : s:preclvl=".s:preclvl) +endfun + +" --------------------------------------------------------------------- +" LP_Execute: execute operators from opstack using pattern stack {{{2 +fun! s:LP_Execute(preclvl) +" call Dfunc("LP_Execute(preclvl=".a:preclvl.") npatstack=".s:npatstack." nopstack=".s:nopstack) + + " execute all higher precedence operators + while s:nopstack > 0 && a:preclvl < s:opprec_{s:nopstack} + let op= s:opstack_{s:nopstack} +" call Decho("op<".op."> nop=".s:nopstack." [preclvl=".a:preclvl."] < [opprec_".s:nopstack."=".s:opprec_{s:nopstack}."]") + + let s:nopstack = s:nopstack - 1 + + if op == '!' + let n1= s:LP_PatPop(1) + call s:LP_PatPush(s:LP_Not(n1)) + + elseif op == '|' + let n1= s:LP_PatPop(1) + let n2= s:LP_PatPop(1) + call s:LP_PatPush(s:LP_Or(n2,n1)) + + elseif op =~ '&' + let n1= s:LP_PatPop(1) + let n2= s:LP_PatPop(1) + call s:LP_PatPush(s:LP_And(n2,n1)) + endif + +" call s:StackLook("execute") "Decho + endwhile + +" call Dret("LP_Execute") +endfun + +" --------------------------------------------------------------------- +" LP_Not: writes a logical-not for a pattern {{{2 +fun! s:LP_Not(pat) +" call Dfunc("LP_Not(pat<".a:pat.">)") + if a:pat =~ '^\.\*' && a:pat =~ '\.\*$' + let pat= substitute(a:pat,'^\.\*\(.*\)\.\*$','\1','') + let ret= '^\%(\%('.pat.'\)\@!.\)*$' + else + let ret= '^\%(\%('.a:pat.'\)\@!.\)*$' + endif +" call Dret("LP_Not ".ret) + return ret +endfun + +" --------------------------------------------------------------------- +" LP_Or: writes a logical-or branch using two patterns {{{2 +fun! s:LP_Or(pat1,pat2) +" call Dfunc("LP_Or(pat1<".a:pat1."> pat2<".a:pat2.">)") + let ret= '\%('.a:pat1.'\|'.a:pat2.'\)' +" call Dret("LP_Or ".ret) + return ret +endfun + +" --------------------------------------------------------------------- +" LP_And: writes a logical-and concat using two patterns {{{2 +fun! s:LP_And(pat1,pat2) +" call Dfunc("LP_And(pat1<".a:pat1."> pat2<".a:pat2.">)") + let ret= '\%('.a:pat1.'\&'.a:pat2.'\)' +" call Dret("LP_And ".ret) + return ret +endfun + +" --------------------------------------------------------------------- +" StackLook: {{{2 +fun! s:StackLook(description) +" call Dfunc("StackLook(description<".a:description.">)") + let iop = 1 + let ifp = 1 +" call Decho("Pattern Operator") + + " print both pattern and operator + while ifp <= s:npatstack && iop <= s:nopstack + let fp = s:patstack_{ifp} + let op = s:opstack_{iop}." (P".s:opprec_{s:nopstack}.')' + let fplen= strlen(fp) + if fplen < 30 + let fp= fp.strpart(" ",1,30-fplen) + endif +" call Decho(fp.op) + let ifp = ifp + 1 + let iop = iop + 1 + endwhile + + " print just pattern + while ifp <= s:npatstack + let fp = s:patstack_{ifp} +" call Decho(fp) + let ifp = ifp + 1 + endwhile + + " print just operator + while iop <= s:nopstack + let op = s:opstack_{iop}." (P".s:opprec_{s:nopstack}.')' +" call Decho(" ".op) + let iop = iop + 1 + endwhile +" call Dret("StackLook") +endfun + +" --------------------------------------------------------------------- +" Cleanup And Modeline: {{{1 +let &cpo= s:keepcpo +unlet s:keepcpo +" vim: ts=4 fdm=marker |