Submitted By: Matt Burgess (matthew at linuxfromscratch dot org) Date: 2007-09-07 Initial Package Version: 7.1 Origin: Upstream Upstream Status: Applied Description: Contains patches 001-100 from upstream excluding patches 003, 007, 041, 065, 070, 072, 080, 088, 091 and 092 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-09-07 07:42:15.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-09-07 07:42:16.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 Jul 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 @@ -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()|. @@ -2824,6 +2838,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 +2928,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 +3654,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 +3701,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 +4462,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 +5111,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-09-07 07:42:17.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-09-07 07:42:16.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-09-07 07:42:17.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-09-07 07:42:16.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-09-07 07:42:17.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-09-07 07:42:14.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-09-07 07:42:17.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-09-07 07:42:14.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-09-07 07:42:17.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 */ @@ -4853,7 +4861,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; 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-09-07 07:42:17.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-09-07 07:42:14.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/digraph.c vim71/src/digraph.c --- vim71.orig/src/digraph.c 2006-05-02 18:24:04.000000000 +0000 +++ vim71/src/digraph.c 2007-09-07 07:42:14.000000000 +0000 @@ -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_unload, 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-09-07 07:42:17.000000000 +0000 @@ -2057,7 +2057,6 @@ * 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 +2067,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) + { + p = compl_orig_text; + actual_compl_length = 0; + while (*p != NUL) + { + 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) { - for (idx = 0; idx < compl_length; ++idx) + 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) { - if (was_letter && isupper(compl_orig_text[idx]) - && islower(IObuff[idx])) +#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 +2934,7 @@ /* * Add the other matches on the line */ + ptr = buf; while (!got_int) { /* Find start of the next word. Skip white @@ -2851,7 +2944,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 +2961,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) @@ -7215,6 +7311,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] == ':') @@ -7998,7 +8096,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' */ 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-09-07 07:42:17.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(); @@ -1411,7 +1416,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 +1490,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 +1513,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 +1538,7 @@ clear_tv(&rettv); return retval; } -#endif +# endif /* * Call vimL function "func" and return the result as a list @@ -1556,9 +1564,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 +1699,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 +1716,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 +1933,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 +1952,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 +1961,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 +2000,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 +2012,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 +2106,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 +2131,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); } @@ -6794,7 +6819,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 +6904,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 +7068,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}, @@ -7099,6 +7125,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 +7176,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 +7219,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 +8270,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 @@ -9868,18 +9912,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 +10186,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 +10325,40 @@ } /* + * "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->dv_refcount; + 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 @@ -12439,6 +12529,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 +12577,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 +13830,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 +14069,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 +14650,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 +14997,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 +15490,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 +16714,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 +16729,7 @@ list_T *l; int len; int error = FALSE; + listitem_T *li; l = varp->vval.v_list; if (l == NULL) @@ -16527,6 +16745,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 +16785,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 +16803,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 +18024,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 +18035,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 +18077,11 @@ if (type == VAR_FUNC) msg_puts((char_u *)"()"); + if (*first) + { + msg_clr_eos(); + *first = FALSE; + } } /* @@ -19136,6 +19371,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 +20226,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 +20237,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 +20321,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 */ 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-09-07 07:42:17.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) @@ -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-09-07 07:42:17.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 <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; } @@ -10816,12 +10844,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 +10859,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 +10870,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 +10894,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-09-07 07:42:16.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-09-07 07:42:17.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 */ @@ -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) @@ -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) @@ -4148,13 +4153,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 +4306,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 +4514,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 +4553,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; 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-09-07 07:42:16.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-09-07 07:42:17.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) 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-09-07 07:42:17.000000000 +0000 @@ -1596,8 +1596,15 @@ continue; } #endif - #ifdef FEAT_GUI + /* The caller doesn't need to know that the focus event is delayed + * until getting a character. */ + if (c == K_FOCUSGAINED || c == K_FOCUSLOST) + { + ui_focus_change(c == K_FOCUSGAINED); + continue; + } + /* 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) 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-09-07 07:42:17.000000000 +0000 @@ -801,7 +801,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-09-07 07:42:17.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-09-07 07:42:17.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-09-07 07:42:17.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); 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-09-07 07:42:17.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,23 @@ 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; -# endif +#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; #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 +749,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 +763,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 +796,7 @@ #ifdef UNIX return CSCOPE_FAILURE; #else + /* WIN32 */ goto err_closing; #endif } @@ -805,6 +813,7 @@ #ifdef UNIX return CSCOPE_FAILURE; #else + /* WIN32 */ goto err_closing; #endif } @@ -823,6 +832,7 @@ #ifdef UNIX return CSCOPE_FAILURE; #else + /* WIN32 */ goto err_closing; #endif } @@ -831,6 +841,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 +867,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 +876,52 @@ 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((intptr_t)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((intptr_t)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 +953,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 +1304,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 +1388,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 +2089,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 +2108,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 +2188,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 +2297,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-09-07 07:42:17.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-09-07 07:42:14.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/keymap.h vim71/src/keymap.h --- vim71.orig/src/keymap.h 2006-08-22 11:38:38.000000000 +0000 +++ vim71/src/keymap.h 2007-09-07 07:42:17.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-09-07 07:42:17.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.c vim71/src/main.c --- vim71.orig/src/main.c 2007-05-07 19:38:44.000000000 +0000 +++ vim71/src/main.c 2007-09-07 07:42:17.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,9 @@ #ifdef FEAT_NETBEANS_INTG netbeans_end(); #endif +#ifdef FEAT_CSCOPE + cs_end(); +#endif mch_exit(exitval); } @@ -1360,8 +1384,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 +3655,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/main.c.orig vim71/src/main.c.orig --- vim71.orig/src/main.c.orig 1970-01-01 00:00:00.000000000 +0000 +++ vim71/src/main.c.orig 2007-09-07 07:42:17.000000000 +0000 @@ -0,0 +1,3861 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +#if defined(MSDOS) || defined(WIN32) || defined(_WIN64) +# include "vimio.h" /* for close() and dup() */ +#endif + +#define EXTERN +#include "vim.h" + +#ifdef SPAWNO +# include /* special MS-DOS swapping library */ +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef __CYGWIN__ +# ifndef WIN32 +# include /* for cygwin_conv_to_posix_path() */ +# endif +# include +#endif + +/* Maximum number of commands from + or -c arguments. */ +#define MAX_ARG_CMDS 10 + +/* values for "window_layout" */ +#define WIN_HOR 1 /* "-o" horizontally split windows */ +#define WIN_VER 2 /* "-O" vertically split windows */ +#define WIN_TABS 3 /* "-p" windows on tab pages */ + +/* Struct for various parameters passed between main() and other functions. */ +typedef struct +{ + int argc; + char **argv; + + int evim_mode; /* started as "evim" */ + char_u *use_vimrc; /* vimrc from -u argument */ + + int n_commands; /* no. of commands from + or -c */ + char_u *commands[MAX_ARG_CMDS]; /* commands from + or -c arg. */ + char_u cmds_tofree[MAX_ARG_CMDS]; /* commands that need free() */ + int n_pre_commands; /* no. of commands from --cmd */ + char_u *pre_commands[MAX_ARG_CMDS]; /* commands from --cmd argument */ + + int edit_type; /* type of editing to do */ + char_u *tagname; /* tag from -t argument */ +#ifdef FEAT_QUICKFIX + char_u *use_ef; /* 'errorfile' from -q argument */ +#endif + + int want_full_screen; + int stdout_isatty; /* is stdout a terminal? */ + char_u *term; /* specified terminal name */ +#ifdef FEAT_CRYPT + int ask_for_key; /* -x argument */ +#endif + int no_swap_file; /* "-n" argument used */ +#ifdef FEAT_EVAL + int use_debug_break_level; +#endif +#ifdef FEAT_WINDOWS + int window_count; /* number of windows to use */ + int window_layout; /* 0, WIN_HOR, WIN_VER or WIN_TABS */ +#endif + +#ifdef FEAT_CLIENTSERVER + int serverArg; /* TRUE when argument for a server */ + char_u *serverName_arg; /* cmdline arg for server name */ + char_u *serverStr; /* remote server command */ + char_u *serverStrEnc; /* encoding of serverStr */ + char_u *servername; /* allocated name for our server */ +#endif +#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) + int literal; /* don't expand file names */ +#endif +#ifdef MSWIN + int full_path; /* file name argument was full path */ +#endif +#ifdef FEAT_DIFF + int diff_mode; /* start with 'diff' set */ +#endif +} mparm_T; + +/* Values for edit_type. */ +#define EDIT_NONE 0 /* no edit type yet */ +#define EDIT_FILE 1 /* file name argument[s] given, use argument list */ +#define EDIT_STDIN 2 /* read file from stdin */ +#define EDIT_TAG 3 /* tag name argument given, use tagname */ +#define EDIT_QF 4 /* start in quickfix mode */ + +#if defined(UNIX) || defined(VMS) +static int file_owned __ARGS((char *fname)); +#endif +static void mainerr __ARGS((int, char_u *)); +static void main_msg __ARGS((char *s)); +static void usage __ARGS((void)); +static int get_number_arg __ARGS((char_u *p, int *idx, int def)); +#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) +static void init_locale __ARGS((void)); +#endif +static void parse_command_name __ARGS((mparm_T *parmp)); +static void early_arg_scan __ARGS((mparm_T *parmp)); +static void command_line_scan __ARGS((mparm_T *parmp)); +static void check_tty __ARGS((mparm_T *parmp)); +static void read_stdin __ARGS((void)); +static void create_windows __ARGS((mparm_T *parmp)); +#ifdef FEAT_WINDOWS +static void edit_buffers __ARGS((mparm_T *parmp)); +#endif +static void exe_pre_commands __ARGS((mparm_T *parmp)); +static void exe_commands __ARGS((mparm_T *parmp)); +static void source_startup_scripts __ARGS((mparm_T *parmp)); +static void main_start_gui __ARGS((void)); +#if defined(HAS_SWAP_EXISTS_ACTION) +static void check_swap_exists_action __ARGS((void)); +#endif +#ifdef FEAT_CLIENTSERVER +static void exec_on_server __ARGS((mparm_T *parmp)); +static void prepare_server __ARGS((mparm_T *parmp)); +static void cmdsrv_main __ARGS((int *argc, char **argv, char_u *serverName_arg, char_u **serverStr)); +static char_u *serverMakeName __ARGS((char_u *arg, char *cmd)); +#endif + + +#ifdef STARTUPTIME +static FILE *time_fd = NULL; +#endif + +/* + * Different types of error messages. + */ +static char *(main_errors[]) = +{ + N_("Unknown option argument"), +#define ME_UNKNOWN_OPTION 0 + N_("Too many edit arguments"), +#define ME_TOO_MANY_ARGS 1 + N_("Argument missing after"), +#define ME_ARG_MISSING 2 + N_("Garbage after option argument"), +#define ME_GARBAGE 3 + N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments"), +#define ME_EXTRA_CMD 4 + N_("Invalid argument for"), +#define ME_INVALID_ARG 5 +}; + +#ifndef PROTO /* don't want a prototype for main() */ + int +# ifdef VIMDLL +_export +# endif +# ifdef FEAT_GUI_MSWIN +# ifdef __BORLANDC__ +_cdecl +# endif +VimMain +# else +main +# endif +(argc, argv) + int argc; + char **argv; +{ + char_u *fname = NULL; /* file name from command line */ + mparm_T params; /* various parameters passed between + * main() and other functions. */ + + /* + * Do any system-specific initialisations. These can NOT use IObuff or + * NameBuff. Thus emsg2() cannot be called! + */ + mch_early_init(); + + /* Many variables are in "params" so that we can pass them to invoked + * functions without a lot of arguments. "argc" and "argv" are also + * copied, so that they can be changed. */ + vim_memset(¶ms, 0, sizeof(params)); + params.argc = argc; + params.argv = argv; + params.want_full_screen = TRUE; +#ifdef FEAT_EVAL + params.use_debug_break_level = -1; +#endif +#ifdef FEAT_WINDOWS + params.window_count = -1; +#endif + +#ifdef FEAT_TCL + vim_tcl_init(params.argv[0]); +#endif + +#ifdef MEM_PROFILE + atexit(vim_mem_profile_dump); +#endif + +#ifdef STARTUPTIME + time_fd = mch_fopen(STARTUPTIME, "a"); + TIME_MSG("--- VIM STARTING ---"); +#endif + starttime = time(NULL); + +#ifdef __EMX__ + _wildcard(¶ms.argc, ¶ms.argv); +#endif + +#ifdef FEAT_MBYTE + (void)mb_init(); /* init mb_bytelen_tab[] to ones */ +#endif +#ifdef FEAT_EVAL + eval_init(); /* init global variables */ +#endif + +#ifdef __QNXNTO__ + qnx_init(); /* PhAttach() for clipboard, (and gui) */ +#endif + +#ifdef MAC_OS_CLASSIC + /* Prepare for possibly starting GUI sometime */ + /* Macintosh needs this before any memory is allocated. */ + gui_prepare(¶ms.argc, params.argv); + TIME_MSG("GUI prepared"); +#endif + + /* Init the table of Normal mode commands. */ + init_normal_cmds(); + +#if defined(HAVE_DATE_TIME) && defined(VMS) && defined(VAXC) + make_version(); /* Construct the long version string. */ +#endif + + /* + * Allocate space for the generic buffers (needed for set_init_1() and + * EMSG2()). + */ + if ((IObuff = alloc(IOSIZE)) == NULL + || (NameBuff = alloc(MAXPATHL)) == NULL) + mch_exit(0); + TIME_MSG("Allocated generic buffers"); + +#ifdef NBDEBUG + /* Wait a moment for debugging NetBeans. Must be after allocating + * NameBuff. */ + nbdebug_log_init("SPRO_GVIM_DEBUG", "SPRO_GVIM_DLEVEL"); + nbdebug_wait(WT_ENV | WT_WAIT | WT_STOP, "SPRO_GVIM_WAIT", 20); + TIME_MSG("NetBeans debug wait"); +#endif + +#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) + /* + * Setup to use the current locale (for ctype() and many other things). + * NOTE: Translated messages with encodings other than latin1 will not + * work until set_init_1() has been called! + */ + init_locale(); + TIME_MSG("locale set"); +#endif + +#ifdef FEAT_GUI + gui.dofork = TRUE; /* default is to use fork() */ +#endif + + /* + * Do a first scan of the arguments in "argv[]": + * -display or --display + * --server... + * --socketid + */ + early_arg_scan(¶ms); + +#ifdef FEAT_SUN_WORKSHOP + findYourself(params.argv[0]); +#endif +#if defined(FEAT_GUI) && !defined(MAC_OS_CLASSIC) + /* Prepare for possibly starting GUI sometime */ + gui_prepare(¶ms.argc, params.argv); + TIME_MSG("GUI prepared"); +#endif + +#ifdef FEAT_CLIPBOARD + clip_init(FALSE); /* Initialise clipboard stuff */ + TIME_MSG("clipboard setup"); +#endif + + /* + * Check if we have an interactive window. + * On the Amiga: If there is no window, we open one with a newcli command + * (needed for :! to * work). mch_check_win() will also handle the -d or + * -dev argument. + */ + params.stdout_isatty = (mch_check_win(params.argc, params.argv) != FAIL); + TIME_MSG("window checked"); + + /* + * Allocate the first window and buffer. + * Can't do anything without it, exit when it fails. + */ + if (win_alloc_first() == FAIL) + mch_exit(0); + + init_yank(); /* init yank buffers */ + + alist_init(&global_alist); /* Init the argument list to empty. */ + + /* + * Set the default values for the options. + * NOTE: Non-latin1 translated messages are working only after this, + * because this is where "has_mbyte" will be set, which is used by + * msg_outtrans_len_attr(). + * First find out the home directory, needed to expand "~" in options. + */ + init_homedir(); /* find real value of $HOME */ + set_init_1(); + TIME_MSG("inits 1"); + +#ifdef FEAT_EVAL + set_lang_var(); /* set v:lang and v:ctype */ +#endif + +#ifdef FEAT_CLIENTSERVER + /* + * Do the client-server stuff, unless "--servername ''" was used. + * This may exit Vim if the command was sent to the server. + */ + exec_on_server(¶ms); +#endif + + /* + * Figure out the way to work from the command name argv[0]. + * "vimdiff" starts diff mode, "rvim" sets "restricted", etc. + */ + parse_command_name(¶ms); + + /* + * Process the command line arguments. File names are put in the global + * argument list "global_alist". + */ + command_line_scan(¶ms); + TIME_MSG("parsing arguments"); + + /* + * On some systems, when we compile with the GUI, we always use it. On Mac + * there is no terminal version, and on Windows we can't fork one off with + * :gui. + */ +#ifdef ALWAYS_USE_GUI + gui.starting = TRUE; +#else +# if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) + /* + * Check if the GUI can be started. Reset gui.starting if not. + * Don't know about other systems, stay on the safe side and don't check. + */ + if (gui.starting && gui_init_check() == FAIL) + { + gui.starting = FALSE; + + /* When running "evim" or "gvim -y" we need the menus, exit if we + * don't have them. */ + if (params.evim_mode) + mch_exit(1); + } +# endif +#endif + + if (GARGCOUNT > 0) + { +#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) + /* + * Expand wildcards in file names. + */ + if (!params.literal) + { + /* Temporarily add '(' and ')' to 'isfname'. These are valid + * filename characters but are excluded from 'isfname' to make + * "gf" work on a file name in parenthesis (e.g.: see vim.h). */ + do_cmdline_cmd((char_u *)":set isf+=(,)"); + alist_expand(NULL, 0); + do_cmdline_cmd((char_u *)":set isf&"); + } +#endif + fname = alist_name(&GARGLIST[0]); + } + +#if defined(WIN32) && defined(FEAT_MBYTE) + { + extern void set_alist_count(void); + + /* Remember the number of entries in the argument list. If it changes + * we don't react on setting 'encoding'. */ + set_alist_count(); + } +#endif + +#ifdef MSWIN + if (GARGCOUNT == 1 && params.full_path) + { + /* + * If there is one filename, fully qualified, we have very probably + * been invoked from explorer, so change to the file's directory. + * Hint: to avoid this when typing a command use a forward slash. + * If the cd fails, it doesn't matter. + */ + (void)vim_chdirfile(fname); + } +#endif + TIME_MSG("expanding arguments"); + +#ifdef FEAT_DIFF + if (params.diff_mode && params.window_count == -1) + params.window_count = 0; /* open up to 3 windows */ +#endif + + /* Don't redraw until much later. */ + ++RedrawingDisabled; + + /* + * When listing swap file names, don't do cursor positioning et. al. + */ + if (recoverymode && fname == NULL) + params.want_full_screen = FALSE; + + /* + * When certain to start the GUI, don't check capabilities of terminal. + * For GTK we can't be sure, but when started from the desktop it doesn't + * make sense to try using a terminal. + */ +#if defined(ALWAYS_USE_GUI) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) + if (gui.starting +# ifdef FEAT_GUI_GTK + && !isatty(2) +# endif + ) + params.want_full_screen = FALSE; +#endif + +#if defined(FEAT_GUI_MAC) && defined(MACOS_X_UNIX) + /* When the GUI is started from Finder, need to display messages in a + * message box. isatty(2) returns TRUE anyway, thus we need to check the + * name to know we're not started from a terminal. */ + if (gui.starting && (!isatty(2) || strcmp("/dev/console", ttyname(2)) == 0)) + { + params.want_full_screen = FALSE; + + /* Avoid always using "/" as the current directory. Note that when + * started from Finder the arglist will be filled later in + * HandleODocAE() and "fname" will be NULL. */ + if (getcwd((char *)NameBuff, MAXPATHL) != NULL + && STRCMP(NameBuff, "/") == 0) + { + if (fname != NULL) + (void)vim_chdirfile(fname); + else + { + expand_env((char_u *)"$HOME", NameBuff, MAXPATHL); + vim_chdir(NameBuff); + } + } + } +#endif + + /* + * mch_init() sets up the terminal (window) for use. This must be + * done after resetting full_screen, otherwise it may move the cursor + * (MSDOS). + * Note that we may use mch_exit() before mch_init()! + */ + mch_init(); + TIME_MSG("shell init"); + +#ifdef USE_XSMP + /* + * For want of anywhere else to do it, try to connect to xsmp here. + * Fitting it in after gui_mch_init, but before gui_init (via termcapinit). + * Hijacking -X 'no X connection' to also disable XSMP connection as that + * has a similar delay upon failure. + * Only try if SESSION_MANAGER is set to something non-null. + */ + if (!x_no_connect) + { + char *p = getenv("SESSION_MANAGER"); + + if (p != NULL && *p != NUL) + { + xsmp_init(); + TIME_MSG("xsmp init"); + } + } +#endif + + /* + * Print a warning if stdout is not a terminal. + */ + check_tty(¶ms); + + /* This message comes before term inits, but after setting "silent_mode" + * when the input is not a tty. */ + if (GARGCOUNT > 1 && !silent_mode) + printf(_("%d files to edit\n"), GARGCOUNT); + + if (params.want_full_screen && !silent_mode) + { + termcapinit(params.term); /* set terminal name and get terminal + capabilities (will set full_screen) */ + screen_start(); /* don't know where cursor is now */ + TIME_MSG("Termcap init"); + } + + /* + * Set the default values for the options that use Rows and Columns. + */ + ui_get_shellsize(); /* inits Rows and Columns */ +#ifdef FEAT_NETBEANS_INTG + if (usingNetbeans) + Columns += 2; /* leave room for glyph gutter */ +#endif + win_init_size(); +#ifdef FEAT_DIFF + /* Set the 'diff' option now, so that it can be checked for in a .vimrc + * file. There is no buffer yet though. */ + if (params.diff_mode) + diff_win_options(firstwin, FALSE); +#endif + + cmdline_row = Rows - p_ch; + msg_row = cmdline_row; + screenalloc(FALSE); /* allocate screen buffers */ + set_init_2(); + TIME_MSG("inits 2"); + + msg_scroll = TRUE; + no_wait_return = TRUE; + + init_mappings(); /* set up initial mappings */ + + init_highlight(TRUE, FALSE); /* set the default highlight groups */ + TIME_MSG("init highlight"); + +#ifdef FEAT_EVAL + /* Set the break level after the terminal is initialized. */ + debug_break_level = params.use_debug_break_level; +#endif + + /* Execute --cmd arguments. */ + exe_pre_commands(¶ms); + + /* Source startup scripts. */ + source_startup_scripts(¶ms); + +#ifdef FEAT_EVAL + /* + * Read all the plugin files. + * Only when compiled with +eval, since most plugins need it. + */ + if (p_lpl) + { +# ifdef VMS /* Somehow VMS doesn't handle the "**". */ + source_runtime((char_u *)"plugin/*.vim", TRUE); +# else + source_runtime((char_u *)"plugin/**/*.vim", TRUE); +# endif + TIME_MSG("loading plugins"); + } +#endif + +#ifdef FEAT_DIFF + /* Decide about window layout for diff mode after reading vimrc. */ + if (params.diff_mode && params.window_layout == 0) + { + if (diffopt_horizontal()) + params.window_layout = WIN_HOR; /* use horizontal split */ + else + params.window_layout = WIN_VER; /* use vertical split */ + } +#endif + + /* + * Recovery mode without a file name: List swap files. + * This uses the 'dir' option, therefore it must be after the + * initializations. + */ + if (recoverymode && fname == NULL) + { + recover_names(NULL, TRUE, 0); + mch_exit(0); + } + + /* + * Set a few option defaults after reading .vimrc files: + * 'title' and 'icon', Unix: 'shellpipe' and 'shellredir'. + */ + set_init_3(); + TIME_MSG("inits 3"); + + /* + * "-n" argument: Disable swap file by setting 'updatecount' to 0. + * Note that this overrides anything from a vimrc file. + */ + if (params.no_swap_file) + p_uc = 0; + +#ifdef FEAT_FKMAP + if (curwin->w_p_rl && p_altkeymap) + { + p_hkmap = FALSE; /* Reset the Hebrew keymap mode */ +# ifdef FEAT_ARABIC + curwin->w_p_arab = FALSE; /* Reset the Arabic keymap mode */ +# endif + p_fkmap = TRUE; /* Set the Farsi keymap mode */ + } +#endif + +#ifdef FEAT_GUI + if (gui.starting) + { +#if defined(UNIX) || defined(VMS) + /* When something caused a message from a vimrc script, need to output + * an extra newline before the shell prompt. */ + if (did_emsg || msg_didout) + putchar('\n'); +#endif + + gui_start(); /* will set full_screen to TRUE */ + TIME_MSG("starting GUI"); + + /* When running "evim" or "gvim -y" we need the menus, exit if we + * don't have them. */ + if (!gui.in_use && params.evim_mode) + mch_exit(1); + } +#endif + +#ifdef SPAWNO /* special MSDOS swapping library */ + init_SPAWNO("", SWAP_ANY); +#endif + +#ifdef FEAT_VIMINFO + /* + * Read in registers, history etc, but not marks, from the viminfo file + */ + if (*p_viminfo != NUL) + { + read_viminfo(NULL, TRUE, FALSE, FALSE); + TIME_MSG("reading viminfo"); + } +#endif + +#ifdef FEAT_QUICKFIX + /* + * "-q errorfile": Load the error file now. + * If the error file can't be read, exit before doing anything else. + */ + if (params.edit_type == EDIT_QF) + { + if (params.use_ef != NULL) + set_string_option_direct((char_u *)"ef", -1, + params.use_ef, OPT_FREE, SID_CARG); + if (qf_init(NULL, p_ef, p_efm, TRUE) < 0) + { + out_char('\n'); + mch_exit(3); + } + TIME_MSG("reading errorfile"); + } +#endif + + /* + * Start putting things on the screen. + * Scroll screen down before drawing over it + * Clear screen now, so file message will not be cleared. + */ + starting = NO_BUFFERS; + no_wait_return = FALSE; + if (!exmode_active) + msg_scroll = FALSE; + +#ifdef FEAT_GUI + /* + * This seems to be required to make callbacks to be called now, instead + * of after things have been put on the screen, which then may be deleted + * when getting a resize callback. + * For the Mac this handles putting files dropped on the Vim icon to + * global_alist. + */ + if (gui.in_use) + { +# ifdef FEAT_SUN_WORKSHOP + if (!usingSunWorkShop) +# endif + gui_wait_for_chars(50L); + TIME_MSG("GUI delay"); + } +#endif + +#if defined(FEAT_GUI_PHOTON) && defined(FEAT_CLIPBOARD) + qnx_clip_init(); +#endif + +#ifdef FEAT_XCLIPBOARD + /* Start using the X clipboard, unless the GUI was started. */ +# ifdef FEAT_GUI + if (!gui.in_use) +# endif + { + setup_term_clip(); + TIME_MSG("setup clipboard"); + } +#endif + +#ifdef FEAT_CLIENTSERVER + /* Prepare for being a Vim server. */ + prepare_server(¶ms); +#endif + + /* + * If "-" argument given: Read file from stdin. + * Do this before starting Raw mode, because it may change things that the + * writing end of the pipe doesn't like, e.g., in case stdin and stderr + * are the same terminal: "cat | vim -". + * Using autocommands here may cause trouble... + */ + if (params.edit_type == EDIT_STDIN && !recoverymode) + read_stdin(); + +#if defined(UNIX) || defined(VMS) + /* When switching screens and something caused a message from a vimrc + * script, need to output an extra newline on exit. */ + if ((did_emsg || msg_didout) && *T_TI != NUL) + newline_on_exit = TRUE; +#endif + + /* + * When done something that is not allowed or error message call + * wait_return. This must be done before starttermcap(), because it may + * switch to another screen. It must be done after settmode(TMODE_RAW), + * because we want to react on a single key stroke. + * Call settmode and starttermcap here, so the T_KS and T_TI may be + * defined by termcapinit and redefined in .exrc. + */ + settmode(TMODE_RAW); + TIME_MSG("setting raw mode"); + + if (need_wait_return || msg_didany) + { + wait_return(TRUE); + TIME_MSG("waiting for return"); + } + + starttermcap(); /* start termcap if not done by wait_return() */ + TIME_MSG("start termcap"); + +#ifdef FEAT_MOUSE + setmouse(); /* may start using the mouse */ +#endif + if (scroll_region) + scroll_region_reset(); /* In case Rows changed */ + scroll_start(); /* may scroll the screen to the right position */ + + /* + * Don't clear the screen when starting in Ex mode, unless using the GUI. + */ + if (exmode_active +#ifdef FEAT_GUI + && !gui.in_use +#endif + ) + must_redraw = CLEAR; + else + { + screenclear(); /* clear screen */ + TIME_MSG("clearing screen"); + } + +#ifdef FEAT_CRYPT + if (params.ask_for_key) + { + (void)get_crypt_key(TRUE, TRUE); + TIME_MSG("getting crypt key"); + } +#endif + + no_wait_return = TRUE; + + /* + * Create the requested number of windows and edit buffers in them. + * Also does recovery if "recoverymode" set. + */ + create_windows(¶ms); + TIME_MSG("opening buffers"); + +#ifdef FEAT_EVAL + /* clear v:swapcommand */ + set_vim_var_string(VV_SWAPCOMMAND, NULL, -1); +#endif + + /* Ex starts at last line of the file */ + if (exmode_active) + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + +#ifdef FEAT_AUTOCMD + apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf); + TIME_MSG("BufEnter autocommands"); +#endif + setpcmark(); + +#ifdef FEAT_QUICKFIX + /* + * When started with "-q errorfile" jump to first error now. + */ + if (params.edit_type == EDIT_QF) + { + qf_jump(NULL, 0, 0, FALSE); + TIME_MSG("jump to first error"); + } +#endif + +#ifdef FEAT_WINDOWS + /* + * If opened more than one window, start editing files in the other + * windows. + */ + edit_buffers(¶ms); +#endif + +#ifdef FEAT_DIFF + if (params.diff_mode) + { + win_T *wp; + + /* set options in each window for "vimdiff". */ + for (wp = firstwin; wp != NULL; wp = wp->w_next) + diff_win_options(wp, TRUE); + } +#endif + + /* + * Shorten any of the filenames, but only when absolute. + */ + shorten_fnames(FALSE); + + /* + * Need to jump to the tag before executing the '-c command'. + * Makes "vim -c '/return' -t main" work. + */ + if (params.tagname != NULL) + { +#if defined(HAS_SWAP_EXISTS_ACTION) + swap_exists_did_quit = FALSE; +#endif + + vim_snprintf((char *)IObuff, IOSIZE, "ta %s", params.tagname); + do_cmdline_cmd(IObuff); + TIME_MSG("jumping to tag"); + +#if defined(HAS_SWAP_EXISTS_ACTION) + /* If the user doesn't want to edit the file then we quit here. */ + if (swap_exists_did_quit) + getout(1); +#endif + } + + /* Execute any "+", "-c" and "-S" arguments. */ + if (params.n_commands > 0) + exe_commands(¶ms); + + RedrawingDisabled = 0; + redraw_all_later(NOT_VALID); + no_wait_return = FALSE; + starting = 0; + +#ifdef FEAT_TERMRESPONSE + /* Requesting the termresponse is postponed until here, so that a "-c q" + * argument doesn't make it appear in the shell Vim was started from. */ + may_req_termresponse(); +#endif + + /* start in insert mode */ + if (p_im) + need_start_insertmode = TRUE; + +#ifdef FEAT_AUTOCMD + apply_autocmds(EVENT_VIMENTER, NULL, NULL, FALSE, curbuf); + TIME_MSG("VimEnter autocommands"); +#endif + +#if defined(FEAT_DIFF) && defined(FEAT_SCROLLBIND) + /* When a startup script or session file setup for diff'ing and + * scrollbind, sync the scrollbind now. */ + if (curwin->w_p_diff && curwin->w_p_scb) + { + update_topline(); + check_scrollbind((linenr_T)0, 0L); + TIME_MSG("diff scrollbinding"); + } +#endif + +#if defined(WIN3264) && !defined(FEAT_GUI_W32) + mch_set_winsize_now(); /* Allow winsize changes from now on */ +#endif + +#if defined(FEAT_GUI) && defined(FEAT_WINDOWS) + /* When tab pages were created, may need to update the tab pages line and + * scrollbars. This is skipped while creating them. */ + if (first_tabpage->tp_next != NULL) + { + out_flush(); + gui_init_which_components(NULL); + gui_update_scrollbars(TRUE); + } + need_mouse_correct = TRUE; +#endif + + /* If ":startinsert" command used, stuff a dummy command to be able to + * call normal_cmd(), which will then start Insert mode. */ + if (restart_edit != 0) + stuffcharReadbuff(K_NOP); + +#ifdef FEAT_NETBEANS_INTG + if (usingNetbeans) + /* Tell the client that it can start sending commands. */ + netbeans_startup_done(); +#endif + + TIME_MSG("before starting main loop"); + + /* + * Call the main command loop. This never returns. + */ + main_loop(FALSE, FALSE); + + return 0; +} +#endif /* PROTO */ + +/* + * Main loop: Execute Normal mode commands until exiting Vim. + * Also used to handle commands in the command-line window, until the window + * is closed. + * Also used to handle ":visual" command after ":global": execute Normal mode + * commands, return when entering Ex mode. "noexmode" is TRUE then. + */ + void +main_loop(cmdwin, noexmode) + int cmdwin; /* TRUE when working in the command-line window */ + int noexmode; /* TRUE when return on entering Ex mode */ +{ + 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 + * it, restore the state and continue. This might not always work + * properly, but at least we don't exit unexpectedly when the X server + * exists while Vim is running in a console. */ + if (!cmdwin && !noexmode && SETJMP(x_jump_env)) + { + State = NORMAL; +# ifdef FEAT_VISUAL + VIsual_active = FALSE; +# endif + got_int = TRUE; + need_wait_return = FALSE; + global_busy = FALSE; + exmode_active = 0; + skip_redraw = FALSE; + RedrawingDisabled = 0; + no_wait_return = 0; +# ifdef FEAT_EVAL + emsg_skip = 0; +# endif + emsg_off = 0; +# ifdef FEAT_MOUSE + setmouse(); +# endif + settmode(TMODE_RAW); + starttermcap(); + scroll_start(); + redraw_later_clear(); + } +#endif + + clear_oparg(&oa); + while (!cmdwin +#ifdef FEAT_CMDWIN + || cmdwin_result == 0 +#endif + ) + { + if (stuff_empty()) + { + did_check_timestamps = FALSE; + if (need_check_timestamps) + check_timestamps(FALSE); + if (need_wait_return) /* if wait_return still needed ... */ + wait_return(FALSE); /* ... call it now */ + if (need_start_insertmode && goto_im() +#ifdef FEAT_VISUAL + && !VIsual_active +#endif + ) + { + need_start_insertmode = FALSE; + stuffReadbuff((char_u *)"i"); /* start insert mode next */ + /* skip the fileinfo message now, because it would be shown + * after insert mode finishes! */ + need_fileinfo = FALSE; + } + } + + /* 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 (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; + + /* + * If skip redraw is set (for ":" in wait_return()), don't redraw now. + * If there is nothing in the stuff_buffer or do_redraw is TRUE, + * update cursor and redraw. + */ + if (skip_redraw || exmode_active) + skip_redraw = FALSE; + else if (do_redraw || stuff_empty()) + { +#ifdef FEAT_AUTOCMD + /* Trigger CursorMoved if the cursor moved. */ + if (!finish_op && has_cursormoved() + && !equalpos(last_cursormoved, curwin->w_cursor)) + { + apply_autocmds(EVENT_CURSORMOVED, NULL, NULL, FALSE, curbuf); + last_cursormoved = curwin->w_cursor; + } +#endif + +#if defined(FEAT_DIFF) && defined(FEAT_SCROLLBIND) + /* Scroll-binding for diff mode may have been postponed until + * here. Avoids doing it for every change. */ + if (diff_need_scrollbind) + { + check_scrollbind((linenr_T)0, 0L); + diff_need_scrollbind = FALSE; + } +#endif +#if defined(FEAT_FOLDING) && defined(FEAT_VISUAL) + /* Include a closed fold completely in the Visual area. */ + foldAdjustVisual(); +#endif +#ifdef FEAT_FOLDING + /* + * When 'foldclose' is set, apply 'foldlevel' to folds that don't + * contain the cursor. + * When 'foldopen' is "all", open the fold(s) under the cursor. + * This may mark the window for redrawing. + */ + if (hasAnyFolding(curwin) && !char_avail()) + { + foldCheckClose(); + if (fdo_flags & FDO_ALL) + foldOpenCursor(); + } +#endif + + /* + * Before redrawing, make sure w_topline is correct, and w_leftcol + * if lines don't wrap, and w_skipcol if lines wrap. + */ + update_topline(); + validate_cursor(); + +#ifdef FEAT_VISUAL + if (VIsual_active) + update_curbuf(INVERTED);/* update inverted part */ + else +#endif + if (must_redraw) + update_screen(0); + else if (redraw_cmdline || clear_cmdline) + showmode(); +#ifdef FEAT_WINDOWS + redraw_statuslines(); +#endif +#ifdef FEAT_TITLE + if (need_maketitle) + maketitle(); +#endif + /* display message after redraw */ + if (keep_msg != NULL) + { + char_u *p; + + /* msg_attr_keep() will set keep_msg to NULL, must free the + * string here. */ + p = keep_msg; + keep_msg = NULL; + msg_attr(p, keep_msg_attr); + vim_free(p); + } + if (need_fileinfo) /* show file info after redraw */ + { + fileinfo(FALSE, TRUE, FALSE); + need_fileinfo = FALSE; + } + + emsg_on_display = FALSE; /* can delete error message now */ + did_emsg = FALSE; + msg_didany = FALSE; /* reset lines_left in msg_start() */ + may_clear_sb_text(); /* clear scroll-back text on next msg */ + showruler(FALSE); + + setcursor(); + cursor_on(); + + do_redraw = FALSE; + } +#ifdef FEAT_GUI + if (need_mouse_correct) + gui_mouse_correct(); +#endif + + /* + * Update w_curswant if w_set_curswant has been set. + * Postponed until here to avoid computing w_virtcol too often. + */ + update_curswant(); + +#ifdef FEAT_EVAL + /* + * May perform garbage collection when waiting for a character, but + * only at the very toplevel. Otherwise we may be using a List or + * Dict internally somewhere. + * "may_garbage_collect" is reset in vgetc() which is invoked through + * do_exmode() and normal_cmd(). + */ + may_garbage_collect = (!cmdwin && !noexmode); +#endif + /* + * If we're invoked as ex, do a round of ex commands. + * Otherwise, get and execute a normal mode command. + */ + if (exmode_active) + { + if (noexmode) /* End of ":global/path/visual" commands */ + return; + do_exmode(exmode_active == EXMODE_VIM); + } + else + normal_cmd(&oa, TRUE); + } +} + + +#if defined(USE_XSMP) || defined(FEAT_GUI_MSWIN) || defined(PROTO) +/* + * Exit, but leave behind swap files for modified buffers. + */ + void +getout_preserve_modified(exitval) + int exitval; +{ +# if defined(SIGHUP) && defined(SIG_IGN) + /* Ignore SIGHUP, because a dropped connection causes a read error, which + * makes Vim exit and then handling SIGHUP causes various reentrance + * problems. */ + signal(SIGHUP, SIG_IGN); +# endif + + ml_close_notmod(); /* close all not-modified buffers */ + ml_sync_all(FALSE, FALSE); /* preserve all swap files */ + ml_close_all(FALSE); /* close all memfiles, without deleting */ + getout(exitval); /* exit Vim properly */ +} +#endif + + +/* Exit properly */ + void +getout(exitval) + int exitval; +{ +#ifdef FEAT_AUTOCMD + buf_T *buf; + win_T *wp; + tabpage_T *tp, *next_tp; +#endif + + exiting = TRUE; + + /* When running in Ex mode an error causes us to exit with a non-zero exit + * code. POSIX requires this, although it's not 100% clear from the + * standard. */ + if (exmode_active) + exitval += ex_exitval; + + /* Position the cursor on the last screen line, below all the text */ +#ifdef FEAT_GUI + if (!gui.in_use) +#endif + windgoto((int)Rows - 1, 0); + +#if defined(FEAT_EVAL) || defined(FEAT_SYN_HL) + /* Optionally print hashtable efficiency. */ + hash_debug_results(); +#endif + +#ifdef FEAT_GUI + msg_didany = FALSE; +#endif + +#ifdef FEAT_AUTOCMD + /* Trigger BufWinLeave for all windows, but only once per buffer. */ +# if defined FEAT_WINDOWS + for (tp = first_tabpage; tp != NULL; tp = next_tp) + { + next_tp = tp->tp_next; + for (wp = (tp == curtab) + ? firstwin : tp->tp_firstwin; wp != NULL; wp = wp->w_next) + { + buf = wp->w_buffer; + if (buf->b_changedtick != -1) + { + apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname, + FALSE, buf); + buf->b_changedtick = -1; /* note that we did it already */ + /* start all over, autocommands may mess up the lists */ + next_tp = first_tabpage; + break; + } + } + } +# else + apply_autocmds(EVENT_BUFWINLEAVE, curbuf, curbuf->b_fname, FALSE, curbuf); +# endif + + /* Trigger BufUnload for buffers that are loaded */ + for (buf = firstbuf; buf != NULL; buf = buf->b_next) + if (buf->b_ml.ml_mfp != NULL) + { + apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, + FALSE, buf); + if (!buf_valid(buf)) /* autocmd may delete the buffer */ + break; + } + apply_autocmds(EVENT_VIMLEAVEPRE, NULL, NULL, FALSE, curbuf); +#endif + +#ifdef FEAT_VIMINFO + if (*p_viminfo != NUL) + /* Write out the registers, history, marks etc, to the viminfo file */ + write_viminfo(NULL, FALSE); +#endif + +#ifdef FEAT_AUTOCMD + apply_autocmds(EVENT_VIMLEAVE, NULL, NULL, FALSE, curbuf); +#endif + +#ifdef FEAT_PROFILE + profile_dump(); +#endif + + if (did_emsg +#ifdef FEAT_GUI + || (gui.in_use && msg_didany && p_verbose > 0) +#endif + ) + { + /* give the user a chance to read the (error) message */ + no_wait_return = FALSE; + wait_return(FALSE); + } + +#ifdef FEAT_AUTOCMD + /* Position the cursor again, the autocommands may have moved it */ +# ifdef FEAT_GUI + if (!gui.in_use) +# endif + windgoto((int)Rows - 1, 0); +#endif + +#ifdef FEAT_MZSCHEME + mzscheme_end(); +#endif +#ifdef FEAT_TCL + tcl_end(); +#endif +#ifdef FEAT_RUBY + ruby_end(); +#endif +#ifdef FEAT_PYTHON + python_end(); +#endif +#ifdef FEAT_PERL + perl_end(); +#endif +#if defined(USE_ICONV) && defined(DYNAMIC_ICONV) + iconv_end(); +#endif +#ifdef FEAT_NETBEANS_INTG + netbeans_end(); +#endif + + mch_exit(exitval); +} + +/* + * Get a (optional) count for a Vim argument. + */ + static int +get_number_arg(p, idx, def) + char_u *p; /* pointer to argument */ + int *idx; /* index in argument, is incremented */ + int def; /* default value */ +{ + if (vim_isdigit(p[*idx])) + { + def = atoi((char *)&(p[*idx])); + while (vim_isdigit(p[*idx])) + *idx = *idx + 1; + } + return def; +} + +#if defined(HAVE_LOCALE_H) || defined(X_LOCALE) +/* + * Setup to use the current locale (for ctype() and many other things). + */ + static void +init_locale() +{ + setlocale(LC_ALL, ""); +# ifdef WIN32 + /* Apparently MS-Windows printf() may cause a crash when we give it 8-bit + * text while it's expecting text in the current locale. This call avoids + * that. */ + setlocale(LC_CTYPE, "C"); +# endif + +# ifdef FEAT_GETTEXT + { + int mustfree = FALSE; + char_u *p; + +# ifdef DYNAMIC_GETTEXT + /* Initialize the gettext library */ + dyn_libintl_init(NULL); +# endif + /* expand_env() doesn't work yet, because chartab[] is not initialized + * yet, call vim_getenv() directly */ + p = vim_getenv((char_u *)"VIMRUNTIME", &mustfree); + if (p != NULL && *p != NUL) + { + vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p); + bindtextdomain(VIMPACKAGE, (char *)NameBuff); + } + if (mustfree) + vim_free(p); + textdomain(VIMPACKAGE); + } +# endif +} +#endif + +/* + * Check for: [r][e][g][vi|vim|view][diff][ex[im]] + * If the executable name starts with "r" we disable shell commands. + * If the next character is "e" we run in Easy mode. + * If the next character is "g" we run the GUI version. + * If the next characters are "view" we start in readonly mode. + * If the next characters are "diff" or "vimdiff" we start in diff mode. + * If the next characters are "ex" we start in Ex mode. If it's followed + * by "im" use improved Ex mode. + */ + static void +parse_command_name(parmp) + mparm_T *parmp; +{ + char_u *initstr; + + initstr = gettail((char_u *)parmp->argv[0]); + +#ifdef MACOS_X_UNIX + /* An issue has been seen when launching Vim in such a way that + * $PWD/$ARGV[0] or $ARGV[0] is not the absolute path to the + * executable or a symbolic link of it. Until this issue is resolved + * we prohibit the GUI from being used. + */ + if (STRCMP(initstr, parmp->argv[0]) == 0) + disallow_gui = TRUE; + + /* TODO: On MacOS X default to gui if argv[0] ends in: + * /Vim.app/Contents/MacOS/Vim */ +#endif + +#ifdef FEAT_EVAL + set_vim_var_string(VV_PROGNAME, initstr, -1); +#endif + + if (TOLOWER_ASC(initstr[0]) == 'r') + { + restricted = TRUE; + ++initstr; + } + + /* Avoid using evim mode for "editor". */ + if (TOLOWER_ASC(initstr[0]) == 'e' + && (TOLOWER_ASC(initstr[1]) == 'v' + || TOLOWER_ASC(initstr[1]) == 'g')) + { +#ifdef FEAT_GUI + gui.starting = TRUE; +#endif + parmp->evim_mode = TRUE; + ++initstr; + } + + if (TOLOWER_ASC(initstr[0]) == 'g' || initstr[0] == 'k') + { + main_start_gui(); +#ifdef FEAT_GUI + ++initstr; +#endif + } + + if (STRNICMP(initstr, "view", 4) == 0) + { + readonlymode = TRUE; + curbuf->b_p_ro = TRUE; + p_uc = 10000; /* don't update very often */ + initstr += 4; + } + else if (STRNICMP(initstr, "vim", 3) == 0) + initstr += 3; + + /* Catch "[r][g]vimdiff" and "[r][g]viewdiff". */ + if (STRICMP(initstr, "diff") == 0) + { +#ifdef FEAT_DIFF + parmp->diff_mode = TRUE; +#else + mch_errmsg(_("This Vim was not compiled with the diff feature.")); + mch_errmsg("\n"); + mch_exit(2); +#endif + } + + if (STRNICMP(initstr, "ex", 2) == 0) + { + if (STRNICMP(initstr + 2, "im", 2) == 0) + exmode_active = EXMODE_VIM; + else + exmode_active = EXMODE_NORMAL; + change_compatible(TRUE); /* set 'compatible' */ + } +} + +/* + * Get the name of the display, before gui_prepare() removes it from + * argv[]. Used for the xterm-clipboard display. + * + * Also find the --server... arguments and --socketid + */ +/*ARGSUSED*/ + static void +early_arg_scan(parmp) + mparm_T *parmp; +{ +#if defined(FEAT_XCLIPBOARD) || defined(FEAT_CLIENTSERVER) + int argc = parmp->argc; + char **argv = parmp->argv; + int i; + + for (i = 1; i < argc; i++) + { + if (STRCMP(argv[i], "--") == 0) + break; +# ifdef FEAT_XCLIPBOARD + else if (STRICMP(argv[i], "-display") == 0 +# if defined(FEAT_GUI_GTK) + || STRICMP(argv[i], "--display") == 0 +# endif + ) + { + if (i == argc - 1) + mainerr_arg_missing((char_u *)argv[i]); + xterm_display = argv[++i]; + } +# endif +# ifdef FEAT_CLIENTSERVER + else if (STRICMP(argv[i], "--servername") == 0) + { + if (i == argc - 1) + mainerr_arg_missing((char_u *)argv[i]); + parmp->serverName_arg = (char_u *)argv[++i]; + } + else if (STRICMP(argv[i], "--serverlist") == 0) + parmp->serverArg = TRUE; + else if (STRNICMP(argv[i], "--remote", 8) == 0) + { + parmp->serverArg = TRUE; +# ifdef FEAT_GUI + if (strstr(argv[i], "-wait") != 0) + /* don't fork() when starting the GUI to edit files ourself */ + gui.dofork = FALSE; +# endif + } +# endif +# ifdef FEAT_GUI_GTK + else if (STRICMP(argv[i], "--socketid") == 0) + { + unsigned int socket_id; + int count; + + if (i == argc - 1) + mainerr_arg_missing((char_u *)argv[i]); + if (STRNICMP(argv[i+1], "0x", 2) == 0) + count = sscanf(&(argv[i + 1][2]), "%x", &socket_id); + else + count = sscanf(argv[i+1], "%u", &socket_id); + if (count != 1) + mainerr(ME_INVALID_ARG, (char_u *)argv[i]); + else + gtk_socket_id = socket_id; + i++; + } + else if (STRICMP(argv[i], "--echo-wid") == 0) + echo_wid_arg = TRUE; +# endif + } +#endif +} + +/* + * Scan the command line arguments. + */ + static void +command_line_scan(parmp) + mparm_T *parmp; +{ + int argc = parmp->argc; + char **argv = parmp->argv; + int argv_idx; /* index in argv[n][] */ + int had_minmin = FALSE; /* found "--" argument */ + int want_argument; /* option argument with argument */ + int c; + char_u *p = NULL; + long n; + + --argc; + ++argv; + argv_idx = 1; /* active option letter is argv[0][argv_idx] */ + while (argc > 0) + { + /* + * "+" or "+{number}" or "+/{pat}" or "+{command}" argument. + */ + if (argv[0][0] == '+' && !had_minmin) + { + if (parmp->n_commands >= MAX_ARG_CMDS) + mainerr(ME_EXTRA_CMD, NULL); + argv_idx = -1; /* skip to next argument */ + if (argv[0][1] == NUL) + parmp->commands[parmp->n_commands++] = (char_u *)"$"; + else + parmp->commands[parmp->n_commands++] = (char_u *)&(argv[0][1]); + } + + /* + * Optional argument. + */ + else if (argv[0][0] == '-' && !had_minmin) + { + want_argument = FALSE; + c = argv[0][argv_idx++]; +#ifdef VMS + /* + * VMS only uses upper case command lines. Interpret "-X" as "-x" + * and "-/X" as "-X". + */ + if (c == '/') + { + c = argv[0][argv_idx++]; + c = TOUPPER_ASC(c); + } + else + c = TOLOWER_ASC(c); +#endif + switch (c) + { + case NUL: /* "vim -" read from stdin */ + /* "ex -" silent mode */ + if (exmode_active) + silent_mode = TRUE; + else + { + if (parmp->edit_type != EDIT_NONE) + mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]); + parmp->edit_type = EDIT_STDIN; + read_cmd_fd = 2; /* read from stderr instead of stdin */ + } + argv_idx = -1; /* skip to next argument */ + break; + + case '-': /* "--" don't take any more option arguments */ + /* "--help" give help message */ + /* "--version" give version message */ + /* "--literal" take files literally */ + /* "--nofork" don't fork */ + /* "--noplugin[s]" skip plugins */ + /* "--cmd " execute cmd before vimrc */ + if (STRICMP(argv[0] + argv_idx, "help") == 0) + usage(); + else if (STRICMP(argv[0] + argv_idx, "version") == 0) + { + Columns = 80; /* need to init Columns */ + info_message = TRUE; /* use mch_msg(), not mch_errmsg() */ + list_version(); + msg_putchar('\n'); + msg_didout = FALSE; + mch_exit(0); + } + else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) + { +#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) + parmp->literal = TRUE; +#endif + } + else if (STRNICMP(argv[0] + argv_idx, "nofork", 6) == 0) + { +#ifdef FEAT_GUI + gui.dofork = FALSE; /* don't fork() when starting GUI */ +#endif + } + else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0) + p_lpl = FALSE; + else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0) + { + want_argument = TRUE; + argv_idx += 3; + } +#ifdef FEAT_CLIENTSERVER + else if (STRNICMP(argv[0] + argv_idx, "serverlist", 10) == 0) + ; /* already processed -- no arg */ + else if (STRNICMP(argv[0] + argv_idx, "servername", 10) == 0 + || STRNICMP(argv[0] + argv_idx, "serversend", 10) == 0) + { + /* already processed -- snatch the following arg */ + if (argc > 1) + { + --argc; + ++argv; + } + } +#endif +#ifdef FEAT_GUI_GTK + else if (STRNICMP(argv[0] + argv_idx, "socketid", 8) == 0) + { + /* already processed -- snatch the following arg */ + if (argc > 1) + { + --argc; + ++argv; + } + } + else if (STRNICMP(argv[0] + argv_idx, "echo-wid", 8) == 0) + { + /* already processed, skip */ + } +#endif + else + { + if (argv[0][argv_idx]) + mainerr(ME_UNKNOWN_OPTION, (char_u *)argv[0]); + had_minmin = TRUE; + } + if (!want_argument) + argv_idx = -1; /* skip to next argument */ + break; + + case 'A': /* "-A" start in Arabic mode */ +#ifdef FEAT_ARABIC + set_option_value((char_u *)"arabic", 1L, NULL, 0); +#else + mch_errmsg(_(e_noarabic)); + mch_exit(2); +#endif + break; + + case 'b': /* "-b" binary mode */ + /* Needs to be effective before expanding file names, because + * for Win32 this makes us edit a shortcut file itself, + * instead of the file it links to. */ + set_options_bin(curbuf->b_p_bin, 1, 0); + curbuf->b_p_bin = 1; /* binary file I/O */ + break; + + case 'C': /* "-C" Compatible */ + change_compatible(TRUE); + break; + + case 'e': /* "-e" Ex mode */ + exmode_active = EXMODE_NORMAL; + break; + + case 'E': /* "-E" Improved Ex mode */ + exmode_active = EXMODE_VIM; + break; + + case 'f': /* "-f" GUI: run in foreground. Amiga: open + window directly, not with newcli */ +#ifdef FEAT_GUI + gui.dofork = FALSE; /* don't fork() when starting GUI */ +#endif + break; + + case 'g': /* "-g" start GUI */ + main_start_gui(); + break; + + case 'F': /* "-F" start in Farsi mode: rl + fkmap set */ +#ifdef FEAT_FKMAP + curwin->w_p_rl = p_fkmap = TRUE; +#else + mch_errmsg(_(e_nofarsi)); + mch_exit(2); +#endif + break; + + case 'h': /* "-h" give help message */ +#ifdef FEAT_GUI_GNOME + /* Tell usage() to exit for "gvim". */ + gui.starting = FALSE; +#endif + usage(); + break; + + case 'H': /* "-H" start in Hebrew mode: rl + hkmap set */ +#ifdef FEAT_RIGHTLEFT + curwin->w_p_rl = p_hkmap = TRUE; +#else + mch_errmsg(_(e_nohebrew)); + mch_exit(2); +#endif + break; + + case 'l': /* "-l" lisp mode, 'lisp' and 'showmatch' on */ +#ifdef FEAT_LISP + set_option_value((char_u *)"lisp", 1L, NULL, 0); + p_sm = TRUE; +#endif + break; + + case 'M': /* "-M" no changes or writing of files */ + reset_modifiable(); + /* FALLTHROUGH */ + + case 'm': /* "-m" no writing of files */ + p_write = FALSE; + break; + + case 'y': /* "-y" easy mode */ +#ifdef FEAT_GUI + gui.starting = TRUE; /* start GUI a bit later */ +#endif + parmp->evim_mode = TRUE; + break; + + case 'N': /* "-N" Nocompatible */ + change_compatible(FALSE); + break; + + case 'n': /* "-n" no swap file */ + parmp->no_swap_file = TRUE; + break; + + case 'p': /* "-p[N]" open N tab pages */ +#ifdef TARGET_API_MAC_OSX + /* For some reason on MacOS X, an argument like: + -psn_0_10223617 is passed in when invoke from Finder + or with the 'open' command */ + if (argv[0][argv_idx] == 's') + { + argv_idx = -1; /* bypass full -psn */ + main_start_gui(); + break; + } +#endif +#ifdef FEAT_WINDOWS + /* default is 0: open window for each file */ + parmp->window_count = get_number_arg((char_u *)argv[0], + &argv_idx, 0); + parmp->window_layout = WIN_TABS; +#endif + break; + + case 'o': /* "-o[N]" open N horizontal split windows */ +#ifdef FEAT_WINDOWS + /* default is 0: open window for each file */ + parmp->window_count = get_number_arg((char_u *)argv[0], + &argv_idx, 0); + parmp->window_layout = WIN_HOR; +#endif + break; + + case 'O': /* "-O[N]" open N vertical split windows */ +#if defined(FEAT_VERTSPLIT) && defined(FEAT_WINDOWS) + /* default is 0: open window for each file */ + parmp->window_count = get_number_arg((char_u *)argv[0], + &argv_idx, 0); + parmp->window_layout = WIN_VER; +#endif + break; + +#ifdef FEAT_QUICKFIX + case 'q': /* "-q" QuickFix mode */ + if (parmp->edit_type != EDIT_NONE) + mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]); + parmp->edit_type = EDIT_QF; + if (argv[0][argv_idx]) /* "-q{errorfile}" */ + { + parmp->use_ef = (char_u *)argv[0] + argv_idx; + argv_idx = -1; + } + else if (argc > 1) /* "-q {errorfile}" */ + want_argument = TRUE; + break; +#endif + + case 'R': /* "-R" readonly mode */ + readonlymode = TRUE; + curbuf->b_p_ro = TRUE; + p_uc = 10000; /* don't update very often */ + break; + + case 'r': /* "-r" recovery mode */ + case 'L': /* "-L" recovery mode */ + recoverymode = 1; + break; + + case 's': + if (exmode_active) /* "-s" silent (batch) mode */ + silent_mode = TRUE; + else /* "-s {scriptin}" read from script file */ + want_argument = TRUE; + break; + + case 't': /* "-t {tag}" or "-t{tag}" jump to tag */ + if (parmp->edit_type != EDIT_NONE) + mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]); + parmp->edit_type = EDIT_TAG; + if (argv[0][argv_idx]) /* "-t{tag}" */ + { + parmp->tagname = (char_u *)argv[0] + argv_idx; + argv_idx = -1; + } + else /* "-t {tag}" */ + want_argument = TRUE; + break; + +#ifdef FEAT_EVAL + case 'D': /* "-D" Debugging */ + parmp->use_debug_break_level = 9999; + break; +#endif +#ifdef FEAT_DIFF + case 'd': /* "-d" 'diff' */ +# ifdef AMIGA + /* check for "-dev {device}" */ + if (argv[0][argv_idx] == 'e' && argv[0][argv_idx + 1] == 'v') + want_argument = TRUE; + else +# endif + parmp->diff_mode = TRUE; + break; +#endif + case 'V': /* "-V{N}" Verbose level */ + /* default is 10: a little bit verbose */ + p_verbose = get_number_arg((char_u *)argv[0], &argv_idx, 10); + if (argv[0][argv_idx] != NUL) + { + set_option_value((char_u *)"verbosefile", 0L, + (char_u *)argv[0] + argv_idx, 0); + argv_idx = (int)STRLEN(argv[0]); + } + break; + + case 'v': /* "-v" Vi-mode (as if called "vi") */ + exmode_active = 0; +#ifdef FEAT_GUI + gui.starting = FALSE; /* don't start GUI */ +#endif + break; + + case 'w': /* "-w{number}" set window height */ + /* "-w {scriptout}" write to script */ + if (vim_isdigit(((char_u *)argv[0])[argv_idx])) + { + n = get_number_arg((char_u *)argv[0], &argv_idx, 10); + set_option_value((char_u *)"window", n, NULL, 0); + break; + } + want_argument = TRUE; + break; + +#ifdef FEAT_CRYPT + case 'x': /* "-x" encrypted reading/writing of files */ + parmp->ask_for_key = TRUE; + break; +#endif + + case 'X': /* "-X" don't connect to X server */ +#if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11) + x_no_connect = TRUE; +#endif + break; + + case 'Z': /* "-Z" restricted mode */ + restricted = TRUE; + break; + + case 'c': /* "-c{command}" or "-c {command}" execute + command */ + if (argv[0][argv_idx] != NUL) + { + if (parmp->n_commands >= MAX_ARG_CMDS) + mainerr(ME_EXTRA_CMD, NULL); + parmp->commands[parmp->n_commands++] = (char_u *)argv[0] + + argv_idx; + argv_idx = -1; + break; + } + /*FALLTHROUGH*/ + case 'S': /* "-S {file}" execute Vim script */ + case 'i': /* "-i {viminfo}" use for viminfo */ +#ifndef FEAT_DIFF + case 'd': /* "-d {device}" device (for Amiga) */ +#endif + case 'T': /* "-T {terminal}" terminal name */ + case 'u': /* "-u {vimrc}" vim inits file */ + case 'U': /* "-U {gvimrc}" gvim inits file */ + case 'W': /* "-W {scriptout}" overwrite */ +#ifdef FEAT_GUI_W32 + case 'P': /* "-P {parent title}" MDI parent */ +#endif + want_argument = TRUE; + break; + + default: + mainerr(ME_UNKNOWN_OPTION, (char_u *)argv[0]); + } + + /* + * Handle option arguments with argument. + */ + if (want_argument) + { + /* + * Check for garbage immediately after the option letter. + */ + if (argv[0][argv_idx] != NUL) + mainerr(ME_GARBAGE, (char_u *)argv[0]); + + --argc; + if (argc < 1 && c != 'S') + mainerr_arg_missing((char_u *)argv[0]); + ++argv; + argv_idx = -1; + + switch (c) + { + case 'c': /* "-c {command}" execute command */ + case 'S': /* "-S {file}" execute Vim script */ + if (parmp->n_commands >= MAX_ARG_CMDS) + mainerr(ME_EXTRA_CMD, NULL); + if (c == 'S') + { + char *a; + + if (argc < 1) + /* "-S" without argument: use default session file + * name. */ + a = SESSION_FILE; + else if (argv[0][0] == '-') + { + /* "-S" followed by another option: use default + * session file name. */ + a = SESSION_FILE; + ++argc; + --argv; + } + else + a = argv[0]; + p = alloc((unsigned)(STRLEN(a) + 4)); + if (p == NULL) + mch_exit(2); + sprintf((char *)p, "so %s", a); + parmp->cmds_tofree[parmp->n_commands] = TRUE; + parmp->commands[parmp->n_commands++] = p; + } + else + parmp->commands[parmp->n_commands++] = + (char_u *)argv[0]; + break; + + case '-': /* "--cmd {command}" execute command */ + if (parmp->n_pre_commands >= MAX_ARG_CMDS) + mainerr(ME_EXTRA_CMD, NULL); + parmp->pre_commands[parmp->n_pre_commands++] = + (char_u *)argv[0]; + break; + + /* case 'd': -d {device} is handled in mch_check_win() for the + * Amiga */ + +#ifdef FEAT_QUICKFIX + case 'q': /* "-q {errorfile}" QuickFix mode */ + parmp->use_ef = (char_u *)argv[0]; + break; +#endif + + case 'i': /* "-i {viminfo}" use for viminfo */ + use_viminfo = (char_u *)argv[0]; + break; + + case 's': /* "-s {scriptin}" read from script file */ + if (scriptin[0] != NULL) + { +scripterror: + mch_errmsg(_("Attempt to open script file again: \"")); + mch_errmsg(argv[-1]); + mch_errmsg(" "); + mch_errmsg(argv[0]); + mch_errmsg("\"\n"); + mch_exit(2); + } + if ((scriptin[0] = mch_fopen(argv[0], READBIN)) == NULL) + { + mch_errmsg(_("Cannot open for reading: \"")); + mch_errmsg(argv[0]); + mch_errmsg("\"\n"); + mch_exit(2); + } + if (save_typebuf() == FAIL) + mch_exit(2); /* out of memory */ + break; + + case 't': /* "-t {tag}" */ + parmp->tagname = (char_u *)argv[0]; + break; + + case 'T': /* "-T {terminal}" terminal name */ + /* + * The -T term argument is always available and when + * HAVE_TERMLIB is supported it overrides the environment + * variable TERM. + */ +#ifdef FEAT_GUI + if (term_is_gui((char_u *)argv[0])) + gui.starting = TRUE; /* start GUI a bit later */ + else +#endif + parmp->term = (char_u *)argv[0]; + break; + + case 'u': /* "-u {vimrc}" vim inits file */ + parmp->use_vimrc = (char_u *)argv[0]; + break; + + case 'U': /* "-U {gvimrc}" gvim inits file */ +#ifdef FEAT_GUI + use_gvimrc = (char_u *)argv[0]; +#endif + break; + + case 'w': /* "-w {nr}" 'window' value */ + /* "-w {scriptout}" append to script file */ + if (vim_isdigit(*((char_u *)argv[0]))) + { + argv_idx = 0; + n = get_number_arg((char_u *)argv[0], &argv_idx, 10); + set_option_value((char_u *)"window", n, NULL, 0); + argv_idx = -1; + break; + } + /*FALLTHROUGH*/ + case 'W': /* "-W {scriptout}" overwrite script file */ + if (scriptout != NULL) + goto scripterror; + if ((scriptout = mch_fopen(argv[0], + c == 'w' ? APPENDBIN : WRITEBIN)) == NULL) + { + mch_errmsg(_("Cannot open for script output: \"")); + mch_errmsg(argv[0]); + mch_errmsg("\"\n"); + mch_exit(2); + } + break; + +#ifdef FEAT_GUI_W32 + case 'P': /* "-P {parent title}" MDI parent */ + gui_mch_set_parent(argv[0]); + break; +#endif + } + } + } + + /* + * File name argument. + */ + else + { + argv_idx = -1; /* skip to next argument */ + + /* Check for only one type of editing. */ + if (parmp->edit_type != EDIT_NONE && parmp->edit_type != EDIT_FILE) + mainerr(ME_TOO_MANY_ARGS, (char_u *)argv[0]); + parmp->edit_type = EDIT_FILE; + +#ifdef MSWIN + /* Remember if the argument was a full path before changing + * slashes to backslashes. */ + if (argv[0][0] != NUL && argv[0][1] == ':' && argv[0][2] == '\\') + parmp->full_path = TRUE; +#endif + + /* Add the file to the global argument list. */ + if (ga_grow(&global_alist.al_ga, 1) == FAIL + || (p = vim_strsave((char_u *)argv[0])) == NULL) + mch_exit(2); +#ifdef FEAT_DIFF + if (parmp->diff_mode && mch_isdir(p) && GARGCOUNT > 0 + && !mch_isdir(alist_name(&GARGLIST[0]))) + { + char_u *r; + + r = concat_fnames(p, gettail(alist_name(&GARGLIST[0])), TRUE); + if (r != NULL) + { + vim_free(p); + p = r; + } + } +#endif +#if defined(__CYGWIN32__) && !defined(WIN32) + /* + * If vim is invoked by non-Cygwin tools, convert away any + * DOS paths, so things like .swp files are created correctly. + * Look for evidence of non-Cygwin paths before we bother. + * This is only for when using the Unix files. + */ + if (strpbrk(p, "\\:") != NULL) + { + char posix_path[PATH_MAX]; + + cygwin_conv_to_posix_path(p, posix_path); + vim_free(p); + p = vim_strsave(posix_path); + if (p == NULL) + mch_exit(2); + } +#endif + +#ifdef USE_FNAME_CASE + /* Make the case of the file name match the actual file. */ + fname_case(p, 0); +#endif + + alist_add(&global_alist, p, +#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) + parmp->literal ? 2 : 0 /* add buffer nr after exp. */ +#else + 2 /* add buffer number now and use curbuf */ +#endif + ); + +#if defined(FEAT_MBYTE) && defined(WIN32) + { + /* Remember this argument has been added to the argument list. + * Needed when 'encoding' is changed. */ + used_file_arg(argv[0], parmp->literal, parmp->full_path, + parmp->diff_mode); + } +#endif + } + + /* + * If there are no more letters after the current "-", go to next + * argument. argv_idx is set to -1 when the current argument is to be + * skipped. + */ + if (argv_idx <= 0 || argv[0][argv_idx] == NUL) + { + --argc; + ++argv; + argv_idx = 1; + } + } + +#ifdef FEAT_EVAL + /* If there is a "+123" or "-c" command, set v:swapcommand to the first + * one. */ + if (parmp->n_commands > 0) + { + p = alloc((unsigned)STRLEN(parmp->commands[0]) + 3); + if (p != NULL) + { + sprintf((char *)p, ":%s\r", parmp->commands[0]); + set_vim_var_string(VV_SWAPCOMMAND, p, -1); + vim_free(p); + } + } +#endif +} + +/* + * Print a warning if stdout is not a terminal. + * When starting in Ex mode and commands come from a file, set Silent mode. + */ + static void +check_tty(parmp) + mparm_T *parmp; +{ + int input_isatty; /* is active input a terminal? */ + + input_isatty = mch_input_isatty(); + if (exmode_active) + { + if (!input_isatty) + silent_mode = TRUE; + } + else if (parmp->want_full_screen && (!parmp->stdout_isatty || !input_isatty) +#ifdef FEAT_GUI + /* don't want the delay when started from the desktop */ + && !gui.starting +#endif + ) + { +#ifdef NBDEBUG + /* + * This shouldn't be necessary. But if I run netbeans with the log + * output coming to the console and XOpenDisplay fails, I get vim + * trying to start with input/output to my console tty. This fills my + * input buffer so fast I can't even kill the process in under 2 + * minutes (and it beeps continuously the whole time :-) + */ + if (usingNetbeans && (!parmp->stdout_isatty || !input_isatty)) + { + mch_errmsg(_("Vim: Error: Failure to start gvim from NetBeans\n")); + exit(1); + } +#endif + if (!parmp->stdout_isatty) + mch_errmsg(_("Vim: Warning: Output is not to a terminal\n")); + if (!input_isatty) + mch_errmsg(_("Vim: Warning: Input is not from a terminal\n")); + out_flush(); + if (scriptin[0] == NULL) + ui_delay(2000L, TRUE); + TIME_MSG("Warning delay"); + } +} + +/* + * Read text from stdin. + */ + static void +read_stdin() +{ + int i; + +#if defined(HAS_SWAP_EXISTS_ACTION) + /* When getting the ATTENTION prompt here, use a dialog */ + swap_exists_action = SEA_DIALOG; +#endif + no_wait_return = TRUE; + i = msg_didany; + set_buflisted(TRUE); + (void)open_buffer(TRUE, NULL); /* create memfile and read file */ + no_wait_return = FALSE; + msg_didany = i; + TIME_MSG("reading stdin"); +#if defined(HAS_SWAP_EXISTS_ACTION) + check_swap_exists_action(); +#endif +#if !(defined(AMIGA) || defined(MACOS)) + /* + * Close stdin and dup it from stderr. Required for GPM to work + * properly, and for running external commands. + * Is there any other system that cannot do this? + */ + close(0); + dup(2); +#endif +} + +/* + * Create the requested number of windows and edit buffers in them. + * Also does recovery if "recoverymode" set. + */ +/*ARGSUSED*/ + static void +create_windows(parmp) + mparm_T *parmp; +{ +#ifdef FEAT_WINDOWS + int dorewind; + int done = 0; + + /* + * Create the number of windows that was requested. + */ + if (parmp->window_count == -1) /* was not set */ + parmp->window_count = 1; + if (parmp->window_count == 0) + parmp->window_count = GARGCOUNT; + if (parmp->window_count > 1) + { + /* Don't change the windows if there was a command in .vimrc that + * already split some windows */ + if (parmp->window_layout == 0) + parmp->window_layout = WIN_HOR; + if (parmp->window_layout == WIN_TABS) + { + parmp->window_count = make_tabpages(parmp->window_count); + TIME_MSG("making tab pages"); + } + else if (firstwin->w_next == NULL) + { + parmp->window_count = make_windows(parmp->window_count, + parmp->window_layout == WIN_VER); + TIME_MSG("making windows"); + } + else + parmp->window_count = win_count(); + } + else + parmp->window_count = 1; +#endif + + if (recoverymode) /* do recover */ + { + msg_scroll = TRUE; /* scroll message up */ + ml_recover(); + if (curbuf->b_ml.ml_mfp == NULL) /* failed */ + getout(1); + do_modelines(0); /* do modelines */ + } + else + { + /* + * Open a buffer for windows that don't have one yet. + * Commands in the .vimrc might have loaded a file or split the window. + * Watch out for autocommands that delete a window. + */ +#ifdef FEAT_AUTOCMD + /* + * Don't execute Win/Buf Enter/Leave autocommands here + */ + ++autocmd_no_enter; + ++autocmd_no_leave; +#endif +#ifdef FEAT_WINDOWS + dorewind = TRUE; + while (done++ < 1000) + { + if (dorewind) + { + if (parmp->window_layout == WIN_TABS) + goto_tabpage(1); + else + curwin = firstwin; + } + else if (parmp->window_layout == WIN_TABS) + { + if (curtab->tp_next == NULL) + break; + goto_tabpage(0); + } + else + { + if (curwin->w_next == NULL) + break; + curwin = curwin->w_next; + } + dorewind = FALSE; +#endif + curbuf = curwin->w_buffer; + if (curbuf->b_ml.ml_mfp == NULL) + { +#ifdef FEAT_FOLDING + /* Set 'foldlevel' to 'foldlevelstart' if it's not negative. */ + if (p_fdls >= 0) + curwin->w_p_fdl = p_fdls; +#endif +#if defined(HAS_SWAP_EXISTS_ACTION) + /* When getting the ATTENTION prompt here, use a dialog */ + swap_exists_action = SEA_DIALOG; +#endif + set_buflisted(TRUE); + (void)open_buffer(FALSE, NULL); /* create memfile, read file */ + +#if defined(HAS_SWAP_EXISTS_ACTION) + if (swap_exists_action == SEA_QUIT) + { + if (got_int || only_one_window()) + { + /* abort selected or quit and only one window */ + did_emsg = FALSE; /* avoid hit-enter prompt */ + getout(1); + } + /* We can't close the window, it would disturb what + * happens next. Clear the file name and set the arg + * index to -1 to delete it later. */ + setfname(curbuf, NULL, NULL, FALSE); + curwin->w_arg_idx = -1; + swap_exists_action = SEA_NONE; + } + else + handle_swap_exists(NULL); +#endif +#ifdef FEAT_AUTOCMD + dorewind = TRUE; /* start again */ +#endif + } +#ifdef FEAT_WINDOWS + ui_breakcheck(); + if (got_int) + { + (void)vgetc(); /* only break the file loading, not the rest */ + break; + } + } +#endif +#ifdef FEAT_WINDOWS + if (parmp->window_layout == WIN_TABS) + goto_tabpage(1); + else + curwin = firstwin; + curbuf = curwin->w_buffer; +#endif +#ifdef FEAT_AUTOCMD + --autocmd_no_enter; + --autocmd_no_leave; +#endif + } +} + +#ifdef FEAT_WINDOWS + /* + * If opened more than one window, start editing files in the other + * windows. make_windows() has already opened the windows. + */ + static void +edit_buffers(parmp) + mparm_T *parmp; +{ + int arg_idx; /* index in argument list */ + int i; + int advance = TRUE; + buf_T *old_curbuf; + +# ifdef FEAT_AUTOCMD + /* + * Don't execute Win/Buf Enter/Leave autocommands here + */ + ++autocmd_no_enter; + ++autocmd_no_leave; +# endif + + /* When w_arg_idx is -1 remove the window (see create_windows()). */ + if (curwin->w_arg_idx == -1) + { + win_close(curwin, TRUE); + advance = FALSE; + } + + arg_idx = 1; + for (i = 1; i < parmp->window_count; ++i) + { + /* When w_arg_idx is -1 remove the window (see create_windows()). */ + if (curwin->w_arg_idx == -1) + { + ++arg_idx; + win_close(curwin, TRUE); + advance = FALSE; + continue; + } + + if (advance) + { + if (parmp->window_layout == WIN_TABS) + { + if (curtab->tp_next == NULL) /* just checking */ + break; + goto_tabpage(0); + } + else + { + if (curwin->w_next == NULL) /* just checking */ + break; + win_enter(curwin->w_next, FALSE); + } + } + advance = TRUE; + + /* Only open the file if there is no file in this window yet (that can + * happen when .vimrc contains ":sall"). */ + if (curbuf == firstwin->w_buffer || curbuf->b_ffname == NULL) + { + curwin->w_arg_idx = arg_idx; + /* Edit file from arg list, if there is one. When "Quit" selected + * at the ATTENTION prompt close the window. */ + old_curbuf = curbuf; + (void)do_ecmd(0, arg_idx < GARGCOUNT + ? alist_name(&GARGLIST[arg_idx]) : NULL, + NULL, NULL, ECMD_LASTL, ECMD_HIDE); + if (curbuf == old_curbuf) + { + if (got_int || only_one_window()) + { + /* abort selected or quit and only one window */ + did_emsg = FALSE; /* avoid hit-enter prompt */ + getout(1); + } + win_close(curwin, TRUE); + advance = FALSE; + } + if (arg_idx == GARGCOUNT - 1) + arg_had_last = TRUE; + ++arg_idx; + } + ui_breakcheck(); + if (got_int) + { + (void)vgetc(); /* only break the file loading, not the rest */ + break; + } + } + + if (parmp->window_layout == WIN_TABS) + goto_tabpage(1); +# ifdef FEAT_AUTOCMD + --autocmd_no_enter; +# endif + win_enter(firstwin, FALSE); /* back to first window */ +# ifdef FEAT_AUTOCMD + --autocmd_no_leave; +# endif + TIME_MSG("editing files in windows"); + if (parmp->window_count > 1 && parmp->window_layout != WIN_TABS) + win_equal(curwin, FALSE, 'b'); /* adjust heights */ +} +#endif /* FEAT_WINDOWS */ + +/* + * Execute the commands from --cmd arguments "cmds[cnt]". + */ + static void +exe_pre_commands(parmp) + mparm_T *parmp; +{ + char_u **cmds = parmp->pre_commands; + int cnt = parmp->n_pre_commands; + int i; + + if (cnt > 0) + { + curwin->w_cursor.lnum = 0; /* just in case.. */ + sourcing_name = (char_u *)_("pre-vimrc command line"); +# ifdef FEAT_EVAL + current_SID = SID_CMDARG; +# endif + for (i = 0; i < cnt; ++i) + do_cmdline_cmd(cmds[i]); + sourcing_name = NULL; +# ifdef FEAT_EVAL + current_SID = 0; +# endif + TIME_MSG("--cmd commands"); + } +} + +/* + * Execute "+", "-c" and "-S" arguments. + */ + static void +exe_commands(parmp) + mparm_T *parmp; +{ + int i; + + /* + * We start commands on line 0, make "vim +/pat file" match a + * pattern on line 1. But don't move the cursor when an autocommand + * with g`" was used. + */ + msg_scroll = TRUE; + if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1) + curwin->w_cursor.lnum = 0; + sourcing_name = (char_u *)"command line"; +#ifdef FEAT_EVAL + current_SID = SID_CARG; +#endif + for (i = 0; i < parmp->n_commands; ++i) + { + do_cmdline_cmd(parmp->commands[i]); + if (parmp->cmds_tofree[i]) + vim_free(parmp->commands[i]); + } + sourcing_name = NULL; +#ifdef FEAT_EVAL + current_SID = 0; +#endif + if (curwin->w_cursor.lnum == 0) + curwin->w_cursor.lnum = 1; + + if (!exmode_active) + msg_scroll = FALSE; + +#ifdef FEAT_QUICKFIX + /* When started with "-q errorfile" jump to first error again. */ + if (parmp->edit_type == EDIT_QF) + qf_jump(NULL, 0, 0, FALSE); +#endif + TIME_MSG("executing command arguments"); +} + +/* + * Source startup scripts. + */ + static void +source_startup_scripts(parmp) + mparm_T *parmp; +{ + int i; + + /* + * For "evim" source evim.vim first of all, so that the user can overrule + * any things he doesn't like. + */ + if (parmp->evim_mode) + { + (void)do_source((char_u *)EVIM_FILE, FALSE, DOSO_NONE); + TIME_MSG("source evim file"); + } + + /* + * If -u argument given, use only the initializations from that file and + * nothing else. + */ + if (parmp->use_vimrc != NULL) + { + if (STRCMP(parmp->use_vimrc, "NONE") == 0 + || STRCMP(parmp->use_vimrc, "NORC") == 0) + { +#ifdef FEAT_GUI + if (use_gvimrc == NULL) /* don't load gvimrc either */ + use_gvimrc = parmp->use_vimrc; +#endif + if (parmp->use_vimrc[2] == 'N') + p_lpl = FALSE; /* don't load plugins either */ + } + else + { + if (do_source(parmp->use_vimrc, FALSE, DOSO_NONE) != OK) + EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc); + } + } + else if (!silent_mode) + { +#ifdef AMIGA + struct Process *proc = (struct Process *)FindTask(0L); + APTR save_winptr = proc->pr_WindowPtr; + + /* Avoid a requester here for a volume that doesn't exist. */ + proc->pr_WindowPtr = (APTR)-1L; +#endif + + /* + * Get system wide defaults, if the file name is defined. + */ +#ifdef SYS_VIMRC_FILE + (void)do_source((char_u *)SYS_VIMRC_FILE, FALSE, DOSO_NONE); +#endif +#ifdef MACOS_X + (void)do_source((char_u *)"$VIMRUNTIME/macmap.vim", FALSE, DOSO_NONE); +#endif + + /* + * Try to read initialization commands from the following places: + * - environment variable VIMINIT + * - user vimrc file (s:.vimrc for Amiga, ~/.vimrc otherwise) + * - second user vimrc file ($VIM/.vimrc for Dos) + * - environment variable EXINIT + * - user exrc file (s:.exrc for Amiga, ~/.exrc otherwise) + * - second user exrc file ($VIM/.exrc for Dos) + * The first that exists is used, the rest is ignored. + */ + if (process_env((char_u *)"VIMINIT", TRUE) != OK) + { + if (do_source((char_u *)USR_VIMRC_FILE, TRUE, DOSO_VIMRC) == FAIL +#ifdef USR_VIMRC_FILE2 + && do_source((char_u *)USR_VIMRC_FILE2, TRUE, + DOSO_VIMRC) == FAIL +#endif +#ifdef USR_VIMRC_FILE3 + && do_source((char_u *)USR_VIMRC_FILE3, TRUE, + DOSO_VIMRC) == FAIL +#endif + && process_env((char_u *)"EXINIT", FALSE) == FAIL + && do_source((char_u *)USR_EXRC_FILE, FALSE, DOSO_NONE) == FAIL) + { +#ifdef USR_EXRC_FILE2 + (void)do_source((char_u *)USR_EXRC_FILE2, FALSE, DOSO_NONE); +#endif + } + } + + /* + * Read initialization commands from ".vimrc" or ".exrc" in current + * directory. This is only done if the 'exrc' option is set. + * Because of security reasons we disallow shell and write commands + * now, except for unix if the file is owned by the user or 'secure' + * option has been reset in environment of global ".exrc" or ".vimrc". + * Only do this if VIMRC_FILE is not the same as USR_VIMRC_FILE or + * SYS_VIMRC_FILE. + */ + if (p_exrc) + { +#if defined(UNIX) || defined(VMS) + /* If ".vimrc" file is not owned by user, set 'secure' mode. */ + if (!file_owned(VIMRC_FILE)) +#endif + secure = p_secure; + + i = FAIL; + if (fullpathcmp((char_u *)USR_VIMRC_FILE, + (char_u *)VIMRC_FILE, FALSE) != FPC_SAME +#ifdef USR_VIMRC_FILE2 + && fullpathcmp((char_u *)USR_VIMRC_FILE2, + (char_u *)VIMRC_FILE, FALSE) != FPC_SAME +#endif +#ifdef USR_VIMRC_FILE3 + && fullpathcmp((char_u *)USR_VIMRC_FILE3, + (char_u *)VIMRC_FILE, FALSE) != FPC_SAME +#endif +#ifdef SYS_VIMRC_FILE + && fullpathcmp((char_u *)SYS_VIMRC_FILE, + (char_u *)VIMRC_FILE, FALSE) != FPC_SAME +#endif + ) + i = do_source((char_u *)VIMRC_FILE, TRUE, DOSO_VIMRC); + + if (i == FAIL) + { +#if defined(UNIX) || defined(VMS) + /* if ".exrc" is not owned by user set 'secure' mode */ + if (!file_owned(EXRC_FILE)) + secure = p_secure; + else + secure = 0; +#endif + if ( fullpathcmp((char_u *)USR_EXRC_FILE, + (char_u *)EXRC_FILE, FALSE) != FPC_SAME +#ifdef USR_EXRC_FILE2 + && fullpathcmp((char_u *)USR_EXRC_FILE2, + (char_u *)EXRC_FILE, FALSE) != FPC_SAME +#endif + ) + (void)do_source((char_u *)EXRC_FILE, FALSE, DOSO_NONE); + } + } + if (secure == 2) + need_wait_return = TRUE; + secure = 0; +#ifdef AMIGA + proc->pr_WindowPtr = save_winptr; +#endif + } + TIME_MSG("sourcing vimrc file(s)"); +} + +/* + * Setup to start using the GUI. Exit with an error when not available. + */ + static void +main_start_gui() +{ +#ifdef FEAT_GUI + gui.starting = TRUE; /* start GUI a bit later */ +#else + mch_errmsg(_(e_nogvim)); + mch_errmsg("\n"); + mch_exit(2); +#endif +} + +/* + * Get an environment variable, and execute it as Ex commands. + * Returns FAIL if the environment variable was not executed, OK otherwise. + */ + int +process_env(env, is_viminit) + char_u *env; + int is_viminit; /* when TRUE, called for VIMINIT */ +{ + char_u *initstr; + char_u *save_sourcing_name; + linenr_T save_sourcing_lnum; +#ifdef FEAT_EVAL + scid_T save_sid; +#endif + + if ((initstr = mch_getenv(env)) != NULL && *initstr != NUL) + { + if (is_viminit) + vimrc_found(NULL, NULL); + save_sourcing_name = sourcing_name; + save_sourcing_lnum = sourcing_lnum; + sourcing_name = env; + sourcing_lnum = 0; +#ifdef FEAT_EVAL + save_sid = current_SID; + current_SID = SID_ENV; +#endif + do_cmdline_cmd(initstr); + sourcing_name = save_sourcing_name; + sourcing_lnum = save_sourcing_lnum; +#ifdef FEAT_EVAL + current_SID = save_sid;; +#endif + return OK; + } + return FAIL; +} + +#if defined(UNIX) || defined(VMS) +/* + * Return TRUE if we are certain the user owns the file "fname". + * Used for ".vimrc" and ".exrc". + * Use both stat() and lstat() for extra security. + */ + static int +file_owned(fname) + char *fname; +{ + struct stat s; +# ifdef UNIX + uid_t uid = getuid(); +# else /* VMS */ + uid_t uid = ((getgid() << 16) | getuid()); +# endif + + return !(mch_stat(fname, &s) != 0 || s.st_uid != uid +# ifdef HAVE_LSTAT + || mch_lstat(fname, &s) != 0 || s.st_uid != uid +# endif + ); +} +#endif + +/* + * Give an error message main_errors["n"] and exit. + */ + static void +mainerr(n, str) + int n; /* one of the ME_ defines */ + char_u *str; /* extra argument or NULL */ +{ +#if defined(UNIX) || defined(__EMX__) || defined(VMS) + reset_signals(); /* kill us with CTRL-C here, if you like */ +#endif + + mch_errmsg(longVersion); + mch_errmsg("\n"); + mch_errmsg(_(main_errors[n])); + if (str != NULL) + { + mch_errmsg(": \""); + mch_errmsg((char *)str); + mch_errmsg("\""); + } + mch_errmsg(_("\nMore info with: \"vim -h\"\n")); + + mch_exit(1); +} + + void +mainerr_arg_missing(str) + char_u *str; +{ + mainerr(ME_ARG_MISSING, str); +} + +/* + * print a message with three spaces prepended and '\n' appended. + */ + static void +main_msg(s) + char *s; +{ + mch_msg(" "); + mch_msg(s); + mch_msg("\n"); +} + +/* + * Print messages for "vim -h" or "vim --help" and exit. + */ + static void +usage() +{ + int i; + static char *(use[]) = + { + N_("[file ..] edit specified file(s)"), + N_("- read text from stdin"), + N_("-t tag edit file where tag is defined"), +#ifdef FEAT_QUICKFIX + N_("-q [errorfile] edit file with first error") +#endif + }; + +#if defined(UNIX) || defined(__EMX__) || defined(VMS) + reset_signals(); /* kill us with CTRL-C here, if you like */ +#endif + + mch_msg(longVersion); + mch_msg(_("\n\nusage:")); + for (i = 0; ; ++i) + { + mch_msg(_(" vim [arguments] ")); + mch_msg(_(use[i])); + if (i == (sizeof(use) / sizeof(char_u *)) - 1) + break; + mch_msg(_("\n or:")); + } +#ifdef VMS + mch_msg(_("\nWhere case is ignored prepend / to make flag upper case")); +#endif + + mch_msg(_("\n\nArguments:\n")); + main_msg(_("--\t\t\tOnly file names after this")); +#if (!defined(UNIX) && !defined(__EMX__)) || defined(ARCHIE) + main_msg(_("--literal\t\tDon't expand wildcards")); +#endif +#ifdef FEAT_OLE + main_msg(_("-register\t\tRegister this gvim for OLE")); + main_msg(_("-unregister\t\tUnregister gvim for OLE")); +#endif +#ifdef FEAT_GUI + main_msg(_("-g\t\t\tRun using GUI (like \"gvim\")")); + main_msg(_("-f or --nofork\tForeground: Don't fork when starting GUI")); +#endif + main_msg(_("-v\t\t\tVi mode (like \"vi\")")); + main_msg(_("-e\t\t\tEx mode (like \"ex\")")); + main_msg(_("-s\t\t\tSilent (batch) mode (only for \"ex\")")); +#ifdef FEAT_DIFF + main_msg(_("-d\t\t\tDiff mode (like \"vimdiff\")")); +#endif + main_msg(_("-y\t\t\tEasy mode (like \"evim\", modeless)")); + main_msg(_("-R\t\t\tReadonly mode (like \"view\")")); + main_msg(_("-Z\t\t\tRestricted mode (like \"rvim\")")); + main_msg(_("-m\t\t\tModifications (writing files) not allowed")); + main_msg(_("-M\t\t\tModifications in text not allowed")); + main_msg(_("-b\t\t\tBinary mode")); +#ifdef FEAT_LISP + main_msg(_("-l\t\t\tLisp mode")); +#endif + main_msg(_("-C\t\t\tCompatible with Vi: 'compatible'")); + main_msg(_("-N\t\t\tNot fully Vi compatible: 'nocompatible'")); + main_msg(_("-V[N][fname]\t\tBe verbose [level N] [log messages to fname]")); +#ifdef FEAT_EVAL + main_msg(_("-D\t\t\tDebugging mode")); +#endif + main_msg(_("-n\t\t\tNo swap file, use memory only")); + main_msg(_("-r\t\t\tList swap files and exit")); + main_msg(_("-r (with file name)\tRecover crashed session")); + main_msg(_("-L\t\t\tSame as -r")); +#ifdef AMIGA + main_msg(_("-f\t\t\tDon't use newcli to open window")); + main_msg(_("-dev \t\tUse for I/O")); +#endif +#ifdef FEAT_ARABIC + main_msg(_("-A\t\t\tstart in Arabic mode")); +#endif +#ifdef FEAT_RIGHTLEFT + main_msg(_("-H\t\t\tStart in Hebrew mode")); +#endif +#ifdef FEAT_FKMAP + main_msg(_("-F\t\t\tStart in Farsi mode")); +#endif + main_msg(_("-T \tSet terminal type to ")); + main_msg(_("-u \t\tUse instead of any .vimrc")); +#ifdef FEAT_GUI + main_msg(_("-U \t\tUse instead of any .gvimrc")); +#endif + main_msg(_("--noplugin\t\tDon't load plugin scripts")); +#ifdef FEAT_WINDOWS + main_msg(_("-p[N]\t\tOpen N tab pages (default: one for each file)")); + main_msg(_("-o[N]\t\tOpen N windows (default: one for each file)")); + main_msg(_("-O[N]\t\tLike -o but split vertically")); +#endif + main_msg(_("+\t\t\tStart at end of file")); + main_msg(_("+\t\tStart at line ")); + main_msg(_("--cmd \tExecute before loading any vimrc file")); + main_msg(_("-c \t\tExecute after loading the first file")); + main_msg(_("-S \t\tSource file after loading the first file")); + main_msg(_("-s \tRead Normal mode commands from file ")); + main_msg(_("-w \tAppend all typed commands to file ")); + main_msg(_("-W \tWrite all typed commands to file ")); +#ifdef FEAT_CRYPT + main_msg(_("-x\t\t\tEdit encrypted files")); +#endif +#if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11) +# if defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK) + main_msg(_("-display \tConnect vim to this particular X-server")); +# endif + main_msg(_("-X\t\t\tDo not connect to X server")); +#endif +#ifdef FEAT_CLIENTSERVER + main_msg(_("--remote \tEdit in a Vim server if possible")); + main_msg(_("--remote-silent Same, don't complain if there is no server")); + main_msg(_("--remote-wait As --remote but wait for files to have been edited")); + main_msg(_("--remote-wait-silent Same, don't complain if there is no server")); +# ifdef FEAT_WINDOWS + main_msg(_("--remote-tab As --remote but open tab page for each file")); +# endif + main_msg(_("--remote-send \tSend to a Vim server and exit")); + main_msg(_("--remote-expr \tEvaluate in a Vim server and print result")); + main_msg(_("--serverlist\t\tList available Vim server names and exit")); + main_msg(_("--servername \tSend to/become the Vim server ")); +#endif +#ifdef FEAT_VIMINFO + main_msg(_("-i \t\tUse instead of .viminfo")); +#endif + main_msg(_("-h or --help\tPrint Help (this message) and exit")); + main_msg(_("--version\t\tPrint version information and exit")); + +#ifdef FEAT_GUI_X11 +# ifdef FEAT_GUI_MOTIF + mch_msg(_("\nArguments recognised by gvim (Motif version):\n")); +# else +# ifdef FEAT_GUI_ATHENA +# ifdef FEAT_GUI_NEXTAW + mch_msg(_("\nArguments recognised by gvim (neXtaw version):\n")); +# else + mch_msg(_("\nArguments recognised by gvim (Athena version):\n")); +# endif +# endif +# endif + main_msg(_("-display \tRun vim on ")); + main_msg(_("-iconic\t\tStart vim iconified")); +# if 0 + main_msg(_("-name \t\tUse resource as if vim was ")); + mch_msg(_("\t\t\t (Unimplemented)\n")); +# endif + main_msg(_("-background \tUse for the background (also: -bg)")); + main_msg(_("-foreground \tUse for normal text (also: -fg)")); + main_msg(_("-font \t\tUse for normal text (also: -fn)")); + main_msg(_("-boldfont \tUse for bold text")); + main_msg(_("-italicfont \tUse for italic text")); + main_msg(_("-geometry \tUse for initial geometry (also: -geom)")); + main_msg(_("-borderwidth \tUse a border width of (also: -bw)")); + main_msg(_("-scrollbarwidth Use a scrollbar width of (also: -sw)")); +# ifdef FEAT_GUI_ATHENA + main_msg(_("-menuheight \tUse a menu bar height of (also: -mh)")); +# endif + main_msg(_("-reverse\t\tUse reverse video (also: -rv)")); + main_msg(_("+reverse\t\tDon't use reverse video (also: +rv)")); + main_msg(_("-xrm \tSet the specified resource")); +#endif /* FEAT_GUI_X11 */ +#if defined(FEAT_GUI) && defined(RISCOS) + mch_msg(_("\nArguments recognised by gvim (RISC OS version):\n")); + main_msg(_("--columns \tInitial width of window in columns")); + main_msg(_("--rows \tInitial height of window in rows")); +#endif +#ifdef FEAT_GUI_GTK + mch_msg(_("\nArguments recognised by gvim (GTK+ version):\n")); + main_msg(_("-font \t\tUse for normal text (also: -fn)")); + main_msg(_("-geometry \tUse for initial geometry (also: -geom)")); + main_msg(_("-reverse\t\tUse reverse video (also: -rv)")); + main_msg(_("-display \tRun vim on (also: --display)")); +# ifdef HAVE_GTK2 + main_msg(_("--role \tSet a unique role to identify the main window")); +# endif + main_msg(_("--socketid \tOpen Vim inside another GTK widget")); +#endif +#ifdef FEAT_GUI_W32 + main_msg(_("-P \tOpen Vim inside parent application")); +#endif + +#ifdef FEAT_GUI_GNOME + /* Gnome gives extra messages for --help if we continue, but not for -h. */ + if (gui.starting) + mch_msg("\n"); + else +#endif + mch_exit(0); +} + +#if defined(HAS_SWAP_EXISTS_ACTION) +/* + * Check the result of the ATTENTION dialog: + * When "Quit" selected, exit Vim. + * When "Recover" selected, recover the file. + */ + static void +check_swap_exists_action() +{ + if (swap_exists_action == SEA_QUIT) + getout(1); + handle_swap_exists(NULL); +} +#endif + +#if defined(STARTUPTIME) || defined(PROTO) +static void time_diff __ARGS((struct timeval *then, struct timeval *now)); + +static struct timeval prev_timeval; + +/* + * Save the previous time before doing something that could nest. + * set "*tv_rel" to the time elapsed so far. + */ + void +time_push(tv_rel, tv_start) + void *tv_rel, *tv_start; +{ + *((struct timeval *)tv_rel) = prev_timeval; + gettimeofday(&prev_timeval, NULL); + ((struct timeval *)tv_rel)->tv_usec = prev_timeval.tv_usec + - ((struct timeval *)tv_rel)->tv_usec; + ((struct timeval *)tv_rel)->tv_sec = prev_timeval.tv_sec + - ((struct timeval *)tv_rel)->tv_sec; + if (((struct timeval *)tv_rel)->tv_usec < 0) + { + ((struct timeval *)tv_rel)->tv_usec += 1000000; + --((struct timeval *)tv_rel)->tv_sec; + } + *(struct timeval *)tv_start = prev_timeval; +} + +/* + * Compute the previous time after doing something that could nest. + * Subtract "*tp" from prev_timeval; + * Note: The arguments are (void *) to avoid trouble with systems that don't + * have struct timeval. + */ + void +time_pop(tp) + void *tp; /* actually (struct timeval *) */ +{ + prev_timeval.tv_usec -= ((struct timeval *)tp)->tv_usec; + prev_timeval.tv_sec -= ((struct timeval *)tp)->tv_sec; + if (prev_timeval.tv_usec < 0) + { + prev_timeval.tv_usec += 1000000; + --prev_timeval.tv_sec; + } +} + + static void +time_diff(then, now) + struct timeval *then; + struct timeval *now; +{ + long usec; + long msec; + + usec = now->tv_usec - then->tv_usec; + msec = (now->tv_sec - then->tv_sec) * 1000L + usec / 1000L, + usec = usec % 1000L; + fprintf(time_fd, "%03ld.%03ld", msec, usec >= 0 ? usec : usec + 1000L); +} + + void +time_msg(msg, tv_start) + char *msg; + void *tv_start; /* only for do_source: start time; actually + (struct timeval *) */ +{ + static struct timeval start; + struct timeval now; + + if (time_fd != NULL) + { + if (strstr(msg, "STARTING") != NULL) + { + gettimeofday(&start, NULL); + prev_timeval = start; + fprintf(time_fd, "\n\ntimes in msec\n"); + fprintf(time_fd, " clock self+sourced self: sourced script\n"); + fprintf(time_fd, " clock elapsed: other lines\n\n"); + } + gettimeofday(&now, NULL); + time_diff(&start, &now); + if (((struct timeval *)tv_start) != NULL) + { + fprintf(time_fd, " "); + time_diff(((struct timeval *)tv_start), &now); + } + fprintf(time_fd, " "); + time_diff(&prev_timeval, &now); + prev_timeval = now; + fprintf(time_fd, ": %s\n", msg); + } +} + +# ifdef WIN3264 +/* + * Windows doesn't have gettimeofday(), although it does have struct timeval. + */ + int +gettimeofday(struct timeval *tv, char *dummy) +{ + long t = clock(); + tv->tv_sec = t / CLOCKS_PER_SEC; + tv->tv_usec = (t - tv->tv_sec * CLOCKS_PER_SEC) * 1000000 / CLOCKS_PER_SEC; + return 0; +} +# endif + +#endif + +#if defined(FEAT_CLIENTSERVER) || defined(PROTO) + +/* + * Common code for the X command server and the Win32 command server. + */ + +static char_u *build_drop_cmd __ARGS((int filec, char **filev, int tabs, int sendReply)); + +/* + * Do the client-server stuff, unless "--servername ''" was used. + */ + static void +exec_on_server(parmp) + mparm_T *parmp; +{ + if (parmp->serverName_arg == NULL || *parmp->serverName_arg != NUL) + { +# ifdef WIN32 + /* Initialise the client/server messaging infrastructure. */ + serverInitMessaging(); +# endif + + /* + * When a command server argument was found, execute it. This may + * exit Vim when it was successful. Otherwise it's executed further + * on. Remember the encoding used here in "serverStrEnc". + */ + if (parmp->serverArg) + { + cmdsrv_main(&parmp->argc, parmp->argv, + parmp->serverName_arg, &parmp->serverStr); +# ifdef FEAT_MBYTE + parmp->serverStrEnc = vim_strsave(p_enc); +# endif + } + + /* If we're still running, get the name to register ourselves. + * On Win32 can register right now, for X11 need to setup the + * clipboard first, it's further down. */ + parmp->servername = serverMakeName(parmp->serverName_arg, + parmp->argv[0]); +# ifdef WIN32 + if (parmp->servername != NULL) + { + serverSetName(parmp->servername); + vim_free(parmp->servername); + } +# endif + } +} + +/* + * Prepare for running as a Vim server. + */ + static void +prepare_server(parmp) + mparm_T *parmp; +{ +# if defined(FEAT_X11) + /* + * Register for remote command execution with :serversend and --remote + * unless there was a -X or a --servername '' on the command line. + * Only register nongui-vim's with an explicit --servername argument. + * When running as root --servername is also required. + */ + if (X_DISPLAY != NULL && parmp->servername != NULL && ( +# ifdef FEAT_GUI + (gui.in_use +# ifdef UNIX + && getuid() != ROOT_UID +# endif + ) || +# endif + parmp->serverName_arg != NULL)) + { + (void)serverRegisterName(X_DISPLAY, parmp->servername); + vim_free(parmp->servername); + TIME_MSG("register server name"); + } + else + serverDelayedStartName = parmp->servername; +# endif + + /* + * Execute command ourselves if we're here because the send failed (or + * else we would have exited above). + */ + if (parmp->serverStr != NULL) + { + char_u *p; + + server_to_input_buf(serverConvert(parmp->serverStrEnc, + parmp->serverStr, &p)); + vim_free(p); + } +} + + static void +cmdsrv_main(argc, argv, serverName_arg, serverStr) + int *argc; + char **argv; + char_u *serverName_arg; + char_u **serverStr; +{ + char_u *res; + int i; + char_u *sname; + int ret; + int didone = FALSE; + int exiterr = 0; + char **newArgV = argv + 1; + int newArgC = 1, + Argc = *argc; + int argtype; +#define ARGTYPE_OTHER 0 +#define ARGTYPE_EDIT 1 +#define ARGTYPE_EDIT_WAIT 2 +#define ARGTYPE_SEND 3 + int silent = FALSE; + int tabs = FALSE; +# ifndef FEAT_X11 + HWND srv; +# else + Window srv; + + setup_term_clip(); +# endif + + sname = serverMakeName(serverName_arg, argv[0]); + if (sname == NULL) + return; + + /* + * Execute the command server related arguments and remove them + * from the argc/argv array; We may have to return into main() + */ + for (i = 1; i < Argc; i++) + { + res = NULL; + if (STRCMP(argv[i], "--") == 0) /* end of option arguments */ + { + for (; i < *argc; i++) + { + *newArgV++ = argv[i]; + newArgC++; + } + break; + } + + if (STRICMP(argv[i], "--remote-send") == 0) + argtype = ARGTYPE_SEND; + else if (STRNICMP(argv[i], "--remote", 8) == 0) + { + char *p = argv[i] + 8; + + argtype = ARGTYPE_EDIT; + while (*p != NUL) + { + if (STRNICMP(p, "-wait", 5) == 0) + { + argtype = ARGTYPE_EDIT_WAIT; + p += 5; + } + else if (STRNICMP(p, "-silent", 7) == 0) + { + silent = TRUE; + p += 7; + } + else if (STRNICMP(p, "-tab", 4) == 0) + { + tabs = TRUE; + p += 4; + } + else + { + argtype = ARGTYPE_OTHER; + break; + } + } + } + else + argtype = ARGTYPE_OTHER; + + if (argtype != ARGTYPE_OTHER) + { + if (i == *argc - 1) + mainerr_arg_missing((char_u *)argv[i]); + if (argtype == ARGTYPE_SEND) + { + *serverStr = (char_u *)argv[i + 1]; + i++; + } + else + { + *serverStr = build_drop_cmd(*argc - i - 1, argv + i + 1, + tabs, argtype == ARGTYPE_EDIT_WAIT); + if (*serverStr == NULL) + { + /* Probably out of memory, exit. */ + didone = TRUE; + exiterr = 1; + break; + } + Argc = i; + } +# ifdef FEAT_X11 + if (xterm_dpy == NULL) + { + mch_errmsg(_("No display")); + ret = -1; + } + else + ret = serverSendToVim(xterm_dpy, sname, *serverStr, + NULL, &srv, 0, 0, silent); +# else + /* Win32 always works? */ + ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, silent); +# endif + if (ret < 0) + { + if (argtype == ARGTYPE_SEND) + { + /* Failed to send, abort. */ + mch_errmsg(_(": Send failed.\n")); + didone = TRUE; + exiterr = 1; + } + else if (!silent) + /* Let vim start normally. */ + mch_errmsg(_(": Send failed. Trying to execute locally\n")); + break; + } + +# ifdef FEAT_GUI_W32 + /* Guess that when the server name starts with "g" it's a GUI + * server, which we can bring to the foreground here. + * Foreground() in the server doesn't work very well. */ + if (argtype != ARGTYPE_SEND && TOUPPER_ASC(*sname) == 'G') + SetForegroundWindow(srv); +# endif + + /* + * For --remote-wait: Wait until the server did edit each + * file. Also detect that the server no longer runs. + */ + if (ret >= 0 && argtype == ARGTYPE_EDIT_WAIT) + { + int numFiles = *argc - i - 1; + int j; + char_u *done = alloc(numFiles); + char_u *p; +# ifdef FEAT_GUI_W32 + NOTIFYICONDATA ni; + int count = 0; + extern HWND message_window; +# endif + + if (numFiles > 0 && argv[i + 1][0] == '+') + /* Skip "+cmd" argument, don't wait for it to be edited. */ + --numFiles; + +# ifdef FEAT_GUI_W32 + ni.cbSize = sizeof(ni); + ni.hWnd = message_window; + ni.uID = 0; + ni.uFlags = NIF_ICON|NIF_TIP; + ni.hIcon = LoadIcon((HINSTANCE)GetModuleHandle(0), "IDR_VIM"); + sprintf(ni.szTip, _("%d of %d edited"), count, numFiles); + Shell_NotifyIcon(NIM_ADD, &ni); +# endif + + /* Wait for all files to unload in remote */ + memset(done, 0, numFiles); + while (memchr(done, 0, numFiles) != NULL) + { +# ifdef WIN32 + p = serverGetReply(srv, NULL, TRUE, TRUE); + if (p == NULL) + break; +# else + if (serverReadReply(xterm_dpy, srv, &p, TRUE) < 0) + break; +# endif + j = atoi((char *)p); + if (j >= 0 && j < numFiles) + { +# ifdef FEAT_GUI_W32 + ++count; + sprintf(ni.szTip, _("%d of %d edited"), + count, numFiles); + Shell_NotifyIcon(NIM_MODIFY, &ni); +# endif + done[j] = 1; + } + } +# ifdef FEAT_GUI_W32 + Shell_NotifyIcon(NIM_DELETE, &ni); +# endif + } + } + else if (STRICMP(argv[i], "--remote-expr") == 0) + { + if (i == *argc - 1) + mainerr_arg_missing((char_u *)argv[i]); +# ifdef WIN32 + /* Win32 always works? */ + if (serverSendToVim(sname, (char_u *)argv[i + 1], + &res, NULL, 1, FALSE) < 0) +# else + if (xterm_dpy == NULL) + mch_errmsg(_("No display: Send expression failed.\n")); + else if (serverSendToVim(xterm_dpy, sname, (char_u *)argv[i + 1], + &res, NULL, 1, 1, FALSE) < 0) +# endif + { + if (res != NULL && *res != NUL) + { + /* Output error from remote */ + mch_errmsg((char *)res); + vim_free(res); + res = NULL; + } + mch_errmsg(_(": Send expression failed.\n")); + } + } + else if (STRICMP(argv[i], "--serverlist") == 0) + { +# ifdef WIN32 + /* Win32 always works? */ + res = serverGetVimNames(); +# else + if (xterm_dpy != NULL) + res = serverGetVimNames(xterm_dpy); +# endif + if (called_emsg) + mch_errmsg("\n"); + } + else if (STRICMP(argv[i], "--servername") == 0) + { + /* Alredy processed. Take it out of the command line */ + i++; + continue; + } + else + { + *newArgV++ = argv[i]; + newArgC++; + continue; + } + didone = TRUE; + if (res != NULL && *res != NUL) + { + mch_msg((char *)res); + if (res[STRLEN(res) - 1] != '\n') + mch_msg("\n"); + } + vim_free(res); + } + + if (didone) + { + display_errors(); /* display any collected messages */ + exit(exiterr); /* Mission accomplished - get out */ + } + + /* Return back into main() */ + *argc = newArgC; + vim_free(sname); +} + +/* + * Build a ":drop" command to send to a Vim server. + */ + static char_u * +build_drop_cmd(filec, filev, tabs, sendReply) + int filec; + char **filev; + int tabs; /* Use ":tab drop" instead of ":drop". */ + int sendReply; +{ + garray_T ga; + int i; + char_u *inicmd = NULL; + char_u *p; + char_u cwd[MAXPATHL]; + + if (filec > 0 && filev[0][0] == '+') + { + inicmd = (char_u *)filev[0] + 1; + filev++; + filec--; + } + /* Check if we have at least one argument. */ + if (filec <= 0) + 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) + return NULL; + ga_init2(&ga, 1, 100); + ga_concat(&ga, (char_u *)":cd "); + ga_concat(&ga, p); + vim_free(p); + + /* Call inputsave() so that a prompt for an encryption key works. */ + ga_concat(&ga, (char_u *)":if exists('*inputsave')|call inputsave()|endif|"); + if (tabs) + ga_concat(&ga, (char_u *)"tab "); + ga_concat(&ga, (char_u *)"drop"); + for (i = 0; i < filec; i++) + { + /* On Unix the shell has already expanded the wildcards, don't want to + * do it again in the Vim server. On MS-Windows only escape + * non-wildcard characters. */ + p = vim_strsave_escaped((char_u *)filev[i], +#ifdef UNIX + PATH_ESC_CHARS +#else + (char_u *)" \t%#" +#endif + ); + if (p == NULL) + { + vim_free(ga.ga_data); + return NULL; + } + ga_concat(&ga, (char_u *)" "); + ga_concat(&ga, p); + vim_free(p); + } + /* The :drop commands goes to Insert mode when 'insertmode' is set, use + * CTRL-\ CTRL-N again. */ + ga_concat(&ga, (char_u *)"|if exists('*inputrestore')|call inputrestore()|endif"); + ga_concat(&ga, (char_u *)":cd -"); + if (sendReply) + ga_concat(&ga, (char_u *)":call SetupRemoteReplies()"); + ga_concat(&ga, (char_u *)":"); + if (inicmd != NULL) + { + /* Can't use after "inicmd", because an "startinsert" would cause + * the following commands to be inserted as text. Use a "|", + * hopefully "inicmd" does allow this... */ + ga_concat(&ga, inicmd); + ga_concat(&ga, (char_u *)"|"); + } + /* Bring the window to the foreground, goto Insert mode when 'im' set and + * clear command line. */ + ga_concat(&ga, (char_u *)"cal foreground()|if &im|star|en|redr|f"); + ga_append(&ga, NUL); + return ga.ga_data; +} + +/* + * Replace termcodes such as and insert as key presses if there is room. + */ + void +server_to_input_buf(str) + char_u *str; +{ + char_u *ptr = NULL; + char_u *cpo_save = p_cpo; + + /* Set 'cpoptions' the way we want it. + * B set - backslashes are *not* treated specially + * k set - keycodes are *not* reverse-engineered + * < unset - sequences *are* interpreted + * The last but one parameter of replace_termcodes() is TRUE so that the + * sequence is recognised - needed for a real backslash. + */ + p_cpo = (char_u *)"Bk"; + str = replace_termcodes((char_u *)str, &ptr, FALSE, TRUE, FALSE); + p_cpo = cpo_save; + + if (*ptr != NUL) /* trailing CTRL-V results in nothing */ + { + /* + * Add the string to the input stream. + * Can't use add_to_input_buf() here, we now have K_SPECIAL bytes. + * + * First clear typed characters from the typeahead buffer, there could + * be half a mapping there. Then append to the existing string, so + * that multiple commands from a client are concatenated. + */ + if (typebuf.tb_maplen < typebuf.tb_len) + del_typebuf(typebuf.tb_len - typebuf.tb_maplen, typebuf.tb_maplen); + (void)ins_typebuf(str, REMAP_NONE, typebuf.tb_len, TRUE, FALSE); + + /* Let input_available() know we inserted text in the typeahead + * buffer. */ + typebuf_was_filled = TRUE; + } + vim_free((char_u *)ptr); +} + +/* + * Evaluate an expression that the client sent to a string. + * Handles disabling error messages and disables debugging, otherwise Vim + * hangs, waiting for "cont" to be typed. + */ + char_u * +eval_client_expr_to_string(expr) + char_u *expr; +{ + char_u *res; + int save_dbl = debug_break_level; + int save_ro = redir_off; + + debug_break_level = -1; + redir_off = 0; + ++emsg_skip; + + res = eval_to_string(expr, NULL, TRUE); + + debug_break_level = save_dbl; + redir_off = save_ro; + --emsg_skip; + + /* A client can tell us to redraw, but not to display the cursor, so do + * that here. */ + setcursor(); + out_flush(); +#ifdef FEAT_GUI + if (gui.in_use) + gui_update_cursor(FALSE, FALSE); +#endif + + return res; +} + +/* + * If conversion is needed, convert "data" from "client_enc" to 'encoding' and + * return an allocated string. Otherwise return "data". + * "*tofree" is set to the result when it needs to be freed later. + */ +/*ARGSUSED*/ + char_u * +serverConvert(client_enc, data, tofree) + char_u *client_enc; + char_u *data; + char_u **tofree; +{ + char_u *res = data; + + *tofree = NULL; +# ifdef FEAT_MBYTE + if (client_enc != NULL && p_enc != NULL) + { + vimconv_T vimconv; + + vimconv.vc_type = CONV_NONE; + if (convert_setup(&vimconv, client_enc, p_enc) != FAIL + && vimconv.vc_type != CONV_NONE) + { + res = string_convert(&vimconv, data, NULL); + if (res == NULL) + res = data; + else + *tofree = res; + } + convert_setup(&vimconv, NULL, NULL); + } +# endif + return res; +} + + +/* + * Make our basic server name: use the specified "arg" if given, otherwise use + * the tail of the command "cmd" we were started with. + * Return the name in allocated memory. This doesn't include a serial number. + */ + static char_u * +serverMakeName(arg, cmd) + char_u *arg; + char *cmd; +{ + char_u *p; + + if (arg != NULL && *arg != NUL) + p = vim_strsave_up(arg); + else + { + p = vim_strsave_up(gettail((char_u *)cmd)); + /* Remove .exe or .bat from the name. */ + if (p != NULL && vim_strchr(p, '.') != NULL) + *vim_strchr(p, '.') = NUL; + } + return p; +} +#endif /* FEAT_CLIENTSERVER */ + +/* + * When FEAT_FKMAP is defined, also compile the Farsi source code. + */ +#if defined(FEAT_FKMAP) || defined(PROTO) +# include "farsi.c" +#endif + +/* + * When FEAT_ARABIC is defined, also compile the Arabic source code. + */ +#if defined(FEAT_ARABIC) || defined(PROTO) +# include "arabic.c" +#endif 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-09-07 07:42:17.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-09-07 07:42:17.000000000 +0000 @@ -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-09-07 07:42:17.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); @@ -4786,7 +4824,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 +5589,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 +5623,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 +5641,8 @@ --lnum; } - s = cin_skipcomment(ml_get(lnum)); + line = ml_get(lnum); + s = cin_skipcomment(line); for (;;) { if (*s == NUL) @@ -5610,7 +5650,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 +7122,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 +7713,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 +8639,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 +8940,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; } 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-09-07 07:42:17.000000000 +0000 @@ -889,6 +889,11 @@ ++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') { /* @@ -3755,7 +3760,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()) @@ -6379,7 +6385,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 +6668,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 +6701,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 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-09-07 07:42:14.000000000 +0000 @@ -3404,7 +3404,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-09-07 07:42:17.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; } } @@ -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 */ @@ -8219,6 +8228,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 +8539,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 +8648,7 @@ } } } + } return OK; } @@ -10585,6 +10621,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 +10636,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 +10656,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-09-07 07:42:17.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-09-07 07:42:15.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-09-07 07:42:17.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-09-07 07:42:17.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-09-07 07:42:14.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)); 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-09-07 07:42:17.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-09-07 07:42:17.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/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-09-07 07:42:17.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-09-07 07:42:16.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-09-07 07:42:16.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-09-07 07:42:14.000000000 +0000 @@ -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 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-09-07 07:42:17.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-09-07 07:42:17.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 { @@ -2542,7 +2555,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 +2639,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 +3090,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 +3146,8 @@ area_highlighting = TRUE; } } + if (shl != &search_hl && cur != NULL) + cur = cur->next; } #endif @@ -3163,10 +3189,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 +3206,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 +3413,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 +3478,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 +3549,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 +3666,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; @@ -3752,10 +3809,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 +4309,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 +4372,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 +4542,8 @@ { if (mb_utf8) { + int i; + ScreenLinesUC[off] = mb_c; if ((c & 0xff) == 0) ScreenLines[off] = 0x80; /* avoid storing zero */ @@ -4548,7 +4632,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 +4709,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 +4875,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 +4905,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 +4943,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 +5020,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 +5029,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 +5049,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 +5192,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 +5382,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 +5448,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 +6200,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 +6217,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 @@ -6241,19 +6343,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 +6420,7 @@ #ifdef FEAT_SEARCH_EXTRA /* - * Prepare for 'searchhl' highlighting. + * Prepare for 'hlsearch' highlighting. */ static void start_search_hl() @@ -6331,7 +6433,7 @@ } /* - * Clean up for 'searchhl' highlighting. + * Clean up for 'hlsearch' highlighting. */ static void end_search_hl() @@ -6351,18 +6453,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 +6509,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 +6525,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 +6593,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 +6941,9 @@ { int r, c; int off; +#ifdef FEAT_MBYTE + int max_off; +#endif /* Can't use ScreenLines unless initialized */ if (ScreenLines == NULL) @@ -6837,10 +6954,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 +6970,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-09-07 07:42:17.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-09-07 07:42:17.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-09-07 07:42:17.000000000 +0000 @@ -1453,6 +1453,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 +1695,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 +1970,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-09-07 07:42:17.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 @@ -4460,8 +4491,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 +5987,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 +5999,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 +6037,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 +8533,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 +9003,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 +9021,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 +9030,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 +9039,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 +9099,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/termlib.c vim71/src/termlib.c --- vim71.orig/src/termlib.c 2007-05-07 19:39:49.000000000 +0000 +++ vim71/src/termlib.c 2007-09-07 07:42:17.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-09-07 07:42:17.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 --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 @@ -38,7 +43,7 @@ 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; \ 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-09-07 07:42:16.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 succesfull 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 succesfull 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 succesfull 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-09-07 07:42:16.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-09-07 07:42:17.000000000 +0000 @@ -0,0 +1,52 @@ +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 +: endif +:endfor +:/^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-09-07 07:42:17.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-09-07 07:42:17.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/version.c vim71/src/version.c --- vim71.orig/src/version.c 2007-05-12 10:23:44.000000000 +0000 +++ vim71/src/version.c 2007-09-07 07:42:17.000000000 +0000 @@ -667,6 +667,186 @@ static int included_patches[] = { /* Add new patch number below this line */ /**/ + 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-09-07 07:42:17.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-09-07 07:42:15.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-09-07 07:42:17.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)); @@ -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; + } + } } /* @@ -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 @@ -4128,6 +4209,10 @@ #ifdef FEAT_AUTOCMD --autocmd_block; #endif +#ifdef FEAT_SEARCH_EXTRA + newwin->w_match_head = NULL; + newwin->w_next_match_id = 4; +#endif } return newwin; } @@ -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 @@ -6174,3 +6259,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