diff options
Diffstat (limited to 'src/nvim/buffer.c')
-rw-r--r-- | src/nvim/buffer.c | 1506 |
1 files changed, 26 insertions, 1480 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index f23a1caf8b..ab5b32bf3e 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -25,17 +25,21 @@ #include <string.h> #include "nvim/api/private/helpers.h" +#include "nvim/arglist.h" #include "nvim/ascii.h" #include "nvim/assert.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_updates.h" #include "nvim/change.h" #include "nvim/channel.h" #include "nvim/charset.h" +#include "nvim/cmdexpand.h" #include "nvim/cursor.h" #include "nvim/decoration.h" #include "nvim/diff.h" #include "nvim/digraph.h" +#include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/vars.h" #include "nvim/ex_cmds.h" @@ -50,6 +54,7 @@ #include "nvim/garray.h" #include "nvim/getchar.h" #include "nvim/hashtab.h" +#include "nvim/help.h" #include "nvim/highlight_group.h" #include "nvim/indent.h" #include "nvim/indent_c.h" @@ -62,6 +67,7 @@ #include "nvim/message.h" #include "nvim/move.h" #include "nvim/option.h" +#include "nvim/optionstr.h" #include "nvim/os/input.h" #include "nvim/os/os.h" #include "nvim/os/time.h" @@ -69,9 +75,10 @@ #include "nvim/plines.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" -#include "nvim/screen.h" +#include "nvim/runtime.h" #include "nvim/sign.h" #include "nvim/spell.h" +#include "nvim/statusline.h" #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/ui.h" @@ -85,11 +92,6 @@ # include "buffer.c.generated.h" #endif -// Determines how deeply nested %{} blocks will be evaluated in statusline. -#define MAX_STL_EVAL_DEPTH 100 - -static char *msg_loclist = N_("[Location List]"); -static char *msg_qflist = N_("[Quickfix List]"); static char *e_auabort = N_("E855: Autocommands caused command to abort"); static char *e_buflocked = N_("E937: Attempt to delete a buffer that is in use"); @@ -793,8 +795,8 @@ static void free_buffer(buf_T *buf) if (autocmd_busy) { // Do not free the buffer structure while autocommands are executing, // it's still needed. Free it when autocmd_busy is reset. - memset(&buf->b_namedm[0], 0, sizeof(buf->b_namedm)); - memset(&buf->b_changelist[0], 0, sizeof(buf->b_changelist)); + CLEAR_FIELD(buf->b_namedm); + CLEAR_FIELD(buf->b_changelist); buf->b_next = au_pending_free_buf; au_pending_free_buf = buf; } else { @@ -1532,6 +1534,15 @@ void set_curbuf(buf_T *buf, int action) /// be pointing to freed memory. void enter_buffer(buf_T *buf) { + // when closing the current buffer stop Visual mode + if (VIsual_active +#if defined(EXITFREE) + && !entered_free_all_mem +#endif + ) { + end_visual_mode(); + } + // Get the buffer in the current window. curwin->w_buffer = buf; curbuf = buf; @@ -2595,7 +2606,7 @@ void get_winopts(buf_T *buf) } if (curwin->w_float_config.style == kWinStyleMinimal) { - didset_window_options(curwin); + didset_window_options(curwin, false); win_set_minimal_style(curwin); } @@ -2603,7 +2614,7 @@ void get_winopts(buf_T *buf) if (p_fdls >= 0) { curwin->w_p_fdl = p_fdls; } - didset_window_options(curwin); + didset_window_options(curwin, false); } /// Find the mark for the buffer 'buf' for the current window. @@ -3346,1192 +3357,6 @@ void free_titles(void) #endif -/// Enumeration specifying the valid numeric bases that can -/// be used when printing numbers in the status line. -typedef enum { - kNumBaseDecimal = 10, - kNumBaseHexadecimal = 16, -} NumberBase; - -/// Build a string from the status line items in "fmt". -/// Return length of string in screen cells. -/// -/// Normally works for window "wp", except when working for 'tabline' then it -/// is "curwin". -/// -/// Items are drawn interspersed with the text that surrounds it -/// Specials: %-<wid>(xxx%) => group, %= => separation marker, %< => truncation -/// Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional -/// -/// If maxwidth is not zero, the string will be filled at any middle marker -/// or truncated if too long, fillchar is used for all whitespace. -/// -/// @param wp The window to build a statusline for -/// @param out The output buffer to write the statusline to -/// Note: This should not be NameBuff -/// @param outlen The length of the output buffer -/// @param fmt The statusline format string -/// @param use_sandbox Use a sandboxed environment when evaluating fmt -/// @param fillchar Character to use when filling empty space in the statusline -/// @param maxwidth The maximum width to make the statusline -/// @param hltab HL attributes (can be NULL) -/// @param tabtab Tab clicks definition (can be NULL). -/// -/// @return The final width of the statusline -int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, int use_sandbox, int fillchar, - int maxwidth, stl_hlrec_t **hltab, StlClickRecord **tabtab) -{ - static size_t stl_items_len = 20; // Initial value, grows as needed. - static stl_item_t *stl_items = NULL; - static int *stl_groupitems = NULL; - static stl_hlrec_t *stl_hltab = NULL; - static StlClickRecord *stl_tabtab = NULL; - static int *stl_separator_locations = NULL; - -#define TMPLEN 70 - char buf_tmp[TMPLEN]; - char win_tmp[TMPLEN]; - char *usefmt = fmt; - const int save_must_redraw = must_redraw; - const int save_redr_type = curwin->w_redr_type; - - if (stl_items == NULL) { - stl_items = xmalloc(sizeof(stl_item_t) * stl_items_len); - stl_groupitems = xmalloc(sizeof(int) * stl_items_len); - - // Allocate one more, because the last element is used to indicate the - // end of the list. - stl_hltab = xmalloc(sizeof(stl_hlrec_t) * (stl_items_len + 1)); - stl_tabtab = xmalloc(sizeof(StlClickRecord) * (stl_items_len + 1)); - - stl_separator_locations = xmalloc(sizeof(int) * stl_items_len); - } - - // When the format starts with "%!" then evaluate it as an expression and - // use the result as the actual format string. - if (fmt[0] == '%' && fmt[1] == '!') { - typval_T tv = { - .v_type = VAR_NUMBER, - .vval.v_number = wp->handle, - }; - set_var(S_LEN("g:statusline_winid"), &tv, false); - - usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox); - if (usefmt == NULL) { - usefmt = fmt; - } - - do_unlet(S_LEN("g:statusline_winid"), true); - } - - if (fillchar == 0) { - fillchar = ' '; - } - - // The cursor in windows other than the current one isn't always - // up-to-date, esp. because of autocommands and timers. - linenr_T lnum = wp->w_cursor.lnum; - if (lnum > wp->w_buffer->b_ml.ml_line_count) { - lnum = wp->w_buffer->b_ml.ml_line_count; - wp->w_cursor.lnum = lnum; - } - - // Get line & check if empty (cursorpos will show "0-1"). - const char *line_ptr = (char *)ml_get_buf(wp->w_buffer, lnum, false); - bool empty_line = (*line_ptr == NUL); - - // Get the byte value now, in case we need it below. This is more - // efficient than making a copy of the line. - int byteval; - const size_t len = STRLEN(line_ptr); - if (wp->w_cursor.col > (colnr_T)len) { - // Line may have changed since checking the cursor column, or the lnum - // was adjusted above. - wp->w_cursor.col = (colnr_T)len; - wp->w_cursor.coladd = 0; - byteval = 0; - } else { - byteval = utf_ptr2char(line_ptr + wp->w_cursor.col); - } - - int groupdepth = 0; - int evaldepth = 0; - - int curitem = 0; - bool prevchar_isflag = true; - bool prevchar_isitem = false; - - // out_p is the current position in the output buffer - char *out_p = out; - - // out_end_p is the last valid character in the output buffer - // Note: The null termination character must occur here or earlier, - // so any user-visible characters must occur before here. - char *out_end_p = (out + outlen) - 1; - - // Proceed character by character through the statusline format string - // fmt_p is the current position in the input buffer - for (char *fmt_p = usefmt; *fmt_p != NUL;) { - if (curitem == (int)stl_items_len) { - size_t new_len = stl_items_len * 3 / 2; - - stl_items = xrealloc(stl_items, sizeof(stl_item_t) * new_len); - stl_groupitems = xrealloc(stl_groupitems, sizeof(int) * new_len); - stl_hltab = xrealloc(stl_hltab, sizeof(stl_hlrec_t) * (new_len + 1)); - stl_tabtab = xrealloc(stl_tabtab, sizeof(StlClickRecord) * (new_len + 1)); - stl_separator_locations = - xrealloc(stl_separator_locations, sizeof(int) * new_len); - - stl_items_len = new_len; - } - - if (*fmt_p != '%') { - prevchar_isflag = prevchar_isitem = false; - } - - // Copy the formatting verbatim until we reach the end of the string - // or find a formatting item (denoted by `%`) - // or run out of room in our output buffer. - while (*fmt_p != NUL && *fmt_p != '%' && out_p < out_end_p) { - *out_p++ = *fmt_p++; - } - - // If we have processed the entire format string or run out of - // room in our output buffer, exit the loop. - if (*fmt_p == NUL || out_p >= out_end_p) { - break; - } - - // The rest of this loop will handle a single `%` item. - // Note: We increment here to skip over the `%` character we are currently - // on so we can process the item's contents. - fmt_p++; - - // Ignore `%` at the end of the format string - if (*fmt_p == NUL) { - break; - } - - // Two `%` in a row is the escape sequence to print a - // single `%` in the output buffer. - if (*fmt_p == '%') { - *out_p++ = *fmt_p++; - prevchar_isflag = prevchar_isitem = false; - continue; - } - - // STL_SEPARATE: Separation place between left and right aligned items. - if (*fmt_p == STL_SEPARATE) { - fmt_p++; - // Ignored when we are inside of a grouping - if (groupdepth > 0) { - continue; - } - stl_items[curitem].type = Separate; - stl_items[curitem++].start = out_p; - continue; - } - - // STL_TRUNCMARK: Where to begin truncating if the statusline is too long. - if (*fmt_p == STL_TRUNCMARK) { - fmt_p++; - stl_items[curitem].type = Trunc; - stl_items[curitem++].start = out_p; - continue; - } - - // The end of a grouping - if (*fmt_p == ')') { - fmt_p++; - // Ignore if we are not actually inside a group currently - if (groupdepth < 1) { - continue; - } - groupdepth--; - - // Determine how long the group is. - // Note: We set the current output position to null - // so `vim_strsize` will work. - char *t = stl_items[stl_groupitems[groupdepth]].start; - *out_p = NUL; - long group_len = vim_strsize(t); - - // If the group contained internal items - // and the group did not have a minimum width, - // and if there were no normal items in the group, - // move the output pointer back to where the group started. - // Note: This erases any non-item characters that were in the group. - // Otherwise there would be no reason to do this step. - if (curitem > stl_groupitems[groupdepth] + 1 - && stl_items[stl_groupitems[groupdepth]].minwid == 0) { - // remove group if all items are empty and highlight group - // doesn't change - int group_start_userhl = 0; - int group_end_userhl = 0; - int n; - for (n = stl_groupitems[groupdepth] - 1; n >= 0; n--) { - if (stl_items[n].type == Highlight) { - group_start_userhl = group_end_userhl = stl_items[n].minwid; - break; - } - } - for (n = stl_groupitems[groupdepth] + 1; n < curitem; n++) { - if (stl_items[n].type == Normal) { - break; - } - if (stl_items[n].type == Highlight) { - group_end_userhl = stl_items[n].minwid; - } - } - if (n == curitem && group_start_userhl == group_end_userhl) { - // empty group - out_p = t; - group_len = 0; - for (n = stl_groupitems[groupdepth] + 1; n < curitem; n++) { - // do not use the highlighting from the removed group - if (stl_items[n].type == Highlight) { - stl_items[n].type = Empty; - } - // adjust the start position of TabPage to the next - // item position - if (stl_items[n].type == TabPage) { - stl_items[n].start = out_p; - } - } - } - } - - // If the group is longer than it is allowed to be - // truncate by removing bytes from the start of the group text. - if (group_len > stl_items[stl_groupitems[groupdepth]].maxwid) { - // { Determine the number of bytes to remove - - // Find the first character that should be included. - long n = 0; - while (group_len >= stl_items[stl_groupitems[groupdepth]].maxwid) { - group_len -= ptr2cells(t + n); - n += utfc_ptr2len(t + n); - } - // } - - // Prepend the `<` to indicate that the output was truncated. - *t = '<'; - - // { Move the truncated output - memmove(t + 1, t + n, (size_t)(out_p - (t + n))); - out_p = out_p - n + 1; - // Fill up space left over by half a double-wide char. - while (++group_len < stl_items[stl_groupitems[groupdepth]].minwid) { - MB_CHAR2BYTES(fillchar, out_p); - } - // } - - // correct the start of the items for the truncation - for (int idx = stl_groupitems[groupdepth] + 1; idx < curitem; idx++) { - // Shift everything back by the number of removed bytes - // Minus one for the leading '<' added above. - stl_items[idx].start -= n - 1; - - // If the item was partially or completely truncated, set its - // start to the start of the group - if (stl_items[idx].start < t) { - stl_items[idx].start = t; - } - } - // If the group is shorter than the minimum width, add padding characters. - } else if (abs(stl_items[stl_groupitems[groupdepth]].minwid) > group_len) { - long min_group_width = stl_items[stl_groupitems[groupdepth]].minwid; - // If the group is left-aligned, add characters to the right. - if (min_group_width < 0) { - min_group_width = 0 - min_group_width; - while (group_len++ < min_group_width && out_p < out_end_p) { - MB_CHAR2BYTES(fillchar, out_p); - } - // If the group is right-aligned, shift everything to the right and - // prepend with filler characters. - } else { - // { Move the group to the right - group_len = (min_group_width - group_len) * utf_char2len(fillchar); - memmove(t + group_len, t, (size_t)(out_p - t)); - if (out_p + group_len >= (out_end_p + 1)) { - group_len = (long)(out_end_p - out_p); - } - out_p += group_len; - // } - - // Adjust item start positions - for (int n = stl_groupitems[groupdepth] + 1; n < curitem; n++) { - stl_items[n].start += group_len; - } - - // Prepend the fill characters - for (; group_len > 0; group_len--) { - MB_CHAR2BYTES(fillchar, t); - } - } - } - continue; - } - int minwid = 0; - int maxwid = 9999; - bool left_align = false; - - // Denotes that numbers should be left-padded with zeros - bool zeropad = (*fmt_p == '0'); - if (zeropad) { - fmt_p++; - } - - // Denotes that the item should be left-aligned. - // This is tracked by using a negative length. - if (*fmt_p == '-') { - fmt_p++; - left_align = true; - } - - // The first digit group is the item's min width - if (ascii_isdigit(*fmt_p)) { - minwid = getdigits_int(&fmt_p, false, 0); - } - - // User highlight groups override the min width field - // to denote the styling to use. - if (*fmt_p == STL_USER_HL) { - stl_items[curitem].type = Highlight; - stl_items[curitem].start = out_p; - stl_items[curitem].minwid = minwid > 9 ? 1 : minwid; - fmt_p++; - curitem++; - continue; - } - - // TABPAGE pairs are used to denote a region that when clicked will - // either switch to or close a tab. - // - // Ex: tabline=%0Ttab\ zero%X - // This tabline has a TABPAGENR item with minwid `0`, - // which is then closed with a TABCLOSENR item. - // Clicking on this region with mouse enabled will switch to tab 0. - // Setting the minwid to a different value will switch - // to that tab, if it exists - // - // Ex: tabline=%1Xtab\ one%X - // This tabline has a TABCLOSENR item with minwid `1`, - // which is then closed with a TABCLOSENR item. - // Clicking on this region with mouse enabled will close tab 0. - // This is determined by the following formula: - // tab to close = (1 - minwid) - // This is because for TABPAGENR we use `minwid` = `tab number`. - // For TABCLOSENR we store the tab number as a negative value. - // Because 0 is a valid TABPAGENR value, we have to - // start our numbering at `-1`. - // So, `-1` corresponds to us wanting to close tab `0` - // - // Note: These options are only valid when creating a tabline. - if (*fmt_p == STL_TABPAGENR || *fmt_p == STL_TABCLOSENR) { - if (*fmt_p == STL_TABCLOSENR) { - if (minwid == 0) { - // %X ends the close label, go back to the previous tab label nr. - for (long n = curitem - 1; n >= 0; n--) { - if (stl_items[n].type == TabPage && stl_items[n].minwid >= 0) { - minwid = stl_items[n].minwid; - break; - } - } - } else { - // close nrs are stored as negative values - minwid = -minwid; - } - } - stl_items[curitem].type = TabPage; - stl_items[curitem].start = out_p; - stl_items[curitem].minwid = minwid; - fmt_p++; - curitem++; - continue; - } - - if (*fmt_p == STL_CLICK_FUNC) { - fmt_p++; - char *t = fmt_p; - while (*fmt_p != STL_CLICK_FUNC && *fmt_p) { - fmt_p++; - } - if (*fmt_p != STL_CLICK_FUNC) { - break; - } - stl_items[curitem].type = ClickFunc; - stl_items[curitem].start = out_p; - stl_items[curitem].cmd = xmemdupz(t, (size_t)(fmt_p - t)); - stl_items[curitem].minwid = minwid; - fmt_p++; - curitem++; - continue; - } - - // Denotes the end of the minwid - // the maxwid may follow immediately after - if (*fmt_p == '.') { - fmt_p++; - if (ascii_isdigit(*fmt_p)) { - maxwid = getdigits_int(&fmt_p, false, 50); - } - } - - // Bound the minimum width at 50. - // Make the number negative to denote left alignment of the item - minwid = (minwid > 50 ? 50 : minwid) * (left_align ? -1 : 1); - - // Denotes the start of a new group - if (*fmt_p == '(') { - stl_groupitems[groupdepth++] = curitem; - stl_items[curitem].type = Group; - stl_items[curitem].start = out_p; - stl_items[curitem].minwid = minwid; - stl_items[curitem].maxwid = maxwid; - fmt_p++; - curitem++; - continue; - } - - // Denotes end of expanded %{} block - if (*fmt_p == '}' && evaldepth > 0) { - fmt_p++; - evaldepth--; - continue; - } - - // An invalid item was specified. - // Continue processing on the next character of the format string. - if (vim_strchr(STL_ALL, *fmt_p) == NULL) { - fmt_p++; - continue; - } - - // The status line item type - char opt = *fmt_p++; - - // OK - now for the real work - NumberBase base = kNumBaseDecimal; - bool itemisflag = false; - bool fillable = true; - long num = -1; - char *str = NULL; - switch (opt) { - case STL_FILEPATH: - case STL_FULLPATH: - case STL_FILENAME: - // Set fillable to false so that ' ' in the filename will not - // get replaced with the fillchar - fillable = false; - if (buf_spname(wp->w_buffer) != NULL) { - STRLCPY(NameBuff, buf_spname(wp->w_buffer), MAXPATHL); - } else { - char *t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname - : wp->w_buffer->b_fname; - home_replace(wp->w_buffer, t, (char *)NameBuff, MAXPATHL, true); - } - trans_characters((char *)NameBuff, MAXPATHL); - if (opt != STL_FILENAME) { - str = (char *)NameBuff; - } else { - str = path_tail((char *)NameBuff); - } - break; - case STL_VIM_EXPR: // '{' - { - char *block_start = fmt_p - 1; - int reevaluate = (*fmt_p == '%'); - itemisflag = true; - - if (reevaluate) { - fmt_p++; - } - - // Attempt to copy the expression to evaluate into - // the output buffer as a null-terminated string. - char *t = out_p; - while ((*fmt_p != '}' || (reevaluate && fmt_p[-1] != '%')) - && *fmt_p != NUL && out_p < out_end_p) { - *out_p++ = *fmt_p++; - } - if (*fmt_p != '}') { // missing '}' or out of space - break; - } - fmt_p++; - if (reevaluate) { - out_p[-1] = 0; // remove the % at the end of %{% expr %} - } else { - *out_p = 0; - } - - // Move our position in the output buffer - // to the beginning of the expression - out_p = t; - - // { Evaluate the expression - - // Store the current buffer number as a string variable - vim_snprintf(buf_tmp, sizeof(buf_tmp), "%d", curbuf->b_fnum); - set_internal_string_var("g:actual_curbuf", buf_tmp); - vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->handle); - set_internal_string_var("g:actual_curwin", (char *)win_tmp); - - buf_T *const save_curbuf = curbuf; - win_T *const save_curwin = curwin; - const int save_VIsual_active = VIsual_active; - curwin = wp; - curbuf = wp->w_buffer; - // Visual mode is only valid in the current window. - if (curwin != save_curwin) { - VIsual_active = false; - } - - // Note: The result stored in `t` is unused. - str = eval_to_string_safe(out_p, &t, use_sandbox); - - curwin = save_curwin; - curbuf = save_curbuf; - VIsual_active = save_VIsual_active; - - // Remove the variable we just stored - do_unlet(S_LEN("g:actual_curbuf"), true); - do_unlet(S_LEN("g:actual_curwin"), true); - - // } - - // Check if the evaluated result is a number. - // If so, convert the number to an int and free the string. - if (str != NULL && *str != 0) { - if (*skipdigits(str) == NUL) { - num = atoi(str); - XFREE_CLEAR(str); - itemisflag = false; - } - } - - // If the output of the expression needs to be evaluated - // replace the %{} block with the result of evaluation - if (reevaluate && str != NULL && *str != 0 - && strchr((const char *)str, '%') != NULL - && evaldepth < MAX_STL_EVAL_DEPTH) { - size_t parsed_usefmt = (size_t)(block_start - usefmt); - size_t str_length = STRLEN(str); - size_t fmt_length = STRLEN(fmt_p); - size_t new_fmt_len = parsed_usefmt + str_length + fmt_length + 3; - char *new_fmt = xmalloc(new_fmt_len * sizeof(char)); - char *new_fmt_p = new_fmt; - - new_fmt_p = (char *)memcpy(new_fmt_p, usefmt, parsed_usefmt) + parsed_usefmt; - new_fmt_p = (char *)memcpy(new_fmt_p, str, str_length) + str_length; - new_fmt_p = (char *)memcpy(new_fmt_p, "%}", 2) + 2; - new_fmt_p = (char *)memcpy(new_fmt_p, fmt_p, fmt_length) + fmt_length; - *new_fmt_p = 0; - new_fmt_p = NULL; - - if (usefmt != fmt) { - xfree(usefmt); - } - XFREE_CLEAR(str); - usefmt = new_fmt; - fmt_p = usefmt + parsed_usefmt; - evaldepth++; - continue; - } - break; - } - - case STL_LINE: - num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) - ? 0L : (long)(wp->w_cursor.lnum); - break; - - case STL_NUMLINES: - num = wp->w_buffer->b_ml.ml_line_count; - break; - - case STL_COLUMN: - num = (State & MODE_INSERT) == 0 && empty_line ? 0 : (int)wp->w_cursor.col + 1; - break; - - case STL_VIRTCOL: - case STL_VIRTCOL_ALT: { - colnr_T virtcol = wp->w_virtcol + 1; - // Don't display %V if it's the same as %c. - if (opt == STL_VIRTCOL_ALT - && (virtcol == (colnr_T)((State & MODE_INSERT) == 0 && empty_line - ? 0 : (int)wp->w_cursor.col + 1))) { - break; - } - num = (long)virtcol; - break; - } - - case STL_PERCENTAGE: - num = (int)(((long)wp->w_cursor.lnum * 100L) / - (long)wp->w_buffer->b_ml.ml_line_count); - break; - - case STL_ALTPERCENT: - // Store the position percentage in our temporary buffer. - // Note: We cannot store the value in `num` because - // `get_rel_pos` can return a named position. Ex: "Top" - get_rel_pos(wp, buf_tmp, TMPLEN); - str = buf_tmp; - break; - - case STL_ARGLISTSTAT: - fillable = false; - - // Note: This is important because `append_arg_number` starts appending - // at the end of the null-terminated string. - // Setting the first byte to null means it will place the argument - // number string at the beginning of the buffer. - buf_tmp[0] = 0; - - // Note: The call will only return true if it actually - // appended data to the `buf_tmp` buffer. - if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), false)) { - str = buf_tmp; - } - break; - - case STL_KEYMAP: - fillable = false; - if (get_keymap_str(wp, "<%s>", buf_tmp, TMPLEN)) { - str = buf_tmp; - } - break; - case STL_PAGENUM: - num = printer_page_num; - break; - - case STL_BUFNO: - num = wp->w_buffer->b_fnum; - break; - - case STL_OFFSET_X: - base = kNumBaseHexadecimal; - FALLTHROUGH; - case STL_OFFSET: { - long l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL, - false); - num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ? - 0L : l + 1 + ((State & MODE_INSERT) == 0 && empty_line ? - 0 : (int)wp->w_cursor.col); - break; - } - case STL_BYTEVAL_X: - base = kNumBaseHexadecimal; - FALLTHROUGH; - case STL_BYTEVAL: - num = byteval; - if (num == NL) { - num = 0; - } else if (num == CAR && get_fileformat(wp->w_buffer) == EOL_MAC) { - num = NL; - } - break; - - case STL_ROFLAG: - case STL_ROFLAG_ALT: - itemisflag = true; - if (wp->w_buffer->b_p_ro) { - str = (opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]"); - } - break; - - case STL_HELPFLAG: - case STL_HELPFLAG_ALT: - itemisflag = true; - if (wp->w_buffer->b_help) { - str = (opt == STL_HELPFLAG_ALT) ? ",HLP" : _("[Help]"); - } - break; - - case STL_FILETYPE: - // Copy the filetype if it is not null and the formatted string will fit - // in the temporary buffer - // (including the brackets and null terminating character) - if (*wp->w_buffer->b_p_ft != NUL - && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3) { - vim_snprintf(buf_tmp, sizeof(buf_tmp), "[%s]", - wp->w_buffer->b_p_ft); - str = buf_tmp; - } - break; - - case STL_FILETYPE_ALT: - itemisflag = true; - // Copy the filetype if it is not null and the formatted string will fit - // in the temporary buffer - // (including the comma and null terminating character) - if (*wp->w_buffer->b_p_ft != NUL - && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2) { - vim_snprintf(buf_tmp, sizeof(buf_tmp), ",%s", wp->w_buffer->b_p_ft); - // Uppercase the file extension - for (char *t = buf_tmp; *t != 0; t++) { - *t = (char)TOUPPER_LOC(*t); - } - str = buf_tmp; - } - break; - case STL_PREVIEWFLAG: - case STL_PREVIEWFLAG_ALT: - itemisflag = true; - if (wp->w_p_pvw) { - str = (opt == STL_PREVIEWFLAG_ALT) ? ",PRV" : _("[Preview]"); - } - break; - - case STL_QUICKFIX: - if (bt_quickfix(wp->w_buffer)) { - str = wp->w_llist_ref ? _(msg_loclist) : _(msg_qflist); - } - break; - - case STL_MODIFIED: - case STL_MODIFIED_ALT: - itemisflag = true; - switch ((opt == STL_MODIFIED_ALT) - + bufIsChanged(wp->w_buffer) * 2 - + (!MODIFIABLE(wp->w_buffer)) * 4) { - case 2: - str = "[+]"; break; - case 3: - str = ",+"; break; - case 4: - str = "[-]"; break; - case 5: - str = ",-"; break; - case 6: - str = "[+-]"; break; - case 7: - str = ",+-"; break; - } - break; - - case STL_HIGHLIGHT: { - // { The name of the highlight is surrounded by `#` - char *t = fmt_p; - while (*fmt_p != '#' && *fmt_p != NUL) { - fmt_p++; - } - // } - - // Create a highlight item based on the name - if (*fmt_p == '#') { - stl_items[curitem].type = Highlight; - stl_items[curitem].start = out_p; - stl_items[curitem].minwid = -syn_name2id_len(t, (size_t)(fmt_p - t)); - curitem++; - fmt_p++; - } - continue; - } - } - - // If we made it this far, the item is normal and starts at - // our current position in the output buffer. - // Non-normal items would have `continued`. - stl_items[curitem].start = out_p; - stl_items[curitem].type = Normal; - - // Copy the item string into the output buffer - if (str != NULL && *str) { - // { Skip the leading `,` or ` ` if the item is a flag - // and the proper conditions are met - char *t = str; - if (itemisflag) { - if ((t[0] && t[1]) - && ((!prevchar_isitem && *t == ',') - || (prevchar_isflag && *t == ' '))) { - t++; - } - prevchar_isflag = true; - } - // } - - long l = vim_strsize(t); - - // If this item is non-empty, record that the last thing - // we put in the output buffer was an item - if (l > 0) { - prevchar_isitem = true; - } - - // If the item is too wide, truncate it from the beginning - if (l > maxwid) { - while (l >= maxwid) { - l -= ptr2cells(t); - t += utfc_ptr2len(t); - } - - // Early out if there isn't enough room for the truncation marker - if (out_p >= out_end_p) { - break; - } - - // Add the truncation marker - *out_p++ = '<'; - } - - // If the item is right aligned and not wide enough, - // pad with fill characters. - if (minwid > 0) { - for (; l < minwid && out_p < out_end_p; l++) { - // Don't put a "-" in front of a digit. - if (l + 1 == minwid && fillchar == '-' && ascii_isdigit(*t)) { - *out_p++ = ' '; - } else { - MB_CHAR2BYTES(fillchar, out_p); - } - } - minwid = 0; - } else { - // Note: The negative value denotes a left aligned item. - // Here we switch the minimum width back to a positive value. - minwid *= -1; - } - - // { Copy the string text into the output buffer - for (; *t && out_p < out_end_p; t++) { - // Change a space by fillchar, unless fillchar is '-' and a - // digit follows. - if (fillable && *t == ' ' - && (!ascii_isdigit(*(t + 1)) || fillchar != '-')) { - MB_CHAR2BYTES(fillchar, out_p); - } else { - *out_p++ = *t; - } - } - // } - - // For left-aligned items, fill any remaining space with the fillchar - for (; l < minwid && out_p < out_end_p; l++) { - MB_CHAR2BYTES(fillchar, out_p); - } - - // Otherwise if the item is a number, copy that to the output buffer. - } else if (num >= 0) { - if (out_p + 20 > out_end_p) { - break; // not sufficient space - } - prevchar_isitem = true; - - // { Build the formatting string - char nstr[20]; - char *t = nstr; - if (opt == STL_VIRTCOL_ALT) { - *t++ = '-'; - minwid--; - } - *t++ = '%'; - if (zeropad) { - *t++ = '0'; - } - - // Note: The `*` means we take the width as one of the arguments - *t++ = '*'; - *t++ = base == kNumBaseHexadecimal ? 'X' : 'd'; - *t = 0; - // } - - // { Determine how many characters the number will take up when printed - // Note: We have to cast the base because the compiler uses - // unsigned ints for the enum values. - long num_chars = 1; - for (long n = num; n >= (int)base; n /= (int)base) { - num_chars++; - } - - // VIRTCOL_ALT takes up an extra character because - // of the `-` we added above. - if (opt == STL_VIRTCOL_ALT) { - num_chars++; - } - // } - - assert(out_end_p >= out_p); - size_t remaining_buf_len = (size_t)(out_end_p - out_p) + 1; - - // If the number is going to take up too much room - // Figure out the approximate number in "scientific" type notation. - // Ex: 14532 with maxwid of 4 -> '14>3' - if (num_chars > maxwid) { - // Add two to the width because the power piece will take - // two extra characters - num_chars += 2; - - // How many extra characters there are - long n = num_chars - maxwid; - - // { Reduce the number by base^n - while (num_chars-- > maxwid) { - num /= (long)base; - } - // } - - // { Add the format string for the exponent bit - *t++ = '>'; - *t++ = '%'; - // Use the same base as the first number - *t = t[-3]; - *++t = 0; - // } - - vim_snprintf(out_p, remaining_buf_len, nstr, 0, num, n); - } else { - vim_snprintf(out_p, remaining_buf_len, nstr, minwid, num); - } - - // Advance the output buffer position to the end of the - // number we just printed - out_p += STRLEN(out_p); - - // Otherwise, there was nothing to print so mark the item as empty - } else { - stl_items[curitem].type = Empty; - } - - // Only free the string buffer if we allocated it. - // Note: This is not needed if `str` is pointing at `tmp` - if (opt == STL_VIM_EXPR) { - XFREE_CLEAR(str); - } - - if (num >= 0 || (!itemisflag && str && *str)) { - prevchar_isflag = false; // Item not NULL, but not a flag - } - - // Item processed, move to the next - curitem++; - } - - *out_p = NUL; - int itemcnt = curitem; - - // Free the format buffer if we allocated it internally - if (usefmt != fmt) { - xfree(usefmt); - } - - // We have now processed the entire statusline format string. - // What follows is post-processing to handle alignment and highlighting. - - int width = vim_strsize(out); - if (maxwidth > 0 && width > maxwidth) { - // Result is too long, must truncate somewhere. - int item_idx = 0; - char *trunc_p; - - // If there are no items, truncate from beginning - if (itemcnt == 0) { - trunc_p = out; - - // Otherwise, look for the truncation item - } else { - // Default to truncating at the first item - trunc_p = stl_items[0].start; - item_idx = 0; - - for (int i = 0; i < itemcnt; i++) { - if (stl_items[i].type == Trunc) { - // Truncate at %< stl_items. - trunc_p = stl_items[i].start; - item_idx = i; - break; - } - } - } - - // If the truncation point we found is beyond the maximum - // length of the string, truncate the end of the string. - if (width - vim_strsize(trunc_p) >= maxwidth) { - // Walk from the beginning of the - // string to find the last character that will fit. - trunc_p = out; - width = 0; - for (;;) { - width += ptr2cells(trunc_p); - if (width >= maxwidth) { - break; - } - - // Note: Only advance the pointer if the next - // character will fit in the available output space - trunc_p += utfc_ptr2len(trunc_p); - } - - // Ignore any items in the statusline that occur after - // the truncation point - for (int i = 0; i < itemcnt; i++) { - if (stl_items[i].start > trunc_p) { - itemcnt = i; - break; - } - } - - // Truncate the output - *trunc_p++ = '>'; - *trunc_p = 0; - - // Truncate at the truncation point we found - } else { - // { Determine how many bytes to remove - long trunc_len = 0; - while (width >= maxwidth) { - width -= ptr2cells(trunc_p + trunc_len); - trunc_len += utfc_ptr2len(trunc_p + trunc_len); - } - // } - - // { Truncate the string - char *trunc_end_p = trunc_p + trunc_len; - STRMOVE(trunc_p + 1, trunc_end_p); - - // Put a `<` to mark where we truncated at - *trunc_p = '<'; - - if (width + 1 < maxwidth) { - // Advance the pointer to the end of the string - trunc_p = trunc_p + STRLEN(trunc_p); - } - - // Fill up for half a double-wide character. - while (++width < maxwidth) { - MB_CHAR2BYTES(fillchar, trunc_p); - *trunc_p = NUL; - } - // } - - // { Change the start point for items based on - // their position relative to our truncation point - - // Note: The offset is one less than the truncation length because - // the truncation marker `<` is not counted. - long item_offset = trunc_len - 1; - - for (int i = item_idx; i < itemcnt; i++) { - // Items starting at or after the end of the truncated section need - // to be moved backwards. - if (stl_items[i].start >= trunc_end_p) { - stl_items[i].start -= item_offset; - // Anything inside the truncated area is set to start - // at the `<` truncation character. - } else { - stl_items[i].start = trunc_p; - } - } - // } - } - width = maxwidth; - - // If there is room left in our statusline, and room left in our buffer, - // add characters at the separate marker (if there is one) to - // fill up the available space. - } else if (width < maxwidth - && STRLEN(out) + (size_t)(maxwidth - width) + 1 < outlen) { - // Find how many separators there are, which we will use when - // figuring out how many groups there are. - int num_separators = 0; - for (int i = 0; i < itemcnt; i++) { - if (stl_items[i].type == Separate) { - // Create an array of the start location for each - // separator mark. - stl_separator_locations[num_separators] = i; - num_separators++; - } - } - - // If we have separated groups, then we deal with it now - if (num_separators) { - int standard_spaces = (maxwidth - width) / num_separators; - int final_spaces = (maxwidth - width) - - standard_spaces * (num_separators - 1); - - for (int i = 0; i < num_separators; i++) { - int dislocation = (i == (num_separators - 1)) ? final_spaces : standard_spaces; - dislocation *= utf_char2len(fillchar); - char *start = stl_items[stl_separator_locations[i]].start; - char *seploc = start + dislocation; - STRMOVE(seploc, start); - for (char *s = start; s < seploc;) { - MB_CHAR2BYTES(fillchar, s); - } - - for (int item_idx = stl_separator_locations[i] + 1; - item_idx < itemcnt; - item_idx++) { - stl_items[item_idx].start += dislocation; - } - } - - width = maxwidth; - } - } - - // Store the info about highlighting. - if (hltab != NULL) { - *hltab = stl_hltab; - stl_hlrec_t *sp = stl_hltab; - for (long l = 0; l < itemcnt; l++) { - if (stl_items[l].type == Highlight) { - sp->start = stl_items[l].start; - sp->userhl = stl_items[l].minwid; - sp++; - } - } - sp->start = NULL; - sp->userhl = 0; - } - - // Store the info about tab pages labels. - if (tabtab != NULL) { - *tabtab = stl_tabtab; - StlClickRecord *cur_tab_rec = stl_tabtab; - for (long l = 0; l < itemcnt; l++) { - if (stl_items[l].type == TabPage) { - cur_tab_rec->start = stl_items[l].start; - if (stl_items[l].minwid == 0) { - cur_tab_rec->def.type = kStlClickDisabled; - cur_tab_rec->def.tabnr = 0; - } else { - int tabnr = stl_items[l].minwid; - if (stl_items[l].minwid > 0) { - cur_tab_rec->def.type = kStlClickTabSwitch; - } else { - cur_tab_rec->def.type = kStlClickTabClose; - tabnr = -tabnr; - } - cur_tab_rec->def.tabnr = tabnr; - } - cur_tab_rec->def.func = NULL; - cur_tab_rec++; - } else if (stl_items[l].type == ClickFunc) { - cur_tab_rec->start = stl_items[l].start; - cur_tab_rec->def.type = kStlClickFuncRun; - cur_tab_rec->def.tabnr = stl_items[l].minwid; - cur_tab_rec->def.func = stl_items[l].cmd; - cur_tab_rec++; - } - } - cur_tab_rec->start = NULL; - cur_tab_rec->def.type = kStlClickDisabled; - cur_tab_rec->def.tabnr = 0; - cur_tab_rec->def.func = NULL; - } - - // When inside update_screen we do not want redrawing a statusline, ruler, - // title, etc. to trigger another redraw, it may cause an endless loop. - if (updating_screen) { - must_redraw = save_must_redraw; - curwin->w_redr_type = save_redr_type; - } - - return width; -} - /// Get relative cursor position in window into "buf[buflen]", in the form 99%, /// using "Top", "Bot" or "All" when appropriate. void get_rel_pos(win_T *wp, char *buf, int buflen) @@ -4571,7 +3396,7 @@ void get_rel_pos(win_T *wp, char *buf, int buflen) /// @param add_file if true, add "file" before the arg number /// /// @return true if it was appended. -static bool append_arg_number(win_T *wp, char *buf, int buflen, bool add_file) +bool append_arg_number(win_T *wp, char *buf, int buflen, bool add_file) FUNC_ATTR_NONNULL_ALL { // Nothing to do @@ -4628,279 +3453,6 @@ void fname_expand(buf_T *buf, char **ffname, char **sfname) #endif } -/// Get the file name for an argument list entry. -char *alist_name(aentry_T *aep) -{ - buf_T *bp; - - // Use the name from the associated buffer if it exists. - bp = buflist_findnr(aep->ae_fnum); - if (bp == NULL || bp->b_fname == NULL) { - return (char *)aep->ae_fname; - } - return bp->b_fname; -} - -/// do_arg_all(): Open up to 'count' windows, one for each argument. -/// -/// @param forceit hide buffers in current windows -/// @param keep_tabs keep current tabs, for ":tab drop file" -void do_arg_all(int count, int forceit, int keep_tabs) -{ - uint8_t *opened; // Array of weight for which args are open: - // 0: not opened - // 1: opened in other tab - // 2: opened in curtab - // 3: opened in curtab and curwin - - int opened_len; // length of opened[] - int use_firstwin = false; // use first window for arglist - bool tab_drop_empty_window = false; - int split_ret = OK; - bool p_ea_save; - alist_T *alist; // argument list to be used - buf_T *buf; - tabpage_T *tpnext; - int had_tab = cmdmod.cmod_tab; - win_T *old_curwin, *last_curwin; - tabpage_T *old_curtab, *last_curtab; - win_T *new_curwin = NULL; - tabpage_T *new_curtab = NULL; - - assert(firstwin != NULL); // satisfy coverity - - if (ARGCOUNT <= 0) { - // Don't give an error message. We don't want it when the ":all" command is in the .vimrc. - return; - } - setpcmark(); - - opened_len = ARGCOUNT; - opened = xcalloc((size_t)opened_len, 1); - - // Autocommands may do anything to the argument list. Make sure it's not - // freed while we are working here by "locking" it. We still have to - // watch out for its size to be changed. - alist = curwin->w_alist; - alist->al_refcount++; - - old_curwin = curwin; - old_curtab = curtab; - - // Try closing all windows that are not in the argument list. - // Also close windows that are not full width; - // When 'hidden' or "forceit" set the buffer becomes hidden. - // Windows that have a changed buffer and can't be hidden won't be closed. - // When the ":tab" modifier was used do this for all tab pages. - if (had_tab > 0) { - goto_tabpage_tp(first_tabpage, true, true); - } - for (;;) { - win_T *wpnext = NULL; - tpnext = curtab->tp_next; - for (win_T *wp = firstwin; wp != NULL; wp = wpnext) { - int i; - wpnext = wp->w_next; - buf = wp->w_buffer; - if (buf->b_ffname == NULL - || (!keep_tabs && (buf->b_nwindows > 1 || wp->w_width != Columns))) { - i = opened_len; - } else { - // check if the buffer in this window is in the arglist - for (i = 0; i < opened_len; i++) { - if (i < alist->al_ga.ga_len - && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum - || path_full_compare(alist_name(&AARGLIST(alist)[i]), - buf->b_ffname, - true, true) & kEqualFiles)) { - int weight = 1; - - if (old_curtab == curtab) { - weight++; - if (old_curwin == wp) { - weight++; - } - } - - if (weight > (int)opened[i]) { - opened[i] = (uint8_t)weight; - if (i == 0) { - if (new_curwin != NULL) { - new_curwin->w_arg_idx = opened_len; - } - new_curwin = wp; - new_curtab = curtab; - } - } else if (keep_tabs) { - i = opened_len; - } - - if (wp->w_alist != alist) { - // Use the current argument list for all windows containing a file from it. - alist_unlink(wp->w_alist); - wp->w_alist = alist; - wp->w_alist->al_refcount++; - } - break; - } - } - } - wp->w_arg_idx = i; - - if (i == opened_len && !keep_tabs) { // close this window - if (buf_hide(buf) || forceit || buf->b_nwindows > 1 - || !bufIsChanged(buf)) { - // If the buffer was changed, and we would like to hide it, try autowriting. - if (!buf_hide(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf)) { - bufref_T bufref; - set_bufref(&bufref, buf); - (void)autowrite(buf, false); - // Check if autocommands removed the window. - if (!win_valid(wp) || !bufref_valid(&bufref)) { - wpnext = firstwin; // Start all over... - continue; - } - } - // don't close last window - if (ONE_WINDOW - && (first_tabpage->tp_next == NULL || !had_tab)) { - use_firstwin = true; - } else { - win_close(wp, !buf_hide(buf) && !bufIsChanged(buf), false); - // check if autocommands removed the next window - if (!win_valid(wpnext)) { - // start all over... - wpnext = firstwin; - } - } - } - } - } - - // Without the ":tab" modifier only do the current tab page. - if (had_tab == 0 || tpnext == NULL) { - break; - } - - // check if autocommands removed the next tab page - if (!valid_tabpage(tpnext)) { - tpnext = first_tabpage; // start all over... - } - goto_tabpage_tp(tpnext, true, true); - } - - // Open a window for files in the argument list that don't have one. - // ARGCOUNT may change while doing this, because of autocommands. - if (count > opened_len || count <= 0) { - count = opened_len; - } - - // Don't execute Win/Buf Enter/Leave autocommands here. - autocmd_no_enter++; - autocmd_no_leave++; - last_curwin = curwin; - last_curtab = curtab; - win_enter(lastwin, false); - // ":tab drop file" should re-use an empty window to avoid "--remote-tab" - // leaving an empty tab page when executed locally. - if (keep_tabs && buf_is_empty(curbuf) && curbuf->b_nwindows == 1 - && curbuf->b_ffname == NULL && !curbuf->b_changed) { - use_firstwin = true; - tab_drop_empty_window = true; - } - - for (int i = 0; i < count && !got_int; i++) { - if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) { - arg_had_last = true; - } - if (opened[i] > 0) { - // Move the already present window to below the current window - if (curwin->w_arg_idx != i) { - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_arg_idx == i) { - if (keep_tabs) { - new_curwin = wp; - new_curtab = curtab; - } else if (wp->w_frame->fr_parent != curwin->w_frame->fr_parent) { - emsg(_("E249: window layout changed unexpectedly")); - i = count; - break; - } else { - win_move_after(wp, curwin); - } - break; - } - } - } - } else if (split_ret == OK) { - // trigger events for tab drop - if (tab_drop_empty_window && i == count - 1) { - autocmd_no_enter--; - } - if (!use_firstwin) { // split current window - p_ea_save = p_ea; - p_ea = true; // use space from all windows - split_ret = win_split(0, WSP_ROOM | WSP_BELOW); - p_ea = p_ea_save; - if (split_ret == FAIL) { - continue; - } - } else { // first window: do autocmd for leaving this buffer - autocmd_no_leave--; - } - - // edit file "i" - curwin->w_arg_idx = i; - if (i == 0) { - new_curwin = curwin; - new_curtab = curtab; - } - (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, ECMD_ONE, - ((buf_hide(curwin->w_buffer) - || bufIsChanged(curwin->w_buffer)) - ? ECMD_HIDE : 0) + ECMD_OLDBUF, - curwin); - if (tab_drop_empty_window && i == count - 1) { - autocmd_no_enter++; - } - if (use_firstwin) { - autocmd_no_leave++; - } - use_firstwin = false; - } - os_breakcheck(); - - // When ":tab" was used open a new tab for a new window repeatedly. - if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) { - cmdmod.cmod_tab = 9999; - } - } - - // Remove the "lock" on the argument list. - alist_unlink(alist); - - autocmd_no_enter--; - // restore last referenced tabpage's curwin - if (last_curtab != new_curtab) { - if (valid_tabpage(last_curtab)) { - goto_tabpage_tp(last_curtab, true, true); - } - if (win_valid(last_curwin)) { - win_enter(last_curwin, false); - } - } - // to window with first arg - if (valid_tabpage(new_curtab)) { - goto_tabpage_tp(new_curtab, true, true); - } - if (win_valid(new_curwin)) { - win_enter(new_curwin, false); - } - - autocmd_no_leave--; - xfree(opened); -} - /// @return true if "buf" is a prompt buffer. bool bt_prompt(buf_T *buf) FUNC_ATTR_PURE @@ -5139,8 +3691,6 @@ static int chk_modeline(linenr_T lnum, int flags) intmax_t vers; int end; int retval = OK; - char *save_sourcing_name; - linenr_T save_sourcing_lnum; prev = -1; for (s = (char *)ml_get(lnum); *s != NUL; s++) { @@ -5185,10 +3735,8 @@ static int chk_modeline(linenr_T lnum, int flags) s = linecopy = xstrdup(s); // copy the line, it will change - save_sourcing_lnum = sourcing_lnum; - save_sourcing_name = sourcing_name; - sourcing_lnum = lnum; // prepare for emsg() - sourcing_name = "modelines"; + // prepare for emsg() + estack_push(ETYPE_MODELINE, "modelines", lnum); end = false; while (end == false) { @@ -5228,7 +3776,7 @@ static int chk_modeline(linenr_T lnum, int flags) const sctx_T save_current_sctx = current_sctx; current_sctx.sc_sid = SID_MODELINE; current_sctx.sc_seq = 0; - current_sctx.sc_lnum = 0; + current_sctx.sc_lnum = lnum; // Make sure no risky things are executed as a side effect. secure = 1; @@ -5243,9 +3791,7 @@ static int chk_modeline(linenr_T lnum, int flags) s = e + 1; // advance to next part } - sourcing_lnum = save_sourcing_lnum; - sourcing_name = save_sourcing_name; - + estack_pop(); xfree(linecopy); return retval; |