diff options
Diffstat (limited to 'src')
56 files changed, 884 insertions, 537 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index a8446265d0..b7a86af134 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1,6 +1,5 @@ // Much of this code was adapted from 'if_py_both.h' from the original // vim source -#include <errno.h> #include <stdbool.h> #include <stdint.h> #include <stdlib.h> diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 10106bcb1d..fb1aeb7ba8 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -25,7 +25,6 @@ */ #include <stdbool.h> -#include <errno.h> #include <string.h> #include <inttypes.h> @@ -2803,58 +2802,59 @@ 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, + kNumBaseOctal = 8, + 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, %= => middle 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. - */ -int -build_stl_str_hl ( + +/// 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, %= => middle 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 page nrs (can be NULL) +/// +/// @return The final width of the statusline +int build_stl_str_hl( win_T *wp, - char_u *out, /* buffer to write into != NameBuff */ - size_t outlen, /* length of out[] */ + char_u *out, + size_t outlen, char_u *fmt, - int use_sandbox, /* "fmt" was set insecurely, use sandbox */ + int use_sandbox, int fillchar, int maxwidth, - struct stl_hlrec *hltab, /* return: HL attributes (can be NULL) */ - struct stl_hlrec *tabtab /* return: tab page nrs (can be NULL) */ + struct stl_hlrec *hltab, + struct stl_hlrec *tabtab ) { - char_u *p; - char_u *s; - char_u *t; - int byteval; - win_T *o_curwin; - buf_T *o_curbuf; - int empty_line; - colnr_T virtcol; - long l; - long n; - int prevchar_isflag; - int prevchar_isitem; - int itemisflag; - int fillable; - char_u *str; - long num; - int width; - int itemcnt; - int curitem; int groupitem[STL_MAX_ITEM]; - int groupdepth; struct stl_item { + // Where the item starts in the status line output buffer char_u *start; + // The minimum width of the item int minwid; + // The maximum width of the item int maxwid; enum { Normal, @@ -2866,20 +2866,13 @@ build_stl_str_hl ( Trunc } type; } item[STL_MAX_ITEM]; - int minwid; - int maxwid; - int zeropad; - char_u base; - char_u opt; + #define TMPLEN 70 char_u tmp[TMPLEN]; char_u *usefmt = fmt; - struct stl_hlrec *sp; - /* - * When the format starts with "%!" then evaluate it as an expression and - * use the result as the actual format string. - */ + // 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] == '!') { usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox); if (usefmt == NULL) @@ -2888,175 +2881,280 @@ build_stl_str_hl ( if (fillchar == 0) fillchar = ' '; - /* Can't handle a multi-byte fill character yet. */ + // Can't handle a multi-byte fill character yet. else if (mb_char2len(fillchar) > 1) fillchar = '-'; - /* Get line & check if empty (cursorpos will show "0-1"). Note that - * p will become invalid when getting another buffer line. */ - p = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE); - empty_line = (*p == NUL); + // Get line & check if empty (cursorpos will show "0-1"). + char_u *line_ptr = ml_get_buf(wp->w_buffer, wp->w_cursor.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. */ - if (wp->w_cursor.col > (colnr_T)STRLEN(p)) + // Get the byte value now, in case we need it below. This is more + // efficient than making a copy of the line. + int byteval; + if (wp->w_cursor.col > (colnr_T)STRLEN(line_ptr)) byteval = 0; else - byteval = (*mb_ptr2char)(p + wp->w_cursor.col); - - groupdepth = 0; - p = out; - curitem = 0; - prevchar_isflag = TRUE; - prevchar_isitem = FALSE; - for (s = usefmt; *s; ) { + byteval = (*mb_ptr2char)(line_ptr + wp->w_cursor.col); + + int groupdepth = 0; + + int curitem = 0; + bool prevchar_isflag = true; + bool prevchar_isitem = false; + + // out_p is the current position in the output buffer + char_u *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_u *out_end_p = (out + outlen) - 1; + + + // Proceed character by character through the statusline format string + // fmt_p is the current positon in the input buffer + for (char_u *fmt_p = usefmt; *fmt_p; ) { if (curitem == STL_MAX_ITEM) { - /* There are too many items. Add the error code to the statusline - * to give the user a hint about what went wrong. */ - if (p + 6 < out + outlen) { - memmove(p, " E541", (size_t)5); - p += 5; + // There are too many items. Add the error code to the statusline + // to give the user a hint about what went wrong. + if (out_p + 5 < out_end_p) { + memmove(out_p, " E541", (size_t)5); + out_p += 5; } break; } - if (*s != NUL && *s != '%') - prevchar_isflag = prevchar_isitem = FALSE; + if (*fmt_p != NUL && *fmt_p != '%') { + prevchar_isflag = prevchar_isitem = false; + } - /* - * Handle up to the next '%' or the end. - */ - while (*s != NUL && *s != '%' && p + 1 < out + outlen) - *p++ = *s++; - if (*s == NUL || p + 1 >= out + outlen) + // 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; - /* - * Handle one '%' item. - */ - s++; - if (*s == NUL) /* ignore trailing % */ + // 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; - if (*s == '%') { - if (p + 1 >= out + outlen) + } + + // Two `%` in a row is the escape sequence to print a + // single `%` in the output buffer. + if (*fmt_p == '%') { + // Ignore the character if we're out of room in the output buffer. + if (out_p >= out_end_p) break; - *p++ = *s++; - prevchar_isflag = prevchar_isitem = FALSE; + *out_p++ = *fmt_p++; + prevchar_isflag = prevchar_isitem = false; continue; } - if (*s == STL_MIDDLEMARK) { - s++; - if (groupdepth > 0) + + // STL_MIDDLEMARK: Separation place between left and right aligned items. + if (*fmt_p == STL_MIDDLEMARK) { + fmt_p++; + // Ignored when we are inside of a grouping + if (groupdepth > 0) { continue; + } item[curitem].type = Middle; - item[curitem++].start = p; + item[curitem++].start = out_p; continue; } - if (*s == STL_TRUNCMARK) { - s++; + + // STL_TRUNCMARK: Where to begin truncating if the statusline is too long. + if (*fmt_p == STL_TRUNCMARK) { + fmt_p++; item[curitem].type = Trunc; - item[curitem++].start = p; + item[curitem++].start = out_p; continue; } - if (*s == ')') { - s++; - if (groupdepth < 1) + + // 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--; - t = item[groupitem[groupdepth]].start; - *p = NUL; - l = vim_strsize(t); + // Determine how long the group is. + // Note: We set the current output position to null + // so `vim_strsize` will work. + char_u *t = item[groupitem[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 > groupitem[groupdepth] + 1 && item[groupitem[groupdepth]].minwid == 0) { - /* remove group if all items are empty */ - for (n = groupitem[groupdepth] + 1; n < curitem; n++) - if (item[n].type == Normal) + bool has_normal_items = false; + for (long n = groupitem[groupdepth] + 1; n < curitem; n++) { + if (item[n].type == Normal) { + has_normal_items = true; break; - if (n == curitem) { - p = t; - l = 0; + } + } + + if (!has_normal_items) { + out_p = t; + group_len = 0; } } - if (l > item[groupitem[groupdepth]].maxwid) { - /* truncate, remove n bytes of text at the start */ + + // 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 > item[groupitem[groupdepth]].maxwid) { + // { Determine the number of bytes to remove + long n; if (has_mbyte) { /* Find the first character that should be included. */ n = 0; - while (l >= item[groupitem[groupdepth]].maxwid) { - l -= ptr2cells(t + n); + while (group_len >= item[groupitem[groupdepth]].maxwid) { + group_len -= ptr2cells(t + n); n += (*mb_ptr2len)(t + n); } - } else - n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1; + } else { + n = (long)(out_p - t) - item[groupitem[groupdepth]].maxwid + 1; + } + // } + // Prepend the `<` to indicate that the output was truncated. *t = '<'; - memmove(t + 1, t + n, (size_t)(p - (t + n))); - p = p - n + 1; + + // { 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 (++l < item[groupitem[groupdepth]].minwid) - *p++ = fillchar; + while (++group_len < item[groupitem[groupdepth]].minwid) + *out_p++ = fillchar; + // } /* correct the start of the items for the truncation */ - for (l = groupitem[groupdepth] + 1; l < curitem; l++) { - item[l].start -= n; - if (item[l].start < t) - item[l].start = t; + for (int idx = groupitem[groupdepth] + 1; idx < curitem; idx++) { + // Shift everything back by the number of removed bytes + item[idx].start -= n; + + // If the item was partially or completely truncated, set its + // start to the start of the group + if (item[idx].start < t) { + item[idx].start = t; + } } - } else if (abs(item[groupitem[groupdepth]].minwid) > l) { - /* fill */ - n = item[groupitem[groupdepth]].minwid; - if (n < 0) { - /* fill by appending characters */ - n = 0 - n; - while (l++ < n && p + 1 < out + outlen) - *p++ = fillchar; + // If the group is shorter than the minimum width, add padding characters. + } else if (abs(item[groupitem[groupdepth]].minwid) > group_len) { + long min_group_width = item[groupitem[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) + *out_p++ = fillchar; + // If the group is right-aligned, shift everything to the right and + // prepend with filler characters. } else { - /* fill by inserting characters */ - memmove(t + n - l, t, (size_t)(p - t)); - l = n - l; - if (p + l >= out + outlen) - l = (long)((out + outlen) - p - 1); - p += l; - for (n = groupitem[groupdepth] + 1; n < curitem; n++) - item[n].start += l; - for (; l > 0; l--) + // { Move the group to the right + memmove(t + min_group_width - group_len, t, (size_t)(out_p - t)); + group_len = min_group_width - group_len; + 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 = groupitem[groupdepth] + 1; n < curitem; n++) { + item[n].start += group_len; + } + + // Prepend the fill characters + for (; group_len > 0; group_len--) { *t++ = fillchar; + } } } continue; } - minwid = 0; - maxwid = 9999; - zeropad = FALSE; - l = 1; - if (*s == '0') { - s++; - zeropad = TRUE; + 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++; } - if (*s == '-') { - s++; - l = -1; + + // Denotes that the item should be left-aligned. + // This is tracked by using a negative length. + if (*fmt_p == '-') { + fmt_p++; + left_align = true; } - if (ascii_isdigit(*s)) { - minwid = getdigits_int(&s); + + // The first digit group is the item's min width + if (ascii_isdigit(*fmt_p)) { + minwid = getdigits_int(&fmt_p); if (minwid < 0) /* overflow */ minwid = 0; } - if (*s == STL_USER_HL) { + + // User highlight groups override the min width field + // to denote the styling to use. + if (*fmt_p == STL_USER_HL) { item[curitem].type = Highlight; - item[curitem].start = p; + item[curitem].start = out_p; item[curitem].minwid = minwid > 9 ? 1 : minwid; - s++; + fmt_p++; curitem++; continue; } - if (*s == STL_TABPAGENR || *s == STL_TABCLOSENR) { - if (*s == STL_TABCLOSENR) { + + // 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 previously * define tab label nr. */ - for (n = curitem - 1; n >= 0; --n) + for (long n = curitem - 1; n >= 0; --n) if (item[n].type == TabPage && item[n].minwid >= 0) { minwid = item[n].minwid; break; @@ -3066,54 +3164,70 @@ build_stl_str_hl ( minwid = -minwid; } item[curitem].type = TabPage; - item[curitem].start = p; + item[curitem].start = out_p; item[curitem].minwid = minwid; - s++; + fmt_p++; curitem++; continue; } - if (*s == '.') { - s++; - if (ascii_isdigit(*s)) { - maxwid = getdigits_int(&s); + + // 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); if (maxwid <= 0) /* overflow */ maxwid = 50; } } - minwid = (minwid > 50 ? 50 : minwid) * l; - if (*s == '(') { + + // 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 == '(') { groupitem[groupdepth++] = curitem; item[curitem].type = Group; - item[curitem].start = p; + item[curitem].start = out_p; item[curitem].minwid = minwid; item[curitem].maxwid = maxwid; - s++; + fmt_p++; curitem++; continue; } - if (vim_strchr(STL_ALL, *s) == NULL) { - s++; + + // 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; } - opt = *s++; - - /* OK - now for the real work */ - base = 'D'; - itemisflag = FALSE; - fillable = TRUE; - num = -1; - str = NULL; + + // The status line item type + char_u opt = *fmt_p++; + + // OK - now for the real work + NumberBase base = kNumBaseDecimal; + bool itemisflag = false; + bool fillable = true; + long num = -1; + char_u *str = NULL; switch (opt) { case STL_FILEPATH: case STL_FULLPATH: case STL_FILENAME: - fillable = FALSE; /* don't change ' ' to fillchar */ - if (buf_spname(wp->w_buffer) != NULL) + { + // Set fillable to false to 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 { - t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname - : wp->w_buffer->b_fname; - home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, TRUE); + } else { + char_u *t = (opt == STL_FULLPATH) ? wp->w_buffer->b_ffname + : wp->w_buffer->b_fname; + home_replace(wp->w_buffer, t, NameBuff, MAXPATHL, true); } trans_characters(NameBuff, MAXPATHL); if (opt != STL_FILENAME) @@ -3121,42 +3235,59 @@ build_stl_str_hl ( else str = path_tail(NameBuff); break; - + } case STL_VIM_EXPR: /* '{' */ - itemisflag = TRUE; - t = p; - while (*s != '}' && *s != NUL && p + 1 < out + outlen) - *p++ = *s++; - if (*s != '}') /* missing '}' or out of space */ + { + itemisflag = true; + + // Attempt to copy the expression to evaluate into + // the output buffer as a null-terminated string. + char_u *t = out_p; + while (*fmt_p != '}' && *fmt_p != NUL && out_p < out_end_p) + *out_p++ = *fmt_p++; + if (*fmt_p != '}') /* missing '}' or out of space */ break; - s++; - *p = 0; - p = t; + fmt_p++; + *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((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum); set_internal_string_var((char_u *)"actual_curbuf", tmp); - o_curbuf = curbuf; - o_curwin = curwin; + buf_T *o_curbuf = curbuf; + win_T *o_curwin = curwin; curwin = wp; curbuf = wp->w_buffer; - str = eval_to_string_safe(p, &t, use_sandbox); + // Note: The result stored in `t` is unused. + str = eval_to_string_safe(out_p, &t, use_sandbox); curwin = o_curwin; curbuf = o_curbuf; - do_unlet((char_u *)"g:actual_curbuf", TRUE); + // Remove the variable we just stored + do_unlet((char_u *)"g:actual_curbuf", 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((char *)str); xfree(str); str = NULL; - itemisflag = FALSE; + itemisflag = false; } } break; - + } case STL_LINE: num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0L : (long)(wp->w_cursor.lnum); @@ -3173,21 +3304,23 @@ build_stl_str_hl ( case STL_VIRTCOL: case STL_VIRTCOL_ALT: - /* In list mode virtcol needs to be recomputed */ - virtcol = wp->w_virtcol; + { + // In list mode virtcol needs to be recomputed + colnr_T virtcol = wp->w_virtcol; if (wp->w_p_list && lcs_tab1 == NUL) { wp->w_p_list = FALSE; getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL); wp->w_p_list = TRUE; } ++virtcol; - /* Don't display %V if it's the same as %c. */ + // Don't display %V if it's the same as %c. if (opt == STL_VIRTCOL_ALT && (virtcol == (colnr_T)(!(State & INSERT) && 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) / @@ -3195,19 +3328,31 @@ build_stl_str_hl ( 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, tmp, TMPLEN); str = tmp; - get_rel_pos(wp, str, TMPLEN); break; case STL_ARGLISTSTAT: - fillable = FALSE; + 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. tmp[0] = 0; - if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE)) + + // Note: The call will only return true if it actually + // appended data to the `tmp` buffer. + if (append_arg_number(wp, tmp, (int)sizeof(tmp), false)) { str = tmp; + } break; case STL_KEYMAP: - fillable = FALSE; + fillable = false; if (get_keymap_str(wp, tmp, TMPLEN)) str = tmp; break; @@ -3220,16 +3365,17 @@ build_stl_str_hl ( break; case STL_OFFSET_X: - base = 'X'; + base = kNumBaseHexadecimal; case STL_OFFSET: - l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL); + { + long l = ml_find_line_or_offset(wp->w_buffer, wp->w_cursor.lnum, NULL); num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) || l < 0 ? 0L : l + 1 + (!(State & INSERT) && empty_line ? 0 : (int)wp->w_cursor.col); break; - + } case STL_BYTEVAL_X: - base = 'X'; + base = kNumBaseHexadecimal; case STL_BYTEVAL: num = byteval; if (num == NL) @@ -3240,20 +3386,23 @@ build_stl_str_hl ( case STL_ROFLAG: case STL_ROFLAG_ALT: - itemisflag = TRUE; + itemisflag = true; if (wp->w_buffer->b_p_ro) str = (char_u *)((opt == STL_ROFLAG_ALT) ? ",RO" : _("[RO]")); break; case STL_HELPFLAG: case STL_HELPFLAG_ALT: - itemisflag = TRUE; + itemisflag = true; if (wp->w_buffer->b_help) str = (char_u *)((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((char *)tmp, sizeof(tmp), "[%s]", @@ -3263,20 +3412,26 @@ build_stl_str_hl ( break; case STL_FILETYPE_ALT: - itemisflag = TRUE; + { + 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((char *)tmp, sizeof(tmp), ",%s", wp->w_buffer->b_p_ft); - for (t = tmp; *t != 0; t++) + // Uppercase the file extension + for (char_u *t = tmp; *t != 0; t++) { *t = TOUPPER_LOC(*t); + } str = tmp; } break; - + } case STL_PREVIEWFLAG: case STL_PREVIEWFLAG_ALT: - itemisflag = TRUE; + itemisflag = true; if (wp->w_p_pvw) str = (char_u *)((opt == STL_PREVIEWFLAG_ALT) ? ",PRV" : _("[Preview]")); @@ -3291,7 +3446,7 @@ build_stl_str_hl ( case STL_MODIFIED: case STL_MODIFIED_ALT: - itemisflag = TRUE; + itemisflag = true; switch ((opt == STL_MODIFIED_ALT) + bufIsChanged(wp->w_buffer) * 2 + (!MODIFIABLE(wp->w_buffer)) * 4) { @@ -3305,212 +3460,360 @@ build_stl_str_hl ( break; case STL_HIGHLIGHT: - t = s; - while (*s != '#' && *s != NUL) - ++s; - if (*s == '#') { + { + // { The name of the highlight is surrounded by `#` + char_u *t = fmt_p; + while (*fmt_p != '#' && *fmt_p != NUL) { + ++fmt_p; + } + // } + + // Create a highlight item based on the name + if (*fmt_p == '#') { item[curitem].type = Highlight; - item[curitem].start = p; - item[curitem].minwid = -syn_namen2id(t, (int)(s - t)); + item[curitem].start = out_p; + item[curitem].minwid = -syn_namen2id(t, (int)(fmt_p - t)); curitem++; + fmt_p++; } - if (*s != NUL) - ++s; continue; } + } - item[curitem].start = p; + // 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`. + item[curitem].start = out_p; item[curitem].type = Normal; + + // Copy the item string into the output buffer if (str != NULL && *str) { - t = str; + // { Skip the leading `,` or ` ` if the item is a flag + // and the proper conditions are met + char_u *t = str; if (itemisflag) { if ((t[0] && t[1]) && ((!prevchar_isitem && *t == ',') || (prevchar_isflag && *t == ' '))) t++; - prevchar_isflag = TRUE; + 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; } - l = vim_strsize(t); - if (l > 0) - prevchar_isitem = TRUE; + + // If the item is too wide, truncate it from the beginning if (l > maxwid) { while (l >= maxwid) if (has_mbyte) { l -= ptr2cells(t); t += (*mb_ptr2len)(t); - } else + } else { l -= byte2cells(*t++); - if (p + 1 >= out + outlen) + } + + // Early out if there isn't enough room for the truncation marker + if (out_p >= out_end_p) break; - *p++ = '<'; + + // 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 && p + 1 < out + outlen; l++) { - /* Don't put a "-" in front of a digit. */ + 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)) - *p++ = ' '; + *out_p++ = ' '; else - *p++ = fillchar; + *out_p++ = fillchar; } minwid = 0; - } else + } else { + // Note: The negative value denotes a left aligned item. + // Here we switch the minimum width back to a positive value. minwid *= -1; - while (*t && p + 1 < out + outlen) { - *p++ = *t++; - /* Change a space by fillchar, unless fillchar is '-' and a - * digit follows. */ - if (fillable && p[-1] == ' ' + } + + // { Copy the string text into the output buffer + while (*t && out_p < out_end_p) { + *out_p++ = *t++; + // Change a space by fillchar, unless fillchar is '-' and a + // digit follows. + if (fillable && out_p[-1] == ' ' && (!ascii_isdigit(*t) || fillchar != '-')) - p[-1] = fillchar; + out_p[-1] = fillchar; + } + // } + + // For left-aligned items, fill any remaining space with the fillchar + for (; l < minwid && out_p < out_end_p; l++) { + *out_p++ = fillchar; } - for (; l < minwid && p + 1 < out + outlen; l++) - *p++ = fillchar; - } else if (num >= 0) { - int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16)); - char_u nstr[20]; - if (p + 20 >= out + outlen) + // 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; - t = nstr; + prevchar_isitem = true; + + // { Build the formatting string + char_u nstr[20]; + char_u *t = nstr; if (opt == STL_VIRTCOL_ALT) { *t++ = '-'; minwid--; } *t++ = '%'; - if (zeropad) + if (zeropad) { *t++ = '0'; + } + + // Note: The `*` means we take the width as one of the arguments *t++ = '*'; - *t++ = nbase == 16 ? base : (char_u)(nbase == 8 ? 'o' : 'd'); + *t++ = (char_u) (base == kNumBaseHexadecimal ? 'X' + : (base == kNumBaseOctal ? 'o' + : '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++; + } - for (n = num, l = 1; n >= nbase; n /= nbase) - l++; - if (opt == STL_VIRTCOL_ALT) - l++; - if (l > maxwid) { - l += 2; - n = l - maxwid; - while (l-- > maxwid) - num /= nbase; + // VIRTCOL_ALT takes up an extra character because + // of the `-` we added above. + if (opt == STL_VIRTCOL_ALT) { + num_chars++; + } + // } + + size_t remaining_buf_len = (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 /= 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((char *)p, outlen - (p - out), (char *)nstr, + // } + + vim_snprintf((char *)out_p, remaining_buf_len, (char *)nstr, 0, num, n); - } else - vim_snprintf((char *)p, outlen - (p - out), (char *)nstr, + } else { + vim_snprintf((char *)out_p, remaining_buf_len, (char *)nstr, minwid, num); - p += STRLEN(p); - } else + } + + // 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 { item[curitem].type = Empty; + } - if (opt == STL_VIM_EXPR) + // 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(str); + } if (num >= 0 || (!itemisflag && str && *str)) - prevchar_isflag = FALSE; /* Item not NULL, but not a flag */ + prevchar_isflag = false; /* Item not NULL, but not a flag */ + + // Item processed, move to the next curitem++; } - *p = NUL; - itemcnt = curitem; - if (usefmt != fmt) + *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 factors. - width = vim_strsize(out); + int width = vim_strsize(out); if (maxwidth > 0 && width > maxwidth) { - /* Result is too long, must truncate somewhere. */ - l = 0; - if (itemcnt == 0) - s = out; - else { - for (; l < itemcnt; l++) - if (item[l].type == Trunc) { - /* Truncate at %< item. */ - s = item[l].start; + // Result is too long, must truncate somewhere. + int item_idx = 0; + char_u *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 = item[0].start; + item_idx = 0; + + for (int i = 0; i < itemcnt; i++) + if (item[i].type == Trunc) { + // Truncate at %< item. + trunc_p = item[i].start; + item_idx = i; break; } - if (l == itemcnt) { - /* No %< item, truncate first item. */ - s = item[0].start; - l = 0; - } } - if (width - vim_strsize(s) >= maxwidth) { - /* Truncation mark is beyond max length */ + // 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) { + // If we are using a multi-byte encoding, walk from the beginning of the + // string to find the last character that will fit. if (has_mbyte) { - s = out; + trunc_p = out; width = 0; for (;; ) { - width += ptr2cells(s); + width += ptr2cells(trunc_p); if (width >= maxwidth) break; - s += (*mb_ptr2len)(s); + + // Note: Only advance the pointer if the next + // character will fit in the available output space + trunc_p += (*mb_ptr2len)(trunc_p); } - /* Fill up for half a double-wide character. */ - while (++width < maxwidth) - *s++ = fillchar; - } else - s = out + maxwidth - 1; - for (l = 0; l < itemcnt; l++) - if (item[l].start > s) + + // Otherwise put the truncation point at the end, leaving enough room + // for a single-character truncation marker + } else { + trunc_p = out + maxwidth - 1; + } + + // Ignore any items in the statusline that occur after + // the truncation point + for (int i = 0; i < itemcnt; i++) { + if (item[i].start > trunc_p) { + itemcnt = i; break; - itemcnt = l; - *s++ = '>'; - *s = 0; + } + } + + // 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; if (has_mbyte) { - n = 0; + trunc_len = 0; while (width >= maxwidth) { - width -= ptr2cells(s + n); - n += (*mb_ptr2len)(s + n); + width -= ptr2cells(trunc_p + trunc_len); + trunc_len += (*mb_ptr2len)(trunc_p + trunc_len); } - } else - n = width - maxwidth + 1; - p = s + n; - STRMOVE(s + 1, p); - *s = '<'; + } else { + // Truncate an extra character so we can insert our `<`. + trunc_len = (width - maxwidth) + 1; + } + // } - /* Fill up for half a double-wide character. */ + // { Truncate the string + char_u *trunc_end_p = trunc_p + trunc_len; + STRMOVE(trunc_p + 1, trunc_end_p); + + // Put a `<` to mark where we truncated at + *trunc_p = '<'; + + // 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) { - s = s + STRLEN(s); - *s++ = fillchar; - *s = NUL; + *trunc_p++ = fillchar; + *trunc_p = NUL; } - - --n; /* count the '<' */ - for (; l < itemcnt; l++) { - if (item[l].start - n >= s) - item[l].start -= n; - else - item[l].start = s; + // } + + // { 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 (item[i].start >= trunc_end_p) { + item[i].start -= item_offset; + // Anything inside the truncated area is set to start + // at the `<` truncation character. + } else { + item[i].start = trunc_p; + } } + // } } width = maxwidth; - } else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < - outlen) { - /* Apply STL_MIDDLE if any */ - for (l = 0; l < itemcnt; l++) - if (item[l].type == Middle) + + // If there is room left in our statusline, and room left in our buffer, + // add characters at the middle marker (if there is one) to + // fill up the available space. + } else if (width < maxwidth + && STRLEN(out) + maxwidth - width + 1 < outlen) { + for (int item_idx = 0; item_idx < itemcnt; item_idx++) { + if (item[item_idx].type == Middle) { + // Move the statusline to make room for the middle characters + char_u *middle_end = item[item_idx].start + (maxwidth - width); + STRMOVE(middle_end, item[item_idx].start); + + // Fill the middle section with our fill character + for (char_u *s = item[item_idx].start; s < middle_end; s++) + *s = fillchar; + + // Adjust the offset of any items after the middle + for (item_idx++; item_idx < itemcnt; item_idx++) + item[item_idx].start += maxwidth - width; + + width = maxwidth; break; - if (l < itemcnt) { - p = item[l].start + maxwidth - width; - STRMOVE(p, item[l].start); - for (s = item[l].start; s < p; s++) - *s = fillchar; - for (l++; l < itemcnt; l++) - item[l].start += maxwidth - width; - width = maxwidth; + } } } - /* Store the info about highlighting. */ + // Store the info about highlighting. if (hltab != NULL) { - sp = hltab; - for (l = 0; l < itemcnt; l++) { + struct stl_hlrec *sp = hltab; + for (long l = 0; l < itemcnt; l++) { if (item[l].type == Highlight) { sp->start = item[l].start; sp->userhl = item[l].minwid; @@ -3521,10 +3824,10 @@ build_stl_str_hl ( sp->userhl = 0; } - /* Store the info about tab pages labels. */ + // Store the info about tab pages labels. if (tabtab != NULL) { - sp = tabtab; - for (l = 0; l < itemcnt; l++) { + struct stl_hlrec *sp = tabtab; + for (long l = 0; l < itemcnt; l++) { if (item[l].type == TabPage) { sp->start = item[l].start; sp->userhl = item[l].minwid; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 6e2b3056e4..d311588ab4 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -2,7 +2,6 @@ /// /// Code for diff'ing two, three or four buffers. -#include <errno.h> #include <inttypes.h> #include <stdbool.h> diff --git a/src/nvim/edit.c b/src/nvim/edit.c index abd16e57ae..08b587df8a 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <string.h> #include <inttypes.h> #include <stdbool.h> @@ -977,6 +976,14 @@ static int insert_handle_key(InsertState *s) queue_process_events(loop.events); break; + case K_FOCUSGAINED: // Neovim has been given focus + apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf); + break; + + case K_FOCUSLOST: // Neovim has lost focus + apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf); + break; + case K_HOME: // <Home> case K_KHOME: case K_S_HOME: diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9581b81456..cec7c91c03 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -4,7 +4,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -12,7 +12,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdarg.h> #include <string.h> diff --git a/src/nvim/event/socket.c b/src/nvim/event/socket.c index 347e464d25..93cc592683 100644 --- a/src/nvim/event/socket.c +++ b/src/nvim/event/socket.c @@ -97,7 +97,7 @@ int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb) result = uv_listen(watcher->stream, backlog, connection_cb); } - assert(result <= 0); // libuv should have returned -errno or zero. + assert(result <= 0); // libuv should return negative error code or zero. if (result < 0) { if (result == -EACCES) { // Libuv converts ENOENT to EACCES for Windows compatibility, but if diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index 376eb9fce7..71582ab357 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -13,7 +13,7 @@ /// Sets the stream associated with `fd` to "blocking" mode. /// -/// @return `0` on success, or `-errno` on failure. +/// @return `0` on success, or libuv error code on failure. int stream_set_blocking(int fd, bool blocking) { // Private loop to avoid conflict with existing watcher(s): diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index c4fffcda71..f69910eb99 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <stdbool.h> #include <string.h> #include <stdlib.h> diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 79b53b9fb5..b7a3505c99 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -989,13 +989,13 @@ return { command='gui', flags=bit.bor(BANG, FILES, EDITCMD, ARGOPT, TRLBAR, CMDWIN), addr_type=ADDR_LINES, - func='ex_gui', + func='ex_nogui', }, { command='gvim', flags=bit.bor(BANG, FILES, EDITCMD, ARGOPT, TRLBAR, CMDWIN), addr_type=ADDR_LINES, - func='ex_gui', + func='ex_nogui', }, { command='help', @@ -1013,7 +1013,7 @@ return { command='helpfind', flags=bit.bor(EXTRA, NOTRLCOM), addr_type=ADDR_LINES, - func='ex_helpfind', + func='ex_ni', }, { command='helpgrep', @@ -1643,19 +1643,19 @@ return { command='nbkey', flags=bit.bor(EXTRA, NOTADR, NEEDARG), addr_type=ADDR_LINES, - func='ex_nbkey', + func='ex_ni', }, { command='nbclose', flags=bit.bor(TRLBAR, CMDWIN), addr_type=ADDR_LINES, - func='ex_nbclose', + func='ex_ni', }, { command='nbstart', flags=bit.bor(WORD1, TRLBAR, CMDWIN), addr_type=ADDR_LINES, - func='ex_nbstart', + func='ex_ni', }, { command='new', @@ -1859,7 +1859,7 @@ return { command='popup', flags=bit.bor(NEEDARG, EXTRA, BANG, TRLBAR, NOTRLCOM, CMDWIN), addr_type=ADDR_LINES, - func='ex_popup', + func='ex_ni', }, { command='ppop', @@ -1883,13 +1883,13 @@ return { command='promptfind', flags=bit.bor(EXTRA, NOTRLCOM, CMDWIN), addr_type=ADDR_LINES, - func='gui_mch_find_dialog', + func='ex_ni', }, { command='promptrepl', flags=bit.bor(EXTRA, NOTRLCOM, CMDWIN), addr_type=ADDR_LINES, - func='gui_mch_replace_dialog', + func='ex_ni', }, { command='profile', @@ -2303,7 +2303,7 @@ return { command='simalt', flags=bit.bor(NEEDARG, WORD1, TRLBAR, CMDWIN), addr_type=ADDR_LINES, - func='ex_simalt', + func='ex_ni', }, { command='sign', @@ -3029,7 +3029,7 @@ return { command='wsverb', flags=bit.bor(EXTRA, NOTADR, NEEDARG), addr_type=ADDR_LINES, - func='ex_wsverb', + func='ex_ni', }, { command='wshada', diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index a632a3cce4..bb629fad76 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 7b5e3939f2..b50c7330d3 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -14,7 +14,6 @@ #include <string.h> #include <stdbool.h> #include <stdint.h> -#include <errno.h> #include <inttypes.h> #include "nvim/vim.h" @@ -80,6 +79,9 @@ static int quitmore = 0; static int ex_pressedreturn = FALSE; +/* whether ":lcd" was produced for a session */ +static int did_lcd; + typedef struct ucmd { char_u *uc_name; /* The command name */ uint32_t uc_argt; /* The argument type */ @@ -144,23 +146,9 @@ struct dbg_stuff { # include "ex_docmd.c.generated.h" #endif -# define ex_gui ex_nogui -# define ex_popup ex_ni -# define ex_simalt ex_ni -# define gui_mch_find_dialog ex_ni -# define gui_mch_replace_dialog ex_ni -# define ex_helpfind ex_ni -static int did_lcd; /* whether ":lcd" was produced for a session */ #ifndef HAVE_WORKING_LIBINTL # define ex_language ex_ni #endif -# define ex_wsverb ex_ni -# define ex_nbclose ex_ni -# define ex_nbkey ex_ni -# define ex_nbstart ex_ni - - - /* * Declare cmdnames[]. diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index bea1aecb58..773005e72b 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 52292128d8..c9a324b49f 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <stdbool.h> #include <string.h> #include <stdlib.h> @@ -1448,6 +1447,14 @@ static int command_line_handle_key(CommandLineState *s) } return command_line_not_changed(s); + case K_FOCUSGAINED: // Neovim has been given focus + apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf); + return command_line_not_changed(s); + + case K_FOCUSLOST: // Neovim has lost focus + apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf); + return command_line_not_changed(s); + default: // Normal character with no special meaning. Just set mod_mask // to 0x0 so that typing Shift-Space in the GUI doesn't enter diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index fbff7d2417..4f345158cf 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -45,7 +45,6 @@ */ #include <assert.h> -#include <errno.h> #include <string.h> #include <stdbool.h> #include <stdint.h> diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index a7472b40e2..4aa4d4c399 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -535,11 +535,7 @@ readfile ( if (!newfile) { return FAIL; } - if (perm < 0 -#ifdef ENOENT - && errno == ENOENT -#endif - ) { + if (perm == UV_ENOENT) { /* * Set the 'new-file' flag, so that when the file has * been created by someone else, a ":w" will complain. @@ -582,11 +578,11 @@ readfile ( return OK; /* a new file is not an error */ } else { filemess(curbuf, sfname, (char_u *)( -# ifdef EFBIG - (errno == EFBIG) ? _("[File too big]") : -# endif -# ifdef EOVERFLOW - (errno == EOVERFLOW) ? _("[File too big]") : + (fd == UV_EFBIG) ? _("[File too big]") : +# if defined(UNIX) && defined(EOVERFLOW) + // libuv only returns -errno in Unix and in Windows open() does not + // set EOVERFLOW + (fd == -EOVERFLOW) ? _("[File too big]") : # endif _("[Permission Denied]")), 0); curbuf->b_p_ro = TRUE; /* must use "w!" now */ diff --git a/src/nvim/fold.c b/src/nvim/fold.c index b52938075c..29921bc816 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -4,7 +4,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index b77a030158..3692fa27aa 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index 819015a85d..9f7431ee7d 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <string.h> #include <inttypes.h> #include <stdint.h> diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index e5cbb58608..578ae5de1e 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -5,7 +5,7 @@ * The basic idea/structure of cscope for Vim was borrowed from Nvi. There * might be a few lines of code that look similar to what Nvi has. * - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ #include <stdbool.h> diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 9d656276ec..85380ba173 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -284,6 +284,8 @@ static struct key_name_entry { {K_SNR, (char_u *)"SNR"}, {K_PLUG, (char_u *)"Plug"}, {K_PASTE, (char_u *)"Paste"}, + {K_FOCUSGAINED, (char_u *)"FocusGained"}, + {K_FOCUSLOST, (char_u *)"FocusLost"}, {0, NULL} }; diff --git a/src/nvim/main.c b/src/nvim/main.c index 83fe32cccb..203aeb8d69 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -3,12 +3,11 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ #define EXTERN #include <assert.h> -#include <errno.h> #include <stdint.h> #include <string.h> #include <stdbool.h> diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 0432ec5cef..38a76a45e6 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <string.h> #include <limits.h> diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 087d2e677c..fc7199e3a6 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -4,7 +4,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* * mbyte.c: Code specifically for handling multi-byte characters. @@ -71,7 +71,6 @@ * some commands, like ":menutrans" */ -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index b6a341d5e8..b2783736e1 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /// An abstraction to handle blocks of memory which can be stored in a file. @@ -44,7 +44,6 @@ /// mf_fullname() make file name full path (use before first :cd) #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <limits.h> #include <string.h> diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 85f545f960..e822a58273 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* for debugging */ diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 6d386f3599..8db47b79c1 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -1,7 +1,6 @@ // Various routines dealing with allocation and deallocation of memory. #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <string.h> #include <stdbool.h> diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 9857b8a778..3859ba5ec8 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -4,7 +4,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* diff --git a/src/nvim/message.c b/src/nvim/message.c index 5f06506a31..52e2a286c3 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <stdarg.h> diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 5097255880..0ba6929686 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/misc2.c b/src/nvim/misc2.c index d9bc35470f..d72a8f17e0 100644 --- a/src/nvim/misc2.c +++ b/src/nvim/misc2.c @@ -3,14 +3,13 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* * misc2.c: Various functions. */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <string.h> diff --git a/src/nvim/move.c b/src/nvim/move.c index 3831004703..b44d3f2fd9 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* * move.c: Functions for moving the cursor and scrolling text. diff --git a/src/nvim/normal.c b/src/nvim/normal.c index d6bc416c91..a0d2c7903d 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* * normal.c: Contains the main routine for processing characters in command @@ -12,7 +12,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <string.h> #include <stdbool.h> @@ -349,6 +348,8 @@ static const struct nv_cmd { {K_F8, farsi_fkey, 0, 0}, {K_F9, farsi_fkey, 0, 0}, {K_EVENT, nv_event, NV_KEEPREG, 0}, + {K_FOCUSGAINED, nv_focusgained, NV_KEEPREG, 0}, + {K_FOCUSLOST, nv_focuslost, NV_KEEPREG, 0}, }; /* Number of commands in nv_cmds[]. */ @@ -7715,6 +7716,18 @@ static void nv_event(cmdarg_T *cap) cap->retval |= CA_COMMAND_BUSY; // don't call edit() now } +/// Trigger FocusGained event. +static void nv_focusgained(cmdarg_T *cap) +{ + apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf); +} + +/// Trigger FocusLost event. +static void nv_focuslost(cmdarg_T *cap) +{ + apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf); +} + /* * Return TRUE when 'mousemodel' is set to "popup" or "popup_setpos". */ diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 3fd2c0b773..6693ca23c8 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* diff --git a/src/nvim/option.c b/src/nvim/option.c index cc4df28837..8b4aab88a3 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -30,7 +30,6 @@ #define IN_OPTION_C #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <stdint.h> diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 633eabab60..b22e994efe 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -51,15 +51,6 @@ return { defaults={if_true={vi=224}} }, { - full_name='antialias', abbreviation='anti', - type='bool', scope={'global'}, - vi_def=true, - vim=true, - redraw={'everything'}, - enable_if=false, - defaults={if_true={vi=false, vim=false}} - }, - { full_name='arabic', abbreviation='arab', type='bool', scope={'window'}, vi_def=true, diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 3fb00eb24e..d59b66e773 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -185,13 +185,13 @@ static bool is_executable_in_path(const char_u *name, char_u **abspath) /// Opens or creates a file and returns a non-negative integer representing /// the lowest-numbered unused file descriptor, for use in subsequent system -/// calls (read, write, lseek, fcntl, etc.). If the operation fails, `-errno` -/// is returned, and no file is created or modified. +/// calls (read, write, lseek, fcntl, etc.). If the operation fails, a libuv +/// error code is returned, and no file is created or modified. /// /// @param flags Bitwise OR of flags defined in <fcntl.h> /// @param mode Permissions for the newly-created file (IGNORED if 'flags' is /// not `O_CREAT` or `O_TMPFILE`), subject to the current umask -/// @return file descriptor, or negative `errno` on failure +/// @return file descriptor, or libuv error code on failure int os_open(const char* path, int flags, int mode) FUNC_ATTR_NONNULL_ALL { @@ -204,28 +204,29 @@ int os_open(const char* path, int flags, int mode) /// Get stat information for a file. /// -/// @return OK on success, FAIL if a failure occurred. -static bool os_stat(const char *name, uv_stat_t *statbuf) +/// @return libuv return code. +static int os_stat(const char *name, uv_stat_t *statbuf) FUNC_ATTR_NONNULL_ALL { uv_fs_t request; int result = uv_fs_stat(&fs_loop, &request, name, NULL); *statbuf = request.statbuf; uv_fs_req_cleanup(&request); - return (result == kLibuvSuccess); + return result; } /// Get the file permissions for a given file. /// -/// @return `-1` when `name` doesn't exist. +/// @return libuv error code on error. int32_t os_getperm(const char_u *name) FUNC_ATTR_NONNULL_ALL { uv_stat_t statbuf; - if (os_stat((char *)name, &statbuf)) { + int stat_result = os_stat((char *)name, &statbuf); + if (stat_result == kLibuvSuccess) { return (int32_t)statbuf.st_mode; } else { - return -1; + return stat_result; } } @@ -270,7 +271,7 @@ bool os_file_exists(const char_u *name) FUNC_ATTR_NONNULL_ALL { uv_stat_t statbuf; - return os_stat((char *)name, &statbuf); + return os_stat((char *)name, &statbuf) == kLibuvSuccess; } /// Check if a file is readable. @@ -322,7 +323,7 @@ int os_rename(const char_u *path, const char_u *new_path) /// Make a directory. /// -/// @return `0` for success, -errno for failure. +/// @return `0` for success, libuv error code for failure. int os_mkdir(const char *path, int32_t mode) FUNC_ATTR_NONNULL_ALL { @@ -342,7 +343,7 @@ int os_mkdir(const char *path, int32_t mode) /// failed to create. I.e. it will contain dir or any /// of the higher level directories. /// -/// @return `0` for success, -errno for failure. +/// @return `0` for success, libuv error code for failure. int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_dir) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT @@ -470,7 +471,7 @@ int os_remove(const char *path) bool os_fileinfo(const char *path, FileInfo *file_info) FUNC_ATTR_NONNULL_ALL { - return os_stat(path, &(file_info->stat)); + return os_stat(path, &(file_info->stat)) == kLibuvSuccess; } /// Get the file information for a given path without following links @@ -572,7 +573,7 @@ bool os_fileid(const char *path, FileID *file_id) FUNC_ATTR_NONNULL_ALL { uv_stat_t statbuf; - if (os_stat(path, &statbuf)) { + if (os_stat(path, &statbuf) == kLibuvSuccess) { file_id->inode = statbuf.st_ino; file_id->device_id = statbuf.st_dev; return true; diff --git a/src/nvim/os/fs_defs.h b/src/nvim/os/fs_defs.h index df1031b721..52b2841514 100644 --- a/src/nvim/os/fs_defs.h +++ b/src/nvim/os/fs_defs.h @@ -21,9 +21,9 @@ typedef struct { uv_dirent_t ent; ///< @private The entry information. } Directory; -/// Function to convert -errno error to char * error description +/// Function to convert libuv error to char * error description /// -/// -errno errors are returned by a number of os functions. +/// negative libuv error codes are returned by a number of os functions. #define os_strerror uv_strerror #endif // NVIM_OS_FS_DEFS_H diff --git a/src/nvim/os/os_defs.h b/src/nvim/os/os_defs.h index 3d56115401..55a2d5513e 100644 --- a/src/nvim/os/os_defs.h +++ b/src/nvim/os/os_defs.h @@ -103,9 +103,9 @@ # include <strings.h> #endif -/// Function to convert -errno error to char * error description +/// Function to convert libuv error to char * error description /// -/// -errno errors are returned by a number of os functions. +/// negative libuv error codes are returned by a number of os functions. #define os_strerror uv_strerror #endif // NVIM_OS_OS_DEFS_H diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h index d614582250..bfd431c9c6 100644 --- a/src/nvim/os/win_defs.h +++ b/src/nvim/os/win_defs.h @@ -28,7 +28,9 @@ # endif #endif +#ifdef _MSC_VER typedef SSIZE_T ssize_t; +#endif #ifndef SSIZE_MAX # ifdef _WIN64 diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index 828ccd556d..ddb799f23d 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* diff --git a/src/nvim/path.c b/src/nvim/path.c index eaca85ed40..a14ba38508 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1,6 +1,5 @@ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <stdlib.h> diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 4d53238381..8be010c560 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 0c4cf30602..bea09fd804 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -87,7 +87,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/search.c b/src/nvim/search.c index a44b0e00c7..89c96fe31e 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -3,14 +3,13 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* * search.c: code for normal mode searching commands */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> @@ -4623,6 +4622,7 @@ void set_search_pattern(const SearchPattern pat) { free_spat(&spats[0]); memcpy(&(spats[0]), &pat, sizeof(spats[0])); + set_vv_searchforward(); } /// Set last substitute pattern diff --git a/src/nvim/shada.c b/src/nvim/shada.c index f8643fe655..e21c6f17fe 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -43,6 +43,7 @@ #include "nvim/path.h" #include "nvim/fileio.h" #include "nvim/strings.h" +#include "nvim/quickfix.h" #include "nvim/lib/khash.h" #include "nvim/lib/kvec.h" @@ -98,6 +99,7 @@ KHASH_SET_INIT_STR(strset) #define SEARCH_KEY_HIGHLIGHTED "sh" #define SEARCH_KEY_OFFSET "so" #define SEARCH_KEY_PAT "sp" +#define SEARCH_KEY_BACKWARD "sb" #define REG_KEY_TYPE "rt" #define REG_KEY_WIDTH "rw" @@ -263,6 +265,7 @@ typedef struct { bool is_last_used; bool is_substitute_pattern; bool highlighted; + bool search_backward; char *pat; dict_T *additional_data; } search_pattern; @@ -455,6 +458,7 @@ static const ShadaEntry sd_default_values[] = { .is_last_used = true, .is_substitute_pattern = false, .highlighted = false, + .search_backward = false, .pat = NULL, .additional_data = NULL), DEF_SDE(SubString, sub_string, .sub = NULL, .additional_elements = NULL), @@ -812,7 +816,7 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, /// /// All arguments are passed to os_open(). /// -/// @return file descriptor or -errno on failure. +/// @return file descriptor or libuv error on failure. static int open_file(const char *const fname, const int flags, const int mode) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { @@ -822,15 +826,15 @@ open_file_start: fd = os_open(fname, flags, mode); if (fd < 0) { - if (-fd == ENOENT) { + if (fd == UV_ENOENT) { return fd; } - if (-fd == ENOMEM && !did_try_to_free) { + if (fd == UV_ENOMEM && !did_try_to_free) { try_to_free_memory(); did_try_to_free = true; goto open_file_start; } - if (-fd != EEXIST) { + if (fd != UV_EEXIST) { emsg3(_(SERR "System error while opening ShaDa file %s: %s"), fname, os_strerror(fd)); } @@ -844,7 +848,7 @@ open_file_start: /// @param[in] fname File name to open. /// @param[out] sd_reader Location where reader structure will be saved. /// -/// @return -errno in case of error, 0 otherwise. +/// @return libuv error in case of error, 0 otherwise. static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader) FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL @@ -962,7 +966,7 @@ static int shada_read_file(const char *const file, const int flags) } if (of_ret != 0) { - if (-of_ret == ENOENT && (flags & kShaDaMissingError)) { + if (of_ret == UV_ENOENT && (flags & kShaDaMissingError)) { emsg3(_(SERR "System error while opening ShaDa file %s for reading: %s"), fname, os_strerror(of_ret)); } @@ -1338,6 +1342,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) .magic = cur_entry.data.search_pattern.magic, .no_scs = !cur_entry.data.search_pattern.smartcase, .off = { + .dir = cur_entry.data.search_pattern.search_backward ? '?' : '/', .line = cur_entry.data.search_pattern.has_line_offset, .end = cur_entry.data.search_pattern.place_cursor_at_end, .off = cur_entry.data.search_pattern.offset, @@ -1754,6 +1759,7 @@ static bool shada_pack_entry(msgpack_packer *const packer, + ONE_IF_NOT_DEFAULT(entry, search_pattern.is_substitute_pattern) + ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted) + ONE_IF_NOT_DEFAULT(entry, search_pattern.offset) + + ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward) // finally, additional data: + (size_t) ( entry.data.search_pattern.additional_data @@ -1780,6 +1786,7 @@ static bool shada_pack_entry(msgpack_packer *const packer, PACK_BOOL(entry, SEARCH_KEY_PLACE_CURSOR_AT_END, place_cursor_at_end); PACK_BOOL(entry, SEARCH_KEY_IS_SUBSTITUTE_PATTERN, is_substitute_pattern); PACK_BOOL(entry, SEARCH_KEY_HIGHLIGHTED, highlighted); + PACK_BOOL(entry, SEARCH_KEY_BACKWARD, search_backward); if (!CHECK_DEFAULT(entry, search_pattern.offset)) { PACK_STATIC_STR(SEARCH_KEY_OFFSET); msgpack_pack_int64(spacker, entry.data.search_pattern.offset); @@ -2478,8 +2485,11 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, // Write buffer list if (find_shada_parameter('%') != NULL) { size_t buf_count = 0; +#define IGNORE_BUF(buf)\ + (buf->b_ffname == NULL || !buf->b_p_bl || bt_quickfix(buf) \ + || in_bufset(&removable_bufs, buf)) FOR_ALL_BUFFERS(buf) { - if (buf->b_ffname != NULL && !in_bufset(&removable_bufs, buf)) { + if (!IGNORE_BUF(buf)) { buf_count++; } } @@ -2497,7 +2507,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, }; size_t i = 0; FOR_ALL_BUFFERS(buf) { - if (buf->b_ffname == NULL || in_bufset(&removable_bufs, buf)) { + if (IGNORE_BUF(buf)) { continue; } buflist_entry.data.buffer_list.buffers[i] = (struct buffer_list_buffer) { @@ -2513,6 +2523,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, goto shada_write_exit; } xfree(buflist_entry.data.buffer_list.buffers); +#undef IGNORE_BUF } // Write some of the variables @@ -2581,6 +2592,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, && search_highlighted), \ .pat = (char *) pat.pat, \ .additional_data = pat.additional_data, \ + .search_backward = (!is_sub && pat.off.dir == '?'), \ } \ } \ } \ @@ -2957,9 +2969,9 @@ shada_write_file_open: fd = (intptr_t) open_file(tempname, O_CREAT|O_WRONLY|O_NOFOLLOW|O_EXCL, perm); if (fd < 0) { - if (-fd == EEXIST + if (fd == UV_EEXIST #ifdef ELOOP - || -fd == ELOOP + || fd == UV_ELOOP #endif ) { // File already exists, try another name @@ -3633,6 +3645,9 @@ shada_read_next_item_start: BOOLEAN_KEY("search pattern", SEARCH_KEY_HIGHLIGHTED, entry->data.search_pattern.highlighted) else + BOOLEAN_KEY("search pattern", SEARCH_KEY_BACKWARD, + entry->data.search_pattern.search_backward) + else INTEGER_KEY("search pattern", SEARCH_KEY_OFFSET, entry->data.search_pattern.offset) else diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 7d9257141a..a5b66ad220 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -2,7 +2,7 @@ // // Do ":help uganda" in Vim to read copying and usage conditions. // Do ":help credits" in Vim to see a list of people who contributed. -// See README.txt for an overview of the Vim source code. +// See README.md for an overview of the Vim source code. // spell.c: code for spell checking // @@ -285,7 +285,6 @@ // few bytes as possible, see offset2bytes()) #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <limits.h> #include <stdbool.h> diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 9ffa5c6a76..4bd394cb44 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1,5 +1,4 @@ -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index d0491ab42b..f65b21a40b 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -12,7 +12,6 @@ #include <assert.h> #include <ctype.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/tag.c b/src/nvim/tag.c index b0d1a17c89..1b3fda8aca 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -11,7 +11,6 @@ */ #include <assert.h> -#include <errno.h> #include <inttypes.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 119ee2c5b3..adf3f725a2 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -402,6 +402,14 @@ static int terminal_execute(VimState *state, int key) TerminalState *s = (TerminalState *)state; switch (key) { + case K_FOCUSGAINED: // Neovim has been given focus + apply_autocmds(EVENT_FOCUSGAINED, NULL, NULL, false, curbuf); + break; + + case K_FOCUSLOST: // Neovim has lost focus + apply_autocmds(EVENT_FOCUSLOST, NULL, NULL, false, curbuf); + break; + case K_LEFTMOUSE: case K_LEFTDRAG: case K_LEFTRELEASE: diff --git a/src/nvim/terminal.h b/src/nvim/terminal.h index 6e0b062fbd..25e609fb68 100644 --- a/src/nvim/terminal.h +++ b/src/nvim/terminal.h @@ -18,15 +18,6 @@ typedef struct { terminal_close_cb close_cb; } TerminalOptions; -#define TERMINAL_OPTIONS_INIT ((TerminalOptions) { \ - .data = NULL, \ - .width = 80, \ - .height = 24, \ - .write_cb = NULL, \ - .resize_cb = NULL, \ - .close_cb = NULL \ - }) - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "terminal.h.generated.h" #endif diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 654b857301..b41e4d2fba 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -10,6 +10,8 @@ #include "nvim/event/rstream.h" #define PASTETOGGLE_KEY "<Paste>" +#define FOCUSGAINED_KEY "<FocusGained>" +#define FOCUSLOST_KEY "<FocusLost>" #define KEY_BUFFER_SIZE 0xfff #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -252,6 +254,32 @@ static void timer_cb(TimeWatcher *watcher, void *data) flush_input(data, true); } +/// Handle focus events. +/// +/// If the upcoming sequence of bytes in the input stream matches either the +/// escape code for focus gained `<ESC>[I` or focus lost `<ESC>[O` then consume +/// that sequence and push the appropriate event into the input queue +/// +/// @param input the input stream +/// @return true iff handle_focus_event consumed some input +static bool handle_focus_event(TermInput *input) +{ + if (rbuffer_size(input->read_stream.buffer) > 2 + && (!rbuffer_cmp(input->read_stream.buffer, "\x1b[I", 3) + || !rbuffer_cmp(input->read_stream.buffer, "\x1b[O", 3))) { + // Advance past the sequence + bool focus_gained = *rbuffer_get(input->read_stream.buffer, 2) == 'I'; + rbuffer_consumed(input->read_stream.buffer, 3); + if (focus_gained) { + enqueue_input(input, FOCUSGAINED_KEY, sizeof(FOCUSGAINED_KEY) - 1); + } else { + enqueue_input(input, FOCUSLOST_KEY, sizeof(FOCUSLOST_KEY) - 1); + } + return true; + } + return false; +} + static bool handle_bracketed_paste(TermInput *input) { if (rbuffer_size(input->read_stream.buffer) > 5 && @@ -314,7 +342,9 @@ static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, } do { - if (handle_bracketed_paste(input) || handle_forced_escape(input)) { + if (handle_focus_event(input) + || handle_bracketed_paste(input) + || handle_forced_escape(input)) { continue; } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 02efa1f8df..7f7d138358 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -66,6 +66,7 @@ typedef struct { int enable_bracketed_paste, disable_bracketed_paste; int enter_insert_mode, enter_replace_mode, exit_insert_mode; int set_rgb_foreground, set_rgb_background; + int enable_focus_reporting, disable_focus_reporting; } unibi_ext; } TUIData; @@ -120,6 +121,8 @@ static void terminfo_start(UI *ui) data->unibi_ext.enter_insert_mode = -1; data->unibi_ext.enter_replace_mode = -1; data->unibi_ext.exit_insert_mode = -1; + data->unibi_ext.enable_focus_reporting = -1; + data->unibi_ext.disable_focus_reporting = -1; data->out_fd = 1; data->out_isatty = os_isatty(data->out_fd); // setup unibilium @@ -135,6 +138,8 @@ static void terminfo_start(UI *ui) unibi_out(ui, unibi_clear_screen); // Enable bracketed paste unibi_out(ui, data->unibi_ext.enable_bracketed_paste); + // Enable focus reporting + unibi_out(ui, data->unibi_ext.enable_focus_reporting); uv_loop_init(&data->write_loop); if (data->out_isatty) { uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0); @@ -157,6 +162,8 @@ static void terminfo_stop(UI *ui) unibi_out(ui, unibi_exit_ca_mode); // Disable bracketed paste unibi_out(ui, data->unibi_ext.disable_bracketed_paste); + // Disable focus reporting + unibi_out(ui, data->unibi_ext.disable_focus_reporting); flush_buf(ui); uv_tty_reset_mode(); uv_close((uv_handle_t *)&data->output_handle, NULL); @@ -807,6 +814,11 @@ static void fix_terminfo(TUIData *data) data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, NULL, "\x1b[?2004l"); + data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, NULL, + "\x1b[?1004h"); + data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, NULL, + "\x1b[?1004l"); + #define XTERM_SETAF \ "\x1b[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m" #define XTERM_SETAB \ diff --git a/src/nvim/undo.c b/src/nvim/undo.c index b0c49cbf8e..6c87f01746 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -3,7 +3,7 @@ * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ /* @@ -83,7 +83,6 @@ #include <assert.h> #include <inttypes.h> #include <limits.h> -#include <errno.h> #include <stdbool.h> #include <string.h> diff --git a/src/nvim/version.c b/src/nvim/version.c index f5e43878e4..d5bbd734f4 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -74,86 +74,92 @@ static char *features[] = { // clang-format off static int included_patches[] = { + // 922, + // 921 NA + // 920 NA + // 919 NA + // 918 NA + // 917 NA 916, // 915, // 914, - // 913, + // 913 NA // 912, - // 911, - // 910, + // 911 NA + // 910 NA // 909, - // 908, - // 907, - // 906, + // 908 NA + // 907 NA + // 906 NA // 905, // 904, // 903, - // 902, + // 902 NA // 901, - // 900, - // 899, + // 900 NA + // 899 NA // 898, // 897, // 896, // 895, - // 894, + // 894 NA // 893, // 892, // 891, - // 890, + // 890 NA // 889, // 888, // 887, - // 886, + // 886 NA // 885, - // 884, + // 884 NA // 883, // 882, // 881, - // 880, + // 880 NA // 879, // 878, // 877, - // 876, - // 875, - // 874, + // 876 NA + // 875 NA + // 874 NA // 873, - // 872, + // 872 NA // 871, // 870, - // 869, + // 869 NA // 868, - // 867, + // 867 NA // 866, // 865, // 864, // 863, - // 862, - // 861, + // 862 NA + // 861 NA // 860, // 859, // 858, // 857, // 856, - // 855, + // 855 NA // 854, // 853, - // 852, - // 851, - // 850, - 849, + // 852 NA + // 851 NA + // 850 NA + 849, // 848, // 847, - // 846, + // 846 NA // 845, // 844, // 843, // 842, // 841, - // 840, + // 840 NA // 839, // 838, - // 837, + // 837 NA 836, // 835, // 834, @@ -161,7 +167,7 @@ static int included_patches[] = { // 832, // 831, // 830, - // 829, + // 829 NA // 828, // 827, 826, @@ -181,14 +187,14 @@ static int included_patches[] = { // 812, // 811, // 810, - // 809, + 809, // 808, // 807, // 806, // 805, // 804, // 803, - // 802, + 802, // 801, // 800, 799, @@ -218,35 +224,35 @@ static int included_patches[] = { 775, 774, 773, - // 772, + // 772 NA // 771, - // 770, + // 770 NA // 769, // 768, // 767, - // 766, + // 766 NA // 765, // 764, - // 763, - // 762, - // 761, + // 763 NA + // 762 NA + // 761 NA // 760, - // 759, + // 759 NA // 758, - // 757, - // 756, + // 757 NA + // 756 NA // 755, // 754, // 753, // 752, - // 751, - // 750, + // 751 NA + // 750 NA // 749, // 748, // 747, // 746, // 745, - // 744, + // 744 NA // 743, // 742, // 741, @@ -338,7 +344,7 @@ static int included_patches[] = { // 655, // 654, 653, - // 652, + // 652 NA 651, // 650 NA // 649, diff --git a/src/nvim/window.c b/src/nvim/window.c index b71b2cb603..8ac50b2731 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3,10 +3,9 @@ * * Do ":help uganda" in Vim to read a list of people who contributed. * Do ":help credits" in Vim to see a list of people who contributed. - * See README.txt for an overview of the Vim source code. + * See README.md for an overview of the Vim source code. */ -#include <errno.h> #include <assert.h> #include <inttypes.h> #include <stdbool.h> |