]> granicus.if.org Git - vim/commitdiff
updated for version 7.0187 v7.0187
authorBram Moolenaar <Bram@vim.org>
Wed, 25 Jan 2006 22:10:52 +0000 (22:10 +0000)
committerBram Moolenaar <Bram@vim.org>
Wed, 25 Jan 2006 22:10:52 +0000 (22:10 +0000)
21 files changed:
runtime/autoload/pycomplete.vim
runtime/autoload/xmlcomplete.vim
runtime/doc/eval.txt
runtime/doc/quickfix.txt
runtime/doc/spell.txt
runtime/doc/todo.txt
runtime/doc/version7.txt
src/Makefile
src/edit.c
src/ex_cmds.h
src/globals.h
src/if_cscope.c
src/main.c
src/misc2.c
src/option.c
src/os_unix.c
src/proto/quickfix.pro
src/quickfix.c
src/screen.c
src/structs.h
src/version.h

index 8cd5a5f6d3eac67879ccc5ea181d43376fbbcb52..56a6b4e26c94508f5ab5a08fd81a5226073db168 100644 (file)
@@ -1,10 +1,20 @@
 "pycomplete.vim - Omni Completion for python
 " Maintainer: Aaron Griffin
-" Version: 0.2
-" Last Updated: 5 January 2006
+" Version: 0.3
+" Last Updated: 23 January 2006
+"
+"   v0.3 Changes:
+"       added top level def parsing
+"       for safety, call returns are not evaluated
+"       handful of parsing changes
+"       trailing ( and . characters
+"       argument completion on open parens
+"       stop parsing at current line - ++performance, local var resolution
 "
 "   TODO
-"   * local variables *inside* class members
+"       RExec subclass
+"       Code cleanup + make class
+"       use internal dict, not globals()
 
 if !has('python')
     echo "Error: Required vim compiled with +python"
@@ -20,10 +30,10 @@ function! pycomplete#Complete(findstart, base)
             let idx -= 1
             let c = line[idx-1]
             if c =~ '\w'
-                               continue
-                       elseif ! c =~ '\.'
+                continue
+            elseif ! c =~ '\.'
                 idx = -1
-                               break
+                break
             else
                 break
             endif
@@ -39,79 +49,222 @@ endfunction
 
 function! s:DefPython()
 python << PYTHONEOF
-import vim
-import sys
+import vim, sys, types
 import __builtin__
+import tokenize, keyword, cStringIO
 
 LOCALDEFS = \
        ['LOCALDEFS', 'clean_up','eval_source_code', \
         'get_completions', '__builtin__', '__builtins__', \
-        'dbg', '__name__', 'vim', 'sys']
-#comment/uncomment one line at a time to enable/disable debugging
-def dbg(msg):
-    pass
-#    print(msg)
-
-#it seems that by this point, vim has already stripped the base
-#  matched in the findstart=1 section, so we will create the
-#  statement from scratch
+        'dbg', '__name__', 'vim', 'sys', 'parse_to_end', \
+     'parse_statement', 'tokenize', 'keyword', 'cStringIO', \
+     'debug_level', 'safe_eval', '_ctor', 'get_arguments', \
+     'strip_calls', 'types', 'parse_block']
+
+def dbg(level,msg):
+    debug_level = 1
+    try:
+        debug_level = vim.eval("g:pycomplete_debug_level")
+    except:
+        pass
+    if level <= debug_level: print(msg)
+
+def strip_calls(stmt):
+    parsed=''
+    level = 0
+    for c in stmt:
+        if c in ['[','(']:
+            level += 1
+        elif c in [')',']']:
+            level -= 1
+        elif level == 0:
+            parsed += c
+    ##dbg(10,"stripped: %s" % parsed)
+    return parsed
+
 def get_completions(base):
-    stmt = vim.eval('expand("<cWORD>")')+base
-    dbg("parsed statement => %s" % stmt)
+    stmt = vim.eval('expand("<cWORD>")')
+    #dbg(1,"statement: %s - %s" % (stmt, base))
+    stmt = stmt+base
     eval_source_code()
+
     try:
-        dbg("eval: %s" % stmt)
-        if len(stmt.split('.')) == 1:
-            all = globals().keys() + dir(__builtin__)
+        ridx = stmt.rfind('.')
+        if stmt[-1] == '(':
+            match = ""
+            stmt = strip_calls(stmt[:len(stmt)-1])
+            all = get_arguments(eval(stmt))
+        elif ridx == -1:
             match = stmt
+            all = globals() + __builtin__.__dict__
         else:
-            rindex= stmt.rfind('.')
-            all = dir(eval(stmt[:rindex]))
-            match = stmt[rindex+1:]
+            match = stmt[ridx+1:]
+            stmt = strip_calls(stmt[:ridx])
+            all = eval(stmt).__dict__
 
+        #dbg(15,"completions for: %s, match=%s" % (stmt,match))
         completions = []
-        dbg("match == %s" % match)
-        for m in all:
-            #TODO: remove private (_foo) functions?
-            if m.find('__') != 0 and \
-               m.find(match) == 0 and \
-                          m not in LOCALDEFS:
-                dbg("matched... %s, %s" % (m, m.find(match)))
-                completions.append(m)
-        dbg("all completions: %s" % completions)
+        if type(all) == types.DictType:
+            for m in all:
+                if m.find('_') != 0 and m.find(match) == 0 and \
+                              m not in LOCALDEFS:
+                    #dbg(25,"matched... %s, %s" % (m, m.find(match)))
+                    typestr = str(all[m])
+                    if "function" in typestr: m += '('
+                    elif "method" in typestr: m += '('
+                    elif "module" in typestr: m += '.'
+                    elif "class" in typestr: m += '('
+                    completions.append(m)
+            completions.sort()
+        else:
+            completions.append(all)
+        #dbg(10,"all completions: %s" % completions)
         vim.command("let g:pycomplete_completions = %s" % completions)
     except:
-        dbg("exception: %s" % sys.exc_info()[1])
         vim.command("let g:pycomplete_completions = []")
+        #dbg(1,"exception: %s" % sys.exc_info()[1])
     clean_up()
 
-#yes, this is a quasi-functional python lexer
+def get_arguments(func_obj):
+    def _ctor(obj):
+        try:
+            return class_ob.__init__.im_func
+        except AttributeError:
+            for base in class_ob.__bases__:
+                rc = _find_constructor(base)
+                if rc is not None: return rc
+        return None
+
+    arg_offset = 1
+    if type(func_obj) == types.ClassType: func_obj = _ctor(func_obj)
+    elif type(func_obj) == types.MethodType: func_obj = func_obj.im_func
+    else: arg_offset = 0
+    
+    #dbg(20,"%s, offset=%s" % (str(func_obj), arg_offset))
+
+    arg_text = ''
+    if type(func_obj) in [types.FunctionType, types.LambdaType]:
+        try:
+            cd = func_obj.func_code
+            real_args = cd.co_varnames[arg_offset:cd.co_argcount]
+            defaults = func_obj.func_defaults or []
+            defaults = list(map(lambda name: "=%s" % name, defaults))
+            defaults = [""] * (len(real_args)-len(defaults)) + defaults
+            items = map(lambda a,d: a+d, real_args, defaults)
+            if func_obj.func_code.co_flags & 0x4:
+                items.append("...")
+            if func_obj.func_code.co_flags & 0x8:
+                items.append("***")
+            arg_text = ", ".join(items) + ')'
+
+        except:
+            #dbg(1,"exception: %s" % sys.exc_info()[1])
+            pass
+    if len(arg_text) == 0:
+        # The doc string sometimes contains the function signature
+        #  this works for alot of C modules that are part of the
+        #  standard library
+        doc = getattr(func_obj, '__doc__', '')
+        if doc:
+            doc = doc.lstrip()
+            pos = doc.find('\n')
+            if pos > 0:
+                sigline = doc[:pos]
+                lidx = sigline.find('(')
+                ridx = sigline.find(')')
+                retidx = sigline.find('->')
+                ret = sigline[retidx+2:].strip()
+                if lidx > 0 and ridx > 0:
+                    arg_text = sigline[lidx+1:ridx] + ')'
+                    if len(ret) > 0: arg_text += ' #returns %s' % ret
+    #dbg(15,"argument completion: %s" % arg_text)
+    return arg_text
+
+def parse_to_end(gen):
+    stmt=''
+    level = 0
+    for type, str, begin, end, line in gen:
+        if line == vim.eval('getline(\'.\')'): break
+        elif str == '\\': continue
+        elif str == ';':
+            break
+        elif type == tokenize.NEWLINE and level == 0:
+            break
+        elif str in ['[','(']:
+            level += 1
+        elif str in [')',']']:
+            level -= 1
+        elif level == 0:
+            stmt += str
+        #dbg(10,"current statement: %s" % stmt)
+    return stmt
+
+def parse_block(gen):
+    lines = []
+    level = 0
+    for type, str, begin, end, line in gen:
+        if line.replace('\n','') == vim.eval('getline(\'.\')'): break
+        elif type == tokenize.INDENT:
+            level += 1
+        elif type == tokenize.DEDENT:
+            level -= 1
+            if level == 0: break;
+        else:
+            stmt = parse_statement(gen,str)
+            if len(stmt) > 0: lines.append(stmt)
+    return lines
+
+def parse_statement(gen,curstr=''):
+    var = curstr
+    type, str, begin, end, line = gen.next()
+    if str == '=':
+        type, str, begin, end, line = gen.next()
+        if type == tokenize.NEWLINE:
+            return ''
+        elif type == tokenize.STRING or str == 'str':  
+            return '%s = str' % var
+        elif str == '[' or str == 'list':
+            return '%s= list' % var
+        elif str == '{' or str == 'dict':
+            return '%s = dict' % var
+        elif type == tokenize.NUMBER:
+            return '%s = 0' % var
+        elif str == 'Set': 
+            return '%s = Set' % var
+        elif str == 'open' or str == 'file':
+            return '%s = file' % var
+        else:
+            inst = str + parse_to_end(gen)
+            if len(inst) > 0:
+                #dbg(5,"found [%s = %s]" % (var, inst))
+                return '%s = %s' % (var, inst)
+    return ''
+
 def eval_source_code():
-    import tokenize
-    import keyword
-    import StringIO
-    s = StringIO.StringIO('\n'.join(vim.current.buffer[:]) + '\n')
+    LINE=vim.eval('getline(\'.\')')
+    s = cStringIO.StringIO('\n'.join(vim.current.buffer[:]) + '\n')
     g = tokenize.generate_tokens(s.readline)
 
     stmts = []
     lineNo = 0
     try:
         for type, str, begin, end, line in g:
-            if begin[0] == lineNo:
-                continue
+            if line.replace('\n','') == vim.eval('getline(\'.\')'): break
+            elif begin[0] == lineNo: continue
             #junk
             elif type == tokenize.INDENT or \
                  type == tokenize.DEDENT or \
                  type == tokenize.ERRORTOKEN or \
                  type == tokenize.ENDMARKER or \
-                 type == tokenize.NEWLINE:
+                 type == tokenize.NEWLINE or \
+                 type == tokenize.COMMENT:
                 continue
             #import statement
             elif str == 'import':
-                for type, str, begin, end, line in g:
-                    if str == ';' or type == tokenize.NEWLINE: break
-                    dbg("found [import %s]" % str)
-                    stmts.append("import %s" % str)
+                import_stmt=parse_to_end(g)
+                if len(import_stmt) > 0:
+                    #dbg(5,"found [import %s]" % import_stmt)
+                    stmts.append("import %s" % import_stmt)
             #import from statement
             elif str == 'from':
                 type, str, begin, end, line = g.next()
@@ -119,87 +272,68 @@ def eval_source_code():
 
                 type, str, begin, end, line = g.next()
                 if str != "import": break
-                mem = ''
+                from_stmt=parse_to_end(g)
+                if len(from_stmt) > 0:
+                    #dbg(5,"found [from %s import %s]" % (mod, from_stmt))
+                    stmts.append("from %s import %s" % (mod, from_stmt))
+            #def statement
+            elif str == 'def':
+                funcstr = ''
                 for type, str, begin, end, line in g:
-                    if str == ';' or type == tokenize.NEWLINE: break
-                    mem += (str + ',')
-                if len(mem) > 0:
-                    dbg("found [from %s import %s]" % (mod, mem[:-1]))
-                    stmts.append("from %s import %s" % (mod, mem[:-1]))
+                    if line.replace('\n','') == vim.eval('getline(\'.\')'): break
+                    elif str == ':':
+                        stmts += parse_block(g)
+                        break
+                    funcstr += str
+                if len(funcstr) > 0:
+                    #dbg(5,"found [def %s]" % funcstr)
+                    stmts.append("def %s:\n   pass" % funcstr)
             #class declaration
             elif str == 'class':
                 type, str, begin, end, line = g.next()
                 classname = str
-                dbg("found [class %s]" % classname)
+                #dbg(5,"found [class %s]" % classname)
 
                 level = 0
                 members = []
-                #we don't care about the meat of the members,
-                # only the signatures, so we'll replace the bodies
-                # with 'pass' for evaluation
                 for type, str, begin, end, line in g:
-                    if type == tokenize.INDENT:
+                    if line.replace('\n','') == vim.eval('getline(\'.\')'): break
+                    elif type == tokenize.INDENT:
                         level += 1
                     elif type == tokenize.DEDENT:
                         level -= 1
                         if level == 0: break;
                     elif str == 'def':
-                        #TODO: if name begins with '_', keep private
                         memberstr = ''
                         for type, str, begin, end, line in g:
-                            if str == ':': break
+                            if line.replace('\n','') == vim.eval('getline(\'.\')'): break
+                            elif str == ':':
+                                stmts += parse_block(g)
+                                break
                             memberstr += str
-                        dbg("   member [%s]" % memberstr)
+                        #dbg(5,"   member [%s]" % memberstr)
                         members.append(memberstr)
-                    #TODO parse self.blah = something lines
-                    #elif str == "self" && next && str == "." ...blah...
                 classstr = 'class %s:' % classname
                 for m in members:
                     classstr += ("\n   def %s:\n      pass" % m)
                 stmts.append("%s\n" % classstr)
             elif keyword.iskeyword(str) or str in globals():
-                dbg("keyword = %s" % str)
+                #dbg(5,"keyword = %s" % str)
                 lineNo = begin[0]
             else:
-                if line.find("=") == -1: continue
-                var = str
-                type, str, begin, end, line = g.next()
-                dbg('next = %s' % str)
-                if str != '=': continue
-
-                type, str, begin, end, line = g.next()
-                if type == tokenize.NEWLINE:
-                    continue
-                elif type == tokenize.STRING or str == 'str':  
-                    stmts.append('%s = str' % var)
-                elif str == '[' or str == 'list':
-                    stmts.append('%s= list' % var)
-                elif str == '{' or str == 'dict':
-                    stmts.append('%s = dict' % var)
-                elif type == tokenize.NUMBER:
-                    continue
-                elif str == 'Set': 
-                    stmts.append('%s = Set' % var)
-                elif str == 'open' or str == 'file':
-                    stmts.append('%s = file' % var)
-                else:
-                    inst = str
-                    for type, str, begin, end, line in g:
-                        if type == tokenize.NEWLINE:
-                            break
-                        inst += str
-                    if len(inst) > 0:
-                        dbg("found [%s = %s]" % (var, inst))
-                        stmts.append('%s = %s' % (var, inst))
-                lineNo = begin[0]
+                assign = parse_statement(g,str)
+                if len(assign) > 0: stmts.append(assign)
+                
         for s in stmts:
             try:
-                dbg("evaluating: %s\n" % s)
+                #dbg(15,"evaluating: %s\n" % s)
                 exec(s) in globals()
             except:
+                #dbg(1,"exception: %s" % sys.exc_info()[1])
                 pass
     except:
-        dbg("exception: %s" % sys.exc_info()[1])
+        #dbg(1,"exception: %s" % sys.exc_info()[1])
+        pass
 
 def clean_up():
     for o in globals().keys():
@@ -212,5 +346,6 @@ sys.path.extend(['.','..'])
 PYTHONEOF
 endfunction
 
+let g:pycomplete_debug_level = 0
 call s:DefPython()
 " vim: set et ts=4:
index 2d09eff096c4c9886f2b3d2667d044c44194830a..fc4ad7844e8cd0a829d8e507224269bd4c04dee2 100644 (file)
@@ -1,7 +1,7 @@
 " Vim completion script
-" Language:    XHTML 1.0 Strict
+" Language:    XML
 " Maintainer:  Mikolaj Machowski ( mikmach AT wp DOT pl )
-" Last Change: 2005 Nov 22
+" Last Change: 2006 Jan 24
 
 " This function will create Dictionary with users namespace strings and values
 " canonical (system) names of data files.  Names should be lowercase,
@@ -54,6 +54,7 @@ endfunction
 function! xmlcomplete#CompleteTags(findstart, base)
   if a:findstart
     " locate the start of the word
+       let curline = line('.')
     let line = getline('.')
     let start = col('.') - 1
        let compl_begin = col('.') - 2
@@ -69,11 +70,32 @@ function! xmlcomplete#CompleteTags(findstart, base)
        endif
 
        let b:compl_context = getline('.')[0:(compl_begin)]
-       let b:compl_context = matchstr(b:compl_context, '.*<\zs.*')
+       if b:compl_context !~ '<[^>]*$'
+               " Look like we may have broken tag. Check previous lines. Up to
+               " 10?
+               let i = 1
+               while 1
+                       let context_line = getline(curline-i)
+                       if context_line =~ '<[^>]*$'
+                               " Yep, this is this line
+                               let context_lines = getline(curline-i, curline)
+                               let b:compl_context = join(context_lines, ' ')
+                               break
+                       elseif context_line =~ '>[^<]*$'
+                               " Normal tag line, no need for completion at all
+                               let b:compl_context = ''
+                               break
+                       endif
+                       let i += 1
+               endwhile
+               " Make sure we don't have counter
+               unlet! i
+       endif
+       let b:compl_context = matchstr(b:compl_context, '.*\zs<.*')
 
        " Make sure we will have only current namespace
        unlet! b:xml_namespace
-       let b:xml_namespace = matchstr(b:compl_context, '^\k*\ze:')
+       let b:xml_namespace = matchstr(b:compl_context, '^<\zs\k*\ze:')
        if b:xml_namespace == ''
                let b:xml_namespace = 'DEFAULT'
        endif
@@ -89,7 +111,10 @@ function! xmlcomplete#CompleteTags(findstart, base)
     let res = []
     let res2 = []
        " a:base is very short - we need context
-       let context = b:compl_context
+       if len(b:compl_context) == 0  && !exists("b:entitiescompl")
+               return []
+       endif
+       let context = matchstr(b:compl_context, '^<\zs.*')
        unlet! b:compl_context
 
        " Make entities completion
@@ -111,13 +136,24 @@ function! xmlcomplete#CompleteTags(findstart, base)
                        let values = intent + values
                endif
 
-               for m in values
-                       if m =~ '^'.a:base
-                               call add(res, m.';')
-                       endif
-               endfor
+               if len(a:base) == 1
+                       for m in values
+                               if m =~ '^'.a:base
+                                       call add(res, m.';')
+                               endif
+                       endfor
+                       return res
+               else
+                       for m in values
+                               if m =~? '^'.a:base
+                                       call add(res, m.';')
+                               elseif m =~? a:base
+                                       call add(res2, m.';')
+                               endif
+                       endfor
 
-               return res
+                       return res + res2
+               endif
 
        endif
        if context =~ '>'
@@ -265,6 +301,9 @@ function! xmlcomplete#CompleteTags(findstart, base)
        " Deal with tag completion.
        let opentag = xmlcomplete#GetLastOpenTag("b:unaryTagsStack")
        let opentag = substitute(opentag, '^\k*:', '', '')
+       if opentag == ''
+               return []
+       endif
 
        let tags = g:xmldata{'_'.g:xmldata_connection[b:xml_namespace]}[opentag][0]
        let context = substitute(context, '^\k*:', '', '')
index 837ba3cb1ff74cd6a479974b195ad75cebd9cf6f..563e4bbe1e129f8ddcf0cd8963273a1c5279f278 100644 (file)
@@ -1,4 +1,4 @@
-*eval.txt*      For Vim version 7.0aa.  Last change: 2006 Jan 20
+*eval.txt*      For Vim version 7.0aa.  Last change: 2006 Jan 24
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -3260,7 +3260,7 @@ map({expr}, {string})                                     *map()*
 maparg({name}[, {mode}])                               *maparg()*
                Return the rhs of mapping {name} in mode {mode}.  When there
                is no mapping for {name}, an empty String is returned.
-               These characters can be used for {mode}:
+               {mode} can be one of these strings:
                        "n"     Normal
                        "v"     Visual
                        "o"     Operator-pending
@@ -3268,7 +3268,7 @@ maparg({name}[, {mode}])                          *maparg()*
                        "c"     Cmd-line
                        "l"     langmap |language-mapping|
                        ""      Normal, Visual and Operator-pending
-               When {mode} is omitted, the modes from "" are used.
+               When {mode} is omitted, the modes for "" are used.
                The {name} can have special key names, like in the ":map"
                command.  The returned String has special characters
                translated like in the output of the ":map" command listing.
index f97e634072cc5b84973a750826bb88c8ccfecdbe..6cd0878450ff77e9892dc9626920e315e75d1f42 100644 (file)
@@ -42,6 +42,13 @@ easy way to do this is with the |:make| command (see below).  The
 'errorformat' option should be set to match the error messages from your
 compiler (see |errorformat| below).
 
+                                               *location-list* *E776*
+A location list is a window-local quickfix list. Each window can have a
+separate location list. A location list can be associated with only one
+window. When a window with a location list is split, the new window gets a
+copy of the location list. When there are no references to a location list,
+the location list is destroyed.
+
 The following quickfix commands can be used:
 
                                                        *:cc*
@@ -56,18 +63,32 @@ The following quickfix commands can be used:
                        The 'switchbuf' settings are respected when jumping
                        to a buffer.
 
+                                                       *:ll*
+:ll[!] [nr]            Same as ":cc", except the location list for the
+                       current window is used instead of the quickfix list.
+
                                                        *:cn* *:cnext* *E553*
 :[count]cn[ext][!]     Display the [count] next error in the list that
                        includes a file name.  If there are no file names at
                        all, go to the [count] next error.  See |:cc| for
                        [!] and 'switchbuf'.
 
+                                                       *:ln* *:lnext*
+:[count]ln[ext][!]     Same as ":cnext", except the location list for the
+                       current window is used instead of the quickfix list.
+
 :[count]cN[ext][!]                     *:cp* *:cprevious* *:cN* *:cNext*
 :[count]cp[revious][!] Display the [count] previous error in the list that
                        includes a file name.  If there are no file names at
                        all, go to the [count] previous error.  See |:cc| for
                        [!] and 'switchbuf'.
 
+                                       *:lp* *:lprevious* *:lN* *:lNext*
+:[count]lN[ext][!]
+:[count]lp[revious][!] Same as ":cNext" and ":cprevious", except the location
+                       list for the current window is used instead of the
+                       quickfix list.
+
                                                        *:cnf* *:cnfile*
 :[count]cnf[ile][!]    Display the first error in the [count] next file in
                        the list that includes a file name.  If there are no
@@ -75,6 +96,10 @@ The following quickfix commands can be used:
                        the [count] next error.  See |:cc| for [!] and
                        'switchbuf'.
 
+                                                       *:lnf* *:lnfile*
+:[count]lnf[ile][!]    Same as ":cnfile", except the location list for the
+                       current window is used instead of the quickfix list.
+
 :[count]cNf[ile][!]                    *:cpf* *:cpfile* *:cNf* *:cNfile*
 :[count]cpf[ile][!]    Display the last error in the [count] previous file in
                        the list that includes a file name.  If there are no
@@ -82,17 +107,34 @@ The following quickfix commands can be used:
                        the [count] previous error.  See |:cc| for [!] and
                        'switchbuf'.
 
+                                       *:lpf* *:lpfile* *:lNf* *:lNfile*
+:[count]lNf[ile][!]
+:[count]lpf[ile][!]    Same as ":cNfile" and ":cpfile", except the location
+                       list for the current window is used instead of the
+                       quickfix list.
+
                                                        *:crewind* *:cr*
 :cr[ewind][!] [nr]     Display error [nr].  If [nr] is omitted, the FIRST
                        error is displayed.  See |:cc|.
 
+                                                       *:lrewind* *:lr*
+:lr[ewind][!] [nr]     Same as ":crewind", except the location list for the
+                       current window is used instead of the quickfix list.
+
                                                        *:cfirst* *:cfir*
 :cfir[st][!] [nr]      Same as ":crewind".
 
+                                                       *:lfirst* *:lfir*
+:lfir[st][!] [nr]      Same as ":lrewind".
+
                                                        *:clast* *:cla*
 :cla[st][!] [nr]       Display error [nr].  If [nr] is omitted, the LAST
                        error is displayed.  See |:cc|.
 
+                                                       *:llast* *:lla*
+:lla[st][!] [nr]       Same as ":clast", except the location list for the
+                       current window is used instead of the quickfix list.
+
                                                        *:cq* *:cquit*
 :cq[uit]               Quit Vim with an error code, so that the compiler
                        will not compile the same file again.
@@ -105,16 +147,31 @@ The following quickfix commands can be used:
                        name of the errorfile, the 'errorfile' option will
                        be set to [errorfile].  See |:cc| for [!].
 
+                                                       *:lf* *:lfile*
+:lf[ile][!] [errorfile]        Same as ":cfile", except the location list for the
+                       current window is used instead of the quickfix list.
+                       You can not use the -q command-line option to set
+                       the location list.
+
                                                        *:cg* *:cgetfile*
 :cg[etfile][!] [errorfile]
                        Read the error file.  Just like ":cfile" but don't
                        jump to the first error.
 
+                                                       *:lg* *:lgetfile*
+:lg[etfile][!] [errorfile]
+                       Same as ":cgetfile", except the location list for the
+                       current window is used instead of the quickfix list.
+
                                                        *:caddf* *:caddfile*
 :caddf[ile] [errorfile]        Read the error file and add the errors from the
                        errorfile to the current quickfix list. If a quickfix
                        list is not present, then a new list is created.
 
+                                                       *:laddf* *:laddfile*
+:laddf[ile] [errorfile]        Same as ":caddfile", except the location list for the
+                       current window is used instead of the quickfix list.
+
                                                *:cb* *:cbuffer* *E681*
 :cb[uffer] [bufnr]     Read the error list from the current buffer.
                        When [bufnr] is given it must be the number of a
@@ -123,6 +180,10 @@ The following quickfix commands can be used:
                        A range can be specified for the lines to be used.
                        Otherwise all lines in the buffer are used.
 
+                                               *:lb* *:lbuffer*
+:lb[uffer] [bufnr]     Same as ":cbuffer", except the location list for the
+                       current window is used instead of the quickfix list.
+
                                                        *:cex* *:cexpr* *E777*
 :cex[pr][!] {expr}     Create a quickfix list using the result of {expr} and
                        jump to the first error.  If {expr} is a String, then
@@ -137,6 +198,10 @@ The following quickfix commands can be used:
                                :cexpr system('grep -n xyz *')
                                :cexpr getline(1, '$')
 <
+                                                       *:lex* *:lexpr*
+:lex[pr][!] {expr}     Same as ":cexpr", except the location list for the
+                       current window is used instead of the quickfix list.
+
                                                        *:cad* *:caddexpr*
 :cad[dexpr][!] {expr}  Evaluate {expr} and add the resulting lines to the
                        current quickfix list. If a quickfix list is not
@@ -146,6 +211,10 @@ The following quickfix commands can be used:
                        Example: >
     :g/mypattern/caddexpr expand("%") . ":" . line(".") .  ":" . getline(".")
 <
+                                                       *:lad* *:laddexpr*
+:lad[dexpr][!] {expr}  Same as ":caddexpr", except the location list for the
+                       current window is used instead of the quickfix list.
+
                                                        *:cl* *:clist*
 :cl[ist] [from] [, [to]]
                        List all errors that are valid |quickfix-valid|.
@@ -158,6 +227,15 @@ The following quickfix commands can be used:
 :cl[ist]! [from] [, [to]]
                        List all errors.
 
+                                                       *:lli* *:llist*
+:lli[st] [from] [, [to]]
+                       Same as ":clist", except the location list for the
+                       current window is used instead of the quickfix list.
+
+:lli[st]! [from] [, [to]]
+                       List all the entries in the location list for the
+                       current window.
+
 If you insert or delete lines, mostly the correct error location is still
 found because hidden marks are used.  Sometimes, when the mark has been
 deleted for some reason, the message "line changed" is shown to warn you that
@@ -182,14 +260,28 @@ on) is executed. See |QuickFixCmdPre| and |QuickFixCmdPost| for details.
                        the current window.  It is not possible to open a
                        second quickfix window.
 
+                                                       *:lope* *:lopen*
+:lope[n] [height]      Open a window to show the location list for the
+                       current window. Works only when the location list for
+                       the current window is present. You can have more than
+                       one location window opened at a time.  Otherewise,
+                       same as ":copen".
+
                                                        *:ccl* *:cclose*
 :ccl[ose]              Close the quickfix window.
 
+                                                       *:lcl* *:lclose*
+:lcl[ose]              Close the window showing the location list for the
+                       current window.
+
                                                        *:cw* *:cwindow*
 :cw[indow] [height]    Open the quickfix window when there are recognized
                        errors.  If the window is already open and there are
                        no recognized errors, close the window.
 
+                                                       *:lw* *:lwindow*
+:lw[indow] [height]    Same as ":cwindow", except use the window showing the
+                       location list for the current window.
 
 Normally the quickfix window is at the bottom of the screen.  If there are
 vertical splits, it's at the bottom of the rightmost column of windows.  To
@@ -228,6 +320,19 @@ errors.  'modifiable' is off to avoid making changes.  If you delete or insert
 lines anyway, the relation between the text and the error number is messed up.
 If you really want to do this, you could write the contents of the quickfix
 window to a file and use ":cfile" to have it parsed and used as the new error
+list.
+
+                                               *location-list-window*
+The location list window displays the entries in a location list.  When
+opening a location list window, it is created just below the current window
+and displays the location list for the current window.  The location list
+window is similar to the quickfix window, except that you can have more than
+one location list window opened at a time.
+
+When an entry is selected from the location list window, the file is opened in
+the window with the corresponding location list.  If the window is not found,
+but the file is opened in another window, then cursor is moved to that window.
+Otherwise a new window is opened. The new window gets a copy of the location
 list.
 
 =============================================================================
@@ -243,11 +348,19 @@ lists.  They set one of the existing error lists as the current one.
                        this [count] times.  When already at the oldest error
                        list, an error message is given.
 
+                                               *:lolder* *:lol*
+:lol[der] [count]      Same as ":colder", except use the location list for
+                       the current window instead of the quickfix list.
+
                                                *:cnewer* *:cnew* *E381*
 :cnew[er] [count]      Go to newer error list.  When [count] is given, do
                        this [count] times.  When already at the newest error
                        list, an error message is given.
 
+                                               *:lnewer* *:lnew*
+:lnew[er] [count]      Same as ":cnewer", except use the location list for
+                       the current window instead of the quickfix list.
+
 When adding a new error list, it becomes the current list.
 
 When ":colder" has been used and ":make" or ":grep" is used to add a new error
index aa9c4e4755e4e52ff070e6446c4d34b708fa0d45..f9559c825f47d4de086f191f337ec3e58192fbb2 100644 (file)
@@ -1,4 +1,4 @@
-*spell.txt*    For Vim version 7.0aa.  Last change: 2006 Jan 23
+*spell.txt*    For Vim version 7.0aa.  Last change: 2006 Jan 25
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -1316,13 +1316,17 @@ efficient if the first letter is ASCII or at least one without accents.
 .SUG FILE                                              *spell-NOSUGFILE*
 
 When soundfolding is specified in the affix file then ":mkspell" will normally
-p ~ ~roduce a .sug file next to the .spl file.  This used to find suggestions by
-their sound-a-like form quickly.  At the cost of a lot of memory.
+produce a .sug file next to the .spl file.  This file is used to find
+suggestions by their sound-a-like form quickly.  At the cost of a lot of
+memory (the amount depends on the number of words, |:mkspell| will display an
+estimate when it's done).
 
 To avoid producing a .sug file use this item in the affix file:
 
        NOSUGFILE ~
 
+Users can simply omit the .sug file if they don't want to use it.
+
 
 SOUND-A-LIKE                                           *spell-SAL*
 
index aa6e2fe3cb69823778ed8378add7ace53724f56f..2566b8c640860cf1c396f9adbead4592464bf794 100644 (file)
@@ -1,4 +1,4 @@
-*todo.txt*      For Vim version 7.0aa.  Last change: 2006 Jan 23
+*todo.txt*      For Vim version 7.0aa.  Last change: 2006 Jan 25
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -30,10 +30,7 @@ be worked on, but only if you sponsor Vim development.  See |sponsor|.
                                                        *known-bugs*
 -------------------- Known bugs and current work -----------------------
 
-When ":silent" is used mode message is (should) not be displayed.  Thus don't
-set clear_cmdline to clear it.  Use separate flag to remember whether mode is
-currently displayed (and needs to be cleared).
-
+Include location list commands, patch from Yegappan Lakshmanan.
 
 ccomplete:
 - When an option is set: In completion mode and the user types (identifier)
@@ -62,7 +59,8 @@ ccomplete:
 
 spelling:
 - Use runtime/cleanadd script to cleanup .add files.  When to invoke it?
-  After deleting a word and some timestamp difference perhaps?
+  After deleting a word with "zw" and some timestamp difference perhaps?
+  Store it as spell/cleanadd.vim.
 - suggestion for "KG" to "kg" when it's keepcase.
 - Autocommand event for when a spell file is missing.  Allows making a plugin
   that fetches the file over internet.  Pattern == language.
@@ -400,25 +398,9 @@ Also place vimtutor.bat in %windir%?
 
 Add gui_mch_browsedir() for Motif, Mac OS/X.
 
-Add extra list of file locations.  A bit like the quickfix list, but there is
-one per window.  Can be used with:
+Implement:
     :ltag            list of matching tags, like :tselect
 Patch from Yegappan Lakshmanan, Jan 13.
-Commands to use the location list:
-    :lnext           next location
-    :lprevious :lNext previous location
-    :lnfile          location in next file
-    :lNfile :lpfile   location in previous file
-    :lrewind :lfirst  first location
-    :llast           last location
-    :ll [N]          go to location N (current one if N omitted)
-    :lwindow         open window with locations (separate from quickfix window)
-    :lopen           open window with locations
-    :lclose          close window with locations
-    :llist           list locations
-    :lfile           read locations from file using 'errorformat'
-    :lgetfile        idem, don't jump to first one
-    :lbuffer         idem, from current buffer.
 
 HTML indenting can be slow, find out why.  Any way to do some kind of
 profiling for Vim script?  At least add a function to get the current time in
index 0dcc713c9fe0bc43d0b392028dc812f5b2a256a6..ed929f31a7bbe6f2997e9d82b32a5aef5e6722f8 100644 (file)
@@ -1,4 +1,4 @@
-*version7.txt*  For Vim version 7.0aa.  Last change: 2006 Jan 22
+*version7.txt*  For Vim version 7.0aa.  Last change: 2006 Jan 25
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -1608,4 +1608,8 @@ value didn't fill the whole screen. (SungHyun Nam)
 Win32 installer: The generated _vimrc contained an absolute path to diff.exe.
 After upgrading it becomes invalid.  Now use $VIMRUNTIME instead.
 
+The command line was cleared to often when 'showmode' was set and ":silent
+normal vy" was used.  Don't clear the command line unless the mode was
+actually displayed.  Added the "mode_displayed" variable.
+
  vim:tw=78:ts=8:ft=help:norl:
index da6137cbbaf4b556c9e90a6c1162e803f93a2795..2da7860835cadc621fe0fc393897e24e8cedf253 100644 (file)
@@ -1699,10 +1699,10 @@ types.vim: $(TAGS_SRC) $(TAGS_INCL)
 #
 test check:
        $(MAKE) -f Makefile $(VIMTARGET)
-       cd testdir; $(MAKE) -f Makefile $(GUI_TESTTARGET) VIMPROG=../$(VIMTARGET) $(GUI_TESTARG)
-       @if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
+       -@if test -n "$(MAKEMO)" -a -f $(PODIR)/Makefile; then \
                cd $(PODIR); $(MAKE) -f Makefile check VIM=../$(VIMTARGET); \
        fi
+       cd testdir; $(MAKE) -f Makefile $(GUI_TESTTARGET) VIMPROG=../$(VIMTARGET) $(GUI_TESTARG)
 
 testclean:
        cd testdir; $(MAKE) -f Makefile clean
index 8dc07fdf97e6b44d8e88fc8239b49f8970492787..e331c4c5a9617b8e865c94a7f42bf64b9587f9b7 100644 (file)
@@ -89,7 +89,7 @@ static compl_T    *compl_shown_match = NULL;
 
 /* When the first completion is done "compl_started" is set.  When it's
  * FALSE the word to be completed must be located. */
-static int                 compl_started = FALSE;
+static int       compl_started = FALSE;
 
 static int       compl_matches = 0;
 static char_u    *compl_pattern = NULL;
@@ -123,6 +123,7 @@ static void ins_compl_delete __ARGS((void));
 static void ins_compl_insert __ARGS((void));
 static int  ins_compl_next __ARGS((int allow_get_expansion, int count));
 static int  ins_compl_key2dir __ARGS((int c));
+static int  ins_compl_pum_key __ARGS((int c));
 static int  ins_compl_key2count __ARGS((int c));
 static int  ins_complete __ARGS((int c));
 static int  quote_meta __ARGS((char_u *dest, char_u *str, int len));
@@ -495,7 +496,7 @@ edit(cmdchar, startln, count)
      * actually changing anything.  It's put after the mode, if any.
      */
     i = 0;
-    if (p_smd)
+    if (p_smd && msg_silent == 0)
        i = showmode();
 
     if (!p_im && did_restart_edit == 0)
@@ -1116,7 +1117,10 @@ doESCkey:
             * cursor. */
            if (bt_quickfix(curbuf) && c == CAR)
            {
-               do_cmdline_cmd((char_u *)".cc");
+               if (curwin->w_llist_ref == NULL)    /* quickfix window */
+                   do_cmdline_cmd((char_u *)".cc");
+               else                                /* location list window */
+                   do_cmdline_cmd((char_u *)".ll");
                break;
            }
 #endif
@@ -1846,8 +1850,7 @@ vim_is_ctrl_x_key(c)
        return TRUE;
 
     /* Accept <PageUp> and <PageDown> if the popup menu is visible. */
-    if (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
-                    || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN))
+    if (ins_compl_pum_key(c))
        return TRUE;
 
     switch (ctrl_x_mode)
@@ -2648,7 +2651,8 @@ ins_compl_prep(c)
         * 'Pattern not found') until another key is hit, then go back to
         * showing what mode we are in. */
        showmode();
-       if ((ctrl_x_mode == 0 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_R)
+       if ((ctrl_x_mode == 0 && c != Ctrl_N && c != Ctrl_P && c != Ctrl_R
+                                                    && !ins_compl_pum_key(c))
                || ctrl_x_mode == CTRL_X_FINISHED)
        {
            /* Get here when we have finished typing a sequence of ^N and
@@ -3451,6 +3455,18 @@ ins_compl_key2dir(c)
     return FORWARD;
 }
 
+/*
+ * Return TRUE for keys that are used for completion only when the popup menu
+ * is visible.
+ */
+    static int
+ins_compl_pum_key(c)
+    int                c;
+{
+    return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
+                    || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN);
+}
+
 /*
  * Decide the number of completions to move forward.
  * Returns 1 for most keys, height of the popup menu for page-up/down keys.
@@ -3461,8 +3477,7 @@ ins_compl_key2count(c)
 {
     int                h;
 
-    if (pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
-           || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN))
+    if (ins_compl_pum_key(c))
     {
        h = pum_get_height();
        if (h > 3)
index a15ed464d856a2a7199cc0c6af7fc8f8d7b580df..8211a7f8f79744df8f24b508980fc618a3e2b125 100644 (file)
@@ -473,26 +473,58 @@ EX(CMD_keepalt,           "keepalt",      ex_wrongmodifier,
                        NEEDARG|EXTRA|NOTRLCOM),
 EX(CMD_list,           "list",         ex_print,
                        RANGE|WHOLEFOLD|COUNT|EXFLAGS|TRLBAR|CMDWIN),
+EX(CMD_lNext,          "lNext",        ex_cnext,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
+EX(CMD_lNfile,         "lNfile",       ex_cnext,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
 EX(CMD_last,           "last",         ex_last,
                        EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR),
 EX(CMD_language,       "language",     ex_language,
                        EXTRA|TRLBAR|CMDWIN),
+EX(CMD_laddexpr,       "laddexpr",     ex_cexpr,
+                       NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG),
+EX(CMD_laddfile,       "laddfile",     ex_cfile,
+                       TRLBAR|FILE1),
+EX(CMD_lbuffer,                "lbuffer",      ex_cbuffer,
+                       RANGE|NOTADR|WORD1|TRLBAR),
 EX(CMD_lcd,            "lcd",          ex_cd,
                        BANG|FILE1|TRLBAR|CMDWIN),
 EX(CMD_lchdir,         "lchdir",       ex_cd,
                        BANG|FILE1|TRLBAR|CMDWIN),
+EX(CMD_lclose,         "lclose",       ex_cclose,
+                       RANGE|NOTADR|COUNT|TRLBAR),
 EX(CMD_left,           "left",         ex_align,
                        TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY),
 EX(CMD_leftabove,      "leftabove",    ex_wrongmodifier,
                        NEEDARG|EXTRA|NOTRLCOM),
 EX(CMD_let,            "let",          ex_let,
                        EXTRA|NOTRLCOM|SBOXOK|CMDWIN),
+EX(CMD_lexpr,          "lexpr",        ex_cexpr,
+                       NEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG),
+EX(CMD_lfile,          "lfile",        ex_cfile,
+                       TRLBAR|FILE1|BANG),
+EX(CMD_lfirst,         "lfirst",       ex_cc,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
+EX(CMD_lgetfile,       "lgetfile",     ex_cfile,
+                       TRLBAR|FILE1|BANG),
+EX(CMD_ll,             "ll",           ex_cc,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
+EX(CMD_llast,          "llast",        ex_cc,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
+EX(CMD_llist,          "llist",        qf_list,
+                       BANG|EXTRA|TRLBAR|CMDWIN),
 EX(CMD_lmap,           "lmap",         ex_map,
                        EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
 EX(CMD_lmapclear,      "lmapclear",    ex_mapclear,
                        EXTRA|TRLBAR|CMDWIN),
 EX(CMD_lnoremap,       "lnoremap",     ex_map,
                        EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_lnext,          "lnext",        ex_cnext,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
+EX(CMD_lnewer,         "lnewer",       qf_age,
+                       RANGE|NOTADR|COUNT|TRLBAR),
+EX(CMD_lnfile,         "lnfile",       ex_cnext,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
 EX(CMD_loadview,       "loadview",     ex_loadview,
                        FILE1|TRLBAR),
 EX(CMD_loadkeymap,     "loadkeymap",   ex_loadkeymap,
@@ -501,8 +533,20 @@ EX(CMD_lockmarks,  "lockmarks",    ex_wrongmodifier,
                        NEEDARG|EXTRA|NOTRLCOM),
 EX(CMD_lockvar,                "lockvar",      ex_lockvar,
                        BANG|EXTRA|NEEDARG|SBOXOK|CMDWIN),
+EX(CMD_lolder,         "lolder",       qf_age,
+                       RANGE|NOTADR|COUNT|TRLBAR),
+EX(CMD_lopen,          "lopen",        ex_copen,
+                       RANGE|NOTADR|COUNT|TRLBAR),
+EX(CMD_lprevious,      "lprevious",    ex_cnext,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
+EX(CMD_lpfile,         "lpfile",       ex_cnext,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
+EX(CMD_lrewind,                "lrewind",      ex_cc,
+                       RANGE|NOTADR|COUNT|TRLBAR|BANG),
 EX(CMD_lunmap,         "lunmap",       ex_unmap,
                        EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN),
+EX(CMD_lwindow,                "lwindow",      ex_cwindow,
+                       RANGE|NOTADR|COUNT|TRLBAR),
 EX(CMD_ls,             "ls",           buflist_list,
                        BANG|TRLBAR|CMDWIN),
 EX(CMD_move,           "move",         ex_copymove,
index 9fd9b668cc40f530cc132e0b4608c495162b5e91..82c42b2b65916013eddc5d7d527dabf55509e064 100644 (file)
@@ -83,6 +83,7 @@ EXTERN int    cmdline_row;
 
 EXTERN int     redraw_cmdline INIT(= FALSE);   /* cmdline must be redrawn */
 EXTERN int     clear_cmdline INIT(= FALSE);    /* cmdline must be cleared */
+EXTERN int     mode_displayed INIT(= FALSE);   /* mode is being displayed */
 #if defined(FEAT_CRYPT) || defined(FEAT_EVAL)
 EXTERN int     cmdline_star INIT(= FALSE);     /* cmdline is crypted */
 #endif
@@ -1366,6 +1367,7 @@ EXTERN char_u e_prev_dir[]        INIT(= N_("E459: Cannot go back to previous directory
 
 #ifdef FEAT_QUICKFIX
 EXTERN char_u e_quickfix[]     INIT(= N_("E42: No Errors"));
+EXTERN char_u e_loclist[]      INIT(= N_("E776: No location list"));
 #endif
 EXTERN char_u e_re_damg[]      INIT(= N_("E43: Damaged match string"));
 EXTERN char_u e_re_corr[]      INIT(= N_("E44: Corrupted regexp program"));
index 56fd12aa2b914ed13ae69400571730751e47d19c..7a44253151c6799c34e6cfbb7eef1826656293f5 100644 (file)
@@ -1104,7 +1104,7 @@ cs_find_common(opt, pat, forceit, verbose)
        cs_file_results(f, nummatches);
        fclose(f);
        /* '-' starts a new error list */
-       if (qf_init(tmp, (char_u *)"%f%*\\t%l%*\\t%m", *qfpos == '-') > 0)
+       if (qf_init(NULL, tmp, (char_u *)"%f%*\\t%l%*\\t%m", *qfpos == '-') > 0)
        {
 # ifdef FEAT_WINDOWS
            if (postponed_split != 0)
@@ -1117,7 +1117,7 @@ cs_find_common(opt, pat, forceit, verbose)
                postponed_split = 0;
            }
 # endif
-           qf_jump(0, 0, forceit);
+           qf_jump(NULL, 0, 0, forceit);
        }
        mch_remove(tmp);
        vim_free(tmp);
index 561d6ae4bb08cce1748894c78dc847cabe8a1fdf..2661c26bbb4081765f1654b545c27be66964abc3 100644 (file)
@@ -636,7 +636,7 @@ main
        if (params.use_ef != NULL)
            set_string_option_direct((char_u *)"ef", -1,
                                                     params.use_ef, OPT_FREE);
-       if (qf_init(p_ef, p_efm, TRUE) < 0)
+       if (qf_init(NULL, p_ef, p_efm, TRUE) < 0)
        {
            out_char('\n');
            mch_exit(3);
@@ -785,7 +785,7 @@ main
      */
     if (params.edit_type == EDIT_QF)
     {
-       qf_jump(0, 0, FALSE);
+       qf_jump(NULL, 0, 0, FALSE);
        TIME_MSG("jump to first error");
     }
 #endif
@@ -2442,7 +2442,7 @@ exe_commands(parmp)
 #ifdef FEAT_QUICKFIX
     /* When started with "-q errorfile" jump to first error again. */
     if (parmp->edit_type == EDIT_QF)
-       qf_jump(0, 0, FALSE);
+       qf_jump(NULL, 0, 0, FALSE);
 #endif
     TIME_MSG("executing command arguments");
 }
index fb873fb4a295b0afe82150e7680277c95f571269..328bdf216b3f6fa4a1af3784b88ddbd2dffee9a7 100644 (file)
@@ -952,6 +952,7 @@ free_all_mem()
 {
     buf_T      *buf, *nextbuf;
     static int entered = FALSE;
+    win_T      *win;
 
     /* When we cause a crash here it is caught and Vim tries to exit cleanly.
      * Don't try freeing everything again. */
@@ -1027,7 +1028,10 @@ free_all_mem()
     init_history();
 
 #ifdef FEAT_QUICKFIX
-    qf_free_all();
+    qf_free_all(NULL);
+    /* Free all location lists */
+    FOR_ALL_WINDOWS(win)
+       qf_free_all(win);
 #endif
 
     /* Close all script inputs. */
index b7f1cf02bf447e4ea2dfdd18dab3af6656090e49..079e472db177772b274ca225d34a25903f258512 100644 (file)
@@ -6743,7 +6743,7 @@ set_bool_option(opt_idx, varp, value, opt_flags)
        {
            need_start_insertmode = FALSE;
            stop_insert_mode = TRUE;
-           if (p_smd && msg_silent == 0 && restart_edit != 0)
+           if (restart_edit != 0 && mode_displayed)
                clear_cmdline = TRUE;   /* remove "(insert)" */
            restart_edit = 0;
        }
index afc68ff841375c4910afbb414e085c47b8629c69..374d85e762bc664a8107909190fe06fbd3cc11f2 100644 (file)
@@ -4852,7 +4852,7 @@ mch_expandpath(gap, path, flags)
 # define SEEK_END 2
 #endif
 
-#define SHELL_SPECIAL (char_u *)"\t \"&';<>\\|"
+#define SHELL_SPECIAL (char_u *)"\t \"&';<>()\\|"
 
 /* ARGSUSED */
     int
@@ -5128,7 +5128,12 @@ mch_expand_wildcards(num_pat, pat, num_file, file, flags)
                }
                else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
                {
-                   /* Remove a backslash, take char literally. */
+                   /* Remove a backslash, take char literally.  But keep
+                    * backslash before special character and inside
+                    * backticks. */
+                   if (intick
+                         || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL)
+                       *p++ = '\\';
                    *p++ = pat[i][++j];
                }
                else if (!intick && vim_strchr(SHELL_SPECIAL,
@@ -5140,12 +5145,8 @@ mch_expand_wildcards(num_pat, pat, num_file, file, flags)
                    *p++ = pat[i][j];
                }
                else
-               {
-                   /* For a backslash also copy the next character, don't
-                    * want to put quotes around it. */
-                   if ((*p++ = pat[i][j]) == '\\' && pat[i][j + 1] != NUL)
-                       *p++ = pat[i][++j];
-               }
+                   /* Simply copy the character. */
+                   *p++ = pat[i][++j];
            }
            *p = NUL;
 #endif
index 6712cf15172785dd00bed03432ab27a623416517..4ea4f01d49dc0b47a6f062d1b19ba23adad51d17 100644 (file)
@@ -1,14 +1,14 @@
 /* quickfix.c */
-int qf_init __ARGS((char_u *efile, char_u *errorformat, int newlist));
-void qf_free_all __ARGS((void));
-void qf_jump __ARGS((int dir, int errornr, int forceit));
+int qf_init __ARGS((win_T *wp, char_u *efile, char_u *errorformat, int newlist));
+void qf_free_all __ARGS((win_T *wp));
+void qf_jump __ARGS((win_T *wp, int dir, int errornr, int forceit));
 void qf_list __ARGS((exarg_T *eap));
 void qf_age __ARGS((exarg_T *eap));
-void qf_mark_adjust __ARGS((linenr_T line1, linenr_T line2, long amount, long amount_after));
+void qf_mark_adjust __ARGS((win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after));
 void ex_cwindow __ARGS((exarg_T *eap));
 void ex_cclose __ARGS((exarg_T *eap));
 void ex_copen __ARGS((exarg_T *eap));
-linenr_T qf_current_entry __ARGS((void));
+linenr_T qf_current_entry __ARGS((win_T *wp));
 int bt_quickfix __ARGS((buf_T *buf));
 int bt_nofile __ARGS((buf_T *buf));
 int bt_dontwrite __ARGS((buf_T *buf));
@@ -26,4 +26,5 @@ int set_errorlist __ARGS((list_T *list, int action));
 void ex_cbuffer __ARGS((exarg_T *eap));
 void ex_cexpr __ARGS((exarg_T *eap));
 void ex_helpgrep __ARGS((exarg_T *eap));
+void copy_loclist __ARGS((win_T *from, win_T *to));
 /* vim: set ft=c : */
index 2cd0bd03b1384edf9ae2ce555f8d55d0f9404454..923c7fda0b5716fd2e758545efe271d7cec26746 100644 (file)
@@ -49,17 +49,30 @@ struct qfline_S
  */
 #define LISTCOUNT   10
 
-static struct qf_list
+typedef struct qf_list_S
 {
     qfline_T   *qf_start;      /* pointer to the first error */
     qfline_T   *qf_ptr;        /* pointer to the current error */
     int                qf_count;       /* number of errors (0 means no error list) */
     int                qf_index;       /* current index in the error list */
     int                qf_nonevalid;   /* TRUE if not a single valid entry found */
-} qf_lists[LISTCOUNT];
+} qf_list_T;
 
-static int     qf_curlist = 0; /* current error list */
-static int     qf_listcount = 0;   /* current number of lists */
+struct qf_info_S
+{
+    /*
+     * Count of references to this list. Used only for location lists.
+     * When a location list window reference this list, qf_refcount
+     * will be 2. Otherwise, qf_refcount will be 1. When qf_refcount
+     * reaches 0, the list is freed.
+     */
+    int                qf_refcount;
+    int                qf_listcount;       /* current number of lists */
+    int                qf_curlist;         /* current error list */
+    qf_list_T  qf_lists[LISTCOUNT];
+};
+
+static qf_info_T ql_info;      /* global quickfix list */
 
 #define FMT_PATTERNS 10                /* maximum number of % recognized */
 
@@ -89,11 +102,11 @@ struct eformat
                                /*   '+' include whole line in message */
 };
 
-static int     qf_init_ext __ARGS((char_u *efile, buf_T *buf, typval_T *tv, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast));
-static void    qf_new_list __ARGS((void));
-static int     qf_add_entry __ARGS((qfline_T **prevp, char_u *dir, char_u *fname, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid));
-static void    qf_msg __ARGS((void));
-static void    qf_free __ARGS((int idx));
+static int     qf_init_ext __ARGS((qf_info_T *qi, char_u *efile, buf_T *buf, typval_T *tv, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast));
+static void    qf_new_list __ARGS((qf_info_T *qi));
+static int     qf_add_entry __ARGS((qf_info_T *qi, qfline_T **prevp, char_u *dir, char_u *fname, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid));
+static void    qf_msg __ARGS((qf_info_T *qi));
+static void    qf_free __ARGS((qf_info_T *qi, int idx));
 static char_u  *qf_types __ARGS((int, int));
 static int     qf_get_fnum __ARGS((char_u *, char_u *));
 static char_u  *qf_push_dir __ARGS((char_u *, struct dir_stack_T **));
@@ -102,30 +115,48 @@ static char_u     *qf_guess_filepath __ARGS((char_u *));
 static void    qf_fmt_text __ARGS((char_u *text, char_u *buf, int bufsize));
 static void    qf_clean_dir_stack __ARGS((struct dir_stack_T **));
 #ifdef FEAT_WINDOWS
-static int     qf_win_pos_update __ARGS((int old_qf_index));
-static buf_T   *qf_find_buf __ARGS((void));
-static void    qf_update_buffer __ARGS((void));
-static void    qf_fill_buffer __ARGS((void));
+static int     qf_win_pos_update __ARGS((qf_info_T *qi, int old_qf_index));
+static win_T   *qf_find_win __ARGS((qf_info_T *qi));
+static buf_T   *qf_find_buf __ARGS((qf_info_T *qi));
+static void    qf_update_buffer __ARGS((qf_info_T *qi));
+static void    qf_fill_buffer __ARGS((qf_info_T *qi));
 #endif
 static char_u  *get_mef_name __ARGS((void));
 static buf_T   *load_dummy_buffer __ARGS((char_u *fname));
 static void    wipe_dummy_buffer __ARGS((buf_T *buf));
 static void    unload_dummy_buffer __ARGS((buf_T *buf));
 
+/* Quickfix window check helper macro */
+#define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL)
+/* Location list window check helper macro */
+#define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
+/*
+ * Return location list for window 'wp'
+ * For location list window, return the referenced location list
+ */
+#define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist)
+
 /*
  * Read the errorfile "efile" into memory, line by line, building the error
  * list.
  * Return -1 for error, number of errors for success.
  */
     int
-qf_init(efile, errorformat, newlist)
+qf_init(wp, efile, errorformat, newlist)
+    win_T          *wp;
     char_u         *efile;
     char_u         *errorformat;
     int                    newlist;            /* TRUE: start a new error list */
 {
+    qf_info_T      *qi = &ql_info;
+
     if (efile == NULL)
        return FAIL;
-    return qf_init_ext(efile, curbuf, NULL, errorformat, newlist,
+
+    if (wp != NULL)
+       qi = GET_LOC_LIST(wp);
+
+    return qf_init_ext(qi, efile, curbuf, NULL, errorformat, newlist,
                                                    (linenr_T)0, (linenr_T)0);
 }
 
@@ -138,7 +169,8 @@ qf_init(efile, errorformat, newlist)
  * Return -1 for error, number of errors for success.
  */
     static int
-qf_init_ext(efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast)
+qf_init_ext(qi, efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast)
+    qf_info_T      *qi;
     char_u         *efile;
     buf_T          *buf;
     typval_T       *tv;
@@ -212,12 +244,12 @@ qf_init_ext(efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast)
        goto qf_init_end;
     }
 
-    if (newlist || qf_curlist == qf_listcount)
+    if (newlist || qi->qf_curlist == qi->qf_listcount)
        /* make place for a new list */
-       qf_new_list();
-    else if (qf_lists[qf_curlist].qf_count > 0)
+       qf_new_list(qi);
+    else if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
        /* Adding to existing list, find last entry. */
-       for (qfprev = qf_lists[qf_curlist].qf_start;
+       for (qfprev = qi->qf_lists[qi->qf_curlist].qf_start;
                            qfprev->qf_next != qfprev; qfprev = qfprev->qf_next)
            ;
 
@@ -703,7 +735,7 @@ restofline:
            }
        }
 
-       if (qf_add_entry(&qfprev,
+       if (qf_add_entry(qi, &qfprev,
                        directory,
                        (*namebuf || directory)
                            ? namebuf
@@ -721,27 +753,31 @@ restofline:
     }
     if (fd == NULL || !ferror(fd))
     {
-       if (qf_lists[qf_curlist].qf_index == 0) /* no valid entry found */
+       if (qi->qf_lists[qi->qf_curlist].qf_index == 0)
        {
-           qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
-           qf_lists[qf_curlist].qf_index = 1;
-           qf_lists[qf_curlist].qf_nonevalid = TRUE;
+           /* no valid entry found */
+           qi->qf_lists[qi->qf_curlist].qf_ptr =
+               qi->qf_lists[qi->qf_curlist].qf_start;
+           qi->qf_lists[qi->qf_curlist].qf_index = 1;
+           qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE;
        }
        else
        {
-           qf_lists[qf_curlist].qf_nonevalid = FALSE;
-           if (qf_lists[qf_curlist].qf_ptr == NULL)
-               qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
+           qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
+           if (qi->qf_lists[qi->qf_curlist].qf_ptr == NULL)
+               qi->qf_lists[qi->qf_curlist].qf_ptr =
+                   qi->qf_lists[qi->qf_curlist].qf_start;
        }
-       retval = qf_lists[qf_curlist].qf_count; /* return number of matches */
+       /* return number of matches */
+       retval = qi->qf_lists[qi->qf_curlist].qf_count;
        goto qf_init_ok;
     }
     EMSG(_(e_readerrf));
 error2:
-    qf_free(qf_curlist);
-    qf_listcount--;
-    if (qf_curlist > 0)
-       --qf_curlist;
+    qf_free(qi, qi->qf_curlist);
+    qi->qf_listcount--;
+    if (qi->qf_curlist > 0)
+       --qi->qf_curlist;
 qf_init_ok:
     if (fd != NULL)
        fclose(fd);
@@ -760,7 +796,7 @@ qf_init_end:
     vim_free(fmtstr);
 
 #ifdef FEAT_WINDOWS
-    qf_update_buffer();
+    qf_update_buffer(qi);
 #endif
 
     return retval;
@@ -770,7 +806,8 @@ qf_init_end:
  * Prepare for adding a new quickfix list.
  */
     static void
-qf_new_list()
+qf_new_list(qi)
+    qf_info_T  *qi;
 {
     int                i;
 
@@ -779,44 +816,78 @@ qf_new_list()
      * the current entry.  This makes it possible to browse in a tree-like
      * way with ":grep'.
      */
-    while (qf_listcount > qf_curlist + 1)
-       qf_free(--qf_listcount);
+    while (qi->qf_listcount > qi->qf_curlist + 1)
+       qf_free(qi, --qi->qf_listcount);
 
     /*
      * When the stack is full, remove to oldest entry
      * Otherwise, add a new entry.
      */
-    if (qf_listcount == LISTCOUNT)
+    if (qi->qf_listcount == LISTCOUNT)
     {
-       qf_free(0);
+       qf_free(qi, 0);
        for (i = 1; i < LISTCOUNT; ++i)
-           qf_lists[i - 1] = qf_lists[i];
-       qf_curlist = LISTCOUNT - 1;
+           qi->qf_lists[i - 1] = qi->qf_lists[i];
+       qi->qf_curlist = LISTCOUNT - 1;
     }
     else
-       qf_curlist = qf_listcount++;
-    qf_lists[qf_curlist].qf_index = 0;
-    qf_lists[qf_curlist].qf_count = 0;
+       qi->qf_curlist = qi->qf_listcount++;
+    qi->qf_lists[qi->qf_curlist].qf_index = 0;
+    qi->qf_lists[qi->qf_curlist].qf_count = 0;
+}
+
+/*
+ * Free a location list
+ */
+    static void
+ll_free_all(pqi)
+    qf_info_T  **pqi;
+{
+    int                i;
+    qf_info_T  *qi;
+
+    qi = *pqi;
+    if (qi == NULL)
+       return;
+    *pqi = NULL;       /* Remove reference to this list */
+
+    qi->qf_refcount--;
+    if (qi->qf_refcount < 1)
+    {
+       /* No references to this location list */
+       for (i = 0; i < qi->qf_listcount; ++i)
+           qf_free(qi, i);
+       vim_free(qi);
+    }
 }
 
-#if defined(EXITFREE) || defined(PROTO)
     void
-qf_free_all()
+qf_free_all(wp)
+    win_T      *wp;
 {
     int                i;
+    qf_info_T  *qi = &ql_info;
 
-    for (i = 0; i < qf_listcount; ++i)
-       qf_free(i);
+    if (wp != NULL)
+    {
+       /* location list */
+       ll_free_all(&wp->w_llist);
+       ll_free_all(&wp->w_llist_ref);
+    }
+    else
+       /* quickfix list */
+       for (i = 0; i < qi->qf_listcount; ++i)
+           qf_free(qi, i);
 }
-#endif
 
 /*
  * Add an entry to the end of the list of errors.
  * Returns OK or FAIL.
  */
     static int
-qf_add_entry(prevp, dir, fname, mesg, lnum, col, vis_col, pattern, nr, type,
+qf_add_entry(qi, prevp, dir, fname, mesg, lnum, col, vis_col, pattern, nr, type,
             valid)
+    qf_info_T  *qi;            /* quickfix list */
     qfline_T   **prevp;        /* pointer to previously added entry or NULL */
     char_u     *dir;           /* optional directory name */
     char_u     *fname;         /* file name or NULL */
@@ -856,9 +927,10 @@ qf_add_entry(prevp, dir, fname, mesg, lnum, col, vis_col, pattern, nr, type,
     qfp->qf_type = type;
     qfp->qf_valid = valid;
 
-    if (qf_lists[qf_curlist].qf_count == 0)    /* first element in the list */
+    if (qi->qf_lists[qi->qf_curlist].qf_count == 0)
+                               /* first element in the list */
     {
-       qf_lists[qf_curlist].qf_start = qfp;
+       qi->qf_lists[qi->qf_curlist].qf_start = qfp;
        qfp->qf_prev = qfp;     /* first element points to itself */
     }
     else
@@ -869,17 +941,153 @@ qf_add_entry(prevp, dir, fname, mesg, lnum, col, vis_col, pattern, nr, type,
     qfp->qf_next = qfp;        /* last element points to itself */
     qfp->qf_cleared = FALSE;
     *prevp = qfp;
-    ++qf_lists[qf_curlist].qf_count;
-    if (qf_lists[qf_curlist].qf_index == 0 && qfp->qf_valid)
-                                           /* first valid entry */
+    ++qi->qf_lists[qi->qf_curlist].qf_count;
+    if (qi->qf_lists[qi->qf_curlist].qf_index == 0 && qfp->qf_valid)
+                               /* first valid entry */
     {
-       qf_lists[qf_curlist].qf_index = qf_lists[qf_curlist].qf_count;
-       qf_lists[qf_curlist].qf_ptr = qfp;
+       qi->qf_lists[qi->qf_curlist].qf_index =
+           qi->qf_lists[qi->qf_curlist].qf_count;
+       qi->qf_lists[qi->qf_curlist].qf_ptr = qfp;
     }
 
     return OK;
 }
 
+/*
+ * Allocate a new location list for window 'wp'
+ */
+    static int
+ll_new_list(wp)
+    win_T   *wp;
+{
+    if ((wp->w_llist = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T))) == NULL)
+       return FAIL;
+
+    vim_memset(wp->w_llist, 0, (size_t)(sizeof(qf_info_T)));
+    wp->w_llist->qf_refcount++;
+
+    return OK;
+}
+
+/*
+ * Return the location list for window 'wp'.
+ * If not present, allocate a location list
+ */
+    static qf_info_T *
+ll_get_or_alloc_list(wp)
+    win_T   *wp;
+{
+    if (IS_LL_WINDOW(wp))
+       /* For a location list window, use the referenced location list */
+       return wp->w_llist_ref;
+
+    /*
+     * For a non-location list window, w_llist_ref should not point to a
+     * location list.
+     */
+    ll_free_all(&wp->w_llist_ref);
+
+    if (wp->w_llist == NULL)
+       if (ll_new_list(wp) == FAIL)    /* new location list */
+           return NULL;
+    return wp->w_llist;
+}
+
+/*
+ * Copy the location list from window "from" to window "to".
+ */
+    void
+copy_loclist(from, to)
+    win_T      *from;
+    win_T      *to;
+{
+    qf_info_T  *qi;
+    int                idx;
+    int                i;
+
+    /*
+     * When copying from a location list window, copy the referenced
+     * location list. For other windows, copy the location list for
+     * that window.
+     */
+    if (IS_LL_WINDOW(from))
+       qi = from->w_llist_ref;
+    else
+       qi = from->w_llist;
+
+    if (qi == NULL)                /* no location list to copy */
+       return;
+
+    if (ll_new_list(to) == FAIL)    /* allocate a new location list */
+       return;
+
+    to->w_llist->qf_listcount = qi->qf_listcount;
+
+    /* Copy the location lists one at a time */
+    for (idx = 0; idx < qi->qf_listcount; idx++)
+    {
+       qf_list_T   *from_qfl;
+       qf_list_T   *to_qfl;
+
+       to->w_llist->qf_curlist = idx;
+
+       from_qfl = &qi->qf_lists[idx];
+       to_qfl = &to->w_llist->qf_lists[idx];
+
+       /* Some of the fields are populated by qf_add_entry() */
+       to_qfl->qf_nonevalid = from_qfl->qf_nonevalid;
+       to_qfl->qf_count = 0;
+       to_qfl->qf_index = 0;
+       to_qfl->qf_start = NULL;
+       to_qfl->qf_ptr = NULL;
+
+       if (from_qfl->qf_count)
+       {
+           qfline_T    *from_qfp;
+           qfline_T    *prevp = NULL;
+
+           /* copy all the location entries in this list */
+           for (i = 0, from_qfp = from_qfl->qf_start; i < from_qfl->qf_count;
+                ++i, from_qfp = from_qfp->qf_next)
+           {
+               if (qf_add_entry(to->w_llist, &prevp,
+                                NULL,
+                                NULL,
+                                from_qfp->qf_text,
+                                from_qfp->qf_lnum,
+                                from_qfp->qf_col,
+                                from_qfp->qf_viscol,
+                                from_qfp->qf_pattern,
+                                from_qfp->qf_nr,
+                                0,
+                                from_qfp->qf_valid) == FAIL)
+               {
+                   qf_free_all(to);
+                   return;
+               }
+               /*
+                * qf_add_entry() will not set the qf_num field, as the
+                * directory and file names are not supplied. So the qf_fnum
+                * field is copied here.
+                */
+               prevp->qf_fnum = from_qfp->qf_fnum; /* file number */
+               prevp->qf_type = from_qfp->qf_type; /* error type */
+               if (from_qfl->qf_ptr == from_qfp)
+                   to_qfl->qf_ptr = prevp;         /* current location */
+           }
+       }
+
+       to_qfl->qf_index = from_qfl->qf_index;  /* current index in the list */
+
+       /* When no valid entries are present in the list, qf_ptr points to
+        * the first item in the list */
+       if (to_qfl->qf_nonevalid == TRUE)
+           to_qfl->qf_ptr = to_qfl->qf_start;
+    }
+
+    to->w_llist->qf_curlist = qi->qf_curlist;  /* current list */
+}
+
 /*
  * get buffer number for file "dir.name"
  */
@@ -1123,11 +1331,14 @@ qf_guess_filepath(filename)
  * else go to entry "errornr"
  */
     void
-qf_jump(dir, errornr, forceit)
+qf_jump(winptr, dir, errornr, forceit)
+    win_T      *winptr;
     int                dir;
     int                errornr;
     int                forceit;
 {
+    qf_info_T          *qi = &ql_info;
+    qf_info_T          *ll_ref;
     qfline_T           *qf_ptr;
     qfline_T           *old_qf_ptr;
     int                        qf_index;
@@ -1154,16 +1365,21 @@ qf_jump(dir, errornr, forceit)
     int                        old_KeyTyped = KeyTyped; /* getting file may reset it */
 #endif
     int                        ok = OK;
+    int                        usable_win;
+
+    if (winptr != NULL)
+       qi = GET_LOC_LIST(winptr);
 
-    if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
+    if (qi->qf_curlist >= qi->qf_listcount
+       || qi->qf_lists[qi->qf_curlist].qf_count == 0)
     {
        EMSG(_(e_quickfix));
        return;
     }
 
-    qf_ptr = qf_lists[qf_curlist].qf_ptr;
+    qf_ptr = qi->qf_lists[qi->qf_curlist].qf_ptr;
     old_qf_ptr = qf_ptr;
-    qf_index = qf_lists[qf_curlist].qf_index;
+    qf_index = qi->qf_lists[qi->qf_curlist].qf_index;
     old_qf_index = qf_index;
     if (dir == FORWARD || dir == FORWARD_FILE)     /* next valid entry */
     {
@@ -1174,7 +1390,7 @@ qf_jump(dir, errornr, forceit)
            old_qf_fnum = qf_ptr->qf_fnum;
            do
            {
-               if (qf_index == qf_lists[qf_curlist].qf_count
+               if (qf_index == qi->qf_lists[qi->qf_curlist].qf_count
                                                   || qf_ptr->qf_next == NULL)
                {
                    qf_ptr = old_qf_ptr;
@@ -1189,7 +1405,8 @@ qf_jump(dir, errornr, forceit)
                }
                ++qf_index;
                qf_ptr = qf_ptr->qf_next;
-           } while ((!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid)
+           } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid
+                     && !qf_ptr->qf_valid)
                  || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
            err = NULL;
        }
@@ -1217,7 +1434,8 @@ qf_jump(dir, errornr, forceit)
                }
                --qf_index;
                qf_ptr = qf_ptr->qf_prev;
-           } while ((!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid)
+           } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid
+                     && !qf_ptr->qf_valid)
                  || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
            err = NULL;
        }
@@ -1229,7 +1447,8 @@ qf_jump(dir, errornr, forceit)
            --qf_index;
            qf_ptr = qf_ptr->qf_prev;
        }
-       while (errornr > qf_index && qf_index < qf_lists[qf_curlist].qf_count
+       while (errornr > qf_index && qf_index <
+                                   qi->qf_lists[qi->qf_curlist].qf_count
                                                   && qf_ptr->qf_next != NULL)
        {
            ++qf_index;
@@ -1238,8 +1457,8 @@ qf_jump(dir, errornr, forceit)
     }
 
 #ifdef FEAT_WINDOWS
-    qf_lists[qf_curlist].qf_index = qf_index;
-    if (qf_win_pos_update(old_qf_index))
+    qi->qf_lists[qi->qf_curlist].qf_index = qf_index;
+    if (qf_win_pos_update(qi, old_qf_index))
        /* No need to print the error message if it's visible in the error
         * window */
        print_message = FALSE;
@@ -1294,12 +1513,23 @@ qf_jump(dir, errornr, forceit)
        if (qf_ptr->qf_fnum == 0)
            goto theend;
 
+       /* Locate a window showing a normal buffer */
+       usable_win = 0;
+       FOR_ALL_WINDOWS(win)
+           if (win->w_buffer->b_p_bt[0] == NUL)
+           {
+               usable_win = 1;
+               break;
+           }
+
        /*
         * If there is only one window, create a new one above the quickfix
         * window.
         */
-       if (firstwin == lastwin)
+       if (firstwin == lastwin || !usable_win)
        {
+           ll_ref = curwin->w_llist_ref;
+
            if (win_split(0, WSP_ABOVE) == FAIL)
                goto failed;            /* not enough room for window */
            opened_window = TRUE;       /* close it when fail */
@@ -1307,9 +1537,60 @@ qf_jump(dir, errornr, forceit)
 # ifdef FEAT_SCROLLBIND
            curwin->w_p_scb = FALSE;
 # endif
+           if (ll_ref != NULL)
+           {
+               /* The new window should use the location list from the
+                * location list window */
+               qf_free_all(curwin);
+               curwin->w_llist = ll_ref;
+               ll_ref->qf_refcount++;
+           }
        }
        else
        {
+           if (curwin->w_llist_ref != NULL)
+           {
+               /* In a location window */
+               ll_ref = curwin->w_llist_ref;
+
+               /* Find the window with the same location list */
+               FOR_ALL_WINDOWS(win)
+                   if (win->w_llist == ll_ref)
+                       break;
+               if (win == NULL)
+               {
+                   /* Find the window showing the selected file */
+                   FOR_ALL_WINDOWS(win)
+                       if (win->w_buffer->b_fnum == qf_ptr->qf_fnum)
+                           break;
+                   if (win == NULL)
+                   {
+                       /* Find a previous usable window */
+                       win = curwin;
+                       do
+                       {
+                           if (win->w_buffer->b_p_bt[0] == NUL)
+                               break;
+                           if (win->w_prev == NULL)
+                               win = lastwin;  /* wrap around the top */
+                           else
+                               win = win->w_prev; /* go to previous window */
+                       } while (win != curwin);
+                   }
+               }
+               win_goto(win);
+
+               /* If the location list for the window is not set, then set it
+                * to the location list from the location window */
+               if (win->w_llist == NULL)
+               {
+                   win->w_llist = ll_ref;
+                   ll_ref->qf_refcount++;
+               }
+           }
+           else
+           {
+
            /*
             * Try to find a window that shows the right buffer.
             * Default to the window just above the quickfix buffer.
@@ -1325,7 +1606,7 @@ qf_jump(dir, errornr, forceit)
                else
                    win = win->w_prev;  /* go to previous window */
 
-               if (bt_quickfix(win->w_buffer))
+               if (IS_QF_WINDOW(win))
                {
                    /* Didn't find it, go to the window before the quickfix
                     * window. */
@@ -1345,6 +1626,7 @@ qf_jump(dir, errornr, forceit)
            }
 
            win_goto(win);
+           }
        }
     }
 #endif
@@ -1445,7 +1727,7 @@ qf_jump(dir, errornr, forceit)
            /* Update the screen before showing the message */
            update_topline_redraw();
            sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index,
-                   qf_lists[qf_curlist].qf_count,
+                   qi->qf_lists[qi->qf_curlist].qf_count,
                    qf_ptr->qf_cleared ? _(" (line deleted)") : "",
                    (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
            /* Add the message, skipping leading whitespace and newlines. */
@@ -1484,8 +1766,8 @@ failed:
        }
     }
 theend:
-    qf_lists[qf_curlist].qf_ptr = qf_ptr;
-    qf_lists[qf_curlist].qf_index = qf_index;
+    qi->qf_lists[qi->qf_curlist].qf_ptr = qf_ptr;
+    qi->qf_lists[qi->qf_curlist].qf_index = qf_index;
 #ifdef FEAT_WINDOWS
     if (p_swb != old_swb && opened_window)
     {
@@ -1501,6 +1783,7 @@ theend:
 
 /*
  * ":clist": list all errors
+ * ":llist": list all locations
  */
     void
 qf_list(eap)
@@ -1516,8 +1799,20 @@ qf_list(eap)
     char_u     *arg = eap->arg;
     int                all = eap->forceit;     /* if not :cl!, only show
                                                   recognised errors */
+    qf_info_T  *qi = &ql_info;
 
-    if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
+    if (eap->cmdidx == CMD_llist)
+    {
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+       {
+           EMSG(_(e_loclist));
+           return;
+       }
+    }
+
+    if (qi->qf_curlist >= qi->qf_listcount
+       || qi->qf_lists[qi->qf_curlist].qf_count == 0)
     {
        EMSG(_(e_quickfix));
        return;
@@ -1527,16 +1822,16 @@ qf_list(eap)
        EMSG(_(e_trailing));
        return;
     }
-    i = qf_lists[qf_curlist].qf_count;
+    i = qi->qf_lists[qi->qf_curlist].qf_count;
     if (idx1 < 0)
        idx1 = (-idx1 > i) ? 0 : idx1 + i + 1;
     if (idx2 < 0)
        idx2 = (-idx2 > i) ? 0 : idx2 + i + 1;
 
-    if (qf_lists[qf_curlist].qf_nonevalid)
+    if (qi->qf_lists[qi->qf_curlist].qf_nonevalid)
        all = TRUE;
-    qfp = qf_lists[qf_curlist].qf_start;
-    for (i = 1; !got_int && i <= qf_lists[qf_curlist].qf_count; )
+    qfp = qi->qf_lists[qi->qf_curlist].qf_start;
+    for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; )
     {
        if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2)
        {
@@ -1561,7 +1856,7 @@ qf_list(eap)
            else
                vim_snprintf((char *)IObuff, IOSIZE, "%2d %s",
                                                            i, (char *)fname);
-           msg_outtrans_attr(IObuff, i == qf_lists[qf_curlist].qf_index
+           msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index
                                           ? hl_attr(HLF_L) : hl_attr(HLF_D));
            if (qfp->qf_lnum == 0)
                IObuff[0] = NUL;
@@ -1629,48 +1924,64 @@ qf_fmt_text(text, buf, bufsize)
 /*
  * ":colder [count]": Up in the quickfix stack.
  * ":cnewer [count]": Down in the quickfix stack.
+ * ":lolder [count]": Up in the location list stack.
+ * ":lnewer [count]": Down in the location list stack.
  */
     void
 qf_age(eap)
     exarg_T    *eap;
 {
+    qf_info_T  *qi = &ql_info;
     int                count;
 
+    if (eap->cmdidx == CMD_lolder || eap->cmdidx == CMD_lnewer)
+    {
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+       {
+           EMSG(_(e_loclist));
+           return;
+       }
+    }
+
     if (eap->addr_count != 0)
        count = eap->line2;
     else
        count = 1;
     while (count--)
     {
-       if (eap->cmdidx == CMD_colder)
+       if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder)
        {
-           if (qf_curlist == 0)
+           if (qi->qf_curlist == 0)
            {
                EMSG(_("E380: At bottom of quickfix stack"));
                return;
            }
-           --qf_curlist;
+           --qi->qf_curlist;
        }
        else
        {
-           if (qf_curlist >= qf_listcount - 1)
+           if (qi->qf_curlist >= qi->qf_listcount - 1)
            {
                EMSG(_("E381: At top of quickfix stack"));
                return;
            }
-           ++qf_curlist;
+           ++qi->qf_curlist;
        }
     }
-    qf_msg();
+    qf_msg(qi);
+
 }
 
     static void
-qf_msg()
+qf_msg(qi)
+    qf_info_T  *qi;
 {
     smsg((char_u *)_("error list %d of %d; %d errors"),
-           qf_curlist + 1, qf_listcount, qf_lists[qf_curlist].qf_count);
+           qi->qf_curlist + 1, qi->qf_listcount,
+           qi->qf_lists[qi->qf_curlist].qf_count);
 #ifdef FEAT_WINDOWS
-    qf_update_buffer();
+    qf_update_buffer(qi);
 #endif
 }
 
@@ -1678,19 +1989,20 @@ qf_msg()
  * Free error list "idx".
  */
     static void
-qf_free(idx)
+qf_free(qi, idx)
+    qf_info_T  *qi;
     int                idx;
 {
     qfline_T   *qfp;
 
-    while (qf_lists[idx].qf_count)
+    while (qi->qf_lists[idx].qf_count)
     {
-       qfp = qf_lists[idx].qf_start->qf_next;
-       vim_free(qf_lists[idx].qf_start->qf_text);
-       vim_free(qf_lists[idx].qf_start->qf_pattern);
-       vim_free(qf_lists[idx].qf_start);
-       qf_lists[idx].qf_start = qfp;
-       --qf_lists[idx].qf_count;
+       qfp = qi->qf_lists[idx].qf_start->qf_next;
+       vim_free(qi->qf_lists[idx].qf_start->qf_text);
+       vim_free(qi->qf_lists[idx].qf_start->qf_pattern);
+       vim_free(qi->qf_lists[idx].qf_start);
+       qi->qf_lists[idx].qf_start = qfp;
+       --qi->qf_lists[idx].qf_count;
     }
 }
 
@@ -1698,7 +2010,8 @@ qf_free(idx)
  * qf_mark_adjust: adjust marks
  */
    void
-qf_mark_adjust(line1, line2, amount, amount_after)
+qf_mark_adjust(wp, line1, line2, amount, amount_after)
+    win_T      *wp;
     linenr_T   line1;
     linenr_T   line2;
     long       amount;
@@ -1707,11 +2020,19 @@ qf_mark_adjust(line1, line2, amount, amount_after)
     int                i;
     qfline_T   *qfp;
     int                idx;
+    qf_info_T  *qi = &ql_info;
 
-    for (idx = 0; idx < qf_listcount; ++idx)
-       if (qf_lists[idx].qf_count)
-           for (i = 0, qfp = qf_lists[idx].qf_start;
-                      i < qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next)
+    if (wp != NULL)
+    {
+       if (wp->w_llist == NULL)
+           return;
+       qi = wp->w_llist;
+    }
+
+    for (idx = 0; idx < qi->qf_listcount; ++idx)
+       if (qi->qf_lists[idx].qf_count)
+           for (i = 0, qfp = qi->qf_lists[idx].qf_start;
+                      i < qi->qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next)
                if (qfp->qf_fnum == curbuf->b_fnum)
                {
                    if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
@@ -1776,26 +2097,33 @@ qf_types(c, nr)
 /*
  * ":cwindow": open the quickfix window if we have errors to display,
  *            close it if not.
+ * ":lwindow": open the location list window if we have locations to display,
+ *            close it if not.
  */
     void
 ex_cwindow(eap)
     exarg_T    *eap;
 {
+    qf_info_T  *qi = &ql_info;
     win_T      *win;
 
-    /*
-     * Look for an existing quickfix window.
-     */
-    for (win = firstwin; win != NULL; win = win->w_next)
-       if (bt_quickfix(win->w_buffer))
-           break;
+    if (eap->cmdidx == CMD_lwindow)
+    {
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+           return;
+    }
+
+    /* Look for an existing quickfix window.  */
+    win = qf_find_win(qi);
 
     /*
      * If a quickfix window is open but we have no errors to display,
      * close the window.  If a quickfix window is not open, then open
      * it if we have errors; otherwise, leave it closed.
      */
-    if (qf_lists[qf_curlist].qf_nonevalid || qf_curlist >= qf_listcount)
+    if (qi->qf_lists[qi->qf_curlist].qf_nonevalid
+       || qi->qf_curlist >= qi->qf_listcount)
     {
        if (win != NULL)
            ex_cclose(eap);
@@ -1806,36 +2134,51 @@ ex_cwindow(eap)
 
 /*
  * ":cclose": close the window showing the list of errors.
+ * ":lclose": close the window showing the location list
  */
 /*ARGSUSED*/
     void
 ex_cclose(eap)
     exarg_T    *eap;
 {
-    win_T      *win;
+    win_T      *win = NULL;
+    qf_info_T  *qi = &ql_info;
 
-    /*
-     * Find existing quickfix window and close it.
-     */
-    for (win = firstwin; win != NULL; win = win->w_next)
-       if (bt_quickfix(win->w_buffer))
-           break;
+    if (eap->cmdidx == CMD_lclose || eap->cmdidx == CMD_lwindow)
+    {
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+           return;
+    }
 
+    /* Find existing quickfix window and close it. */
+    win = qf_find_win(qi);
     if (win != NULL)
        win_close(win, FALSE);
 }
 
 /*
  * ":copen": open a window that shows the list of errors.
+ * ":lopen": open a window that shows the location list.
  */
     void
 ex_copen(eap)
     exarg_T    *eap;
 {
+    qf_info_T  *qi = &ql_info;
     int                height;
-    buf_T      *buf;
     win_T      *win;
 
+    if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow)
+    {
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+       {
+           EMSG(_(e_loclist));
+           return;
+       }
+    }
+
     if (eap->addr_count != 0)
        height = eap->line2;
     else
@@ -1851,9 +2194,8 @@ ex_copen(eap)
     /*
      * Find existing quickfix window, or open a new one.
      */
-    for (win = firstwin; win != NULL; win = win->w_next)
-       if (bt_quickfix(win->w_buffer))
-           break;
+    win = qf_find_win(qi);
+
     if (win != NULL)
        win_goto(win);
     else
@@ -1861,30 +2203,35 @@ ex_copen(eap)
        /* The current window becomes the previous window afterwards. */
        win = curwin;
 
-       /* Create the new window at the very bottom. */
-       win_goto(lastwin);
+       if (eap->cmdidx == CMD_copen || eap->cmdidx == CMD_cwindow)
+           /* Create the new window at the very bottom. */
+           win_goto(lastwin);
        if (win_split(height, WSP_BELOW) == FAIL)
            return;             /* not enough room for window */
 #ifdef FEAT_SCROLLBIND
        curwin->w_p_scb = FALSE;
 #endif
 
-       /*
-        * Find existing quickfix buffer, or create a new one.
-        */
-       buf = qf_find_buf();
-       if (buf == NULL)
+       /* Remove the location list for the quickfix window */
+       qf_free_all(curwin);
+
+       if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow)
        {
-           (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE);
-           /* switch off 'swapfile' */
-           set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
-           set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
-                                                                  OPT_LOCAL);
-           set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL);
-           set_option_value((char_u *)"diff", 0L, (char_u *)"", OPT_LOCAL);
+           /*
+            * For the location list window, create a reference to the
+            * location list from the window 'win'.
+            */
+           curwin->w_llist_ref = win->w_llist;
+           win->w_llist->qf_refcount++;
        }
-       else if (buf != curbuf)
-           set_curbuf(buf, DOBUF_GOTO);
+
+       (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE);
+       /* switch off 'swapfile' */
+       set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
+       set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
+                        OPT_LOCAL);
+       set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL);
+       set_option_value((char_u *)"diff", 0L, (char_u *)"", OPT_LOCAL);
 
 #ifdef FEAT_VERTSPLIT
        /* Only set the height when there is no window to the side. */
@@ -1899,9 +2246,9 @@ ex_copen(eap)
     /*
      * Fill the buffer with the quickfix list.
      */
-    qf_fill_buffer();
+    qf_fill_buffer(qi);
 
-    curwin->w_cursor.lnum = qf_lists[qf_curlist].qf_index;
+    curwin->w_cursor.lnum = qi->qf_lists[qi->qf_curlist].qf_index;
     curwin->w_cursor.col = 0;
     check_cursor();
     update_topline();          /* scroll to show the line */
@@ -1912,9 +2259,16 @@ ex_copen(eap)
  * window).
  */
      linenr_T
-qf_current_entry()
+qf_current_entry(wp)
+    win_T      *wp;
 {
-    return qf_lists[qf_curlist].qf_index;
+    qf_info_T  *qi = &ql_info;
+
+    if (IS_LL_WINDOW(wp))
+       /* In the location list window, use the referenced location list */
+       qi = wp->w_llist_ref;
+
+    return qi->qf_lists[qi->qf_curlist].qf_index;
 }
 
 /*
@@ -1922,19 +2276,18 @@ qf_current_entry()
  * Return TRUE if there is a quickfix window.
  */
     static int
-qf_win_pos_update(old_qf_index)
+qf_win_pos_update(qi, old_qf_index)
+    qf_info_T  *qi;
     int                old_qf_index;   /* previous qf_index or zero */
 {
     win_T      *win;
-    int                qf_index = qf_lists[qf_curlist].qf_index;
+    int                qf_index = qi->qf_lists[qi->qf_curlist].qf_index;
 
     /*
      * Put the cursor on the current error in the quickfix window, so that
      * it's viewable.
      */
-    for (win = firstwin; win != NULL; win = win->w_next)
-       if (bt_quickfix(win->w_buffer))
-           break;
+    win = qf_find_win(qi);
     if (win != NULL
            && qf_index <= win->w_buffer->b_ml.ml_line_count
            && old_qf_index != qf_index)
@@ -1964,25 +2317,50 @@ qf_win_pos_update(old_qf_index)
     return win != NULL;
 }
 
+/*
+ * Find a window displaying the quickfix/location list 'qi'
+ */
+    static win_T *
+qf_find_win(qi)
+    qf_info_T  *qi;
+{
+    win_T      *win;
+
+    /*
+     * When searching for the quickfix buffer, find a window
+     * with w_llist_ref set to NULL.
+     * When searching for the location list buffer, find a window
+     * with w_llist_ref pointing to the supplied location list.
+     */
+    FOR_ALL_WINDOWS(win)
+       if (bt_quickfix(win->w_buffer))
+           if ((qi == &ql_info && win->w_llist_ref == NULL)
+               || (qi != &ql_info && win->w_llist_ref == qi))
+               break;
+
+    return win;
+}
+
 /*
  * Find quickfix buffer.
  */
     static buf_T *
-qf_find_buf()
+qf_find_buf(qi)
+    qf_info_T  *qi;
 {
-    buf_T      *buf;
+    win_T      *win;
 
-    for (buf = firstbuf; buf != NULL; buf = buf->b_next)
-       if (bt_quickfix(buf))
-           break;
-    return buf;
+    win = qf_find_win(qi);
+
+    return (win != NULL) ? win->w_buffer: NULL;
 }
 
 /*
  * Find the quickfix buffer.  If it exists, update the contents.
  */
     static void
-qf_update_buffer()
+qf_update_buffer(qi)
+    qf_info_T  *qi;
 {
     buf_T      *buf;
 #ifdef FEAT_AUTOCMD
@@ -1992,7 +2370,7 @@ qf_update_buffer()
 #endif
 
     /* Check if a buffer for the quickfix list exists.  Update it. */
-    buf = qf_find_buf();
+    buf = qf_find_buf(qi);
     if (buf != NULL)
     {
 #ifdef FEAT_AUTOCMD
@@ -2003,7 +2381,7 @@ qf_update_buffer()
        curbuf = buf;
 #endif
 
-       qf_fill_buffer();
+       qf_fill_buffer(qi);
 
 #ifdef FEAT_AUTOCMD
        /* restore curwin/curbuf and a few other things */
@@ -2012,7 +2390,7 @@ qf_update_buffer()
        curbuf = save_curbuf;
 #endif
 
-       (void)qf_win_pos_update(0);
+       (void)qf_win_pos_update(qi, 0);
     }
 }
 
@@ -2021,7 +2399,8 @@ qf_update_buffer()
  * curbuf must be the quickfix buffer!
  */
     static void
-qf_fill_buffer()
+qf_fill_buffer(qi)
+    qf_info_T  *qi;
 {
     linenr_T   lnum;
     qfline_T   *qfp;
@@ -2034,11 +2413,11 @@ qf_fill_buffer()
        (void)ml_delete((linenr_T)1, FALSE);
 
     /* Check if there is anything to display */
-    if (qf_curlist < qf_listcount)
+    if (qi->qf_curlist < qi->qf_listcount)
     {
        /* Add one line for each error */
-       qfp = qf_lists[qf_curlist].qf_start;
-       for (lnum = 0; lnum < qf_lists[qf_curlist].qf_count; ++lnum)
+       qfp = qi->qf_lists[qi->qf_curlist].qf_start;
+       for (lnum = 0; lnum < qi->qf_lists[qi->qf_curlist].qf_count; ++lnum)
        {
            if (qfp->qf_fnum != 0
                    && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
@@ -2268,10 +2647,10 @@ ex_make(eap)
     (void)char_avail();
 #endif
 
-    if (qf_init(fname, eap->cmdidx != CMD_make ? p_gefm : p_efm,
+    if (qf_init(NULL, fname, eap->cmdidx != CMD_make ? p_gefm : p_efm,
                                               eap->cmdidx != CMD_grepadd) > 0
            && !eap->forceit)
-       qf_jump(0, 0, FALSE);           /* display first error */
+       qf_jump(NULL, 0, 0, FALSE);             /* display first error */
 
     mch_remove(fname);
     vim_free(fname);
@@ -2343,17 +2722,34 @@ get_mef_name()
 
 /*
  * ":cc", ":crewind", ":cfirst" and ":clast".
+ * ":ll", ":lrewind", ":lfirst" and ":llast".
  */
     void
 ex_cc(eap)
     exarg_T    *eap;
 {
-    qf_jump(0,
+    win_T      *wp = NULL;
+    qf_info_T  *qi;
+
+    if (eap->cmdidx == CMD_ll || eap->cmdidx == CMD_lrewind
+       || eap->cmdidx == CMD_lfirst || eap->cmdidx == CMD_llast)
+    {
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+       {
+           EMSG(_(e_loclist));
+           return;
+       }
+       wp = curwin;
+    }
+
+    qf_jump(wp, 0,
            eap->addr_count > 0
            ? (int)eap->line2
-           : eap->cmdidx == CMD_cc
+           : (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll)
                ? 0
-               : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_cfirst)
+               : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind
+                  || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst)
                    ? 1
                    : 32767,
            eap->forceit);
@@ -2361,16 +2757,34 @@ ex_cc(eap)
 
 /*
  * ":cnext", ":cnfile", ":cNext" and ":cprevious".
+ * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
  */
     void
 ex_cnext(eap)
     exarg_T    *eap;
 {
-    qf_jump(eap->cmdidx == CMD_cnext
+    win_T      *wp = NULL;
+    qf_info_T  *qi;
+
+    if (eap->cmdidx == CMD_lnext || eap->cmdidx == CMD_lNext
+       || eap->cmdidx == CMD_lprevious || eap->cmdidx == CMD_lnfile
+       || eap->cmdidx == CMD_lNfile || eap->cmdidx == CMD_lpfile)
+    {
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+       {
+           EMSG(_(e_loclist));
+           return;
+       }
+       wp = curwin;
+    }
+
+    qf_jump(wp, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext)
            ? FORWARD
-           : eap->cmdidx == CMD_cnfile
+           : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile)
                ? FORWARD_FILE
-               : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_cNfile)
+               : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile
+                  || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile)
                    ? BACKWARD_FILE
                    : BACKWARD,
            eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit);
@@ -2378,11 +2792,24 @@ ex_cnext(eap)
 
 /*
  * ":cfile"/":cgetfile"/":caddfile" commands.
+ * ":lfile"/":lgetfile"/":laddfile" commands.
  */
     void
 ex_cfile(eap)
     exarg_T    *eap;
 {
+    win_T      *wp = NULL;
+    qf_info_T  *qi;
+
+    if (eap->cmdidx == CMD_lfile || eap->cmdidx == CMD_lgetfile
+       || eap->cmdidx == CMD_laddfile)
+    {
+       qi = ll_get_or_alloc_list(curwin);
+       if (qi == NULL)
+           return;
+       wp = curwin;
+    }
+
     if (*eap->arg != NUL)
        set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE);
 
@@ -2396,9 +2823,11 @@ ex_cfile(eap)
      * :caddfile adds to an existing quickfix list. If there is no
      * quickfix list then a new list is created.
      */
-    if (qf_init(p_ef, p_efm, eap->cmdidx != CMD_caddfile) > 0
-                                                 && eap->cmdidx == CMD_cfile)
-       qf_jump(0, 0, eap->forceit);            /* display first error */
+    if (qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile
+                                 && eap->cmdidx != CMD_laddfile)) > 0
+                                 && (eap->cmdidx == CMD_cfile
+                                            || eap->cmdidx == CMD_lfile))
+       qf_jump(wp, 0, 0, eap->forceit);        /* display first error */
 }
 
 /*
@@ -2430,6 +2859,7 @@ ex_vimgrep(eap)
     char_u     *au_name =  NULL;
     int                flags = 0;
     colnr_T    col;
+    qf_info_T  *qi = &ql_info;
 
     switch (eap->cmdidx)
     {
@@ -2468,12 +2898,12 @@ ex_vimgrep(eap)
     }
 
     if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_vimgrepadd)
-                                               || qf_curlist == qf_listcount)
+                                       || qi->qf_curlist == qi->qf_listcount)
        /* make place for a new list */
-       qf_new_list();
-    else if (qf_lists[qf_curlist].qf_count > 0)
+       qf_new_list(qi);
+    else if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
        /* Adding to existing list, find last entry. */
-       for (prevp = qf_lists[qf_curlist].qf_start;
+       for (prevp = qi->qf_lists[qi->qf_curlist].qf_start;
                            prevp->qf_next != prevp; prevp = prevp->qf_next)
            ;
 
@@ -2550,7 +2980,7 @@ ex_vimgrep(eap)
                while (vim_regexec_multi(&regmatch, curwin, buf, lnum,
                                                                     col) > 0)
                {
-                   if (qf_add_entry(&prevp,
+                   if (qf_add_entry(qi, &prevp,
                                NULL,       /* dir */
                                fnames[fi],
                                ml_get_buf(buf,
@@ -2630,19 +3060,19 @@ ex_vimgrep(eap)
 
     FreeWild(fcount, fnames);
 
-    qf_lists[qf_curlist].qf_nonevalid = FALSE;
-    qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
-    qf_lists[qf_curlist].qf_index = 1;
+    qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
+    qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start;
+    qi->qf_lists[qi->qf_curlist].qf_index = 1;
 
 #ifdef FEAT_WINDOWS
-    qf_update_buffer();
+    qf_update_buffer(qi);
 #endif
 
     /* Jump to first match. */
-    if (qf_lists[qf_curlist].qf_count > 0)
+    if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
     {
        if ((flags & VGR_NOJUMP) == 0)
-           qf_jump(0, 0, eap->forceit);
+           qf_jump(NULL, 0, 0, eap->forceit);
     }
     else
        EMSG2(_(e_nomatch2), s);
@@ -2821,16 +3251,18 @@ unload_dummy_buffer(buf)
 get_errorlist(list)
     list_T     *list;
 {
+    qf_info_T  *qi = &ql_info;
     dict_T     *dict;
     char_u     buf[2];
     qfline_T   *qfp;
     int                i;
 
-    if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0)
+    if (qi->qf_curlist >= qi->qf_listcount
+       || qi->qf_lists[qi->qf_curlist].qf_count == 0)
        return FAIL;
 
-    qfp = qf_lists[qf_curlist].qf_start;
-    for (i = 1; !got_int && i <= qf_lists[qf_curlist].qf_count; ++i)
+    qfp = qi->qf_lists[qi->qf_curlist].qf_start;
+    for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ++i)
     {
        if ((dict = dict_alloc()) == NULL)
            return FAIL;
@@ -2873,17 +3305,18 @@ set_errorlist(list, action)
     qfline_T   *prevp = NULL;
     int                valid, status;
     int                retval = OK;
+    qf_info_T  *qi = &ql_info;
 
-    if (action == ' ' || qf_curlist == qf_listcount)
+    if (action == ' ' || qi->qf_curlist == qi->qf_listcount)
        /* make place for a new list */
-       qf_new_list();
-    else if (action == 'a' && qf_lists[qf_curlist].qf_count > 0)
+       qf_new_list(qi);
+    else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0)
        /* Adding to existing list, find last entry. */
-       for (prevp = qf_lists[qf_curlist].qf_start;
+       for (prevp = qi->qf_lists[qi->qf_curlist].qf_start;
             prevp->qf_next != prevp; prevp = prevp->qf_next)
            ;
     else if (action == 'r')
-       qf_free(qf_curlist);
+       qf_free(qi, qi->qf_curlist);
 
     for (li = list->lv_first; li != NULL; li = li->li_next)
     {
@@ -2909,7 +3342,7 @@ set_errorlist(list, action)
        if (filename == NULL || (lnum == 0 && pattern == NULL))
            valid = FALSE;
 
-       status =  qf_add_entry(&prevp,
+       status =  qf_add_entry(qi, &prevp,
                               NULL,        /* dir */
                               filename,
                               text,
@@ -2933,12 +3366,12 @@ set_errorlist(list, action)
        }
     }
 
-    qf_lists[qf_curlist].qf_nonevalid = FALSE;
-    qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
-    qf_lists[qf_curlist].qf_index = 1;
+    qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
+    qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start;
+    qi->qf_lists[qi->qf_curlist].qf_index = 1;
 
 #ifdef FEAT_WINDOWS
-    qf_update_buffer();
+    qf_update_buffer(qi);
 #endif
 
     return retval;
@@ -2947,12 +3380,21 @@ set_errorlist(list, action)
 
 /*
  * ":[range]cbuffer [bufnr]" command.
+ * ":[range]lbuffer [bufnr]" command.
  */
     void
 ex_cbuffer(eap)
     exarg_T   *eap;
 {
     buf_T      *buf = NULL;
+    qf_info_T  *qi = &ql_info;
+
+    if (eap->cmdidx == CMD_lbuffer)
+    {
+       qi = ll_get_or_alloc_list(curwin);
+       if (qi == NULL)
+           return;
+    }
 
     if (*eap->arg == NUL)
        buf = curbuf;
@@ -2973,19 +3415,30 @@ ex_cbuffer(eap)
                || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count)
            EMSG(_(e_invrange));
        else
-           qf_init_ext(NULL, buf, NULL, p_efm, TRUE, eap->line1, eap->line2);
+           qf_init_ext(qi, NULL, buf, NULL, p_efm, TRUE, eap->line1, eap->line2);
     }
 }
 
 #if defined(FEAT_EVAL) || defined(PROTO)
 /*
  * ":cexpr {expr}" and ":caddexpr {expr}" command.
+ * ":lexpr {expr}" and ":laddexpr {expr}" command.
  */
     void
 ex_cexpr(eap)
     exarg_T    *eap;
 {
     typval_T   *tv;
+    qf_info_T  *qi = &ql_info;
+    win_T      *wp = NULL;
+
+    if (eap->cmdidx == CMD_lexpr || eap->cmdidx == CMD_laddexpr)
+    {
+       qi = ll_get_or_alloc_list(curwin);
+       if (qi == NULL)
+           return;
+       wp = curwin;
+    }
 
     /* Evaluate the expression.  When the result is a string or a list we can
      * use it to fill the errorlist. */
@@ -2995,10 +3448,12 @@ ex_cexpr(eap)
        if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
                || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL))
        {
-           if (qf_init_ext(NULL, NULL, tv, p_efm, eap->cmdidx == CMD_cexpr,
+           if (qf_init_ext(qi, NULL, NULL, tv, p_efm,
+                           (eap->cmdidx == CMD_cexpr
+                            || eap->cmdidx == CMD_lexpr),
                                                 (linenr_T)0, (linenr_T)0) > 0
-                   && eap->cmdidx == CMD_cexpr)
-               qf_jump(0, 0, eap->forceit);    /* display first error */
+                   && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr))
+               qf_jump(wp, 0, 0, eap->forceit);  /* display first error */
        }
        else
            EMSG(_("E777: String or List expected"));
@@ -3026,6 +3481,7 @@ ex_helpgrep(eap)
 #ifdef FEAT_MULTI_LANG
     char_u     *lang;
 #endif
+    qf_info_T  *qi = &ql_info;
 
     /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
     save_cpo = p_cpo;
@@ -3041,7 +3497,7 @@ ex_helpgrep(eap)
     if (regmatch.regprog != NULL)
     {
        /* create a new quickfix list */
-       qf_new_list();
+       qf_new_list(qi);
 
        /* Go through all directories in 'runtimepath' */
        p = p_rtp;
@@ -3082,7 +3538,7 @@ ex_helpgrep(eap)
                                while (l > 0 && IObuff[l - 1] <= ' ')
                                     IObuff[--l] = NUL;
 
-                               if (qf_add_entry(&prevp,
+                               if (qf_add_entry(qi, &prevp,
                                            NULL,       /* dir */
                                            fnames[fi],
                                            IObuff,
@@ -3111,20 +3567,21 @@ ex_helpgrep(eap)
        }
        vim_free(regmatch.regprog);
 
-       qf_lists[qf_curlist].qf_nonevalid = FALSE;
-       qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
-       qf_lists[qf_curlist].qf_index = 1;
+       qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE;
+       qi->qf_lists[qi->qf_curlist].qf_ptr =
+           qi->qf_lists[qi->qf_curlist].qf_start;
+       qi->qf_lists[qi->qf_curlist].qf_index = 1;
     }
 
     p_cpo = save_cpo;
 
 #ifdef FEAT_WINDOWS
-    qf_update_buffer();
+    qf_update_buffer(qi);
 #endif
 
     /* Jump to first match. */
-    if (qf_lists[qf_curlist].qf_count > 0)
-       qf_jump(0, 0, FALSE);
+    if (qi->qf_lists[qi->qf_curlist].qf_count > 0)
+       qf_jump(NULL, 0, 0, FALSE);
     else
        EMSG2(_(e_nomatch2), eap->arg);
 }
index 4657566f74d51073a45303eebf56e858a5bea3af..e2f10db82f52f85eda34e11d67f40459ea7242b4 100644 (file)
@@ -2806,7 +2806,7 @@ win_line(wp, lnum, startrow, endrow, nochange)
 # endif
 # if defined(FEAT_QUICKFIX) && defined(FEAT_WINDOWS)
     /* Highlight the current line in the quickfix window. */
-    if (bt_quickfix(wp->w_buffer) && qf_current_entry() == lnum)
+    if (bt_quickfix(wp->w_buffer) && qf_current_entry(wp) == lnum)
        line_attr = hl_attr(HLF_L);
 # endif
     if (line_attr != 0)
@@ -6651,6 +6651,8 @@ screen_fill(start_row, end_row, start_col, end_col, c1, c2, attr)
            redraw_cmdline = TRUE;
            if (c1 == ' ' && c2 == ' ')
                clear_cmdline = FALSE;  /* command line has been cleared */
+           if (start_col == 0)
+               mode_displayed = FALSE; /* mode cleared or overwritten */
        }
     }
 }
@@ -7027,6 +7029,7 @@ screenclear2()
     {
        out_str(T_CL);          /* clear the display */
        clear_cmdline = FALSE;
+       mode_displayed = FALSE;
     }
     else
     {
@@ -8326,6 +8329,7 @@ showmode()
 #endif
                MSG_PUTS_ATTR(" --", attr);
            }
+
            need_clear = TRUE;
        }
        if (Recording
@@ -8337,6 +8341,8 @@ showmode()
            MSG_PUTS_ATTR(_("recording"), attr);
            need_clear = TRUE;
        }
+
+       mode_displayed = TRUE;
        if (need_clear || clear_cmdline)
            msg_clr_eos();
        msg_didout = FALSE;             /* overwrite this message */
@@ -8383,6 +8389,7 @@ msg_pos_mode()
 /*
  * Delete mode message.  Used when ESC is typed which is expected to end
  * Insert mode (but Insert mode didn't end yet!).
+ * Caller should check "mode_displayed".
  */
     void
 unshowmode(force)
index b71f592b0bc874e12da652abf2ae16ee7c1d8f25..e8d5b72ed70b664afa8e71a10d295214a1bf828d 100644 (file)
@@ -1085,6 +1085,9 @@ struct dictvar_S
 # define B_SPELL(buf)  (0)
 #endif
 
+#ifdef FEAT_QUICKFIX
+typedef struct qf_info_S qf_info_T;
+#endif
 
 /*
  * buffer: structure that holds information about one file
@@ -1835,6 +1838,15 @@ struct window
     int                w_nrwidth_width;        /* nr of chars to print line count. */
 #endif
 
+#ifdef FEAT_QUICKFIX
+    qf_info_T  *w_llist;               /* Location list for this window */
+    /*
+     * Location list reference used in the location list window.
+     * In a non-location list window, w_llist_ref is NULL.
+     */
+    qf_info_T  *w_llist_ref;
+#endif
+
 
 #ifdef FEAT_MZSCHEME
     void       *w_mzscheme_ref;        /* The MzScheme value for this window */
index 3d42437adf41f7c56d611c48a83737a5d4629197..569cb6e804066d30269b33e84511f38556f15e44 100644 (file)
@@ -36,5 +36,5 @@
 #define VIM_VERSION_NODOT      "vim70aa"
 #define VIM_VERSION_SHORT      "7.0aa"
 #define VIM_VERSION_MEDIUM     "7.0aa ALPHA"
-#define VIM_VERSION_LONG       "VIM - Vi IMproved 7.0aa ALPHA (2006 Jan 23)"
-#define VIM_VERSION_LONG_DATE  "VIM - Vi IMproved 7.0aa ALPHA (2006 Jan 23, compiled "
+#define VIM_VERSION_LONG       "VIM - Vi IMproved 7.0aa ALPHA (2006 Jan 25)"
+#define VIM_VERSION_LONG_DATE  "VIM - Vi IMproved 7.0aa ALPHA (2006 Jan 25, compiled "