Submitted By: Matt Burgess (matthew at linuxfromscratch dot org) Date: 2007-10-24 Initial Package Version: 7.1 Origin: Upstream Upstream Status: Applied Description: Contains patches 001-145 from upstream excluding patches 003, 007, 041, 065, 070, 072, 080, 088, 091, 092, 124, 126, 128, 129 and 134 as they are for "extras" (e.g. Mac, Windows) only. diff -Naur vim71.orig/runtime/doc/change.txt vim71/runtime/doc/change.txt --- vim71.orig/runtime/doc/change.txt 2007-05-12 10:18:46.000000000 +0000 +++ vim71/runtime/doc/change.txt 2007-10-24 22:09:07.000000000 +0000 @@ -1571,6 +1571,10 @@ in their original order, right before the sorted lines. + If {pattern} is empty (e.g. // is specified), the + last search pattern is used. This allows trying out + a pattern first. + Note that using ":sort" with ":global" doesn't sort the matching lines, it's quite useless. diff -Naur vim71.orig/runtime/doc/eval.txt vim71/runtime/doc/eval.txt --- vim71.orig/runtime/doc/eval.txt 2007-05-12 10:18:46.000000000 +0000 +++ vim71/runtime/doc/eval.txt 2007-10-24 22:09:09.000000000 +0000 @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 7.1. Last change: 2007 May 11 +*eval.txt* For Vim version 7.1. Last change: 2007 Sep 25 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1557,6 +1557,7 @@ changenr() Number current change number char2nr( {expr}) Number ASCII value of first char in {expr} cindent( {lnum}) Number C indent for line {lnum} +clearmatches() None clear all matches col( {expr}) Number column nr of cursor or mark complete({startcol}, {matches}) String set Insert mode completion complete_add( {expr}) Number add completion match @@ -1602,7 +1603,7 @@ foldtextresult( {lnum}) String text for closed fold at {lnum} foreground( ) Number bring the Vim window to the foreground function( {name}) Funcref reference to function {name} -garbagecollect() none free memory, breaking cyclic references +garbagecollect( [at_exit]) none free memory, breaking cyclic references get( {list}, {idx} [, {def}]) any get item {idx} from {list} or {def} get( {dict}, {key} [, {def}]) any get item {key} from {dict} or {def} getbufline( {expr}, {lnum} [, {end}]) @@ -1622,6 +1623,7 @@ getline( {lnum}) String line {lnum} of current buffer getline( {lnum}, {end}) List lines {lnum} to {end} of current buffer getloclist({nr}) List list of location list items +getmatches() List list of current matches getpos( {expr}) List position of cursor, mark, etc. getqflist() List list of quickfix items getreg( [{regname} [, 1]]) String contents of register @@ -1676,7 +1678,10 @@ String check for mappings matching {name} match( {expr}, {pat}[, {start}[, {count}]]) Number position where {pat} matches in {expr} +matchadd( {group}, {pattern}[, {priority}[, {id}]]) + Number highlight {pattern} with {group} matcharg( {nr}) List arguments of |:match| +matchdelete( {id}) Number delete match identified by {id} matchend( {expr}, {pat}[, {start}[, {count}]]) Number position where {pat} ends in {expr} matchlist( {expr}, {pat}[, {start}[, {count}]]) @@ -1731,6 +1736,7 @@ setline( {lnum}, {line}) Number set line {lnum} to {line} setloclist( {nr}, {list}[, {action}]) Number modify location list using {list} +setmatches( {list}) Number restore a list of matches setpos( {expr}, {list}) none set the {expr} position to {list} setqflist( {list}[, {action}]) Number modify quickfix list using {list} setreg( {n}, {v}[, {opt}]) Number set register to value and type @@ -2012,6 +2018,10 @@ feature, -1 is returned. See |C-indenting|. +clearmatches() *clearmatches()* + Clears all matches previously defined by |matchadd()| and the + |:match| commands. + *col()* col({expr}) The result is a Number, which is the byte index of the column position given with {expr}. The accepted positions are: @@ -2020,6 +2030,10 @@ number of characters in the cursor line plus one) 'x position of mark x (if the mark is not set, 0 is returned) + Additionally {expr} can be [lnum, col]: a |List| with the line + and column number. Most useful when the column is "$", to get + the las column of a specific line. When "lnum" or "col" is + out of range then col() returns zero. To get the line number use |line()|. To get both use |getpos()|. For the screen column position use |virtcol()|. @@ -2659,7 +2673,7 @@ {name} can be a user defined function or an internal function. -garbagecollect() *garbagecollect()* +garbagecollect([at_exit]) *garbagecollect()* Cleanup unused |Lists| and |Dictionaries| that have circular references. There is hardly ever a need to invoke this function, as it is automatically done when Vim runs out of @@ -2669,6 +2683,9 @@ This is useful if you have deleted a very big |List| and/or |Dictionary| with circular references in a script that runs for a long time. + When the optional "at_exit" argument is one, garbage + collection will also be done when exiting Vim, if it wasn't + done before. This is useful when checking for memory leaks. get({list}, {idx} [, {default}]) *get()* Get item {idx} from |List| {list}. When this item is not @@ -2824,6 +2841,8 @@ given file {fname}. If {fname} is a directory, 0 is returned. If the file {fname} can't be found, -1 is returned. + If the size of {fname} is too big to fit in a Number then -2 + is returned. getfontname([{name}]) *getfontname()* Without an argument returns the name of the normal font being @@ -2912,6 +2931,28 @@ returned. For an invalid window number {nr}, an empty list is returned. Otherwise, same as getqflist(). +getmatches() *getmatches()* + Returns a |List| with all matches previously defined by + |matchadd()| and the |:match| commands. |getmatches()| is + useful in combination with |setmatches()|, as |setmatches()| + can restore a list of matches saved by |getmatches()|. + Example: > + :echo getmatches() +< [{'group': 'MyGroup1', 'pattern': 'TODO', + 'priority': 10, 'id': 1}, {'group': 'MyGroup2', + 'pattern': 'FIXME', 'priority': 10, 'id': 2}] > + :let m = getmatches() + :call clearmatches() + :echo getmatches() +< [] > + :call setmatches(m) + :echo getmatches() +< [{'group': 'MyGroup1', 'pattern': 'TODO', + 'priority': 10, 'id': 1}, {'group': 'MyGroup2', + 'pattern': 'FIXME', 'priority': 10, 'id': 2}] > + :unlet m +< + getqflist() *getqflist()* Returns a list with all the current quickfix errors. Each list item is a dictionary with these entries: @@ -3616,6 +3657,44 @@ the pattern. 'smartcase' is NOT used. The matching is always done like 'magic' is set and 'cpoptions' is empty. + *matchadd()* *E798* *E799* *E801* +matchadd({group}, {pattern}[, {priority}[, {id}]]) + Defines a pattern to be highlighted in the current window (a + "match"). It will be highlighted with {group}. Returns an + identification number (ID), which can be used to delete the + match using |matchdelete()|. + + The optional {priority} argument assigns a priority to the + match. A match with a high priority will have its + highlighting overrule that of a match with a lower priority. + A priority is specified as an integer (negative numbers are no + exception). If the {priority} argument is not specified, the + default priority is 10. The priority of 'hlsearch' is zero, + hence all matches with a priority greater than zero will + overrule it. Syntax highlighting (see 'syntax') is a separate + mechanism, and regardless of the chosen priority a match will + always overrule syntax highlighting. + + The optional {id} argument allows the request for a specific + match ID. If a specified ID is already taken, an error + message will appear and the match will not be added. An ID + is specified as a positive integer (zero excluded). IDs 1, 2 + and 3 are reserved for |:match|, |:2match| and |:3match|, + respectively. If the {id} argument is not specified, + |matchadd()| automatically chooses a free ID. + + The number of matches is not limited, as it is the case with + the |:match| commands. + + Example: > + :highlight MyGroup ctermbg=green guibg=green + :let m = matchadd("MyGroup", "TODO") +< Deletion of the pattern: > + :call matchdelete(m) + +< A list of matches defined by |matchadd()| and |:match| are + available from |getmatches()|. All matches can be deleted in + one operation by |clearmatches()|. matcharg({nr}) *matcharg()* Selects the {nr} match item, as set with a |:match|, @@ -3625,8 +3704,15 @@ The pattern used. When {nr} is not 1, 2 or 3 returns an empty |List|. When there is no match item set returns ['', '']. - This is usef to save and restore a |:match|. - + This is useful to save and restore a |:match|. + Highlighting matches using the |:match| commands are limited + to three matches. |matchadd()| does not have this limitation. + +matchdelete({id}) *matchdelete()* *E802* *E803* + Deletes a match with ID {id} previously defined by |matchadd()| + or one of the |:match| commands. Returns 0 if succesfull, + otherwise -1. See example for |matchadd()|. All matches can + be deleted in one operation by |clearmatches()|. matchend({expr}, {pat}[, {start}[, {count}]]) *matchend()* Same as match(), but return the index of first character after @@ -4379,7 +4465,13 @@ When {nr} is zero the current window is used. For a location list window, the displayed location list is modified. For an invalid window number {nr}, -1 is returned. - Otherwise, same as setqflist(). + Otherwise, same as |setqflist()|. + Also see |location-list|. + +setmatches({list}) *setmatches()* + Restores a list of matches saved by |getmatches()|. Returns 0 + if succesfull, otherwise -1. All current matches are cleared + before the list is restored. See example for |getmatches()|. *setpos()* setpos({expr}, {list}) @@ -5022,14 +5114,12 @@ position, the returned Number will be the column at the end of the . For example, for a in column 1, with 'ts' set to 8, it returns 8. - For the use of {expr} see |col()|. Additionally you can use - [lnum, col]: a |List| with the line and column number. When - "lnum" or "col" is out of range then virtcol() returns zero. - When 'virtualedit' is used it can be [lnum, col, off], where + For the byte position use |col()|. + For the use of {expr} see |col()|. + When 'virtualedit' is used {expr} can be [lnum, col, off], where "off" is the offset in screen columns from the start of the character. E.g., a position within a or after the last character. - For the byte position use |col()|. When Virtual editing is active in the current mode, a position beyond the end of the line can be returned. |'virtualedit'| The accepted positions are: diff -Naur vim71.orig/runtime/doc/options.txt vim71/runtime/doc/options.txt --- vim71.orig/runtime/doc/options.txt 2007-05-12 10:18:47.000000000 +0000 +++ vim71/runtime/doc/options.txt 2007-10-24 22:09:09.000000000 +0000 @@ -1,4 +1,4 @@ -*options.txt* For Vim version 7.1. Last change: 2007 May 11 +*options.txt* For Vim version 7.1. Last change: 2007 Aug 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2415,8 +2415,8 @@ When mixing vertically and horizontally split windows, a minimal size is computed and some windows may be larger if there is room. The 'eadirection' option tells in which direction the size is affected. - Changing the height of a window can be avoided by setting - 'winfixheight'. + Changing the height and width of a window can be avoided by setting + 'winfixheight' and 'winfixwidth', respectively. *'equalprg'* *'ep'* 'equalprg' 'ep' string (default "") diff -Naur vim71.orig/runtime/doc/pattern.txt vim71/runtime/doc/pattern.txt --- vim71.orig/runtime/doc/pattern.txt 2007-05-12 10:18:47.000000000 +0000 +++ vim71/runtime/doc/pattern.txt 2007-10-24 22:09:07.000000000 +0000 @@ -1212,7 +1212,10 @@ {group} must exist at the moment this command is executed. The {group} highlighting still applies when a character is - to be highlighted for 'hlsearch'. + to be highlighted for 'hlsearch', as the highlighting for + matches is given higher priority than that of 'hlsearch'. + Syntax highlighting (see 'syntax') is also overruled by + matches. Note that highlighting the last used search pattern with 'hlsearch' is used in all windows, while the pattern defined @@ -1226,8 +1229,15 @@ display you may get unexpected results. That is because Vim looks for a match in the line where redrawing starts. - Also see |matcharg()|, it returns the highlight group and - pattern of a previous :match command. + Also see |matcharg()|and |getmatches()|. The former returns + the highlight group and pattern of a previous |:match| + command. The latter returns a list with highlight groups and + patterns defined by both |matchadd()| and |:match|. + + Highlighting matches using |:match| are limited to three + matches (aside from |:match|, |:2match| and |:3match|are + available). |matchadd()| does not have this limitation and in + addition makes it possible to prioritize matches. Another example, which highlights all characters in virtual column 72 and more: > diff -Naur vim71.orig/runtime/doc/pi_paren.txt vim71/runtime/doc/pi_paren.txt --- vim71.orig/runtime/doc/pi_paren.txt 2007-05-12 10:18:47.000000000 +0000 +++ vim71/runtime/doc/pi_paren.txt 2007-10-24 22:09:09.000000000 +0000 @@ -12,8 +12,8 @@ You can avoid loading this plugin by setting the "loaded_matchparen" variable: > :let loaded_matchparen = 1 -The plugin installs CursorMoved autocommands to redefine the match -highlighting. +The plugin installs CursorMoved, CursorMovedI and WinEnter autocommands to +redefine the match highlighting. To disable the plugin after it was loaded use this command: > diff -Naur vim71.orig/runtime/doc/usr_41.txt vim71/runtime/doc/usr_41.txt --- vim71.orig/runtime/doc/usr_41.txt 2007-05-12 10:18:48.000000000 +0000 +++ vim71/runtime/doc/usr_41.txt 2007-10-24 22:09:07.000000000 +0000 @@ -763,13 +763,22 @@ foldtextresult() get the text displayed for a closed fold Syntax and highlighting: + clearmatches() clear all matches defined by |matchadd()| and + the |:match| commands + getmatches() get all matches defined by |matchadd()| and + the |:match| commands hlexists() check if a highlight group exists hlID() get ID of a highlight group synID() get syntax ID at a specific position synIDattr() get a specific attribute of a syntax ID synIDtrans() get translated syntax ID diff_hlID() get highlight ID for diff mode at a position + matchadd() define a pattern to highlight (a "match") matcharg() get info about |:match| arguments + matchdelete() delete a match defined by |matchadd()| or a + |:match| command + setmatches() restore a list of matches saved by + |getmatches()| Spelling: spellbadword() locate badly spelled word at or after cursor diff -Naur vim71.orig/runtime/doc/windows.txt vim71/runtime/doc/windows.txt --- vim71.orig/runtime/doc/windows.txt 2007-05-12 10:18:49.000000000 +0000 +++ vim71/runtime/doc/windows.txt 2007-10-24 22:09:09.000000000 +0000 @@ -132,7 +132,8 @@ the same file. Make new window N high (default is to use half the height of the current window). Reduces the current window height to create room (and others, if the 'equalalways' option - is set and 'eadirection' isn't "hor"). + is set, 'eadirection' isn't "hor", and one of them is higher + than the current or the new window). Note: CTRL-S does not work on all terminals and might block further input, use CTRL-Q to get going again. Also see |++opt| and |+cmd|. @@ -140,9 +141,13 @@ CTRL-W CTRL-V *CTRL-W_CTRL-V* CTRL-W v *CTRL-W_v* :[N]vs[plit] [++opt] [+cmd] [file] *:vs* *:vsplit* - Like |:split|, but split vertically. If 'equalalways' is set - and 'eadirection' isn't "ver" the windows will be spread out - horizontally, unless a width was specified. + Like |:split|, but split vertically. The windows will be + spread out horizontally if + 1. a width was not specified, + 2. 'equalalways' is set, + 3. 'eadirection' isn't "ver", and + 4. one of the other windows are wider than the current or new + window. Note: In other places CTRL-Q does the same as CTRL-V, but here it doesn't! diff -Naur vim71.orig/runtime/filetype.vim vim71/runtime/filetype.vim --- vim71.orig/runtime/filetype.vim 2007-05-10 15:14:37.000000000 +0000 +++ vim71/runtime/filetype.vim 2007-10-24 22:09:07.000000000 +0000 @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar -" Last Change: 2007 May 10 +" Last Change: 2007 May 15 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -1286,7 +1286,7 @@ au BufNewFile,BufRead *.it,*.ih setf ppwiz " Oracle Pro*C/C++ -au BufNewFile,BufRead .pc setf proc +au BufNewFile,BufRead *.pc setf proc " Privoxy actions file au BufNewFile,BufRead *.action setf privoxy diff -Naur vim71.orig/runtime/plugin/matchparen.vim vim71/runtime/plugin/matchparen.vim --- vim71.orig/runtime/plugin/matchparen.vim 2006-10-12 20:05:05.000000000 +0000 +++ vim71/runtime/plugin/matchparen.vim 2007-10-24 22:09:09.000000000 +0000 @@ -1,6 +1,6 @@ " Vim plugin for showing matching parens " Maintainer: Bram Moolenaar -" Last Change: 2006 Oct 12 +" Last Change: 2007 Aug 8 " Exit quickly when: " - this plugin was already loaded (or disabled) @@ -13,7 +13,7 @@ augroup matchparen " Replace all matchparen autocommands - autocmd! CursorMoved,CursorMovedI * call s:Highlight_Matching_Pair() + autocmd! CursorMoved,CursorMovedI,WinEnter * call s:Highlight_Matching_Pair() augroup END " Skip the rest if it was already done. @@ -62,25 +62,37 @@ " Figure out the arguments for searchpairpos(). " Restrict the search to visible lines with "stopline". " And avoid searching very far (e.g., for closed folds and long lines) + " The "viewable" variables give a range in which we can scroll while keeping + " the cursor at the same position + " adjustedScrolloff accounts for very large numbers of scrolloff + let adjustedScrolloff = min([&scrolloff, (line('w$') - line('w0')) / 2]) + let bottom_viewable = min([line('$'), c_lnum + &lines - adjustedScrolloff - 2]) + let top_viewable = max([1, c_lnum-&lines+adjustedScrolloff + 2]) + " one of these stoplines will be adjusted below, but the current values are + " minimal boundaries within the current window + let stoplinebottom = line('w$') + let stoplinetop = line('w0') if i % 2 == 0 let s_flags = 'nW' let c2 = plist[i + 1] if has("byte_offset") && has("syntax_items") && &smc > 0 let stopbyte = min([line2byte("$"), line2byte(".") + col(".") + &smc * 2]) - let stopline = min([line('w$'), byte2line(stopbyte)]) + let stopline = min([bottom_viewable, byte2line(stopbyte)]) else - let stopline = min([line('w$'), c_lnum + 100]) + let stopline = min([bottom_viewable, c_lnum + 100]) endif + let stoplinebottom = stopline else let s_flags = 'nbW' let c2 = c let c = plist[i - 1] if has("byte_offset") && has("syntax_items") && &smc > 0 let stopbyte = max([1, line2byte(".") + col(".") - &smc * 2]) - let stopline = max([line('w0'), byte2line(stopbyte)]) + let stopline = max([top_viewable, byte2line(stopbyte)]) else - let stopline = max([line('w0'), c_lnum - 100]) + let stopline = max([top_viewable, c_lnum - 100]) endif + let stoplinetop = stopline endif if c == '[' let c = '\[' @@ -106,7 +118,7 @@ endif " If a match is found setup match highlighting. - if m_lnum > 0 && m_lnum >= line('w0') && m_lnum <= line('w$') + if m_lnum > 0 && m_lnum >= stoplinetop && m_lnum <= stoplinebottom exe '3match MatchParen /\(\%' . c_lnum . 'l\%' . (c_col - before) . \ 'c\)\|\(\%' . m_lnum . 'l\%' . m_col . 'c\)/' let w:paren_hl_on = 1 @@ -114,7 +126,8 @@ endfunction " Define commands that will disable and enable the plugin. -command! NoMatchParen 3match none | unlet! g:loaded_matchparen | au! matchparen -command! DoMatchParen runtime plugin/matchparen.vim | doau CursorMoved +command! NoMatchParen windo 3match none | unlet! g:loaded_matchparen | + \ au! matchparen +command! DoMatchParen runtime plugin/matchparen.vim | windo doau CursorMoved let &cpo = cpo_save diff -Naur vim71.orig/src/auto/configure vim71/src/auto/configure --- vim71.orig/src/auto/configure 2007-05-12 11:49:09.000000000 +0000 +++ vim71/src/auto/configure 2007-10-24 22:09:07.000000000 +0000 @@ -3843,7 +3843,9 @@ fi if test "X$vi_cv_path_mzscheme_pfx" != "X"; then - if test -f "${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"; then + if test "x$MACOSX" = "xyes"; then + MZSCHEME_LIBS="-framework PLT_MzScheme" + elif test -f "${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"; then MZSCHEME_LIBS="${vi_cv_path_mzscheme_pfx}/lib/libmzscheme.a ${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a" else MZSCHEME_LIBS="-L${vi_cv_path_mzscheme_pfx}/lib -lmzscheme -lmzgc" diff -Naur vim71.orig/src/buffer.c vim71/src/buffer.c --- vim71.orig/src/buffer.c 2007-05-10 15:25:59.000000000 +0000 +++ vim71/src/buffer.c 2007-10-24 22:09:09.000000000 +0000 @@ -171,6 +171,13 @@ /* Put the cursor on the first line. */ curwin->w_cursor.lnum = 1; curwin->w_cursor.col = 0; + + /* Set or reset 'modified' before executing autocommands, so that + * it can be changed there. */ + if (!readonlymode && !bufempty()) + changed(); + else if (retval != FAIL) + unchanged(curbuf, FALSE); #ifdef FEAT_AUTOCMD # ifdef FEAT_EVAL apply_autocmds_retval(EVENT_STDINREADPOST, NULL, NULL, FALSE, @@ -194,16 +201,16 @@ /* When reading stdin, the buffer contents always needs writing, so set * the changed flag. Unless in readonly mode: "ls | gview -". * When interrupted and 'cpoptions' contains 'i' set changed flag. */ - if ((read_stdin && !readonlymode && !bufempty()) + if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL) #ifdef FEAT_AUTOCMD || modified_was_set /* ":set modified" used in autocmd */ # ifdef FEAT_EVAL || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL) # endif #endif - || (got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) + ) changed(); - else if (retval != FAIL) + else if (retval != FAIL && !read_stdin) unchanged(curbuf, FALSE); save_file_ff(curbuf); /* keep this fileformat */ @@ -495,6 +502,7 @@ buf->b_start_eol = TRUE; #ifdef FEAT_MBYTE buf->b_p_bomb = FALSE; + buf->b_start_bomb = FALSE; #endif buf->b_ml.ml_mfp = NULL; buf->b_ml.ml_flags = ML_EMPTY; /* empty buffer */ @@ -4167,29 +4175,35 @@ * mess up the full path name, even though it starts with a '/'. * Also expand when there is ".." in the file name, try to remove it, * because "c:/src/../README" is equal to "c:/README". + * Similarly "c:/src//file" is equal to "c:/src/file". * For MS-Windows also expand names like "longna~1" to "longname". */ #ifdef UNIX return FullName_save(fname, TRUE); #else - if (!vim_isAbsName(fname) || strstr((char *)fname, "..") != NULL -#if defined(MSWIN) || defined(DJGPP) + if (!vim_isAbsName(fname) + || strstr((char *)fname, "..") != NULL + || strstr((char *)fname, "//") != NULL +# ifdef BACKSLASH_IN_FILENAME + || strstr((char *)fname, "\\\\") != NULL +# endif +# if defined(MSWIN) || defined(DJGPP) || vim_strchr(fname, '~') != NULL -#endif +# endif ) return FullName_save(fname, FALSE); fname = vim_strsave(fname); -#ifdef USE_FNAME_CASE -# ifdef USE_LONG_FNAME +# ifdef USE_FNAME_CASE +# ifdef USE_LONG_FNAME if (USE_LONG_FNAME) -# endif +# endif { if (fname != NULL) fname_case(fname, 0); /* set correct case for file name */ } -#endif +# endif return fname; #endif @@ -4853,7 +4867,7 @@ */ for (e = s; *e != ':' && *e != NUL; ++e) if (e[0] == '\\' && e[1] == ':') - STRCPY(e, e + 1); + mch_memmove(e, e + 1, STRLEN(e)); if (*e == NUL) end = TRUE; @@ -5507,11 +5521,11 @@ #ifdef FEAT_AUTOCMD if (!aucmd) /* Don't trigger BufDelete autocommands here. */ - ++autocmd_block; + block_autocmds(); #endif close_buffer(NULL, buf, DOBUF_WIPE); #ifdef FEAT_AUTOCMD if (!aucmd) - --autocmd_block; + unblock_autocmds(); #endif } diff -Naur vim71.orig/src/charset.c vim71/src/charset.c --- vim71.orig/src/charset.c 2007-03-24 20:10:37.000000000 +0000 +++ vim71/src/charset.c 2007-10-24 22:09:09.000000000 +0000 @@ -207,7 +207,10 @@ } while (c <= c2) { - if (!do_isalpha || isalpha(c) + /* Use the MB_ functions here, because isalpha() doesn't + * work properly when 'encoding' is "latin1" and the locale is + * "C". */ + if (!do_isalpha || MB_ISLOWER(c) || MB_ISUPPER(c) #ifdef FEAT_FKMAP || (p_altkeymap && (F_isalpha(c) || F_isdigit(c))) #endif @@ -929,6 +932,23 @@ } /* + * return TRUE if 'c' is a valid file-name character or a wildcard character + * Assume characters above 0x100 are valid (multi-byte). + * Explicitly interpret ']' as a wildcard character as mch_has_wildcard("]") + * returns false. + */ + int +vim_isfilec_or_wc(c) + int c; +{ + char_u buf[2]; + + buf[0] = (char_u)c; + buf[1] = NUL; + return vim_isfilec(c) || c == ']' || mch_has_wildcard(buf); +} + +/* * return TRUE if 'c' is a printable character * Assume characters above 0x100 are printable (multi-byte), except for * Unicode. @@ -1898,7 +1918,7 @@ { for ( ; *p; ++p) if (rem_backslash(p)) - STRCPY(p, p + 1); + mch_memmove(p, p + 1, STRLEN(p)); } /* diff -Naur vim71.orig/src/configure.in vim71/src/configure.in --- vim71.orig/src/configure.in 2007-05-12 09:19:27.000000000 +0000 +++ vim71/src/configure.in 2007-10-24 22:09:07.000000000 +0000 @@ -423,7 +423,9 @@ fi if test "X$vi_cv_path_mzscheme_pfx" != "X"; then - if test -f "${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"; then + if test "x$MACOSX" = "xyes"; then + MZSCHEME_LIBS="-framework PLT_MzScheme" + elif test -f "${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a"; then MZSCHEME_LIBS="${vi_cv_path_mzscheme_pfx}/lib/libmzscheme.a ${vi_cv_path_mzscheme_pfx}/lib/libmzgc.a" else MZSCHEME_LIBS="-L${vi_cv_path_mzscheme_pfx}/lib -lmzscheme -lmzgc" diff -Naur vim71.orig/src/diff.c vim71/src/diff.c --- vim71.orig/src/diff.c 2007-02-16 00:18:41.000000000 +0000 +++ vim71/src/diff.c 2007-10-24 22:09:09.000000000 +0000 @@ -791,6 +791,9 @@ } mch_remove(tmp_orig); + /* force updating cursor position on screen */ + curwin->w_valid_cursor.lnum = 0; + diff_redraw(TRUE); theend: @@ -840,11 +843,11 @@ tmp_orig, tmp_new); append_redir(cmd, p_srr, tmp_diff); #ifdef FEAT_AUTOCMD - ++autocmd_block; /* Avoid ShellCmdPost stuff */ + block_autocmds(); /* Avoid ShellCmdPost stuff */ #endif (void)call_shell(cmd, SHELL_FILTER|SHELL_SILENT|SHELL_DOOUT); #ifdef FEAT_AUTOCMD - --autocmd_block; + unblock_autocmds(); #endif vim_free(cmd); } @@ -949,11 +952,11 @@ # endif eap->arg); #ifdef FEAT_AUTOCMD - ++autocmd_block; /* Avoid ShellCmdPost stuff */ + block_autocmds(); /* Avoid ShellCmdPost stuff */ #endif (void)call_shell(buf, SHELL_FILTER | SHELL_COOKED); #ifdef FEAT_AUTOCMD - --autocmd_block; + unblock_autocmds(); #endif } @@ -1310,7 +1313,7 @@ dp->df_count[idx_new] += -off; off = 0; } - for (i = idx_orig; i < idx_new + !notset; ++i) + for (i = idx_orig; i < idx_new; ++i) if (curtab->tp_diffbuf[i] != NULL) dp->df_count[i] = dpl->df_lnum[i] + dpl->df_count[i] - dp->df_lnum[i] + off; diff -Naur vim71.orig/src/digraph.c vim71/src/digraph.c --- vim71.orig/src/digraph.c 2006-05-02 18:24:04.000000000 +0000 +++ vim71/src/digraph.c 2007-10-24 22:09:09.000000000 +0000 @@ -2028,7 +2028,7 @@ ++no_mapping; ++allow_keys; - c = safe_vgetc(); + c = plain_vgetc(); --no_mapping; --allow_keys; if (c != ESC) /* ESC cancels CTRL-K */ @@ -2050,7 +2050,7 @@ #endif ++no_mapping; ++allow_keys; - cc = safe_vgetc(); + cc = plain_vgetc(); --no_mapping; --allow_keys; if (cc != ESC) /* ESC cancels CTRL-K */ @@ -2349,8 +2349,10 @@ if (*curbuf->b_p_keymap == NUL) { - /* Stop any active keymap and clear the table. */ + /* Stop any active keymap and clear the table. Also remove + * b:keymap_name, as no keymap is active now. */ keymap_unload(); + do_cmdline_cmd((char_u *)"unlet! b:keymap_name"); } else { @@ -2500,7 +2502,6 @@ ga_clear(&curbuf->b_kmap_ga); curbuf->b_kmap_state &= ~KEYMAP_LOADED; - do_cmdline_cmd((char_u *)"unlet! b:keymap_name"); #ifdef FEAT_WINDOWS status_redraw_curbuf(); #endif diff -Naur vim71.orig/src/edit.c vim71/src/edit.c --- vim71.orig/src/edit.c 2007-05-07 19:43:55.000000000 +0000 +++ vim71/src/edit.c 2007-10-24 22:09:10.000000000 +0000 @@ -129,6 +129,7 @@ static void ins_ctrl_x __ARGS((void)); static int has_compl_option __ARGS((int dict_opt)); +static int ins_compl_accept_char __ARGS((int c)); static int ins_compl_add __ARGS((char_u *str, int len, int icase, char_u *fname, char_u **cptext, int cdir, int flags, int adup)); static int ins_compl_equal __ARGS((compl_T *match, char_u *str, int len)); static void ins_compl_longest_match __ARGS((compl_T *match)); @@ -754,8 +755,9 @@ continue; } - /* A printable, non-white character: Add to "compl_leader". */ - if (vim_isprintc(c) && !vim_iswhite(c)) + /* A non-white character that fits in with the current + * completion: Add to "compl_leader". */ + if (ins_compl_accept_char(c)) { ins_compl_addleader(c); continue; @@ -788,7 +790,7 @@ ins_redraw(FALSE); ++no_mapping; ++allow_keys; - c = safe_vgetc(); + c = plain_vgetc(); --no_mapping; --allow_keys; if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O) @@ -981,7 +983,7 @@ #ifdef FEAT_NETBEANS_INTG case K_F21: /* NetBeans command */ ++no_mapping; /* don't map the next key hits */ - i = safe_vgetc(); + i = plain_vgetc(); --no_mapping; netbeans_keycommand(i); break; @@ -2053,11 +2055,44 @@ } /* + * Return TRUE when character "c" is part of the item currently being + * completed. Used to decide whether to abandon complete mode when the menu + * is visible. + */ + static int +ins_compl_accept_char(c) + int c; +{ + if (ctrl_x_mode & CTRL_X_WANT_IDENT) + /* When expanding an identifier only accept identifier chars. */ + return vim_isIDc(c); + + switch (ctrl_x_mode) + { + case CTRL_X_FILES: + /* When expanding file name only accept file name chars. But not + * path separators, so that "proto/" expands files in + * "proto", not "proto/" as a whole */ + return vim_isfilec(c) && !vim_ispathsep(c); + + case CTRL_X_CMDLINE: + case CTRL_X_OMNI: + /* Command line and Omni completion can work with just about any + * printable character, but do stop at white space. */ + return vim_isprintc(c) && !vim_iswhite(c); + + case CTRL_X_WHOLE_LINE: + /* For while line completion a space can be part of the line. */ + return vim_isprintc(c); + } + return vim_iswordc(c); +} + +/* * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the * case of the originally typed text is used, and the case of the completed * text is inferred, ie this tries to work out what case you probably wanted * the rest of the word to be in -- webb - * TODO: make this work for multi-byte characters. */ int ins_compl_add_infercase(str, len, icase, fname, dir, flags) @@ -2068,54 +2103,147 @@ int dir; int flags; { + char_u *p; + int i, c; + int actual_len; /* Take multi-byte characters */ + int actual_compl_length; /* into account. */ + int *wca; /* Wide character array. */ int has_lower = FALSE; int was_letter = FALSE; - int idx; - if (p_ic && curbuf->b_p_inf && len < IOSIZE) + if (p_ic && curbuf->b_p_inf) { - /* Infer case of completed part -- webb */ - /* Use IObuff, str would change text in buffer! */ - vim_strncpy(IObuff, str, len); + /* Infer case of completed part. */ - /* Rule 1: Were any chars converted to lower? */ - for (idx = 0; idx < compl_length; ++idx) + /* Find actual length of completion. */ +#ifdef FEAT_MBYTE + if (has_mbyte) { - if (islower(compl_orig_text[idx])) + p = str; + actual_len = 0; + while (*p != NUL) { - has_lower = TRUE; - if (isupper(IObuff[idx])) - { - /* Rule 1 is satisfied */ - for (idx = compl_length; idx < len; ++idx) - IObuff[idx] = TOLOWER_LOC(IObuff[idx]); - break; - } + mb_ptr_adv(p); + ++actual_len; } } + else +#endif + actual_len = len; - /* - * Rule 2: No lower case, 2nd consecutive letter converted to - * upper case. - */ - if (!has_lower) + /* Find actual length of original text. */ +#ifdef FEAT_MBYTE + if (has_mbyte) { - for (idx = 0; idx < compl_length; ++idx) + p = compl_orig_text; + actual_compl_length = 0; + while (*p != NUL) { - if (was_letter && isupper(compl_orig_text[idx]) - && islower(IObuff[idx])) + mb_ptr_adv(p); + ++actual_compl_length; + } + } + else +#endif + actual_compl_length = compl_length; + + /* Allocate wide character array for the completion and fill it. */ + wca = (int *)alloc(actual_len * sizeof(int)); + if (wca != NULL) + { + p = str; + for (i = 0; i < actual_len; ++i) +#ifdef FEAT_MBYTE + if (has_mbyte) + wca[i] = mb_ptr2char_adv(&p); + else +#endif + wca[i] = *(p++); + + /* Rule 1: Were any chars converted to lower? */ + p = compl_orig_text; + for (i = 0; i < actual_compl_length; ++i) + { +#ifdef FEAT_MBYTE + if (has_mbyte) + c = mb_ptr2char_adv(&p); + else +#endif + c = *(p++); + if (MB_ISLOWER(c)) { - /* Rule 2 is satisfied */ - for (idx = compl_length; idx < len; ++idx) - IObuff[idx] = TOUPPER_LOC(IObuff[idx]); - break; + has_lower = TRUE; + if (MB_ISUPPER(wca[i])) + { + /* Rule 1 is satisfied. */ + for (i = actual_compl_length; i < actual_len; ++i) + wca[i] = MB_TOLOWER(wca[i]); + break; + } } - was_letter = isalpha(compl_orig_text[idx]); } - } - /* Copy the original case of the part we typed */ - STRNCPY(IObuff, compl_orig_text, compl_length); + /* + * Rule 2: No lower case, 2nd consecutive letter converted to + * upper case. + */ + if (!has_lower) + { + p = compl_orig_text; + for (i = 0; i < actual_compl_length; ++i) + { +#ifdef FEAT_MBYTE + if (has_mbyte) + c = mb_ptr2char_adv(&p); + else +#endif + c = *(p++); + if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i])) + { + /* Rule 2 is satisfied. */ + for (i = actual_compl_length; i < actual_len; ++i) + wca[i] = MB_TOUPPER(wca[i]); + break; + } + was_letter = MB_ISLOWER(c) || MB_ISUPPER(c); + } + } + + /* Copy the original case of the part we typed. */ + p = compl_orig_text; + for (i = 0; i < actual_compl_length; ++i) + { +#ifdef FEAT_MBYTE + if (has_mbyte) + c = mb_ptr2char_adv(&p); + else +#endif + c = *(p++); + if (MB_ISLOWER(c)) + wca[i] = MB_TOLOWER(wca[i]); + else if (MB_ISUPPER(c)) + wca[i] = MB_TOUPPER(wca[i]); + } + + /* + * Generate encoding specific output from wide character array. + * Multi-byte characters can occupy up to five bytes more than + * ASCII characters, and we also need one byte for NUL, so stay + * six bytes away from the edge of IObuff. + */ + p = IObuff; + i = 0; + while (i < actual_len && (p - IObuff + 6) < IOSIZE) +#ifdef FEAT_MBYTE + if (has_mbyte) + p += mb_char2bytes(wca[i++], p); + else +#endif + *(p++) = wca[i++]; + *p = NUL; + + vim_free(wca); + } return ins_compl_add(IObuff, len, icase, fname, NULL, dir, flags, FALSE); @@ -2842,6 +2970,7 @@ /* * Add the other matches on the line */ + ptr = buf; while (!got_int) { /* Find start of the next word. Skip white @@ -2851,7 +2980,7 @@ break; wstart = ptr; - /* Find end of the word and add it. */ + /* Find end of the word. */ #ifdef FEAT_MBYTE if (has_mbyte) /* Japanese words may have characters in @@ -2868,9 +2997,12 @@ else #endif ptr = find_word_end(ptr); - add_r = ins_compl_add_infercase(wstart, - (int)(ptr - wstart), - p_ic, files[i], *dir, 0); + + /* Add the word. Skip the regexp match. */ + if (wstart != regmatch->startp[0]) + add_r = ins_compl_add_infercase(wstart, + (int)(ptr - wstart), + p_ic, files[i], *dir, 0); } } if (add_r == OK) @@ -3032,8 +3164,11 @@ p = line + curwin->w_cursor.col; mb_ptr_back(line, p); - /* Stop completion when the whole word was deleted. */ - if ((int)(p - line) - (int)compl_col <= 0) + /* Stop completion when the whole word was deleted. For Omni completion + * allow the word to be deleted, we won't match everything. */ + if ((int)(p - line) - (int)compl_col < 0 + || ((int)(p - line) - (int)compl_col == 0 + && (ctrl_x_mode & CTRL_X_OMNI) == 0)) return K_BS; /* Deleted more than what was used to find matches or didn't finish @@ -4495,14 +4630,13 @@ curs_col = curwin->w_cursor.col; compl_pending = 0; - /* if this same ctrl_x_mode has been interrupted use the text from + /* If this same ctrl_x_mode has been interrupted use the text from * "compl_startpos" to the cursor as a pattern to add a new word * instead of expand the one before the cursor, in word-wise if - * "compl_startpos" - * is not in the same line as the cursor then fix it (the line has - * been split because it was longer than 'tw'). if SOL is set then - * skip the previous pattern, a word at the beginning of the line has - * been inserted, we'll look for that -- Acevedo. */ + * "compl_startpos" is not in the same line as the cursor then fix it + * (the line has been split because it was longer than 'tw'). if SOL + * is set then skip the previous pattern, a word at the beginning of + * the line has been inserted, we'll look for that -- Acevedo. */ if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT && compl_cont_mode == ctrl_x_mode) { @@ -5128,10 +5262,7 @@ i = 0; for (;;) { - do - nc = safe_vgetc(); - while (nc == K_IGNORE || nc == K_VER_SCROLLBAR - || nc == K_HOR_SCROLLBAR); + nc = plain_vgetc(); #ifdef FEAT_CMDL_INFO if (!(State & CMDLINE) # ifdef FEAT_MBYTE @@ -7215,6 +7346,8 @@ p = ml_get_curline(); if (cin_iscase(p) || cin_isscopedecl(p) || cin_islabel(30)) return TRUE; + /* Need to get the line again after cin_islabel(). */ + p = ml_get_curline(); if (curwin->w_cursor.col > 2 && p[curwin->w_cursor.col - 1] == ':' && p[curwin->w_cursor.col - 2] == ':') @@ -7477,7 +7610,7 @@ * deleted when ESC is hit. */ ++no_mapping; - regname = safe_vgetc(); + regname = plain_vgetc(); #ifdef FEAT_LANGMAP LANGMAP_ADJUST(regname, TRUE); #endif @@ -7488,7 +7621,7 @@ #ifdef FEAT_CMDL_INFO add_to_showcmd_c(literally); #endif - regname = safe_vgetc(); + regname = plain_vgetc(); #ifdef FEAT_LANGMAP LANGMAP_ADJUST(regname, TRUE); #endif @@ -7579,7 +7712,7 @@ * deleted when ESC is hit. */ ++no_mapping; - c = safe_vgetc(); + c = plain_vgetc(); --no_mapping; switch (c) { @@ -7998,7 +8131,8 @@ /* * 0^D and ^^D: remove all indent. */ - if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col) + if (c == Ctrl_D && (lastc == '0' || lastc == '^') + && curwin->w_cursor.col > 0) { --curwin->w_cursor.col; (void)del_char(FALSE); /* delete the '^' or '0' */ @@ -9257,7 +9391,7 @@ * mode message to be deleted when ESC is hit */ ++no_mapping; ++allow_keys; - c = safe_vgetc(); + c = plain_vgetc(); --no_mapping; --allow_keys; if (IS_SPECIAL(c) || mod_mask) /* special key */ @@ -9289,7 +9423,7 @@ } ++no_mapping; ++allow_keys; - cc = safe_vgetc(); + cc = plain_vgetc(); --no_mapping; --allow_keys; if (cc != ESC) diff -Naur vim71.orig/src/eval.c vim71/src/eval.c --- vim71.orig/src/eval.c 2007-05-07 19:47:32.000000000 +0000 +++ vim71/src/eval.c 2007-10-24 22:09:09.000000000 +0000 @@ -369,17 +369,17 @@ static int ex_let_vars __ARGS((char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars)); static char_u *skip_var_list __ARGS((char_u *arg, int *var_count, int *semicolon)); static char_u *skip_var_one __ARGS((char_u *arg)); -static void list_hashtable_vars __ARGS((hashtab_T *ht, char_u *prefix, int empty)); -static void list_glob_vars __ARGS((void)); -static void list_buf_vars __ARGS((void)); -static void list_win_vars __ARGS((void)); +static void list_hashtable_vars __ARGS((hashtab_T *ht, char_u *prefix, int empty, int *first)); +static void list_glob_vars __ARGS((int *first)); +static void list_buf_vars __ARGS((int *first)); +static void list_win_vars __ARGS((int *first)); #ifdef FEAT_WINDOWS -static void list_tab_vars __ARGS((void)); +static void list_tab_vars __ARGS((int *first)); #endif -static void list_vim_vars __ARGS((void)); -static void list_script_vars __ARGS((void)); -static void list_func_vars __ARGS((void)); -static char_u *list_arg_vars __ARGS((exarg_T *eap, char_u *arg)); +static void list_vim_vars __ARGS((int *first)); +static void list_script_vars __ARGS((int *first)); +static void list_func_vars __ARGS((int *first)); +static char_u *list_arg_vars __ARGS((exarg_T *eap, char_u *arg, int *first)); static char_u *ex_let_one __ARGS((char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op)); static int check_changedtick __ARGS((char_u *arg)); static char_u *get_lval __ARGS((char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int quiet, int fne_flags)); @@ -475,6 +475,7 @@ static void f_changenr __ARGS((typval_T *argvars, typval_T *rettv)); static void f_char2nr __ARGS((typval_T *argvars, typval_T *rettv)); static void f_cindent __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_clearmatches __ARGS((typval_T *argvars, typval_T *rettv)); static void f_col __ARGS((typval_T *argvars, typval_T *rettv)); #if defined(FEAT_INS_EXPAND) static void f_complete __ARGS((typval_T *argvars, typval_T *rettv)); @@ -529,6 +530,7 @@ static void f_getftime __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getftype __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getline __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_getmatches __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getpos __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getqflist __ARGS((typval_T *argvars, typval_T *rettv)); static void f_getreg __ARGS((typval_T *argvars, typval_T *rettv)); @@ -577,7 +579,9 @@ static void f_maparg __ARGS((typval_T *argvars, typval_T *rettv)); static void f_mapcheck __ARGS((typval_T *argvars, typval_T *rettv)); static void f_match __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_matchadd __ARGS((typval_T *argvars, typval_T *rettv)); static void f_matcharg __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_matchdelete __ARGS((typval_T *argvars, typval_T *rettv)); static void f_matchend __ARGS((typval_T *argvars, typval_T *rettv)); static void f_matchlist __ARGS((typval_T *argvars, typval_T *rettv)); static void f_matchstr __ARGS((typval_T *argvars, typval_T *rettv)); @@ -618,6 +622,7 @@ static void f_setcmdpos __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setline __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setloclist __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_setmatches __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setpos __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setqflist __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setreg __ARGS((typval_T *argvars, typval_T *rettv)); @@ -672,7 +677,7 @@ static void f_writefile __ARGS((typval_T *argvars, typval_T *rettv)); static int list2fpos __ARGS((typval_T *arg, pos_T *posp, int *fnump)); -static pos_T *var2fpos __ARGS((typval_T *varp, int lnum, int *fnum)); +static pos_T *var2fpos __ARGS((typval_T *varp, int dollar_lnum, int *fnum)); static int get_env_len __ARGS((char_u **arg)); static int get_id_len __ARGS((char_u **arg)); static int get_name_len __ARGS((char_u **arg, char_u **alias, int evaluate, int verbose)); @@ -699,8 +704,8 @@ static hashtab_T *find_var_ht __ARGS((char_u *name, char_u **varname)); static void vars_clear_ext __ARGS((hashtab_T *ht, int free_val)); static void delete_var __ARGS((hashtab_T *ht, hashitem_T *hi)); -static void list_one_var __ARGS((dictitem_T *v, char_u *prefix)); -static void list_one_var_a __ARGS((char_u *prefix, char_u *name, int type, char_u *string)); +static void list_one_var __ARGS((dictitem_T *v, char_u *prefix, int *first)); +static void list_one_var_a __ARGS((char_u *prefix, char_u *name, int type, char_u *string, int *first)); static void set_var __ARGS((char_u *name, typval_T *varp, int copy)); static int var_check_ro __ARGS((int flags, char_u *name)); static int var_check_fixed __ARGS((int flags, char_u *name)); @@ -992,20 +997,20 @@ char_u *value; int value_len; { - size_t len; + int len; if (redir_lval == NULL) return; if (value_len == -1) - len = STRLEN(value); /* Append the entire string */ + len = (int)STRLEN(value); /* Append the entire string */ else - len = value_len; /* Append only "value_len" characters */ + len = value_len; /* Append only "value_len" characters */ - if (ga_grow(&redir_ga, (int)len) == OK) + if (ga_grow(&redir_ga, len) == OK) { mch_memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len); - redir_ga.ga_len += (int)len; + redir_ga.ga_len += len; } else var_redir_stop(); @@ -1313,7 +1318,6 @@ { hashitem_T *hi; - clear_tv(&vimvars[idx].vv_tv); vimvars[idx].vv_tv = *save_tv; if (vimvars[idx].vv_type == VAR_UNKNOWN) { @@ -1357,7 +1361,6 @@ if (p_verbose == 0) --emsg_off; - vimvars[VV_VAL].vv_str = NULL; restore_vimvar(VV_VAL, &save_val); return list; @@ -1411,7 +1414,8 @@ } -#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO) +#if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) \ + || defined(FEAT_COMPL_FUNC) || defined(PROTO) /* * Call some vimL function and return the result in "*rettv". * Uses argv[argc] for the function arguments. @@ -1484,6 +1488,7 @@ return ret; } +# if (defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL)) || defined(PROTO) /* * Call vimL function "func" and return the result as a string. * Returns NULL when calling the function fails. @@ -1506,8 +1511,9 @@ clear_tv(&rettv); return retval; } +# endif -#if defined(FEAT_COMPL_FUNC) || defined(PROTO) +# if defined(FEAT_COMPL_FUNC) || defined(PROTO) /* * Call vimL function "func" and return the result as a number. * Returns -1 when calling the function fails. @@ -1530,7 +1536,7 @@ clear_tv(&rettv); return retval; } -#endif +# endif /* * Call vimL function "func" and return the result as a list @@ -1556,9 +1562,9 @@ return rettv.vval.v_list; } - #endif + /* * Save the current function call pointer, and set it to NULL. * Used when executing autocommands and for ":source". @@ -1691,6 +1697,7 @@ int semicolon = 0; char_u op[2]; char_u *argend; + int first = TRUE; argend = skip_var_list(arg, &var_count, &semicolon); if (argend == NULL) @@ -1707,19 +1714,19 @@ EMSG(_(e_invarg)); else if (!ends_excmd(*arg)) /* ":let var1 var2" */ - arg = list_arg_vars(eap, arg); + arg = list_arg_vars(eap, arg, &first); else if (!eap->skip) { /* ":let" */ - list_glob_vars(); - list_buf_vars(); - list_win_vars(); + list_glob_vars(&first); + list_buf_vars(&first); + list_win_vars(&first); #ifdef FEAT_WINDOWS - list_tab_vars(); + list_tab_vars(&first); #endif - list_script_vars(); - list_func_vars(); - list_vim_vars(); + list_script_vars(&first); + list_func_vars(&first); + list_vim_vars(&first); } eap->nextcmd = check_nextcmd(arg); } @@ -1924,10 +1931,11 @@ * If "empty" is TRUE also list NULL strings as empty strings. */ static void -list_hashtable_vars(ht, prefix, empty) +list_hashtable_vars(ht, prefix, empty, first) hashtab_T *ht; char_u *prefix; int empty; + int *first; { hashitem_T *hi; dictitem_T *di; @@ -1942,7 +1950,7 @@ di = HI2DI(hi); if (empty || di->di_tv.v_type != VAR_STRING || di->di_tv.vval.v_string != NULL) - list_one_var(di, prefix); + list_one_var(di, prefix, first); } } } @@ -1951,32 +1959,38 @@ * List global variables. */ static void -list_glob_vars() +list_glob_vars(first) + int *first; { - list_hashtable_vars(&globvarht, (char_u *)"", TRUE); + list_hashtable_vars(&globvarht, (char_u *)"", TRUE, first); } /* * List buffer variables. */ static void -list_buf_vars() +list_buf_vars(first) + int *first; { char_u numbuf[NUMBUFLEN]; - list_hashtable_vars(&curbuf->b_vars.dv_hashtab, (char_u *)"b:", TRUE); + list_hashtable_vars(&curbuf->b_vars.dv_hashtab, (char_u *)"b:", + TRUE, first); sprintf((char *)numbuf, "%ld", (long)curbuf->b_changedtick); - list_one_var_a((char_u *)"b:", (char_u *)"changedtick", VAR_NUMBER, numbuf); + list_one_var_a((char_u *)"b:", (char_u *)"changedtick", VAR_NUMBER, + numbuf, first); } /* * List window variables. */ static void -list_win_vars() +list_win_vars(first) + int *first; { - list_hashtable_vars(&curwin->w_vars.dv_hashtab, (char_u *)"w:", TRUE); + list_hashtable_vars(&curwin->w_vars.dv_hashtab, + (char_u *)"w:", TRUE, first); } #ifdef FEAT_WINDOWS @@ -1984,9 +1998,11 @@ * List tab page variables. */ static void -list_tab_vars() +list_tab_vars(first) + int *first; { - list_hashtable_vars(&curtab->tp_vars.dv_hashtab, (char_u *)"t:", TRUE); + list_hashtable_vars(&curtab->tp_vars.dv_hashtab, + (char_u *)"t:", TRUE, first); } #endif @@ -1994,39 +2010,44 @@ * List Vim variables. */ static void -list_vim_vars() +list_vim_vars(first) + int *first; { - list_hashtable_vars(&vimvarht, (char_u *)"v:", FALSE); + list_hashtable_vars(&vimvarht, (char_u *)"v:", FALSE, first); } /* * List script-local variables, if there is a script. */ static void -list_script_vars() +list_script_vars(first) + int *first; { if (current_SID > 0 && current_SID <= ga_scripts.ga_len) - list_hashtable_vars(&SCRIPT_VARS(current_SID), (char_u *)"s:", FALSE); + list_hashtable_vars(&SCRIPT_VARS(current_SID), + (char_u *)"s:", FALSE, first); } /* * List function variables, if there is a function. */ static void -list_func_vars() +list_func_vars(first) + int *first; { if (current_funccal != NULL) list_hashtable_vars(¤t_funccal->l_vars.dv_hashtab, - (char_u *)"l:", FALSE); + (char_u *)"l:", FALSE, first); } /* * List variables in "arg". */ static char_u * -list_arg_vars(eap, arg) +list_arg_vars(eap, arg, first) exarg_T *eap; char_u *arg; + int *first; { int error = FALSE; int len; @@ -2083,15 +2104,15 @@ { switch (*name) { - case 'g': list_glob_vars(); break; - case 'b': list_buf_vars(); break; - case 'w': list_win_vars(); break; + case 'g': list_glob_vars(first); break; + case 'b': list_buf_vars(first); break; + case 'w': list_win_vars(first); break; #ifdef FEAT_WINDOWS - case 't': list_tab_vars(); break; + case 't': list_tab_vars(first); break; #endif - case 'v': list_vim_vars(); break; - case 's': list_script_vars(); break; - case 'l': list_func_vars(); break; + case 'v': list_vim_vars(first); break; + case 's': list_script_vars(first); break; + case 'l': list_func_vars(first); break; default: EMSG2(_("E738: Can't list variables for %s"), name); } @@ -2108,7 +2129,9 @@ *arg = NUL; list_one_var_a((char_u *)"", arg == arg_subsc ? name : name_start, - tv.v_type, s == NULL ? (char_u *)"" : s); + tv.v_type, + s == NULL ? (char_u *)"" : s, + first); *arg = c; vim_free(tf); } @@ -6105,6 +6128,7 @@ /* Only do this once. */ want_garbage_collect = FALSE; may_garbage_collect = FALSE; + garbage_collect_at_exit = FALSE; /* * 1. Go through all accessible variables and mark all lists and dicts @@ -6681,7 +6705,7 @@ dict_T *d = NULL; typval_T tvkey; typval_T tv; - char_u *key; + char_u *key = NULL; dictitem_T *item; char_u *start = skipwhite(*arg + 1); char_u buf[NUMBUFLEN]; @@ -6721,20 +6745,24 @@ clear_tv(&tvkey); goto failret; } - key = get_tv_string_buf_chk(&tvkey, buf); - if (key == NULL || *key == NUL) + if (evaluate) { - /* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */ - if (key != NULL) - EMSG(_(e_emptykey)); - clear_tv(&tvkey); - goto failret; + key = get_tv_string_buf_chk(&tvkey, buf); + if (key == NULL || *key == NUL) + { + /* "key" is NULL when get_tv_string_buf_chk() gave an errmsg */ + if (key != NULL) + EMSG(_(e_emptykey)); + clear_tv(&tvkey); + goto failret; + } } *arg = skipwhite(*arg + 1); if (eval1(arg, &tv, evaluate) == FAIL) /* recursive! */ { - clear_tv(&tvkey); + if (evaluate) + clear_tv(&tvkey); goto failret; } if (evaluate) @@ -6794,7 +6822,7 @@ * "numbuf" is used for a number. * Does not put quotes around strings, as ":echo" displays values. * When "copyID" is not NULL replace recursive lists and dicts with "...". - * May return NULL; + * May return NULL. */ static char_u * echo_string(tv, tofree, numbuf, copyID) @@ -6879,7 +6907,7 @@ * If the memory is allocated "tofree" is set to it, otherwise NULL. * "numbuf" is used for a number. * Puts quotes around strings, so that they can be parsed back by eval(). - * May return NULL; + * May return NULL. */ static char_u * tv2string(tv, tofree, numbuf, copyID) @@ -7043,6 +7071,7 @@ {"changenr", 0, 0, f_changenr}, {"char2nr", 1, 1, f_char2nr}, {"cindent", 1, 1, f_cindent}, + {"clearmatches", 0, 0, f_clearmatches}, {"col", 1, 1, f_col}, #if defined(FEAT_INS_EXPAND) {"complete", 2, 2, f_complete}, @@ -7082,7 +7111,7 @@ {"foldtextresult", 1, 1, f_foldtextresult}, {"foreground", 0, 0, f_foreground}, {"function", 1, 1, f_function}, - {"garbagecollect", 0, 0, f_garbagecollect}, + {"garbagecollect", 0, 1, f_garbagecollect}, {"get", 2, 3, f_get}, {"getbufline", 2, 3, f_getbufline}, {"getbufvar", 2, 2, f_getbufvar}, @@ -7099,6 +7128,7 @@ {"getftype", 1, 1, f_getftype}, {"getline", 1, 2, f_getline}, {"getloclist", 1, 1, f_getqflist}, + {"getmatches", 0, 0, f_getmatches}, {"getpos", 1, 1, f_getpos}, {"getqflist", 0, 0, f_getqflist}, {"getreg", 0, 2, f_getreg}, @@ -7149,7 +7179,9 @@ {"maparg", 1, 3, f_maparg}, {"mapcheck", 1, 3, f_mapcheck}, {"match", 2, 4, f_match}, + {"matchadd", 2, 4, f_matchadd}, {"matcharg", 1, 1, f_matcharg}, + {"matchdelete", 1, 1, f_matchdelete}, {"matchend", 2, 4, f_matchend}, {"matchlist", 2, 4, f_matchlist}, {"matchstr", 2, 4, f_matchstr}, @@ -7190,6 +7222,7 @@ {"setcmdpos", 1, 1, f_setcmdpos}, {"setline", 2, 2, f_setline}, {"setloclist", 2, 3, f_setloclist}, + {"setmatches", 1, 1, f_setmatches}, {"setpos", 2, 2, f_setpos}, {"setqflist", 1, 2, f_setqflist}, {"setreg", 2, 3, f_setreg}, @@ -8240,6 +8273,20 @@ } /* + * "clearmatches()" function + */ +/*ARGSUSED*/ + static void +f_clearmatches(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ +#ifdef FEAT_SEARCH_EXTRA + clear_matches(curwin); +#endif +} + +/* * "col(string)" function */ static void @@ -9339,15 +9386,16 @@ { typval_T rettv; char_u *s; + int retval = FAIL; copy_tv(tv, &vimvars[VV_VAL].vv_tv); s = expr; if (eval1(&s, &rettv, TRUE) == FAIL) - return FAIL; + goto theend; if (*s != NUL) /* check for trailing chars after expr */ { EMSG2(_(e_invexpr2), s); - return FAIL; + goto theend; } if (map) { @@ -9366,10 +9414,12 @@ /* On type error, nothing has been removed; return FAIL to stop the * loop. The error message was given by get_tv_number_chk(). */ if (error) - return FAIL; + goto theend; } + retval = OK; +theend: clear_tv(&vimvars[VV_VAL].vv_tv); - return OK; + return retval; } /* @@ -9670,6 +9720,9 @@ /* This is postponed until we are back at the toplevel, because we may be * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */ want_garbage_collect = TRUE; + + if (argvars[0].v_type != VAR_UNKNOWN && get_tv_number(&argvars[0]) == 1) + garbage_collect_at_exit = TRUE; } /* @@ -9868,18 +9921,24 @@ ++no_mapping; ++allow_keys; - if (argvars[0].v_type == VAR_UNKNOWN) - /* getchar(): blocking wait. */ - n = safe_vgetc(); - else if (get_tv_number_chk(&argvars[0], &error) == 1) - /* getchar(1): only check if char avail */ - n = vpeekc(); - else if (error || vpeekc() == NUL) - /* illegal argument or getchar(0) and no char avail: return zero */ - n = 0; - else - /* getchar(0) and char avail: return char */ - n = safe_vgetc(); + for (;;) + { + if (argvars[0].v_type == VAR_UNKNOWN) + /* getchar(): blocking wait. */ + n = safe_vgetc(); + else if (get_tv_number_chk(&argvars[0], &error) == 1) + /* getchar(1): only check if char avail */ + n = vpeekc(); + else if (error || vpeekc() == NUL) + /* illegal argument or getchar(0) and no char avail: return zero */ + n = 0; + else + /* getchar(0) and char avail: return char */ + n = safe_vgetc(); + if (n == K_IGNORE) + continue; + break; + } --no_mapping; --allow_keys; @@ -10136,7 +10195,13 @@ if (mch_isdir(fname)) rettv->vval.v_number = 0; else + { rettv->vval.v_number = (varnumber_T)st.st_size; + + /* non-perfect check for overflow */ + if ((off_t)rettv->vval.v_number != (off_t)st.st_size) + rettv->vval.v_number = -2; + } } else rettv->vval.v_number = -1; @@ -10269,6 +10334,39 @@ } /* + * "getmatches()" function + */ +/*ARGSUSED*/ + static void +f_getmatches(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ +#ifdef FEAT_SEARCH_EXTRA + dict_T *dict; + matchitem_T *cur = curwin->w_match_head; + + rettv->vval.v_number = 0; + + if (rettv_list_alloc(rettv) == OK) + { + while (cur != NULL) + { + dict = dict_alloc(); + if (dict == NULL) + return; + dict_add_nr_str(dict, "group", 0L, syn_id2name(cur->hlg_id)); + dict_add_nr_str(dict, "pattern", 0L, cur->pattern); + dict_add_nr_str(dict, "priority", (long)cur->priority, NULL); + dict_add_nr_str(dict, "id", (long)cur->id, NULL); + list_append_dict(rettv->vval.v_list, dict); + cur = cur->next; + } + } +#endif +} + +/* * "getpos(string)" function */ static void @@ -10290,7 +10388,8 @@ list_append_number(l, (varnumber_T)0); list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum : (varnumber_T)0); - list_append_number(l, (fp != NULL) ? (varnumber_T)fp->col + 1 + list_append_number(l, (fp != NULL) + ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1) : (varnumber_T)0); list_append_number(l, #ifdef FEAT_VIRTUALEDIT @@ -10785,6 +10884,9 @@ "gui_gtk2", # endif #endif +#ifdef FEAT_GUI_GNOME + "gui_gnome", +#endif #ifdef FEAT_GUI_MAC "gui_mac", #endif @@ -11471,14 +11573,12 @@ char_u *xp_arg = NULL; rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; #ifdef NO_CONSOLE_INPUT /* While starting up, there is no place to enter text. */ if (no_console_input()) - { - rettv->vval.v_string = NULL; return; - } #endif cmd_silent = FALSE; /* Want to see the prompt. */ @@ -12439,6 +12539,44 @@ } /* + * "matchadd()" function + */ + static void +f_matchadd(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ +#ifdef FEAT_SEARCH_EXTRA + char_u buf[NUMBUFLEN]; + char_u *grp = get_tv_string_buf_chk(&argvars[0], buf); /* group */ + char_u *pat = get_tv_string_buf_chk(&argvars[1], buf); /* pattern */ + int prio = 10; /* default priority */ + int id = -1; + int error = FALSE; + + rettv->vval.v_number = -1; + + if (grp == NULL || pat == NULL) + return; + if (argvars[2].v_type != VAR_UNKNOWN) + { + prio = get_tv_number_chk(&argvars[2], &error); + if (argvars[3].v_type != VAR_UNKNOWN) + id = get_tv_number_chk(&argvars[3], &error); + } + if (error == TRUE) + return; + if (id >= 1 && id <= 3) + { + EMSGN("E798: ID is reserved for \":match\": %ld", id); + return; + } + + rettv->vval.v_number = match_add(curwin, grp, pat, prio, id); +#endif +} + +/* * "matcharg()" function */ static void @@ -12449,20 +12587,42 @@ if (rettv_list_alloc(rettv) == OK) { #ifdef FEAT_SEARCH_EXTRA - int mi = get_tv_number(&argvars[0]); + int id = get_tv_number(&argvars[0]); + matchitem_T *m; - if (mi >= 1 && mi <= 3) + if (id >= 1 && id <= 3) { - list_append_string(rettv->vval.v_list, - syn_id2name(curwin->w_match_id[mi - 1]), -1); - list_append_string(rettv->vval.v_list, - curwin->w_match_pat[mi - 1], -1); + if ((m = (matchitem_T *)get_match(curwin, id)) != NULL) + { + list_append_string(rettv->vval.v_list, + syn_id2name(m->hlg_id), -1); + list_append_string(rettv->vval.v_list, m->pattern, -1); + } + else + { + list_append_string(rettv->vval.v_list, NUL, -1); + list_append_string(rettv->vval.v_list, NUL, -1); + } } #endif } } /* + * "matchdelete()" function + */ + static void +f_matchdelete(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ +#ifdef FEAT_SEARCH_EXTRA + rettv->vval.v_number = match_delete(curwin, + (int)get_tv_number(&argvars[0]), TRUE); +#endif +} + +/* * "matchend()" function */ static void @@ -13680,7 +13840,7 @@ } /* Shorten "remain". */ if (*q != NUL) - STRCPY(remain, q - 1); + mch_memmove(remain, q - 1, STRLEN(q - 1) + 1); else { vim_free(remain); @@ -13919,6 +14079,8 @@ /* If 'n' flag is used: restore cursor position. */ if (flags & SP_NOMOVE) curwin->w_cursor = save_cursor; + else + curwin->w_set_curswant = TRUE; theend: p_ws = save_p_ws; @@ -14498,6 +14660,66 @@ } /* + * "setmatches()" function + */ + static void +f_setmatches(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ +#ifdef FEAT_SEARCH_EXTRA + list_T *l; + listitem_T *li; + dict_T *d; + + rettv->vval.v_number = -1; + if (argvars[0].v_type != VAR_LIST) + { + EMSG(_(e_listreq)); + return; + } + if ((l = argvars[0].vval.v_list) != NULL) + { + + /* To some extent make sure that we are dealing with a list from + * "getmatches()". */ + li = l->lv_first; + while (li != NULL) + { + if (li->li_tv.v_type != VAR_DICT + || (d = li->li_tv.vval.v_dict) == NULL) + { + EMSG(_(e_invarg)); + return; + } + if (!(dict_find(d, (char_u *)"group", -1) != NULL + && dict_find(d, (char_u *)"pattern", -1) != NULL + && dict_find(d, (char_u *)"priority", -1) != NULL + && dict_find(d, (char_u *)"id", -1) != NULL)) + { + EMSG(_(e_invarg)); + return; + } + li = li->li_next; + } + + clear_matches(curwin); + li = l->lv_first; + while (li != NULL) + { + d = li->li_tv.vval.v_dict; + match_add(curwin, get_dict_string(d, (char_u *)"group", FALSE), + get_dict_string(d, (char_u *)"pattern", FALSE), + (int)get_dict_number(d, (char_u *)"priority"), + (int)get_dict_number(d, (char_u *)"id")); + li = li->li_next; + } + rettv->vval.v_number = 0; + } +#endif +} + +/* * "setpos()" function */ /*ARGSUSED*/ @@ -14785,6 +15007,10 @@ p1 = tv2string(&(*(listitem_T **)s1)->li_tv, &tofree1, numbuf1, 0); p2 = tv2string(&(*(listitem_T **)s2)->li_tv, &tofree2, numbuf2, 0); + if (p1 == NULL) + p1 = (char_u *)""; + if (p2 == NULL) + p2 = (char_u *)""; if (item_compare_ic) res = STRICMP(p1, p2); else @@ -15274,7 +15500,8 @@ rettv->v_type = VAR_STRING; rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf, 0); - if (tofree == NULL) + /* Make a copy if we have a value but it's not in allocate memory. */ + if (rettv->vval.v_string != NULL && tofree == NULL) rettv->vval.v_string = vim_strsave(rettv->vval.v_string); } @@ -16497,9 +16724,9 @@ * Returns NULL when there is an error. */ static pos_T * -var2fpos(varp, lnum, fnum) +var2fpos(varp, dollar_lnum, fnum) typval_T *varp; - int lnum; /* TRUE when $ is last line */ + int dollar_lnum; /* TRUE when $ is last line */ int *fnum; /* set to fnum for '0, 'A, etc. */ { char_u *name; @@ -16512,6 +16739,7 @@ list_T *l; int len; int error = FALSE; + listitem_T *li; l = varp->vval.v_list; if (l == NULL) @@ -16527,6 +16755,14 @@ if (error) return NULL; len = (long)STRLEN(ml_get(pos.lnum)); + + /* We accept "$" for the column number: last column. */ + li = list_find(l, 1L); + if (li != NULL && li->li_tv.v_type == VAR_STRING + && li->li_tv.vval.v_string != NULL + && STRCMP(li->li_tv.vval.v_string, "$") == 0) + pos.col = len + 1; + /* Accept a position up to the NUL after the line. */ if (pos.col == 0 || (int)pos.col > len + 1) return NULL; /* invalid column number */ @@ -16559,7 +16795,7 @@ pos.coladd = 0; #endif - if (name[0] == 'w' && lnum) + if (name[0] == 'w' && dollar_lnum) { pos.col = 0; if (name[1] == '0') /* "w0": first visible line */ @@ -16577,7 +16813,7 @@ } else if (name[0] == '$') /* last column or line */ { - if (lnum) + if (dollar_lnum) { pos.lnum = curbuf->b_ml.ml_line_count; pos.col = 0; @@ -17798,9 +18034,10 @@ * List the value of one internal variable. */ static void -list_one_var(v, prefix) +list_one_var(v, prefix, first) dictitem_T *v; char_u *prefix; + int *first; { char_u *tofree; char_u *s; @@ -17808,18 +18045,21 @@ s = echo_string(&v->di_tv, &tofree, numbuf, ++current_copyID); list_one_var_a(prefix, v->di_key, v->di_tv.v_type, - s == NULL ? (char_u *)"" : s); + s == NULL ? (char_u *)"" : s, first); vim_free(tofree); } static void -list_one_var_a(prefix, name, type, string) +list_one_var_a(prefix, name, type, string, first) char_u *prefix; char_u *name; int type; char_u *string; + int *first; /* when TRUE clear rest of screen and set to FALSE */ { - msg_attr(prefix, 0); /* don't use msg(), it overwrites "v:statusmsg" */ + /* don't use msg() or msg_attr() to avoid overwriting "v:statusmsg" */ + msg_start(); + msg_puts(prefix); if (name != NULL) /* "a:" vars don't have a name stored */ msg_puts(name); msg_putchar(' '); @@ -17847,6 +18087,11 @@ if (type == VAR_FUNC) msg_puts((char_u *)"()"); + if (*first) + { + msg_clr_eos(); + *first = FALSE; + } } /* @@ -19136,6 +19381,28 @@ goto theend; } + /* Check if the name is a Funcref. If so, use the value. */ + if (lv.ll_exp_name != NULL) + { + len = (int)STRLEN(lv.ll_exp_name); + name = deref_func_name(lv.ll_exp_name, &len); + if (name == lv.ll_exp_name) + name = NULL; + } + else + { + len = (int)(end - *pp); + name = deref_func_name(*pp, &len); + if (name == *pp) + name = NULL; + } + if (name != NULL) + { + name = vim_strsave(name); + *pp = end; + goto theend; + } + if (lv.ll_exp_name != NULL) { len = (int)STRLEN(lv.ll_exp_name); @@ -19969,6 +20236,7 @@ char_u buf[MSG_BUF_LEN]; char_u numbuf2[NUMBUFLEN]; char_u *tofree; + char_u *s; msg_puts((char_u *)"("); for (i = 0; i < argcount; ++i) @@ -19979,10 +20247,13 @@ msg_outnum((long)argvars[i].vval.v_number); else { - trunc_string(tv2string(&argvars[i], &tofree, - numbuf2, 0), buf, MSG_BUF_CLEN); - msg_puts(buf); - vim_free(tofree); + s = tv2string(&argvars[i], &tofree, numbuf2, 0); + if (s != NULL) + { + trunc_string(s, buf, MSG_BUF_CLEN); + msg_puts(buf); + vim_free(tofree); + } } } msg_puts((char_u *)")"); @@ -20060,14 +20331,18 @@ char_u buf[MSG_BUF_LEN]; char_u numbuf2[NUMBUFLEN]; char_u *tofree; + char_u *s; /* The value may be very long. Skip the middle part, so that we * have some idea how it starts and ends. smsg() would always * truncate it at the end. */ - trunc_string(tv2string(fc.rettv, &tofree, numbuf2, 0), - buf, MSG_BUF_CLEN); - smsg((char_u *)_("%s returning %s"), sourcing_name, buf); - vim_free(tofree); + s = tv2string(fc.rettv, &tofree, numbuf2, 0); + if (s != NULL) + { + trunc_string(s, buf, MSG_BUF_CLEN); + smsg((char_u *)_("%s returning %s"), sourcing_name, buf); + vim_free(tofree); + } } msg_puts((char_u *)"\n"); /* don't overwrite this either */ @@ -21034,14 +21309,27 @@ *usedlen += 2; s = get_past_head(*fnamep); while (tail > s && after_pathsep(s, tail)) - --tail; + mb_ptr_back(*fnamep, tail); *fnamelen = (int)(tail - *fnamep); #ifdef VMS if (*fnamelen > 0) *fnamelen += 1; /* the path separator is part of the path */ #endif - while (tail > s && !after_pathsep(s, tail)) - mb_ptr_back(*fnamep, tail); + if (*fnamelen == 0) + { + /* Result is empty. Turn it into "." to make ":cd %:h" work. */ + p = vim_strsave((char_u *)"."); + if (p == NULL) + return -1; + vim_free(*bufp); + *bufp = *fnamep = tail = p; + *fnamelen = 1; + } + else + { + while (tail > s && !after_pathsep(s, tail)) + mb_ptr_back(*fnamep, tail); + } } /* ":8" - shortname */ diff -Naur vim71.orig/src/ex_cmds.c vim71/src/ex_cmds.c --- vim71.orig/src/ex_cmds.c 2007-05-07 19:41:01.000000000 +0000 +++ vim71/src/ex_cmds.c 2007-10-24 22:09:09.000000000 +0000 @@ -408,7 +408,11 @@ goto sortend; } *s = NUL; - regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC); + /* Use last search pattern if sort pattern is empty. */ + if (s == p + 1 && last_search_pat() != NULL) + regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC); + else + regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC); if (regmatch.regprog == NULL) goto sortend; p = s; /* continue after the regexp */ @@ -2912,22 +2916,35 @@ } /* - * Check if a buffer is read-only. Ask for overruling in a dialog. - * Return TRUE and give an error message when the buffer is readonly. + * Check if a buffer is read-only (either 'readonly' option is set or file is + * read-only). Ask for overruling in a dialog. Return TRUE and give an error + * message when the buffer is readonly. */ static int check_readonly(forceit, buf) int *forceit; buf_T *buf; { - if (!*forceit && buf->b_p_ro) + struct stat st; + + /* Handle a file being readonly when the 'readonly' option is set or when + * the file exists and permissions are read-only. + * We will send 0777 to check_file_readonly(), as the "perm" variable is + * important for device checks but not here. */ + if (!*forceit && (buf->b_p_ro + || (mch_stat((char *)buf->b_ffname, &st) >= 0 + && check_file_readonly(buf->b_ffname, 0777)))) { #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL) { char_u buff[IOSIZE]; - dialog_msg(buff, _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"), + if (buf->b_p_ro) + dialog_msg(buff, _("'readonly' option is set for \"%s\".\nDo you wish to write anyway?"), + buf->b_fname); + else + dialog_msg(buff, _("File permissions of \"%s\" are read-only.\nIt may still be possible to write it.\nDo you wish to try?"), buf->b_fname); if (vim_dialog_yesno(VIM_QUESTION, NULL, buff, 2) == VIM_YES) @@ -2941,9 +2958,14 @@ } else #endif + if (buf->b_p_ro) EMSG(_(e_readonly)); + else + EMSG2(_("E505: \"%s\" is read-only (add ! to override)"), + buf->b_fname); return TRUE; } + return FALSE; } @@ -2952,7 +2974,7 @@ * 'fnum' is the number of the file, if zero use ffname/sfname. * * Return 1 for "normal" error, 2 for "not written" error, 0 for success - * -1 for succesfully opening another file. + * -1 for successfully opening another file. * 'lnum' is the line number for the cursor in the new file (if non-zero). */ int @@ -3367,7 +3389,7 @@ * was in this window (or another window). If not used * before, reset the local window options to the global * values. Also restores old folding stuff. */ - get_winopts(buf); + get_winopts(curbuf); #ifdef FEAT_SPELL did_get_winopts = TRUE; #endif @@ -3562,9 +3584,20 @@ curwin_init(); #ifdef FEAT_FOLDING - /* It's like all lines in the buffer changed. Need to update - * automatic folding. */ + /* It's possible that all lines in the buffer changed. Need to update + * automatic folding for all windows where it's used. */ +# ifdef FEAT_WINDOWS + { + win_T *win; + tabpage_T *tp; + + FOR_ALL_TAB_WINDOWS(tp, win) + if (win->w_buffer == curbuf) + foldUpdateAll(win); + } +# else foldUpdateAll(curwin); +# endif #endif /* Change directories when the 'acd' option is set. */ @@ -3649,8 +3682,8 @@ #ifdef FEAT_SPELL /* If the window options were changed may need to set the spell language. * Can only do this after the buffer has been properly setup. */ - if (did_get_winopts && curwin->w_p_spell && *buf->b_p_spl != NUL) - did_set_spelllang(buf); + if (did_get_winopts && curwin->w_p_spell && *curbuf->b_p_spl != NUL) + did_set_spelllang(curbuf); #endif if (command == NULL) @@ -3754,7 +3787,7 @@ workshop_file_opened((char *)curbuf->b_ffname, curbuf->b_p_ro); # endif # ifdef FEAT_NETBEANS_INTG - if (usingNetbeans & ((flags & ECMD_SET_HELP) != ECMD_SET_HELP)) + if (usingNetbeans && ((flags & ECMD_SET_HELP) != ECMD_SET_HELP)) netbeans_file_opened(curbuf); # endif } @@ -4294,6 +4327,7 @@ do_error = TRUE; do_print = FALSE; do_count = FALSE; + do_number = FALSE; do_ic = 0; } while (*cmd) @@ -4464,7 +4498,7 @@ * * The new text is built up in new_start[]. It has some extra * room to avoid using alloc()/free() too often. new_start_len is - * the lenght of the allocated memory at new_start. + * the length of the allocated memory at new_start. * * Make a copy of the old line, so it won't be taken away when * updating the screen or handling a multi-line match. The "old_" @@ -4635,7 +4669,7 @@ #endif ++no_mapping; /* don't map this key */ ++allow_keys; /* allow special keys */ - i = safe_vgetc(); + i = plain_vgetc(); --allow_keys; --no_mapping; @@ -6351,9 +6385,9 @@ for (i = 0; i < ga.ga_len; ++i) { s = ((char_u **)ga.ga_data)[i]; - if (STRNCMP(s, "help-tags", 9) == 0) + if (STRNCMP(s, "help-tags\t", 10) == 0) /* help-tags entry was added in formatted form */ - fprintf(fd_tags, (char *)s); + fputs((char *)s, fd_tags); else { fprintf(fd_tags, "%s\t/*", s); diff -Naur vim71.orig/src/ex_docmd.c vim71/src/ex_docmd.c --- vim71.orig/src/ex_docmd.c 2007-05-07 19:49:38.000000000 +0000 +++ vim71/src/ex_docmd.c 2007-10-24 22:09:09.000000000 +0000 @@ -133,6 +133,7 @@ static void get_flags __ARGS((exarg_T *eap)); #if !defined(FEAT_PERL) || !defined(FEAT_PYTHON) || !defined(FEAT_TCL) \ || !defined(FEAT_RUBY) || !defined(FEAT_MZSCHEME) +# define HAVE_EX_SCRIPT_NI static void ex_script_ni __ARGS((exarg_T *eap)); #endif static char_u *invalid_range __ARGS((exarg_T *eap)); @@ -2118,7 +2119,11 @@ #ifdef FEAT_USR_CMDS !USER_CMDIDX(ea.cmdidx) && #endif - cmdnames[ea.cmdidx].cmd_func == ex_ni); + (cmdnames[ea.cmdidx].cmd_func == ex_ni +#ifdef HAVE_EX_SCRIPT_NI + || cmdnames[ea.cmdidx].cmd_func == ex_script_ni +#endif + )); #ifndef FEAT_EVAL /* @@ -3276,39 +3281,65 @@ if (ea.argt & XFILE) { - int in_quote = FALSE; - char_u *bow = NULL; /* Beginning of word */ + int c; + int in_quote = FALSE; + char_u *bow = NULL; /* Beginning of word */ /* * Allow spaces within back-quotes to count as part of the argument * being expanded. */ xp->xp_pattern = skipwhite(arg); - for (p = xp->xp_pattern; *p; ) + p = xp->xp_pattern; + while (*p != NUL) { - if (*p == '\\' && p[1] != NUL) +#ifdef FEAT_MBYTE + if (has_mbyte) + c = mb_ptr2char(p); + else +#endif + c = *p; + if (c == '\\' && p[1] != NUL) ++p; + else if (c == '`') + { + if (!in_quote) + { + xp->xp_pattern = p; + bow = p + 1; + } + in_quote = !in_quote; + } #ifdef SPACE_IN_FILENAME - else if (vim_iswhite(*p) && (!(ea.argt & NOSPC) || usefilter)) + else if (!vim_isfilec_or_wc(c) + && (!(ea.argt & NOSPC) || usefilter)) #else - else if (vim_iswhite(*p)) + else if (!vim_isfilec_or_wc(c)) #endif { - p = skipwhite(p); + while (*p != NUL) + { +#ifdef FEAT_MBYTE + if (has_mbyte) + c = mb_ptr2char(p); + else +#endif + c = *p; + if (c == '`' || vim_isfilec_or_wc(c)) + break; +#ifdef FEAT_MBYTE + if (has_mbyte) + len = (*mb_ptr2len)(p); + else +#endif + len = 1; + mb_ptr_adv(p); + } if (in_quote) bow = p; else xp->xp_pattern = p; - --p; - } - else if (*p == '`') - { - if (!in_quote) - { - xp->xp_pattern = p; - bow = p + 1; - } - in_quote = !in_quote; + p -= len; } mb_ptr_adv(p); } @@ -3401,14 +3432,13 @@ case CMD_windo: return arg; -#ifdef FEAT_SEARCH_EXTRA +#ifdef FEAT_CMDL_COMPL +# ifdef FEAT_SEARCH_EXTRA case CMD_match: if (*arg == NUL || !ends_excmd(*arg)) { - /* Dummy call to clear variables. */ - set_context_in_highlight_cmd(xp, (char_u *)"link n"); - xp->xp_context = EXPAND_HIGHLIGHT; - xp->xp_pattern = arg; + /* also complete "None" */ + set_context_in_echohl_cmd(xp, arg); arg = skipwhite(skiptowhite(arg)); if (*arg != NUL) { @@ -3417,9 +3447,8 @@ } } return find_nextcmd(arg); -#endif +# endif -#ifdef FEAT_CMDL_COMPL /* * All completion for the +cmdline_compl feature goes here. */ @@ -3617,8 +3646,7 @@ break; case CMD_echohl: - xp->xp_context = EXPAND_HIGHLIGHT; - xp->xp_pattern = arg; + set_context_in_echohl_cmd(xp, arg); break; #endif case CMD_highlight: @@ -3997,8 +4025,7 @@ eap->errmsg = (char_u *)N_("E319: Sorry, the command is not available in this version"); } -#if !defined(FEAT_PERL) || !defined(FEAT_PYTHON) || !defined(FEAT_TCL) \ - || !defined(FEAT_RUBY) || !defined(FEAT_MZSCHEME) +#ifdef HAVE_EX_SCRIPT_NI /* * Function called for script command which is Not Implemented. NI! * Skips over ":perl <arg, '~') != NULL) { expand_env_esc(eap->arg, NameBuff, MAXPATHL, - TRUE, NULL); + TRUE, TRUE, NULL); has_wildcards = mch_has_wildcard(NameBuff); p = NameBuff; } @@ -4492,7 +4519,8 @@ if (eap->argt & (USECTRLV | XFILE)) ++p; /* skip CTRL-V and next char */ else - STRCPY(p, p + 1); /* remove CTRL-V and skip next char */ + /* remove CTRL-V and skip next char */ + mch_memmove(p, p + 1, STRLEN(p)); if (*p == NUL) /* stop at NUL after CTRL-V */ break; } @@ -8399,21 +8427,17 @@ || *arg == '"') { redir_reg = *arg++; - if (*arg == '>' && arg[1] == '>') + if (*arg == '>' && arg[1] == '>') /* append */ arg += 2; - else if ((*arg == NUL || (*arg == '>' && arg[1] == NUL)) && - (islower(redir_reg) -# ifdef FEAT_CLIPBOARD - || redir_reg == '*' - || redir_reg == '+' -# endif - || redir_reg == '"')) + else { + /* Can use both "@a" and "@a>". */ if (*arg == '>') arg++; - - /* make register empty */ - write_reg_contents(redir_reg, (char_u *)"", -1, FALSE); + /* Make register empty when not using @A-@Z and the + * command is valid. */ + if (*arg == NUL && !isupper(redir_reg)) + write_reg_contents(redir_reg, (char_u *)"", -1, FALSE); } } if (*arg != NUL) @@ -10816,12 +10840,13 @@ exarg_T *eap; { char_u *p; + char_u *g = NULL; char_u *end; int c; - int mi; + int id; if (eap->line2 <= 3) - mi = eap->line2 - 1; + id = eap->line2; else { EMSG(e_invcmd); @@ -10830,13 +10855,7 @@ /* First clear any old pattern. */ if (!eap->skip) - { - vim_free(curwin->w_match[mi].regprog); - curwin->w_match[mi].regprog = NULL; - vim_free(curwin->w_match_pat[mi]); - curwin->w_match_pat[mi] = NULL; - redraw_later(SOME_VALID); /* always need a redraw */ - } + match_delete(curwin, id, FALSE); if (ends_excmd(*eap->arg)) end = eap->arg; @@ -10847,15 +10866,7 @@ { p = skiptowhite(eap->arg); if (!eap->skip) - { - curwin->w_match_id[mi] = syn_namen2id(eap->arg, - (int)(p - eap->arg)); - if (curwin->w_match_id[mi] == 0) - { - EMSG2(_(e_nogroup), eap->arg); - return; - } - } + g = vim_strnsave(eap->arg, (int)(p - eap->arg)); p = skipwhite(p); if (*p == NUL) { @@ -10879,14 +10890,8 @@ c = *end; *end = NUL; - curwin->w_match[mi].regprog = vim_regcomp(p + 1, RE_MAGIC); - if (curwin->w_match[mi].regprog == NULL) - { - EMSG2(_(e_invarg2), p); - *end = c; - return; - } - curwin->w_match_pat[mi] = vim_strsave(p + 1); + match_add(curwin, g, p + 1, 10, id); + vim_free(g); *end = c; } } diff -Naur vim71.orig/src/ex_eval.c vim71/src/ex_eval.c --- vim71.orig/src/ex_eval.c 2007-05-07 19:47:50.000000000 +0000 +++ vim71/src/ex_eval.c 2007-10-24 22:09:07.000000000 +0000 @@ -1551,7 +1551,7 @@ } save_cpo = p_cpo; p_cpo = (char_u *)""; - regmatch.regprog = vim_regcomp(pat, TRUE); + regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING); regmatch.rm_ic = FALSE; if (end != NULL) *end = save_char; diff -Naur vim71.orig/src/ex_getln.c vim71/src/ex_getln.c --- vim71.orig/src/ex_getln.c 2007-05-07 19:47:23.000000000 +0000 +++ vim71/src/ex_getln.c 2007-10-24 22:09:09.000000000 +0000 @@ -268,7 +268,9 @@ { xpc.xp_context = ccline.xp_context; xpc.xp_pattern = ccline.cmdbuff; +# if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) xpc.xp_arg = ccline.xp_arg; +# endif } #endif @@ -484,7 +486,8 @@ if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu) { /* Hitting after "emenu Name.": complete submenu */ - if (ccline.cmdbuff[ccline.cmdpos - 1] == '.' && c == K_DOWN) + if (c == K_DOWN && ccline.cmdpos > 0 + && ccline.cmdbuff[ccline.cmdpos - 1] == '.') c = p_wc; else if (c == K_UP) { @@ -533,9 +536,11 @@ upseg[3] = PATHSEP; upseg[4] = NUL; - if (ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP - && c == K_DOWN - && (ccline.cmdbuff[ccline.cmdpos - 2] != '.' + if (c == K_DOWN + && ccline.cmdpos > 0 + && ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP + && (ccline.cmdpos < 3 + || ccline.cmdbuff[ccline.cmdpos - 2] != '.' || ccline.cmdbuff[ccline.cmdpos - 3] != '.')) { /* go down a directory */ @@ -636,7 +641,7 @@ { ++no_mapping; ++allow_keys; - c = safe_vgetc(); + c = plain_vgetc(); --no_mapping; --allow_keys; /* CTRL-\ e doesn't work when obtaining an expression. */ @@ -730,8 +735,8 @@ /* In Ex mode a backslash escapes a newline. */ if (exmode_active && c != ESC - && ccline.cmdpos > 0 && ccline.cmdpos == ccline.cmdlen + && ccline.cmdpos > 0 && ccline.cmdbuff[ccline.cmdpos - 1] == '\\') { if (c == K_KENTER) @@ -1086,11 +1091,11 @@ #endif putcmdline('"', TRUE); ++no_mapping; - i = c = safe_vgetc(); /* CTRL-R */ + i = c = plain_vgetc(); /* CTRL-R */ if (i == Ctrl_O) i = Ctrl_R; /* CTRL-R CTRL-O == CTRL-R CTRL-R */ if (i == Ctrl_R) - c = safe_vgetc(); /* CTRL-R CTRL-R */ + c = plain_vgetc(); /* CTRL-R CTRL-R */ --no_mapping; #ifdef FEAT_EVAL /* @@ -2090,11 +2095,11 @@ garray_T line_ga; char_u *pend; int startcol = 0; - int c1; + int c1 = 0; int escaped = FALSE; /* CTRL-V typed */ int vcol = 0; char_u *p; - int prev_char = 0; + int prev_char; /* Switch cursor on now. This avoids that it happens after the "\n", which * confuses the system function that computes tabstops. */ @@ -2147,6 +2152,7 @@ /* Get one character at a time. Don't use inchar(), it can't handle * special characters. */ + prev_char = c1; c1 = vgetc(); /* @@ -2204,7 +2210,6 @@ redraw: /* redraw the line */ msg_col = startcol; - windgoto(msg_row, msg_col); vcol = 0; for (p = (char_u *)line_ga.ga_data; p < (char_u *)line_ga.ga_data + line_ga.ga_len; ++p) @@ -2223,6 +2228,7 @@ } } msg_clr_eos(); + windgoto(msg_row, msg_col); continue; } @@ -2268,7 +2274,6 @@ if (IS_SPECIAL(c1)) c1 = '?'; ((char_u *)line_ga.ga_data)[line_ga.ga_len] = c1; - prev_char = c1; if (c1 == '\n') msg_putchar('\n'); else if (c1 == TAB) @@ -3311,6 +3316,10 @@ * Return a pointer to alloced memory containing the new string. * Return NULL for failure. * + * "orig" is the originally expanded string, copied to allocated memory. It + * should either be kept in orig_save or freed. When "mode" is WILD_NEXT or + * WILD_PREV "orig" should be NULL. + * * Results are cached in xp->xp_files and xp->xp_numfiles, except when "mode" * is WILD_EXPAND_FREE or WILD_ALL. * @@ -3395,7 +3404,7 @@ return NULL; } -/* free old names */ + /* free old names */ if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) { FreeWild(xp->xp_numfiles, xp->xp_files); @@ -3536,6 +3545,10 @@ if (mode == WILD_EXPAND_FREE || mode == WILD_ALL) ExpandCleanup(xp); + /* Free "orig" if it wasn't stored in "orig_save". */ + if (orig != orig_save) + vim_free(orig); + return ss; } @@ -4148,13 +4161,19 @@ #ifdef FEAT_EVAL if (ccline.cmdfirstc == '=') + { +# ifdef FEAT_CMDL_COMPL /* pass CMD_SIZE because there is no real command */ set_context_for_expression(xp, str, CMD_SIZE); +# endif + } else if (ccline.input_fn) { xp->xp_context = ccline.xp_context; xp->xp_pattern = ccline.cmdbuff; +# if defined(FEAT_USR_CMDS) && defined(FEAT_CMDL_COMPL) xp->xp_arg = ccline.xp_arg; +# endif } else #endif @@ -4295,10 +4314,11 @@ && pat[i + 1] == '\\' && pat[i + 2] == '\\' && pat[i + 3] == ' ') - STRCPY(pat + i, pat + i + 3); + mch_memmove(pat + i, pat + i + 3, + STRLEN(pat + i + 3) + 1); if (xp->xp_backslash == XP_BS_ONE && pat[i + 1] == ' ') - STRCPY(pat + i, pat + i + 1); + mch_memmove(pat + i, pat + i + 1, STRLEN(pat + i)); } } @@ -4502,6 +4522,12 @@ if (xp->xp_context != EXPAND_MENUNAMES && xp->xp_context != EXPAND_MENUS) sort_strings(*file, *num_file); +#ifdef FEAT_CMDL_COMPL + /* Reset the variables used for special highlight names expansion, so that + * they don't show up when getting normal highlight names by ID. */ + reset_expand_highlight(); +#endif + return OK; } @@ -4535,7 +4561,7 @@ pat = vim_strsave(filepat); for (i = 0; pat[i]; ++i) if (pat[i] == '\\' && pat[i + 1] == ' ') - STRCPY(pat + i, pat + i + 1); + mch_memmove(pat + i, pat + i + 1, STRLEN(pat + i)); flags |= EW_FILE | EW_EXEC; @@ -5907,7 +5933,7 @@ # ifdef FEAT_AUTOCMD /* Don't execute autocommands while creating the window. */ - ++autocmd_block; + block_autocmds(); # endif /* don't use a new tab page */ cmdmod.tab = 0; @@ -5916,6 +5942,9 @@ if (win_split((int)p_cwh, WSP_BOT) == FAIL) { beep_flush(); +# ifdef FEAT_AUTOCMD + unblock_autocmds(); +# endif return K_IGNORE; } cmdwin_type = ccline.cmdfirstc; @@ -5938,7 +5967,7 @@ # ifdef FEAT_AUTOCMD /* Do execute autocommands for setting the filetype (load syntax). */ - --autocmd_block; + unblock_autocmds(); # endif /* Showing the prompt may have set need_wait_return, reset it. */ @@ -6092,7 +6121,7 @@ # ifdef FEAT_AUTOCMD /* Don't execute autocommands while deleting the window. */ - ++autocmd_block; + block_autocmds(); # endif wp = curwin; bp = curbuf; @@ -6104,7 +6133,7 @@ win_size_restore(&winsizes); # ifdef FEAT_AUTOCMD - --autocmd_block; + unblock_autocmds(); # endif } diff -Naur vim71.orig/src/feature.h vim71/src/feature.h --- vim71.orig/src/feature.h 2007-05-07 19:33:19.000000000 +0000 +++ vim71/src/feature.h 2007-10-24 22:09:07.000000000 +0000 @@ -673,7 +673,7 @@ # define ESC_CHG_TO_ENG_MODE /* if defined, when ESC pressed, * turn to english mode */ -# if !defined(FEAT_XFONTSET) && defined(HAVE_X11) +# if !defined(FEAT_XFONTSET) && defined(HAVE_X11) && !defined(HAVE_GTK2) # define FEAT_XFONTSET /* Hangul input requires xfontset */ # endif # if defined(FEAT_XIM) && !defined(LINT) diff -Naur vim71.orig/src/fileio.c vim71/src/fileio.c --- vim71.orig/src/fileio.c 2007-05-10 11:29:44.000000000 +0000 +++ vim71/src/fileio.c 2007-10-24 22:09:09.000000000 +0000 @@ -44,6 +44,10 @@ /* Is there any system that doesn't have access()? */ #define USE_MCH_ACCESS +#if defined(sun) && defined(S_ISCHR) +# define OPEN_CHR_FILES +static int is_dev_fd_file(char_u *fname); +#endif #ifdef FEAT_MBYTE static char_u *next_fenc __ARGS((char_u **pp)); # ifdef FEAT_EVAL @@ -406,6 +410,10 @@ # ifdef S_ISSOCK && !S_ISSOCK(perm) /* ... or socket */ # endif +# ifdef OPEN_CHR_FILES + && !(S_ISCHR(perm) && is_dev_fd_file(fname)) + /* ... or a character special file named /dev/fd/ */ +# endif ) { if (S_ISDIR(perm)) @@ -424,7 +432,7 @@ */ if (!p_odev && mch_nodetype(fname) == NODE_WRITABLE) { - filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option"), 0); + filemess(curbuf, fname, (char_u *)_("is a device (disabled with 'opendevice' option)"), 0); msg_end(); msg_scroll = msg_save; return FAIL; @@ -646,6 +654,7 @@ curbuf->b_start_eol = TRUE; #ifdef FEAT_MBYTE curbuf->b_p_bomb = FALSE; + curbuf->b_start_bomb = FALSE; #endif } @@ -904,7 +913,10 @@ file_rewind = FALSE; #ifdef FEAT_MBYTE if (set_options) + { curbuf->b_p_bomb = FALSE; + curbuf->b_start_bomb = FALSE; + } conv_error = 0; #endif } @@ -1353,7 +1365,10 @@ size -= blen; mch_memmove(ptr, ptr + blen, (size_t)size); if (set_options) + { curbuf->b_p_bomb = TRUE; + curbuf->b_start_bomb = TRUE; + } } if (fio_flags == FIO_UCSBOM) @@ -2265,6 +2280,13 @@ } # endif # endif +# ifdef OPEN_CHR_FILES + if (S_ISCHR(perm)) /* or character special */ + { + STRCAT(IObuff, _("[character special]")); + c = TRUE; + } +# endif #endif if (curbuf->b_p_ro) { @@ -2464,6 +2486,25 @@ return OK; } +#ifdef OPEN_CHR_FILES +/* + * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+", + * which is the name of files used for process substitution output by + * some shells on some operating systems, e.g., bash on SunOS. + * Do not accept "/dev/fd/[012]", opening these may hang Vim. + */ + static int +is_dev_fd_file(fname) + char_u *fname; +{ + return (STRNCMP(fname, "/dev/fd/", 8) == 0 + && VIM_ISDIGIT(fname[8]) + && *skipdigits(fname + 9) == NUL + && (fname[9] != NUL + || (fname[8] != '0' && fname[8] != '1' && fname[8] != '2'))); +} +#endif + #ifdef FEAT_MBYTE /* @@ -2734,6 +2775,32 @@ #endif /* + * Return TRUE if a file appears to be read-only from the file permissions. + */ + int +check_file_readonly(fname, perm) + char_u *fname; /* full path to file */ + int perm; /* known permissions on file */ +{ +#ifndef USE_MCH_ACCESS + int fd = 0; +#endif + + return ( +#ifdef USE_MCH_ACCESS +# ifdef UNIX + (perm & 0222) == 0 || +# endif + mch_access((char *)fname, W_OK) +#else + (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0 + ? TRUE : (close(fd), FALSE) +#endif + ); +} + + +/* * buf_write() - write to file "fname" lines "start" through "end" * * We do our own buffering here because fwrite() is so slow. @@ -3219,17 +3286,8 @@ * Check if the file is really writable (when renaming the file to * make a backup we won't discover it later). */ - file_readonly = ( -# ifdef USE_MCH_ACCESS -# ifdef UNIX - (perm & 0222) == 0 || -# endif - mch_access((char *)fname, W_OK) -# else - (fd = mch_open((char *)fname, O_RDWR | O_EXTRA, 0)) < 0 - ? TRUE : (close(fd), FALSE) -# endif - ); + file_readonly = check_file_readonly(fname, (int)perm); + if (!forceit && file_readonly) { if (vim_strchr(p_cpo, CPO_FWRITE) != NULL) @@ -5495,6 +5553,8 @@ } #endif +#if defined(FEAT_VIMINFO) || defined(FEAT_BROWSE) || \ + defined(FEAT_QUICKFIX) || defined(PROTO) /* * Try to find a shortname by comparing the fullname with the current * directory. @@ -5548,6 +5608,7 @@ p = NULL; return p; } +#endif /* * Shorten filenames for all buffers. @@ -7107,6 +7168,7 @@ static event_T last_event; static int last_group; +static int autocmd_blocked = 0; /* block all autocmds */ /* * Show the autocommands for one AutoPat. @@ -8396,7 +8458,7 @@ * Quickly return if there are no autocommands for this event or * autocommands are blocked. */ - if (first_autopat[(int)event] == NULL || autocmd_block > 0) + if (first_autopat[(int)event] == NULL || autocmd_blocked > 0) goto BYPASS_AU; /* @@ -8710,6 +8772,40 @@ return retval; } +# ifdef FEAT_EVAL +static char_u *old_termresponse = NULL; +# endif + +/* + * Block triggering autocommands until unblock_autocmd() is called. + * Can be used recursively, so long as it's symmetric. + */ + void +block_autocmds() +{ +# ifdef FEAT_EVAL + /* Remember the value of v:termresponse. */ + if (autocmd_blocked == 0) + old_termresponse = get_vim_var_str(VV_TERMRESPONSE); +# endif + ++autocmd_blocked; +} + + void +unblock_autocmds() +{ + --autocmd_blocked; + +# ifdef FEAT_EVAL + /* When v:termresponse was set while autocommands were blocked, trigger + * the autocommands now. Esp. useful when executing a shell command + * during startup (vimdiff). */ + if (autocmd_blocked == 0 + && get_vim_var_str(VV_TERMRESPONSE) != old_termresponse) + apply_autocmds(EVENT_TERMRESPONSE, NULL, NULL, FALSE, curbuf); +# endif +} + /* * Find next autocommand pattern that matches. */ diff -Naur vim71.orig/src/fold.c vim71/src/fold.c --- vim71.orig/src/fold.c 2007-05-07 19:46:32.000000000 +0000 +++ vim71/src/fold.c 2007-10-24 22:09:09.000000000 +0000 @@ -858,7 +858,14 @@ || foldmethodIsDiff(wp) #endif || foldmethodIsSyntax(wp)) + { + int save_got_int = got_int; + + /* reset got_int here, otherwise it won't work */ + got_int = FALSE; foldUpdateIEMS(wp, top, bot); + got_int |= save_got_int; + } } /* foldUpdateAll() {{{2 */ diff -Naur vim71.orig/src/getchar.c vim71/src/getchar.c --- vim71.orig/src/getchar.c 2007-05-07 19:18:20.000000000 +0000 +++ vim71/src/getchar.c 2007-10-24 22:09:09.000000000 +0000 @@ -1596,8 +1596,16 @@ continue; } #endif - #ifdef FEAT_GUI + /* Handle focus event here, so that the caller doesn't need to + * know about it. Return K_IGNORE so that we loop once (needed if + * 'lazyredraw' is set). */ + if (c == K_FOCUSGAINED || c == K_FOCUSLOST) + { + ui_focus_change(c == K_FOCUSGAINED); + c = K_IGNORE; + } + /* Translate K_CSI to CSI. The special key is only used to avoid * it being recognized as the start of a special key. */ if (c == K_CSI) @@ -1741,6 +1749,22 @@ } /* + * Like safe_vgetc(), but loop to handle K_IGNORE. + * Also ignore scrollbar events. + */ + int +plain_vgetc() +{ + int c; + + do + { + c = safe_vgetc(); + } while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR); + return c; +} + +/* * Check if a character is available, such that vgetc() will not block. * If the next character is a special character or multi-byte, the returned * character is not valid!. diff -Naur vim71.orig/src/globals.h vim71/src/globals.h --- vim71.orig/src/globals.h 2007-05-07 19:44:26.000000000 +0000 +++ vim71/src/globals.h 2007-10-24 22:09:09.000000000 +0000 @@ -301,13 +301,17 @@ #endif #ifdef FEAT_EVAL -/* Garbage collection can only take place when we are sure there are no Lists +/* + * Garbage collection can only take place when we are sure there are no Lists * or Dictionaries being used internally. This is flagged with * "may_garbage_collect" when we are at the toplevel. * "want_garbage_collect" is set by the garbagecollect() function, which means - * we do garbage collection before waiting for a char at the toplevel. */ + * we do garbage collection before waiting for a char at the toplevel. + * "garbage_collect_at_exit" indicates garbagecollect(1) was called. + */ EXTERN int may_garbage_collect INIT(= FALSE); EXTERN int want_garbage_collect INIT(= FALSE); +EXTERN int garbage_collect_at_exit INIT(= FALSE); /* ID of script being sourced or was sourced to define the current function. */ EXTERN scid_T current_SID INIT(= 0); @@ -362,7 +366,6 @@ EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */ EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */ EXTERN int autocmd_no_leave INIT(= FALSE); /* *Leave autocmds disabled */ -EXTERN int autocmd_block INIT(= 0); /* block all autocmds */ EXTERN int modified_was_set; /* did ":set modified" */ EXTERN int did_filetype INIT(= FALSE); /* FileType event found */ EXTERN int keep_filetype INIT(= FALSE); /* value for did_filetype when @@ -801,7 +804,7 @@ EXTERN int (*mb_char2bytes) __ARGS((int c, char_u *buf)) INIT(= latin_char2bytes); EXTERN int (*mb_ptr2cells) __ARGS((char_u *p)) INIT(= latin_ptr2cells); EXTERN int (*mb_char2cells) __ARGS((int c)) INIT(= latin_char2cells); -EXTERN int (*mb_off2cells) __ARGS((unsigned off)) INIT(= latin_off2cells); +EXTERN int (*mb_off2cells) __ARGS((unsigned off, unsigned max_off)) INIT(= latin_off2cells); EXTERN int (*mb_ptr2char) __ARGS((char_u *p)) INIT(= latin_ptr2char); EXTERN int (*mb_head_off) __ARGS((char_u *base, char_u *p)) INIT(= latin_head_off); diff -Naur vim71.orig/src/gui.c vim71/src/gui.c --- vim71.orig/src/gui.c 2007-05-07 19:50:55.000000000 +0000 +++ vim71/src/gui.c 2007-10-24 22:09:09.000000000 +0000 @@ -1080,7 +1080,8 @@ cur_width = gui.char_width; } #ifdef FEAT_MBYTE - if (has_mbyte && (*mb_off2cells)(LineOffset[gui.row] + gui.col) > 1) + if (has_mbyte && (*mb_off2cells)(LineOffset[gui.row] + gui.col, + LineOffset[gui.row] + screen_Columns) > 1) { /* Double wide character. */ if (shape_table[idx].shape != SHAPE_VER) @@ -1159,7 +1160,7 @@ #endif # if defined(FEAT_GUI_TABLINE) && (defined(FEAT_GUI_MSWIN) \ - || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_MAC)) + || defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_MAC)) if (gui_has_tabline()) text_area_y += gui.tabline_height; #endif @@ -4518,7 +4519,18 @@ xim_set_focus(in_focus); # endif - ui_focus_change(in_focus); + /* Put events in the input queue only when allowed. + * ui_focus_change() isn't called directly, because it invokes + * autocommands and that must not happen asynchronously. */ + if (!hold_gui_events) + { + char_u bytes[3]; + + bytes[0] = CSI; + bytes[1] = KS_EXTRA; + bytes[2] = in_focus ? (int)KE_FOCUSGAINED : (int)KE_FOCUSLOST; + add_to_input_buf(bytes, 3); + } #endif } @@ -5117,7 +5129,7 @@ p = vim_strsave_escaped(fnames[i], (char_u *)"\\ \t\"|"); # endif if (p != NULL) - add_to_input_buf(p, (int)STRLEN(p)); + add_to_input_buf_csi(p, (int)STRLEN(p)); vim_free(p); vim_free(fnames[i]); } diff -Naur vim71.orig/src/gui_gtk.c vim71/src/gui_gtk.c --- vim71.orig/src/gui_gtk.c 2007-05-10 08:37:37.000000000 +0000 +++ vim71/src/gui_gtk.c 2007-10-24 22:09:09.000000000 +0000 @@ -53,8 +53,8 @@ # ifdef bindtextdomain # undef bindtextdomain # endif -# ifdef bindtextdomain_codeset -# undef bindtextdomain_codeset +# ifdef bind_textdomain_codeset +# undef bind_textdomain_codeset # endif # if defined(FEAT_GETTEXT) && !defined(ENABLE_NLS) # define ENABLE_NLS /* so the texts in the dialog boxes are translated */ @@ -1630,11 +1630,14 @@ */ /*ARGSUSED*/ static int -dlg_key_press_event(GtkWidget * widget, GdkEventKey * event, CancelData *data) +dlg_key_press_event(GtkWidget *widget, GdkEventKey *event, CancelData *data) { - /* Ignore hitting Enter when there is no default button. */ - if (data->ignore_enter && event->keyval == GDK_Return) + /* Ignore hitting Enter (or Space) when there is no default button. */ + if (data->ignore_enter && (event->keyval == GDK_Return + || event->keyval == ' ')) return TRUE; + else /* A different key was pressed, return to normal behavior */ + data->ignore_enter = FALSE; if (event->keyval != GDK_Escape && event->keyval != GDK_Return) return FALSE; @@ -2224,6 +2227,13 @@ { DialogInfo *di = (DialogInfo *)data; + /* Ignore hitting Enter (or Space) when there is no default button. */ + if (di->ignore_enter && (event->keyval == GDK_Return + || event->keyval == ' ')) + return TRUE; + else /* A different key was pressed, return to normal behavior */ + di->ignore_enter = FALSE; + /* Close the dialog when hitting "Esc". */ if (event->keyval == GDK_Escape) { diff -Naur vim71.orig/src/gui_gtk_x11.c vim71/src/gui_gtk_x11.c --- vim71.orig/src/gui_gtk_x11.c 2007-05-10 08:37:49.000000000 +0000 +++ vim71/src/gui_gtk_x11.c 2007-10-24 22:09:09.000000000 +0000 @@ -36,8 +36,8 @@ # ifdef bindtextdomain # undef bindtextdomain # endif -# ifdef bindtextdomain_codeset -# undef bindtextdomain_codeset +# ifdef bind_textdomain_codeset +# undef bind_textdomain_codeset # endif # if defined(FEAT_GETTEXT) && !defined(ENABLE_NLS) # define ENABLE_NLS /* so the texts in the dialog boxes are translated */ @@ -813,10 +813,15 @@ if (blink_state == BLINK_NONE) gui_mch_start_blink(); - /* make sure keyboard input goes to the draw area (if this is focus for a window) */ + /* make sure keyboard input goes to the draw area (if this is focus for a + * window) */ if (widget != gui.drawarea) gtk_widget_grab_focus(gui.drawarea); + /* make sure the input buffer is read */ + if (gtk_main_level() > 0) + gtk_main_quit(); + return TRUE; } @@ -829,6 +834,10 @@ if (blink_state != BLINK_NONE) gui_mch_stop_blink(); + /* make sure the input buffer is read */ + if (gtk_main_level() > 0) + gtk_main_quit(); + return TRUE; } @@ -2188,8 +2197,10 @@ escaped_filename = vim_strsave_escaped(filename, escape_chars); if (escaped_filename == NULL) return FALSE; - mksession_cmdline = g_strconcat("mksession ", (char *)escaped_filename, NULL); + mksession_cmdline = g_strconcat("mksession ", (char *)escaped_filename, + NULL); vim_free(escaped_filename); + /* * Use a reasonable hardcoded set of 'sessionoptions' flags to avoid * unpredictable effects when the session is saved automatically. Also, @@ -2199,7 +2210,7 @@ */ save_ssop_flags = ssop_flags; ssop_flags = (SSOP_BLANK|SSOP_CURDIR|SSOP_FOLDS|SSOP_GLOBALS - |SSOP_HELP|SSOP_OPTIONS|SSOP_WINSIZE); + |SSOP_HELP|SSOP_OPTIONS|SSOP_WINSIZE|SSOP_TABPAGES); do_cmdline_cmd((char_u *)"let Save_VV_this_session = v:this_session"); failed = (do_cmdline_cmd((char_u *)mksession_cmdline) == FAIL); @@ -3212,8 +3223,9 @@ { if (clicked_page == 0) { - /* Click after all tabs moves to next tab page. */ - if (send_tabline_event(0) && gtk_main_level() > 0) + /* Click after all tabs moves to next tab page. When "x" is + * small guess it's the left button. */ + if (send_tabline_event(x < 50 ? -1 : 0) && gtk_main_level() > 0) gtk_main_quit(); } #ifndef HAVE_GTK2 @@ -4032,6 +4044,8 @@ unsigned int w, h; int x = 0; int y = 0; + guint pixel_width; + guint pixel_height; mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h); @@ -4043,12 +4057,31 @@ p_window = h - 1; Rows = h; } + + pixel_width = (guint)(gui_get_base_width() + Columns * gui.char_width); + pixel_height = (guint)(gui_get_base_height() + Rows * gui.char_height); + +#ifdef HAVE_GTK2 + pixel_width += get_menu_tool_width(); + pixel_height += get_menu_tool_height(); +#endif + if (mask & (XValue | YValue)) + { + int w, h; + gui_mch_get_screen_dimensions(&w, &h); + h += p_ghr + get_menu_tool_height(); + w += get_menu_tool_width(); + if (mask & XNegative) + x += w - pixel_width; + if (mask & YNegative) + y += h - pixel_height; #ifdef HAVE_GTK2 gtk_window_move(GTK_WINDOW(gui.mainwin), x, y); #else gtk_widget_set_uposition(gui.mainwin, x, y); #endif + } vim_free(gui.geom); gui.geom = NULL; @@ -4059,14 +4092,6 @@ */ if (gtk_socket_id != 0 && (mask & WidthValue || mask & HeightValue)) { - guint pixel_width = (guint)(gui_get_base_width() + Columns * gui.char_width); - guint pixel_height = (guint)(gui_get_base_height() + Rows * gui.char_height); - -#ifdef HAVE_GTK2 - pixel_width += get_menu_tool_width(); - pixel_height += get_menu_tool_height(); -#endif - update_window_manager_hints(pixel_width, pixel_height); init_window_hints_state = 1; g_timeout_add(1000, check_startup_plug_hints, NULL); diff -Naur vim71.orig/src/if_cscope.c vim71/src/if_cscope.c --- vim71.orig/src/if_cscope.c 2007-03-11 14:29:57.000000000 +0000 +++ vim71/src/if_cscope.c 2007-10-24 22:09:09.000000000 +0000 @@ -24,11 +24,6 @@ /* not UNIX, must be WIN32 */ # include "vimio.h" # include -# include -# define STDIN_FILENO 0 -# define STDOUT_FILENO 1 -# define STDERR_FILENO 2 -# define pipe(fds) _pipe(fds, 256, O_TEXT|O_NOINHERIT) #endif #include "if_cscope.h" @@ -65,7 +60,7 @@ static char * cs_parse_results __ARGS((int cnumber, char *buf, int bufsize, char **context, char **linenumber, char **search)); static char * cs_pathcomponents __ARGS((char *path)); static void cs_print_tags_priv __ARGS((char **, char **, int)); -static int cs_read_prompt __ARGS((int )); +static int cs_read_prompt __ARGS((int)); static void cs_release_csp __ARGS((int, int freefnpp)); static int cs_reset __ARGS((exarg_T *eap)); static char * cs_resolve_file __ARGS((int, char *)); @@ -73,6 +68,8 @@ static csinfo_T csinfo[CSCOPE_MAX_CONNECTIONS]; +static int eap_arg_len; /* length of eap->arg, set in + cs_lookup_cmd() */ static cscmd_T cs_cmds[] = { { "add", cs_add, @@ -260,14 +257,7 @@ if ((p = cs_manage_matches(NULL, NULL, -1, Get)) == NULL) return TRUE; - - if ((int)strlen(p) > size) - { - strncpy((char *)buf, p, size - 1); - buf[size] = '\0'; - } - else - (void)strcpy((char *)buf, p); + vim_strncpy(buf, (char_u *)p, size - 1); return FALSE; } /* cs_fgets */ @@ -386,7 +376,7 @@ * PRIVATE: cs_add * * add cscope database or a directory name (to look for cscope.out) - * the the cscope connection list + * to the cscope connection list * * MAXPATHL 256 */ @@ -509,7 +499,7 @@ #if defined(UNIX) else if (S_ISREG(statbuf.st_mode) || S_ISLNK(statbuf.st_mode)) #else - /* substitute define S_ISREG from os_unix.h */ + /* WIN32 - substitute define S_ISREG from os_unix.h */ else if (((statbuf.st_mode) & S_IFMT) == S_IFREG) #endif { @@ -722,17 +712,32 @@ cs_create_connection(i) int i; { - int to_cs[2], from_cs[2], len; - char *prog, *cmd, *ppath = NULL; -#ifndef UNIX - int in_save, out_save, err_save; - long_i ph; -# ifdef FEAT_GUI - HWND activewnd = NULL; - HWND consolewnd = NULL; +#ifdef UNIX + int to_cs[2], from_cs[2]; +#endif + int len; + char *prog, *cmd, *ppath = NULL; +#ifdef WIN32 + int fd; + SECURITY_ATTRIBUTES sa; + PROCESS_INFORMATION pi; + STARTUPINFO si; + BOOL pipe_stdin = FALSE, pipe_stdout = FALSE; + HANDLE stdin_rd, stdout_rd; + HANDLE stdout_wr, stdin_wr; + BOOL created; +# ifdef __BORLANDC__ +# define OPEN_OH_ARGTYPE long +# else +# if (_MSC_VER >= 1300) +# define OPEN_OH_ARGTYPE intptr_t +# else +# define OPEN_OH_ARGTYPE long +# endif # endif #endif +#if defined(UNIX) /* * Cscope reads from to_cs[0] and writes to from_cs[1]; vi reads from * from_cs[0] and writes to to_cs[1]. @@ -753,18 +758,12 @@ return CSCOPE_FAILURE; } -#if defined(UNIX) switch (csinfo[i].pid = fork()) { case -1: (void)EMSG(_("E622: Could not fork for cscope")); goto err_closing; case 0: /* child: run cscope. */ -#else - in_save = dup(STDIN_FILENO); - out_save = dup(STDOUT_FILENO); - err_save = dup(STDERR_FILENO); -#endif if (dup2(to_cs[0], STDIN_FILENO) == -1) PERROR("cs_create_connection 1"); if (dup2(from_cs[1], STDOUT_FILENO) == -1) @@ -773,15 +772,32 @@ PERROR("cs_create_connection 3"); /* close unused */ -#if defined(UNIX) (void)close(to_cs[1]); (void)close(from_cs[0]); #else - /* On win32 we must close opposite ends because we are the parent */ - (void)close(to_cs[0]); - to_cs[0] = -1; - (void)close(from_cs[1]); - from_cs[1] = -1; + /* WIN32 */ + /* Create pipes to communicate with cscope */ + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + if (!(pipe_stdin = CreatePipe(&stdin_rd, &stdin_wr, &sa, 0)) + || !(pipe_stdout = CreatePipe(&stdout_rd, &stdout_wr, &sa, 0))) + { + (void)EMSG(_("E566: Could not create cscope pipes")); +err_closing: + if (pipe_stdin) + { + CloseHandle(stdin_rd); + CloseHandle(stdin_wr); + } + if (pipe_stdout) + { + CloseHandle(stdout_rd); + CloseHandle(stdout_wr); + } + return CSCOPE_FAILURE; + } #endif /* expand the cscope exec for env var's */ if ((prog = (char *)alloc(MAXPATHL + 1)) == NULL) @@ -789,6 +805,7 @@ #ifdef UNIX return CSCOPE_FAILURE; #else + /* WIN32 */ goto err_closing; #endif } @@ -805,6 +822,7 @@ #ifdef UNIX return CSCOPE_FAILURE; #else + /* WIN32 */ goto err_closing; #endif } @@ -823,6 +841,7 @@ #ifdef UNIX return CSCOPE_FAILURE; #else + /* WIN32 */ goto err_closing; #endif } @@ -831,6 +850,7 @@ #if defined(UNIX) (void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname); #else + /* WIN32 */ (void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname); #endif if (csinfo[i].ppath != NULL) @@ -856,60 +876,6 @@ exit(127); /* NOTREACHED */ default: /* parent. */ -#else -# ifdef FEAT_GUI - activewnd = GetForegroundWindow(); /* on win9x cscope steals focus */ - /* Dirty hack to hide annoying console window */ - if (AllocConsole()) - { - char *title; - title = (char *)alloc(1024); - if (title == NULL) - FreeConsole(); - else - { - GetConsoleTitle(title, 1024); /* save for future restore */ - SetConsoleTitle( - "GVIMCS{5499421B-CBEF-45b0-85EF-38167FDEA5C5}GVIMCS"); - Sleep(40); /* as stated in MS KB we must wait 40 ms */ - consolewnd = FindWindow(NULL, - "GVIMCS{5499421B-CBEF-45b0-85EF-38167FDEA5C5}GVIMCS"); - if (consolewnd != NULL) - ShowWindow(consolewnd, SW_HIDE); - SetConsoleTitle(title); - vim_free(title); - } - } -# endif - /* May be use &shell, &shellquote etc */ -# ifdef __BORLANDC__ - /* BCC 5.5 uses a different function name for spawnlp */ - ph = (long_i)spawnlp(P_NOWAIT, prog, cmd, NULL); -# else - ph = (long_i)_spawnlp(_P_NOWAIT, prog, cmd, NULL); -# endif - vim_free(prog); - vim_free(cmd); -# ifdef FEAT_GUI - /* Dirty hack part two */ - if (activewnd != NULL) - /* restoring focus */ - SetForegroundWindow(activewnd); - if (consolewnd != NULL) - FreeConsole(); - -# endif - if (ph == -1) - { - PERROR(_("cs_create_connection exec failed")); - (void)EMSG(_("E623: Could not spawn cscope process")); - goto err_closing; - } - /* else */ - csinfo[i].pid = 0; - csinfo[i].hProc = (HANDLE)ph; - -#endif /* !UNIX */ /* * Save the file descriptors for later duplication, and * reopen as streams. @@ -919,22 +885,54 @@ if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL) PERROR(_("cs_create_connection: fdopen for fr_fp failed")); -#if defined(UNIX) /* close unused */ (void)close(to_cs[0]); (void)close(from_cs[1]); break; } + #else - /* restore stdhandles */ - dup2(in_save, STDIN_FILENO); - dup2(out_save, STDOUT_FILENO); - dup2(err_save, STDERR_FILENO); - close(in_save); - close(out_save); - close(err_save); -#endif + /* WIN32 */ + /* Create a new process to run cscope and use pipes to talk with it */ + GetStartupInfo(&si); + si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; /* Hide child application window */ + si.hStdOutput = stdout_wr; + si.hStdError = stdout_wr; + si.hStdInput = stdin_rd; + created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, + NULL, NULL, &si, &pi); + vim_free(prog); + vim_free(cmd); + + if (!created) + { + PERROR(_("cs_create_connection exec failed")); + (void)EMSG(_("E623: Could not spawn cscope process")); + goto err_closing; + } + /* else */ + csinfo[i].pid = pi.dwProcessId; + csinfo[i].hProc = pi.hProcess; + CloseHandle(pi.hThread); + + /* TODO - tidy up after failure to create files on pipe handles. */ + if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdin_wr, + _O_TEXT|_O_APPEND)) < 0) + || ((csinfo[i].to_fp = _fdopen(fd, "w")) == NULL)) + PERROR(_("cs_create_connection: fdopen for to_fp failed")); + if (((fd = _open_osfhandle((OPEN_OH_ARGTYPE)stdout_rd, + _O_TEXT|_O_RDONLY)) < 0) + || ((csinfo[i].fr_fp = _fdopen(fd, "r")) == NULL)) + PERROR(_("cs_create_connection: fdopen for fr_fp failed")); + + /* Close handles for file descriptors inherited by the cscope process */ + CloseHandle(stdin_rd); + CloseHandle(stdout_wr); + +#endif /* !UNIX */ + return CSCOPE_SUCCESS; } /* cs_create_connection */ @@ -966,7 +964,7 @@ } pat = opt + strlen(opt) + 1; - if (pat == NULL || (pat != NULL && pat[0] == '\0')) + if (pat >= (char *)eap->arg + eap_arg_len) { cs_usage_msg(Find); return FALSE; @@ -1317,7 +1315,7 @@ #else /* compare pathnames first */ && ((fullpathcmp(csinfo[j].fname, fname, FALSE) & FPC_SAME) - /* if not Windows 9x, test index file atributes too */ + /* if not Windows 9x, test index file attributes too */ || (!mch_windows95() && csinfo[j].nVolume == bhfi.dwVolumeSerialNumber && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh @@ -1401,6 +1399,9 @@ if (eap->arg == NULL) return NULL; + /* Store length of eap->arg before it gets modified by strtok(). */ + eap_arg_len = STRLEN(eap->arg); + if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL) return NULL; @@ -2099,8 +2100,8 @@ /* * PRIVATE: cs_release_csp * - * does the actual free'ing for the cs ptr with an optional flag of whether - * or not to free the filename. called by cs_kill and cs_reset. + * Does the actual free'ing for the cs ptr with an optional flag of whether + * or not to free the filename. Called by cs_kill and cs_reset. */ static void cs_release_csp(i, freefnpp) @@ -2118,10 +2119,13 @@ (void)fputs("q\n", csinfo[i].to_fp); (void)fflush(csinfo[i].to_fp); } - /* give cscope chance to exit normally */ - if (csinfo[i].hProc != NULL - && WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT) - TerminateProcess(csinfo[i].hProc, 0); + if (csinfo[i].hProc != NULL) + { + /* Give cscope a chance to exit normally */ + if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT) + TerminateProcess(csinfo[i].hProc, 0); + CloseHandle(csinfo[i].hProc); + } #endif if (csinfo[i].fr_fp != NULL) @@ -2195,7 +2199,7 @@ cs_add_common(dblist[i], pplist[i], fllist[i]); if (p_csverbose) { - /* dont' use smsg_attr because want to display + /* don't use smsg_attr() because we want to display the * connection number in the same line as * "Added cscope database..." */ @@ -2304,6 +2308,21 @@ return CSCOPE_SUCCESS; } /* cs_show */ + +/* + * PUBLIC: cs_end + * + * Only called when VIM exits to quit any cscope sessions. + */ + void +cs_end() +{ + int i; + + for (i = 0; i < CSCOPE_MAX_CONNECTIONS; i++) + cs_release_csp(i, TRUE); +} + #endif /* FEAT_CSCOPE */ /* the end */ diff -Naur vim71.orig/src/if_cscope.h vim71/src/if_cscope.h --- vim71.orig/src/if_cscope.h 2005-06-30 17:14:22.000000000 +0000 +++ vim71/src/if_cscope.h 2007-10-24 22:09:09.000000000 +0000 @@ -72,7 +72,7 @@ ino_t st_ino; /* inode number of cscope db */ #else # if defined(WIN32) - int pid; /* Can't get pid so set it to 0 ;) */ + DWORD pid; /* PID of the connected cscope process. */ HANDLE hProc; /* cscope process handle */ DWORD nVolume; /* Volume serial number, instead of st_dev */ DWORD nIndexHigh; /* st_ino has no meaning in the Windows */ diff -Naur vim71.orig/src/if_mzsch.c vim71/src/if_mzsch.c --- vim71.orig/src/if_mzsch.c 2007-05-12 11:13:47.000000000 +0000 +++ vim71/src/if_mzsch.c 2007-10-24 22:09:07.000000000 +0000 @@ -308,6 +308,8 @@ static Scheme_Config *(*dll_scheme_current_config)(void); static Scheme_Object *(*dll_scheme_char_string_to_byte_string) (Scheme_Object *s); +static Scheme_Object *(*dll_scheme_char_string_to_path) + (Scheme_Object *s); # endif /* arrays are imported directly */ @@ -398,6 +400,8 @@ # define scheme_current_config dll_scheme_current_config # define scheme_char_string_to_byte_string \ dll_scheme_char_string_to_byte_string +# define scheme_char_string_to_path \ + dll_scheme_char_string_to_path # endif typedef struct @@ -498,6 +502,8 @@ {"scheme_current_config", (void **)&dll_scheme_current_config}, {"scheme_char_string_to_byte_string", (void **)&dll_scheme_char_string_to_byte_string}, + {"scheme_char_string_to_path", + (void **)&dll_scheme_char_string_to_path}, # endif {NULL, NULL}}; @@ -773,7 +779,14 @@ #ifdef MZSCHEME_COLLECTS /* setup 'current-library-collection-paths' parameter */ scheme_set_param(scheme_config, MZCONFIG_COLLECTION_PATHS, - scheme_make_pair(scheme_make_string(MZSCHEME_COLLECTS), + scheme_make_pair( +# if MZSCHEME_VERSION_MAJOR >= 299 + scheme_char_string_to_path( + scheme_byte_string_to_char_string( + scheme_make_byte_string(MZSCHEME_COLLECTS))), +# else + scheme_make_string(MZSCHEME_COLLECTS), +# endif scheme_null)); #endif #ifdef HAVE_SANDBOX diff -Naur vim71.orig/src/if_perl.xs vim71/src/if_perl.xs --- vim71.orig/src/if_perl.xs 2006-08-16 12:45:15.000000000 +0000 +++ vim71/src/if_perl.xs 2007-10-24 22:09:09.000000000 +0000 @@ -40,6 +40,28 @@ # define PERL_SUBVERSION SUBVERSION #endif +/* + * Quoting Jan Dubois of Active State: + * ActivePerl build 822 still identifies itself as 5.8.8 but already + * contains many of the changes from the upcoming Perl 5.8.9 release. + * + * The changes include addition of two symbols (Perl_sv_2iv_flags, + * Perl_newXS_flags) not present in earlier releases. + * + * Jan Dubois suggested the following guarding scheme. + * + * Active State defined ACTIVEPERL_VERSION as a string in versions before + * 5.8.8; and so the comparison to 822 below needs to be guarded. + */ +#if (PERL_REVISION == 5) && (PERL_VERSION == 8) && (PERL_SUBVERSION >= 8) +# if (ACTIVEPERL_VERSION >= 822) || (PERL_SUBVERSION >= 9) +# define PERL589_OR_LATER +# endif +#endif +#if (PERL_REVISION == 5) && (PERL_VERSION >= 9) +# define PERL589_OR_LATER +#endif + #ifndef pTHX # define pTHX void # define pTHX_ @@ -109,6 +131,10 @@ # else # define Perl_sv_catpvn dll_Perl_sv_catpvn # endif +#ifdef PERL589_OR_LATER +# define Perl_sv_2iv_flags dll_Perl_sv_2iv_flags +# define Perl_newXS_flags dll_Perl_newXS_flags +#endif # define Perl_sv_free dll_Perl_sv_free # define Perl_sv_isa dll_Perl_sv_isa # define Perl_sv_magic dll_Perl_sv_magic @@ -192,6 +218,10 @@ #else static void (*Perl_sv_catpvn)(pTHX_ SV*, const char*, STRLEN); #endif +#ifdef PERL589_OR_LATER +static IV (*Perl_sv_2iv_flags)(pTHX_ SV* sv, I32 flags); +static CV * (*Perl_newXS_flags)(pTHX_ const char *name, XSUBADDR_t subaddr, const char *const filename, const char *const proto, U32 flags); +#endif static void (*Perl_sv_free)(pTHX_ SV*); static int (*Perl_sv_isa)(pTHX_ SV*, const char*); static void (*Perl_sv_magic)(pTHX_ SV*, SV*, int, const char*, I32); @@ -267,6 +297,10 @@ #else {"Perl_sv_2pv", (PERL_PROC*)&Perl_sv_2pv}, #endif +#ifdef PERL589_OR_LATER + {"Perl_sv_2iv_flags", (PERL_PROC*)&Perl_sv_2iv_flags}, + {"Perl_newXS_flags", (PERL_PROC*)&Perl_newXS_flags}, +#endif {"Perl_sv_bless", (PERL_PROC*)&Perl_sv_bless}, #if (PERL_REVISION == 5) && (PERL_VERSION >= 8) {"Perl_sv_catpvn_flags", (PERL_PROC*)&Perl_sv_catpvn_flags}, @@ -411,13 +445,13 @@ char *next; char *token = (char *)s; - while ((next = strchr(token, '\n'))) + while ((next = strchr(token, '\n')) && !got_int) { *next++ = '\0'; /* replace \n with \0 */ msg_attr((char_u *)token, attr); token = next; } - if (*token) + if (*token && !got_int) msg_attr((char_u *)token, attr); } diff -Naur vim71.orig/src/if_ruby.c vim71/src/if_ruby.c --- vim71.orig/src/if_ruby.c 2007-05-12 09:54:12.000000000 +0000 +++ vim71/src/if_ruby.c 2007-10-24 22:09:09.000000000 +0000 @@ -789,7 +789,7 @@ return get_buffer_line(curbuf, curwin->w_cursor.lnum); } -static VALUE set_current_line(VALUE str) +static VALUE set_current_line(VALUE self, VALUE str) { return set_buffer_line(curbuf, curwin->w_cursor.lnum, str); } diff -Naur vim71.orig/src/keymap.h vim71/src/keymap.h --- vim71.orig/src/keymap.h 2006-08-22 11:38:38.000000000 +0000 +++ vim71/src/keymap.h 2007-10-24 22:09:09.000000000 +0000 @@ -254,6 +254,8 @@ , KE_DROP /* DnD data is available */ , KE_CURSORHOLD /* CursorHold event */ , KE_NOP /* doesn't do something */ + , KE_FOCUSGAINED /* focus gained */ + , KE_FOCUSLOST /* focus lost */ }; /* @@ -445,6 +447,8 @@ #define K_CMDWIN TERMCAP2KEY(KS_EXTRA, KE_CMDWIN) #define K_DROP TERMCAP2KEY(KS_EXTRA, KE_DROP) +#define K_FOCUSGAINED TERMCAP2KEY(KS_EXTRA, KE_FOCUSGAINED) +#define K_FOCUSLOST TERMCAP2KEY(KS_EXTRA, KE_FOCUSLOST) #define K_CURSORHOLD TERMCAP2KEY(KS_EXTRA, KE_CURSORHOLD) diff -Naur vim71.orig/src/macros.h vim71/src/macros.h --- vim71.orig/src/macros.h 2007-05-07 19:38:22.000000000 +0000 +++ vim71/src/macros.h 2007-10-24 22:09:09.000000000 +0000 @@ -54,10 +54,12 @@ /* * toupper() and tolower() that use the current locale. - * On some systems toupper()/tolower() only work on lower/uppercase characters + * On some systems toupper()/tolower() only work on lower/uppercase + * characters, first use islower() or isupper() then. * Careful: Only call TOUPPER_LOC() and TOLOWER_LOC() with a character in the * range 0 - 255. toupper()/tolower() on some systems can't handle others. - * Note: for UTF-8 use utf_toupper() and utf_tolower(). + * Note: It is often better to use MB_TOLOWER() and MB_TOUPPER(), because many + * toupper() and tolower() implementations only work for ASCII. */ #ifdef MSWIN # define TOUPPER_LOC(c) toupper_tab[(c) & 255] diff -Naur vim71.orig/src/main.aap vim71/src/main.aap --- vim71.orig/src/main.aap 2007-05-07 19:46:43.000000000 +0000 +++ vim71/src/main.aap 2007-10-24 22:09:09.000000000 +0000 @@ -56,9 +56,16 @@ config {virtual} auto/config.h auto/config.aap : auto/configure.aap configure.aap config.arg config.h.in config.aap.in + # Use "uname -a" to detect the architecture of the system. + @ok, uname = redir_system('uname -a', 0) + @if string.find(uname, "i386") >= 0: + @ arch = "i386" + @else: + @ arch = "ppc" + :print Building for $arch system :sys CONFIG_STATUS=auto/config.status ./configure.aap `file2string("config.arg")` - --with-mac-arch=ppc + --with-mac-arch=$arch --cache-file=auto/config.cache # Configure arguments: create an empty "config.arg" file when its missing @@ -1167,7 +1174,7 @@ :symlink `os.getcwd()`/../runtime $RESDIR/vim/runtime # TODO: Create the vimtutor application. -gui_bundle {virtual}: $(RESDIR) bundle-dir bundle-executable bundle-info +gui_bundle {virtual}: $(RESDIR) bundle-dir bundle-executable bundle-info \ bundle-resource bundle-language bundle-dir {virtual}: $(APPDIR)/Contents $(VIMTARGET) @@ -1187,7 +1194,7 @@ :sys m4 $(M4FLAGSX) infplist.xml > $(APPDIR)/Contents/Info.plist bundle-resource {virtual}: bundle-dir bundle-rsrc - :copy {force} $(RSRC_DIR)/*.icns $(RESDIR) + :copy {force} $(RSRC_DIR)/*.icns $(RESDIR) ### Classic resources # Resource fork (in the form of a .rsrc file) for Classic Vim (Mac OS 9) diff -Naur vim71.orig/src/main.c vim71/src/main.c --- vim71.orig/src/main.c 2007-05-07 19:38:44.000000000 +0000 +++ vim71/src/main.c 2007-10-24 22:09:09.000000000 +0000 @@ -954,7 +954,8 @@ int cmdwin; /* TRUE when working in the command-line window */ int noexmode; /* TRUE when return on entering Ex mode */ { - oparg_T oa; /* operator arguments */ + oparg_T oa; /* operator arguments */ + int previous_got_int = FALSE; /* "got_int" was TRUE */ #if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) /* Setup to catch a terminating error from the X server. Just ignore @@ -1015,12 +1016,32 @@ need_fileinfo = FALSE; } } - if (got_int && !global_busy) + + /* Reset "got_int" now that we got back to the main loop. Except when + * inside a ":g/pat/cmd" command, then the "got_int" needs to abort + * the ":g" command. + * For ":g/pat/vi" we reset "got_int" when used once. When used + * a second time we go back to Ex mode and abort the ":g" command. */ + if (got_int) { - if (!quit_more) - (void)vgetc(); /* flush all buffers */ - got_int = FALSE; + if (noexmode && global_busy && !exmode_active && previous_got_int) + { + /* Typed two CTRL-C in a row: go back to ex mode as if "Q" was + * used and keep "got_int" set, so that it aborts ":g". */ + exmode_active = EXMODE_NORMAL; + State = NORMAL; + } + else if (!global_busy || !exmode_active) + { + if (!quit_more) + (void)vgetc(); /* flush all buffers */ + got_int = FALSE; + } + previous_got_int = TRUE; } + else + previous_got_int = FALSE; + if (!exmode_active) msg_scroll = FALSE; quit_more = FALSE; @@ -1309,6 +1330,13 @@ #ifdef FEAT_NETBEANS_INTG netbeans_end(); #endif +#ifdef FEAT_CSCOPE + cs_end(); +#endif +#ifdef FEAT_EVAL + if (garbage_collect_at_exit) + garbage_collect(); +#endif mch_exit(exitval); } @@ -1360,8 +1388,7 @@ p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree); if (p != NULL && *p != NUL) { - STRCPY(NameBuff, p); - STRCAT(NameBuff, "/lang"); + vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p); bindtextdomain(VIMPACKAGE, (char *)NameBuff); } if (mustfree) @@ -3632,7 +3659,13 @@ mainerr_arg_missing((char_u *)filev[-1]); if (mch_dirname(cwd, MAXPATHL) != OK) return NULL; - if ((p = vim_strsave_escaped_ext(cwd, PATH_ESC_CHARS, '\\', TRUE)) == NULL) + if ((p = vim_strsave_escaped_ext(cwd, +#ifdef BACKSLASH_IN_FILENAME + "", /* rem_backslash() will tell what chars to escape */ +#else + PATH_ESC_CHARS, +#endif + '\\', TRUE)) == NULL) return NULL; ga_init2(&ga, 1, 100); ga_concat(&ga, (char_u *)":cd "); diff -Naur vim71.orig/src/mbyte.c vim71/src/mbyte.c --- vim71.orig/src/mbyte.c 2007-05-07 19:47:09.000000000 +0000 +++ vim71/src/mbyte.c 2007-10-24 22:09:09.000000000 +0000 @@ -1310,20 +1310,26 @@ /* * mb_off2cells() function pointer. * Return number of display cells for char at ScreenLines[off]. - * Caller must make sure "off" and "off + 1" are valid! + * We make sure that the offset used is less than "max_off". */ /*ARGSUSED*/ int -latin_off2cells(off) +latin_off2cells(off, max_off) unsigned off; + unsigned max_off; { return 1; } int -dbcs_off2cells(off) +dbcs_off2cells(off, max_off) unsigned off; + unsigned max_off; { + /* never check beyond end of the line */ + if (off >= max_off) + return 1; + /* Number of cells is equal to number of bytes, except for euc-jp when * the first byte is 0x8e. */ if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e) @@ -1332,10 +1338,11 @@ } int -utf_off2cells(off) +utf_off2cells(off, max_off) unsigned off; + unsigned max_off; { - return ScreenLines[off + 1] == 0 ? 2 : 1; + return (off + 1 < max_off && ScreenLines[off + 1] == 0) ? 2 : 1; } /* @@ -2320,7 +2327,7 @@ /* Single byte: first check normally, then with ignore case. */ if (s1[i] != s2[i]) { - cdiff = TOLOWER_LOC(s1[i]) - TOLOWER_LOC(s2[i]); + cdiff = MB_TOLOWER(s1[i]) - MB_TOLOWER(s2[i]); if (cdiff != 0) return cdiff; } @@ -2899,12 +2906,8 @@ if (composing_hangul) return TRUE; #endif - if (enc_dbcs != 0) - return dbcs_off2cells(LineOffset[row] + col) > 1; - if (enc_utf8) - return (col + 1 < Columns - && ScreenLines[LineOffset[row] + col + 1] == 0); - return FALSE; + return (*mb_off2cells)(LineOffset[row] + col, + LineOffset[row] + screen_Columns) > 1; } # if defined(FEAT_CLIPBOARD) || defined(FEAT_GUI) || defined(FEAT_RIGHTLEFT) \ diff -Naur vim71.orig/src/message.c vim71/src/message.c --- vim71.orig/src/message.c 2007-05-07 19:31:59.000000000 +0000 +++ vim71/src/message.c 2007-10-24 22:09:09.000000000 +0000 @@ -828,7 +828,7 @@ _("Messages maintainer: Bram Moolenaar "), hl_attr(HLF_T)); - for (p = first_msg_hist; p != NULL; p = p->next) + for (p = first_msg_hist; p != NULL && !got_int; p = p->next) if (p->msg != NULL) msg_attr(p->msg, p->attr); @@ -944,6 +944,7 @@ c = K_IGNORE; } #endif + /* * Allow scrolling back in the messages. * Also accept scroll-down commands when messages fill the screen, @@ -1840,9 +1841,10 @@ char_u *sb_str = str; int sb_col = msg_col; int wrap; + int did_last_char; did_wait_return = FALSE; - while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) + while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) { /* * We are at the end of the screen line when: @@ -1878,7 +1880,7 @@ /* output postponed text */ t_puts(&t_col, t_s, s, attr); - /* When no more prompt an no more room, truncate here */ + /* When no more prompt and no more room, truncate here */ if (msg_no_more && lines_left == 0) break; @@ -1909,7 +1911,10 @@ else #endif msg_screen_putchar(*s++, attr); + did_last_char = TRUE; } + else + did_last_char = FALSE; if (p_more) /* store text for scrolling back */ @@ -1927,7 +1932,8 @@ * If screen is completely filled and 'more' is set then wait * for a character. */ - --lines_left; + if (lines_left > 0) + --lines_left; if (p_more && lines_left == 0 && State != HITRETURN && !msg_no_more && !exmode_active) { @@ -1943,11 +1949,7 @@ /* When we displayed a char in last column need to check if there * is still more. */ - if (*s >= ' ' -#ifdef FEAT_RIGHTLEFT - && !cmdmsg_rl -#endif - ) + if (did_last_char) continue; } @@ -2234,7 +2236,7 @@ { msgchunk_T *mp; - /* Only show somethign if there is more than one line, otherwise it looks + /* Only show something if there is more than one line, otherwise it looks * weird, typing a command without output results in one line. */ mp = msg_sb_start(last_msgchunk); if (mp == NULL || mp->sb_prev == NULL) @@ -2622,7 +2624,7 @@ } } - if (scroll < 0 || (scroll == 0 && mp_last != NULL)) + if (scroll <= 0) { /* displayed the requested text, more prompt again */ screen_fill((int)Rows - 1, (int)Rows, 0, @@ -3456,11 +3458,11 @@ /* advance to next hotkey and set default hotkey */ #ifdef FEAT_MBYTE if (has_mbyte) - hotkp += (*mb_ptr2len)(hotkp); + hotkp += STRLEN(hotkp); else #endif ++hotkp; - (void)copy_char(r + 1, hotkp, TRUE); + hotkp[copy_char(r + 1, hotkp, TRUE)] = NUL; if (dfltbutton) --dfltbutton; @@ -3493,7 +3495,7 @@ *msgp++ = (dfltbutton == 1) ? ']' : ')'; /* redefine hotkey */ - (void)copy_char(r, hotkp, TRUE); + hotkp[copy_char(r, hotkp, TRUE)] = NUL; } } else @@ -3519,8 +3521,6 @@ *msgp++ = ':'; *msgp++ = ' '; *msgp = NUL; - mb_ptr_adv(hotkp); - *hotkp = NUL; } else { @@ -3555,8 +3555,9 @@ msgp = confirm_msg + 1 + STRLEN(message); hotkp = hotk; - /* define first default hotkey */ - (void)copy_char(buttons, hotkp, TRUE); + /* Define first default hotkey. Keep the hotkey string NUL + * terminated to avoid reading past the end. */ + hotkp[copy_char(buttons, hotkp, TRUE)] = NUL; /* Remember where the choices start, displaying starts here when * "hotkp" typed at the more prompt. */ diff -Naur vim71.orig/src/misc1.c vim71/src/misc1.c --- vim71.orig/src/misc1.c 2007-05-07 19:49:03.000000000 +0000 +++ vim71/src/misc1.c 2007-10-24 22:09:09.000000000 +0000 @@ -90,7 +90,7 @@ */ int set_indent(size, flags) - int size; + int size; /* measured in spaces */ int flags; { char_u *p; @@ -98,12 +98,14 @@ char_u *oldline; char_u *s; int todo; - int ind_len; + int ind_len; /* measured in characters */ int line_len; int doit = FALSE; - int ind_done; + int ind_done = 0; /* measured in spaces */ int tab_pad; int retval = FALSE; + int orig_char_len = -1; /* number of initial whitespace chars when + 'et' and 'pi' are both set */ /* * First check if there is anything to do and compute the number of @@ -116,8 +118,10 @@ /* Calculate the buffer size for the new indent, and check to see if it * isn't already set */ - /* if 'expandtab' isn't set: use TABs */ - if (!curbuf->b_p_et) + /* if 'expandtab' isn't set: use TABs; if both 'expandtab' and + * 'preserveindent' are set count the number of characters at the + * beginning of the line to be copied */ + if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi)) { /* If 'preserveindent' is set then reuse as much as possible of * the existing indent structure for the new indent */ @@ -148,9 +152,14 @@ ++p; } + /* Set initial number of whitespace chars to copy if we are + * preserving indent but expandtab is set */ + if (curbuf->b_p_et) + orig_char_len = ind_len; + /* Fill to next tabstop with a tab, if possible */ tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts); - if (todo >= tab_pad) + if (todo >= tab_pad && orig_char_len == -1) { doit = TRUE; todo -= tab_pad; @@ -193,13 +202,42 @@ else p = skipwhite(p); line_len = (int)STRLEN(p) + 1; - newline = alloc(ind_len + line_len); - if (newline == NULL) - return FALSE; + + /* If 'preserveindent' and 'expandtab' are both set keep the original + * characters and allocate accordingly. We will fill the rest with spaces + * after the if (!curbuf->b_p_et) below. */ + if (orig_char_len != -1) + { + newline = alloc(orig_char_len + size - ind_done + line_len); + if (newline == NULL) + return FALSE; + todo = size - ind_done; + ind_len = orig_char_len + todo; /* Set total length of indent in + * characters, which may have been + * undercounted until now */ + p = oldline; + s = newline; + while (orig_char_len > 0) + { + *s++ = *p++; + orig_char_len--; + } + /* Skip over any additional white space (useful when newindent is less + * than old) */ + while (vim_iswhite(*p)) + (void)*p++; + + } + else + { + todo = size; + newline = alloc(ind_len + line_len); + if (newline == NULL) + return FALSE; + s = newline; + } /* Put the characters in the new line. */ - s = newline; - todo = size; /* if 'expandtab' isn't set: use TABs */ if (!curbuf->b_p_et) { @@ -1320,8 +1358,8 @@ newindent += (int)curbuf->b_p_sw; } #endif - /* Copy the indent only if expand tab is disabled */ - if (curbuf->b_p_ci && !curbuf->b_p_et) + /* Copy the indent */ + if (curbuf->b_p_ci) { (void)copy_indent(newindent, saved_line); @@ -3468,9 +3506,38 @@ #endif /* + * Call expand_env() and store the result in an allocated string. + * This is not very memory efficient, this expects the result to be freed + * again soon. + */ + char_u * +expand_env_save(src) + char_u *src; +{ + return expand_env_save_opt(src, FALSE); +} + +/* + * Idem, but when "one" is TRUE handle the string as one file name, only + * expand "~" at the start. + */ + char_u * +expand_env_save_opt(src, one) + char_u *src; + int one; +{ + char_u *p; + + p = alloc(MAXPATHL); + if (p != NULL) + expand_env_esc(src, p, MAXPATHL, FALSE, one, NULL); + return p; +} + +/* * Expand environment variable with path name. * "~/" is also expanded, using $HOME. For Unix "~user/" is expanded. - * Skips over "\ ", "\~" and "\$". + * Skips over "\ ", "\~" and "\$" (not for Win32 though). * If anything fails no expansion is done and dst equals src. */ void @@ -3479,15 +3546,16 @@ char_u *dst; /* where to put the result */ int dstlen; /* maximum length of the result */ { - expand_env_esc(src, dst, dstlen, FALSE, NULL); + expand_env_esc(src, dst, dstlen, FALSE, FALSE, NULL); } void -expand_env_esc(srcp, dst, dstlen, esc, startstr) +expand_env_esc(srcp, dst, dstlen, esc, one, startstr) char_u *srcp; /* input string e.g. "$HOME/vim.hlp" */ char_u *dst; /* where to put the result */ int dstlen; /* maximum length of the result */ int esc; /* escape spaces in expanded variables */ + int one; /* "srcp" is one file name */ char_u *startstr; /* start again after this (can be NULL) */ { char_u *src; @@ -3728,6 +3796,8 @@ { /* * Recognize the start of a new name, for '~'. + * Don't do this when "one" is TRUE, to avoid expanding "~" in + * ":edit foo ~ foo". */ at_start = FALSE; if (src[0] == '\\' && src[1] != NUL) @@ -3735,7 +3805,7 @@ *dst++ = *src++; --dstlen; } - else if (src[0] == ' ' || src[0] == ',') + else if ((src[0] == ' ' || src[0] == ',') && !one) at_start = TRUE; *dst++ = *src++; --dstlen; @@ -4032,23 +4102,6 @@ } /* - * Call expand_env() and store the result in an allocated string. - * This is not very memory efficient, this expects the result to be freed - * again soon. - */ - char_u * -expand_env_save(src) - char_u *src; -{ - char_u *p; - - p = alloc(MAXPATHL); - if (p != NULL) - expand_env(src, p, MAXPATHL); - return p; -} - -/* * Our portable version of setenv. */ void @@ -4786,7 +4839,7 @@ static int cin_iswhileofdo __ARGS((char_u *, linenr_T, int)); static int cin_iswhileofdo_end __ARGS((int terminated, int ind_maxparen, int ind_maxcomment)); static int cin_isbreak __ARGS((char_u *)); -static int cin_is_cpp_baseclass __ARGS((char_u *line, colnr_T *col)); +static int cin_is_cpp_baseclass __ARGS((colnr_T *col)); static int get_baseclass_amount __ARGS((int col, int ind_maxparen, int ind_maxcomment, int ind_cpp_baseclass)); static int cin_ends_in __ARGS((char_u *, char_u *, char_u *)); static int cin_skip2pos __ARGS((pos_T *trypos)); @@ -5551,13 +5604,13 @@ * This is a lot of guessing. Watch out for "cond ? func() : foo". */ static int -cin_is_cpp_baseclass(line, col) - char_u *line; +cin_is_cpp_baseclass(col) colnr_T *col; /* return: column to align with */ { char_u *s; int class_or_struct, lookfor_ctor_init, cpp_base_class; linenr_T lnum = curwin->w_cursor.lnum; + char_u *line = ml_get_curline(); *col = 0; @@ -5585,7 +5638,8 @@ */ while (lnum > 1) { - s = skipwhite(ml_get(lnum - 1)); + line = ml_get(lnum - 1); + s = skipwhite(line); if (*s == '#' || *s == NUL) break; while (*s != NUL) @@ -5602,7 +5656,8 @@ --lnum; } - s = cin_skipcomment(ml_get(lnum)); + line = ml_get(lnum); + s = cin_skipcomment(line); for (;;) { if (*s == NUL) @@ -5610,7 +5665,10 @@ if (lnum == curwin->w_cursor.lnum) break; /* Continue in the cursor line. */ - s = cin_skipcomment(ml_get(++lnum)); + line = ml_get(++lnum); + s = cin_skipcomment(line); + if (*s == NUL) + continue; } if (s[0] == ':') @@ -7079,7 +7137,7 @@ n = FALSE; if (lookfor != LOOKFOR_TERM && ind_cpp_baseclass > 0) { - n = cin_is_cpp_baseclass(l, &col); + n = cin_is_cpp_baseclass(&col); l = ml_get_curline(); } if (n) @@ -7670,7 +7728,7 @@ n = FALSE; if (ind_cpp_baseclass != 0 && theline[0] != '{') { - n = cin_is_cpp_baseclass(l, &col); + n = cin_is_cpp_baseclass(&col); l = ml_get_curline(); } if (n) @@ -8596,7 +8654,7 @@ for (p = buf + wildoff; p < s; ++p) if (rem_backslash(p)) { - STRCPY(p, p + 1); + mch_memmove(p, p + 1, STRLEN(p)); --e; --s; } @@ -8897,7 +8955,7 @@ for (p = buf + wildoff; p < s; ++p) if (rem_backslash(p)) { - STRCPY(p, p + 1); + mch_memmove(p, p + 1, STRLEN(p)); --e; --s; } @@ -9096,7 +9154,7 @@ */ if (vim_strpbrk(p, (char_u *)"$~") != NULL) { - p = expand_env_save(p); + p = expand_env_save_opt(p, TRUE); if (p == NULL) p = pat[i]; #ifdef UNIX diff -Naur vim71.orig/src/misc2.c vim71/src/misc2.c --- vim71.orig/src/misc2.c 2007-05-07 19:49:26.000000000 +0000 +++ vim71/src/misc2.c 2007-10-24 22:09:09.000000000 +0000 @@ -972,7 +972,7 @@ return; entered = TRUE; - ++autocmd_block; /* don't want to trigger autocommands here */ + block_autocmds(); /* don't want to trigger autocommands here */ #ifdef FEAT_WINDOWS /* close all tabs and windows */ @@ -1037,7 +1037,9 @@ /* Free some global vars. */ vim_free(username); +# ifdef FEAT_CLIPBOARD vim_free(clip_exclude_prog); +# endif vim_free(last_cmdline); vim_free(new_last_cmdline); set_keep_msg(NULL, 0); diff -Naur vim71.orig/src/normal.c vim71/src/normal.c --- vim71.orig/src/normal.c 2007-05-07 19:34:39.000000000 +0000 +++ vim71/src/normal.c 2007-10-24 22:09:09.000000000 +0000 @@ -690,13 +690,20 @@ ca.count0 = ca.count0 * 10 + (c - '0'); if (ca.count0 < 0) /* got too large! */ ca.count0 = 999999999L; +#ifdef FEAT_EVAL + /* Set v:count here, when called from main() and not a stuffed + * command, so that v:count can be used in an expression mapping + * right after the count. */ + if (toplevel && stuff_empty()) + set_vcount(ca.count0, ca.count0 == 0 ? 1 : ca.count0); +#endif if (ctrl_w) { ++no_mapping; ++allow_keys; /* no mapping for nchar, but keys */ } ++no_zero_mapping; /* don't map zero here */ - c = safe_vgetc(); + c = plain_vgetc(); #ifdef FEAT_LANGMAP LANGMAP_ADJUST(c, TRUE); #endif @@ -721,7 +728,7 @@ ca.count0 = 0; ++no_mapping; ++allow_keys; /* no mapping for nchar, but keys */ - c = safe_vgetc(); /* get next character */ + c = plain_vgetc(); /* get next character */ #ifdef FEAT_LANGMAP LANGMAP_ADJUST(c, TRUE); #endif @@ -889,13 +896,18 @@ ++no_mapping; ++allow_keys; /* no mapping for nchar, but allow key codes */ +#ifdef FEAT_AUTOCMD + /* Don't generate a CursorHold event here, most commands can't handle + * it, e.g., nv_replace(), nv_csearch(). */ + did_cursorhold = TRUE; +#endif if (ca.cmdchar == 'g') { /* * For 'g' get the next character now, so that we can check for * "gr", "g'" and "g`". */ - ca.nchar = safe_vgetc(); + ca.nchar = plain_vgetc(); #ifdef FEAT_LANGMAP LANGMAP_ADJUST(ca.nchar, TRUE); #endif @@ -952,7 +964,7 @@ im_set_active(TRUE); #endif - *cp = safe_vgetc(); + *cp = plain_vgetc(); if (langmap_active) { @@ -1040,7 +1052,7 @@ } if (c > 0) { - c = safe_vgetc(); + c = plain_vgetc(); if (c != Ctrl_N && c != Ctrl_G) vungetc(c); else @@ -1059,7 +1071,7 @@ while (enc_utf8 && lang && (c = vpeekc()) > 0 && (c >= 0x100 || MB_BYTE2LEN(vpeekc()) > 1)) { - c = safe_vgetc(); + c = plain_vgetc(); if (!utf_iscomposing(c)) { vungetc(c); /* it wasn't, put it back */ @@ -3755,7 +3767,8 @@ extra_len = (int)STRLEN(p); overflow = old_len + extra_len - SHOWCMD_COLS; if (overflow > 0) - STRCPY(showcmd_buf, showcmd_buf + overflow); + mch_memmove(showcmd_buf, showcmd_buf + overflow, + old_len - overflow + 1); STRCAT(showcmd_buf, p); if (char_avail()) @@ -4558,7 +4571,7 @@ #endif ++no_mapping; ++allow_keys; /* no mapping for nchar, but allow key codes */ - nchar = safe_vgetc(); + nchar = plain_vgetc(); #ifdef FEAT_LANGMAP LANGMAP_ADJUST(nchar, TRUE); #endif @@ -4916,7 +4929,7 @@ case 'u': /* "zug" and "zuw": undo "zg" and "zw" */ ++no_mapping; ++allow_keys; /* no mapping for nchar, but allow key codes */ - nchar = safe_vgetc(); + nchar = plain_vgetc(); #ifdef FEAT_LANGMAP LANGMAP_ADJUST(nchar, TRUE); #endif @@ -6379,7 +6392,7 @@ */ else if (cap->nchar == 'p' || cap->nchar == 'P') { - if (!checkclearopq(cap->oap)) + if (!checkclearop(cap->oap)) { prep_redo_cmd(cap); do_put(cap->oap->regname, @@ -6662,6 +6675,13 @@ else had_ctrl_v = NUL; + /* Abort if the character is a special key. */ + if (IS_SPECIAL(cap->nchar)) + { + clearopbeep(cap->oap); + return; + } + #ifdef FEAT_VISUAL /* Visual mode "r" */ if (VIsual_active) @@ -6688,11 +6708,9 @@ } #endif - /* - * Check for a special key or not enough characters to replace. - */ + /* Abort if not enough characters to replace. */ ptr = ml_get_cursor(); - if (IS_SPECIAL(cap->nchar) || STRLEN(ptr) < (unsigned)cap->count1 + if (STRLEN(ptr) < (unsigned)cap->count1 #ifdef FEAT_MBYTE || (has_mbyte && mb_charlen(ptr) < cap->count1) #endif @@ -8353,7 +8371,7 @@ n = fwd_word(cap->count1, cap->arg, cap->oap->op_type != OP_NOP); /* Don't leave the cursor on the NUL past a line */ - if (curwin->w_cursor.col && gchar_cursor() == NUL) + if (n != FAIL && curwin->w_cursor.col > 0 && gchar_cursor() == NUL) { --curwin->w_cursor.col; cap->oap->inclusive = TRUE; diff -Naur vim71.orig/src/ops.c vim71/src/ops.c --- vim71.orig/src/ops.c 2007-05-07 19:33:47.000000000 +0000 +++ vim71/src/ops.c 2007-10-24 22:09:09.000000000 +0000 @@ -2477,7 +2477,7 @@ /* * Spaces and tabs in the indent may have changed to other spaces and - * tabs. Get the starting column again and correct the lenght. + * tabs. Get the starting column again and correct the length. * Don't do this when "$" used, end-of-line will have changed. */ block_prep(oap, &bd2, oap->start.lnum, TRUE); @@ -2534,7 +2534,9 @@ #ifdef FEAT_VISUALEXTRA long offset; linenr_T linenr; - long ins_len, pre_textlen = 0; + long ins_len; + long pre_textlen = 0; + long pre_indent = 0; char_u *firstline; char_u *ins_text, *newp, *oldp; struct block_def bd; @@ -2579,7 +2581,9 @@ || gchar_cursor() == NUL)) coladvance_force(getviscol()); # endif - pre_textlen = (long)STRLEN(ml_get(oap->start.lnum)); + firstline = ml_get(oap->start.lnum); + pre_textlen = (long)STRLEN(firstline); + pre_indent = (long)(skipwhite(firstline) - firstline); bd.textcol = curwin->w_cursor.col; } #endif @@ -2598,13 +2602,22 @@ */ if (oap->block_mode && oap->start.lnum != oap->end.lnum) { + /* Auto-indenting may have changed the indent. If the cursor was past + * the indent, exclude that indent change from the inserted text. */ firstline = ml_get(oap->start.lnum); - /* - * Subsequent calls to ml_get() flush the firstline data - take a - * copy of the required bit. - */ - if ((ins_len = (long)STRLEN(firstline) - pre_textlen) > 0) + if (bd.textcol > (colnr_T)pre_indent) + { + long new_indent = (long)(skipwhite(firstline) - firstline); + + pre_textlen += new_indent - pre_indent; + bd.textcol += new_indent - pre_indent; + } + + ins_len = (long)STRLEN(firstline) - pre_textlen; + if (ins_len > 0) { + /* Subsequent calls to ml_get() flush the firstline data - take a + * copy of the inserted text. */ if ((ins_text = alloc_check((unsigned)(ins_len + 1))) != NULL) { vim_strncpy(ins_text, firstline + bd.textcol, (size_t)ins_len); @@ -3404,7 +3417,9 @@ #ifdef FEAT_VIRTUALEDIT col += curwin->w_cursor.coladd; - if (ve_flags == VE_ALL && curwin->w_cursor.coladd > 0) + if (ve_flags == VE_ALL + && (curwin->w_cursor.coladd > 0 + || endcol2 == curwin->w_cursor.col)) { if (dir == FORWARD && c == NUL) ++col; diff -Naur vim71.orig/src/option.c vim71/src/option.c --- vim71.orig/src/option.c 2007-05-01 11:26:10.000000000 +0000 +++ vim71/src/option.c 2007-10-24 22:09:09.000000000 +0000 @@ -427,6 +427,8 @@ #define P_NOGLOB 0x100000L/* do not use local value for global vimrc */ #define P_NFNAME 0x200000L/* only normal file name chars allowed */ #define P_INSECURE 0x400000L/* option was set from a modeline */ +#define P_PRI_MKRC 0x800000L/* priority for :mkvimrc (setting option has + side effects) */ #define ISK_LATIN1 (char_u *)"@,48-57,_,192-255" @@ -773,6 +775,8 @@ {(char_u *)0L, (char_u *)0L} #endif }, + /* P_PRI_MKRC isn't needed here, optval_default() + * always returns TRUE for 'compatible' */ {"compatible", "cp", P_BOOL|P_RALL, (char_u *)&p_cp, PV_NONE, {(char_u *)TRUE, (char_u *)FALSE}}, @@ -1515,7 +1519,7 @@ {(char_u *)0L, (char_u *)0L} #endif }, - {"keymap", "kmp", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_RSTAT|P_NFNAME, + {"keymap", "kmp", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_RSTAT|P_NFNAME|P_PRI_MKRC, #ifdef FEAT_KEYMAP (char_u *)&p_keymap, PV_KMAP, {(char_u *)"", (char_u *)0L} @@ -1836,7 +1840,7 @@ {"paragraphs", "para", P_STRING|P_VI_DEF, (char_u *)&p_para, PV_NONE, {(char_u *)"IPLPPPQPP LIpplpipbp", (char_u *)0L}}, - {"paste", NULL, P_BOOL|P_VI_DEF, + {"paste", NULL, P_BOOL|P_VI_DEF|P_PRI_MKRC, (char_u *)&p_paste, PV_NONE, {(char_u *)FALSE, (char_u *)0L}}, {"pastetoggle", "pt", P_STRING|P_VI_DEF, @@ -4628,7 +4632,7 @@ if ((!(flags & P_COMMA) || *s != ',') && vim_strchr(s + 1, *s) != NULL) { - STRCPY(s, s + 1); + mch_memmove(s, s + 1, STRLEN(s)); --s; } } @@ -4992,7 +4996,7 @@ * For 'spellsuggest' expand after "file:". */ expand_env_esc(val, NameBuff, MAXPATHL, - (char_u **)options[opt_idx].var == &p_tags, + (char_u **)options[opt_idx].var == &p_tags, FALSE, #ifdef FEAT_SPELL (char_u **)options[opt_idx].var == &p_sps ? (char_u *)"file:" : #endif @@ -6348,7 +6352,7 @@ errmsg = check_stl_option(p_ruf); } /* check 'statusline' only if it doesn't start with "%!" */ - else if (varp != &p_stl || s[0] != '%' || s[1] != '!') + else if (varp == &p_ruf || s[0] != '%' || s[1] != '!') errmsg = check_stl_option(s); if (varp == &p_ruf && errmsg == NULL) comp_col(); @@ -7118,6 +7122,11 @@ /* when 'endofline' is changed, redraw the window title */ else if ((int *)varp == &curbuf->b_p_eol) need_maketitle = TRUE; +#ifdef FEAT_MBYTE + /* when 'bomb' is changed, redraw the window title */ + else if ((int *)varp == &curbuf->b_p_bomb) + need_maketitle = TRUE; +#endif #endif /* when 'bin' is set also set some other options */ @@ -7815,6 +7824,8 @@ errmsg = e_positive; p_ch = 1; } + if (p_ch > Rows - min_rows() + 1) + p_ch = Rows - min_rows() + 1; /* Only compute the new window layout when startup has been * completed. Otherwise the frame sizes may be wrong. */ @@ -8219,6 +8230,25 @@ varp = get_varp(&options[opt_idx]); if (varp != NULL) /* hidden option is not changed */ { + if (number == 0 && string != NULL) + { + int index; + + /* Either we are given a string or we are setting option + * to zero. */ + for (index = 0; string[index] == '0'; ++index) + ; + if (string[index] != NUL || index == 0) + { + /* There's another character after zeros or the string + * is empty. In both cases, we are trying to set a + * num option using a string. */ + EMSG3(_("E521: Number required: &%s = '%s'"), + name, string); + return; /* do nothing as we hit an error */ + + } + } if (flags & P_NUM) (void)set_num_option(opt_idx, varp, number, NULL, 0, opt_flags); @@ -8511,13 +8541,20 @@ char_u *varp_local = NULL; /* fresh value */ char *cmd; int round; + int pri; /* * The options that don't have a default (terminal name, columns, lines) * are never written. Terminal options are also not written. + * Do the loop over "options[]" twice: once for options with the + * P_PRI_MKRC flag and once without. */ - for (p = &options[0]; !istermoption(p); p++) - if (!(p->flags & P_NO_MKRC) && !istermoption(p)) + for (pri = 1; pri >= 0; --pri) + { + for (p = &options[0]; !istermoption(p); p++) + if (!(p->flags & P_NO_MKRC) + && !istermoption(p) + && ((pri == 1) == ((p->flags & P_PRI_MKRC) != 0))) { /* skip global option when only doing locals */ if (p->indir == PV_NONE && !(opt_flags & OPT_GLOBAL)) @@ -8613,6 +8650,7 @@ } } } + } return OK; } @@ -8715,6 +8753,8 @@ char *name; int value; { + if (value < 0) /* global/local option using global value */ + return OK; if (fprintf(fd, "%s %s%s", cmd, value ? "" : "no", name) < 0 || put_eol(fd) < 0) return FAIL; @@ -10585,6 +10625,8 @@ buf->b_start_ffc = *buf->b_p_ff; buf->b_start_eol = buf->b_p_eol; #ifdef FEAT_MBYTE + buf->b_start_bomb = buf->b_p_bomb; + /* Only use free/alloc when necessary, they take time. */ if (buf->b_start_fenc == NULL || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0) @@ -10598,13 +10640,17 @@ /* * Return TRUE if 'fileformat' and/or 'fileencoding' has a different value * from when editing started (save_file_ff() called). - * Also when 'endofline' was changed and 'binary' is set. + * Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was + * changed and 'binary' is not set. * Don't consider a new, empty buffer to be changed. */ int file_ff_differs(buf) buf_T *buf; { + /* In a buffer that was never loaded the options are not valid. */ + if (buf->b_flags & BF_NEVERLOADED) + return FALSE; if ((buf->b_flags & BF_NEW) && buf->b_ml.ml_line_count == 1 && *ml_get_buf(buf, (linenr_T)1, FALSE) == NUL) @@ -10614,6 +10660,8 @@ if (buf->b_p_bin && buf->b_start_eol != buf->b_p_eol) return TRUE; #ifdef FEAT_MBYTE + if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb) + return TRUE; if (buf->b_start_fenc == NULL) return (*buf->b_p_fenc != NUL); return (STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0); diff -Naur vim71.orig/src/os_unix.c vim71/src/os_unix.c --- vim71.orig/src/os_unix.c 2007-05-09 19:41:58.000000000 +0000 +++ vim71/src/os_unix.c 2007-10-24 22:09:09.000000000 +0000 @@ -753,7 +753,8 @@ if (signal_stack != NULL) { # ifdef HAVE_SIGALTSTACK -# ifdef __APPLE__ +# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \ + || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040) /* missing prototype. Adding it to osdef?.h.in doesn't work, because * "struct sigaltstack" needs to be declared. */ extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss)); @@ -2499,7 +2500,13 @@ if (stat((char *)name, &statb)) #endif return -1; +#ifdef __INTERIX + /* The top bit makes the value negative, which means the file doesn't + * exist. Remove the bit, we don't use it. */ + return statb.st_mode & ~S_ADDACE; +#else return statb.st_mode; +#endif } /* @@ -5682,7 +5689,7 @@ /* * Closes connection to gpm - * returns non-zero if connection succesfully closed + * returns non-zero if connection successfully closed */ static void gpm_close() diff -Naur vim71.orig/src/os_unix.h vim71/src/os_unix.h --- vim71.orig/src/os_unix.h 2007-05-07 19:35:05.000000000 +0000 +++ vim71/src/os_unix.h 2007-10-24 22:09:07.000000000 +0000 @@ -508,6 +508,9 @@ #if !defined(S_ISFIFO) && defined(S_IFIFO) # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) #endif +#if !defined(S_ISCHR) && defined(S_IFCHR) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#endif /* Note: Some systems need both string.h and strings.h (Savage). However, * some systems can't handle both, only use string.h in that case. */ diff -Naur vim71.orig/src/popupmnu.c vim71/src/popupmnu.c --- vim71.orig/src/popupmnu.c 2007-03-24 20:07:39.000000000 +0000 +++ vim71/src/popupmnu.c 2007-10-24 22:09:07.000000000 +0000 @@ -75,7 +75,6 @@ row = curwin->w_cline_row + W_WINROW(curwin); height = curwin->w_cline_height; - col = curwin->w_wcol + W_WINCOL(curwin) - curwin->w_leftcol; if (firstwin->w_p_pvw) top_clear = firstwin->w_height; @@ -167,6 +166,15 @@ pum_base_width = max_width; pum_kind_width = kind_width; + /* Calculate column */ +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + col = W_WINCOL(curwin) + W_WIDTH(curwin) - curwin->w_wcol - + curwin->w_leftcol - 1; + else +#endif + col = W_WINCOL(curwin) + curwin->w_wcol - curwin->w_leftcol; + /* if there are more items than room we need a scrollbar */ if (pum_height < size) { @@ -179,11 +187,23 @@ if (def_width < max_width) def_width = max_width; - if (col < Columns - PUM_DEF_WIDTH || col < Columns - max_width) + if (((col < Columns - PUM_DEF_WIDTH || col < Columns - max_width) +#ifdef FEAT_RIGHTLEFT + && !curwin->w_p_rl) + || (curwin->w_p_rl && (col > PUM_DEF_WIDTH || col > max_width) +#endif + )) { /* align pum column with "col" */ pum_col = col; - pum_width = Columns - pum_col - pum_scrollbar; + +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + pum_width = pum_col - pum_scrollbar + 1; + else +#endif + pum_width = Columns - pum_col - pum_scrollbar; + if (pum_width > max_width + kind_width + extra_width + 1 && pum_width > PUM_DEF_WIDTH) { @@ -195,14 +215,24 @@ else if (Columns < def_width) { /* not enough room, will use what we have */ - pum_col = 0; +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + pum_col = Columns - 1; + else +#endif + pum_col = 0; pum_width = Columns - 1; } else { if (max_width > PUM_DEF_WIDTH) max_width = PUM_DEF_WIDTH; /* truncate */ - pum_col = Columns - max_width; +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + pum_col = max_width - 1; + else +#endif + pum_col = Columns - max_width; pum_width = max_width - pum_scrollbar; } @@ -255,8 +285,16 @@ attr = (idx == pum_selected) ? attr_select : attr_norm; /* prepend a space if there is room */ - if (pum_col > 0) - screen_putchar(' ', row, pum_col - 1, attr); +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + { + if (pum_col < W_WINCOL(curwin) + W_WIDTH(curwin) - 1) + screen_putchar(' ', row, pum_col + 1, attr); + } + else +#endif + if (pum_col > 0) + screen_putchar(' ', row, pum_col - 1, attr); /* Display each entry, use two spaces for a Tab. * Do this 3 times: For the main text, kind and extra info */ @@ -282,26 +320,67 @@ { /* Display the text that fits or comes before a Tab. * First convert it to printable characters. */ - char_u *st; - int saved = *p; + char_u *st; + int saved = *p; *p = NUL; st = transstr(s); *p = saved; - if (st != NULL) +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) { - screen_puts_len(st, (int)STRLEN(st), row, col, + if (st != NULL) + { + char_u *rt = reverse_text(st); + char_u *rt_saved = rt; + int len, j; + + if (rt != NULL) + { + len = STRLEN(rt); + if (len > pum_width) + { + for (j = pum_width; j < len; ++j) + mb_ptr_adv(rt); + len = pum_width; + } + screen_puts_len(rt, len, row, + col - len + 1, attr); + vim_free(rt_saved); + } + vim_free(st); + } + col -= width; + } + else +#endif + { + if (st != NULL) + { + screen_puts_len(st, (int)STRLEN(st), row, col, attr); - vim_free(st); + vim_free(st); + } + col += width; } - col += width; if (*p != TAB) break; /* Display two spaces for a Tab. */ - screen_puts_len((char_u *)" ", 2, row, col, attr); - col += 2; +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + { + screen_puts_len((char_u *)" ", 2, row, col - 1, + attr); + col -= 2; + } + else +#endif + { + screen_puts_len((char_u *)" ", 2, row, col, attr); + col += 2; + } totwidth += 2; s = NULL; /* start text at next char */ width = 0; @@ -322,17 +401,44 @@ && pum_array[idx].pum_extra == NULL) || pum_base_width + n >= pum_width) break; - screen_fill(row, row + 1, col, pum_col + pum_base_width + n, +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + { + screen_fill(row, row + 1, pum_col - pum_base_width - n + 1, + col + 1, ' ', ' ', attr); + col = pum_col - pum_base_width - n + 1; + } + else +#endif + { + screen_fill(row, row + 1, col, pum_col + pum_base_width + n, ' ', ' ', attr); - col = pum_col + pum_base_width + n; + col = pum_col + pum_base_width + n; + } totwidth = pum_base_width + n; } - screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ', attr); +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ', + ' ', attr); + else +#endif + screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ', + attr); if (pum_scrollbar > 0) - screen_putchar(' ', row, pum_col + pum_width, - i >= thumb_pos && i < thumb_pos + thumb_heigth + { +#ifdef FEAT_RIGHTLEFT + if (curwin->w_p_rl) + screen_putchar(' ', row, pum_col - pum_width, + i >= thumb_pos && i < thumb_pos + thumb_heigth ? attr_thumb : attr_scroll); + else +#endif + screen_putchar(' ', row, pum_col + pum_width, + i >= thumb_pos && i < thumb_pos + thumb_heigth + ? attr_thumb : attr_scroll); + } ++row; } @@ -466,7 +572,7 @@ set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL); set_option_value((char_u *)"diff", 0L, - (char_u *)"", OPT_LOCAL); + NULL, OPT_LOCAL); } } if (res == OK) diff -Naur vim71.orig/src/proto/charset.pro vim71/src/proto/charset.pro --- vim71.orig/src/proto/charset.pro 2007-05-12 10:39:01.000000000 +0000 +++ vim71/src/proto/charset.pro 2007-10-24 22:09:09.000000000 +0000 @@ -21,6 +21,7 @@ int vim_iswordp __ARGS((char_u *p)); int vim_iswordc_buf __ARGS((char_u *p, buf_T *buf)); int vim_isfilec __ARGS((int c)); +int vim_isfilec_or_wc __ARGS((int c)); int vim_isprintc __ARGS((int c)); int vim_isprintc_strict __ARGS((int c)); int lbr_chartabsize __ARGS((unsigned char *s, colnr_T col)); diff -Naur vim71.orig/src/proto/fileio.pro vim71/src/proto/fileio.pro --- vim71.orig/src/proto/fileio.pro 2007-05-12 10:39:14.000000000 +0000 +++ vim71/src/proto/fileio.pro 2007-10-24 22:09:09.000000000 +0000 @@ -2,6 +2,7 @@ void filemess __ARGS((buf_T *buf, char_u *name, char_u *s, int attr)); int readfile __ARGS((char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T *eap, int flags)); int prep_exarg __ARGS((exarg_T *eap, buf_T *buf)); +int check_file_readonly __ARGS((char_u *fname, int perm)); int buf_write __ARGS((buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering)); void msg_add_fname __ARGS((buf_T *buf, char_u *fname)); void msg_add_lines __ARGS((int insert_space, long lnum, long nchars)); @@ -39,6 +40,8 @@ int trigger_cursorhold __ARGS((void)); int has_cursormoved __ARGS((void)); int has_cursormovedI __ARGS((void)); +void block_autocmds __ARGS((void)); +void unblock_autocmds __ARGS((void)); int has_autocmd __ARGS((event_T event, char_u *sfname, buf_T *buf)); char_u *get_augroup_name __ARGS((expand_T *xp, int idx)); char_u *set_context_in_autocmd __ARGS((expand_T *xp, char_u *arg, int doautocmd)); diff -Naur vim71.orig/src/proto/getchar.pro vim71/src/proto/getchar.pro --- vim71.orig/src/proto/getchar.pro 2007-05-12 10:39:16.000000000 +0000 +++ vim71/src/proto/getchar.pro 2007-10-24 22:09:09.000000000 +0000 @@ -38,6 +38,7 @@ void updatescript __ARGS((int c)); int vgetc __ARGS((void)); int safe_vgetc __ARGS((void)); +int plain_vgetc __ARGS((void)); int vpeekc __ARGS((void)); int vpeekc_nomap __ARGS((void)); int vpeekc_any __ARGS((void)); diff -Naur vim71.orig/src/proto/if_cscope.pro vim71/src/proto/if_cscope.pro --- vim71.orig/src/proto/if_cscope.pro 2007-05-12 10:39:21.000000000 +0000 +++ vim71/src/proto/if_cscope.pro 2007-10-24 22:09:09.000000000 +0000 @@ -6,4 +6,5 @@ void cs_free_tags __ARGS((void)); void cs_print_tags __ARGS((void)); int cs_connection __ARGS((int num, char_u *dbpath, char_u *ppath)); +void cs_end __ARGS((void)); /* vim: set ft=c : */ diff -Naur vim71.orig/src/proto/mbyte.pro vim71/src/proto/mbyte.pro --- vim71.orig/src/proto/mbyte.pro 2007-05-12 10:39:38.000000000 +0000 +++ vim71/src/proto/mbyte.pro 2007-10-24 22:09:09.000000000 +0000 @@ -12,9 +12,9 @@ int utf_ptr2cells __ARGS((char_u *p)); int dbcs_ptr2cells __ARGS((char_u *p)); int latin_char2cells __ARGS((int c)); -int latin_off2cells __ARGS((unsigned off)); -int dbcs_off2cells __ARGS((unsigned off)); -int utf_off2cells __ARGS((unsigned off)); +int latin_off2cells __ARGS((unsigned off, unsigned max_off)); +int dbcs_off2cells __ARGS((unsigned off, unsigned max_off)); +int utf_off2cells __ARGS((unsigned off, unsigned max_off)); int latin_ptr2char __ARGS((char_u *p)); int utf_ptr2char __ARGS((char_u *p)); int mb_ptr2char_adv __ARGS((char_u **pp)); diff -Naur vim71.orig/src/proto/misc1.pro vim71/src/proto/misc1.pro --- vim71.orig/src/proto/misc1.pro 2007-05-12 10:39:34.000000000 +0000 +++ vim71/src/proto/misc1.pro 2007-10-24 22:09:09.000000000 +0000 @@ -48,10 +48,11 @@ void vim_beep __ARGS((void)); void init_homedir __ARGS((void)); void free_homedir __ARGS((void)); +char_u *expand_env_save __ARGS((char_u *src)); +char_u *expand_env_save_opt __ARGS((char_u *src, int one)); void expand_env __ARGS((char_u *src, char_u *dst, int dstlen)); -void expand_env_esc __ARGS((char_u *srcp, char_u *dst, int dstlen, int esc, char_u *startstr)); +void expand_env_esc __ARGS((char_u *srcp, char_u *dst, int dstlen, int esc, int one, char_u *startstr)); char_u *vim_getenv __ARGS((char_u *name, int *mustfree)); -char_u *expand_env_save __ARGS((char_u *src)); void vim_setenv __ARGS((char_u *name, char_u *val)); char_u *get_env_name __ARGS((expand_T *xp, int idx)); void home_replace __ARGS((buf_T *buf, char_u *src, char_u *dst, int dstlen, int one)); diff -Naur vim71.orig/src/proto/search.pro vim71/src/proto/search.pro --- vim71.orig/src/proto/search.pro 2007-05-12 10:39:50.000000000 +0000 +++ vim71/src/proto/search.pro 2007-10-24 22:09:07.000000000 +0000 @@ -1,6 +1,7 @@ /* search.c */ int search_regcomp __ARGS((char_u *pat, int pat_save, int pat_use, int options, regmmatch_T *regmatch)); char_u *get_search_pat __ARGS((void)); +char_u *reverse_text __ARGS((char_u *s)); void save_search_patterns __ARGS((void)); void restore_search_patterns __ARGS((void)); void free_search_patterns __ARGS((void)); diff -Naur vim71.orig/src/proto/syntax.pro vim71/src/proto/syntax.pro --- vim71.orig/src/proto/syntax.pro 2007-05-12 10:39:52.000000000 +0000 +++ vim71/src/proto/syntax.pro 2007-10-24 22:09:07.000000000 +0000 @@ -8,6 +8,8 @@ void syntax_clear __ARGS((buf_T *buf)); void ex_syntax __ARGS((exarg_T *eap)); int syntax_present __ARGS((buf_T *buf)); +void reset_expand_highlight __ARGS((void)); +void set_context_in_echohl_cmd __ARGS((expand_T *xp, char_u *arg)); void set_context_in_syntax_cmd __ARGS((expand_T *xp, char_u *arg)); char_u *get_syntax_name __ARGS((expand_T *xp, int idx)); int syn_get_id __ARGS((win_T *wp, long lnum, colnr_T col, int trans, int *spellp)); diff -Naur vim71.orig/src/proto/window.pro vim71/src/proto/window.pro --- vim71.orig/src/proto/window.pro 2007-05-12 10:40:00.000000000 +0000 +++ vim71/src/proto/window.pro 2007-10-24 22:09:07.000000000 +0000 @@ -59,4 +59,8 @@ int only_one_window __ARGS((void)); void check_lnums __ARGS((int do_curwin)); int win_hasvertsplit __ARGS((void)); +int match_add __ARGS((win_T *wp, char_u *grp, char_u *pat, int prio, int id)); +int match_delete __ARGS((win_T *wp, int id, int perr)); +void clear_matches __ARGS((win_T *wp)); +matchitem_T *get_match __ARGS((win_T *wp, int id)); /* vim: set ft=c : */ diff -Naur vim71.orig/src/quickfix.c vim71/src/quickfix.c --- vim71.orig/src/quickfix.c 2007-02-04 00:50:17.000000000 +0000 +++ vim71/src/quickfix.c 2007-10-24 22:09:09.000000000 +0000 @@ -1612,8 +1612,8 @@ } /* - * If there is only one window and is the quickfix window, create a new - * one above the quickfix window. + * If there is only one window and it is the quickfix window, create a + * new one above the quickfix window. */ if (((firstwin == lastwin) && bt_quickfix(curbuf)) || !usable_win) { @@ -2331,7 +2331,7 @@ 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); + set_option_value((char_u *)"diff", 0L, NULL, OPT_LOCAL); } /* Only set the height when still in the same tab page and there is no @@ -2981,6 +2981,7 @@ buf_T *buf; int duplicate_name = FALSE; int using_dummy; + int redraw_for_dummy = FALSE; int found_match; buf_T *first_match_buf = NULL; time_t seconds = 0; @@ -3097,6 +3098,7 @@ /* Remember that a buffer with this name already exists. */ duplicate_name = (buf != NULL); using_dummy = TRUE; + redraw_for_dummy = TRUE; #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) /* Don't do Filetype autocommands to avoid loading syntax and @@ -3243,11 +3245,29 @@ if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { if ((flags & VGR_NOJUMP) == 0) + { + buf = curbuf; qf_jump(qi, 0, 0, eap->forceit); + if (buf != curbuf) + /* If we jumped to another buffer redrawing will already be + * taken care of. */ + redraw_for_dummy = FALSE; + } } else EMSG2(_(e_nomatch2), s); + /* If we loaded a dummy buffer into the current window, the autocommands + * may have messed up things, need to redraw and recompute folds. */ + if (redraw_for_dummy) + { +#ifdef FEAT_FOLDING + foldUpdateAll(curwin); +#else + redraw_later(NOT_VALID); +#endif + } + theend: vim_free(regmatch.regprog); } diff -Naur vim71.orig/src/regexp.c vim71/src/regexp.c --- vim71.orig/src/regexp.c 2007-05-07 19:50:03.000000000 +0000 +++ vim71/src/regexp.c 2007-10-24 22:09:07.000000000 +0000 @@ -2220,7 +2220,7 @@ break; case CLASS_LOWER: for (cu = 1; cu <= 255; cu++) - if (islower(cu)) + if (MB_ISLOWER(cu)) regc(cu); break; case CLASS_PRINT: @@ -2240,7 +2240,7 @@ break; case CLASS_UPPER: for (cu = 1; cu <= 255; cu++) - if (isupper(cu)) + if (MB_ISUPPER(cu)) regc(cu); break; case CLASS_XDIGIT: @@ -3465,7 +3465,7 @@ (enc_utf8 && utf_fold(prog->regstart) == utf_fold(c))) || (c < 255 && prog->regstart < 255 && #endif - TOLOWER_LOC(prog->regstart) == TOLOWER_LOC(c))))) + MB_TOLOWER(prog->regstart) == MB_TOLOWER(c))))) retval = regtry(prog, col); else retval = 0; @@ -4200,7 +4200,7 @@ #ifdef FEAT_MBYTE !enc_utf8 && #endif - TOLOWER_LOC(*opnd) != TOLOWER_LOC(*reginput)))) + MB_TOLOWER(*opnd) != MB_TOLOWER(*reginput)))) status = RA_NOMATCH; else if (*opnd == NUL) { @@ -4733,10 +4733,10 @@ rst.nextb = *OPERAND(next); if (ireg_ic) { - if (isupper(rst.nextb)) - rst.nextb_ic = TOLOWER_LOC(rst.nextb); + if (MB_ISUPPER(rst.nextb)) + rst.nextb_ic = MB_TOLOWER(rst.nextb); else - rst.nextb_ic = TOUPPER_LOC(rst.nextb); + rst.nextb_ic = MB_TOUPPER(rst.nextb); } else rst.nextb_ic = rst.nextb; @@ -5558,11 +5558,12 @@ int cu, cl; /* This doesn't do a multi-byte character, because a MULTIBYTECODE - * would have been used for it. */ + * would have been used for it. It does handle single-byte + * characters, such as latin1. */ if (ireg_ic) { - cu = TOUPPER_LOC(*opnd); - cl = TOLOWER_LOC(*opnd); + cu = MB_TOUPPER(*opnd); + cl = MB_TOLOWER(*opnd); while (count < maxcount && (*scan == cu || *scan == cl)) { count++; @@ -6490,10 +6491,10 @@ cc = utf_fold(c); else #endif - if (isupper(c)) - cc = TOLOWER_LOC(c); - else if (islower(c)) - cc = TOUPPER_LOC(c); + if (MB_ISUPPER(c)) + cc = MB_TOLOWER(c); + else if (MB_ISLOWER(c)) + cc = MB_TOUPPER(c); else return vim_strchr(s, c); @@ -6637,9 +6638,9 @@ } } else if (magic) - STRCPY(p, p + 1); /* remove '~' */ + mch_memmove(p, p + 1, STRLEN(p)); /* remove '~' */ else - STRCPY(p, p + 2); /* remove '\~' */ + mch_memmove(p, p + 2, STRLEN(p) - 1); /* remove '\~' */ --p; } else @@ -7014,7 +7015,14 @@ #ifdef FEAT_MBYTE if (has_mbyte) { - int l = mb_ptr2len(s) - 1; + int l; + + /* Copy composing characters separately, one + * at a time. */ + if (enc_utf8) + l = utf_ptr2len(s) - 1; + else + l = mb_ptr2len(s) - 1; s += l; len -= l; diff -Naur vim71.orig/src/screen.c vim71/src/screen.c --- vim71.orig/src/screen.c 2007-05-07 19:27:53.000000000 +0000 +++ vim71/src/screen.c 2007-10-24 22:09:09.000000000 +0000 @@ -100,27 +100,7 @@ static int screen_cur_row, screen_cur_col; /* last known cursor position */ #ifdef FEAT_SEARCH_EXTRA -/* - * Struct used for highlighting 'hlsearch' matches for the last use search - * pattern or a ":match" item. - * For 'hlsearch' there is one pattern for all windows. For ":match" there is - * a different pattern for each window. - */ -typedef struct -{ - regmmatch_T rm; /* points to the regexp program; contains last found - match (may continue in next line) */ - buf_T *buf; /* the buffer to search for a match */ - linenr_T lnum; /* the line to search for a match */ - int attr; /* attributes to be used for a match */ - int attr_cur; /* attributes currently active in win_line() */ - linenr_T first_lnum; /* first lnum to search for multi-line pat */ - colnr_T startcol; /* in win_line() points to char where HL starts */ - colnr_T endcol; /* in win_line() points to char where HL ends */ -} match_T; - static match_T search_hl; /* used for 'hlsearch' highlight matching */ -static match_T match_hl[3]; /* used for ":match" highlight matching */ #endif #ifdef FEAT_FOLDING @@ -155,6 +135,7 @@ static void redraw_custum_statusline __ARGS((win_T *wp)); #endif #ifdef FEAT_SEARCH_EXTRA +#define SEARCH_HL_PRIORITY 0 static void start_search_hl __ARGS((void)); static void end_search_hl __ARGS((void)); static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum)); @@ -350,6 +331,11 @@ { if (type < must_redraw) /* use maximal type */ type = must_redraw; + + /* must_redraw is reset here, so that when we run into some weird + * reason to redraw while busy redrawing (e.g., asynchronous + * scrolling), or update_topline() in win_update() will cause a + * scroll, the screen will be redrawn later or in win_update(). */ must_redraw = 0; } @@ -787,6 +773,7 @@ w_topline got smaller a bit */ #endif #ifdef FEAT_SEARCH_EXTRA + matchitem_T *cur; /* points to the match list */ int top_to_mod = FALSE; /* redraw above mod_top */ #endif @@ -848,18 +835,20 @@ #endif #ifdef FEAT_SEARCH_EXTRA - /* Setup for ":match" and 'hlsearch' highlighting. Disable any previous + /* Setup for match and 'hlsearch' highlighting. Disable any previous * match */ - for (i = 0; i < 3; ++i) + cur = wp->w_match_head; + while (cur != NULL) { - match_hl[i].rm = wp->w_match[i]; - if (wp->w_match_id[i] == 0) - match_hl[i].attr = 0; - else - match_hl[i].attr = syn_id2attr(wp->w_match_id[i]); - match_hl[i].buf = buf; - match_hl[i].lnum = 0; - match_hl[i].first_lnum = 0; + cur->hl.rm = cur->match; + if (cur->hlg_id == 0) + cur->hl.attr = 0; + else + cur->hl.attr = syn_id2attr(cur->hlg_id); + cur->hl.buf = buf; + cur->hl.lnum = 0; + cur->hl.first_lnum = 0; + cur = cur->next; } search_hl.buf = buf; search_hl.lnum = 0; @@ -923,19 +912,25 @@ * change in one line may make the Search highlighting in a * previous line invalid. Simple solution: redraw all visible * lines above the change. - * Same for a ":match" pattern. + * Same for a match pattern. */ if (search_hl.rm.regprog != NULL && re_multiline(search_hl.rm.regprog)) top_to_mod = TRUE; else - for (i = 0; i < 3; ++i) - if (match_hl[i].rm.regprog != NULL - && re_multiline(match_hl[i].rm.regprog)) + { + cur = wp->w_match_head; + while (cur != NULL) + { + if (cur->match.regprog != NULL + && re_multiline(cur->match.regprog)) { top_to_mod = TRUE; break; } + cur = cur->next; + } + } #endif } #ifdef FEAT_FOLDING @@ -1029,6 +1024,13 @@ type = VALID; } + /* Trick: we want to avoid clearing the screen twice. screenclear() will + * set "screen_cleared" to TRUE. The special value MAYBE (which is still + * non-zero and thus not FALSE) will indicate that screenclear() was not + * called. */ + if (screen_cleared) + screen_cleared = MAYBE; + /* * If there are no changes on the screen that require a complete redraw, * handle three cases: @@ -1230,7 +1232,11 @@ mid_end = wp->w_height; if (lastwin == firstwin) { - screenclear(); + /* Clear the screen when it was not done by win_del_lines() or + * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE + * then. */ + if (screen_cleared != TRUE) + screenclear(); #ifdef FEAT_WINDOWS /* The screen was cleared, redraw the tab pages line. */ if (redraw_tabline) @@ -1238,6 +1244,13 @@ #endif } } + + /* When win_del_lines() or win_ins_lines() caused the screen to be + * cleared (only happens for the first window) or when screenclear() + * was called directly above, "must_redraw" will have been set to + * NOT_VALID, need to reset it here to avoid redrawing twice. */ + if (screen_cleared == TRUE) + must_redraw = 0; } else { @@ -2292,9 +2305,11 @@ prev_c = u8c; #endif /* Non-BMP character: display as ? or fullwidth ?. */ +#ifdef UNICODE16 if (u8c >= 0x10000) ScreenLinesUC[idx] = (cells == 2) ? 0xff1f : (int)'?'; else +#endif ScreenLinesUC[idx] = u8c; for (i = 0; i < Screen_mco; ++i) { @@ -2542,7 +2557,7 @@ char_u extra[18]; /* "%ld" and 'fdc' must fit in here */ int n_extra = 0; /* number of extra chars */ - char_u *p_extra = NULL; /* string of extra chars */ + char_u *p_extra = NULL; /* string of extra chars, plus NUL */ int c_extra = NUL; /* extra chars, all the same */ int extra_attr = 0; /* attributes when n_extra != 0 */ static char_u *at_end_str = (char_u *)""; /* used for p_extra when @@ -2626,10 +2641,13 @@ int line_attr = 0; /* atrribute for the whole line */ #endif #ifdef FEAT_SEARCH_EXTRA - match_T *shl; /* points to search_hl or match_hl */ -#endif -#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_MBYTE) - int i; + matchitem_T *cur; /* points to the match list */ + match_T *shl; /* points to search_hl or a match */ + int shl_flag; /* flag to indicate whether search_hl + has been processed or not */ + int prevcol_hl_flag; /* flag to indicate whether prevcol + equals startcol of search_hl or one + of the matches */ #endif #ifdef FEAT_ARABIC int prev_c = 0; /* previous Arabic character */ @@ -3074,12 +3092,20 @@ #ifdef FEAT_SEARCH_EXTRA /* - * Handle highlighting the last used search pattern and ":match". - * Do this for both search_hl and match_hl[3]. + * Handle highlighting the last used search pattern and matches. + * Do this for both search_hl and the match list. */ - for (i = 3; i >= 0; --i) + cur = wp->w_match_head; + shl_flag = FALSE; + while (cur != NULL || shl_flag == FALSE) { - shl = (i == 3) ? &search_hl : &match_hl[i]; + if (shl_flag == FALSE) + { + shl = &search_hl; + shl_flag = TRUE; + } + else + shl = &cur->hl; shl->startcol = MAXCOL; shl->endcol = MAXCOL; shl->attr_cur = 0; @@ -3122,6 +3148,8 @@ area_highlighting = TRUE; } } + if (shl != &search_hl && cur != NULL) + cur = cur->next; } #endif @@ -3163,10 +3191,8 @@ if (cmdwin_type != 0 && wp == curwin) { /* Draw the cmdline character. */ - *extra = cmdwin_type; n_extra = 1; - p_extra = extra; - c_extra = NUL; + c_extra = cmdwin_type; char_attr = hl_attr(HLF_AT); } } @@ -3182,6 +3208,7 @@ fill_foldcolumn(extra, wp, FALSE, lnum); n_extra = wp->w_p_fdc; p_extra = extra; + p_extra[n_extra] = NUL; c_extra = NUL; char_attr = hl_attr(HLF_FC); } @@ -3388,13 +3415,24 @@ * After end, check for start/end of next match. * When another match, have to check for start again. * Watch out for matching an empty string! - * Do this first for search_hl, then for match_hl, so that - * ":match" overrules 'hlsearch'. + * Do this for 'search_hl' and the match list (ordered by + * priority). */ v = (long)(ptr - line); - for (i = 3; i >= 0; --i) - { - shl = (i == 3) ? &search_hl : &match_hl[i]; + cur = wp->w_match_head; + shl_flag = FALSE; + while (cur != NULL || shl_flag == FALSE) + { + if (shl_flag == FALSE + && ((cur != NULL + && cur->priority > SEARCH_HL_PRIORITY) + || cur == NULL)) + { + shl = &search_hl; + shl_flag = TRUE; + } + else + shl = &cur->hl; while (shl->rm.regprog != NULL) { if (shl->startcol != MAXCOL @@ -3442,26 +3480,43 @@ } break; } + if (shl != &search_hl && cur != NULL) + cur = cur->next; } - /* ":match" highlighting overrules 'hlsearch' */ - for (i = 0; i <= 3; ++i) - if (i == 3) - search_attr = search_hl.attr_cur; - else if (match_hl[i].attr_cur != 0) + /* Use attributes from match with highest priority among + * 'search_hl' and the match list. */ + search_attr = search_hl.attr_cur; + cur = wp->w_match_head; + shl_flag = FALSE; + while (cur != NULL || shl_flag == FALSE) + { + if (shl_flag == FALSE + && ((cur != NULL + && cur->priority > SEARCH_HL_PRIORITY) + || cur == NULL)) { - search_attr = match_hl[i].attr_cur; - break; + shl = &search_hl; + shl_flag = TRUE; } + else + shl = &cur->hl; + if (shl->attr_cur != 0) + search_attr = shl->attr_cur; + if (shl != &search_hl && cur != NULL) + cur = cur->next; + } } #endif #ifdef FEAT_DIFF if (diff_hlf != (hlf_T)0) { - if (diff_hlf == HLF_CHD && ptr - line >= change_start) + if (diff_hlf == HLF_CHD && ptr - line >= change_start + && n_extra == 0) diff_hlf = HLF_TXD; /* changed text */ - if (diff_hlf == HLF_TXD && ptr - line > change_end) + if (diff_hlf == HLF_TXD && ptr - line > change_end + && n_extra == 0) diff_hlf = HLF_CHD; /* changed line */ line_attr = hl_attr(diff_hlf); } @@ -3496,9 +3551,11 @@ * Get the next character to put on the screen. */ /* - * The 'extra' array contains the extra stuff that is inserted to - * represent special characters (non-printable stuff). When all - * characters are the same, c_extra is used. + * The "p_extra" points to the extra stuff that is inserted to + * represent special characters (non-printable stuff) and other + * things. When all characters are the same, c_extra is used. + * "p_extra" must end in a NUL to avoid mb_ptr2len() reads past + * "p_extra[n_extra]". * For the '$' of the 'list' option, n_extra == 1, p_extra == "". */ if (n_extra > 0) @@ -3611,6 +3668,8 @@ * Draw it as a space with a composing char. */ if (utf_iscomposing(mb_c)) { + int i; + for (i = Screen_mco - 1; i > 0; --i) u8cc[i] = u8cc[i - 1]; u8cc[0] = mb_c; @@ -3621,13 +3680,18 @@ if ((mb_l == 1 && c >= 0x80) || (mb_l >= 1 && mb_c == 0) || (mb_l > 1 && (!vim_isprintc(mb_c) - || mb_c >= 0x10000))) +# ifdef UNICODE16 + || mb_c >= 0x10000 +# endif + ))) { /* * Illegal UTF-8 byte: display as . * Non-BMP character : display as ? or fullwidth ?. */ +# ifdef UNICODE16 if (mb_c < 0x10000) +# endif { transchar_hex(extra, mb_c); # ifdef FEAT_RIGHTLEFT @@ -3635,11 +3699,13 @@ rl_mirror(extra); # endif } +# ifdef UNICODE16 else if (utf_char2cells(mb_c) != 2) STRCPY(extra, "?"); else /* 0xff1f in UTF-8: full-width '?' */ STRCPY(extra, "\357\274\237"); +# endif p_extra = extra; c = *p_extra; @@ -3752,10 +3818,8 @@ * a '<' in the first column. */ if (n_skip > 0 && mb_l > 1) { - extra[0] = '<'; - p_extra = extra; n_extra = 1; - c_extra = NUL; + c_extra = '<'; c = ' '; if (area_attr == 0 && search_attr == 0) { @@ -4254,14 +4318,29 @@ * highlight match at end of line. If it's beyond the last * char on the screen, just overwrite that one (tricky!) Not * needed when a '$' was displayed for 'list'. */ +#ifdef FEAT_SEARCH_EXTRA + prevcol_hl_flag = FALSE; + if (prevcol == (long)search_hl.startcol) + prevcol_hl_flag = TRUE; + else + { + cur = wp->w_match_head; + while (cur != NULL) + { + if (prevcol == (long)cur->hl.startcol) + { + prevcol_hl_flag = TRUE; + break; + } + cur = cur->next; + } + } +#endif if (lcs_eol == lcs_eol_one && ((area_attr != 0 && vcol == fromcol && c == NUL) #ifdef FEAT_SEARCH_EXTRA /* highlight 'hlsearch' match at end of line */ - || ((prevcol == (long)search_hl.startcol - || prevcol == (long)match_hl[0].startcol - || prevcol == (long)match_hl[1].startcol - || prevcol == (long)match_hl[2].startcol) + || (prevcol_hl_flag == TRUE # if defined(LINE_ATTR) && did_line_attr <= 1 # endif @@ -4302,15 +4381,27 @@ #ifdef FEAT_SEARCH_EXTRA if (area_attr == 0) { - for (i = 0; i <= 3; ++i) - { - if (i == 3) - char_attr = search_hl.attr; - else if ((ptr - line) - 1 == (long)match_hl[i].startcol) + /* Use attributes from match with highest priority among + * 'search_hl' and the match list. */ + char_attr = search_hl.attr; + cur = wp->w_match_head; + shl_flag = FALSE; + while (cur != NULL || shl_flag == FALSE) + { + if (shl_flag == FALSE + && ((cur != NULL + && cur->priority > SEARCH_HL_PRIORITY) + || cur == NULL)) { - char_attr = match_hl[i].attr; - break; + shl = &search_hl; + shl_flag = TRUE; } + else + shl = &cur->hl; + if ((ptr - line) - 1 == (long)shl->startcol) + char_attr = shl->attr; + if (shl != &search_hl && cur != NULL) + cur = cur->next; } } #endif @@ -4460,6 +4551,8 @@ { if (mb_utf8) { + int i; + ScreenLinesUC[off] = mb_c; if ((c & 0xff) == 0) ScreenLines[off] = 0x80; /* avoid storing zero */ @@ -4548,7 +4641,7 @@ /* * At end of screen line and there is more to come: Display the line - * so far. If there is no more to display it is catched above. + * so far. If there is no more to display it is caught above. */ if (( #ifdef FEAT_RIGHTLEFT @@ -4625,9 +4718,13 @@ #endif #ifdef FEAT_MBYTE && !(has_mbyte - && ((*mb_off2cells)(LineOffset[screen_row]) == 2 + && ((*mb_off2cells)(LineOffset[screen_row], + LineOffset[screen_row] + screen_Columns) + == 2 || (*mb_off2cells)(LineOffset[screen_row - 1] - + (int)Columns - 2) == 2)) + + (int)Columns - 2, + LineOffset[screen_row] + screen_Columns) + == 2)) #endif ) { @@ -4787,6 +4884,10 @@ { unsigned off_from; unsigned off_to; +#ifdef FEAT_MBYTE + unsigned max_off_from; + unsigned max_off_to; +#endif int col = 0; #if defined(FEAT_GUI) || defined(UNIX) || defined(FEAT_VERTSPLIT) int hl; @@ -4813,6 +4914,10 @@ off_from = (unsigned)(current_ScreenLine - ScreenLines); off_to = LineOffset[row] + coloff; +#ifdef FEAT_MBYTE + max_off_from = off_from + screen_Columns; + max_off_to = LineOffset[row] + screen_Columns; +#endif #ifdef FEAT_RIGHTLEFT if (rlflag) @@ -4847,7 +4952,7 @@ { #ifdef FEAT_MBYTE if (has_mbyte && (col + 1 < endcol)) - char_cells = (*mb_off2cells)(off_from); + char_cells = (*mb_off2cells)(off_from, max_off_from); else char_cells = 1; #endif @@ -4924,7 +5029,7 @@ * ScreenLinesUC[] is sufficient. */ if (char_cells == 1 && col + 1 < endcol - && (*mb_off2cells)(off_to) > 1) + && (*mb_off2cells)(off_to, max_off_to) > 1) { /* Writing a single-cell character over a double-cell * character: need to redraw the next cell. */ @@ -4933,8 +5038,8 @@ } else if (char_cells == 2 && col + 2 < endcol - && (*mb_off2cells)(off_to) == 1 - && (*mb_off2cells)(off_to + 1) > 1) + && (*mb_off2cells)(off_to, max_off_to) == 1 + && (*mb_off2cells)(off_to + 1, max_off_to) > 1) { /* Writing the second half of a double-cell character over * a double-cell character: need to redraw the second @@ -4953,10 +5058,10 @@ * char over the left halve of an existing one. */ if (has_mbyte && col + char_cells == endcol && ((char_cells == 1 - && (*mb_off2cells)(off_to) > 1) + && (*mb_off2cells)(off_to, max_off_to) > 1) || (char_cells == 2 - && (*mb_off2cells)(off_to) == 1 - && (*mb_off2cells)(off_to + 1) > 1))) + && (*mb_off2cells)(off_to, max_off_to) == 1 + && (*mb_off2cells)(off_to + 1, max_off_to) > 1))) clear_next = TRUE; #endif @@ -5096,10 +5201,11 @@ /* find previous character by counting from first * column and get its width. */ unsigned off = LineOffset[row]; + unsigned max_off = LineOffset[row] + screen_Columns; while (off < off_to) { - prev_cells = (*mb_off2cells)(off); + prev_cells = (*mb_off2cells)(off, max_off); off += prev_cells; } } @@ -5285,7 +5391,7 @@ static int skip_status_match_char __ARGS((expand_T *xp, char_u *s)); /* - * Get the lenght of an item as it will be shown in the status line. + * Get the length of an item as it will be shown in the status line. */ static int status_match_len(xp, s) @@ -5351,7 +5457,7 @@ int row; char_u *buf; int len; - int clen; /* lenght in screen cells */ + int clen; /* length in screen cells */ int fillchar; int attr; int i; @@ -6103,6 +6209,7 @@ char_u *ptr = text; int c; #ifdef FEAT_MBYTE + unsigned max_off; int mbyte_blen = 1; int mbyte_cells = 1; int u8c = 0; @@ -6119,8 +6226,12 @@ return; off = LineOffset[row] + col; - while (*ptr != NUL && col < screen_Columns - && (len < 0 || (int)(ptr - text) < len)) +#ifdef FEAT_MBYTE + max_off = LineOffset[row] + screen_Columns; +#endif + while (col < screen_Columns + && (len < 0 || (int)(ptr - text) < len) + && *ptr != NUL) { c = *ptr; #ifdef FEAT_MBYTE @@ -6143,6 +6254,7 @@ else u8c = utfc_ptr2char(ptr, u8cc); mbyte_cells = utf_char2cells(u8c); +# ifdef UNICODE16 /* Non-BMP character: display as ? or fullwidth ?. */ if (u8c >= 0x10000) { @@ -6150,6 +6262,7 @@ if (attr == 0) attr = hl_attr(HLF_8); } +# endif # ifdef FEAT_ARABIC if (p_arshape && !p_tbidi && ARABIC_CHAR(u8c)) { @@ -6241,19 +6354,19 @@ else if (has_mbyte && (len < 0 ? ptr[mbyte_blen] == NUL : ptr + mbyte_blen >= text + len) - && ((mbyte_cells == 1 && (*mb_off2cells)(off) > 1) + && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1) || (mbyte_cells == 2 - && (*mb_off2cells)(off) == 1 - && (*mb_off2cells)(off + 1) > 1))) + && (*mb_off2cells)(off, max_off) == 1 + && (*mb_off2cells)(off + 1, max_off) > 1))) clear_next_cell = TRUE; /* Make sure we never leave a second byte of a double-byte behind, * it confuses mb_off2cells(). */ if (enc_dbcs - && ((mbyte_cells == 1 && (*mb_off2cells)(off) > 1) + && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1) || (mbyte_cells == 2 - && (*mb_off2cells)(off) == 1 - && (*mb_off2cells)(off + 1) > 1))) + && (*mb_off2cells)(off, max_off) == 1 + && (*mb_off2cells)(off + 1, max_off) > 1))) ScreenLines[off + mbyte_blen] = 0; #endif ScreenLines[off] = c; @@ -6318,7 +6431,7 @@ #ifdef FEAT_SEARCH_EXTRA /* - * Prepare for 'searchhl' highlighting. + * Prepare for 'hlsearch' highlighting. */ static void start_search_hl() @@ -6331,7 +6444,7 @@ } /* - * Clean up for 'searchhl' highlighting. + * Clean up for 'hlsearch' highlighting. */ static void end_search_hl() @@ -6351,18 +6464,28 @@ win_T *wp; linenr_T lnum; { - match_T *shl; /* points to search_hl or match_hl */ + matchitem_T *cur; /* points to the match list */ + match_T *shl; /* points to search_hl or a match */ + int shl_flag; /* flag to indicate whether search_hl + has been processed or not */ int n; - int i; /* * When using a multi-line pattern, start searching at the top * of the window or just after a closed fold. - * Do this both for search_hl and match_hl[3]. + * Do this both for search_hl and the match list. */ - for (i = 3; i >= 0; --i) + cur = wp->w_match_head; + shl_flag = FALSE; + while (cur != NULL || shl_flag == FALSE) { - shl = (i == 3) ? &search_hl : &match_hl[i]; + if (shl_flag == FALSE) + { + shl = &search_hl; + shl_flag = TRUE; + } + else + shl = &cur->hl; if (shl->rm.regprog != NULL && shl->lnum == 0 && re_multiline(shl->rm.regprog)) @@ -6397,11 +6520,13 @@ } } } + if (shl != &search_hl && cur != NULL) + cur = cur->next; } } /* - * Search for a next 'searchl' or ":match" match. + * Search for a next 'hlsearch' or match. * Uses shl->buf. * Sets shl->lnum and shl->rm contents. * Note: Assumes a previous match is always before "lnum", unless @@ -6411,7 +6536,7 @@ static void next_search_hl(win, shl, lnum, mincol) win_T *win; - match_T *shl; /* points to search_hl or match_hl */ + match_T *shl; /* points to search_hl or a match */ linenr_T lnum; colnr_T mincol; /* minimal column for a match */ { @@ -6479,7 +6604,7 @@ /* Error while handling regexp: stop using this regexp. */ if (shl == &search_hl) { - /* don't free the regprog in match_hl[], it's a copy */ + /* don't free regprog in the match list, it's a copy */ vim_free(shl->rm.regprog); no_hlsearch = TRUE; } @@ -6827,6 +6952,9 @@ { int r, c; int off; +#ifdef FEAT_MBYTE + int max_off; +#endif /* Can't use ScreenLines unless initialized */ if (ScreenLines == NULL) @@ -6837,10 +6965,13 @@ for (r = row; r < row + height; ++r) { off = LineOffset[r]; +#ifdef FEAT_MBYTE + max_off = off + screen_Columns; +#endif for (c = col; c < col + width; ++c) { #ifdef FEAT_MBYTE - if (enc_dbcs != 0 && dbcs_off2cells(off + c) > 1) + if (enc_dbcs != 0 && dbcs_off2cells(off + c, max_off) > 1) { screen_char_2(off + c, r, c); ++c; @@ -6850,7 +6981,7 @@ { screen_char(off + c, r, c); #ifdef FEAT_MBYTE - if (utf_off2cells(off + c) > 1) + if (utf_off2cells(off + c, max_off) > 1) ++c; #endif } diff -Naur vim71.orig/src/search.c vim71/src/search.c --- vim71.orig/src/search.c 2007-05-07 19:42:02.000000000 +0000 +++ vim71/src/search.c 2007-10-24 22:09:07.000000000 +0000 @@ -101,7 +101,6 @@ static char_u *mr_pattern = NULL; /* pattern used by search_regcomp() */ #ifdef FEAT_RIGHTLEFT static int mr_pattern_alloced = FALSE; /* mr_pattern was allocated */ -static char_u *reverse_text __ARGS((char_u *s)); #endif #ifdef FEAT_FIND_ID @@ -228,12 +227,12 @@ return mr_pattern; } -#ifdef FEAT_RIGHTLEFT +#if defined(FEAT_RIGHTLEFT) || defined(PROTO) /* * Reverse text into allocated memory. * Returns the allocated string, NULL when out of memory. */ - static char_u * + char_u * reverse_text(s) char_u *s; { @@ -573,8 +572,12 @@ /* * Start searching in current line, unless searching backwards and * we're in column 0. + * If we are searching backwards, in column 0, and not including the + * current position, gain some efficiency by skipping back a line. + * Otherwise begin the search in the current line. */ - if (dir == BACKWARD && start_pos.col == 0) + if (dir == BACKWARD && start_pos.col == 0 + && (options & SEARCH_START) == 0) { lnum = pos->lnum - 1; at_first_line = FALSE; @@ -1894,7 +1897,7 @@ } #ifdef FEAT_RIGHTLEFT - /* This is just guessing: when 'rightleft' is set, search for a maching + /* This is just guessing: when 'rightleft' is set, search for a matching * paren/brace in the other direction. */ if (curwin->w_p_rl && vim_strchr((char_u *)"()[]{}<>", initc) != NULL) backwards = !backwards; @@ -2124,6 +2127,9 @@ else if (!backwards) inquote = TRUE; } + + /* ml_get() only keeps one line, need to get linep again */ + linep = ml_get(pos.lnum); } } } @@ -2795,7 +2801,7 @@ i = inc_cursor(); if (i == -1 || (i >= 1 && last_line)) /* started at last char in file */ return FAIL; - if (i == 1 && eol && count == 0) /* started at last char in line */ + if (i >= 1 && eol && count == 0) /* started at last char in line */ return OK; /* @@ -3600,13 +3606,16 @@ { oap->start = start_pos; oap->motion_type = MCHAR; + oap->inclusive = FALSE; if (sol) - { incl(&curwin->w_cursor); - oap->inclusive = FALSE; - } - else + else if (lt(start_pos, curwin->w_cursor)) + /* Include the character under the cursor. */ oap->inclusive = TRUE; + else + /* End is before the start (no text in between <>, [], etc.): don't + * operate on any text. */ + curwin->w_cursor = start_pos; } return OK; @@ -3734,7 +3743,7 @@ if (in_html_tag(FALSE)) { - /* cursor on start tag, move to just after it */ + /* cursor on start tag, move to its '>' */ while (*ml_get_cursor() != '>') if (inc_cursor() < 0) break; @@ -3838,7 +3847,7 @@ /* Exclude the start tag. */ curwin->w_cursor = start_pos; while (inc_cursor() >= 0) - if (*ml_get_cursor() == '>' && lt(curwin->w_cursor, end_pos)) + if (*ml_get_cursor() == '>') { inc_cursor(); start_pos = curwin->w_cursor; @@ -3860,7 +3869,11 @@ #ifdef FEAT_VISUAL if (VIsual_active) { - if (*p_sel == 'e') + /* If the end is before the start there is no text between tags, select + * the char under the cursor. */ + if (lt(end_pos, start_pos)) + curwin->w_cursor = start_pos; + else if (*p_sel == 'e') ++curwin->w_cursor.col; VIsual = start_pos; VIsual_mode = 'v'; @@ -3872,7 +3885,15 @@ { oap->start = start_pos; oap->motion_type = MCHAR; - oap->inclusive = TRUE; + if (lt(end_pos, start_pos)) + { + /* End is before the start: there is no text between tags; operate + * on an empty area. */ + curwin->w_cursor = start_pos; + oap->inclusive = FALSE; + } + else + oap->inclusive = TRUE; } retval = OK; diff -Naur vim71.orig/src/spell.c vim71/src/spell.c --- vim71.orig/src/spell.c 2007-05-07 19:48:38.000000000 +0000 +++ vim71/src/spell.c 2007-10-24 22:09:07.000000000 +0000 @@ -7829,7 +7829,7 @@ # if (_MSC_VER <= 1200) /* This line is required for VC6 without the service pack. Also see the * matching #pragma below. */ -/* # pragma optimize("", off) */ + # pragma optimize("", off) # endif #endif @@ -7859,7 +7859,7 @@ #ifdef _MSC_VER # if (_MSC_VER <= 1200) -/* # pragma optimize("", on) */ + # pragma optimize("", on) # endif #endif @@ -12182,7 +12182,9 @@ { n = mb_cptr2len(p); c = mb_ptr2char(p); - if (!soundfold && !spell_iswordp(p + n, curbuf)) + if (p[n] == NUL) + c2 = NUL; + else if (!soundfold && !spell_iswordp(p + n, curbuf)) c2 = c; /* don't swap non-word char */ else c2 = mb_ptr2char(p + n); @@ -12190,12 +12192,21 @@ else #endif { - if (!soundfold && !spell_iswordp(p + 1, curbuf)) + if (p[1] == NUL) + c2 = NUL; + else if (!soundfold && !spell_iswordp(p + 1, curbuf)) c2 = c; /* don't swap non-word char */ else c2 = p[1]; } + /* When the second character is NUL we can't swap. */ + if (c2 == NUL) + { + sp->ts_state = STATE_REP_INI; + break; + } + /* When characters are identical, swap won't do anything. * Also get here if the second char is not a word character. */ if (c == c2) diff -Naur vim71.orig/src/structs.h vim71/src/structs.h --- vim71.orig/src/structs.h 2007-05-07 19:50:49.000000000 +0000 +++ vim71/src/structs.h 2007-10-24 22:09:09.000000000 +0000 @@ -278,6 +278,9 @@ linenr_T ue_lcount; /* linecount when u_save called */ char_u **ue_array; /* array of lines in undo block */ long ue_size; /* number of lines in ue_array */ +#ifdef U_DEBUG + int ue_magic; /* magic number to check allocation */ +#endif }; struct u_header @@ -300,6 +303,9 @@ visualinfo_T uh_visual; /* Visual areas before undo/after redo */ #endif time_t uh_time; /* timestamp when the change was made */ +#ifdef U_DEBUG + int uh_magic; /* magic number to check allocation */ +#endif }; /* values for uh_flags */ @@ -1453,6 +1459,7 @@ #ifdef FEAT_MBYTE char_u *b_start_fenc; /* 'fileencoding' when edit started or NULL */ int b_bad_char; /* "++bad=" argument when edit started or 0 */ + int b_start_bomb; /* 'bomb' when it was read */ #endif #ifdef FEAT_EVAL @@ -1694,6 +1701,41 @@ #define FR_COL 2 /* frame with a column of windows */ /* + * Struct used for highlighting 'hlsearch' matches, matches defined by + * ":match" and matches defined by match functions. + * For 'hlsearch' there is one pattern for all windows. For ":match" and the + * match functions there is a different pattern for each window. + */ +typedef struct +{ + regmmatch_T rm; /* points to the regexp program; contains last found + match (may continue in next line) */ + buf_T *buf; /* the buffer to search for a match */ + linenr_T lnum; /* the line to search for a match */ + int attr; /* attributes to be used for a match */ + int attr_cur; /* attributes currently active in win_line() */ + linenr_T first_lnum; /* first lnum to search for multi-line pat */ + colnr_T startcol; /* in win_line() points to char where HL starts */ + colnr_T endcol; /* in win_line() points to char where HL ends */ +} match_T; + +/* + * matchitem_T provides a linked list for storing match items for ":match" and + * the match functions. + */ +typedef struct matchitem matchitem_T; +struct matchitem +{ + matchitem_T *next; + int id; /* match ID */ + int priority; /* match priority */ + char_u *pattern; /* pattern to highlight */ + int hlg_id; /* highlight group ID */ + regmmatch_T match; /* regexp program for pattern */ + match_T hl; /* struct for doing the actual highlighting */ +}; + +/* * Structure which contains all information that belongs to a window * * All row numbers are relative to the start of the window, except w_winrow. @@ -1934,9 +1976,8 @@ #endif #ifdef FEAT_SEARCH_EXTRA - regmmatch_T w_match[3]; /* regexp programs for ":match" */ - char_u *(w_match_pat[3]); /* patterns for ":match" */ - int w_match_id[3]; /* highlight IDs for ":match" */ + matchitem_T *w_match_head; /* head of match list */ + int w_next_match_id; /* next match ID */ #endif /* diff -Naur vim71.orig/src/syntax.c vim71/src/syntax.c --- vim71.orig/src/syntax.c 2007-05-07 19:42:55.000000000 +0000 +++ vim71/src/syntax.c 2007-10-24 22:09:09.000000000 +0000 @@ -66,8 +66,10 @@ #define HL_TABLE() ((struct hl_group *)((highlight_ga.ga_data))) #ifdef FEAT_CMDL_COMPL -static int include_default = FALSE; /* include "default" for expansion */ -static int include_link = FALSE; /* include "link" for expansion */ +/* Flags to indicate an additional string for highlight name completion. */ +static int include_none = 0; /* when 1 include "None" */ +static int include_default = 0; /* when 1 include "default" */ +static int include_link = 0; /* when 2 include "link" and "clear" */ #endif /* @@ -277,7 +279,8 @@ */ typedef struct state_item { - int si_idx; /* index of syntax pattern */ + int si_idx; /* index of syntax pattern or + KEYWORD_IDX */ int si_id; /* highlight group ID for keywords */ int si_trans_id; /* idem, transparancy removed */ int si_m_lnum; /* lnum of the match */ @@ -835,9 +838,18 @@ current_lnum = end_lnum; break; } - spp = &(SYN_ITEMS(syn_buf)[cur_si->si_idx]); - found_flags = spp->sp_flags; - found_match_idx = spp->sp_sync_idx; + if (cur_si->si_idx < 0) + { + /* Cannot happen? */ + found_flags = 0; + found_match_idx = KEYWORD_IDX; + } + else + { + spp = &(SYN_ITEMS(syn_buf)[cur_si->si_idx]); + found_flags = spp->sp_flags; + found_match_idx = spp->sp_sync_idx; + } found_current_lnum = current_lnum; found_current_col = current_col; found_m_endpos = cur_si->si_m_endpos; @@ -1725,6 +1737,13 @@ { int attr = 0; + if (can_spell != NULL) + /* Default: Only do spelling when there is no @Spell cluster or when + * ":syn spell toplevel" was used. */ + *can_spell = syn_buf->b_syn_spell == SYNSPL_DEFAULT + ? (syn_buf->b_spell_cluster_id == 0) + : (syn_buf->b_syn_spell == SYNSPL_TOP); + /* check for out of memory situation */ if (syn_buf->b_sst_array == NULL) return 0; @@ -2524,6 +2543,10 @@ stateitem_T *sip = &CUR_STATE(idx); synpat_T *spp; + /* This should not happen... */ + if (sip->si_idx < 0) + return; + spp = &(SYN_ITEMS(syn_buf)[sip->si_idx]); if (sip->si_flags & HL_MATCH) sip->si_id = spp->sp_syn_match_id; @@ -2639,6 +2662,10 @@ lpos_T end_endpos; int end_idx; + /* return quickly for a keyword */ + if (sip->si_idx < 0) + return; + /* Don't update when it's already done. Can be a match of an end pattern * that started in a previous line. Watch out: can also be a "keepend" * from a containing item. */ @@ -2751,6 +2778,10 @@ char_u *line; int had_match = FALSE; + /* just in case we are invoked for a keyword */ + if (idx < 0) + return; + /* * Check for being called with a START pattern. * Can happen with a match that continues to the next line, because it @@ -3323,6 +3354,7 @@ { vim_free(SYN_ITEMS(buf)[i].sp_cont_list); vim_free(SYN_ITEMS(buf)[i].sp_next_list); + vim_free(SYN_ITEMS(buf)[i].sp_syn.cont_in_list); } } @@ -4460,8 +4492,8 @@ current_syn_inc_tag = ++running_syn_inc_tag; prev_toplvl_grp = curbuf->b_syn_topgrp; curbuf->b_syn_topgrp = sgl_id; - if (source ? do_source(eap->arg, FALSE, FALSE) == FAIL - : source_runtime(eap->arg, DOSO_NONE) == FAIL) + if (source ? do_source(eap->arg, FALSE, DOSO_NONE) == FAIL + : source_runtime(eap->arg, TRUE) == FAIL) EMSG2(_(e_notopen), eap->arg); curbuf->b_syn_topgrp = prev_toplvl_grp; current_syn_inc_tag = prev_syn_inc_tag; @@ -5956,8 +5988,8 @@ { return (buf->b_syn_patterns.ga_len != 0 || buf->b_syn_clusters.ga_len != 0 - || curbuf->b_keywtab.ht_used > 0 - || curbuf->b_keywtab_ic.ht_used > 0); + || buf->b_keywtab.ht_used > 0 + || buf->b_keywtab_ic.ht_used > 0); } #if defined(FEAT_CMDL_COMPL) || defined(PROTO) @@ -5968,6 +6000,29 @@ EXP_CASE /* expand ":syn case" arguments */ } expand_what; +/* + * Reset include_link, include_default, include_none to 0. + * Called when we are done expanding. + */ + void +reset_expand_highlight() +{ + include_link = include_default = include_none = 0; +} + +/* + * Handle command line completion for :match and :echohl command: Add "None" + * as highlight group. + */ + void +set_context_in_echohl_cmd(xp, arg) + expand_T *xp; + char_u *arg; +{ + xp->xp_context = EXPAND_HIGHLIGHT; + xp->xp_pattern = arg; + include_none = 1; +} /* * Handle command line completion for :syntax command. @@ -5983,8 +6038,8 @@ xp->xp_context = EXPAND_SYNTAX; expand_what = EXP_SUBCMD; xp->xp_pattern = arg; - include_link = FALSE; - include_default = FALSE; + include_link = 0; + include_default = 0; /* (part of) subcommand already typed */ if (*arg != NUL) @@ -8479,7 +8534,7 @@ syn_id2name(id) int id; { - if (id <= 0 || id >= highlight_ga.ga_len) + if (id <= 0 || id > highlight_ga.ga_len) return (char_u *)""; return HL_TABLE()[id - 1].sg_name; } @@ -8949,7 +9004,7 @@ return OK; } -#ifdef FEAT_CMDL_COMPL +#if defined(FEAT_CMDL_COMPL) || defined(PROTO) static void highlight_list __ARGS((void)); static void highlight_list_two __ARGS((int cnt, int attr)); @@ -8967,8 +9022,8 @@ /* Default: expand group names */ xp->xp_context = EXPAND_HIGHLIGHT; xp->xp_pattern = arg; - include_link = TRUE; - include_default = TRUE; + include_link = 2; + include_default = 1; /* (part of) subcommand already typed */ if (*arg != NUL) @@ -8976,7 +9031,7 @@ p = skiptowhite(arg); if (*p != NUL) /* past "default" or group name */ { - include_default = FALSE; + include_default = 0; if (STRNCMP("default", arg, p - arg) == 0) { arg = skipwhite(p); @@ -8985,7 +9040,7 @@ } if (*p != NUL) /* past group name */ { - include_link = FALSE; + include_link = 0; if (arg[1] == 'i' && arg[0] == 'N') highlight_list(); if (STRNCMP("link", arg, p - arg) == 0 @@ -9045,31 +9100,25 @@ expand_T *xp; int idx; { - if (idx == highlight_ga.ga_len #ifdef FEAT_CMDL_COMPL - && include_link -#endif - ) + if (idx == highlight_ga.ga_len && include_none != 0) + return (char_u *)"none"; + if (idx == highlight_ga.ga_len + include_none && include_default != 0) + return (char_u *)"default"; + if (idx == highlight_ga.ga_len + include_none + include_default + && include_link != 0) return (char_u *)"link"; - if (idx == highlight_ga.ga_len + 1 -#ifdef FEAT_CMDL_COMPL - && include_link -#endif - ) + if (idx == highlight_ga.ga_len + include_none + include_default + 1 + && include_link != 0) return (char_u *)"clear"; - if (idx == highlight_ga.ga_len + 2 -#ifdef FEAT_CMDL_COMPL - && include_default #endif - ) - return (char_u *)"default"; if (idx < 0 || idx >= highlight_ga.ga_len) return NULL; return HL_TABLE()[idx].sg_name; } #endif -#ifdef FEAT_GUI +#if defined(FEAT_GUI) || defined(PROTO) /* * Free all the highlight group fonts. * Used when quitting for systems which need it. diff -Naur vim71.orig/src/term.c vim71/src/term.c --- vim71.orig/src/term.c 2007-05-07 19:39:11.000000000 +0000 +++ vim71/src/term.c 2007-10-24 22:09:09.000000000 +0000 @@ -4809,6 +4809,8 @@ if (num_bytes == -1) return -1; current_tab = (int)bytes[0]; + if (current_tab == 255) /* -1 in a byte gives 255 */ + current_tab = -1; slen += num_bytes; } else if (key_name[0] == (int)KS_TABMENU) diff -Naur vim71.orig/src/termlib.c vim71/src/termlib.c --- vim71.orig/src/termlib.c 2007-05-07 19:39:49.000000000 +0000 +++ vim71/src/termlib.c 2007-10-24 22:09:07.000000000 +0000 @@ -191,7 +191,7 @@ lbuf[0] == '\t' && lbuf[1] == ':') { - strcpy(lbuf, lbuf+2); + mch_memmove(lbuf, lbuf + 2, strlen(lbuf + 2) + 1); llen -= 2; } if (lbuf[llen-2] == '\\') /* and continuations */ diff -Naur vim71.orig/src/testdir/Makefile vim71/src/testdir/Makefile --- vim71.orig/src/testdir/Makefile 2006-04-30 11:08:01.000000000 +0000 +++ vim71/src/testdir/Makefile 2007-10-24 22:09:09.000000000 +0000 @@ -1,9 +1,13 @@ # -# Makefile to run al tests for Vim +# Makefile to run all tests for Vim # VIMPROG = ../vim +# Uncomment this line for using valgrind. +# The output goes into a file "valgrind.$PID" (sorry, no test number). +# VALGRIND = valgrind --tool=memcheck --leak-check=yes --num-callers=15 --logfile=valgrind + SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \ test7.out test8.out test9.out test10.out test11.out \ test12.out test13.out test14.out test15.out test17.out \ @@ -15,7 +19,8 @@ test43.out test44.out test45.out test46.out test47.out \ test48.out test49.out test51.out test52.out test53.out \ test54.out test55.out test56.out test57.out test58.out \ - test59.out test60.out test61.out test62.out + test59.out test60.out test61.out test62.out test63.out \ + test64.out SCRIPTS_GUI = test16.out @@ -34,11 +39,11 @@ $(SCRIPTS) $(SCRIPTS_GUI): $(VIMPROG) clean: - -rm -rf *.out *.failed *.rej *.orig test.log tiny.vim small.vim mbyte.vim test.ok X* viminfo + -rm -rf *.out *.failed *.rej *.orig test.log tiny.vim small.vim mbyte.vim test.ok X* valgrind.pid* viminfo test1.out: test1.in -rm -f $*.failed tiny.vim small.vim mbyte.vim test.ok X* viminfo - $(VIMPROG) -u unix.vim -U NONE --noplugin -s dotest.in $*.in + $(VALGRIND) $(VIMPROG) -u unix.vim -U NONE --noplugin -s dotest.in $*.in @/bin/sh -c "if diff test.out $*.ok; \ then mv -f test.out $*.out; \ else echo; \ @@ -51,7 +56,7 @@ cp $*.ok test.ok # Sleep a moment to avoid that the xterm title is messed up @-sleep .2 - -$(VIMPROG) -u unix.vim -U NONE --noplugin -s dotest.in $*.in + -$(VALGRIND) $(VIMPROG) -u unix.vim -U NONE --noplugin -s dotest.in $*.in @/bin/sh -c "if test -f test.out; then\ if diff test.out $*.ok; \ then mv -f test.out $*.out; \ @@ -61,5 +66,9 @@ fi" -rm -rf X* test.ok viminfo +test49.out: test49.vim + +test60.out: test60.vim + nolog: -echo Test results: >test.log diff -Naur vim71.orig/src/testdir/test14.in vim71/src/testdir/test14.in --- vim71.orig/src/testdir/test14.in 2004-06-07 14:32:05.000000000 +0000 +++ vim71/src/testdir/test14.in 2007-10-24 22:09:09.000000000 +0000 @@ -18,6 +18,7 @@ : let tt = "o\65\x42\o103 \33a\xfg\o78\" :endif :exe "normal " . tt +:unlet tt :.w >>test.out :set vb /^Piece diff -Naur vim71.orig/src/testdir/test26.in vim71/src/testdir/test26.in --- vim71.orig/src/testdir/test26.in 2004-06-07 14:32:05.000000000 +0000 +++ vim71/src/testdir/test26.in 2007-10-24 22:09:09.000000000 +0000 @@ -37,6 +37,7 @@ : endif : endif :endwhile +:unlet i j :'t,$w! test.out :qa! ENDTEST diff -Naur vim71.orig/src/testdir/test34.in vim71/src/testdir/test34.in --- vim71.orig/src/testdir/test34.in 2006-04-30 13:33:24.000000000 +0000 +++ vim71/src/testdir/test34.in 2007-10-24 22:09:09.000000000 +0000 @@ -52,7 +52,15 @@ ---*--- (one (two -[(one again:$-5,$wq! test.out +[(one again:$-5,$w! test.out +:delfunc Table +:delfunc Compute +:delfunc Expr1 +:delfunc Expr2 +:delfunc ListItem +:delfunc ListReset +:unlet retval counter +:q! ENDTEST here diff -Naur vim71.orig/src/testdir/test45.in vim71/src/testdir/test45.in --- vim71.orig/src/testdir/test45.in 2004-06-07 14:32:05.000000000 +0000 +++ vim71/src/testdir/test45.in 2007-10-24 22:09:09.000000000 +0000 @@ -55,6 +55,7 @@ /kk$ :call append("$", foldlevel(".")) :/^last/+1,$w! test.out +:delfun Flvl :qa! ENDTEST diff -Naur vim71.orig/src/testdir/test47.in vim71/src/testdir/test47.in --- vim71.orig/src/testdir/test47.in 2004-06-07 14:32:05.000000000 +0000 +++ vim71/src/testdir/test47.in 2007-10-24 22:09:09.000000000 +0000 @@ -34,6 +34,7 @@ :call append("$", two) :call append("$", three) :$-2,$w! test.out +:unlet one two three :qa! ENDTEST diff -Naur vim71.orig/src/testdir/test49.in vim71/src/testdir/test49.in --- vim71.orig/src/testdir/test49.in 2006-04-28 09:29:54.000000000 +0000 +++ vim71/src/testdir/test49.in 2007-10-24 22:09:09.000000000 +0000 @@ -1,13 +1,29 @@ This is a test of the script language. If after adding a new test, the test output doesn't appear properly in -test49.failed, try to add one ore more "G"s at the line before ENDTEST. +test49.failed, try to add one ore more "G"s at the line ending in "test.out" STARTTEST :so small.vim :se nocp nomore viminfo+=nviminfo :so test49.vim -GGGGGGGGGG"rp:.-,$wq! test.out +GGGGGGGGGGGGGG"rp:.-,$w! test.out +:" +:" make valgrind happy +:redir => funclist +:silent func +:redir END +:for line in split(funclist, "\n") +: let name = matchstr(line, 'function \zs[A-Z]\w*\ze(') +: if name != '' +: exe "delfunc " . name +: endif +:endfor +:for v in keys(g:) +: silent! exe "unlet " . v +:endfor +:unlet v +:qa! ENDTEST Results of test49.vim: diff -Naur vim71.orig/src/testdir/test55.in vim71/src/testdir/test55.in --- vim71.orig/src/testdir/test55.in 2006-10-15 14:07:05.000000000 +0000 +++ vim71/src/testdir/test55.in 2007-10-24 22:09:09.000000000 +0000 @@ -345,6 +345,10 @@ :endfun :call Test(1, 2, [3, 4], {5: 6}) " This may take a while :" +:delfunc Test +:unlet dict +:call garbagecollect(1) +:" :/^start:/,$wq! test.out ENDTEST diff -Naur vim71.orig/src/testdir/test56.in vim71/src/testdir/test56.in --- vim71.orig/src/testdir/test56.in 2006-09-03 14:28:41.000000000 +0000 +++ vim71/src/testdir/test56.in 2007-10-24 22:09:09.000000000 +0000 @@ -17,5 +17,5 @@ fun s:DoNothing() call append(line('$'), "nothing line") endfun -nnoremap _x :call DoNothing()call DoLast() +nnoremap _x :call DoNothing()call DoLast()delfunc DoNothingdelfunc DoLast end: diff -Naur vim71.orig/src/testdir/test58.in vim71/src/testdir/test58.in --- vim71.orig/src/testdir/test58.in 2006-04-03 18:24:04.000000000 +0000 +++ vim71/src/testdir/test58.in 2007-10-24 22:09:09.000000000 +0000 @@ -86,6 +86,7 @@ :$put =str `m]s:let [str, a] = spellbadword() :$put =str +:unlet str a :" :" Postponed prefixes :call TestOne('2', '1') @@ -100,6 +101,10 @@ :" NOSLITSUGS :call TestOne('8', '8') :" +:" clean up for valgrind +:delfunc TestOne +:set spl= enc=latin1 +:" gg:/^test output:/,$wq! test.out ENDTEST diff -Naur vim71.orig/src/testdir/test59.in vim71/src/testdir/test59.in --- vim71.orig/src/testdir/test59.in 2006-04-03 18:29:24.000000000 +0000 +++ vim71/src/testdir/test59.in 2007-10-24 22:09:09.000000000 +0000 @@ -90,6 +90,7 @@ :$put =str `m]s:let [str, a] = spellbadword() :$put =str +:unlet str a :" :" Postponed prefixes :call TestOne('2', '1') @@ -101,6 +102,10 @@ :call TestOne('6', '6') :call TestOne('7', '7') :" +:" clean up for valgrind +:delfunc TestOne +:set spl= enc=latin1 +:" gg:/^test output:/,$wq! test.out ENDTEST diff -Naur vim71.orig/src/testdir/test60.in vim71/src/testdir/test60.in --- vim71.orig/src/testdir/test60.in 2006-05-05 18:41:18.000000000 +0000 +++ vim71/src/testdir/test60.in 2007-10-24 22:09:09.000000000 +0000 @@ -569,6 +569,9 @@ redir END endfunction :call TestExists() +:delfunc TestExists +:delfunc RunTest +:delfunc TestFuncArg :edit! test.out :set ff=unix :w diff -Naur vim71.orig/src/testdir/test60.vim vim71/src/testdir/test60.vim --- vim71.orig/src/testdir/test60.vim 2006-01-12 19:45:59.000000000 +0000 +++ vim71/src/testdir/test60.vim 2007-10-24 22:09:09.000000000 +0000 @@ -94,4 +94,5 @@ else echo "FAILED" endif +unlet str diff -Naur vim71.orig/src/testdir/test62.in vim71/src/testdir/test62.in --- vim71.orig/src/testdir/test62.in 2006-04-30 11:29:15.000000000 +0000 +++ vim71/src/testdir/test62.in 2007-10-24 22:09:09.000000000 +0000 @@ -7,6 +7,7 @@ :let nr = tabpagenr() :q :call append(line('$'), 'tab page ' . nr) +:unlet nr :" :" Open three tab pages and use ":tabdo" :0tabnew @@ -23,6 +24,7 @@ :q! :call append(line('$'), line1) :call append(line('$'), line2) +:unlet line1 line2 :" :" :/^Results/,$w! test.out diff -Naur vim71.orig/src/testdir/test63.in vim71/src/testdir/test63.in --- vim71.orig/src/testdir/test63.in 1970-01-01 00:00:00.000000000 +0000 +++ vim71/src/testdir/test63.in 2007-10-24 22:09:09.000000000 +0000 @@ -0,0 +1,157 @@ +Test for ":match", ":2match", ":3match", "clearmatches()", "getmatches()", +"matchadd()", "matcharg()", "matchdelete()", and "setmatches()". + +STARTTEST +:so small.vim +:" --- Check that "matcharg()" returns the correct group and pattern if a match +:" --- is defined. +:let @r = "*** Test 1: " +:highlight MyGroup1 ctermbg=red +:highlight MyGroup2 ctermbg=green +:highlight MyGroup3 ctermbg=blue +:match MyGroup1 /TODO/ +:2match MyGroup2 /FIXME/ +:3match MyGroup3 /XXX/ +:if matcharg(1) == ['MyGroup1', 'TODO'] && matcharg(2) == ['MyGroup2', 'FIXME'] && matcharg(3) == ['MyGroup3', 'XXX'] +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:" --- Check that "matcharg()" returns an empty list if the argument is not 1, +:" --- 2 or 3 (only 0 and 4 are tested). +:let @r .= "*** Test 2: " +:if matcharg(0) == [] && matcharg(4) == [] +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:" --- Check that "matcharg()" returns ['', ''] if a match is not defined. +:let @r .= "*** Test 3: " +:match +:2match +:3match +:if matcharg(1) == ['', ''] && matcharg(2) == ['', ''] && matcharg(3) == ['', ''] +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:" --- Check that "matchadd()" and "getmatches()" agree on added matches and +:" --- that default values apply. +:let @r .= "*** Test 4: " +:let m1 = matchadd("MyGroup1", "TODO") +:let m2 = matchadd("MyGroup2", "FIXME", 42) +:let m3 = matchadd("MyGroup3", "XXX", 60, 17) +:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5}, {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}] +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:" --- Check that "matchdelete()" deletes the matches defined in the previous +:" --- test correctly. +:let @r .= "*** Test 5: " +:call matchdelete(m1) +:call matchdelete(m2) +:call matchdelete(m3) +:unlet m1 +:unlet m2 +:unlet m3 +:if getmatches() == [] +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:" --- Check that "matchdelete()" returns 0 if successful and otherwise -1. +:let @r .= "*** Test 6: " +:let m = matchadd("MyGroup1", "TODO") +:let r1 = matchdelete(m) +:let r2 = matchdelete(42) +:if r1 == 0 && r2 == -1 +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:unlet m +:unlet r1 +:unlet r2 +:" --- Check that "clearmatches()" clears all matches defined by ":match" and +:" --- "matchadd()". +:let @r .= "*** Test 7: " +:let m1 = matchadd("MyGroup1", "TODO") +:let m2 = matchadd("MyGroup2", "FIXME", 42) +:let m3 = matchadd("MyGroup3", "XXX", 60, 17) +:match MyGroup1 /COFFEE/ +:2match MyGroup2 /HUMPPA/ +:3match MyGroup3 /VIM/ +:call clearmatches() +:if getmatches() == [] +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:unlet m1 +:unlet m2 +:unlet m3 +:" --- Check that "setmatches()" restores a list of matches saved by +:" --- "getmatches()" without changes. (Matches with equal priority must also +:" --- remain in the same order.) +:let @r .= "*** Test 8: " +:let m1 = matchadd("MyGroup1", "TODO") +:let m2 = matchadd("MyGroup2", "FIXME", 42) +:let m3 = matchadd("MyGroup3", "XXX", 60, 17) +:match MyGroup1 /COFFEE/ +:2match MyGroup2 /HUMPPA/ +:3match MyGroup3 /VIM/ +:let ml = getmatches() +:call clearmatches() +:call setmatches(ml) +:if getmatches() == ml +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:call clearmatches() +:unlet m1 +:unlet m2 +:unlet m3 +:unlet ml +:" --- Check that "setmatches()" will not add two matches with the same ID. The +:" --- expected behaviour (for now) is to add the first match but not the +:" --- second and to return 0 (even though it is a matter of debate whether +:" --- this can be considered successful behaviour). +:let @r .= "*** Test 9: " +:let r1 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}, {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 10, 'id': 1}]) +:if getmatches() == [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}] && r1 == 0 +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:call clearmatches() +:unlet r1 +:" --- Check that "setmatches()" returns 0 if successful and otherwise -1. +:" --- (A range of valid and invalid input values are tried out to generate the +:" --- return values.) +:let @r .= "*** Test 10: " +:let rs1 = setmatches([]) +:let rs2 = setmatches([{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1}]) +:call clearmatches() +:let rf1 = setmatches(0) +:let rf2 = setmatches([0]) +:let rf3 = setmatches([{'wrong key': 'wrong value'}]) +:if rs1 == 0 && rs2 == 0 && rf1 == -1 && rf2 == -1 && rf3 == -1 +: let @r .= "OK\n" +:else +: let @r .= "FAILED\n" +:endif +:unlet rs1 +:unlet rs2 +:unlet rf1 +:unlet rf2 +:unlet rf3 +:highlight clear MyGroup1 +:highlight clear MyGroup2 +:highlight clear MyGroup3 +G"rp +:/^Results/,$wq! test.out +ENDTEST + +Results of test63: diff -Naur vim71.orig/src/testdir/test63.ok vim71/src/testdir/test63.ok --- vim71.orig/src/testdir/test63.ok 1970-01-01 00:00:00.000000000 +0000 +++ vim71/src/testdir/test63.ok 2007-10-24 22:09:07.000000000 +0000 @@ -0,0 +1,11 @@ +Results of test63: +*** Test 1: OK +*** Test 2: OK +*** Test 3: OK +*** Test 4: OK +*** Test 5: OK +*** Test 6: OK +*** Test 7: OK +*** Test 8: OK +*** Test 9: OK +*** Test 10: OK diff -Naur vim71.orig/src/testdir/test64.in vim71/src/testdir/test64.in --- vim71.orig/src/testdir/test64.in 1970-01-01 00:00:00.000000000 +0000 +++ vim71/src/testdir/test64.in 2007-10-24 22:09:09.000000000 +0000 @@ -0,0 +1,54 @@ +Test for regexp patterns. + +A pattern that gives the expected result produces OK, so that we know it was +actually tried. + +STARTTEST +:so small.vim +:" tl is a List of Lists with: +:" regexp pattern +:" text to test the pattern on +:" expected match (optional) +:" expected submatch 1 (optional) +:" expected submatch 2 (optional) +:" etc. +:" When there is no match use only the first two items. +:let tl = [] +:call add(tl, ['b', 'abcdef', 'b']) +:call add(tl, ['bc*', 'abccccdef', 'bcccc']) +:call add(tl, ['bc\{-}', 'abccccdef', 'b']) +:call add(tl, ['bc\{-}\(d\)', 'abccccdef', 'bccccd', 'd']) +:call add(tl, ['x', 'abcdef']) +:" +:for t in tl +: let l = matchlist(t[1], t[0]) +:" check the match itself +: if len(l) == 0 && len(t) > 2 +: $put ='ERROR: pat: \"' . t[0] . '\", text: \"' . t[1] . '\", did not match, expected: \"' . t[2] . '\"' +: elseif len(l) > 0 && len(t) == 2 +: $put ='ERROR: pat: \"' . t[0] . '\", text: \"' . t[1] . '\", match: \"' . l[0] . '\", expected no match' +: elseif len(t) > 2 && l[0] != t[2] +: $put ='ERROR: pat: \"' . t[0] . '\", text: \"' . t[1] . '\", match: \"' . l[0] . '\", expected: \"' . t[2] . '\"' +: else +: $put ='OK' +: endif +: if len(l) > 0 +:" check all the nine submatches +: for i in range(1, 9) +: if len(t) <= i + 2 +: let e = '' +: else +: let e = t[i + 2] +: endif +: if l[i] != e +: $put ='ERROR: pat: \"' . t[0] . '\", text: \"' . t[1] . '\", submatch ' . i . ': \"' . l[i] . '\", expected: \"' . e . '\"' +: endif +: endfor +: unlet i +: endif +:endfor +:unlet t tl e l +:/^Results/,$wq! test.out +ENDTEST + +Results of test64: diff -Naur vim71.orig/src/testdir/test64.ok vim71/src/testdir/test64.ok --- vim71.orig/src/testdir/test64.ok 1970-01-01 00:00:00.000000000 +0000 +++ vim71/src/testdir/test64.ok 2007-10-24 22:09:09.000000000 +0000 @@ -0,0 +1,6 @@ +Results of test64: +OK +OK +OK +OK +OK diff -Naur vim71.orig/src/ui.c vim71/src/ui.c --- vim71.orig/src/ui.c 2007-05-07 19:49:09.000000000 +0000 +++ vim71/src/ui.c 2007-10-24 22:09:09.000000000 +0000 @@ -1603,8 +1603,6 @@ #if defined(FEAT_GUI) || defined(FEAT_MOUSE_GPM) \ || defined(FEAT_XCLIPBOARD) || defined(VMS) \ || defined(FEAT_SNIFF) || defined(FEAT_CLIENTSERVER) \ - || (defined(FEAT_GUI) && (!defined(USE_ON_FLY_SCROLL) \ - || defined(FEAT_MENU))) \ || defined(PROTO) /* * Add the given bytes to the input buffer @@ -1630,7 +1628,9 @@ } #endif -#if (defined(FEAT_XIM) && defined(FEAT_GUI_GTK)) \ +#if ((defined(FEAT_XIM) || defined(FEAT_DND)) && defined(FEAT_GUI_GTK)) \ + || defined(FEAT_GUI_MSWIN) \ + || defined(FEAT_GUI_MAC) \ || (defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)) \ || (defined(FEAT_GUI) && (!defined(USE_ON_FLY_SCROLL) \ || defined(FEAT_MENU))) \ diff -Naur vim71.orig/src/undo.c vim71/src/undo.c --- vim71.orig/src/undo.c 2007-05-07 19:21:14.000000000 +0000 +++ vim71/src/undo.c 2007-10-24 22:09:09.000000000 +0000 @@ -76,6 +76,12 @@ * buffer is unloaded. */ +/* Uncomment the next line for including the u_check() function. This warns + * for errors in the debug information. */ +/* #define U_DEBUG 1 */ +#define UH_MAGIC 0x18dade /* value for uh_magic when in use */ +#define UE_MAGIC 0xabc123 /* value for ue_magic when in use */ + #include "vim.h" /* See below: use malloc()/free() for memory management. */ @@ -113,6 +119,95 @@ */ static int undo_undoes = FALSE; +#ifdef U_DEBUG +/* + * Check the undo structures for being valid. Print a warning when something + * looks wrong. + */ +static int seen_b_u_curhead; +static int seen_b_u_newhead; +static int header_count; + + static void +u_check_tree(u_header_T *uhp, + u_header_T *exp_uh_next, + u_header_T *exp_uh_alt_prev) +{ + u_entry_T *uep; + + if (uhp == NULL) + return; + ++header_count; + if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1) + { + EMSG("b_u_curhead found twice (looping?)"); + return; + } + if (uhp == curbuf->b_u_newhead && ++seen_b_u_newhead > 1) + { + EMSG("b_u_newhead found twice (looping?)"); + return; + } + + if (uhp->uh_magic != UH_MAGIC) + EMSG("uh_magic wrong (may be using freed memory)"); + else + { + /* Check pointers back are correct. */ + if (uhp->uh_next != exp_uh_next) + { + EMSG("uh_next wrong"); + smsg((char_u *)"expected: 0x%x, actual: 0x%x", + exp_uh_next, uhp->uh_next); + } + if (uhp->uh_alt_prev != exp_uh_alt_prev) + { + EMSG("uh_alt_prev wrong"); + smsg((char_u *)"expected: 0x%x, actual: 0x%x", + exp_uh_alt_prev, uhp->uh_alt_prev); + } + + /* Check the undo tree at this header. */ + for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) + { + if (uep->ue_magic != UE_MAGIC) + { + EMSG("ue_magic wrong (may be using freed memory)"); + break; + } + } + + /* Check the next alt tree. */ + u_check_tree(uhp->uh_alt_next, uhp->uh_next, uhp); + + /* Check the next header in this branch. */ + u_check_tree(uhp->uh_prev, uhp, NULL); + } +} + + void +u_check(int newhead_may_be_NULL) +{ + seen_b_u_newhead = 0; + seen_b_u_curhead = 0; + header_count = 0; + + u_check_tree(curbuf->b_u_oldhead, NULL, NULL); + + if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL + && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL)) + EMSGN("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead); + if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0) + EMSGN("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead); + if (header_count != curbuf->b_u_numhead) + { + EMSG("b_u_numhead invalid"); + smsg((char_u *)"expected: %ld, actual: %ld", + (long)header_count, (long)curbuf->b_u_numhead); + } +} +#endif + /* * Save the current line for both the "u" and "U" command. * Returns OK or FAIL. @@ -243,6 +338,9 @@ if (!undo_allowed()) return FAIL; +#ifdef U_DEBUG + u_check(FALSE); +#endif #ifdef FEAT_NETBEANS_INTG /* * Netbeans defines areas that cannot be modified. Bail out here when @@ -294,6 +392,9 @@ uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T)); if (uhp == NULL) goto nomem; +#ifdef U_DEBUG + uhp->uh_magic = UH_MAGIC; +#endif } else uhp = NULL; @@ -316,8 +417,11 @@ { u_header_T *uhfree = curbuf->b_u_oldhead; - /* If there is no branch only free one header. */ - if (uhfree->uh_alt_next == NULL) + if (uhfree == old_curhead) + /* Can't reconnect the branch, delete all of it. */ + u_freebranch(curbuf, uhfree, &old_curhead); + else if (uhfree->uh_alt_next == NULL) + /* There is no branch, only free one header. */ u_freeheader(curbuf, uhfree, &old_curhead); else { @@ -326,6 +430,9 @@ uhfree = uhfree->uh_alt_next; u_freebranch(curbuf, uhfree, &old_curhead); } +#ifdef U_DEBUG + u_check(TRUE); +#endif } if (uhp == NULL) /* no undo at all */ @@ -478,6 +585,9 @@ uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T)); if (uep == NULL) goto nomem; +#ifdef U_DEBUG + uep->ue_magic = UE_MAGIC; +#endif uep->ue_size = size; uep->ue_top = top; @@ -525,6 +635,9 @@ curbuf->b_u_synced = FALSE; undo_undoes = FALSE; +#ifdef U_DEBUG + u_check(FALSE); +#endif return OK; nomem: @@ -955,6 +1068,9 @@ int empty_buffer; /* buffer became empty */ u_header_T *curhead = curbuf->b_u_curhead; +#ifdef U_DEBUG + u_check(FALSE); +#endif old_flags = curhead->uh_flags; new_flags = (curbuf->b_changed ? UH_CHANGED : 0) + ((curbuf->b_ml.ml_flags & ML_EMPTY) ? UH_EMPTYBUF : 0); @@ -1186,6 +1302,9 @@ /* The timestamp can be the same for multiple changes, just use the one of * the undone/redone change. */ curbuf->b_u_seq_time = curhead->uh_time; +#ifdef U_DEBUG + u_check(FALSE); +#endif } /* @@ -1515,7 +1634,7 @@ } /* - * Free one header and its entry list and adjust the pointers. + * Free one header "uhp" and its entry list and adjust the pointers. */ static void u_freeheader(buf, uhp, uhpp) @@ -1523,6 +1642,8 @@ u_header_T *uhp; u_header_T **uhpp; /* if not NULL reset when freeing this header */ { + u_header_T *uhap; + /* When there is an alternate redo list free that branch completely, * because we can never go there. */ if (uhp->uh_alt_next != NULL) @@ -1540,7 +1661,8 @@ if (uhp->uh_prev == NULL) buf->b_u_newhead = uhp->uh_next; else - uhp->uh_prev->uh_next = uhp->uh_next; + for (uhap = uhp->uh_prev; uhap != NULL; uhap = uhap->uh_alt_next) + uhap->uh_next = uhp->uh_next; u_freeentries(buf, uhp, uhpp); } @@ -1585,6 +1707,8 @@ /* Check for pointers to the header that become invalid now. */ if (buf->b_u_curhead == uhp) buf->b_u_curhead = NULL; + if (buf->b_u_newhead == uhp) + buf->b_u_newhead = NULL; /* freeing the newest entry */ if (uhpp != NULL && uhp == *uhpp) *uhpp = NULL; @@ -1594,6 +1718,9 @@ u_freeentry(uep, uep->ue_size); } +#ifdef U_DEBUG + uhp->uh_magic = 0; +#endif U_FREE_LINE((char_u *)uhp); --buf->b_u_numhead; } @@ -1609,6 +1736,9 @@ while (n > 0) U_FREE_LINE(uep->ue_array[--n]); U_FREE_LINE((char_u *)uep->ue_array); +#ifdef U_DEBUG + uep->ue_magic = 0; +#endif U_FREE_LINE((char_u *)uep); } diff -Naur vim71.orig/src/version.c vim71/src/version.c --- vim71.orig/src/version.c 2007-05-12 10:23:44.000000000 +0000 +++ vim71/src/version.c 2007-10-24 22:09:10.000000000 +0000 @@ -667,6 +667,266 @@ static int included_patches[] = { /* Add new patch number below this line */ /**/ + 145, +/**/ + 144, +/**/ + 143, +/**/ + 142, +/**/ + 141, +/**/ + 140, +/**/ + 139, +/**/ + 138, +/**/ + 137, +/**/ + 136, +/**/ + 135, +/**/ + 133, +/**/ + 132, +/**/ + 131, +/**/ + 130, +/**/ + 127, +/**/ + 125, +/**/ + 123, +/**/ + 122, +/**/ + 121, +/**/ + 120, +/**/ + 119, +/**/ + 118, +/**/ + 117, +/**/ + 116, +/**/ + 115, +/**/ + 114, +/**/ + 113, +/**/ + 112, +/**/ + 111, +/**/ + 110, +/**/ + 109, +/**/ + 108, +/**/ + 107, +/**/ + 106, +/**/ + 105, +/**/ + 104, +/**/ + 103, +/**/ + 102, +/**/ + 101, +/**/ + 100, +/**/ + 99, +/**/ + 98, +/**/ + 97, +/**/ + 96, +/**/ + 95, +/**/ + 94, +/**/ + 93, +/**/ + 90, +/**/ + 89, +/**/ + 87, +/**/ + 86, +/**/ + 85, +/**/ + 84, +/**/ + 83, +/**/ + 82, +/**/ + 81, +/**/ + 79, +/**/ + 78, +/**/ + 77, +/**/ + 76, +/**/ + 75, +/**/ + 74, +/**/ + 73, +/**/ + 71, +/**/ + 69, +/**/ + 68, +/**/ + 67, +/**/ + 66, +/**/ + 64, +/**/ + 63, +/**/ + 62, +/**/ + 61, +/**/ + 60, +/**/ + 59, +/**/ + 58, +/**/ + 57, +/**/ + 56, +/**/ + 55, +/**/ + 54, +/**/ + 53, +/**/ + 52, +/**/ + 51, +/**/ + 50, +/**/ + 49, +/**/ + 48, +/**/ + 47, +/**/ + 46, +/**/ + 45, +/**/ + 44, +/**/ + 43, +/**/ + 42, +/**/ + 40, +/**/ + 39, +/**/ + 38, +/**/ + 37, +/**/ + 36, +/**/ + 35, +/**/ + 34, +/**/ + 33, +/**/ + 32, +/**/ + 31, +/**/ + 30, +/**/ + 29, +/**/ + 28, +/**/ + 27, +/**/ + 26, +/**/ + 25, +/**/ + 24, +/**/ + 23, +/**/ + 22, +/**/ + 21, +/**/ + 20, +/**/ + 19, +/**/ + 18, +/**/ + 17, +/**/ + 16, +/**/ + 15, +/**/ + 14, +/**/ + 13, +/**/ + 12, +/**/ + 11, +/**/ + 10, +/**/ + 9, +/**/ + 8, +/**/ + 6, +/**/ + 5, +/**/ + 4, +/**/ + 2, +/**/ + 1, +/**/ 0 }; diff -Naur vim71.orig/src/vim.h vim71/src/vim.h --- vim71.orig/src/vim.h 2007-05-12 09:53:29.000000000 +0000 +++ vim71/src/vim.h 2007-10-24 22:09:07.000000000 +0000 @@ -1380,8 +1380,14 @@ #endif #ifdef FEAT_MBYTE -# define MB_STRICMP(d, s) (has_mbyte ? mb_strnicmp((char_u *)(d), (char_u *)(s), (int)MAXCOL) : STRICMP((d), (s))) -# define MB_STRNICMP(d, s, n) (has_mbyte ? mb_strnicmp((char_u *)(d), (char_u *)(s), (int)(n)) : STRNICMP((d), (s), (n))) +/* We need to call mb_stricmp() even when we aren't dealing with a multi-byte + * encoding because mb_stricmp() takes care of all ascii and non-ascii + * encodings, including characters with umluats in latin1, etc., while + * STRICMP() only handles the system locale version, which often does not + * handle non-ascii properly. */ + +# define MB_STRICMP(d, s) mb_strnicmp((char_u *)(d), (char_u *)(s), (int)MAXCOL) +# define MB_STRNICMP(d, s, n) mb_strnicmp((char_u *)(d), (char_u *)(s), (int)(n)) #else # define MB_STRICMP(d, s) STRICMP((d), (s)) # define MB_STRNICMP(d, s, n) STRNICMP((d), (s), (n)) diff -Naur vim71.orig/src/vimtutor vim71/src/vimtutor --- vim71.orig/src/vimtutor 2004-06-07 14:32:27.000000000 +0000 +++ vim71/src/vimtutor 2007-10-24 22:09:07.000000000 +0000 @@ -39,18 +39,22 @@ # remove the copy of the tutor on exit trap "rm -rf $TODELETE" 0 1 2 3 9 11 13 15 -# Vim could be called "vim" or "vi". Also check for "vim6", for people who -# have Vim 5.x installed as "vim" and Vim 6.0 as "vim6". -testvim=`which vim6 2>/dev/null` -if test -f "$testvim"; then - VIM=vim6 -else - testvim=`which vim` +# Vim could be called "vim" or "vi". Also check for "vimN", for people who +# have Vim installed with its version number. +# We anticipate up to a future Vim 8 version :-). +seq="vim vim8 vim75 vim74 vim73 vim72 vim71 vim70 vim7 vim6 vi" +for i in $seq; do + testvim=`which $i 2>/dev/null` if test -f "$testvim"; then - VIM=vim - else - VIM=vi + VIM=$i + break fi +done + +# When no Vim version was found fall back to "vim", you'll get an error message +# below. +if test -z "$VIM"; then + VIM=vim fi # Use Vim to copy the tutor, it knows the value of $VIMRUNTIME diff -Naur vim71.orig/src/window.c vim71/src/window.c --- vim71.orig/src/window.c 2007-05-07 19:25:30.000000000 +0000 +++ vim71/src/window.c 2007-10-24 22:09:09.000000000 +0000 @@ -75,6 +75,7 @@ static win_T *restore_snapshot_rec __ARGS((frame_T *sn, frame_T *fr)); #endif /* FEAT_WINDOWS */ + static win_T *win_alloc __ARGS((win_T *after)); static void win_new_height __ARGS((win_T *, int)); @@ -583,7 +584,7 @@ ++no_mapping; ++allow_keys; /* no mapping for xchar, but allow key codes */ if (xchar == NUL) - xchar = safe_vgetc(); + xchar = plain_vgetc(); #ifdef FEAT_LANGMAP LANGMAP_ADJUST(xchar, TRUE); #endif @@ -732,7 +733,6 @@ if (flags & WSP_VERT) { layout = FR_ROW; - do_equal = (p_ea && new_size == 0 && *p_ead != 'v'); /* * Check if we are able to split the current window and compute its @@ -769,16 +769,31 @@ * instead, if possible. */ if (oldwin->w_p_wfw) win_setwidth_win(oldwin->w_width + new_size, oldwin); + + /* Only make all windows the same width if one of them (except oldwin) + * is wider than one of the split windows. */ + if (!do_equal && p_ea && size == 0 && *p_ead != 'v' + && oldwin->w_frame->fr_parent != NULL) + { + frp = oldwin->w_frame->fr_parent->fr_child; + while (frp != NULL) + { + if (frp->fr_win != oldwin && frp->fr_win != NULL + && (frp->fr_win->w_width > new_size + || frp->fr_win->w_width > oldwin->w_width + - new_size - STATUS_HEIGHT)) + { + do_equal = TRUE; + break; + } + frp = frp->fr_next; + } + } } else #endif { layout = FR_COL; - do_equal = (p_ea && new_size == 0 -#ifdef FEAT_VERTSPLIT - && *p_ead != 'h' -#endif - ); /* * Check if we are able to split the current window and compute its @@ -831,6 +846,29 @@ if (need_status) oldwin_height -= STATUS_HEIGHT; } + + /* Only make all windows the same height if one of them (except oldwin) + * is higher than one of the split windows. */ + if (!do_equal && p_ea && size == 0 +#ifdef FEAT_VERTSPLIT + && *p_ead != 'h' +#endif + && oldwin->w_frame->fr_parent != NULL) + { + frp = oldwin->w_frame->fr_parent->fr_child; + while (frp != NULL) + { + if (frp->fr_win != oldwin && frp->fr_win != NULL + && (frp->fr_win->w_height > new_size + || frp->fr_win->w_height > oldwin_height - new_size + - STATUS_HEIGHT)) + { + do_equal = TRUE; + break; + } + frp = frp->fr_next; + } + } } /* @@ -1253,7 +1291,7 @@ * Don't execute autocommands while creating the windows. Must do that * when putting the buffers in the windows. */ - ++autocmd_block; + block_autocmds(); #endif /* todo is number of windows left to create */ @@ -1275,7 +1313,7 @@ } #ifdef FEAT_AUTOCMD - --autocmd_block; + unblock_autocmds(); #endif /* return actual number of windows */ @@ -2120,7 +2158,7 @@ if (wp->w_p_pvw || bt_quickfix(wp->w_buffer)) { /* - * The cursor goes to the preview or the quickfix window, try + * If the cursor goes to the preview or the quickfix window, try * finding another window to go to. */ for (;;) @@ -2307,7 +2345,6 @@ frame_T *frp, *frp2, *frp3; frame_T *frp_close = win->w_frame; win_T *wp; - int old_size = 0; /* * If there is only one window there is nothing to remove. @@ -2328,33 +2365,77 @@ if (frp_close->fr_parent->fr_layout == FR_COL) { #endif - /* When 'winfixheight' is set, remember its old size and restore - * it later (it's a simplistic solution...). Don't do this if the - * window will occupy the full height of the screen. */ - if (frp2->fr_win != NULL - && (frp2->fr_next != NULL || frp2->fr_prev != NULL) - && frp2->fr_win->w_p_wfh) - old_size = frp2->fr_win->w_height; + /* When 'winfixheight' is set, try to find another frame in the column + * (as close to the closed frame as possible) to distribute the height + * to. */ + if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfh) + { + frp = frp_close->fr_prev; + frp3 = frp_close->fr_next; + while (frp != NULL || frp3 != NULL) + { + if (frp != NULL) + { + if (frp->fr_win != NULL && !frp->fr_win->w_p_wfh) + { + frp2 = frp; + wp = frp->fr_win; + break; + } + frp = frp->fr_prev; + } + if (frp3 != NULL) + { + if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfh) + { + frp2 = frp3; + wp = frp3->fr_win; + break; + } + frp3 = frp3->fr_next; + } + } + } frame_new_height(frp2, frp2->fr_height + frp_close->fr_height, frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE); - if (old_size != 0) - win_setheight_win(old_size, frp2->fr_win); #ifdef FEAT_VERTSPLIT *dirp = 'v'; } else { - /* When 'winfixwidth' is set, remember its old size and restore - * it later (it's a simplistic solution...). Don't do this if the - * window will occupy the full width of the screen. */ - if (frp2->fr_win != NULL - && (frp2->fr_next != NULL || frp2->fr_prev != NULL) - && frp2->fr_win->w_p_wfw) - old_size = frp2->fr_win->w_width; + /* When 'winfixwidth' is set, try to find another frame in the column + * (as close to the closed frame as possible) to distribute the width + * to. */ + if (frp2->fr_win != NULL && frp2->fr_win->w_p_wfw) + { + frp = frp_close->fr_prev; + frp3 = frp_close->fr_next; + while (frp != NULL || frp3 != NULL) + { + if (frp != NULL) + { + if (frp->fr_win != NULL && !frp->fr_win->w_p_wfw) + { + frp2 = frp; + wp = frp->fr_win; + break; + } + frp = frp->fr_prev; + } + if (frp3 != NULL) + { + if (frp3->fr_win != NULL && !frp3->fr_win->w_p_wfw) + { + frp2 = frp3; + wp = frp3->fr_win; + break; + } + frp3 = frp3->fr_next; + } + } + } frame_new_width(frp2, frp2->fr_width + frp_close->fr_width, frp2 == frp_close->fr_next ? TRUE : FALSE, FALSE); - if (old_size != 0) - win_setwidth_win(old_size, frp2->fr_win); *dirp = 'h'; } #endif @@ -3334,7 +3415,7 @@ * Don't execute autocommands while creating the tab pages. Must do that * when putting the buffers in the windows. */ - ++autocmd_block; + block_autocmds(); #endif for (todo = count - 1; todo > 0; --todo) @@ -3342,7 +3423,7 @@ break; #ifdef FEAT_AUTOCMD - --autocmd_block; + unblock_autocmds(); #endif /* return actual number of tab pages */ @@ -4081,7 +4162,7 @@ /* Don't execute autocommands while the window is not properly * initialized yet. gui_create_scrollbar() may trigger a FocusGained * event. */ - ++autocmd_block; + block_autocmds(); #endif /* * link the window in the window list @@ -4126,7 +4207,11 @@ foldInitWin(newwin); #endif #ifdef FEAT_AUTOCMD - --autocmd_block; + unblock_autocmds(); +#endif +#ifdef FEAT_SEARCH_EXTRA + newwin->w_match_head = NULL; + newwin->w_next_match_id = 4; #endif } return newwin; @@ -4147,7 +4232,7 @@ #ifdef FEAT_AUTOCMD /* Don't execute autocommands while the window is halfway being deleted. * gui_mch_destroy_scrollbar() may trigger a FocusGained event. */ - ++autocmd_block; + block_autocmds(); #endif #ifdef FEAT_MZSCHEME @@ -4185,11 +4270,11 @@ vim_free(wp->w_tagstack[i].tagname); vim_free(wp->w_localdir); + #ifdef FEAT_SEARCH_EXTRA - vim_free(wp->w_match[0].regprog); - vim_free(wp->w_match[1].regprog); - vim_free(wp->w_match[2].regprog); + clear_matches(wp); #endif + #ifdef FEAT_JUMPLIST free_jumplist(wp); #endif @@ -4210,7 +4295,7 @@ vim_free(wp); #ifdef FEAT_AUTOCMD - --autocmd_block; + unblock_autocmds(); #endif } @@ -5438,6 +5523,7 @@ { EMSG(_(e_noroom)); p_ch = old_p_ch; + curtab->tp_ch_used = p_ch; cmdline_row = Rows - p_ch; break; } @@ -6174,3 +6260,175 @@ return FALSE; } #endif + +#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO) +/* + * Add match to the match list of window 'wp'. The pattern 'pat' will be + * highligted with the group 'grp' with priority 'prio'. + * Optionally, a desired ID 'id' can be specified (greater than or equal to 1). + * If no particular ID is desired, -1 must be specified for 'id'. + * Return ID of added match, -1 on failure. + */ + int +match_add(wp, grp, pat, prio, id) + win_T *wp; + char_u *grp; + char_u *pat; + int prio; + int id; +{ + matchitem_T *cur; + matchitem_T *prev; + matchitem_T *m; + int hlg_id; + regprog_T *regprog; + + if (*grp == NUL || *pat == NUL) + return -1; + if (id < -1 || id == 0) + { + EMSGN("E799: Invalid ID: %ld (must be greater than or equal to 1)", id); + return -1; + } + if (id != -1) + { + cur = wp->w_match_head; + while (cur != NULL) + { + if (cur->id == id) + { + EMSGN("E801: ID already taken: %ld", id); + return -1; + } + cur = cur->next; + } + } + if ((hlg_id = syn_namen2id(grp, STRLEN(grp))) == 0) + { + EMSG2(_(e_nogroup), grp); + return -1; + } + if ((regprog = vim_regcomp(pat, RE_MAGIC)) == NULL) + { + EMSG2(_(e_invarg2), pat); + return -1; + } + + /* Find available match ID. */ + while (id == -1) + { + cur = wp->w_match_head; + while (cur != NULL && cur->id != wp->w_next_match_id) + cur = cur->next; + if (cur == NULL) + id = wp->w_next_match_id; + wp->w_next_match_id++; + } + + /* Build new match. */ + m = (matchitem_T *)alloc(sizeof(matchitem_T)); + m->id = id; + m->priority = prio; + m->pattern = vim_strsave(pat); + m->hlg_id = hlg_id; + m->match.regprog = regprog; + m->match.rmm_ic = FALSE; + m->match.rmm_maxcol = 0; + + /* Insert new match. The match list is in ascending order with regard to + * the match priorities. */ + cur = wp->w_match_head; + prev = cur; + while (cur != NULL && prio >= cur->priority) + { + prev = cur; + cur = cur->next; + } + if (cur == prev) + wp->w_match_head = m; + else + prev->next = m; + m->next = cur; + + redraw_later(SOME_VALID); + return id; +} + +/* + * Delete match with ID 'id' in the match list of window 'wp'. + * Print error messages if 'perr' is TRUE. + */ + int +match_delete(wp, id, perr) + win_T *wp; + int id; + int perr; +{ + matchitem_T *cur = wp->w_match_head; + matchitem_T *prev = cur; + + if (id < 1) + { + if (perr == TRUE) + EMSGN("E802: Invalid ID: %ld (must be greater than or equal to 1)", + id); + return -1; + } + while (cur != NULL && cur->id != id) + { + prev = cur; + cur = cur->next; + } + if (cur == NULL) + { + if (perr == TRUE) + EMSGN("E803: ID not found: %ld", id); + return -1; + } + if (cur == prev) + wp->w_match_head = cur->next; + else + prev->next = cur->next; + vim_free(cur->match.regprog); + vim_free(cur->pattern); + vim_free(cur); + redraw_later(SOME_VALID); + return 0; +} + +/* + * Delete all matches in the match list of window 'wp'. + */ + void +clear_matches(wp) + win_T *wp; +{ + matchitem_T *m; + + while (wp->w_match_head != NULL) + { + m = wp->w_match_head->next; + vim_free(wp->w_match_head->match.regprog); + vim_free(wp->w_match_head->pattern); + vim_free(wp->w_match_head); + wp->w_match_head = m; + } + redraw_later(SOME_VALID); +} + +/* + * Get match from ID 'id' in window 'wp'. + * Return NULL if match not found. + */ + matchitem_T * +get_match(wp, id) + win_T *wp; + int id; +{ + matchitem_T *cur = wp->w_match_head; + + while (cur != NULL && cur->id != id) + cur = cur->next; + return cur; +} +#endif