Commits

ZyX_I committed d6069cc

@/fwc: Fixed {optional} completion when next alternative contains a check

Comments (0)

Files changed (4)

plugin/frawor/fwc/compiler.vim

 function s:compiler.getlvarid(v)
     return printf('@$@%s%X', a:v, len(self.stack))
 endfunction
+"▶1 getulvarid      :: varname + self → varname
+function s:compiler.getulvarid(v)
+    let lvarid=printf('@$@%s%X', a:v, len(self.stack))
+    let i=0
+    while has_key(self.lvars, printf('%s_%X', lvarid, i))
+        let i+=1
+    endwhile
+    let lvarid=printf('%s_%X', lvarid, i)
+    let self.lvars[lvarid]=1
+    return lvarid
+endfunction
 "▶1 getd            :: varname + self → varname + self
 function s:compiler.getd(var)
     if !has_key(self.o, 'requiresd')
                     \'(sort(keys('.a:ldtmp.'))))'
     endif
 endfunction
-"▶1 addmatches      :: &self(ldstr, exptype)
-function s:compiler.addmatches(ldstr, exptype)
+"▶1 setmatches      :: &self(ldstr, exptype)
+function s:compiler.setmatches(ldstr, exptype)
     if self.joinlists
         call add(self.ldstrs, [a:ldstr, a:exptype])
         return self
     else
-        return self.increment('@-@', self.getmatcher(self.matcher, a:ldstr,
-                    \                                self.comparg, 1))
+        let vstr=self.vstrs[-1]
+        call add(self.vstinf[vstr], ['let', a:ldstr])
+        call filter(self.l, '!(v:val[0] is# "let" && v:val[1] is# vstr)')
+        return self.let(vstr, self.getmatcher(self.matcher, a:ldstr,
+                    \                         self.comparg, 1))
     endif
 endfunction
+"▶1 newvstr         :: idx + self → varname + self
+function s:compiler.newvstr(idx)
+    let vstr=self.getulvarid('matches_'.matchstr(a:idx, '\v\w+$'))
+    call add(self.vstrs, vstr)
+    call self.let(vstr, '[]')
+    let self.vstinf[vstr]=[]
+    return vstr
+endfunction
+"▶1 popvstr         :: &self
+function s:compiler.popvstr()
+    let vstr=self.vstrs[-1]
+    call remove(self.vstrs, -1)
+    if !empty(self.vstinf[vstr])
+        call self.increment(self.vstrs[-1], vstr)
+        call add(self.vstinf[self.vstrs[-1]], ['inc', vstr])
+    endif
+    return self
+endfunction
 "▶1 addjoinedmtchs  :: &self
 function s:compiler.addjoinedmtchs()
     if !self.joinlists && !empty(self.ldstrs)
         let curldbase=self.getlvarid('curld').'_'
         let lststrs=map(remove(self.ldstrs, 0, -1),
                     \   'self.getmatchstr(v:val[0], v:val[1], curldbase.v:key)')
-        call self.addmatches(join(lststrs, '+'), type([]))
+        call self.setmatches(join(lststrs, '+'), type([]))
     endif
     return self
 endfunction
                     \.up().addif()
                         \.increment(argidxstr)
                     \.up()
-                \.up()
+                \.up().up()
         endif
     endif
     return self
 endfunction
 "▶1 compilearg      :: &self(argcontext, idx, type)
 function s:compiler.compilearg(argcon, idx, type)
+    "▶2 Define variables
     if a:argcon[0] is# 'arg'
         let arg=a:argcon[1:]
     else
     endif
     let pmsgnum=len(self.msgs.own)
     let msg=[]
-    let i=0
     let savedonlystrings=self.o.onlystrings
+    "▶3 Variables useful only for completion
     if a:type is# 'complete'
         let addedcompletion=0
         let addedcycle=0
         let argidxstr=self.getlvarid('argidx')
-        let vstr='@-@'
+        " Name of variable containing current matches
+        let vstr=self.newvstr(a:idx)
         let jstart=len(self.ldstrs)
     endif
+    "▲2
+    let i=0
     for proc in arg
         let i+=1
         let compargs=[proc, a:idx.'.'.i, a:type]
             continue
         endif
         if a:type is# 'complete'
-            if addedcompletion && !addedcycle
-                let addedcycle=1
-                if self.joinlists && vstr is# '@-@'
-                    let mtchsstr=self.getlvarid('matches').'_'.matchstr(a:idx,
-                                \                                      '\v\d+$')
-                    let vstr=mtchsstr
-                    call self.joinmatches(jstart, mtchsstr)
+            if addedcompletion
+                if !addedcycle
+                    let addedcycle=1
+                    if self.joinlists
+                        call self.joinmatches(jstart, vstr)
+                    endif
+                    call self.let(argidxstr, 0)
+                                \.while(argidxstr.'<len('.vstr.')')
+                                    \.try()
+                                        \.pushms('throwignore')
+                                        \.witharg([vstr, [[argidxstr]]])
                 endif
-                call self.let(argidxstr, 0)
-                            \.while(argidxstr.'<len('.vstr.')')
-                                \.try()
-                                    \.pushms('throwignore')
-                                    \.witharg([vstr, [[argidxstr]]])
             elseif compargs[0][1][0] is# 'intfunc' &&
                         \has_key(s:_r.FWC_intfuncs[compargs[0][1][1]],
                         \        'breakscomp')
     if len(self.msgs.own)>pmsgnum
         call remove(self.msgs.own, pmsgnum, -1)
     endif
-    if a:type is# 'complete' && addedcycle
-        call self.without().popms()
-                    \.increment(argidxstr)
-                \.up().catch(s:cfreg)
-                    \.call('remove('.vstr.', '.argidxstr.')')
-                \.up()
-            \.up().up()
-            \.optimizecompf(vstr)
+    if a:type is# 'complete'
+        if addedcycle
+            call self.without().popms()
+                        \.increment(argidxstr)
+                    \.up().catch(s:cfreg)
+                        \.call('remove('.vstr.', '.argidxstr.')')
+                    \.up()
+                \.up().up()
+                \.optimizecompf(vstr)
+        endif
+        call self.popvstr()
     endif
     return self
 endfunction
 "▶1 compadescr      :: &self(adescr, idx, type[, purgemax]])
 function s:compiler.compadescr(adescr, idx, type, ...)
     let purgemax=get(a:000, 0, 0)
-    "▶2 Length checks, lagsstr and nextsub variables
-    if !empty(self.subs)
-        let largsstr=self.getlargsstr()
-        if a:type is# 'check' || a:type is# 'pipe'
-            if !has_key(a:adescr, 'minimum')
-                call s:F.getlenrange(a:adescr)
+    if a:type is# 'complete'
+        call self.newvstr(a:idx)
+    endif
+    try
+        "▶2 Length checks, lagsstr and nextsub variables
+        if !empty(self.subs)
+            let largsstr=self.getlargsstr()
+            if a:type is# 'check' || a:type is# 'pipe'
+                if !has_key(a:adescr, 'minimum')
+                    call s:F.getlenrange(a:adescr)
+                endif
+                if !has_key(a:adescr, 'checkedfor')
+                    call self.addlencheck(a:adescr.minimum,
+                                \         ((purgemax)?(-1):(a:adescr.maximum)))
+                    let a:adescr.checkedfor=1
+                endif
             endif
-            if !has_key(a:adescr, 'checkedfor')
-                call self.addlencheck(a:adescr.minimum, ((purgemax)?
-                            \                               (-1):
-                            \                               (a:adescr.maximum)))
-                let a:adescr.checkedfor=1
+            let nextsub=copy(self.subs[-1])
+        endif
+        "▶2 `arg' key
+        if has_key(a:adescr, 'arg')
+            let i=0
+            for arg in a:adescr.arg
+                let i+=1
+                if self.o.only
+                    let idx=a:idx
+                else
+                    let idx=a:idx.'.'.i
+                endif
+                if a:type is# 'complete' && !self.o.only
+                    call self.addif(largsstr.'-1 == '.self.getlastsub())
+                endif
+                call self.compilearg(arg, idx, a:type)
+                call self.incsub()
+                if a:type is# 'complete' && !self.o.only
+                    call self.up()
+                endif
+                if self.onlyfirst
+                    return self
+                endif
+            endfor
+            if !empty(self.subs)
+                unlet nextsub
+                let nextsub=copy(self.subs[-1])
             endif
         endif
-        let nextsub=copy(self.subs[-1])
-    endif
-    "▶2 `arg' key
-    if has_key(a:adescr, 'arg')
-        let i=0
-        for arg in a:adescr.arg
-            let i+=1
-            if self.o.only
-                let idx=a:idx
-            else
-                let idx=a:idx.'.'.i
-            endif
-            if a:type is# 'complete' && !self.o.only
-                call self.addif(largsstr.'-1 == '.self.getlastsub())
-            endif
-            call self.compilearg(arg, idx, a:type)
-            call self.incsub()
-            if a:type is# 'complete' && !self.o.only
-                call self.up()
-            endif
-            if self.onlyfirst
-                return self
+        "▶2 Quit if no more keys are present or if we are checking the only argument
+        if empty(self.subs) || empty(a:adescr)
+                    \|| empty(filter(copy(s:_r.FWC_topconstructs._order),
+                    \         'has_key(a:adescr, v:val)'))
+            return self
+        endif
+        "▲2
+        let addedsavemsgs=0
+        let caidxstr=self.getlvarid('caidx')
+        let oldsub=self.getsub(nextsub)
+        if oldsub isnot caidxstr
+            call self.let(caidxstr, oldsub)
+        endif
+        let self.subs[-1]=[caidxstr]
+        "▶2 Following keys (optional, prefixes, next, actions)
+        for key in s:_r.FWC_topconstructs._order
+            if has_key(a:adescr, key)
+                if self.o.only && !get(s:_r.FWC_topconstructs[key], 'allowonly',
+                            \          0)
+                    call s:_f.throw('onlyforb', key)
+                endif
+                if a:type is# 'complete'
+                    call self.newvstr(a:idx)
+                endif
+                let [newnextsub, addedsavemsgs]=
+                            \call(s:_r.FWC_topconstructs[key].compile,
+                            \     [a:adescr, a:idx, caidxstr, largsstr,
+                            \      purgemax, a:type, nextsub, addedsavemsgs],
+                            \     self)
+                unlet nextsub
+                let nextsub=newnextsub
+                unlet newnextsub
+                if a:type is# 'complete'
+                    call self.popvstr()
+                endif
             endif
         endfor
-        if !empty(self.subs)
-            unlet nextsub
-            let nextsub=copy(self.subs[-1])
+        "▶2 Check for processed argument length
+        " XXX a:0 is checked here
+        if !a:0 && type(self.subs[-1])==type([]) && a:type isnot 'complete'
+            let largsstr=self.getlargsstr()
+            let proclen=self.getlastsub()
+            call self.addif(proclen.' isnot '.largsstr)
+                        \.addthrow('lennmatch', 0, proclen, largsstr)
         endif
-    endif
-    "▶2 Quit if no more keys are present or if we are checking the only argument
-    if empty(self.subs) || empty(a:adescr)
-                \|| empty(filter(copy(s:_r.FWC_topconstructs._order),
-                \         'has_key(a:adescr, v:val)'))
+        "▶2 addrestmsgs
+        if addedsavemsgs
+            call self.addrestmsgs()
+        endif
+        "▲2
         return self
-    endif
+    "▶2 popvstr
+    finally
+        if a:type is# 'complete'
+            call self.popvstr()
+        endif
+    endtry
     "▲2
-    let addedsavemsgs=0
-    let caidxstr=self.getlvarid('caidx')
-    let oldsub=self.getsub(nextsub)
-    if oldsub isnot caidxstr
-        call self.let(caidxstr, oldsub)
-    endif
-    let self.subs[-1]=[caidxstr]
-    "▶2 Following keys (optional, prefixes, next, actions)
-    for key in s:_r.FWC_topconstructs._order
-        if has_key(a:adescr, key)
-            if self.o.only && !get(s:_r.FWC_topconstructs[key], 'allowonly', 0)
-                call s:_f.throw('onlyforb', key)
-            endif
-            let [newnextsub, addedsavemsgs]=
-                        \call(s:_r.FWC_topconstructs[key].compile,
-                        \     [a:adescr,a:idx,caidxstr,largsstr,purgemax,a:type,
-                        \      nextsub, addedsavemsgs],
-                        \     self)
-            unlet nextsub
-            let nextsub=newnextsub
-            unlet newnextsub
-        endif
-    endfor
-    "▶2 Check for processed argument length
-    " XXX a:0 is checked here
-    if !a:0 && type(self.subs[-1])==type([]) && a:type isnot 'complete'
-        let largsstr=self.getlargsstr()
-        let proclen=self.getlastsub()
-        call self.addif(proclen.' isnot '.largsstr)
-                    \.addthrow('lennmatch', 0, proclen, largsstr)
-    endif
-    "▶2 addrestmsgs
-    if addedsavemsgs
-        call self.addrestmsgs()
-    endif
-    "▲2
-    return self
 endfunction
 "▶1 compstr         :: vars, String, type, doreturn → [String]
 let s:defcompletematcher=['matcher', ['intfunc', 'smart', 2]]
                 \   'type': a:type,
                 \   'subs': [],
                 \   'vars': a:vars,
+                \  'lvars': {},
                 \   'vids': {},
                 \'argbase': '@@@',
                 \  'preva': [],
         let t.comparg=t.argbase.t.getsubs([-1])
         let t.joinlists=0
         let t.ldstrs=[]
+        let t.vstrs=['@-@']
+        let t.vstinf={'@-@': []}
     endif
     "▲2
     let a:vars.F={'warn': s:_f.warn, 'throw': s:_f.throw}

plugin/frawor/fwc/intfuncs.vim

         " XXX a:desc[1] contains one more items then required, as well as output 
         " of getuserfunctions
         let ldescr=len(a:desc[1])
-        return self.addmatches('map(filter('.getuserfunctionsstr.
+        return self.setmatches('map(filter('.getuserfunctionsstr.
                     \          ', "len(v:val)=='.ldescr.' || '.
                     \             '(len(v:val)<='.(ldescr+1).' && '.
                     \              'v:val[-1] is# ''...'')"), "v:val[0]")+'.
                     \                          'v:val[-1]<='.(ldescr).')")))',
                     \          type([]))
     endif
-    return self.addmatches('map('.getuserfunctionsstr.', "v:val[0]")', type([]))
+    return self.setmatches('map('.getuserfunctionsstr.', "v:val[0]")', type([]))
 endfunction
 "▶1 `earg'
 " Replaces {argument} with the result of evaluating itself
     endif
     let i=1
     for arg in a:desc[1][1:]
-        call self.if('empty(@-@)')
+        call self.if('empty('.self.vstrs[-1].')')
                     \.compilearg(arg, a:idx.'(either).'.i, 'complete')
                 \.up().endif()
         let i+=1
     endif
 endfunction
 function s:r.in.complete(desc, idx, type)
-    return self.addmatches(self.getvar(a:desc[1]), type([]))
+    return self.setmatches(self.getvar(a:desc[1]), type([]))
 endfunction
 "▶1 `key'
 let s:r.key={'args': ['var', '?omtchr']}
     return call(s:r.in.pipe, a:000+['key'], self)
 endfunction
 function s:r.key.complete(desc, idx, type)
-    return self.addmatches(self.getvar(a:desc[1]), type({}))
+    return self.setmatches(self.getvar(a:desc[1]), type({}))
 endfunction
 "▶1 `take'
 " Replaces {argument} with value of the first key from {var}::Dictionary that 
     if has_key(s:idofcompletes, spec)
         let getvariantsstr=self.getfunstatvar('completers', s:F['get'.spec.'s'],
                     \                         spec.'s').'()'
-        return self.addmatches(getvariantsstr, type([]))
+        return self.setmatches(getvariantsstr, type([]))
     elseif spec is# 'command'
         let intcmdsstr=self.getfunstatvar('completers', s:F.getinternalcommands,
                     \                     'commands').'()'
         let usercmdsstr=self.getfunstatvar('completers', s:F.getusercommands,
                     \                      'ucommands').'()'
-        return self.addmatches(intcmdsstr.'+'.usercmdsstr, type([]))
+        return self.setmatches(intcmdsstr.'+'.usercmdsstr, type([]))
     elseif spec is# 'function'
         let userfunctionsstr='map('.self.getfunstatvar('completers',
                     \                                  s:F.getuserfunctions,
         let intfuncsstr='keys('.self.getfunstatvar('completers',
                     \                              s:F.getinternalfunctions,
                     \                              'vimfunctions').'())'
-        return self.addmatches(userfunctionsstr.'+'.intfuncsstr, type([]))
+        return self.setmatches(userfunctionsstr.'+'.intfuncsstr, type([]))
     elseif spec is# 'option'
         let intoptsstr='map('.self.getfunstatvar('completers', s:F.getoptions,
                     \                            'options').'(), "v:val[0]")'
-        return self.addmatches(intoptsstr, type([]))
+        return self.setmatches(intoptsstr, type([]))
     elseif spec is# 'variable'
-        return self.addmatches(s:varsstr, type([]))
+        return self.setmatches(s:varsstr, type([]))
     endif
 endfunction
 "▲2
         endif
     endif
     let getfilesstr=self.getfunstatvar('completers', s:F.getfiles, 'path')
-    return self.addmatches(getfilesstr.'('.self.comparg.', '.
+    return self.setmatches(getfilesstr.'('.self.comparg.', '.
                 \                          self.string(filter).', 1)', type([]))
 endfunction
 "▶1 `type'

plugin/frawor/fwc/topconstructs.vim

         endif
     else
         call self.addif(a:caidxstr.'=='.a:largsstr.'-1')
-                    \.addmatches(plstr, type([]))
+                    \.setmatches(plstr, type([]))
                     \.break()
                 \.up()
     endif
                                 \.increment(a:caidxstr)
                             \.up()
                         \.catch(s:cfreg)
-                            \.call('remove(@$@variants, 0, -1)')
+                            \.call('remove('.self.vstrs[-1].', 0, -1)')
                         \.up()
         endif
     else
     let curargstr=self.argstr()
     if a:type is# 'complete'
         call self.addif(a:largsstr.'-1 == '.self.getlastsub())
-                        \.addmatches(fsastr, type([]))
+                        \.setmatches(fsastr, type([]))
         let savedsub=copy(self.subs[-1])
         if noact isnot 0 && len(noact)>1
             let self.onlyfirst+=1

test/fwccompletetests.dat

 
   @a+
   =s:list2
+
+`[(in list  match /e/)] [(key dict  match /b/]
+  @+
+  def-ghi abc adb
 #▶2 {prefixes}
 `{   abc  in list
 +    def  in list2
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.