diff options
author | Bram Moolenaar <Bram@vim.org> | 2006-02-14 22:29:30 +0000 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2006-02-14 22:29:30 +0000 |
commit | 1d2ba7fa851f988ea9eab47b7662be243f85ddfa (patch) | |
tree | 5882ec62c5c5c6047021a94e74e4797139944a95 /src | |
parent | f52c725c4739f2d3368029d67218d6cae0d87995 (diff) | |
download | vim-git-1d2ba7fa851f988ea9eab47b7662be243f85ddfa.tar.gz |
updated for version 7.0197v7.0197
Diffstat (limited to 'src')
-rw-r--r-- | src/buffer.c | 10 | ||||
-rw-r--r-- | src/edit.c | 679 | ||||
-rw-r--r-- | src/eval.c | 164 | ||||
-rw-r--r-- | src/ex_cmds.h | 10 | ||||
-rw-r--r-- | src/ex_docmd.c | 247 | ||||
-rw-r--r-- | src/globals.h | 10 | ||||
-rw-r--r-- | src/gui.h | 2 | ||||
-rw-r--r-- | src/gui_beval.c | 5 | ||||
-rw-r--r-- | src/if_mzsch.c | 2 | ||||
-rw-r--r-- | src/main.c | 13 | ||||
-rw-r--r-- | src/netbeans.c | 2 | ||||
-rw-r--r-- | src/normal.c | 13 | ||||
-rw-r--r-- | src/ops.c | 43 | ||||
-rw-r--r-- | src/option.c | 26 | ||||
-rw-r--r-- | src/proto/eval.pro | 2 | ||||
-rw-r--r-- | src/proto/ex_docmd.pro | 2 | ||||
-rw-r--r-- | src/proto/ops.pro | 2 | ||||
-rw-r--r-- | src/proto/window.pro | 7 | ||||
-rw-r--r-- | src/screen.c | 87 | ||||
-rw-r--r-- | src/search.c | 4 | ||||
-rw-r--r-- | src/structs.h | 30 | ||||
-rw-r--r-- | src/syntax.c | 3 | ||||
-rw-r--r-- | src/term.c | 4 | ||||
-rw-r--r-- | src/ui.c | 1 | ||||
-rw-r--r-- | src/version.h | 4 | ||||
-rw-r--r-- | src/vim.h | 5 | ||||
-rw-r--r-- | src/window.c | 322 |
27 files changed, 1271 insertions, 428 deletions
diff --git a/src/buffer.c b/src/buffer.c index 6d654b26a..eb8799c58 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1700,6 +1700,9 @@ free_buf_options(buf, free_p_ff) clear_string_option(&buf->b_p_inde); clear_string_option(&buf->b_p_indk); #endif +#if defined(FEAT_EVAL) + clear_string_option(&buf->b_p_fex); +#endif #ifdef FEAT_CRYPT clear_string_option(&buf->b_p_key); #endif @@ -2840,9 +2843,12 @@ buf_same_ino(buf, stp) } #endif +/* + * Print info about the current buffer. + */ void fileinfo(fullname, shorthelp, dont_truncate) - int fullname; + int fullname; /* when non-zero print full path */ int shorthelp; int dont_truncate; { @@ -3476,7 +3482,7 @@ build_stl_str_hl(wp, out, outlen, fmt, fillchar, maxwidth, hl) else { t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname - : wp->w_buffer->b_fname; + : wp->w_buffer->b_fname; home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE); } trans_characters(NameBuff, MAXPATHL); diff --git a/src/edit.c b/src/edit.c index 18a1cf15e..9224c5897 100644 --- a/src/edit.c +++ b/src/edit.c @@ -130,6 +130,7 @@ static void ins_compl_del_pum __ARGS((void)); static int pum_wanted __ARGS((void)); static int pum_two_or_more __ARGS((void)); static void ins_compl_dictionaries __ARGS((char_u *dict, char_u *pat, int flags, int thesaurus)); +static char_u *find_line_end __ARGS((char_u *ptr)); static void ins_compl_free __ARGS((void)); static void ins_compl_clear __ARGS((void)); static int ins_compl_bs __ARGS((void)); @@ -157,6 +158,7 @@ static void ins_redraw __ARGS((int ready)); static void ins_ctrl_v __ARGS((void)); static void undisplay_dollar __ARGS((void)); static void insert_special __ARGS((int, int, int)); +static void internal_format __ARGS((int textwidth, int second_indent, int flags, int format_only)); static void check_auto_format __ARGS((int)); static void redo_literal __ARGS((int c)); static void start_arrow __ARGS((pos_T *end_insert_pos)); @@ -2184,13 +2186,13 @@ ins_compl_longest_match(match) if (has_mbyte) { l = mb_ptr2len(p); - if (STRNCMP(p, s, l) != 0) + if (STRNICMP(p, s, l) != 0) break; } else #endif { - if (*p != *s) + if (MB_TOLOWER(*p) != MB_TOLOWER(*s)) break; l = 1; } @@ -2471,7 +2473,7 @@ ins_compl_show_pum() ins_compl_dictionaries(dict, pat, flags, thesaurus) char_u *dict; char_u *pat; - int flags; + int flags; /* DICT_FIRST and/or DICT_EXACT */ int thesaurus; { char_u *ptr; @@ -2490,7 +2492,23 @@ ins_compl_dictionaries(dict, pat, flags, thesaurus) save_p_scs = p_scs; if (curbuf->b_p_inf) p_scs = FALSE; - regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0); + + /* When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern + * to only match at the start of a line. Otherwise just match the + * pattern. */ + if (ctrl_x_mode == CTRL_X_WHOLE_LINE) + { + i = STRLEN(pat) + 8; + ptr = alloc(i); + if (ptr == NULL) + return; + vim_snprintf((char *)ptr, i, "^\\s*\\zs%s", pat); + regmatch.regprog = vim_regcomp(ptr, p_magic ? RE_MAGIC : 0); + vim_free(ptr); + } + else + regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0); + /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */ regmatch.rm_ic = ignorecase(pat); while (buf != NULL && regmatch.regprog != NULL && *dict != NUL @@ -2537,7 +2555,10 @@ ins_compl_dictionaries(dict, pat, flags, thesaurus) while (vim_regexec(®match, buf, (colnr_T)(ptr - buf))) { ptr = regmatch.startp[0]; - ptr = find_word_end(ptr); + if (ctrl_x_mode == CTRL_X_WHOLE_LINE) + ptr = find_line_end(ptr); + else + ptr = find_word_end(ptr); add_r = ins_compl_add_infercase(regmatch.startp[0], (int)(ptr - regmatch.startp[0]), files[i], dir, 0); @@ -2653,6 +2674,22 @@ find_word_end(ptr) } /* + * Find the end of the line, omitting CR and NL at the end. + * Returns a pointer to just after the line. + */ + static char_u * +find_line_end(ptr) + char_u *ptr; +{ + char_u *s; + + s = ptr + STRLEN(ptr); + while (s > ptr && (s[-1] == CAR || s[-1] == NL)) + --s; + return s; +} + +/* * Free the list of completions */ static void @@ -3102,9 +3139,7 @@ ins_compl_next_buf(buf, flag) ? buf->b_p_bl : (!buf->b_p_bl || (buf->b_ml.ml_mfp == NULL) != (flag == 'u'))) - || buf->b_scanned - || (buf->b_ml.ml_mfp == NULL - && ctrl_x_mode == CTRL_X_WHOLE_LINE))) + || buf->b_scanned)) ; return buf; } @@ -3176,8 +3211,8 @@ expand_by_function(type, base) * Get the next expansion(s), using "compl_pattern". * The search starts at position "ini" in curbuf and in the direction * compl_direction. - * When "compl_started" is FALSE start at that position, otherwise - * continue where we stopped searching before. + * When "compl_started" is FALSE start at that position, otherwise continue + * where we stopped searching before. * This may return before finding all the matches. * Return the total number of matches or -1 if still unknown -- Acevedo */ @@ -3432,7 +3467,7 @@ ins_compl_get_exp(ini) RE_LAST); if (!compl_started) { - /* set compl_started even on fail */ + /* set "compl_started" even on fail */ compl_started = TRUE; first_match_pos = *pos; last_match_pos = *pos; @@ -4242,8 +4277,7 @@ ins_complete(c) /* * Find next match (and following matches). */ - n = ins_compl_next(TRUE, ins_compl_key2count(c), - c != K_UP && c != K_DOWN); + n = ins_compl_next(TRUE, ins_compl_key2count(c), c != K_UP && c != K_DOWN); /* may undisplay the popup menu */ ins_compl_upd_pum(); @@ -4671,29 +4705,14 @@ insertchar(c, flags, second_indent) int flags; /* INSCHAR_FORMAT, etc. */ int second_indent; /* indent for second line if >= 0 */ { - int haveto_redraw = FALSE; int textwidth; #ifdef FEAT_COMMENTS - colnr_T leader_len; char_u *p; - int no_leader = FALSE; - int do_comments = (flags & INSCHAR_DO_COM); #endif - int fo_white_par; - int first_line = TRUE; int fo_ins_blank; -#ifdef FEAT_MBYTE - int fo_multibyte; -#endif - int save_char = NUL; - int cc; textwidth = comp_textwidth(flags & INSCHAR_FORMAT); fo_ins_blank = has_format_option(FO_INS_BLANK); -#ifdef FEAT_MBYTE - fo_multibyte = has_format_option(FO_MBYTE_BREAK); -#endif - fo_white_par = has_format_option(FO_WHITE_PAR); /* * Try to break the line in two or more pieces when: @@ -4710,7 +4729,7 @@ insertchar(c, flags, second_indent) * - 'formatoptions' doesn't have 'b' or a blank was inserted at or * before 'textwidth' */ - if (textwidth + if (textwidth > 0 && ((flags & INSCHAR_FORMAT) || (!vim_iswhite(c) && !((State & REPLACE_FLAG) @@ -4725,288 +4744,15 @@ insertchar(c, flags, second_indent) || Insstart_blank_vcol <= (colnr_T)textwidth )))))) { - /* - * When 'ai' is off we don't want a space under the cursor to be - * deleted. Replace it with an 'x' temporarily. - */ - if (!curbuf->b_p_ai) - { - cc = gchar_cursor(); - if (vim_iswhite(cc)) - { - save_char = cc; - pchar_cursor('x'); - } - } - - /* - * Repeat breaking lines, until the current line is not too long. - */ - while (!got_int) - { - int startcol; /* Cursor column at entry */ - int wantcol; /* column at textwidth border */ - int foundcol; /* column for start of spaces */ - int end_foundcol = 0; /* column for start of word */ - colnr_T len; - colnr_T virtcol; -#ifdef FEAT_VREPLACE - int orig_col = 0; - char_u *saved_text = NULL; -#endif - colnr_T col; - - virtcol = get_nolist_virtcol(); - if (virtcol < (colnr_T)textwidth) - break; - -#ifdef FEAT_COMMENTS - if (no_leader) - do_comments = FALSE; - else if (!(flags & INSCHAR_FORMAT) - && has_format_option(FO_WRAP_COMS)) - do_comments = TRUE; - - /* Don't break until after the comment leader */ - if (do_comments) - leader_len = get_leader_len(ml_get_curline(), NULL, FALSE); - else - leader_len = 0; - - /* If the line doesn't start with a comment leader, then don't - * start one in a following broken line. Avoids that a %word - * moved to the start of the next line causes all following lines - * to start with %. */ - if (leader_len == 0) - no_leader = TRUE; -#endif - if (!(flags & INSCHAR_FORMAT) -#ifdef FEAT_COMMENTS - && leader_len == 0 -#endif - && !has_format_option(FO_WRAP)) - - { - textwidth = 0; - break; - } - if ((startcol = curwin->w_cursor.col) == 0) - break; - - /* find column of textwidth border */ - coladvance((colnr_T)textwidth); - wantcol = curwin->w_cursor.col; - - curwin->w_cursor.col = startcol - 1; -#ifdef FEAT_MBYTE - /* Correct cursor for multi-byte character. */ - if (has_mbyte) - mb_adjust_cursor(); -#endif - foundcol = 0; - - /* - * Find position to break at. - * Stop at first entered white when 'formatoptions' has 'v' - */ - while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) - || curwin->w_cursor.lnum != Insstart.lnum - || curwin->w_cursor.col >= Insstart.col) - { - cc = gchar_cursor(); - if (WHITECHAR(cc)) - { - /* remember position of blank just before text */ - end_foundcol = curwin->w_cursor.col; - - /* find start of sequence of blanks */ - while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) - { - dec_cursor(); - cc = gchar_cursor(); - } - if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) - break; /* only spaces in front of text */ -#ifdef FEAT_COMMENTS - /* Don't break until after the comment leader */ - if (curwin->w_cursor.col < leader_len) - break; -#endif - if (has_format_option(FO_ONE_LETTER)) - { - /* do not break after one-letter words */ - if (curwin->w_cursor.col == 0) - break; /* one-letter word at begin */ - - col = curwin->w_cursor.col; - dec_cursor(); - cc = gchar_cursor(); - - if (WHITECHAR(cc)) - continue; /* one-letter, continue */ - curwin->w_cursor.col = col; - } -#ifdef FEAT_MBYTE - if (has_mbyte) - foundcol = curwin->w_cursor.col - + (*mb_ptr2len)(ml_get_cursor()); - else -#endif - foundcol = curwin->w_cursor.col + 1; - if (curwin->w_cursor.col < (colnr_T)wantcol) - break; - } -#ifdef FEAT_MBYTE - else if (cc >= 0x100 && fo_multibyte - && curwin->w_cursor.col <= (colnr_T)wantcol) - { - /* Break after or before a multi-byte character. */ - foundcol = curwin->w_cursor.col; - if (curwin->w_cursor.col < (colnr_T)wantcol) - foundcol += (*mb_char2len)(cc); - end_foundcol = foundcol; - break; - } -#endif - if (curwin->w_cursor.col == 0) - break; - dec_cursor(); - } - - if (foundcol == 0) /* no spaces, cannot break line */ - { - curwin->w_cursor.col = startcol; - break; - } - - /* Going to break the line, remove any "$" now. */ - undisplay_dollar(); - - /* - * Offset between cursor position and line break is used by replace - * stack functions. VREPLACE does not use this, and backspaces - * over the text instead. - */ -#ifdef FEAT_VREPLACE - if (State & VREPLACE_FLAG) - orig_col = startcol; /* Will start backspacing from here */ - else -#endif - replace_offset = startcol - end_foundcol - 1; - - /* - * adjust startcol for spaces that will be deleted and - * characters that will remain on top line - */ - curwin->w_cursor.col = foundcol; - while (cc = gchar_cursor(), WHITECHAR(cc)) - inc_cursor(); - startcol -= curwin->w_cursor.col; - if (startcol < 0) - startcol = 0; - -#ifdef FEAT_VREPLACE - if (State & VREPLACE_FLAG) - { - /* - * In VREPLACE mode, we will backspace over the text to be - * wrapped, so save a copy now to put on the next line. - */ - saved_text = vim_strsave(ml_get_cursor()); - curwin->w_cursor.col = orig_col; - if (saved_text == NULL) - break; /* Can't do it, out of memory */ - saved_text[startcol] = NUL; - - /* Backspace over characters that will move to the next line */ - if (!fo_white_par) - backspace_until_column(foundcol); - } - else + /* Format with 'formatexpr' when it's set. Use internal formatting + * when 'formatexpr' isn't set or it returns non-zero. */ +#if defined(FEAT_EVAL) + if (*curbuf->b_p_fex == NUL + || fex_format(curwin->w_cursor.lnum, 1L) != 0) #endif - { - /* put cursor after pos. to break line */ - if (!fo_white_par) - curwin->w_cursor.col = foundcol; - } - - /* - * Split the line just before the margin. - * Only insert/delete lines, but don't really redraw the window. - */ - open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX - + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) -#ifdef FEAT_COMMENTS - + (do_comments ? OPENLINE_DO_COM : 0) -#endif - , old_indent); - old_indent = 0; - - replace_offset = 0; - if (first_line) - { - if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) - second_indent = get_number_indent(curwin->w_cursor.lnum -1); - if (second_indent >= 0) - { -#ifdef FEAT_VREPLACE - if (State & VREPLACE_FLAG) - change_indent(INDENT_SET, second_indent, FALSE, NUL); - else -#endif - (void)set_indent(second_indent, SIN_CHANGED); - } - first_line = FALSE; - } - -#ifdef FEAT_VREPLACE - if (State & VREPLACE_FLAG) - { - /* - * In VREPLACE mode we have backspaced over the text to be - * moved, now we re-insert it into the new line. - */ - ins_bytes(saved_text); - vim_free(saved_text); - } - else -#endif - { - /* - * Check if cursor is not past the NUL off the line, cindent - * may have added or removed indent. - */ - curwin->w_cursor.col += startcol; - len = (colnr_T)STRLEN(ml_get_curline()); - if (curwin->w_cursor.col > len) - curwin->w_cursor.col = len; - } - - haveto_redraw = TRUE; -#ifdef FEAT_CINDENT - can_cindent = TRUE; -#endif - /* moved the cursor, don't autoindent or cindent now */ - did_ai = FALSE; -#ifdef FEAT_SMARTINDENT - did_si = FALSE; - can_si = FALSE; - can_si_back = FALSE; -#endif - line_breakcheck(); - } - - if (save_char) /* put back space after cursor */ - pchar_cursor(save_char); - - if (c == NUL) /* formatting only */ - return; - if (haveto_redraw) - { - update_topline(); - redraw_curbuf_later(VALID); - } + internal_format(textwidth, second_indent, flags, c == NUL); } + if (c == NUL) /* only formatting was wanted */ return; @@ -5104,7 +4850,7 @@ insertchar(c, flags, second_indent) buf[0] = c; i = 1; - if (textwidth) + if (textwidth > 0) virtcol = get_nolist_virtcol(); /* * Stop the string when: @@ -5157,6 +4903,8 @@ insertchar(c, flags, second_indent) else { #ifdef FEAT_MBYTE + int cc; + if (has_mbyte && (cc = (*mb_char2len)(c)) > 1) { char_u buf[MB_MAXBYTES + 1]; @@ -5179,6 +4927,312 @@ insertchar(c, flags, second_indent) } /* + * Format text at the current insert position. + */ + static void +internal_format(textwidth, second_indent, flags, format_only) + int textwidth; + int second_indent; + int flags; + int format_only; +{ + int cc; + int save_char = NUL; + int haveto_redraw = FALSE; + int fo_ins_blank = has_format_option(FO_INS_BLANK); +#ifdef FEAT_MBYTE + int fo_multibyte = has_format_option(FO_MBYTE_BREAK); +#endif + int fo_white_par = has_format_option(FO_WHITE_PAR); + int first_line = TRUE; +#ifdef FEAT_COMMENTS + colnr_T leader_len; + int no_leader = FALSE; + int do_comments = (flags & INSCHAR_DO_COM); +#endif + + /* + * When 'ai' is off we don't want a space under the cursor to be + * deleted. Replace it with an 'x' temporarily. + */ + if (!curbuf->b_p_ai) + { + cc = gchar_cursor(); + if (vim_iswhite(cc)) + { + save_char = cc; + pchar_cursor('x'); + } + } + + /* + * Repeat breaking lines, until the current line is not too long. + */ + while (!got_int) + { + int startcol; /* Cursor column at entry */ + int wantcol; /* column at textwidth border */ + int foundcol; /* column for start of spaces */ + int end_foundcol = 0; /* column for start of word */ + colnr_T len; + colnr_T virtcol; +#ifdef FEAT_VREPLACE + int orig_col = 0; + char_u *saved_text = NULL; +#endif + colnr_T col; + + virtcol = get_nolist_virtcol(); + if (virtcol < (colnr_T)textwidth) + break; + +#ifdef FEAT_COMMENTS + if (no_leader) + do_comments = FALSE; + else if (!(flags & INSCHAR_FORMAT) + && has_format_option(FO_WRAP_COMS)) + do_comments = TRUE; + + /* Don't break until after the comment leader */ + if (do_comments) + leader_len = get_leader_len(ml_get_curline(), NULL, FALSE); + else + leader_len = 0; + + /* If the line doesn't start with a comment leader, then don't + * start one in a following broken line. Avoids that a %word + * moved to the start of the next line causes all following lines + * to start with %. */ + if (leader_len == 0) + no_leader = TRUE; +#endif + if (!(flags & INSCHAR_FORMAT) +#ifdef FEAT_COMMENTS + && leader_len == 0 +#endif + && !has_format_option(FO_WRAP)) + + { + textwidth = 0; + break; + } + if ((startcol = curwin->w_cursor.col) == 0) + break; + + /* find column of textwidth border */ + coladvance((colnr_T)textwidth); + wantcol = curwin->w_cursor.col; + + curwin->w_cursor.col = startcol - 1; +#ifdef FEAT_MBYTE + /* Correct cursor for multi-byte character. */ + if (has_mbyte) + mb_adjust_cursor(); +#endif + foundcol = 0; + + /* + * Find position to break at. + * Stop at first entered white when 'formatoptions' has 'v' + */ + while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) + || curwin->w_cursor.lnum != Insstart.lnum + || curwin->w_cursor.col >= Insstart.col) + { + cc = gchar_cursor(); + if (WHITECHAR(cc)) + { + /* remember position of blank just before text */ + end_foundcol = curwin->w_cursor.col; + + /* find start of sequence of blanks */ + while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) + { + dec_cursor(); + cc = gchar_cursor(); + } + if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) + break; /* only spaces in front of text */ +#ifdef FEAT_COMMENTS + /* Don't break until after the comment leader */ + if (curwin->w_cursor.col < leader_len) + break; +#endif + if (has_format_option(FO_ONE_LETTER)) + { + /* do not break after one-letter words */ + if (curwin->w_cursor.col == 0) + break; /* one-letter word at begin */ + + col = curwin->w_cursor.col; + dec_cursor(); + cc = gchar_cursor(); + + if (WHITECHAR(cc)) + continue; /* one-letter, continue */ + curwin->w_cursor.col = col; + } +#ifdef FEAT_MBYTE + if (has_mbyte) + foundcol = curwin->w_cursor.col + + (*mb_ptr2len)(ml_get_cursor()); + else +#endif + foundcol = curwin->w_cursor.col + 1; + if (curwin->w_cursor.col < (colnr_T)wantcol) + break; + } +#ifdef FEAT_MBYTE + else if (cc >= 0x100 && fo_multibyte + && curwin->w_cursor.col <= (colnr_T)wantcol) + { + /* Break after or before a multi-byte character. */ + foundcol = curwin->w_cursor.col; + if (curwin->w_cursor.col < (colnr_T)wantcol) + foundcol += (*mb_char2len)(cc); + end_foundcol = foundcol; + break; + } +#endif + if (curwin->w_cursor.col == 0) + break; + dec_cursor(); + } + + if (foundcol == 0) /* no spaces, cannot break line */ + { + curwin->w_cursor.col = startcol; + break; + } + + /* Going to break the line, remove any "$" now. */ + undisplay_dollar(); + + /* + * Offset between cursor position and line break is used by replace + * stack functions. VREPLACE does not use this, and backspaces + * over the text instead. + */ +#ifdef FEAT_VREPLACE + if (State & VREPLACE_FLAG) + orig_col = startcol; /* Will start backspacing from here */ + else +#endif + replace_offset = startcol - end_foundcol - 1; + + /* + * adjust startcol for spaces that will be deleted and + * characters that will remain on top line + */ + curwin->w_cursor.col = foundcol; + while (cc = gchar_cursor(), WHITECHAR(cc)) + inc_cursor(); + startcol -= curwin->w_cursor.col; + if (startcol < 0) + startcol = 0; + +#ifdef FEAT_VREPLACE + if (State & VREPLACE_FLAG) + { + /* + * In VREPLACE mode, we will backspace over the text to be + * wrapped, so save a copy now to put on the next line. + */ + saved_text = vim_strsave(ml_get_cursor()); + curwin->w_cursor.col = orig_col; + if (saved_text == NULL) + break; /* Can't do it, out of memory */ + saved_text[startcol] = NUL; + + /* Backspace over characters that will move to the next line */ + if (!fo_white_par) + backspace_until_column(foundcol); + } + else +#endif + { + /* put cursor after pos. to break line */ + if (!fo_white_par) + curwin->w_cursor.col = foundcol; + } + + /* + * Split the line just before the margin. + * Only insert/delete lines, but don't really redraw the window. + */ + open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX + + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) +#ifdef FEAT_COMMENTS + + (do_comments ? OPENLINE_DO_COM : 0) +#endif + , old_indent); + old_indent = 0; + + replace_offset = 0; + if (first_line) + { + if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) + second_indent = get_number_indent(curwin->w_cursor.lnum -1); + if (second_indent >= 0) + { +#ifdef FEAT_VREPLACE + if (State & VREPLACE_FLAG) + change_indent(INDENT_SET, second_indent, FALSE, NUL); + else +#endif + (void)set_indent(second_indent, SIN_CHANGED); + } + first_line = FALSE; + } + +#ifdef FEAT_VREPLACE + if (State & VREPLACE_FLAG) + { + /* + * In VREPLACE mode we have backspaced over the text to be + * moved, now we re-insert it into the new line. + */ + ins_bytes(saved_text); + vim_free(saved_text); + } + else +#endif + { + /* + * Check if cursor is not past the NUL off the line, cindent + * may have added or removed indent. + */ + curwin->w_cursor.col += startcol; + len = (colnr_T)STRLEN(ml_get_curline()); + if (curwin->w_cursor.col > len) + curwin->w_cursor.col = len; + } + + haveto_redraw = TRUE; +#ifdef FEAT_CINDENT + can_cindent = TRUE; +#endif + /* moved the cursor, don't autoindent or cindent now */ + did_ai = FALSE; +#ifdef FEAT_SMARTINDENT + did_si = FALSE; + can_si = FALSE; + can_si_back = FALSE; +#endif + line_breakcheck(); + } + + if (save_char != NUL) /* put back space after cursor */ + pchar_cursor(save_char); + + if (!format_only && haveto_redraw) + { + update_topline(); + redraw_curbuf_later(VALID); + } +} + +/* * Called after inserting or deleting text: When 'formatoptions' includes the * 'a' flag format from the current line until the end of the paragraph. * Keep the cursor at the same position relative to the text. @@ -7254,7 +7308,10 @@ ins_insert(replaceState) # ifdef FEAT_EVAL set_vim_var_string(VV_INSERTMODE, (char_u *)((State & REPLACE_FLAG) ? "i" : - replaceState == VREPLACE ? "v" : "r"), 1); +# ifdef FEAT_VREPLACE + replaceState == VREPLACE ? "v" : +# endif + "r"), 1); # endif apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, FALSE, curbuf); #endif diff --git a/src/eval.c b/src/eval.c index 50f688a76..6ec0975d7 100644 --- a/src/eval.c +++ b/src/eval.c @@ -573,6 +573,7 @@ static void f_nextnonblank __ARGS((typval_T *argvars, typval_T *rettv)); static void f_nr2char __ARGS((typval_T *argvars, typval_T *rettv)); static void f_prevnonblank __ARGS((typval_T *argvars, typval_T *rettv)); static void f_printf __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_pumvisible __ARGS((typval_T *argvars, typval_T *rettv)); static void f_range __ARGS((typval_T *argvars, typval_T *rettv)); static void f_readfile __ARGS((typval_T *argvars, typval_T *rettv)); static void f_remote_expr __ARGS((typval_T *argvars, typval_T *rettv)); @@ -588,6 +589,8 @@ static void f_reverse __ARGS((typval_T *argvars, typval_T *rettv)); static void f_search __ARGS((typval_T *argvars, typval_T *rettv)); static void f_searchdecl __ARGS((typval_T *argvars, typval_T *rettv)); static void f_searchpair __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_searchpairpos __ARGS((typval_T *argvars, typval_T *rettv)); +static void f_searchpos __ARGS((typval_T *argvars, typval_T *rettv)); static void f_server2client __ARGS((typval_T *argvars, typval_T *rettv)); static void f_serverlist __ARGS((typval_T *argvars, typval_T *rettv)); static void f_setbufvar __ARGS((typval_T *argvars, typval_T *rettv)); @@ -704,6 +707,8 @@ static void func_ref __ARGS((char_u *name)); static void call_user_func __ARGS((ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, linenr_T firstline, linenr_T lastline, dict_T *selfdict)); static void add_nr_var __ARGS((dict_T *dp, dictitem_T *v, char *name, varnumber_T nr)); static win_T *find_win_by_nr __ARGS((typval_T *vp)); +static int searchpair_cmn __ARGS((typval_T *argvars, pos_T *match_pos)); +static int search_cmn __ARGS((typval_T *argvars, pos_T *match_pos)); /* Character used as separated in autoload function/variable names. */ #define AUTOLOAD_CHAR '#' @@ -6930,6 +6935,7 @@ static struct fst {"nr2char", 1, 1, f_nr2char}, {"prevnonblank", 1, 1, f_prevnonblank}, {"printf", 2, 19, f_printf}, + {"pumvisible", 0, 0, f_pumvisible}, {"range", 1, 3, f_range}, {"readfile", 1, 3, f_readfile}, {"remote_expr", 2, 3, f_remote_expr}, @@ -6945,6 +6951,8 @@ static struct fst {"search", 1, 2, f_search}, {"searchdecl", 1, 3, f_searchdecl}, {"searchpair", 3, 5, f_searchpair}, + {"searchpairpos", 3, 5, f_searchpairpos}, + {"searchpos", 1, 2, f_searchpos}, {"server2client", 2, 2, f_server2client}, {"serverlist", 0, 0, f_serverlist}, {"setbufvar", 3, 3, f_setbufvar}, @@ -12214,6 +12222,22 @@ f_printf(argvars, rettv) } /* + * "pumvisible()" function + */ +/*ARGSUSED*/ + static void +f_pumvisible(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + rettv->vval.v_number = 0; +#ifdef FEAT_INS_EXPAND + if (pum_visible()) + rettv->vval.v_number = 1; +#endif +} + +/* * "range()" function */ static void @@ -13135,12 +13159,12 @@ get_search_arg(varp, flagsp) } /* - * "search()" function + * Shared by search() and searchpos() functions */ - static void -f_search(argvars, rettv) + static int +search_cmn(argvars, match_pos) typval_T *argvars; - typval_T *rettv; + pos_T *match_pos; { char_u *pat; pos_T pos; @@ -13148,8 +13172,7 @@ f_search(argvars, rettv) int save_p_ws = p_ws; int dir; int flags = 0; - - rettv->vval.v_number = 0; /* default: FAIL */ + int retval = 0; /* default: FAIL */ pat = get_tv_string(&argvars[0]); dir = get_search_arg(&argvars[1], &flags); /* may set p_ws */ @@ -13172,10 +13195,16 @@ f_search(argvars, rettv) if (searchit(curwin, curbuf, &pos, dir, pat, 1L, SEARCH_KEEP, RE_SEARCH) != FAIL) { - rettv->vval.v_number = pos.lnum; + retval = pos.lnum; if (flags & SP_SETPCMARK) setpcmark(); curwin->w_cursor = pos; + if (match_pos != NULL) + { + /* Store the match cursor position */ + match_pos->lnum = pos.lnum; + match_pos->col = pos.col + 1; + } /* "/$" will put the cursor after the end of the line, may need to * correct that here */ check_cursor(); @@ -13186,6 +13215,19 @@ f_search(argvars, rettv) curwin->w_cursor = save_cursor; theend: p_ws = save_p_ws; + + return retval; +} + +/* + * "search()" function + */ + static void +f_search(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + rettv->vval.v_number = search_cmn(argvars, NULL); } /* @@ -13216,12 +13258,12 @@ f_searchdecl(argvars, rettv) } /* - * "searchpair()" function + * Used by searchpair() and searchpairpos() */ - static void -f_searchpair(argvars, rettv) + static int +searchpair_cmn(argvars, match_pos) typval_T *argvars; - typval_T *rettv; + pos_T *match_pos; { char_u *spat, *mpat, *epat; char_u *skip; @@ -13231,8 +13273,7 @@ f_searchpair(argvars, rettv) char_u nbuf1[NUMBUFLEN]; char_u nbuf2[NUMBUFLEN]; char_u nbuf3[NUMBUFLEN]; - - rettv->vval.v_number = 0; /* default: FAIL */ + int retval = 0; /* default: FAIL */ /* Get the three pattern arguments: start, middle, end. */ spat = get_tv_string_chk(&argvars[0]); @@ -13254,7 +13295,7 @@ f_searchpair(argvars, rettv) goto theend; } - /* Optional fifth argument: skip expresion */ + /* Optional fifth argument: skip expression */ if (argvars[3].v_type == VAR_UNKNOWN || argvars[4].v_type == VAR_UNKNOWN) skip = (char_u *)""; @@ -13263,10 +13304,55 @@ f_searchpair(argvars, rettv) if (skip == NULL) goto theend; /* type error */ - rettv->vval.v_number = do_searchpair(spat, mpat, epat, dir, skip, flags); + retval = do_searchpair(spat, mpat, epat, dir, skip, flags, match_pos); theend: p_ws = save_p_ws; + + return retval; +} + +/* + * "searchpair()" function + */ + static void +f_searchpair(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + rettv->vval.v_number = searchpair_cmn(argvars, NULL); +} + +/* + * "searchpairpos()" function + */ + static void +f_searchpairpos(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + list_T *l; + pos_T match_pos; + int lnum = 0; + int col = 0; + + rettv->vval.v_number = 0; + + l = list_alloc(); + if (l == NULL) + return; + rettv->v_type = VAR_LIST; + rettv->vval.v_list = l; + ++l->lv_refcount; + + if (searchpair_cmn(argvars, &match_pos) > 0) + { + lnum = match_pos.lnum; + col = match_pos.col; + } + + list_append_number(l, (varnumber_T)lnum); + list_append_number(l, (varnumber_T)col); } /* @@ -13275,13 +13361,14 @@ theend: * Returns 0 or -1 for no match, */ long -do_searchpair(spat, mpat, epat, dir, skip, flags) +do_searchpair(spat, mpat, epat, dir, skip, flags, match_pos) char_u *spat; /* start pattern */ char_u *mpat; /* middle pattern */ char_u *epat; /* end pattern */ int dir; /* BACKWARD or FORWARD */ char_u *skip; /* skip expression */ int flags; /* SP_RETCOUNT, SP_REPEAT, SP_NOMOVE */ + pos_T *match_pos; { char_u *save_cpo; char_u *pat, *pat2 = NULL, *pat3 = NULL; @@ -13389,6 +13476,13 @@ do_searchpair(spat, mpat, epat, dir, skip, flags) } } + if (match_pos != NULL) + { + /* Store the match cursor position */ + match_pos->lnum = curwin->w_cursor.lnum; + match_pos->col = curwin->w_cursor.col + 1; + } + /* If 'n' flag is used or search failed: restore cursor position. */ if ((flags & SP_NOMOVE) || retval == 0) curwin->w_cursor = save_cursor; @@ -13401,6 +13495,40 @@ theend: return retval; } +/* + * "searchpos()" function + */ + static void +f_searchpos(argvars, rettv) + typval_T *argvars; + typval_T *rettv; +{ + list_T *l; + pos_T match_pos; + int lnum = 0; + int col = 0; + + rettv->vval.v_number = 0; + + l = list_alloc(); + if (l == NULL) + return; + rettv->v_type = VAR_LIST; + rettv->vval.v_list = l; + ++l->lv_refcount; + + if (search_cmn(argvars, &match_pos) > 0) + { + lnum = match_pos.lnum; + col = match_pos.col; + } + + list_append_number(l, (varnumber_T)lnum); + list_append_number(l, (varnumber_T)col); + +} + + /*ARGSUSED*/ static void f_server2client(argvars, rettv) @@ -14027,11 +14155,9 @@ f_spellbadword(argvars, rettv) typval_T *rettv; { char_u *word = (char_u *)""; -#ifdef FEAT_SYN_HL - int len = 0; hlf_T attr = HLF_COUNT; + int len = 0; list_T *l; -#endif l = list_alloc(); if (l == NULL) diff --git a/src/ex_cmds.h b/src/ex_cmds.h index ca3bed0c3..6571ccef3 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -877,6 +877,16 @@ EX(CMD_tag, "tag", ex_tag, RANGE|NOTADR|BANG|WORD1|TRLBAR|ZEROR), EX(CMD_tags, "tags", do_tags, TRLBAR|CMDWIN), +EX(CMD_tab, "tab", ex_tab, + RANGE|NOTADR|COUNT|TRLBAR), +EX(CMD_tabclose, "tabclose", ex_tabclose, + BANG|TRLBAR|CMDWIN), +EX(CMD_tabedit, "tabedit", ex_tabedit, + BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), +EX(CMD_tabfind, "tabfind", ex_tabedit, + BANG|FILE1|RANGE|NOTADR|EDITCMD|ARGOPT|TRLBAR), +EX(CMD_tabs, "tabs", ex_tabs, + TRLBAR|CMDWIN), EX(CMD_tcl, "tcl", ex_tcl, RANGE|EXTRA|NEEDARG|CMDWIN), EX(CMD_tcldo, "tcldo", ex_tcldo, diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 098f42ca8..e87bb6f6f 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -148,11 +148,13 @@ static void ex_cquit __ARGS((exarg_T *eap)); static void ex_quit_all __ARGS((exarg_T *eap)); #ifdef FEAT_WINDOWS static void ex_close __ARGS((exarg_T *eap)); -static void ex_win_close __ARGS((exarg_T *eap, win_T *win)); +static void ex_win_close __ARGS((int forceit, win_T *win)); static void ex_only __ARGS((exarg_T *eap)); static void ex_all __ARGS((exarg_T *eap)); static void ex_resize __ARGS((exarg_T *eap)); static void ex_stag __ARGS((exarg_T *eap)); +static void ex_tabclose __ARGS((exarg_T *eap)); +static void ex_tabs __ARGS((exarg_T *eap)); #else # define ex_close ex_ni # define ex_only ex_ni @@ -160,6 +162,10 @@ static void ex_stag __ARGS((exarg_T *eap)); # define ex_resize ex_ni # define ex_splitview ex_ni # define ex_stag ex_ni +# define ex_tabedit ex_ni +# define ex_tab ex_ni +# define ex_tabs ex_ni +# define ex_tabclose ex_ni #endif #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) static void ex_pclose __ARGS((exarg_T *eap)); @@ -6138,19 +6144,38 @@ ex_close(eap) else # endif if (!text_locked()) - ex_win_close(eap, curwin); + ex_win_close(eap->forceit, curwin); } +#ifdef FEAT_QUICKFIX +/* + * ":pclose": Close any preview window. + */ static void -ex_win_close(eap, win) +ex_pclose(eap) exarg_T *eap; +{ + win_T *win; + + for (win = firstwin; win != NULL; win = win->w_next) + if (win->w_p_pvw) + { + ex_win_close(eap->forceit, win); + break; + } +} +#endif + + static void +ex_win_close(forceit, win) + int forceit; win_T *win; { int need_hide; buf_T *buf = win->w_buffer; need_hide = (bufIsChanged(buf) && buf->b_nwindows <= 1); - if (need_hide && !P_HID(buf) && !eap->forceit) + if (need_hide && !P_HID(buf) && !forceit) { #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || cmdmod.confirm) && p_write) @@ -6175,24 +6200,33 @@ ex_win_close(eap, win) win_close(win, !need_hide && !P_HID(buf)); } -#ifdef FEAT_QUICKFIX /* - * ":pclose": Close any preview window. + * ":tabclose": close current tab page, unless it is the last one */ static void -ex_pclose(eap) +ex_tabclose(eap) exarg_T *eap; { - win_T *win; - - for (win = firstwin; win != NULL; win = win->w_next) - if (win->w_p_pvw) +# ifdef FEAT_CMDWIN + if (cmdwin_type != 0) + cmdwin_result = K_IGNORE; + else +# endif + if (!text_locked()) { - ex_win_close(eap, win); - break; + if (first_tabpage->tp_next == NULL) + EMSG(_("E999: Cannot close last tab page")); + else + { + /* First close all the windows but the current one. If that + * worked then close the last window in this tab, that will + * close it. */ + ex_only(eap); + if (lastwin == firstwin) + ex_win_close(eap->forceit, curwin); + } } } -#endif /* * ":only". @@ -6722,41 +6756,41 @@ ex_splitview(eap) exarg_T *eap; { win_T *old_curwin; -#if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) +# if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) char_u *fname = NULL; -#endif -#ifdef FEAT_BROWSE +# endif +# ifdef FEAT_BROWSE int browse_flag = cmdmod.browse; -#endif +# endif -#ifndef FEAT_VERTSPLIT +# ifndef FEAT_VERTSPLIT if (eap->cmdidx == CMD_vsplit || eap->cmdidx == CMD_vnew) { ex_ni(eap); return; } -#endif +# endif old_curwin = curwin; -#ifdef FEAT_GUI +# ifdef FEAT_GUI need_mouse_correct = TRUE; -#endif +# endif -#ifdef FEAT_QUICKFIX +# ifdef FEAT_QUICKFIX /* A ":split" in the quickfix window works like ":new". Don't want two * quickfix windows. */ if (bt_quickfix(curbuf)) { if (eap->cmdidx == CMD_split) eap->cmdidx = CMD_new; -# ifdef FEAT_VERTSPLIT +# ifdef FEAT_VERTSPLIT if (eap->cmdidx == CMD_vsplit) eap->cmdidx = CMD_vnew; -# endif +# endif } -#endif +# endif -#ifdef FEAT_SEARCHPATH +# ifdef FEAT_SEARCHPATH if (eap->cmdidx == CMD_sfind) { fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), @@ -6765,15 +6799,15 @@ ex_splitview(eap) goto theend; eap->arg = fname; } -# ifdef FEAT_BROWSE +# ifdef FEAT_BROWSE else +# endif # endif -#endif -#ifdef FEAT_BROWSE +# ifdef FEAT_BROWSE if (cmdmod.browse -# ifdef FEAT_VERTSPLIT +# ifdef FEAT_VERTSPLIT && eap->cmdidx != CMD_vnew -#endif +# endif && eap->cmdidx != CMD_new) { if ( @@ -6797,36 +6831,165 @@ ex_splitview(eap) } } cmdmod.browse = FALSE; /* Don't browse again in do_ecmd(). */ -#endif +# endif if (win_split(eap->addr_count > 0 ? (int)eap->line2 : 0, *eap->cmd == 'v' ? WSP_VERT : 0) != FAIL) { -#ifdef FEAT_SCROLLBIND +# ifdef FEAT_SCROLLBIND /* Reset 'scrollbind' when editing another file, but keep it when * doing ":split" without arguments. */ if (*eap->arg != NUL -#ifdef FEAT_BROWSE +# ifdef FEAT_BROWSE || cmdmod.browse -#endif +# endif ) curwin->w_p_scb = FALSE; else do_check_scrollbind(FALSE); -#endif +# endif do_exedit(eap, old_curwin); } -#ifdef FEAT_BROWSE +# ifdef FEAT_BROWSE cmdmod.browse = browse_flag; -#endif +# endif -#if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) +# if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) theend: vim_free(fname); -#endif +# endif } -#endif + +/* + * :tabedit [[+command] file] open new Tab page with empty window + * :tabedit [[+command] file] open new Tab page and edit "file" + * :tabfind [[+command] file] open new Tab page and find "file" + */ + void +ex_tabedit(eap) + exarg_T *eap; +{ +# if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) + char_u *fname = NULL; +# endif +# ifdef FEAT_BROWSE + int browse_flag = cmdmod.browse; +# endif + +# ifdef FEAT_GUI + need_mouse_correct = TRUE; +# endif + +# ifdef FEAT_SEARCHPATH + if (eap->cmdidx == CMD_tabfind) + { + fname = find_file_in_path(eap->arg, (int)STRLEN(eap->arg), + FNAME_MESS, TRUE, curbuf->b_ffname); + if (fname == NULL) + goto theend; + eap->arg = fname; + } +# ifdef FEAT_BROWSE + else +# endif +# endif +# ifdef FEAT_BROWSE + if (cmdmod.browse) + { + if ( +# ifdef FEAT_GUI + !gui.in_use && +# endif + au_has_group((char_u *)"FileExplorer")) + { + /* No browsing supported but we do have the file explorer: + * Edit the directory. */ + if (*eap->arg == NUL || !mch_isdir(eap->arg)) + eap->arg = (char_u *)"."; + } + else + { + fname = do_browse(0, (char_u *)_("Edit File in new tab page"), + eap->arg, NULL, NULL, NULL, curbuf); + if (fname == NULL) + goto theend; + eap->arg = fname; + } + } + cmdmod.browse = FALSE; /* Don't browse again in do_ecmd(). */ +# endif + + if (win_new_tabpage() != FAIL) + { +# ifdef FEAT_SCROLLBIND + curwin->w_p_scb = FALSE; +# endif + do_exedit(eap, NULL); + } + +# ifdef FEAT_BROWSE + cmdmod.browse = browse_flag; +# endif + +# if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE) +theend: + vim_free(fname); +# endif +} + +/* + * :tab command + */ + void +ex_tab(eap) + exarg_T *eap; +{ + goto_tabpage((int)eap->line2); +} + +/* + * :tabs command: List tabs and their contents. + */ +/*ARGSUSED*/ + static void +ex_tabs(eap) + exarg_T *eap; +{ + tabpage_T *tp; + win_T *wp; + int tabcount = 1; + + msg_start(); + msg_scroll = TRUE; + for (tp = first_tabpage; tp != NULL && !got_int; tp = tp->tp_next) + { + msg_putchar('\n'); + vim_snprintf((char *)IObuff, IOSIZE, _("Tab page %d"), tabcount++); + msg_outtrans_attr(IObuff, hl_attr(HLF_T)); + out_flush(); /* output one line at a time */ + ui_breakcheck(); + + if (tp->tp_topframe == topframe) + wp = firstwin; + else + wp = tp->tp_firstwin; + for ( ; wp != NULL && !got_int; wp = wp->w_next) + { + msg_puts((char_u *)"\n "); + if (buf_spname(wp->w_buffer) != NULL) + STRCPY(IObuff, buf_spname(wp->w_buffer)); + else + home_replace(wp->w_buffer, wp->w_buffer->b_fname, + IObuff, IOSIZE, TRUE); + msg_outtrans(IObuff); + out_flush(); /* output one line at a time */ + ui_breakcheck(); + } + } +} + +#endif /* FEAT_WINDOWS */ /* * ":mode": Set screen mode. diff --git a/src/globals.h b/src/globals.h index 85aeeb95b..57d7d0922 100644 --- a/src/globals.h +++ b/src/globals.h @@ -488,6 +488,7 @@ EXTERN win_T *prevwin INIT(= NULL); /* previous window */ # define W_NEXT(wp) NULL # define FOR_ALL_WINDOWS(wp) wp = curwin; #endif + EXTERN win_T *curwin; /* currently active window */ /* @@ -496,6 +497,15 @@ EXTERN win_T *curwin; /* currently active window */ */ EXTERN frame_T *topframe; /* top of the window frame tree */ +#ifdef FEAT_WINDOWS +/* + * Tab pages are nothing more than alternative topframes. "first_tabpage" + * points to the first one in the list, "topframe" is the current one. + */ +EXTERN tabpage_T *first_tabpage; +EXTERN int redraw_tabpage INIT(= FALSE); /* redraw tab pages line */ +#endif + /* * All buffers are linked in a list. 'firstbuf' points to the first entry, * 'lastbuf' to the last entry and 'curbuf' to the currently active buffer. @@ -168,7 +168,7 @@ typedef struct GuiScrollbar { long ident; /* Unique identifier for each scrollbar */ - struct window *wp; /* Scrollbar's window, NULL for bottom */ + win_T *wp; /* Scrollbar's window, NULL for bottom */ int type; /* one of SBAR_{LEFT,RIGHT,BOTTOM} */ long value; /* Represents top line number visible */ #ifdef FEAT_GUI_ATHENA diff --git a/src/gui_beval.c b/src/gui_beval.c index bb26497fc..6c628cda6 100644 --- a/src/gui_beval.c +++ b/src/gui_beval.c @@ -609,7 +609,10 @@ key_event(BalloonEval *beval, unsigned keyval, int is_keypress) ? (int)GDK_CONTROL_MASK : 0); break; default: - cancelBalloon(beval); + /* Don't do this for key release, we apparently get these with + * focus changes in some GTK version. */ + if (is_keypress) + cancelBalloon(beval); break; } } diff --git a/src/if_mzsch.c b/src/if_mzsch.c index 940c991fe..4d5bb3223 100644 --- a/src/if_mzsch.c +++ b/src/if_mzsch.c @@ -40,7 +40,7 @@ typedef struct typedef struct { Scheme_Type tag; - struct window *win; + win_T *win; } vim_mz_window; #define INVALID_WINDOW_VALUE ((win_T *)(-1)) diff --git a/src/main.c b/src/main.c index 0b96d16cc..81e41b692 100644 --- a/src/main.c +++ b/src/main.c @@ -297,9 +297,11 @@ main TIME_MSG("window checked"); /* - * Allocate the first window and buffer. Can't do much without it. + * Allocate the first window and buffer. + * Can't do anything without it, exit when it fails. */ - win_alloc_first(); + if (win_alloc_first() == FAIL) + mch_exit(0); init_yank(); /* init yank buffers */ @@ -505,12 +507,7 @@ main if (usingNetbeans) Columns += 2; /* leave room for glyph gutter */ #endif - firstwin->w_height = Rows - p_ch; - topframe->fr_height = Rows - p_ch; -#ifdef FEAT_VERTSPLIT - firstwin->w_width = Columns; - topframe->fr_width = Columns; -#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. */ diff --git a/src/netbeans.c b/src/netbeans.c index a2c57fc98..d183e498e 100644 --- a/src/netbeans.c +++ b/src/netbeans.c @@ -3355,7 +3355,7 @@ get_off_or_lnum(buf_T *buf, char_u **argp) /* - * Convert lnum,col to character offset + * Convert (lnum,col) to byte offset in the file. */ static long pos2off(buf_T *buf, pos_T *pos) diff --git a/src/normal.c b/src/normal.c index 09410f030..d4001b494 100644 --- a/src/normal.c +++ b/src/normal.c @@ -1935,7 +1935,12 @@ do_pending_operator(cap, old_col, gui_yank) break; case OP_FORMAT: - if (*p_fp != NUL) +#if defined(FEAT_EVAL) + if (*curbuf->b_p_fex != NUL) + op_formatexpr(oap); /* use expression */ + else +#endif + if (*p_fp != NUL) op_colon(oap); /* use external command */ else op_format(oap, FALSE); /* use internal function */ @@ -7832,6 +7837,12 @@ nv_g_cmd(cap) break; #endif +#ifdef FEAT_WINDOWS + case 't': + goto_tabpage((int)cap->count0); + break; +#endif + default: clearopbeep(oap); break; @@ -4312,6 +4312,49 @@ op_format(oap, keep_cursor) #endif } +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Implementation of the format operator 'gq' for when using 'formatexpr'. + */ + void +op_formatexpr(oap) + oparg_T *oap; +{ +# ifdef FEAT_VISUAL + if (oap->is_VIsual) + /* When there is no change: need to remove the Visual selection */ + redraw_curbuf_later(INVERTED); +# endif + + (void)fex_format(oap->start.lnum, oap->line_count); +} + + int +fex_format(lnum, count) + linenr_T lnum; + long count; +{ + int use_sandbox = was_set_insecurely((char_u *)"formatexpr"); + int r; + + /* + * Set v:lnum to the first line number and v:count to the number of lines. + */ + set_vim_var_nr(VV_LNUM, lnum); + set_vim_var_nr(VV_COUNT, count); + + /* + * Evaluate the function. + */ + if (use_sandbox) + ++sandbox; + r = eval_to_number(curbuf->b_p_fex); + if (use_sandbox) + --sandbox; + return r; +} +#endif + /* * Format "line_count" lines, starting at the cursor position. * When "line_count" is negative, format until the end of the paragraph. diff --git a/src/option.c b/src/option.c index 62cd0e789..cca91cc5d 100644 --- a/src/option.c +++ b/src/option.c @@ -79,6 +79,7 @@ typedef enum , PV_FDT , PV_FEN , PV_FENC + , PV_FEX , PV_FF , PV_FML , PV_FMR @@ -204,6 +205,9 @@ static char_u *p_inex; static char_u *p_inde; static char_u *p_indk; #endif +#if defined(FEAT_EVAL) +static char_u *p_fex; +#endif static int p_inf; static char_u *p_isk; #ifdef FEAT_CRYPT @@ -974,6 +978,15 @@ static struct vimoption # endif }, #endif + {"formatexpr", "fex", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM, +#if defined(FEAT_EVAL) + (char_u *)&p_fex, PV_FEX, + {(char_u *)"", (char_u *)0L} +#else + (char_u *)NULL, PV_NONE, + {(char_u *)0L, (char_u *)0L} +#endif + }, {"formatoptions","fo", P_STRING|P_ALLOCED|P_VIM|P_FLAGLIST, (char_u *)&p_fo, PV_FO, {(char_u *)DFLT_FO_VI, (char_u *)DFLT_FO_VIM}}, @@ -1129,7 +1142,7 @@ static struct vimoption {(char_u *)FALSE, (char_u *)0L}}, {"highlight", "hl", P_STRING|P_VI_DEF|P_RCLR|P_COMMA|P_NODUP, (char_u *)&p_hl, PV_NONE, - {(char_u *)"8:SpecialKey,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar,X:PmenuThumb", + {(char_u *)"8:SpecialKey,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:Search,m:MoreMsg,M:ModeMsg,n:LineNr,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,>:SignColumn,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,x:PmenuSbar,X:PmenuThumb,*:TabPage,#:TabPageSel,_:TabPageFill", (char_u *)0L}}, {"history", "hi", P_NUM|P_VIM, (char_u *)&p_hi, PV_NONE, @@ -2264,7 +2277,7 @@ static struct vimoption (char_u *)NULL, PV_NONE, #endif {(char_u *)85L, (char_u *)0L}}, - {"titleold", NULL, P_STRING|P_VI_DEF|P_GETTEXT|P_SECURE, + {"titleold", NULL, P_STRING|P_VI_DEF|P_GETTEXT|P_SECURE|P_NO_MKRC, #ifdef FEAT_TITLE (char_u *)&p_titleold, PV_NONE, {(char_u *)N_("Thanks for flying Vim"), @@ -4755,6 +4768,9 @@ check_buf_options(buf) check_string_option(&buf->b_p_inde); check_string_option(&buf->b_p_indk); #endif +#if defined(FEAT_EVAL) + check_string_option(&buf->b_p_fex); +#endif #ifdef FEAT_CRYPT check_string_option(&buf->b_p_key); #endif @@ -8583,6 +8599,9 @@ get_varp(p) case PV_INDE: return (char_u *)&(curbuf->b_p_inde); case PV_INDK: return (char_u *)&(curbuf->b_p_indk); #endif +#if defined(FEAT_EVAL) + case PV_FEX: return (char_u *)&(curbuf->b_p_fex); +#endif #ifdef FEAT_CRYPT case PV_KEY: return (char_u *)&(curbuf->b_p_key); #endif @@ -8942,6 +8961,9 @@ buf_copy_options(buf, flags) buf->b_p_inde = vim_strsave(p_inde); buf->b_p_indk = vim_strsave(p_indk); #endif +#if defined(FEAT_EVAL) + buf->b_p_fex = vim_strsave(p_fex); +#endif #ifdef FEAT_CRYPT buf->b_p_key = vim_strsave(p_key); #endif diff --git a/src/proto/eval.pro b/src/proto/eval.pro index b8ba21514..1c2942ce4 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -54,7 +54,7 @@ char_u *get_dict_string __ARGS((dict_T *d, char_u *key, int save)); long get_dict_number __ARGS((dict_T *d, char_u *key)); char_u *get_function_name __ARGS((expand_T *xp, int idx)); char_u *get_expr_name __ARGS((expand_T *xp, int idx)); -long do_searchpair __ARGS((char_u *spat, char_u *mpat, char_u *epat, int dir, char_u *skip, int flags)); +long do_searchpair __ARGS((char_u *spat, char_u *mpat, char_u *epat, int dir, char_u *skip, int flags, pos_T *match_pos)); void set_vim_var_nr __ARGS((int idx, long val)); long get_vim_var_nr __ARGS((int idx)); char_u *get_vim_var_str __ARGS((int idx)); diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index 25601e171..a6998cf50 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -33,6 +33,8 @@ void alist_set __ARGS((alist_T *al, int count, char_u **files, int use_curbuf, i void alist_add __ARGS((alist_T *al, char_u *fname, int set_fnum)); void alist_slash_adjust __ARGS((void)); void ex_splitview __ARGS((exarg_T *eap)); +void ex_tabedit __ARGS((exarg_T *eap)); +void ex_tab __ARGS((exarg_T *eap)); void do_exedit __ARGS((exarg_T *eap, win_T *old_curwin)); void free_cd_dir __ARGS((void)); void do_sleep __ARGS((long msec)); diff --git a/src/proto/ops.pro b/src/proto/ops.pro index da9973bbe..3b4c9c423 100644 --- a/src/proto/ops.pro +++ b/src/proto/ops.pro @@ -38,6 +38,8 @@ void ex_display __ARGS((exarg_T *eap)); void do_do_join __ARGS((long count, int insert_space)); int do_join __ARGS((int insert_space)); void op_format __ARGS((oparg_T *oap, int keep_cursor)); +void op_formatexpr __ARGS((oparg_T *oap)); +int fex_format __ARGS((linenr_T lnum, long count)); void format_lines __ARGS((linenr_T line_count)); int paragraph_start __ARGS((linenr_T lnum)); int do_addsub __ARGS((int command, linenr_T Prenum1)); diff --git a/src/proto/window.pro b/src/proto/window.pro index fd3d62f37..a1808bc69 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -7,11 +7,15 @@ int make_windows __ARGS((int count, int vertical)); void win_move_after __ARGS((win_T *win1, win_T *win2)); void win_equal __ARGS((win_T *next_curwin, int current, int dir)); void close_windows __ARGS((buf_T *buf)); +int last_window __ARGS((void)); void win_close __ARGS((win_T *win, int free_buf)); void win_free_all __ARGS((void)); void close_others __ARGS((int message, int forceit)); void win_init __ARGS((win_T *wp)); -void win_alloc_first __ARGS((void)); +int win_alloc_first __ARGS((void)); +void win_init_size __ARGS((void)); +int win_new_tabpage __ARGS((void)); +void goto_tabpage __ARGS((int n)); void win_goto __ARGS((win_T *wp)); win_T *win_find_nr __ARGS((int winnr)); void win_enter __ARGS((win_T *wp, int undo_sync)); @@ -32,6 +36,7 @@ void win_drag_vsep_line __ARGS((win_T *dragwin, int offset)); void win_comp_scroll __ARGS((win_T *wp)); void command_height __ARGS((long old_p_ch)); void last_status __ARGS((int morewin)); +int tabpageline_height __ARGS((void)); char_u *grab_file_name __ARGS((long count)); char_u *file_name_at_cursor __ARGS((int options, long count)); char_u *file_name_in_line __ARGS((char_u *line, int col, int options, long count, char_u *rel_fname)); diff --git a/src/screen.c b/src/screen.c index e2f10db82..ba5475b0d 100644 --- a/src/screen.c +++ b/src/screen.c @@ -167,6 +167,9 @@ static void redraw_block __ARGS((int row, int end, win_T *wp)); static int win_do_lines __ARGS((win_T *wp, int row, int line_count, int mayclear, int del)); static void win_rest_invalid __ARGS((win_T *wp)); static void msg_pos_mode __ARGS((void)); +#if defined(FEAT_WINDOWS) +static void draw_tabpage __ARGS((void)); +#endif #if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT) static int fillchar_status __ARGS((int *attr, int is_curwin)); #endif @@ -390,6 +393,9 @@ update_screen(type) } } redraw_cmdline = TRUE; +#ifdef FEAT_WINDOWS + redraw_tabpage = TRUE; +#endif } msg_scrolled = 0; need_wait_return = FALSE; @@ -468,6 +474,12 @@ update_screen(type) } #endif +#ifdef FEAT_WINDOWS + /* Redraw the tab pages line if needed. */ + if (redraw_tabpage || type >= NOT_VALID) + draw_tabpage(); +#endif + /* * Go from top to bottom through the windows, redrawing the ones that need * it. @@ -4947,6 +4959,8 @@ redraw_statuslines() for (wp = firstwin; wp; wp = wp->w_next) if (wp->w_redr_status) win_redr_status(wp); + if (redraw_tabpage) + draw_tabpage(); } #endif @@ -8409,6 +8423,79 @@ unshowmode(force) } } +#if defined(FEAT_WINDOWS) +/* + * Draw the tab pages line at the top of the Vim window. + */ + static void +draw_tabpage() +{ + int tabcount = 0; + tabpage_T *tp; + int tabwidth; + int col = 0; + int had_current = FALSE; + int attr; + win_T *wp; + int c; + int len; + int attr_sel = hl_attr(HLF_TPS); + int attr_nosel = hl_attr(HLF_TP); + int attr_fill = hl_attr(HLF_TPF); + + redraw_tabpage = FALSE; + + if (tabpageline_height() < 1) + return; + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + ++tabcount; + + tabwidth = Columns / tabcount; + if (tabwidth < 6) + tabwidth = 6; + + attr = attr_nosel; + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + { + if (tp->tp_topframe == topframe) + { + c = '/'; + had_current = TRUE; + attr = attr_sel; + } + else if (!had_current) + c = '/'; + else + c = '\\'; + screen_putchar(c, 0, col++, attr); + + if (tp->tp_topframe != topframe) + attr = attr_nosel; + + if (tp->tp_topframe == topframe) + wp = curwin; + else + wp = tp->tp_curwin; + if (buf_spname(wp->w_buffer) != NULL) + STRCPY(NameBuff, buf_spname(wp->w_buffer)); + else + home_replace(wp->w_buffer, wp->w_buffer->b_fname, NameBuff, + MAXPATHL, TRUE); + trans_characters(NameBuff, MAXPATHL); + len = STRLEN(NameBuff); + if (len > tabwidth) /* TODO: multi-byte chars */ + len = tabwidth; + screen_puts_len(NameBuff, len, 0, col, attr); + col += len; + } + + screen_putchar('\\', 0, col++, attr); + while (col < Columns) + screen_putchar('_', 0, col++, attr_fill); +} +#endif + #if defined(FEAT_WINDOWS) || defined(FEAT_WILDMENU) || defined(FEAT_STL_OPT) /* * Get the character to use in a status line. Get its attributes in "*attr". diff --git a/src/search.c b/src/search.c index bcb23aa7e..5531fb6c0 100644 --- a/src/search.c +++ b/src/search.c @@ -3733,7 +3733,7 @@ again: { if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)", (char_u *)"", - (char_u *)"</[^>]*>", BACKWARD, (char_u *)"", 0) <= 0) + (char_u *)"</[^>]*>", BACKWARD, (char_u *)"", 0, NULL) <= 0) { curwin->w_cursor = old_pos; goto theend; @@ -3766,7 +3766,7 @@ again: sprintf((char *)spat, "<%.*s\\%%(\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p); sprintf((char *)epat, "</%.*s>\\c", len, p); - r = do_searchpair(spat, (char_u *)"", epat, FORWARD, (char_u *)"", 0); + r = do_searchpair(spat, (char_u *)"", epat, FORWARD, (char_u *)"", 0, NULL); vim_free(spat); vim_free(epat); diff --git a/src/structs.h b/src/structs.h index 462ee521c..a743a4f46 100644 --- a/src/structs.h +++ b/src/structs.h @@ -68,10 +68,10 @@ typedef struct growarray */ #include "regexp.h" -typedef struct window win_T; -typedef struct wininfo wininfo_T; -typedef struct frame frame_T; -typedef int scid_T; /* script ID */ +typedef struct window_S win_T; +typedef struct wininfo_S wininfo_T; +typedef struct frame_S frame_T; +typedef int scid_T; /* script ID */ /* * This is here because gui.h needs the pos_T and win_T, and win_T needs gui.h @@ -215,7 +215,7 @@ typedef struct * The window-info is kept in a list at b_wininfo. It is kept in * most-recently-used order. */ -struct wininfo +struct wininfo_S { wininfo_T *wi_next; /* next entry or NULL for last entry */ wininfo_T *wi_prev; /* previous entry or NULL for first entry */ @@ -1330,6 +1330,9 @@ struct file_buffer char_u *b_p_inde; /* 'indentexpr' */ char_u *b_p_indk; /* 'indentkeys' */ #endif +#if defined(FEAT_EVAL) + char_u *b_p_fex; /* 'formatexpr' */ +#endif #ifdef FEAT_CRYPT char_u *b_p_key; /* 'key' */ #endif @@ -1547,10 +1550,23 @@ typedef struct w_line } wline_T; /* + * Tab pages point to the top frame of each tab page. + */ +typedef struct tabpage_S tabpage_T; +struct tabpage_S +{ + tabpage_T *tp_next; /* next tabpage or NULL */ + frame_T *tp_topframe; + win_T *tp_curwin; /* current window in this Tab page */ + win_T *tp_firstwin; /* first window in this Tab page */ + win_T *tp_lastwin; /* last window in this Tab page */ +}; + +/* * Windows are kept in a tree of frames. Each frame has a column (FR_COL) * or row (FR_ROW) layout or is a leaf, which has a window. */ -struct frame +struct frame_S { char fr_layout; /* FR_LEAF, FR_COL or FR_ROW */ #ifdef FEAT_VERTSPLIT @@ -1577,7 +1593,7 @@ struct frame * * All row numbers are relative to the start of the window, except w_winrow. */ -struct window +struct window_S { buf_T *w_buffer; /* buffer we are a window into (used often, keep it the first item!) */ diff --git a/src/syntax.c b/src/syntax.c index ab9bcced8..0db3a6e74 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -6079,6 +6079,9 @@ static char *(highlight_init_both[]) = "DiffText term=reverse cterm=bold ctermbg=Red gui=bold guibg=Red", "PmenuThumb cterm=reverse gui=reverse", "PmenuSbar ctermbg=Grey guibg=Grey", + "TabPage term=underline cterm=underline ctermbg=grey gui=underline guibg=grey", + "TabPageSel term=reverse,bold cterm=reverse,bold gui=reverse,bold", + "TabPageFill term=underline cterm=underline ctermbg=grey gui=underline guibg=grey", NULL }; diff --git a/src/term.c b/src/term.c index e5f2c9a6d..37b84c74f 100644 --- a/src/term.c +++ b/src/term.c @@ -2980,6 +2980,10 @@ get_bytes_from_buf(buf, bytes, num_bytes) ++len; /* skip KE_FILLER */ /* else it should be KS_SPECIAL, and c already equals K_SPECIAL */ } + else if (c == CSI && buf[len] == KS_EXTRA && buf[len + 1] == (int)KE_CSI) + /* CSI is stored as CSI KS_SPECIAL KE_CSI to avoid confusion with + * the start of a special key, see add_to_input_buf_csi(). */ + len += 2; bytes[i] = c; } return len; @@ -2897,6 +2897,7 @@ mouse_find_win(rowp, colp) frame_T *fp; fp = topframe; + *rowp -= firstwin->w_winrow; for (;;) { if (fp->fr_layout == FR_LEAF) diff --git a/src/version.h b/src/version.h index 8324c3349..6ff870f9f 100644 --- a/src/version.h +++ b/src/version.h @@ -36,5 +36,5 @@ #define VIM_VERSION_NODOT "vim70aa" #define VIM_VERSION_SHORT "7.0aa" #define VIM_VERSION_MEDIUM "7.0aa ALPHA" -#define VIM_VERSION_LONG "VIM - Vi IMproved 7.0aa ALPHA (2006 Feb 10)" -#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.0aa ALPHA (2006 Feb 10, compiled " +#define VIM_VERSION_LONG "VIM - Vi IMproved 7.0aa ALPHA (2006 Feb 14)" +#define VIM_VERSION_LONG_DATE "VIM - Vi IMproved 7.0aa ALPHA (2006 Feb 14, compiled " @@ -1157,6 +1157,9 @@ typedef enum , HLF_PSI /* popup menu selected item */ , HLF_PSB /* popup menu scrollbar */ , HLF_PST /* popup menu scrollbar thumb */ + , HLF_TP /* tabpage line */ + , HLF_TPS /* tabpage line selected */ + , HLF_TPF /* tabpage line filler */ , HLF_COUNT /* MUST be the last one */ } hlf_T; @@ -1165,7 +1168,7 @@ typedef enum 'n', 'r', 's', 'S', 'c', 't', 'v', 'V', 'w', 'W', \ 'f', 'F', 'A', 'C', 'D', 'T', '>', \ 'B', 'P', 'R', 'L', \ - '+', '=', 'x', 'X'} + '+', '=', 'x', 'X', '*', '#', '_'} /* * Boolean constants diff --git a/src/window.c b/src/window.c index 6bb9c4674..4dc98854f 100644 --- a/src/window.c +++ b/src/window.c @@ -29,6 +29,7 @@ static void win_equal_rec __ARGS((win_T *next_curwin, int current, frame_T *topf static win_T *win_free_mem __ARGS((win_T *win, int *dirp)); static win_T *winframe_remove __ARGS((win_T *win, int *dirp)); static frame_T *win_altframe __ARGS((win_T *win)); +static tabpage_T *alt_tabpage __ARGS((void)); static win_T *frame2win __ARGS((frame_T *frp)); static int frame_has_win __ARGS((frame_T *frp, win_T *wp)); static void frame_new_height __ARGS((frame_T *topfrp, int height, int topfirst, int wfh)); @@ -40,6 +41,12 @@ static void frame_add_vsep __ARGS((frame_T *frp)); static int frame_minwidth __ARGS((frame_T *topfrp, win_T *next_curwin)); static void frame_fix_width __ARGS((win_T *wp)); #endif +#endif +static int win_alloc_firstwin __ARGS((void)); +#if defined(FEAT_WINDOWS) || defined(PROTO) +static tabpage_T *current_tabpage __ARGS((void)); +static void leave_tabpage __ARGS((tabpage_T *tp)); +static void enter_tabpage __ARGS((tabpage_T *tp, buf_T *old_curbuf)); static void frame_fix_height __ARGS((win_T *wp)); static int frame_minheight __ARGS((frame_T *topfrp, win_T *next_curwin)); static void win_enter_ext __ARGS((win_T *wp, int undo_sync, int no_curwin)); @@ -77,6 +84,9 @@ static void win_new_height __ARGS((win_T *, int)); #ifdef FEAT_WINDOWS static long p_ch_used = 1L; /* value of 'cmdheight' when frame size was set */ +# define ROWS_AVAIL (Rows - p_ch - tabpageline_height()) +#else +# define ROWS_AVAIL (Rows - p_ch) #endif #if defined(FEAT_WINDOWS) || defined(PROTO) @@ -932,7 +942,7 @@ win_split_ins(size, flags, newwin, dir) if (flags & (WSP_TOP | WSP_BOT)) { /* set height and row of new window to full height */ - wp->w_winrow = 0; + wp->w_winrow = tabpageline_height(); wp->w_height = curfrp->fr_height - (p_ls > 0); wp->w_status_height = (p_ls > 0); } @@ -1507,7 +1517,8 @@ win_equal(next_curwin, current, dir) dir = 'b'; #endif win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current, - topframe, dir, 0, 0, (int)Columns, topframe->fr_height); + topframe, dir, 0, tabpageline_height(), + (int)Columns, topframe->fr_height); } /* @@ -1807,6 +1818,16 @@ close_windows(buf) } /* + * Return TRUE if the current window is the only window that exists. + * Returns FALSE if there is a window in another tab page. + */ + int +last_window() +{ + return (lastwin == firstwin && first_tabpage->tp_next == NULL); +} + +/* * close window "win" * If "free_buf" is TRUE related buffer may be unloaded. * @@ -1818,6 +1839,7 @@ win_close(win, free_buf) int free_buf; { win_T *wp; + buf_T *old_curbuf = curbuf; #ifdef FEAT_AUTOCMD int other_buffer = FALSE; #endif @@ -1825,7 +1847,7 @@ win_close(win, free_buf) int dir; int help_window = FALSE; - if (lastwin == firstwin) + if (last_window()) { EMSG(_("E444: Cannot close last window")); return; @@ -1854,11 +1876,11 @@ win_close(win, free_buf) { other_buffer = TRUE; apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf); - if (!win_valid(win) || firstwin == lastwin) + if (!win_valid(win) || last_window()) return; } apply_autocmds(EVENT_WINLEAVE, NULL, NULL, FALSE, curbuf); - if (!win_valid(win) || firstwin == lastwin) + if (!win_valid(win) || last_window()) return; # ifdef FEAT_EVAL /* autocmds may abort script processing */ @@ -1874,16 +1896,42 @@ win_close(win, free_buf) close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0); /* Autocommands may have closed the window already, or closed the only * other window. */ - if (!win_valid(win) || firstwin == lastwin) + if (!win_valid(win) || last_window()) return; /* Free the memory used for the window. */ wp = win_free_mem(win, &dir); + /* When closing the last window in a tab page go to another tab page. */ + if (wp == NULL) + { + tabpage_T *ptp = NULL; + tabpage_T *tp; + tabpage_T *atp = alt_tabpage(); + + for (tp = first_tabpage; tp->tp_topframe != topframe; tp = tp->tp_next) + ptp = tp; + if (tp == NULL) + { + EMSG2(_(e_intern2), "win_close()"); + return; + } + if (ptp == NULL) + first_tabpage = tp->tp_next; + else + ptp->tp_next = tp->tp_next; + vim_free(tp); + + /* We don't do the window resizing stuff, let enter_tabpage() take + * care of entering a window in another tab page. */ + enter_tabpage(atp, old_curbuf); + return; + } + /* Make sure curwin isn't invalid. It can cause severe trouble when * printing an error message. For win_equal() curbuf needs to be valid * too. */ - if (win == curwin) + else if (win == curwin) { curwin = wp; #ifdef FEAT_QUICKFIX @@ -1937,8 +1985,8 @@ win_close(win, free_buf) } /* - * if last window has a status line now and we don't want one, - * remove the status line + * If last window has a status line now and we don't want one, + * remove the status line. */ last_status(FALSE); @@ -1975,9 +2023,13 @@ win_free_mem(win, dirp) /* reduce the reference count to the argument list. */ alist_unlink(win->w_alist); - /* remove the window and its frame from the tree of frames. */ + /* Remove the window and its frame from the tree of frames. */ frp = win->w_frame; - wp = winframe_remove(win, dirp); + if (firstwin == lastwin) + /* Last window in a tab page. */ + wp = NULL; + else + wp = winframe_remove(win, dirp); vim_free(frp); win_free(win); @@ -2115,6 +2167,10 @@ win_altframe(win) frame_T *frp; int b; + if (firstwin == lastwin) + /* Last window in this tab page, will go to next tab page. */ + return alt_tabpage()->tp_curwin->w_frame; + frp = win->w_frame; #ifdef FEAT_VERTSPLIT if (frp->fr_parent != NULL && frp->fr_parent->fr_layout == FR_ROW) @@ -2128,6 +2184,28 @@ win_altframe(win) } /* + * Return the tabpage that will be used if the current one is closed. + */ + static tabpage_T * +alt_tabpage() +{ + tabpage_T *tp = current_tabpage(); + + if (tp != NULL) + { + /* Use the next tab page if it exists. */ + if (tp->tp_next != NULL) + return tp->tp_next; + + /* Find the previous tab page. */ + for (tp = first_tabpage; tp->tp_next != NULL; tp = tp->tp_next) + if (tp->tp_next == current_tabpage()) + return tp; + } + return first_tabpage; +} + +/* * Find the left-upper window in frame "frp". */ static win_T * @@ -2640,11 +2718,7 @@ close_others(message, forceit) } } - /* - * If current window has a status line and we don't want one, - * remove the status line. - */ - if (lastwin != firstwin) + if (message && lastwin != firstwin) EMSG(_("E445: Other window contains changes")); } @@ -2686,15 +2760,36 @@ win_init(wp) /* * Allocate the first window and put an empty buffer in it. * Called from main(). - * When this fails we can't do anything: exit. + * Return FAIL when something goes wrong (out of memory). */ - void + int win_alloc_first() { + if (win_alloc_firstwin() == FAIL) + return FAIL; + +#ifdef FEAT_WINDOWS + first_tabpage = (tabpage_T *)alloc((unsigned)sizeof(tabpage_T)); + if (first_tabpage == NULL) + return FAIL; + first_tabpage->tp_topframe = topframe; + first_tabpage->tp_next = NULL; +#endif + return OK; +} + +/* + * Allocate one window and put an empty buffer in it. + * Called to create the first window in a new tab page. + * Return FAIL when something goes wrong (out of memory). + */ + static int +win_alloc_firstwin() +{ curwin = win_alloc(NULL); curbuf = buflist_new(NULL, NULL, 1L, BLN_LISTED); if (curwin == NULL || curbuf == NULL) - mch_exit(0); + return FAIL; curwin->w_buffer = curbuf; curbuf->b_nwindows = 1; /* there is one window */ #ifdef FEAT_WINDOWS @@ -2704,7 +2799,7 @@ win_alloc_first() topframe = (frame_T *)alloc_clear((unsigned)sizeof(frame_T)); if (topframe == NULL) - mch_exit(0); + return FAIL; topframe->fr_layout = FR_LEAF; #ifdef FEAT_VERTSPLIT topframe->fr_width = Columns; @@ -2715,9 +2810,169 @@ win_alloc_first() #endif topframe->fr_win = curwin; curwin->w_frame = topframe; + + return OK; +} + +/* + * Initialize the window and frame size to the maximum. + */ + void +win_init_size() +{ + firstwin->w_height = ROWS_AVAIL; + topframe->fr_height = ROWS_AVAIL; +#ifdef FEAT_VERTSPLIT + firstwin->w_width = Columns; + topframe->fr_width = Columns; +#endif } #if defined(FEAT_WINDOWS) || defined(PROTO) +/* + * Create a new Tab page with one empty window. + * Put it just after the current Tab page. + * Return FAIL or OK. + */ + int +win_new_tabpage() +{ + tabpage_T *tp; + tabpage_T *newtp; + + newtp = (tabpage_T *)alloc((unsigned)sizeof(tabpage_T)); + if (newtp == NULL) + return FAIL; + + tp = current_tabpage(); + + /* Remember the current windows in this Tab page. */ + leave_tabpage(tp); + + /* Create a new empty window. */ + if (win_alloc_firstwin() == OK) + { + /* copy options from previous to new curwin */ + win_copy_options(tp->tp_curwin, curwin); + + /* Make the new Tab page the new topframe. */ + newtp->tp_next = tp->tp_next; + tp->tp_next = newtp; + win_init_size(); + firstwin->w_winrow = tabpageline_height(); + + newtp->tp_topframe = topframe; + redraw_all_later(CLEAR); + return OK; + } + + /* Failed, get back the previous Tab page */ + topframe = tp->tp_topframe; + curwin = tp->tp_curwin; + firstwin = tp->tp_firstwin; + lastwin = tp->tp_lastwin; + return FAIL; +} + +/* + * Return a pointer to the current tab page. + */ + static tabpage_T * +current_tabpage() +{ + tabpage_T *tp; + + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + if (tp->tp_topframe == topframe) + break; + if (tp == NULL) + EMSG2(_(e_intern2), "current_tabpage()"); + return tp; +} + +/* + * Prepare for leaving the current tab page "tp". + */ + static void +leave_tabpage(tp) + tabpage_T *tp; +{ + tp->tp_curwin = curwin; + tp->tp_firstwin = firstwin; + tp->tp_lastwin = lastwin; + firstwin = NULL; + lastwin = NULL; +} + +/* + * Start using tab page "tp". + */ +/*ARGSUSED*/ + static void +enter_tabpage(tp, old_curbuf) + tabpage_T *tp; + buf_T *old_curbuf; +{ + firstwin = tp->tp_firstwin; + lastwin = tp->tp_lastwin; + topframe = tp->tp_topframe; + win_enter_ext(tp->tp_curwin, FALSE, TRUE); + +#ifdef FEAT_AUTOCMD + if (old_curbuf != curbuf) + apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf); +#endif + + /* status line may appear or disappear */ + last_status(FALSE); + +#if defined(FEAT_GUI) && defined(FEAT_VERTSPLIT) + /* When 'guioptions' includes 'L' or 'R' may have to add or remove + * scrollbars. */ + if (gui.in_use && !win_hasvertsplit()) + gui_init_which_components(NULL); +#endif + + redraw_all_later(CLEAR); +} + +/* + * Go to tab page "n". For ":tab N" and "Ngt". + */ + void +goto_tabpage(n) + int n; +{ + tabpage_T *otp = current_tabpage(); + tabpage_T *tp; + int i; + + if (otp == NULL) + return; + + if (n == 0) + { + /* No count, go to next tab page, wrap around end. */ + if (otp->tp_next == NULL) + tp = first_tabpage; + else + tp = otp->tp_next; + } + else + { + /* Go to tab page "n". */ + i = 0; + for (tp = first_tabpage; ++i != n; tp = tp->tp_next) + if (tp == NULL) + { + beep_flush(); + return; + } + } + + leave_tabpage(otp); + enter_tabpage(tp, curbuf); +} /* * Go to another window. @@ -3007,6 +3262,7 @@ win_enter_ext(wp, undo_sync, curwin_invalid) maketitle(); #endif curwin->w_redr_status = TRUE; + redraw_tabpage = TRUE; if (restart_edit) redraw_later(VALID); /* causes status line redraw */ @@ -3325,7 +3581,7 @@ win_free_lsize(wp) void shell_new_rows() { - int h = (int)(Rows - p_ch); + int h = (int)ROWS_AVAIL; if (firstwin == NULL) /* not initialized yet */ return; @@ -3430,7 +3686,7 @@ win_size_restore(gap) static int win_comp_pos() { - int row = 0; + int row = tabpageline_height(); int col = 0; frame_comp_pos(topframe, &row, &col); @@ -3593,8 +3849,8 @@ frame_setheight(curfrp, height) if (curfrp->fr_parent == NULL) { /* topframe: can only change the command line */ - if (height > Rows - p_ch) - height = Rows - p_ch; + if (height > ROWS_AVAIL) + height = ROWS_AVAIL; if (height > 0) frame_new_height(curfrp, height, FALSE, FALSE); } @@ -3841,7 +4097,7 @@ frame_setwidth(curfrp, width) if (width <= room) break; - if (run == 2 || curfrp->fr_height >= Rows - p_ch) + if (run == 2 || curfrp->fr_height >= ROWS_AVAIL) { if (width > room) width = room; @@ -4524,6 +4780,18 @@ last_status_rec(fr, statusline) } } +/* + * Return TRUE if the tab page line is to be drawn. + */ + int +tabpageline_height() +{ + /* TODO: option to tell when to show the tabs. */ + if (first_tabpage->tp_next == NULL) + return 0; + return 1; +} + #endif /* FEAT_WINDOWS */ #if defined(FEAT_SEARCHPATH) || defined(PROTO) @@ -4846,6 +5114,10 @@ only_one_window() int count = 0; win_T *wp; + /* If there is another tab page there always is another window. */ + if (first_tabpage->tp_next != NULL) + return FALSE; + for (wp = firstwin; wp != NULL; wp = wp->w_next) if (!((wp->w_buffer->b_help && !curbuf->b_help) # ifdef FEAT_QUICKFIX |