summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2006-02-14 22:29:30 +0000
committerBram Moolenaar <Bram@vim.org>2006-02-14 22:29:30 +0000
commit1d2ba7fa851f988ea9eab47b7662be243f85ddfa (patch)
tree5882ec62c5c5c6047021a94e74e4797139944a95 /src
parentf52c725c4739f2d3368029d67218d6cae0d87995 (diff)
downloadvim-git-1d2ba7fa851f988ea9eab47b7662be243f85ddfa.tar.gz
updated for version 7.0197v7.0197
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c10
-rw-r--r--src/edit.c679
-rw-r--r--src/eval.c164
-rw-r--r--src/ex_cmds.h10
-rw-r--r--src/ex_docmd.c247
-rw-r--r--src/globals.h10
-rw-r--r--src/gui.h2
-rw-r--r--src/gui_beval.c5
-rw-r--r--src/if_mzsch.c2
-rw-r--r--src/main.c13
-rw-r--r--src/netbeans.c2
-rw-r--r--src/normal.c13
-rw-r--r--src/ops.c43
-rw-r--r--src/option.c26
-rw-r--r--src/proto/eval.pro2
-rw-r--r--src/proto/ex_docmd.pro2
-rw-r--r--src/proto/ops.pro2
-rw-r--r--src/proto/window.pro7
-rw-r--r--src/screen.c87
-rw-r--r--src/search.c4
-rw-r--r--src/structs.h30
-rw-r--r--src/syntax.c3
-rw-r--r--src/term.c4
-rw-r--r--src/ui.c1
-rw-r--r--src/version.h4
-rw-r--r--src/vim.h5
-rw-r--r--src/window.c322
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(&regmatch, 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.
diff --git a/src/gui.h b/src/gui.h
index 2f5275c10..c706302d4 100644
--- a/src/gui.h
+++ b/src/gui.h
@@ -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;
diff --git a/src/ops.c b/src/ops.c
index 0c1e853de..a48b6be64 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -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;
diff --git a/src/ui.c b/src/ui.c
index b638c0da5..d1013efb4 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -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 "
diff --git a/src/vim.h b/src/vim.h
index 07acb562a..9af951404 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -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