diff options
Diffstat (limited to 'src')
147 files changed, 6003 insertions, 3779 deletions
diff --git a/src/clint.py b/src/clint.py index 12bada6aac..8dc41fdb93 100755 --- a/src/clint.py +++ b/src/clint.py @@ -1773,7 +1773,7 @@ def CheckSpacingForFunctionCall(filename, line, linenum, error): fncall = match.group(1) break - # Except in if/for/while/switch, there should never be space + # Except in if/for/while/switch/case, there should never be space # immediately inside parens (eg "f( 3, 4 )"). We make an exception # for nested parens ( (a+b) + c ). Likewise, there should never be # a space before a ( when it's a function argument. I assume it's a @@ -1787,7 +1787,7 @@ def CheckSpacingForFunctionCall(filename, line, linenum, error): # Note that we assume the contents of [] to be short enough that # they'll never need to wrap. if ( # Ignore control structures. - not Search(r'\b(if|for|while|switch|return|sizeof)\b', fncall) and + not Search(r'\b(if|for|while|switch|case|return|sizeof)\b', fncall) and # Ignore pointers/references to functions. not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and # Ignore pointers/references to arrays. diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 62290b0778..982fab173f 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -221,7 +221,7 @@ set(gen_cflags ${gen_cflags} ${C_FLAGS_${build_type}_ARRAY} ${C_FLAGS_ARRAY}) function(get_preproc_output varname iname) if(MSVC) - set(${varname} /P /Fi${iname} PARENT_SCOPE) + set(${varname} /P /Fi${iname} /nologo PARENT_SCOPE) else() set(${varname} -E -o ${iname} PARENT_SCOPE) endif() @@ -574,7 +574,6 @@ set_target_properties( libnvim PROPERTIES POSITION_INDEPENDENT_CODE ON - OUTPUT_NAME nvim ) set_property( TARGET libnvim diff --git a/src/nvim/README.md b/src/nvim/README.md index 3f7c05757a..d14ba85546 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -23,14 +23,18 @@ Logs Low-level log messages sink to `$NVIM_LOG_FILE`. -Use `LOG_CALLSTACK()` (Linux only) to log the current stacktrace. To log to an -alternate file (e.g. stderr) use `LOG_CALLSTACK_TO_FILE(FILE*)`. - UI events are logged at DEBUG level (`DEBUG_LOG_LEVEL`). rm -rf build/ make CMAKE_EXTRA_FLAGS="-DMIN_LOG_LEVEL=0" +Use `LOG_CALLSTACK()` (Linux only) to log the current stacktrace. To log to an +alternate file (e.g. stderr) use `LOG_CALLSTACK_TO_FILE(FILE*)`. Requires +`-no-pie` ([ref](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=860394#15)): + + rm -rf build/ + make CMAKE_EXTRA_FLAGS="-DMIN_LOG_LEVEL=0 -DCMAKE_C_FLAGS=-no-pie" + Many log messages have a shared prefix, such as "UI" or "RPC". Use the shell to filter the log, e.g. at DEBUG level you might want to exclude UI messages: diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index a666ed92da..b345dcaccd 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1123,7 +1123,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id, } if (!ns_initialized((uint64_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, _("Invalid ns_id")); + api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); return rv; } @@ -1190,7 +1190,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, } if (!ns_initialized((uint64_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, _("Invalid ns_id")); + api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); return rv; } Integer limit = -1; @@ -1280,7 +1280,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer id, } if (!ns_initialized((uint64_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, _("Invalid ns_id")); + api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); return 0; } @@ -1308,7 +1308,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer id, if (id >= 0) { id_num = (uint64_t)id; } else { - api_set_error(err, kErrorTypeValidation, _("Invalid mark id")); + api_set_error(err, kErrorTypeValidation, "Invalid mark id"); return 0; } @@ -1337,7 +1337,7 @@ Boolean nvim_buf_del_extmark(Buffer buffer, return false; } if (!ns_initialized((uint64_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, _("Invalid ns_id")); + api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); return false; } @@ -1402,7 +1402,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, uint64_t ns_id = src2ns(&src_id); - if (!(0 <= line && line < buf->b_ml.ml_line_count)) { + if (!(line < buf->b_ml.ml_line_count)) { // safety check, we can't add marks outside the range return src_id; } @@ -1420,10 +1420,10 @@ Integer nvim_buf_add_highlight(Buffer buffer, end_line++; } - ns_id = extmark_add_decoration(buf, ns_id, hlg_id, - (int)line, (colnr_T)col_start, - end_line, (colnr_T)col_end, - VIRTTEXT_EMPTY); + extmark_add_decoration(buf, ns_id, hlg_id, + (int)line, (colnr_T)col_start, + end_line, (colnr_T)col_end, + VIRTTEXT_EMPTY); return src_id; } @@ -1655,7 +1655,7 @@ Integer nvim__buf_add_decoration(Buffer buffer, Integer ns_id, String hl_group, } if (!ns_initialized((uint64_t)ns_id)) { - api_set_error(err, kErrorTypeValidation, _("Invalid ns_id")); + api_set_error(err, kErrorTypeValidation, "Invalid ns_id"); return 0; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index a1745ef777..a458762cc6 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -1544,7 +1544,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int *col = MAXCOL; return true; } else if (id < 0) { - api_set_error(err, kErrorTypeValidation, _("Mark id must be positive")); + api_set_error(err, kErrorTypeValidation, "Mark id must be positive"); return false; } @@ -1554,7 +1554,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int *col = extmark.col; return true; } else { - api_set_error(err, kErrorTypeValidation, _("No mark with requested id")); + api_set_error(err, kErrorTypeValidation, "No mark with requested id"); return false; } @@ -1565,7 +1565,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int || pos.items[0].type != kObjectTypeInteger || pos.items[1].type != kObjectTypeInteger) { api_set_error(err, kErrorTypeValidation, - _("Position must have 2 integer elements")); + "Position must have 2 integer elements"); return false; } Integer pos_row = pos.items[0].data.integer; @@ -1575,7 +1575,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int return true; } else { api_set_error(err, kErrorTypeValidation, - _("Position must be a mark id Integer or position Array")); + "Position must be a mark id Integer or position Array"); return false; } } diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 048b937136..df3a263dcf 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -63,8 +63,8 @@ #define FIXED_TEMP_ARRAY(name, fixsize) \ Array name = ARRAY_DICT_INIT; \ Object name##__items[fixsize]; \ - args.size = fixsize; \ - args.items = name##__items; \ + name.size = fixsize; \ + name.items = name##__items; \ #define STATIC_CSTR_AS_STRING(s) ((String) {.data = s, .size = sizeof(s) - 1}) diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 6677e248cf..ab31db39e9 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -115,6 +115,10 @@ void win_close(Integer grid) void msg_set_pos(Integer grid, Integer row, Boolean scrolled, String sep_char) FUNC_API_SINCE(6) FUNC_API_BRIDGE_IMPL FUNC_API_COMPOSITOR_IMPL; +void win_viewport(Integer grid, Window win, Integer topline, + Integer botline, Integer curline, Integer curcol) + FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY; + void popupmenu_show(Array items, Integer selected, Integer row, Integer col, Integer grid) FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9657a37831..087ab37296 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -254,7 +254,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_csi) if (execute) { int save_msg_scroll = msg_scroll; - /* Avoid a 1 second delay when the keys start Insert mode. */ + // Avoid a 1 second delay when the keys start Insert mode. msg_scroll = false; if (!dangerous) { ex_normal_busy++; diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h index ff6840d690..31423e79af 100644 --- a/src/nvim/ascii.h +++ b/src/nvim/ascii.h @@ -23,26 +23,28 @@ #define NL '\012' #define NL_STR "\012" #define FF '\014' -#define CAR '\015' /* CR is used by Mac OS X */ +#define CAR '\015' // CR is used by Mac OS X #define ESC '\033' #define ESC_STR "\033" #define DEL 0x7f #define DEL_STR "\177" #define CSI 0x9b // Control Sequence Introducer #define CSI_STR "\233" -#define DCS 0x90 /* Device Control String */ -#define STERM 0x9c /* String Terminator */ +#define DCS 0x90 // Device Control String +#define DCS_STR "\033P" +#define STERM 0x9c // String Terminator +#define STERM_STR "\033\\" #define POUND 0xA3 -#define Ctrl_chr(x) (TOUPPER_ASC(x) ^ 0x40) /* '?' -> DEL, '@' -> ^@, etc. */ +#define Ctrl_chr(x) (TOUPPER_ASC(x) ^ 0x40) // '?' -> DEL, '@' -> ^@, etc. #define Meta(x) ((x) | 0x80) #define CTRL_F_STR "\006" #define CTRL_H_STR "\010" #define CTRL_V_STR "\026" -#define Ctrl_AT 0 /* @ */ +#define Ctrl_AT 0 // @ #define Ctrl_A 1 #define Ctrl_B 2 #define Ctrl_C 3 @@ -69,16 +71,14 @@ #define Ctrl_X 24 #define Ctrl_Y 25 #define Ctrl_Z 26 -/* CTRL- [ Left Square Bracket == ESC*/ -#define Ctrl_BSL 28 /* \ BackSLash */ -#define Ctrl_RSB 29 /* ] Right Square Bracket */ -#define Ctrl_HAT 30 /* ^ */ +// CTRL- [ Left Square Bracket == ESC +#define Ctrl_BSL 28 // \ BackSLash +#define Ctrl_RSB 29 // ] Right Square Bracket +#define Ctrl_HAT 30 // ^ #define Ctrl__ 31 -/* - * Character that separates dir names in a path. - */ +// Character that separates dir names in a path. #ifdef BACKSLASH_IN_FILENAME # define PATHSEP psepc # define PATHSEPSTR pseps @@ -168,4 +168,4 @@ static inline bool ascii_isspace(int c) return (c >= 9 && c <= 13) || c == ' '; } -#endif /* NVIM_ASCII_H */ +#endif // NVIM_ASCII_H diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 790609ab94..24ba43676a 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1750,6 +1750,7 @@ buf_T * buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags) apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, false, curbuf); } if (aborting()) { // autocmds may abort script processing + xfree(ffname); return NULL; } if (buf == curbuf) { @@ -3397,14 +3398,27 @@ int build_stl_str_hl( 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"). - char_u *line_ptr = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, false); + const char_u *line_ptr = 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; - if (wp->w_cursor.col > (colnr_T)STRLEN(line_ptr)) { + 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); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 9cdf36e4ed..2460159fc0 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -67,14 +67,14 @@ typedef struct { * off off w_botline not valid * on off not possible */ -#define VALID_WROW 0x01 /* w_wrow (window row) is valid */ -#define VALID_WCOL 0x02 /* w_wcol (window col) is valid */ -#define VALID_VIRTCOL 0x04 /* w_virtcol (file col) is valid */ -#define VALID_CHEIGHT 0x08 /* w_cline_height and w_cline_folded valid */ -#define VALID_CROW 0x10 /* w_cline_row is valid */ -#define VALID_BOTLINE 0x20 /* w_botine and w_empty_rows are valid */ -#define VALID_BOTLINE_AP 0x40 /* w_botine is approximated */ -#define VALID_TOPLINE 0x80 /* w_topline is valid (for cursor position) */ +#define VALID_WROW 0x01 // w_wrow (window row) is valid +#define VALID_WCOL 0x02 // w_wcol (window col) is valid +#define VALID_VIRTCOL 0x04 // w_virtcol (file col) is valid +#define VALID_CHEIGHT 0x08 // w_cline_height and w_cline_folded valid +#define VALID_CROW 0x10 // w_cline_row is valid +#define VALID_BOTLINE 0x20 // w_botine and w_empty_rows are valid +#define VALID_BOTLINE_AP 0x40 // w_botine is approximated +#define VALID_TOPLINE 0x80 // w_topline is valid (for cursor position) // flags for b_flags #define BF_RECOVERED 0x01 // buffer has been recovered @@ -92,7 +92,7 @@ typedef struct { #define BF_DUMMY 0x80 // dummy buffer, only used internally #define BF_PRESERVED 0x100 // ":preserve" was used -/* Mask to check for flags that prevent normal writing */ +// Mask to check for flags that prevent normal writing #define BF_WRITE_MASK (BF_NOTEDITED + BF_NEW + BF_READERR) typedef struct window_S win_T; @@ -160,90 +160,92 @@ typedef struct */ typedef struct { int wo_arab; -# define w_p_arab w_onebuf_opt.wo_arab /* 'arabic' */ +# define w_p_arab w_onebuf_opt.wo_arab // 'arabic' int wo_bri; # define w_p_bri w_onebuf_opt.wo_bri // 'breakindent' char_u *wo_briopt; -# define w_p_briopt w_onebuf_opt.wo_briopt /* 'breakindentopt' */ +# define w_p_briopt w_onebuf_opt.wo_briopt // 'breakindentopt' int wo_diff; -# define w_p_diff w_onebuf_opt.wo_diff /* 'diff' */ - long wo_fdc; -# define w_p_fdc w_onebuf_opt.wo_fdc /* 'foldcolumn' */ - int wo_fdc_save; -# define w_p_fdc_save w_onebuf_opt.wo_fdc_save /* 'foldenable' saved for diff mode */ +# define w_p_diff w_onebuf_opt.wo_diff // 'diff' + char_u *wo_fdc; +# define w_p_fdc w_onebuf_opt.wo_fdc // 'foldcolumn' + char_u *wo_fdc_save; +# define w_p_fdc_save w_onebuf_opt.wo_fdc_save // 'fdc' saved for diff mode int wo_fen; -# define w_p_fen w_onebuf_opt.wo_fen /* 'foldenable' */ +# define w_p_fen w_onebuf_opt.wo_fen // 'foldenable' int wo_fen_save; -# define w_p_fen_save w_onebuf_opt.wo_fen_save /* 'foldenable' saved for diff mode */ + // 'foldenable' saved for diff mode +# define w_p_fen_save w_onebuf_opt.wo_fen_save char_u *wo_fdi; -# define w_p_fdi w_onebuf_opt.wo_fdi /* 'foldignore' */ +# define w_p_fdi w_onebuf_opt.wo_fdi // 'foldignore' long wo_fdl; -# define w_p_fdl w_onebuf_opt.wo_fdl /* 'foldlevel' */ +# define w_p_fdl w_onebuf_opt.wo_fdl // 'foldlevel' int wo_fdl_save; -# define w_p_fdl_save w_onebuf_opt.wo_fdl_save /* 'foldlevel' state saved for diff mode */ + // 'foldlevel' state saved for diff mode +# define w_p_fdl_save w_onebuf_opt.wo_fdl_save char_u *wo_fdm; -# define w_p_fdm w_onebuf_opt.wo_fdm /* 'foldmethod' */ +# define w_p_fdm w_onebuf_opt.wo_fdm // 'foldmethod' char_u *wo_fdm_save; -# define w_p_fdm_save w_onebuf_opt.wo_fdm_save /* 'fdm' saved for diff mode */ +# define w_p_fdm_save w_onebuf_opt.wo_fdm_save // 'fdm' saved for diff mode long wo_fml; -# define w_p_fml w_onebuf_opt.wo_fml /* 'foldminlines' */ +# define w_p_fml w_onebuf_opt.wo_fml // 'foldminlines' long wo_fdn; -# define w_p_fdn w_onebuf_opt.wo_fdn /* 'foldnestmax' */ +# define w_p_fdn w_onebuf_opt.wo_fdn // 'foldnestmax' char_u *wo_fde; -# define w_p_fde w_onebuf_opt.wo_fde /* 'foldexpr' */ +# define w_p_fde w_onebuf_opt.wo_fde // 'foldexpr' char_u *wo_fdt; -# define w_p_fdt w_onebuf_opt.wo_fdt /* 'foldtext' */ +# define w_p_fdt w_onebuf_opt.wo_fdt // 'foldtext' char_u *wo_fmr; -# define w_p_fmr w_onebuf_opt.wo_fmr /* 'foldmarker' */ +# define w_p_fmr w_onebuf_opt.wo_fmr // 'foldmarker' int wo_lbr; -# define w_p_lbr w_onebuf_opt.wo_lbr /* 'linebreak' */ +# define w_p_lbr w_onebuf_opt.wo_lbr // 'linebreak' int wo_list; -#define w_p_list w_onebuf_opt.wo_list /* 'list' */ +#define w_p_list w_onebuf_opt.wo_list // 'list' int wo_nu; -#define w_p_nu w_onebuf_opt.wo_nu /* 'number' */ +#define w_p_nu w_onebuf_opt.wo_nu // 'number' int wo_rnu; -#define w_p_rnu w_onebuf_opt.wo_rnu /* 'relativenumber' */ +#define w_p_rnu w_onebuf_opt.wo_rnu // 'relativenumber' long wo_nuw; -# define w_p_nuw w_onebuf_opt.wo_nuw /* 'numberwidth' */ +# define w_p_nuw w_onebuf_opt.wo_nuw // 'numberwidth' int wo_wfh; -# define w_p_wfh w_onebuf_opt.wo_wfh /* 'winfixheight' */ +# define w_p_wfh w_onebuf_opt.wo_wfh // 'winfixheight' int wo_wfw; -# define w_p_wfw w_onebuf_opt.wo_wfw /* 'winfixwidth' */ +# define w_p_wfw w_onebuf_opt.wo_wfw // 'winfixwidth' int wo_pvw; -# define w_p_pvw w_onebuf_opt.wo_pvw /* 'previewwindow' */ +# define w_p_pvw w_onebuf_opt.wo_pvw // 'previewwindow' int wo_rl; -# define w_p_rl w_onebuf_opt.wo_rl /* 'rightleft' */ +# define w_p_rl w_onebuf_opt.wo_rl // 'rightleft' char_u *wo_rlc; -# define w_p_rlc w_onebuf_opt.wo_rlc /* 'rightleftcmd' */ +# define w_p_rlc w_onebuf_opt.wo_rlc // 'rightleftcmd' long wo_scr; -#define w_p_scr w_onebuf_opt.wo_scr /* 'scroll' */ +#define w_p_scr w_onebuf_opt.wo_scr // 'scroll' int wo_spell; -# define w_p_spell w_onebuf_opt.wo_spell /* 'spell' */ +# define w_p_spell w_onebuf_opt.wo_spell // 'spell' int wo_cuc; -# define w_p_cuc w_onebuf_opt.wo_cuc /* 'cursorcolumn' */ +# define w_p_cuc w_onebuf_opt.wo_cuc // 'cursorcolumn' int wo_cul; -# define w_p_cul w_onebuf_opt.wo_cul /* 'cursorline' */ +# define w_p_cul w_onebuf_opt.wo_cul // 'cursorline' char_u *wo_cc; -# define w_p_cc w_onebuf_opt.wo_cc /* 'colorcolumn' */ +# define w_p_cc w_onebuf_opt.wo_cc // 'colorcolumn' char_u *wo_stl; -#define w_p_stl w_onebuf_opt.wo_stl /* 'statusline' */ +#define w_p_stl w_onebuf_opt.wo_stl // 'statusline' int wo_scb; -# define w_p_scb w_onebuf_opt.wo_scb /* 'scrollbind' */ - int wo_diff_saved; /* options were saved for starting diff mode */ +# define w_p_scb w_onebuf_opt.wo_scb // 'scrollbind' + int wo_diff_saved; // options were saved for starting diff mode # define w_p_diff_saved w_onebuf_opt.wo_diff_saved - int wo_scb_save; /* 'scrollbind' saved for diff mode*/ + int wo_scb_save; // 'scrollbind' saved for diff mode # define w_p_scb_save w_onebuf_opt.wo_scb_save int wo_wrap; -#define w_p_wrap w_onebuf_opt.wo_wrap /* 'wrap' */ - int wo_wrap_save; /* 'wrap' state saved for diff mode*/ +#define w_p_wrap w_onebuf_opt.wo_wrap // 'wrap' + int wo_wrap_save; // 'wrap' state saved for diff mode # define w_p_wrap_save w_onebuf_opt.wo_wrap_save - char_u *wo_cocu; /* 'concealcursor' */ + char_u *wo_cocu; // 'concealcursor' # define w_p_cocu w_onebuf_opt.wo_cocu - long wo_cole; /* 'conceallevel' */ + long wo_cole; // 'conceallevel' # define w_p_cole w_onebuf_opt.wo_cole int wo_crb; -# define w_p_crb w_onebuf_opt.wo_crb /* 'cursorbind' */ - int wo_crb_save; /* 'cursorbind' state saved for diff mode*/ +# define w_p_crb w_onebuf_opt.wo_crb // 'cursorbind' + int wo_crb_save; // 'cursorbind' state saved for diff mode # define w_p_crb_save w_onebuf_opt.wo_crb_save char_u *wo_scl; # define w_p_scl w_onebuf_opt.wo_scl // 'signcolumn' @@ -271,14 +273,14 @@ typedef struct { * most-recently-used order. */ struct wininfo_S { - wininfo_T *wi_next; /* next entry or NULL for last entry */ - wininfo_T *wi_prev; /* previous entry or NULL for first entry */ - win_T *wi_win; /* pointer to window that did set wi_fpos */ - pos_T wi_fpos; /* last cursor position in the file */ - bool wi_optset; /* true when wi_opt has useful values */ - winopt_T wi_opt; /* local window options */ - bool wi_fold_manual; /* copy of w_fold_manual */ - garray_T wi_folds; /* clone of w_folds */ + wininfo_T *wi_next; // next entry or NULL for last entry + wininfo_T *wi_prev; // previous entry or NULL for first entry + win_T *wi_win; // pointer to window that did set wi_fpos + pos_T wi_fpos; // last cursor position in the file + bool wi_optset; // true when wi_opt has useful values + winopt_T wi_opt; // local window options + bool wi_fold_manual; // copy of w_fold_manual + garray_T wi_folds; // clone of w_folds }; /* @@ -288,8 +290,8 @@ struct wininfo_S { * TODO: move struct arglist to another header */ typedef struct arglist { - garray_T al_ga; /* growarray with the array of file names */ - int al_refcount; /* number of windows using this arglist */ + garray_T al_ga; // growarray with the array of file names + int al_refcount; // number of windows using this arglist int id; ///< id of this arglist } alist_T; @@ -301,8 +303,8 @@ typedef struct arglist { * TODO: move aentry_T to another header */ typedef struct argentry { - char_u *ae_fname; /* file name as specified */ - int ae_fnum; /* buffer number with expanded file name */ + char_u *ae_fname; // file name as specified + int ae_fnum; // buffer number with expanded file name } aentry_T; # define ALIST(win) (win)->w_alist @@ -318,21 +320,21 @@ typedef struct argentry { * Used for the typeahead buffer: typebuf. */ typedef struct { - char_u *tb_buf; /* buffer for typed characters */ - char_u *tb_noremap; /* mapping flags for characters in tb_buf[] */ - int tb_buflen; /* size of tb_buf[] */ - int tb_off; /* current position in tb_buf[] */ - int tb_len; /* number of valid bytes in tb_buf[] */ - int tb_maplen; /* nr of mapped bytes in tb_buf[] */ - int tb_silent; /* nr of silently mapped bytes in tb_buf[] */ - int tb_no_abbr_cnt; /* nr of bytes without abbrev. in tb_buf[] */ - int tb_change_cnt; /* nr of time tb_buf was changed; never zero */ + char_u *tb_buf; // buffer for typed characters + char_u *tb_noremap; // mapping flags for characters in tb_buf[] + int tb_buflen; // size of tb_buf[] + int tb_off; // current position in tb_buf[] + int tb_len; // number of valid bytes in tb_buf[] + int tb_maplen; // nr of mapped bytes in tb_buf[] + int tb_silent; // nr of silently mapped bytes in tb_buf[] + int tb_no_abbr_cnt; // nr of bytes without abbrev. in tb_buf[] + int tb_change_cnt; // nr of time tb_buf was changed; never zero } typebuf_T; -/* Struct to hold the saved typeahead for save_typeahead(). */ +// Struct to hold the saved typeahead for save_typeahead(). typedef struct { typebuf_T save_typebuf; - int typebuf_valid; /* TRUE when save_typebuf valid */ + int typebuf_valid; // TRUE when save_typebuf valid int old_char; int old_mod_mask; buffheader_T save_readbuf1; @@ -363,15 +365,15 @@ struct mapblock { */ struct stl_hlrec { char_u *start; - int userhl; /* 0: no HL, 1-9: User HL, < 0 for syn ID */ + int userhl; // 0: no HL, 1-9: User HL, < 0 for syn ID }; -/* values for b_syn_spell: what to do with toplevel text */ -#define SYNSPL_DEFAULT 0 /* spell check if @Spell not defined */ -#define SYNSPL_TOP 1 /* spell check toplevel text */ -#define SYNSPL_NOTOP 2 /* don't spell check toplevel text */ +// values for b_syn_spell: what to do with toplevel text +#define SYNSPL_DEFAULT 0 // spell check if @Spell not defined +#define SYNSPL_TOP 1 // spell check toplevel text +#define SYNSPL_NOTOP 2 // don't spell check toplevel text -/* avoid #ifdefs for when b_spell is not available */ +// avoid #ifdefs for when b_spell is not available # define B_SPELL(buf) ((buf)->b_spell) typedef struct qf_info_S qf_info_T; @@ -380,10 +382,10 @@ typedef struct qf_info_S qf_info_T; * Used for :syntime: timing of executing a syntax pattern. */ typedef struct { - proftime_T total; /* total time used */ - proftime_T slowest; /* time of slowest call */ - long count; /* nr of times used */ - long match; /* nr of times matched */ + proftime_T total; // total time used + proftime_T slowest; // time of slowest call + long count; // nr of times used + long match; // nr of times matched } syn_time_T; /* @@ -411,25 +413,23 @@ typedef struct { char_u *b_syn_linecont_pat; // line continuation pattern regprog_T *b_syn_linecont_prog; // line continuation program syn_time_T b_syn_linecont_time; - int b_syn_linecont_ic; /* ignore-case flag for above */ - int b_syn_topgrp; /* for ":syntax include" */ - int b_syn_conceal; /* auto-conceal for :syn cmds */ - int b_syn_folditems; /* number of patterns with the HL_FOLD - flag set */ - /* - * b_sst_array[] contains the state stack for a number of lines, for the - * start of that line (col == 0). This avoids having to recompute the - * syntax state too often. - * b_sst_array[] is allocated to hold the state for all displayed lines, - * and states for 1 out of about 20 other lines. - * b_sst_array pointer to an array of synstate_T - * b_sst_len number of entries in b_sst_array[] - * b_sst_first pointer to first used entry in b_sst_array[] or NULL - * b_sst_firstfree pointer to first free entry in b_sst_array[] or NULL - * b_sst_freecount number of free entries in b_sst_array[] - * b_sst_check_lnum entries after this lnum need to be checked for - * validity (MAXLNUM means no check needed) - */ + int b_syn_linecont_ic; // ignore-case flag for above + int b_syn_topgrp; // for ":syntax include" + int b_syn_conceal; // auto-conceal for :syn cmds + int b_syn_folditems; // number of patterns with the HL_FOLD + // flag set + // b_sst_array[] contains the state stack for a number of lines, for the + // start of that line (col == 0). This avoids having to recompute the + // syntax state too often. + // b_sst_array[] is allocated to hold the state for all displayed lines, + // and states for 1 out of about 20 other lines. + // b_sst_array pointer to an array of synstate_T + // b_sst_len number of entries in b_sst_array[] + // b_sst_first pointer to first used entry in b_sst_array[] or NULL + // b_sst_firstfree pointer to first free entry in b_sst_array[] or NULL + // b_sst_freecount number of free entries in b_sst_array[] + // b_sst_check_lnum entries after this lnum need to be checked for + // validity (MAXLNUM means no check needed) synstate_T *b_sst_array; int b_sst_len; synstate_T *b_sst_first; @@ -488,10 +488,10 @@ struct file_buffer { memline_T b_ml; // associated memline (also contains line count - buf_T *b_next; /* links in list of buffers */ + buf_T *b_next; // links in list of buffers buf_T *b_prev; - int b_nwindows; /* nr of windows open on this buffer */ + int b_nwindows; // nr of windows open on this buffer int b_flags; // various BF_ flags int b_locked; // Buffer is being closed or referenced, don't @@ -532,24 +532,23 @@ struct file_buffer { */ bool b_mod_set; /* true when there are changes since the last time the display was updated */ - linenr_T b_mod_top; /* topmost lnum that was changed */ - linenr_T b_mod_bot; /* lnum below last changed line, AFTER the - change */ - long b_mod_xlines; /* number of extra buffer lines inserted; - negative when lines were deleted */ + linenr_T b_mod_top; // topmost lnum that was changed + linenr_T b_mod_bot; // lnum below last changed line, AFTER the + // change + long b_mod_xlines; // number of extra buffer lines inserted; + // negative when lines were deleted + wininfo_T *b_wininfo; // list of last used info for each window - wininfo_T *b_wininfo; /* list of last used info for each window */ + long b_mtime; // last change time of original file + long b_mtime_read; // last change time when reading + uint64_t b_orig_size; // size of original file in bytes + int b_orig_mode; // mode of original file - long b_mtime; /* last change time of original file */ - long b_mtime_read; /* last change time when reading */ - uint64_t b_orig_size; /* size of original file in bytes */ - int b_orig_mode; /* mode of original file */ + fmark_T b_namedm[NMARKS]; // current named marks (mark.c) - fmark_T b_namedm[NMARKS]; /* current named marks (mark.c) */ - - /* These variables are set when VIsual_active becomes FALSE */ + // These variables are set when VIsual_active becomes FALSE visualinfo_T b_visual; - int b_visual_mode_eval; /* b_visual.vi_mode for visualmode() */ + int b_visual_mode_eval; // b_visual.vi_mode for visualmode() fmark_T b_last_cursor; // cursor position when last unloading this // buffer @@ -560,8 +559,8 @@ struct file_buffer { * the changelist contains old change positions */ fmark_T b_changelist[JUMPLISTSIZE]; - int b_changelistlen; /* number of active entries */ - bool b_new_change; /* set by u_savecommon() */ + int b_changelistlen; // number of active entries + bool b_new_change; // set by u_savecommon() /* * Character table, only used in charset.c for 'iskeyword' @@ -572,9 +571,9 @@ struct file_buffer { // Table used for mappings local to a buffer. mapblock_T *(b_maphash[MAX_MAPHASH]); - /* First abbreviation local to a buffer. */ + // First abbreviation local to a buffer. mapblock_T *b_first_abbr; - /* User commands local to the buffer. */ + // User commands local to the buffer. garray_T b_ucmds; /* * start and end of an operator, also used for '[ and '] @@ -583,31 +582,31 @@ struct file_buffer { pos_T b_op_start_orig; // used for Insstart_orig pos_T b_op_end; - bool b_marks_read; /* Have we read ShaDa marks yet? */ + bool b_marks_read; // Have we read ShaDa marks yet? /* * The following only used in undo.c. */ - u_header_T *b_u_oldhead; /* pointer to oldest header */ - u_header_T *b_u_newhead; /* pointer to newest header; may not be valid - if b_u_curhead is not NULL */ - u_header_T *b_u_curhead; /* pointer to current header */ - int b_u_numhead; /* current number of headers */ - bool b_u_synced; /* entry lists are synced */ - long b_u_seq_last; /* last used undo sequence number */ - long b_u_save_nr_last; /* counter for last file write */ - long b_u_seq_cur; /* hu_seq of header below which we are now */ - time_t b_u_time_cur; /* uh_time of header below which we are now */ - long b_u_save_nr_cur; /* file write nr after which we are now */ + u_header_T *b_u_oldhead; // pointer to oldest header + u_header_T *b_u_newhead; // pointer to newest header; may not be valid + // if b_u_curhead is not NULL + u_header_T *b_u_curhead; // pointer to current header + int b_u_numhead; // current number of headers + bool b_u_synced; // entry lists are synced + long b_u_seq_last; // last used undo sequence number + long b_u_save_nr_last; // counter for last file write + long b_u_seq_cur; // hu_seq of header below which we are now + time_t b_u_time_cur; // uh_time of header below which we are now + long b_u_save_nr_cur; // file write nr after which we are now /* * variables for "U" command in undo.c */ - char_u *b_u_line_ptr; /* saved line for "U" command */ - linenr_T b_u_line_lnum; /* line number of line in u_line */ - colnr_T b_u_line_colnr; /* optional column number */ + char_u *b_u_line_ptr; // saved line for "U" command + linenr_T b_u_line_lnum; // line number of line in u_line + colnr_T b_u_line_colnr; // optional column number - bool b_scanned; /* ^N/^P have scanned this buffer */ + bool b_scanned; // ^N/^P have scanned this buffer // flags for use of ":lmap" and IM control long b_p_iminsert; // input mode for insert @@ -617,10 +616,10 @@ struct file_buffer { #define B_IMODE_LMAP 1 // Input via langmap # define B_IMODE_LAST 1 - short b_kmap_state; /* using "lmap" mappings */ -# define KEYMAP_INIT 1 /* 'keymap' was set, call keymap_init() */ -# define KEYMAP_LOADED 2 /* 'keymap' mappings have been loaded */ - garray_T b_kmap_ga; /* the keymap table */ + int16_t b_kmap_state; // using "lmap" mappings +# define KEYMAP_INIT 1 // 'keymap' was set, call keymap_init() +# define KEYMAP_LOADED 2 // 'keymap' mappings have been loaded + garray_T b_kmap_ga; // the keymap table /* * Options local to a buffer. @@ -720,9 +719,9 @@ struct file_buffer { int b_p_udf; ///< 'undofile' char_u *b_p_lw; ///< 'lispwords' local value - /* end of buffer options */ + // end of buffer options - /* values set from b_p_cino */ + // values set from b_p_cino int b_ind_level; int b_ind_open_imag; int b_ind_no_brace; @@ -763,11 +762,11 @@ struct file_buffer { linenr_T b_no_eol_lnum; /* non-zero lnum when last line of next binary * write should not have an end-of-line */ - int b_start_eol; /* last line had eol when it was read */ - int b_start_ffc; /* first char of 'ff' when edit started */ - char_u *b_start_fenc; /* 'fileencoding' when edit started or NULL */ - int b_bad_char; /* "++bad=" argument when edit started or 0 */ - int b_start_bomb; /* 'bomb' when it was read */ + int b_start_eol; // last line had eol when it was read + int b_start_ffc; // first char of 'ff' when edit started + char_u *b_start_fenc; // 'fileencoding' when edit started or NULL + int b_bad_char; // "++bad=" argument when edit started or 0 + int b_start_bomb; // 'bomb' when it was read ScopeDictDictItem b_bufvar; ///< Variable for "b:" Dictionary. dict_T *b_vars; ///< b: scope dictionary. @@ -866,8 +865,8 @@ struct file_buffer { typedef struct diffblock_S diff_T; struct diffblock_S { diff_T *df_next; - linenr_T df_lnum[DB_COUNT]; /* line number in buffer */ - linenr_T df_count[DB_COUNT]; /* nr of inserted/changed lines */ + linenr_T df_lnum[DB_COUNT]; // line number in buffer + linenr_T df_count[DB_COUNT]; // nr of inserted/changed lines }; #define SNAP_HELP_IDX 0 @@ -915,11 +914,11 @@ struct tabpage_S { * wl_lnum and wl_lastlnum are invalid too. */ typedef struct w_line { - linenr_T wl_lnum; /* buffer line number for logical line */ - uint16_t wl_size; /* height in screen lines */ - char wl_valid; /* TRUE values are valid for text in buffer */ - char wl_folded; /* TRUE when this is a range of folded lines */ - linenr_T wl_lastlnum; /* last buffer line number for logical line */ + linenr_T wl_lnum; // buffer line number for logical line + uint16_t wl_size; // height in screen lines + char wl_valid; // TRUE values are valid for text in buffer + char wl_folded; // TRUE when this is a range of folded lines + linenr_T wl_lastlnum; // last buffer line number for logical line } wline_T; /* @@ -942,9 +941,9 @@ struct frame_S { win_T *fr_win; // window that fills this frame }; -#define FR_LEAF 0 /* frame is a leaf */ -#define FR_ROW 1 /* frame with a row of windows */ -#define FR_COL 2 /* frame with a column of windows */ +#define FR_LEAF 0 // frame is a leaf +#define FR_ROW 1 // frame with a row of windows +#define FR_COL 2 // frame with a column of windows /* * Struct used for highlighting 'hlsearch' matches, matches defined by @@ -1145,16 +1144,16 @@ struct window_S { top of the window */ char w_topline_was_set; /* flag set to TRUE when topline is set, e.g. by winrestview() */ - int w_topfill; /* number of filler lines above w_topline */ - int w_old_topfill; /* w_topfill at last redraw */ - bool w_botfill; /* true when filler lines are actually - below w_topline (at end of file) */ - bool w_old_botfill; /* w_botfill at last redraw */ - colnr_T w_leftcol; /* window column number of the left most - character in the window; used when - 'wrap' is off */ - colnr_T w_skipcol; /* starting column when a single line - doesn't fit in the window */ + int w_topfill; // number of filler lines above w_topline + int w_old_topfill; // w_topfill at last redraw + bool w_botfill; // true when filler lines are actually + // below w_topline (at end of file) + bool w_old_botfill; // w_botfill at last redraw + colnr_T w_leftcol; // window column number of the left most + // character in the window; used when + // 'wrap' is off + colnr_T w_skipcol; // starting column when a single line + // doesn't fit in the window // // Layout of the window in the screen. @@ -1188,16 +1187,18 @@ struct window_S { int w_valid; pos_T w_valid_cursor; /* last known position of w_cursor, used to adjust w_valid */ - colnr_T w_valid_leftcol; /* last known w_leftcol */ + colnr_T w_valid_leftcol; // last known w_leftcol + + bool w_viewport_invalid; /* * w_cline_height is the number of physical lines taken by the buffer line * that the cursor is on. We use this to avoid extra calls to plines(). */ - int w_cline_height; /* current size of cursor line */ - bool w_cline_folded; /* cursor line is folded */ + int w_cline_height; // current size of cursor line + bool w_cline_folded; // cursor line is folded - int w_cline_row; /* starting row of the cursor line */ + int w_cline_row; // starting row of the cursor line colnr_T w_virtcol; // column number of the cursor in the // buffer line, as opposed to the column @@ -1211,7 +1212,7 @@ struct window_S { * This is related to positions in the window, not in the display or * buffer, thus w_wrow is relative to w_winrow. */ - int w_wrow, w_wcol; /* cursor position in window */ + int w_wrow, w_wcol; // cursor position in window linenr_T w_botline; // number of the line below the bottom of // the window @@ -1229,42 +1230,42 @@ struct window_S { * what is currently displayed. wl_valid is reset to indicated this. * This is used for efficient redrawing. */ - int w_lines_valid; /* number of valid entries */ + int w_lines_valid; // number of valid entries wline_T *w_lines; - garray_T w_folds; /* array of nested folds */ - bool w_fold_manual; /* when true: some folds are opened/closed - manually */ - bool w_foldinvalid; /* when true: folding needs to be - recomputed */ - int w_nrwidth; /* width of 'number' and 'relativenumber' - column being used */ + garray_T w_folds; // array of nested folds + bool w_fold_manual; // when true: some folds are opened/closed + // manually + bool w_foldinvalid; // when true: folding needs to be + // recomputed + int w_nrwidth; // width of 'number' and 'relativenumber' + // column being used /* * === end of cached values === */ - int w_redr_type; /* type of redraw to be performed on win */ - int w_upd_rows; /* number of window lines to update when - w_redr_type is REDRAW_TOP */ - linenr_T w_redraw_top; /* when != 0: first line needing redraw */ - linenr_T w_redraw_bot; /* when != 0: last line needing redraw */ - int w_redr_status; /* if TRUE status line must be redrawn */ + int w_redr_type; // type of redraw to be performed on win + int w_upd_rows; // number of window lines to update when + // w_redr_type is REDRAW_TOP + linenr_T w_redraw_top; // when != 0: first line needing redraw + linenr_T w_redraw_bot; // when != 0: last line needing redraw + int w_redr_status; // if TRUE status line must be redrawn - /* remember what is shown in the ruler for this window (if 'ruler' set) */ - pos_T w_ru_cursor; /* cursor position shown in ruler */ - colnr_T w_ru_virtcol; /* virtcol shown in ruler */ - linenr_T w_ru_topline; /* topline shown in ruler */ - linenr_T w_ru_line_count; /* line count used for ruler */ - int w_ru_topfill; /* topfill shown in ruler */ - char w_ru_empty; /* TRUE if ruler shows 0-1 (empty line) */ + // remember what is shown in the ruler for this window (if 'ruler' set) + pos_T w_ru_cursor; // cursor position shown in ruler + colnr_T w_ru_virtcol; // virtcol shown in ruler + linenr_T w_ru_topline; // topline shown in ruler + linenr_T w_ru_line_count; // line count used for ruler + int w_ru_topfill; // topfill shown in ruler + char w_ru_empty; // TRUE if ruler shows 0-1 (empty line) - int w_alt_fnum; /* alternate file (for # and CTRL-^) */ + int w_alt_fnum; // alternate file (for # and CTRL-^) - alist_T *w_alist; /* pointer to arglist for this window */ - int w_arg_idx; /* current index in argument list (can be - out of range!) */ - int w_arg_idx_invalid; /* editing another file than w_arg_idx */ + alist_T *w_alist; // pointer to arglist for this window + int w_arg_idx; // current index in argument list (can be + // out of range!) + int w_arg_idx_invalid; // editing another file than w_arg_idx char_u *w_localdir; /* absolute path of local directory or NULL */ @@ -1278,16 +1279,18 @@ struct window_S { winopt_T w_onebuf_opt; winopt_T w_allbuf_opt; - /* A few options have local flags for P_INSECURE. */ - uint32_t w_p_stl_flags; /* flags for 'statusline' */ - uint32_t w_p_fde_flags; /* flags for 'foldexpr' */ - uint32_t w_p_fdt_flags; /* flags for 'foldtext' */ - int *w_p_cc_cols; /* array of columns to highlight or NULL */ - int w_p_brimin; /* minimum width for breakindent */ - int w_p_brishift; /* additional shift for breakindent */ - bool w_p_brisbr; /* sbr in 'briopt' */ - - /* transform a pointer to a "onebuf" option into a "allbuf" option */ + // A few options have local flags for P_INSECURE. + uint32_t w_p_stl_flags; // flags for 'statusline' + uint32_t w_p_fde_flags; // flags for 'foldexpr' + uint32_t w_p_fdt_flags; // flags for 'foldtext' + int *w_p_cc_cols; // array of columns to highlight or NULL + int w_p_brimin; // minimum width for breakindent + int w_p_brishift; // additional shift for breakindent + bool w_p_brisbr; // sbr in 'briopt' + long w_p_siso; // 'sidescrolloff' local value + long w_p_so; // 'scrolloff' local value + + // transform a pointer to a "onebuf" option into a "allbuf" option #define GLOBAL_WO(p) ((char *)p + sizeof(winopt_T)) long w_scbind_pos; @@ -1300,20 +1303,20 @@ struct window_S { * a new line after setting the w_pcmark. If not, then we revert to * using the previous w_pcmark. */ - pos_T w_pcmark; /* previous context mark */ - pos_T w_prev_pcmark; /* previous w_pcmark */ + pos_T w_pcmark; // previous context mark + pos_T w_prev_pcmark; // previous w_pcmark /* * the jumplist contains old cursor positions */ xfmark_T w_jumplist[JUMPLISTSIZE]; - int w_jumplistlen; /* number of active entries */ - int w_jumplistidx; /* current position */ + int w_jumplistlen; // number of active entries + int w_jumplistidx; // current position - int w_changelistidx; /* current position in b_changelist */ + int w_changelistidx; // current position in b_changelist - matchitem_T *w_match_head; /* head of match list */ - int w_next_match_id; /* next match ID */ + matchitem_T *w_match_head; // head of match list + int w_next_match_id; // next match ID /* * the tagstack grows from 0 upwards: @@ -1321,9 +1324,9 @@ struct window_S { * entry 1: newer * entry 2: newest */ - taggy_T w_tagstack[TAGSTACKSIZE]; /* the tag stack */ - int w_tagstackidx; /* idx just below active entry */ - int w_tagstacklen; /* number of tags on stack */ + taggy_T w_tagstack[TAGSTACKSIZE]; // the tag stack + int w_tagstackidx; // idx just below active entry + int w_tagstacklen; // number of tags on stack ScreenGrid w_grid; // the grid specific to the window bool w_pos_changed; // true if window position changed @@ -1341,13 +1344,11 @@ struct window_S { linenr_T w_nrwidth_line_count; /* line count when ml_nrwidth_width * was computed. */ - int w_nrwidth_width; /* nr of chars to print line count. */ + int w_nrwidth_width; // nr of chars to print line count. - qf_info_T *w_llist; /* Location list for this window */ - /* - * Location list reference used in the location list window. - * In a non-location list window, w_llist_ref is NULL. - */ + qf_info_T *w_llist; // Location list for this window + // Location list reference used in the location list window. + // In a non-location list window, w_llist_ref is NULL. qf_info_T *w_llist_ref; }; diff --git a/src/nvim/change.c b/src/nvim/change.c index a341b8fce1..51afb40b40 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -361,8 +361,8 @@ void changed_bytes(linenr_T lnum, colnr_T col) /// insert/delete bytes at column /// -/// Like changed_bytes() but also adjust extmark for "added" bytes. -/// When "added" is negative text was deleted. +/// Like changed_bytes() but also adjust extmark for "new" bytes. +/// When "new" is negative text was deleted. static void inserted_bytes(linenr_T lnum, colnr_T col, int old, int new) { if (curbuf_splice_pending == 0) { diff --git a/src/nvim/channel.c b/src/nvim/channel.c index c66a0682e3..5eb29a7290 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -19,7 +19,6 @@ #include "nvim/ascii.h" static bool did_stdio = false; -PMap(uint64_t) *channels = NULL; /// next free id for a job or rpc channel /// 1 is reserved for stdio channel diff --git a/src/nvim/channel.h b/src/nvim/channel.h index c733e276be..9d26852ce5 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -85,7 +85,7 @@ struct Channel { bool callback_scheduled; }; -EXTERN PMap(uint64_t) *channels; +EXTERN PMap(uint64_t) *channels INIT(= NULL); #ifdef INCLUDE_GENERATED_DECLARATIONS # include "channel.h.generated.h" diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 0f9e2e23c0..f9d5adbc12 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1570,6 +1570,7 @@ char_u* skiptohex(char_u *q) /// /// @return Pointer to the next whitespace or NUL character. char_u *skiptowhite(const char_u *p) + FUNC_ATTR_NONNULL_ALL { while (*p != ' ' && *p != '\t' && *p != NUL) { p++; diff --git a/src/nvim/cursor_shape.h b/src/nvim/cursor_shape.h index 2c466603f0..a23fa6836d 100644 --- a/src/nvim/cursor_shape.h +++ b/src/nvim/cursor_shape.h @@ -33,11 +33,11 @@ SHAPE_HOR = 1, ///< horizontal bar cursor SHAPE_VER = 2 ///< vertical bar cursor } CursorShape; -#define MSHAPE_NUMBERED 1000 /* offset for shapes identified by number */ -#define MSHAPE_HIDE 1 /* hide mouse pointer */ +#define MSHAPE_NUMBERED 1000 // offset for shapes identified by number +#define MSHAPE_HIDE 1 // hide mouse pointer -#define SHAPE_MOUSE 1 /* used for mouse pointer shape */ -#define SHAPE_CURSOR 2 /* used for text cursor shape */ +#define SHAPE_MOUSE 1 // used for mouse pointer shape +#define SHAPE_CURSOR 2 // used for text cursor shape typedef struct cursor_entry { char *full_name; ///< mode description diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 04309444d9..3de5fc49bd 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -648,8 +648,8 @@ void diff_redraw(bool dofold) foldUpdateAll(wp); } - /* A change may have made filler lines invalid, need to take care - * of that for other windows. */ + // A change may have made filler lines invalid, need to take care + // of that for other windows. int n = diff_check(wp, wp->w_topline); if (((wp != curwin) && (wp->w_topfill > 0)) || (n > 0)) { @@ -1385,11 +1385,18 @@ void diff_win_options(win_T *wp, int addbuf) curbuf = curwin->w_buffer; if (!wp->w_p_diff) { - wp->w_p_fdc_save = wp->w_p_fdc; wp->w_p_fen_save = wp->w_p_fen; wp->w_p_fdl_save = wp->w_p_fdl; + + if (wp->w_p_diff_saved) { + free_string_option(wp->w_p_fdc_save); + } + wp->w_p_fdc_save = vim_strsave(wp->w_p_fdc); } - wp->w_p_fdc = diff_foldcolumn; + xfree(wp->w_p_fdc); + wp->w_p_fdc = (char_u *)xstrdup("2"); + assert(diff_foldcolumn >= 0 && diff_foldcolumn <= 9); + snprintf((char *)wp->w_p_fdc, STRLEN(wp->w_p_fdc) + 1, "%d", diff_foldcolumn); wp->w_p_fen = true; wp->w_p_fdl = 0; foldUpdateAll(wp); @@ -1443,9 +1450,9 @@ void ex_diffoff(exarg_T *eap) wp->w_p_fdm = vim_strsave(*wp->w_p_fdm_save ? wp->w_p_fdm_save : (char_u *)"manual"); - if (wp->w_p_fdc == diff_foldcolumn) { - wp->w_p_fdc = wp->w_p_fdc_save; - } + free_string_option(wp->w_p_fdc); + wp->w_p_fdc = vim_strsave(wp->w_p_fdc_save); + if (wp->w_p_fdl == 0) { wp->w_p_fdl = wp->w_p_fdl_save; } diff --git a/src/nvim/edit.c b/src/nvim/edit.c index cebd08af28..a291ed0401 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -184,7 +184,7 @@ static bool compl_used_match; // Selected one of the matches. static int compl_was_interrupted = FALSE; /* didn't finish finding completions. */ -static int compl_restarting = FALSE; /* don't insert match */ +static bool compl_restarting = false; // don't insert match // When the first completion is done "compl_started" is set. When it's // false the word to be completed must be located. @@ -197,7 +197,7 @@ static int compl_matches = 0; static char_u *compl_pattern = NULL; static int compl_direction = FORWARD; static int compl_shows_dir = FORWARD; -static int compl_pending = 0; /* > 1 for postponed CTRL-N */ +static int compl_pending = 0; // > 1 for postponed CTRL-N static pos_T compl_startpos; static colnr_T compl_col = 0; /* column where the text starts * that is being completed */ @@ -249,30 +249,30 @@ typedef struct insert_state { #define BACKSPACE_WORD_NOT_SPACE 3 #define BACKSPACE_LINE 4 -static size_t spell_bad_len = 0; /* length of located bad word */ +static size_t spell_bad_len = 0; // length of located bad word -static colnr_T Insstart_textlen; /* length of line when insert started */ -static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */ -static bool update_Insstart_orig = true; /* set Insstart_orig to Insstart */ +static colnr_T Insstart_textlen; // length of line when insert started +static colnr_T Insstart_blank_vcol; // vcol for first inserted blank +static bool update_Insstart_orig = true; // set Insstart_orig to Insstart -static char_u *last_insert = NULL; /* the text of the previous insert, - K_SPECIAL and CSI are escaped */ -static int last_insert_skip; /* nr of chars in front of previous insert */ -static int new_insert_skip; /* nr of chars in front of current insert */ -static int did_restart_edit; /* "restart_edit" when calling edit() */ +static char_u *last_insert = NULL; // the text of the previous insert, + // K_SPECIAL and CSI are escaped +static int last_insert_skip; // nr of chars in front of previous insert +static int new_insert_skip; // nr of chars in front of current insert +static int did_restart_edit; // "restart_edit" when calling edit() static bool can_cindent; // may do cindenting on this line -static int old_indent = 0; /* for ^^D command in insert mode */ +static int old_indent = 0; // for ^^D command in insert mode -static int revins_on; /* reverse insert mode on */ -static int revins_chars; /* how much to skip after edit */ -static int revins_legal; /* was the last char 'legal'? */ -static int revins_scol; /* start column of revins session */ +static int revins_on; // reverse insert mode on +static int revins_chars; // how much to skip after edit +static int revins_legal; // was the last char 'legal'? +static int revins_scol; // start column of revins session -static int ins_need_undo; /* call u_save() before inserting a - char. Set when edit() is called. - after that arrow_used is used. */ +static bool ins_need_undo; // call u_save() before inserting a + // char. Set when edit() is called. + // after that arrow_used is used. static bool did_add_space = false; // auto_format() added an extra space // under the cursor @@ -464,8 +464,8 @@ static void insert_enter(InsertState *s) change_warning(s->i == 0 ? 0 : s->i + 1); } - ui_cursor_shape(); /* may show different cursor shape */ - do_digraph(-1); /* clear digraphs */ + ui_cursor_shape(); // may show different cursor shape + do_digraph(-1); // clear digraphs // Get the current length of the redo buffer, those characters have to be // skipped if we want to get to the inserted characters. @@ -574,10 +574,8 @@ static int insert_check(VimState *state) foldCheckClose(); } - int cmdchar_todo = s->cmdchar; if (bt_prompt(curbuf)) { - init_prompt(cmdchar_todo); - cmdchar_todo = NUL; + init_prompt(s->cmdchar); } // If we inserted a character at the last position of the last line in the @@ -595,7 +593,7 @@ static int insert_check(VimState *state) if (curwin->w_wcol < s->mincol - curbuf->b_p_ts && curwin->w_wrow == curwin->w_winrow - + curwin->w_height_inner - 1 - p_so + + curwin->w_height_inner - 1 - get_scrolloff_value() && (curwin->w_cursor.lnum != curwin->w_topline || curwin->w_topfill > 0)) { if (curwin->w_topfill > 0) { @@ -1422,9 +1420,8 @@ bool edit(int cmdchar, bool startln, long count) * Only redraw when there are no characters available. This speeds up * inserting sequences of characters (e.g., for CTRL-R). */ -static void -ins_redraw ( - int ready /* not busy with something */ +static void ins_redraw( + bool ready // not busy with something ) { bool conceal_cursor_moved = false; @@ -1505,7 +1502,7 @@ ins_redraw ( } showruler(false); setcursor(); - emsg_on_display = FALSE; /* may remove error message now */ + emsg_on_display = false; // may remove error message now } /* @@ -1514,24 +1511,25 @@ ins_redraw ( static void ins_ctrl_v(void) { int c; - int did_putchar = FALSE; + bool did_putchar = false; - /* may need to redraw when no more chars available now */ - ins_redraw(FALSE); + // may need to redraw when no more chars available now + ins_redraw(false); if (redrawing() && !char_avail()) { - edit_putchar('^', TRUE); - did_putchar = TRUE; + edit_putchar('^', true); + did_putchar = true; } AppendToRedobuff(CTRL_V_STR); add_to_showcmd_c(Ctrl_V); c = get_literal(); - if (did_putchar) - /* when the line fits in 'columns' the '^' is at the start of the next - * line and will not removed by the redraw */ + if (did_putchar) { + // when the line fits in 'columns' the '^' is at the start of the next + // line and will not removed by the redraw edit_unputchar(); + } clear_showcmd(); insert_special(c, true, true); revins_chars++; @@ -1543,16 +1541,16 @@ static void ins_ctrl_v(void) * Used while handling CTRL-K, CTRL-V, etc. in Insert mode. */ static int pc_status; -#define PC_STATUS_UNSET 0 /* pc_bytes was not set */ -#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */ -#define PC_STATUS_LEFT 2 /* left halve of double-wide char */ -#define PC_STATUS_SET 3 /* pc_bytes was filled */ -static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */ +#define PC_STATUS_UNSET 0 // pc_bytes was not set +#define PC_STATUS_RIGHT 1 // right halve of double-wide char +#define PC_STATUS_LEFT 2 // left halve of double-wide char +#define PC_STATUS_SET 3 // pc_bytes was filled +static char_u pc_bytes[MB_MAXBYTES + 1]; // saved bytes static int pc_attr; static int pc_row; static int pc_col; -void edit_putchar(int c, int highlight) +void edit_putchar(int c, bool highlight) { int attr; @@ -1585,7 +1583,7 @@ void edit_putchar(int c, int highlight) } } - /* save the character to be able to put it back */ + // save the character to be able to put it back if (pc_status == PC_STATUS_UNSET) { grid_getbytes(&curwin->w_grid, pc_row, pc_col, pc_bytes, &pc_attr); pc_status = PC_STATUS_SET; @@ -1708,29 +1706,29 @@ change_indent ( int type, int amount, int round, - int replaced, /* replaced character, put on replace stack */ - int call_changed_bytes /* call changed_bytes() */ + int replaced, // replaced character, put on replace stack + int call_changed_bytes // call changed_bytes() ) { int vcol; int last_vcol; - int insstart_less; /* reduction for Insstart.col */ + int insstart_less; // reduction for Insstart.col int new_cursor_col; int i; char_u *ptr; int save_p_list; int start_col; colnr_T vc; - colnr_T orig_col = 0; /* init for GCC */ - char_u *new_line, *orig_line = NULL; /* init for GCC */ + colnr_T orig_col = 0; // init for GCC + char_u *new_line, *orig_line = NULL; // init for GCC - /* VREPLACE mode needs to know what the line was like before changing */ + // VREPLACE mode needs to know what the line was like before changing if (State & VREPLACE_FLAG) { - orig_line = vim_strsave(get_cursor_line_ptr()); /* Deal with NULL below */ + orig_line = vim_strsave(get_cursor_line_ptr()); // Deal with NULL below orig_col = curwin->w_cursor.col; } - /* for the following tricks we don't want list mode */ + // for the following tricks we don't want list mode save_p_list = curwin->w_p_list; curwin->w_p_list = FALSE; vc = getvcol_nolist(&curwin->w_cursor); @@ -1743,7 +1741,7 @@ change_indent ( */ start_col = curwin->w_cursor.col; - /* determine offset from first non-blank */ + // determine offset from first non-blank new_cursor_col = curwin->w_cursor.col; beginline(BL_WHITE); new_cursor_col -= curwin->w_cursor.col; @@ -1757,8 +1755,9 @@ change_indent ( if (new_cursor_col < 0) vcol = get_indent() - vcol; - if (new_cursor_col > 0) /* can't fix replace stack */ + if (new_cursor_col > 0) { // can't fix replace stack start_col = -1; + } /* * Set the new indent. The cursor will be put on the first non-blank. @@ -1768,9 +1767,10 @@ change_indent ( else { int save_State = State; - /* Avoid being called recursively. */ - if (State & VREPLACE_FLAG) + // Avoid being called recursively. + if (State & VREPLACE_FLAG) { State = INSERT; + } shift_line(type == INDENT_DEC, round, 1, call_changed_bytes); State = save_State; } @@ -1873,8 +1873,8 @@ change_indent ( */ if (REPLACE_NORMAL(State) && start_col >= 0) { while (start_col > (int)curwin->w_cursor.col) { - replace_join(0); /* remove a NUL from the replace stack */ - --start_col; + replace_join(0); // remove a NUL from the replace stack + start_col--; } while (start_col < (int)curwin->w_cursor.col || replaced) { replace_push(NUL); @@ -1892,10 +1892,10 @@ change_indent ( * put it back again the way we wanted it. */ if (State & VREPLACE_FLAG) { - /* Save new line */ + // Save new line new_line = vim_strsave(get_cursor_line_ptr()); - /* We only put back the new line up to the cursor */ + // We only put back the new line up to the cursor new_line[curwin->w_cursor.col] = NUL; int new_col = curwin->w_cursor.col; @@ -1905,10 +1905,10 @@ change_indent ( curbuf_splice_pending++; - /* Backspace from cursor to start of line */ + // Backspace from cursor to start of line backspace_until_column(0); - /* Insert new stuff into line again */ + // Insert new stuff into line again ins_bytes(new_line); xfree(new_line); @@ -1934,10 +1934,11 @@ void truncate_spaces(char_u *line) { int i; - /* find start of trailing white space */ + // find start of trailing white space for (i = (int)STRLEN(line) - 1; i >= 0 && ascii_iswhite(line[i]); i--) { - if (State & REPLACE_FLAG) - replace_join(0); /* remove a NUL from the replace stack */ + if (State & REPLACE_FLAG) { + replace_join(0); // remove a NUL from the replace stack + } } line[i + 1] = NUL; } @@ -2006,7 +2007,7 @@ static void ins_ctrl_x(void) compl_cont_status |= CONT_INTRPT; else compl_cont_status = 0; - /* We're not sure which CTRL-X mode it will be yet */ + // We're not sure which CTRL-X mode it will be yet ctrl_x_mode = CTRL_X_NOT_DEFINED_YET; edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode)); edit_submode_pre = NULL; @@ -2155,8 +2156,8 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, { char_u *str = str_arg; int i, c; - int actual_len; /* Take multi-byte characters */ - int actual_compl_length; /* into account. */ + int actual_len; // Take multi-byte characters + int actual_compl_length; // into account. int min_len; bool has_lower = false; bool was_letter = false; @@ -2176,16 +2177,15 @@ int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, } else actual_len = len; - /* Find actual length of original text. */ - if (has_mbyte) { + // Find actual length of original text. + { const char_u *p = compl_orig_text; actual_compl_length = 0; while (*p != NUL) { MB_PTR_ADV(p); actual_compl_length++; } - } else - actual_compl_length = compl_length; + } /* "actual_len" may be smaller than "actual_compl_length" when using * thesaurus, only use the minimum when comparing. */ @@ -2355,7 +2355,7 @@ static int ins_compl_add(char_u *const str, int len, } while (match != NULL && match != compl_first_match); } - /* Remove any popup menu before changing the list of matches. */ + // Remove any popup menu before changing the list of matches. ins_compl_del_pum(); /* @@ -2411,16 +2411,18 @@ static int ins_compl_add(char_u *const str, int len, else if (dir == FORWARD) { match->cp_next = compl_curr_match->cp_next; match->cp_prev = compl_curr_match; - } else { /* BACKWARD */ + } else { // BACKWARD match->cp_next = compl_curr_match; match->cp_prev = compl_curr_match->cp_prev; } - if (match->cp_next) + if (match->cp_next) { match->cp_next->cp_prev = match; - if (match->cp_prev) + } + if (match->cp_prev) { match->cp_prev->cp_next = match; - else /* if there's nothing before, it is the first match */ + } else { // if there's nothing before, it is the first match compl_first_match = match; + } compl_curr_match = match; /* @@ -2461,7 +2463,7 @@ static void ins_compl_longest_match(compl_T *match) int had_match; if (compl_leader == NULL) { - /* First match, use it as a whole. */ + // First match, use it as a whole. compl_leader = vim_strsave(match->cp_str); had_match = (curwin->w_cursor.col > compl_col); ins_compl_delete(); @@ -2474,7 +2476,7 @@ static void ins_compl_longest_match(compl_T *match) ins_compl_delete(); compl_used_match = false; } else { - /* Reduce the text if this match differs from compl_leader. */ + // Reduce the text if this match differs from compl_leader. p = compl_leader; s = match->cp_str; while (*p != NUL) { @@ -2491,7 +2493,7 @@ static void ins_compl_longest_match(compl_T *match) } if (*p != NUL) { - /* Leader was shortened, need to change the inserted text. */ + // Leader was shortened, need to change the inserted text. *p = NUL; had_match = (curwin->w_cursor.col > compl_col); ins_compl_delete(); @@ -2541,7 +2543,7 @@ static int ins_compl_make_cyclic(void) * Find the end of the list. */ match = compl_first_match; - /* there's always an entry for the compl_orig_text, it doesn't count. */ + // there's always an entry for the compl_orig_text, it doesn't count. while (match->cp_next != NULL && match->cp_next != compl_first_match) { match = match->cp_next; ++count; @@ -2588,7 +2590,7 @@ void set_completion(colnr_T startcol, list_T *list) startcol = curwin->w_cursor.col; compl_col = startcol; compl_length = (int)curwin->w_cursor.col - (int)startcol; - /* compl_pattern doesn't need to be set */ + // compl_pattern doesn't need to be set compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col, compl_length); if (p_ic) { @@ -2721,10 +2723,10 @@ void ins_compl_show_pum(void) if (!pum_wanted() || !pum_enough_matches()) return; - /* Dirty hard-coded hack: remove any matchparen highlighting. */ + // Dirty hard-coded hack: remove any matchparen highlighting. do_cmdline_cmd("if exists('g:loaded_matchparen')|3match none|endif"); - /* Update the screen before drawing the popup menu over it. */ + // Update the screen before drawing the popup menu over it. update_screen(0); if (compl_match_array == NULL) { @@ -2815,17 +2817,19 @@ void ins_compl_show_pum(void) compl = compl->cp_next; } while (compl != NULL && compl != compl_first_match); - if (!shown_match_ok) /* no displayed match at all */ + if (!shown_match_ok) { // no displayed match at all cur = -1; + } } else { - /* popup menu already exists, only need to find the current item.*/ - for (i = 0; i < compl_match_arraysize; ++i) + // popup menu already exists, only need to find the current item. + for (i = 0; i < compl_match_arraysize; i++) { if (compl_match_array[i].pum_text == compl_shown_match->cp_str || compl_match_array[i].pum_text == compl_shown_match->cp_text[CPT_ABBR]) { cur = i; break; } + } } // In Replace mode when a $ is displayed at the end of the line only @@ -2845,8 +2849,8 @@ void ins_compl_show_pum(void) } } -#define DICT_FIRST (1) /* use just first element in "dict" */ -#define DICT_EXACT (2) /* "dict" is the exact name of a file */ +#define DICT_FIRST (1) // use just first element in "dict" +#define DICT_EXACT (2) // "dict" is the exact name of a file /* * Add any identifiers that match the given pattern in the list of dictionary @@ -2856,8 +2860,8 @@ static void ins_compl_dictionaries ( char_u *dict_start, char_u *pat, - int flags, /* DICT_FIRST and/or DICT_EXACT */ - int thesaurus /* Thesaurus completion */ + int flags, // DICT_FIRST and/or DICT_EXACT + int thesaurus // Thesaurus completion ) { char_u *dict = dict_start; @@ -2879,9 +2883,9 @@ ins_compl_dictionaries ( } buf = xmalloc(LSIZE); - regmatch.regprog = NULL; /* so that we can goto theend */ + regmatch.regprog = NULL; // so that we can goto theend - /* If 'infercase' is set, don't use 'smartcase' here */ + // If 'infercase' is set, don't use 'smartcase' here save_p_scs = p_scs; if (curbuf->b_p_inf) p_scs = FALSE; @@ -2904,10 +2908,10 @@ ins_compl_dictionaries ( goto theend; } - /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */ + // ignore case depends on 'ignorecase', 'smartcase' and "pat" regmatch.rm_ic = ignorecase(pat); while (*dict != NUL && !got_int && !compl_interrupted) { - /* copy one dictionary file name into buf */ + // copy one dictionary file name into buf if (flags == DICT_EXACT) { count = 1; files = &dict; @@ -2932,7 +2936,7 @@ ins_compl_dictionaries ( else ptr = pat; spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0); - } else if (count > 0) { /* avoid warning for using "files" uninit */ + } else if (count > 0) { // avoid warning for using "files" uninit ins_compl_files(count, files, thesaurus, flags, ®match, buf, &dir); if (flags != DICT_EXACT) @@ -2998,20 +3002,18 @@ static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, break; wstart = ptr; - /* Find end of the word. */ - if (has_mbyte) - /* Japanese words may have characters in - * different classes, only separate words - * with single-byte non-word characters. */ - while (*ptr != NUL) { - int l = (*mb_ptr2len)(ptr); - - if (l < 2 && !vim_iswordc(*ptr)) - break; - ptr += l; + // Find end of the word. + // Japanese words may have characters in + // different classes, only separate words + // with single-byte non-word characters. + while (*ptr != NUL) { + const int l = utfc_ptr2len(ptr); + + if (l < 2 && !vim_iswordc(*ptr)) { + break; } - else - ptr = find_word_end(ptr); + ptr += l; + } // Add the word. Skip the regexp match. if (wstart != regmatch->startp[0]) { @@ -3020,15 +3022,17 @@ static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, } } } - if (add_r == OK) - /* if dir was BACKWARD then honor it just once */ + if (add_r == OK) { + // if dir was BACKWARD then honor it just once *dir = FORWARD; - else if (add_r == FAIL) + } else if (add_r == FAIL) { break; - /* avoid expensive call to vim_regexec() when at end - * of line */ - if (*ptr == '\n' || got_int) + } + // avoid expensive call to vim_regexec() when at end + // of line + if (*ptr == '\n' || got_int) { break; + } } line_breakcheck(); ins_compl_check_keys(50, false); @@ -3275,9 +3279,10 @@ static int ins_compl_bs(void) xfree(compl_leader); compl_leader = vim_strnsave(line + compl_col, (int)(p - line) - compl_col); ins_compl_new_leader(); - if (compl_shown_match != NULL) - /* Make sure current match is not a hidden item. */ + if (compl_shown_match != NULL) { + // Make sure current match is not a hidden item. compl_curr_match = compl_shown_match; + } return NUL; } @@ -3321,7 +3326,7 @@ static void ins_compl_new_leader(void) compl_enter_selects = !compl_used_match; - /* Show the popup menu with a different set of matches. */ + // Show the popup menu with a different set of matches. ins_compl_show_pum(); /* Don't let Enter select the original text when there is no popup menu. @@ -3364,9 +3369,10 @@ static void ins_compl_addleader(int c) ins_char(c); } - /* If we didn't complete finding matches we must search again. */ - if (ins_compl_need_restart()) + // If we didn't complete finding matches we must search again. + if (ins_compl_need_restart()) { ins_compl_restart(); + } xfree(compl_leader); compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col, @@ -3422,9 +3428,9 @@ static void ins_compl_addfrommatch(void) compl_T *cp; assert(compl_shown_match != NULL); p = compl_shown_match->cp_str; - if ((int)STRLEN(p) <= len) { /* the match is too short */ - /* When still at the original match use the first entry that matches - * the leader. */ + if ((int)STRLEN(p) <= len) { // the match is too short + // When still at the original match use the first entry that matches + // the leader. if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) { p = NULL; for (cp = compl_shown_match->cp_next; cp != NULL @@ -3464,14 +3470,14 @@ static bool ins_compl_prep(int c) if (c != Ctrl_R && vim_is_ctrl_x_key(c)) edit_submode_extra = NULL; - /* Ignore end of Select mode mapping and mouse scroll buttons. */ + // Ignore end of Select mode mapping and mouse scroll buttons. if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT || c == K_COMMAND) { return retval; } - /* Set "compl_get_longest" when finding the first matches. */ + // Set "compl_get_longest" when finding the first matches. if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || (ctrl_x_mode == CTRL_X_NORMAL && !compl_started)) { compl_get_longest = (strstr((char *)p_cot, "longest") != NULL); @@ -3504,7 +3510,7 @@ static bool ins_compl_prep(int c) ctrl_x_mode = CTRL_X_DICTIONARY; break; case Ctrl_R: - /* Simply allow ^R to happen without affecting ^X mode */ + // Simply allow ^R to happen without affecting ^X mode break; case Ctrl_T: ctrl_x_mode = CTRL_X_THESAURUS; @@ -3518,9 +3524,9 @@ static bool ins_compl_prep(int c) case 's': case Ctrl_S: ctrl_x_mode = CTRL_X_SPELL; - ++emsg_off; /* Avoid getting the E756 error twice. */ + emsg_off++; // Avoid getting the E756 error twice. spell_back_to_badword(); - --emsg_off; + emsg_off--; break; case Ctrl_RSB: ctrl_x_mode = CTRL_X_TAGS; @@ -3619,10 +3625,10 @@ static bool ins_compl_prep(int c) // When completing whole lines: fix indent for 'cindent'. // Otherwise, break line if it's too long. if (compl_cont_mode == CTRL_X_WHOLE_LINE) { - /* re-indent the current line */ + // re-indent the current line if (want_cindent) { do_c_expr_indent(); - want_cindent = FALSE; /* don't do it again */ + want_cindent = false; // don't do it again } } else { int prev_col = curwin->w_cursor.col; @@ -3726,10 +3732,11 @@ static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg) char_u *ptr = ptr_arg; if (ptr == NULL) { - if (compl_leader != NULL) + if (compl_leader != NULL) { ptr = compl_leader; - else - return; /* nothing to do */ + } else { + return; // nothing to do + } } if (compl_orig_text != NULL) { p = compl_orig_text; @@ -3758,9 +3765,10 @@ static buf_T *ins_compl_next_buf(buf_T *buf, int flag) { static win_T *wp; - if (flag == 'w') { /* just windows */ - if (buf == curbuf) /* first call for this flag/expansion */ + if (flag == 'w') { // just windows + if (buf == curbuf) { // first call for this flag/expansion wp = curwin; + } assert(wp); while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin && wp->w_buffer->b_scanned) @@ -3838,7 +3846,7 @@ expand_by_function( EMSG(_(e_complwin)); goto theend; } - curwin->w_cursor = pos; /* restore the cursor position */ + curwin->w_cursor = pos; // restore the cursor position validate_cursor(); if (!equalpos(curwin->w_cursor, pos)) { EMSG(_(e_compldel)); @@ -4085,7 +4093,7 @@ static int ins_compl_get_exp(pos_T *ini) type = CTRL_X_PATH_DEFINES; else if (*e_cpt == ']' || *e_cpt == 't') { type = CTRL_X_TAGS; - vim_snprintf((char *)IObuff, IOSIZE, _("Scanning tags.")); + vim_snprintf((char *)IObuff, IOSIZE, "%s", _("Scanning tags.")); (void)msg_trunc_attr(IObuff, true, HL_ATTR(HLF_R)); } else { type = -1; @@ -4476,8 +4484,7 @@ ins_compl_next ( int num_matches = -1; int todo = count; compl_T *found_compl = NULL; - int found_end = FALSE; - int advance; + bool found_end = false; const bool started = compl_started; /* When user complete function return -1 for findstart which is next @@ -4513,17 +4520,17 @@ ins_compl_next ( if (allow_get_expansion && insert_match && (!(compl_get_longest || compl_restarting) || compl_used_match)) - /* Delete old text to be replaced */ + // Delete old text to be replaced ins_compl_delete(); - /* When finding the longest common text we stick at the original text, - * don't let CTRL-N or CTRL-P move to the first match. */ - advance = count != 1 || !allow_get_expansion || !compl_get_longest; + // When finding the longest common text we stick at the original text, + // don't let CTRL-N or CTRL-P move to the first match. + bool advance = count != 1 || !allow_get_expansion || !compl_get_longest; - /* When restarting the search don't insert the first match either. */ + // When restarting the search don't insert the first match either. if (compl_restarting) { - advance = FALSE; - compl_restarting = FALSE; + advance = false; + compl_restarting = false; } /* Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap @@ -4557,10 +4564,10 @@ ins_compl_next ( ++compl_pending; } - /* Find matches. */ + // Find matches. num_matches = ins_compl_get_exp(&compl_startpos); - /* handle any pending completions */ + // handle any pending completions while (compl_pending != 0 && compl_direction == compl_shows_dir && advance) { if (compl_pending > 0 && compl_shown_match->cp_next != NULL) { @@ -4573,7 +4580,7 @@ ins_compl_next ( } else break; } - found_end = FALSE; + found_end = false; } if ((compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0 && compl_leader != NULL @@ -4585,17 +4592,17 @@ ins_compl_next ( found_compl = compl_shown_match; } - /* Stop at the end of the list when we found a usable match. */ + // Stop at the end of the list when we found a usable match. if (found_end) { if (found_compl != NULL) { compl_shown_match = found_compl; break; } - todo = 1; /* use first usable match after wrapping around */ + todo = 1; // use first usable match after wrapping around } } - /* Insert the text of the new completion, or the compl_leader. */ + // Insert the text of the new completion, or the compl_leader. if (compl_no_insert && !started) { ins_bytes(compl_orig_text + ins_compl_len()); compl_used_match = false; @@ -4689,9 +4696,10 @@ void ins_compl_check_keys(int frequency, int in_compl_func) return; } - /* Only do this at regular intervals */ - if (++count < frequency) + // Only do this at regular intervals + if (++count < frequency) { return; + } count = 0; /* Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key() @@ -4699,7 +4707,7 @@ void ins_compl_check_keys(int frequency, int in_compl_func) int c = vpeekc_any(); if (c != NUL) { if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R) { - c = safe_vgetc(); /* Eat the character */ + c = safe_vgetc(); // Eat the character compl_shows_dir = ins_compl_key2dir(c); (void)ins_compl_next(false, ins_compl_key2count(c), c != K_UP && c != K_DOWN, in_compl_func); @@ -4768,8 +4776,9 @@ static int ins_compl_key2count(int c) if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN) { h = pum_get_height(); - if (h > 3) - h -= 2; /* keep some context */ + if (h > 3) { + h -= 2; // keep some context + } return h; } return 1; @@ -4807,8 +4816,8 @@ static bool ins_compl_use_match(int c) static int ins_complete(int c, bool enable_pum) { char_u *line; - int startcol = 0; /* column where searched text starts */ - colnr_T curs_col; /* cursor column */ + int startcol = 0; // column where searched text starts + colnr_T curs_col; // cursor column int n; int save_w_wrow; int save_w_leftcol; @@ -4820,7 +4829,7 @@ static int ins_complete(int c, bool enable_pum) insert_match = ins_compl_use_match(c); if (!compl_started) { - /* First time we hit ^N or ^P (in a row, I mean) */ + // First time we hit ^N or ^P (in a row, I mean) did_ai = false; did_si = false; @@ -4858,7 +4867,7 @@ static int ins_complete(int c, bool enable_pum) compl_col = (colnr_T)getwhitecols(line); compl_startpos.col = compl_col; compl_startpos.lnum = curwin->w_cursor.lnum; - compl_cont_status &= ~CONT_SOL; /* clear SOL if present */ + compl_cont_status &= ~CONT_SOL; // clear SOL if present } else { /* S_IPOS was set when we inserted a word that was at the * beginning of the line, which means that we'll go to SOL @@ -4890,7 +4899,7 @@ static int ins_complete(int c, bool enable_pum) } else compl_cont_status &= CONT_LOCAL; - if (!(compl_cont_status & CONT_ADDING)) { /* normal expansion */ + if (!(compl_cont_status & CONT_ADDING)) { // normal expansion compl_cont_mode = ctrl_x_mode; if (ctrl_x_mode != CTRL_X_NORMAL) { // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL @@ -4919,7 +4928,7 @@ static int ins_complete(int c, bool enable_pum) } else if (compl_cont_status & CONT_ADDING) { char_u *prefix = (char_u *)"\\<"; - /* we need up to 2 extra chars for the prefix */ + // we need up to 2 extra chars for the prefix compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2); if (!vim_iswordp(line + compl_col) @@ -4971,14 +4980,16 @@ static int ins_complete(int c, bool enable_pum) } else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) { compl_col = (colnr_T)getwhitecols(line); compl_length = (int)curs_col - (int)compl_col; - if (compl_length < 0) /* cursor in indent: empty pattern */ + if (compl_length < 0) { // cursor in indent: empty pattern compl_length = 0; - if (p_ic) + } + if (p_ic) { compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0); - else + } else { compl_pattern = vim_strnsave(line + compl_col, compl_length); + } } else if (ctrl_x_mode == CTRL_X_FILES) { - /* Go back to just before the first filename character. */ + // Go back to just before the first filename character. if (startcol > 0) { char_u *p = line + startcol; @@ -5050,7 +5061,7 @@ static int ins_complete(int c, bool enable_pum) EMSG(_(e_complwin)); return FAIL; } - curwin->w_cursor = pos; /* restore the cursor position */ + curwin->w_cursor = pos; // restore the cursor position validate_cursor(); if (!equalpos(curwin->w_cursor, pos)) { EMSG(_(e_compldel)); @@ -5102,7 +5113,7 @@ static int ins_complete(int c, bool enable_pum) spell_expand_check_cap(compl_col); compl_length = (int)curs_col - compl_col; } - /* Need to obtain "line" again, it may have become invalid. */ + // Need to obtain "line" again, it may have become invalid. line = ml_get(curwin->w_cursor.lnum); compl_pattern = vim_strnsave(line + compl_col, compl_length); } else { @@ -5113,7 +5124,7 @@ static int ins_complete(int c, bool enable_pum) if (compl_cont_status & CONT_ADDING) { edit_submode_pre = (char_u *)_(" Adding"); if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) { - /* Insert a new line, keep indentation but ignore 'comments' */ + // Insert a new line, keep indentation but ignore 'comments' char_u *old = curbuf->b_p_com; curbuf->b_p_com = (char_u *)""; @@ -5138,7 +5149,7 @@ static int ins_complete(int c, bool enable_pum) * the redo buffer. */ ins_compl_fixRedoBufForLeader(NULL); - /* Always add completion for the original text. */ + // Always add completion for the original text. xfree(compl_orig_text); compl_orig_text = vim_strnsave(line + compl_col, compl_length); if (p_ic) { @@ -5175,8 +5186,9 @@ static int ins_complete(int c, bool enable_pum) n = ins_compl_next(true, ins_compl_key2count(c), insert_match, false); - if (n > 1) /* all matches have been found */ + if (n > 1) { // all matches have been found compl_matches = n; + } compl_curr_match = compl_shown_match; compl_direction = compl_shows_dir; @@ -5187,7 +5199,7 @@ static int ins_complete(int c, bool enable_pum) got_int = FALSE; } - /* we found no match if the list has only the "compl_orig_text"-entry */ + // we found no match if the list has only the "compl_orig_text"-entry if (compl_first_match == compl_first_match->cp_next) { edit_submode_extra = (compl_cont_status & CONT_ADDING) && compl_length > 1 @@ -5223,7 +5235,7 @@ static int ins_complete(int c, bool enable_pum) edit_submode_extra = (char_u *)_("The only match"); edit_submode_highl = HLF_COUNT; } else { - /* Update completion sequence number when needed. */ + // Update completion sequence number when needed. if (compl_curr_match->cp_number == -1) { int number = 0; compl_T *match; @@ -5246,24 +5258,27 @@ static int ins_complete(int c, bool enable_pum) match != NULL && match->cp_number == -1; match = match->cp_next) match->cp_number = ++number; - } else { /* BACKWARD */ - /* search forwards (upwards) for the first valid (!= -1) - * number. This should normally succeed already at the - * first loop cycle, so it's fast! */ - for (match = compl_curr_match->cp_next; match != NULL - && match != compl_first_match; - match = match->cp_next) + } else { // BACKWARD + // search forwards (upwards) for the first valid (!= -1) + // number. This should normally succeed already at the + // first loop cycle, so it's fast! + for (match = compl_curr_match->cp_next; + match != NULL && match != compl_first_match; + match = match->cp_next) { if (match->cp_number != -1) { number = match->cp_number; break; } - if (match != NULL) - /* go down and assign all numbers which are not - * assigned yet */ - for (match = match->cp_prev; match - && match->cp_number == -1; - match = match->cp_prev) + } + if (match != NULL) { + // go down and assign all numbers which are not + // assigned yet + for (match = match->cp_prev; + match && match->cp_number == -1; + match = match->cp_prev) { match->cp_number = ++number; + } + } } } @@ -5322,7 +5337,7 @@ static int ins_complete(int c, bool enable_pum) */ static unsigned quote_meta(char_u *dest, char_u *src, int len) { - unsigned m = (unsigned)len + 1; /* one extra for the NUL */ + unsigned m = (unsigned)len + 1; // one extra for the NUL for (; --len >= 0; src++) { switch (*src) { @@ -5334,8 +5349,9 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len) break; FALLTHROUGH; case '~': - if (!p_magic) /* quote these only if magic is set */ + if (!p_magic) { // quote these only if magic is set break; + } FALLTHROUGH; case '\\': if (ctrl_x_mode == CTRL_X_DICTIONARY @@ -5345,24 +5361,24 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len) case '^': // currently it's not needed. case '$': m++; - if (dest != NULL) + if (dest != NULL) { *dest++ = '\\'; + } break; } - if (dest != NULL) + if (dest != NULL) { *dest++ = *src; - /* Copy remaining bytes of a multibyte character. */ - if (has_mbyte) { - int i, mb_len; - - mb_len = (*mb_ptr2len)(src) - 1; - if (mb_len > 0 && len >= mb_len) - for (i = 0; i < mb_len; ++i) { - --len; - ++src; - if (dest != NULL) - *dest++ = *src; + } + // Copy remaining bytes of a multibyte character. + const int mb_len = utfc_ptr2len(src) - 1; + if (mb_len > 0 && len >= mb_len) { + for (int i = 0; i < mb_len; i++) { + len--; + src++; + if (dest != NULL) { + *dest++ = *src; } + } } } if (dest != NULL) @@ -5389,7 +5405,7 @@ int get_literal(void) if (got_int) return Ctrl_C; - ++no_mapping; /* don't map the next key hits */ + no_mapping++; // don't map the next key hits cc = 0; i = 0; for (;; ) { @@ -5427,20 +5443,23 @@ int get_literal(void) if (cc > 255 && unicode == 0 ) - cc = 255; /* limit range to 0-255 */ + cc = 255; // limit range to 0-255 nc = 0; - if (hex) { /* hex: up to two chars */ - if (i >= 2) + if (hex) { // hex: up to two chars + if (i >= 2) { break; - } else if (unicode) { /* Unicode: up to four or eight chars */ - if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8)) + } + } else if (unicode) { // Unicode: up to four or eight chars + if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8)) { break; - } else if (i >= 3) /* decimal or octal: up to three chars */ + } + } else if (i >= 3) { // decimal or octal: up to three chars break; + } } - if (i == 0) { /* no number entered */ - if (nc == K_ZERO) { /* NUL is stored as NL */ + if (i == 0) { // no number entered + if (nc == K_ZERO) { // NUL is stored as NL cc = '\n'; nc = 0; } else { @@ -5456,7 +5475,7 @@ int get_literal(void) --no_mapping; if (nc) vungetc(nc); - got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */ + got_int = false; // CTRL-C typed after CTRL-V is not an interrupt return cc; } @@ -5519,11 +5538,10 @@ static void insert_special(int c, int allow_modmask, int ctrlv) * INSCHAR_DO_COM - format comments * INSCHAR_COM_LIST - format comments with num list or 2nd line indent */ -void -insertchar ( - int c, /* character to insert or NUL */ - int flags, /* INSCHAR_FORMAT, etc. */ - int second_indent /* indent for second line if >= 0 */ +void insertchar( + int c, // character to insert or NUL + int flags, // INSCHAR_FORMAT, etc. + int second_indent // indent for second line if >= 0 ) { int textwidth; @@ -5559,27 +5577,27 @@ insertchar ( || ((!has_format_option(FO_INS_LONG) || Insstart_textlen <= (colnr_T)textwidth) && (!fo_ins_blank - || Insstart_blank_vcol <= (colnr_T)textwidth - )))))) { - /* Format with 'formatexpr' when it's set. Use internal formatting - * when 'formatexpr' isn't set or it returns non-zero. */ - int do_internal = TRUE; + || Insstart_blank_vcol <= (colnr_T)textwidth)))))) { + // Format with 'formatexpr' when it's set. Use internal formatting + // when 'formatexpr' isn't set or it returns non-zero. + bool do_internal = true; colnr_T virtcol = get_nolist_virtcol() + char2cells(c != NUL ? c : gchar_cursor()); if (*curbuf->b_p_fex != NUL && (flags & INSCHAR_NO_FEX) == 0 && (force_format || virtcol > (colnr_T)textwidth)) { do_internal = (fex_format(curwin->w_cursor.lnum, 1L, c) != 0); - /* It may be required to save for undo again, e.g. when setline() - * was called. */ - ins_need_undo = TRUE; + // It may be required to save for undo again, e.g. when setline() + // was called. + ins_need_undo = true; } if (do_internal) internal_format(textwidth, second_indent, flags, c == NUL, c); } - if (c == NUL) /* only formatting was wanted */ + if (c == NUL) { // only formatting was wanted return; + } // Check whether this character should end a comment. if (did_ai && c == end_comment_pending) { @@ -5683,8 +5701,8 @@ insertchar ( buf[i++] = c; } - do_digraph(-1); /* clear digraphs */ - do_digraph(buf[i-1]); /* may be the start of a digraph */ + do_digraph(-1); // clear digraphs + do_digraph(buf[i-1]); // may be the start of a digraph buf[i] = NUL; ins_str(buf); if (flags & INSCHAR_CTRLV) { @@ -5727,7 +5745,7 @@ internal_format ( int second_indent, int flags, int format_only, - int c /* character to be inserted (can be NUL) */ + int c // character to be inserted (can be NUL) ) { int cc; @@ -5738,7 +5756,7 @@ internal_format ( int fo_white_par = has_format_option(FO_WHITE_PAR); int first_line = TRUE; colnr_T leader_len; - int no_leader = FALSE; + bool no_leader = false; int do_comments = (flags & INSCHAR_DO_COM); int has_lbr = curwin->w_p_lbr; @@ -5763,10 +5781,10 @@ internal_format ( * Repeat breaking lines, until the current line is not too long. */ while (!got_int) { - int startcol; /* Cursor column at entry */ - int wantcol; /* column at textwidth border */ - int foundcol; /* column for start of spaces */ - int end_foundcol = 0; /* column for start of word */ + int startcol; // Cursor column at entry + int wantcol; // column at textwidth border + int foundcol; // column for start of spaces + int end_foundcol = 0; // column for start of word colnr_T len; colnr_T virtcol; int orig_col = 0; @@ -5779,33 +5797,37 @@ internal_format ( if (virtcol <= (colnr_T)textwidth) break; - if (no_leader) - do_comments = FALSE; - else if (!(flags & INSCHAR_FORMAT) - && has_format_option(FO_WRAP_COMS)) - do_comments = TRUE; + if (no_leader) { + do_comments = false; + } else if (!(flags & INSCHAR_FORMAT) + && has_format_option(FO_WRAP_COMS)) { + do_comments = true; + } - /* Don't break until after the comment leader */ - if (do_comments) - leader_len = get_leader_len(get_cursor_line_ptr(), NULL, FALSE, TRUE); - else + // Don't break until after the comment leader + if (do_comments) { + leader_len = get_leader_len(get_cursor_line_ptr(), NULL, false, true); + } else { leader_len = 0; + } - /* If the line doesn't start with a comment leader, then don't - * start one in a following broken line. Avoids that a %word - * moved to the start of the next line causes all following lines - * to start with %. */ - if (leader_len == 0) - no_leader = TRUE; + // If the line doesn't start with a comment leader, then don't + // start one in a following broken line. Avoids that a %word + // moved to the start of the next line causes all following lines + // to start with %. + if (leader_len == 0) { + no_leader = true; + } if (!(flags & INSCHAR_FORMAT) && leader_len == 0 - && !has_format_option(FO_WRAP)) - + && !has_format_option(FO_WRAP)) { break; - if ((startcol = curwin->w_cursor.col) == 0) + } + if ((startcol = curwin->w_cursor.col) == 0) { break; + } - /* find column of textwidth border */ + // find column of textwidth border coladvance((colnr_T)textwidth); wantcol = curwin->w_cursor.col; @@ -5825,7 +5847,7 @@ internal_format ( else cc = gchar_cursor(); if (WHITECHAR(cc)) { - /* remember position of blank just before text */ + // remember position of blank just before text end_col = curwin->w_cursor.col; // find start of sequence of blanks @@ -5856,18 +5878,21 @@ internal_format ( } if (has_format_option(FO_ONE_LETTER)) { - /* do not break after one-letter words */ - if (curwin->w_cursor.col == 0) - break; /* one-letter word at begin */ - /* do not break "#a b" when 'tw' is 2 */ - if (curwin->w_cursor.col <= leader_len) + // do not break after one-letter words + if (curwin->w_cursor.col == 0) { + break; // one-letter word at begin + } + // do not break "#a b" when 'tw' is 2 + if (curwin->w_cursor.col <= leader_len) { break; + } col = curwin->w_cursor.col; dec_cursor(); cc = gchar_cursor(); - if (WHITECHAR(cc)) - continue; /* one-letter, continue */ + if (WHITECHAR(cc)) { + continue; // one-letter, continue + } curwin->w_cursor.col = col; } @@ -5878,14 +5903,15 @@ internal_format ( if (curwin->w_cursor.col <= (colnr_T)wantcol) break; } else if (cc >= 0x100 && fo_multibyte) { - /* Break after or before a multi-byte character. */ + // Break after or before a multi-byte character. if (curwin->w_cursor.col != startcol) { - /* Don't break until after the comment leader */ - if (curwin->w_cursor.col < leader_len) + // Don't break until after the comment leader + if (curwin->w_cursor.col < leader_len) { break; + } col = curwin->w_cursor.col; inc_cursor(); - /* Don't change end_foundcol if already set. */ + // Don't change end_foundcol if already set. if (foundcol != curwin->w_cursor.col) { foundcol = curwin->w_cursor.col; end_foundcol = foundcol; @@ -5903,11 +5929,13 @@ internal_format ( dec_cursor(); cc = gchar_cursor(); - if (WHITECHAR(cc)) - continue; /* break with space */ - /* Don't break until after the comment leader */ - if (curwin->w_cursor.col < leader_len) + if (WHITECHAR(cc)) { + continue; // break with space + } + // Don't break until after the comment leader + if (curwin->w_cursor.col < leader_len) { break; + } curwin->w_cursor.col = col; @@ -5921,12 +5949,12 @@ internal_format ( dec_cursor(); } - if (foundcol == 0) { /* no spaces, cannot break line */ + if (foundcol == 0) { // no spaces, cannot break line curwin->w_cursor.col = startcol; break; } - /* Going to break the line, remove any "$" now. */ + // Going to break the line, remove any "$" now. undisplay_dollar(); /* @@ -5934,10 +5962,11 @@ internal_format ( * stack functions. VREPLACE does not use this, and backspaces * over the text instead. */ - if (State & VREPLACE_FLAG) - orig_col = startcol; /* Will start backspacing from here */ - else + if (State & VREPLACE_FLAG) { + orig_col = startcol; // Will start backspacing from here + } else { replace_offset = startcol - end_foundcol; + } /* * adjust startcol for spaces that will be deleted and @@ -5960,13 +5989,15 @@ internal_format ( curwin->w_cursor.col = orig_col; saved_text[startcol] = NUL; - /* Backspace over characters that will move to the next line */ - if (!fo_white_par) + // Backspace over characters that will move to the next line + if (!fo_white_par) { backspace_until_column(foundcol); + } } else { - /* put cursor after pos. to break line */ - if (!fo_white_par) + // put cursor after pos. to break line + if (!fo_white_par) { curwin->w_cursor.col = foundcol; + } } /* @@ -5984,32 +6015,29 @@ internal_format ( replace_offset = 0; if (first_line) { if (!(flags & INSCHAR_COM_LIST)) { - /* - * This section is for auto-wrap of numeric lists. When not - * in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST - * flag will be set and open_line() will handle it (as seen - * above). The code here (and in get_number_indent()) will - * recognize comments if needed... - */ - if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) - second_indent = - get_number_indent(curwin->w_cursor.lnum - 1); + // This section is for auto-wrap of numeric lists. When not + // in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST + // flag will be set and open_line() will handle it (as seen + // above). The code here (and in get_number_indent()) will + // recognize comments if needed... + if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) { + second_indent = get_number_indent(curwin->w_cursor.lnum - 1); + } if (second_indent >= 0) { - if (State & VREPLACE_FLAG) - change_indent(INDENT_SET, second_indent, - FALSE, NUL, TRUE); - else if (leader_len > 0 && second_indent - leader_len > 0) { - int i; + if (State & VREPLACE_FLAG) { + change_indent(INDENT_SET, second_indent, false, NUL, true); + } else if (leader_len > 0 && second_indent - leader_len > 0) { int padding = second_indent - leader_len; - /* We started at the first_line of a numbered list - * that has a comment. the open_line() function has - * inserted the proper comment leader and positioned - * the cursor at the end of the split line. Now we - * add the additional whitespace needed after the - * comment leader for the numbered list. */ - for (i = 0; i < padding; i++) + // We started at the first_line of a numbered list + // that has a comment. the open_line() function has + // inserted the proper comment leader and positioned + // the cursor at the end of the split line. Now we + // add the additional whitespace needed after the + // comment leader for the numbered list. + for (int i = 0; i < padding; i++) { ins_str((char_u *)" "); + } changed_bytes(curwin->w_cursor.lnum, leader_len); } else { (void)set_indent(second_indent, SIN_CHANGED); @@ -6047,8 +6075,9 @@ internal_format ( line_breakcheck(); } - if (save_char != NUL) /* put back space after cursor */ + if (save_char != NUL) { // put back space after cursor pchar_cursor(save_char); + } curwin->w_p_lbr = has_lbr; @@ -6065,10 +6094,9 @@ internal_format ( * The caller must have saved the cursor line for undo, following ones will be * saved here. */ -void -auto_format ( - int trailblank, /* when TRUE also format with trailing blank */ - int prev_line /* may start in previous line */ +void auto_format( + bool trailblank, // when true also format with trailing blank + bool prev_line // may start in previous line ) { pos_T pos; @@ -6087,11 +6115,11 @@ auto_format ( // may remove added space check_auto_format(false); - /* Don't format in Insert mode when the cursor is on a trailing blank, the - * user might insert normal text next. Also skip formatting when "1" is - * in 'formatoptions' and there is a single character before the cursor. - * Otherwise the line would be broken and when typing another non-white - * next they are not joined back together. */ + // Don't format in Insert mode when the cursor is on a trailing blank, the + // user might insert normal text next. Also skip formatting when "1" is + // in 'formatoptions' and there is a single character before the cursor. + // Otherwise the line would be broken and when typing another non-white + // next they are not joined back together. wasatend = (pos.col == (colnr_T)STRLEN(old)); if (*old != NUL && !trailblank && wasatend) { dec_cursor(); @@ -6134,16 +6162,16 @@ auto_format ( saved_cursor.lnum = 0; if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - /* "cannot happen" */ + // "cannot happen" curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; coladvance((colnr_T)MAXCOL); } else check_cursor_col(); - /* Insert mode: If the cursor is now after the end of the line while it - * previously wasn't, the line was broken. Because of the rule above we - * need to add a space when 'w' is in 'formatoptions' to keep a paragraph - * formatted. */ + // Insert mode: If the cursor is now after the end of the line while it + // previously wasn't, the line was broken. Because of the rule above we + // need to add a space when 'w' is in 'formatoptions' to keep a paragraph + // formatted. if (!wasatend && has_format_option(FO_WHITE_PAR)) { new = get_cursor_line_ptr(); len = (colnr_T)STRLEN(new); @@ -6202,22 +6230,21 @@ static void check_auto_format( * if invalid value, use 0. * Set default to window width (maximum 79) for "gq" operator. */ -int -comp_textwidth ( - int ff /* force formatting (for "gq" command) */ +int comp_textwidth( + int ff // force formatting (for "gq" command) ) { int textwidth; textwidth = curbuf->b_p_tw; if (textwidth == 0 && curbuf->b_p_wm) { - /* The width is the window width minus 'wrapmargin' minus all the - * things that add to the margin. */ + // The width is the window width minus 'wrapmargin' minus all the + // things that add to the margin. textwidth = curwin->w_width_inner - curbuf->b_p_wm; if (cmdwin_type != 0) { textwidth -= 1; } - textwidth -= curwin->w_p_fdc; + textwidth -= win_fdccol_count(curwin); textwidth -= win_signcol_count(curwin); if (curwin->w_p_nu || curwin->w_p_rnu) @@ -6253,7 +6280,9 @@ static void redo_literal(int c) // start_arrow() is called when an arrow key is used in insert mode. // For undo/redo it resembles hitting the <ESC> key. -static void start_arrow(pos_T *end_insert_pos /* can be NULL */) +static void start_arrow( + pos_T *end_insert_pos // can be NULL +) { start_arrow_common(end_insert_pos, true); } @@ -6326,8 +6355,8 @@ int stop_arrow(void) Insstart_textlen = (colnr_T)linetabsize(get_cursor_line_ptr()); if (u_save_cursor() == OK) { - arrow_used = FALSE; - ins_need_undo = FALSE; + arrow_used = false; + ins_need_undo = false; } ai_col = 0; if (State & VREPLACE_FLAG) { @@ -6338,11 +6367,12 @@ int stop_arrow(void) AppendToRedobuff("1i"); // Pretend we start an insertion. new_insert_skip = 2; } else if (ins_need_undo) { - if (u_save_cursor() == OK) - ins_need_undo = FALSE; + if (u_save_cursor() == OK) { + ins_need_undo = false; + } } - /* Always open fold at the cursor line when inserting something. */ + // Always open fold at the cursor line when inserting something. foldOpenCursor(); return arrow_used || ins_need_undo ? FAIL : OK; @@ -6356,15 +6386,15 @@ int stop_arrow(void) static void stop_insert ( pos_T *end_insert_pos, - int esc, /* called by ins_esc() */ - int nomove /* <c-\><c-o>, don't move cursor */ + int esc, // called by ins_esc() + int nomove // <c-\><c-o>, don't move cursor ) { int cc; char_u *ptr; stop_redo_ins(); - replace_flush(); /* abandon replace stack */ + replace_flush(); // abandon replace stack /* * Save the inserted text for later redo with ^@ and CTRL-A. @@ -6381,16 +6411,16 @@ stop_insert ( xfree(ptr); if (!arrow_used && end_insert_pos != NULL) { - /* Auto-format now. It may seem strange to do this when stopping an - * insertion (or moving the cursor), but it's required when appending - * a line and having it end in a space. But only do it when something - * was actually inserted, otherwise undo won't work. */ + // Auto-format now. It may seem strange to do this when stopping an + // insertion (or moving the cursor), but it's required when appending + // a line and having it end in a space. But only do it when something + // was actually inserted, otherwise undo won't work. if (!ins_need_undo && has_format_option(FO_AUTO)) { pos_T tpos = curwin->w_cursor; - /* When the cursor is at the end of the line after a space the - * formatting will move it to the following word. Avoid that by - * moving the cursor onto the space. */ + // When the cursor is at the end of the line after a space the + // formatting will move it to the following word. Avoid that by + // moving the cursor onto the space. cc = 'x'; if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL) { dec_cursor(); @@ -6416,11 +6446,11 @@ stop_insert ( // If a space was inserted for auto-formatting, remove it now. check_auto_format(true); - /* If we just did an auto-indent, remove the white space from the end - * of the line, and put the cursor back. - * Do this when ESC was used or moving the cursor up/down. - * Check for the old position still being valid, just in case the text - * got changed unexpectedly. */ + // If we just did an auto-indent, remove the white space from the end + // of the line, and put the cursor back. + // Do this when ESC was used or moving the cursor up/down. + // Check for the old position still being valid, just in case the text + // got changed unexpectedly. if (!nomove && did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL && curwin->w_cursor.lnum != end_insert_pos->lnum)) @@ -6428,7 +6458,7 @@ stop_insert ( pos_T tpos = curwin->w_cursor; curwin->w_cursor = *end_insert_pos; - check_cursor_col(); /* make sure it is not past the line */ + check_cursor_col(); // make sure it is not past the line for (;; ) { if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) --curwin->w_cursor.col; @@ -6440,10 +6470,10 @@ stop_insert ( break; // should not happen } } - if (curwin->w_cursor.lnum != tpos.lnum) + if (curwin->w_cursor.lnum != tpos.lnum) { curwin->w_cursor = tpos; - else { - /* reset tpos, could have been invalidated in the loop above */ + } else { + // reset tpos, could have been invalidated in the loop above tpos = curwin->w_cursor; tpos.col++; if (cc != NUL && gchar_pos(&tpos) == NUL) { @@ -6451,8 +6481,8 @@ stop_insert ( } } - /* <C-S-Right> may have started Visual mode, adjust the position for - * deleted characters. */ + // <C-S-Right> may have started Visual mode, adjust the position for + // deleted characters. if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum) { int len = (int)STRLEN(get_cursor_line_ptr()); @@ -6468,8 +6498,8 @@ stop_insert ( can_si = false; can_si_back = false; - /* Set '[ and '] to the inserted text. When end_insert_pos is NULL we are - * now in a different buffer. */ + // Set '[ and '] to the inserted text. When end_insert_pos is NULL we are + // now in a different buffer. if (end_insert_pos != NULL) { curbuf->b_op_start = Insstart; curbuf->b_op_start_orig = Insstart_orig; @@ -6488,9 +6518,10 @@ void set_last_insert(int c) xfree(last_insert); last_insert = xmalloc(MB_MAXBYTES * 3 + 5); s = last_insert; - /* Use the CTRL-V only when entering a special char */ - if (c < ' ' || c == DEL) + // Use the CTRL-V only when entering a special char + if (c < ' ' || c == DEL) { *s++ = Ctrl_V; + } s = add_char2buf(c, s); *s++ = ESC; *s++ = NUL; @@ -6576,7 +6607,7 @@ int oneright(void) if (virtual_active()) { pos_T prevpos = curwin->w_cursor; - /* Adjust for multi-wide char (excluding TAB) */ + // Adjust for multi-wide char (excluding TAB) ptr = get_cursor_pos_ptr(); coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) ? ptr2cells(ptr) : 1)); @@ -6587,20 +6618,18 @@ int oneright(void) } ptr = get_cursor_pos_ptr(); - if (*ptr == NUL) - return FAIL; /* already at the very end */ + if (*ptr == NUL) { + return FAIL; // already at the very end + } - if (has_mbyte) - l = (*mb_ptr2len)(ptr); - else - l = 1; + l = utfc_ptr2len(ptr); - /* move "l" bytes right, but don't end up on the NUL, unless 'virtualedit' - * contains "onemore". */ + // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit' + // contains "onemore". if (ptr[l] == NUL - && (ve_flags & VE_ONEMORE) == 0 - ) + && (ve_flags & VE_ONEMORE) == 0) { return FAIL; + } curwin->w_cursor.col += l; curwin->w_set_curswant = TRUE; @@ -6616,25 +6645,23 @@ int oneleft(void) if (v == 0) return FAIL; - /* We might get stuck on 'showbreak', skip over it. */ + // We might get stuck on 'showbreak', skip over it. width = 1; for (;; ) { coladvance(v - width); - /* getviscol() is slow, skip it when 'showbreak' is empty, - 'breakindent' is not set and there are no multi-byte - characters */ - if ((*p_sbr == NUL - && !curwin->w_p_bri - && !has_mbyte - ) || getviscol() < v) + // getviscol() is slow, skip it when 'showbreak' is empty, + // 'breakindent' is not set and there are no multi-byte + // characters + if (getviscol() < v) { break; - ++width; + } + width++; } if (curwin->w_cursor.coladd == 1) { char_u *ptr; - /* Adjust for multi-wide char (not a TAB) */ + // Adjust for multi-wide char (not a TAB) ptr = get_cursor_pos_ptr(); if (*ptr != TAB && vim_isprintc(utf_ptr2char(ptr)) && ptr2cells(ptr) > 1) { @@ -6652,17 +6679,16 @@ int oneleft(void) curwin->w_set_curswant = TRUE; --curwin->w_cursor.col; - /* if the character on the left of the current cursor is a multi-byte - * character, move to its first byte */ - if (has_mbyte) - mb_adjust_cursor(); + // if the character on the left of the current cursor is a multi-byte + // character, move to its first byte + mb_adjust_cursor(); return OK; } int cursor_up ( long n, - int upd_topline /* When TRUE: update topline */ + int upd_topline // When TRUE: update topline ) { linenr_T lnum; @@ -6680,19 +6706,21 @@ cursor_up ( /* * Count each sequence of folded lines as one logical line. */ - /* go to the start of the current fold */ + // go to the start of the current fold (void)hasFolding(lnum, &lnum, NULL); while (n--) { - /* move up one line */ - --lnum; - if (lnum <= 1) + // move up one line + lnum--; + if (lnum <= 1) { break; - /* If we entered a fold, move to the beginning, unless in - * Insert mode or when 'foldopen' contains "all": it will open - * in a moment. */ - if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL))) + } + // If we entered a fold, move to the beginning, unless in + // Insert mode or when 'foldopen' contains "all": it will open + // in a moment. + if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL))) { (void)hasFolding(lnum, &lnum, NULL); + } } if (lnum < 1) lnum = 1; @@ -6701,11 +6729,12 @@ cursor_up ( curwin->w_cursor.lnum = lnum; } - /* try to advance to the column we want to be at */ + // try to advance to the column we want to be at coladvance(curwin->w_curswant); - if (upd_topline) - update_topline(); /* make sure curwin->w_topline is valid */ + if (upd_topline) { + update_topline(); // make sure curwin->w_topline is valid + } return OK; } @@ -6716,14 +6745,14 @@ cursor_up ( int cursor_down ( long n, - int upd_topline /* When TRUE: update topline */ + int upd_topline // When TRUE: update topline ) { linenr_T lnum; if (n > 0) { lnum = curwin->w_cursor.lnum; - /* Move to last line of fold, will fail if it's the end-of-file. */ + // Move to last line of fold, will fail if it's the end-of-file. (void)hasFolding(lnum, NULL, &lnum); // This fails if the cursor is already in the last line. @@ -6735,7 +6764,7 @@ cursor_down ( else if (hasAnyFolding(curwin)) { linenr_T last; - /* count each sequence of folded lines as one logical line */ + // count each sequence of folded lines as one logical line while (n--) { if (hasFolding(lnum, NULL, &last)) lnum = last + 1; @@ -6751,11 +6780,12 @@ cursor_down ( curwin->w_cursor.lnum = lnum; } - /* try to advance to the column we want to be at */ + // try to advance to the column we want to be at coladvance(curwin->w_curswant); - if (upd_topline) - update_topline(); /* make sure curwin->w_topline is valid */ + if (upd_topline) { + update_topline(); // make sure curwin->w_topline is valid + } return OK; } @@ -6765,11 +6795,10 @@ cursor_down ( * Last_insert actually is a copy of the redo buffer, so we * first have to remove the command. */ -int -stuff_inserted ( - int c, /* Command character to be inserted */ - long count, /* Repeat this many times */ - int no_esc /* Don't add an ESC at the end */ +int stuff_inserted( + int c, // Command character to be inserted + long count, // Repeat this many times + int no_esc // Don't add an ESC at the end ) { char_u *esc_ptr; @@ -6783,18 +6812,18 @@ stuff_inserted ( return FAIL; } - /* may want to stuff the command character, to start Insert mode */ - if (c != NUL) + // may want to stuff the command character, to start Insert mode + if (c != NUL) { stuffcharReadbuff(c); + } if ((esc_ptr = STRRCHR(ptr, ESC)) != NULL) { // remove the ESC. *esc_ptr = NUL; } - /* when the last char is either "0" or "^" it will be quoted if no ESC - * comes after it OR if it will inserted more than once and "ptr" - * starts with ^D. -- Acevedo - */ + // when the last char is either "0" or "^" it will be quoted if no ESC + // comes after it OR if it will inserted more than once and "ptr" + // starts with ^D. -- Acevedo last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1; if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^') && (no_esc || (*ptr == Ctrl_D && count > 1))) { @@ -6815,12 +6844,14 @@ stuff_inserted ( if (last) *last_ptr = last; - if (esc_ptr != NULL) - *esc_ptr = ESC; /* put the ESC back */ + if (esc_ptr != NULL) { + *esc_ptr = ESC; // put the ESC back + } - /* may want to stuff a trailing ESC, to get out of Insert mode */ - if (!no_esc) + // may want to stuff a trailing ESC, to get out of Insert mode + if (!no_esc) { stuffcharReadbuff(ESC); + } return OK; } @@ -6845,8 +6876,9 @@ char_u *get_last_insert_save(void) return NULL; s = vim_strsave(last_insert + last_insert_skip); len = (int)STRLEN(s); - if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */ + if (len > 0 && s[len - 1] == ESC) { // remove trailing ESC s[len - 1] = NUL; + } return s; } @@ -6888,8 +6920,8 @@ static bool echeck_abbr(int c) */ static char_u *replace_stack = NULL; -static ssize_t replace_stack_nr = 0; /* next entry in replace stack */ -static ssize_t replace_stack_len = 0; /* max. number of entries */ +static ssize_t replace_stack_nr = 0; // next entry in replace stack +static ssize_t replace_stack_len = 0; // max. number of entries /// Push character that is replaced onto the the replace stack. /// @@ -6943,9 +6975,8 @@ static int replace_pop(void) * Join the top two items on the replace stack. This removes to "off"'th NUL * encountered. */ -static void -replace_join ( - int off /* offset for which NUL to remove */ +static void replace_join( + int off // offset for which NUL to remove ) { int i; @@ -6968,7 +6999,7 @@ static void replace_pop_ins(void) int cc; int oldState = State; - State = NORMAL; /* don't want REPLACE here */ + State = NORMAL; // don't want REPLACE here while ((cc = replace_pop()) > 0) { mb_replace_pop_ins(cc); dec_cursor(); @@ -6987,7 +7018,7 @@ static void mb_replace_pop_ins(int cc) int i; int c; - if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1) { + if ((n = MB_BYTE2LEN(cc)) > 1) { buf[0] = cc; for (i = 1; i < n; ++i) buf[i] = replace_pop(); @@ -6996,31 +7027,33 @@ static void mb_replace_pop_ins(int cc) ins_char(cc); } - if (enc_utf8) - /* Handle composing chars. */ - for (;; ) { - c = replace_pop(); - if (c == -1) /* stack empty */ - break; - if ((n = MB_BYTE2LEN(c)) == 1) { - /* Not a multi-byte char, put it back. */ - replace_push(c); - break; + // Handle composing chars. + for (;; ) { + c = replace_pop(); + if (c == -1) { // stack empty + break; + } + if ((n = MB_BYTE2LEN(c)) == 1) { + // Not a multi-byte char, put it back. + replace_push(c); + break; + } else { + buf[0] = c; + assert(n > 1); + for (i = 1; i < n; i++) { + buf[i] = replace_pop(); + } + if (utf_iscomposing(utf_ptr2char(buf))) { + ins_bytes_len(buf, n); } else { - buf[0] = c; - assert(n > 1); - for (i = 1; i < n; ++i) - buf[i] = replace_pop(); - if (utf_iscomposing(utf_ptr2char(buf))) - ins_bytes_len(buf, n); - else { - /* Not a composing char, put it back. */ - for (i = n - 1; i >= 0; --i) - replace_push(buf[i]); - break; + // Not a composing char, put it back. + for (i = n - 1; i >= 0; i--) { + replace_push(buf[i]); } + break; } } + } } /* @@ -7058,8 +7091,8 @@ static void replace_do_bs(int limit_col) cc = replace_pop(); if (cc > 0) { if (l_State & VREPLACE_FLAG) { - /* Get the number of screen cells used by the character we are - * going to delete. */ + // Get the number of screen cells used by the character we are + // going to delete. getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL); orig_vcols = chartabsize(get_cursor_pos_ptr(), start_vcol); } @@ -7076,7 +7109,7 @@ static void replace_do_bs(int limit_col) replace_pop_ins(); if (l_State & VREPLACE_FLAG) { - /* Get the number of screen cells used by the inserted characters */ + // Get the number of screen cells used by the inserted characters p = get_cursor_pos_ptr(); ins_len = (int)STRLEN(p) - orig_len; vcol = start_vcol; @@ -7086,8 +7119,8 @@ static void replace_do_bs(int limit_col) } vcol -= start_vcol; - /* Delete spaces that were inserted after the cursor to keep the - * text aligned. */ + // Delete spaces that were inserted after the cursor to keep the + // text aligned. curwin->w_cursor.col += ins_len; while (vcol > orig_vcols && gchar_cursor() == ' ') { del_char(false); @@ -7096,7 +7129,7 @@ static void replace_do_bs(int limit_col) curwin->w_cursor.col -= ins_len; } - /* mark the buffer as changed and prepare for displaying */ + // mark the buffer as changed and prepare for displaying changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); } else if (cc == 0) (void)del_char_after_col(limit_col); @@ -7164,10 +7197,11 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) return false; } - if (*curbuf->b_p_inde != NUL) - look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */ - else - look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */ + if (*curbuf->b_p_inde != NUL) { + look = curbuf->b_p_indk; // 'indentexpr' set: use 'indentkeys' + } else { + look = curbuf->b_p_cink; // 'indentexpr' empty: use 'cinkeys' + } while (*look) { /* * Find out if we want to try a match with this key, depending on @@ -7366,10 +7400,12 @@ bool in_cinkeys(int keytyped, int when, bool line_is_empty) */ int hkmap(int c) { - if (p_hkmapp) { /* phonetic mapping, by Ilya Dogolazky */ - enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD, - KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN, - PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV}; + if (p_hkmapp) { // phonetic mapping, by Ilya Dogolazky + enum { + hALEF = 0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD, + KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN, + PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV + }; static char_u map[26] = {(char_u)hALEF /*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/, (char_u)DALET /*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit /*f*/, @@ -7381,28 +7417,27 @@ int hkmap(int c) (char_u)VAV /*v*/, (char_u)hSHIN /*w*/, (char_u)-1 /*x*/, (char_u)AIN /*y*/, (char_u)ZADI /*z*/}; - if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z') + if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z') { return (int)(map[CharOrd(c)] - 1 + p_aleph); - /* '-1'='sofit' */ - else if (c == 'x') + } else if (c == 'x') { // '-1'='sofit' return 'X'; - else if (c == 'q') - return '\''; /* {geresh}={'} */ - else if (c == 246) - return ' '; /* \"o --> ' ' for a german keyboard */ - else if (c == 228) - return ' '; /* \"a --> ' ' -- / -- */ - else if (c == 252) - return ' '; /* \"u --> ' ' -- / -- */ - /* NOTE: islower() does not do the right thing for us on Linux so we - * do this the same was as 5.7 and previous, so it works correctly on - * all systems. Specifically, the e.g. Delete and Arrow keys are - * munged and won't work if e.g. searching for Hebrew text. - */ - else if (c >= 'a' && c <= 'z') + } else if (c == 'q') { + return '\''; // {geresh}={'} + } else if (c == 246) { + return ' '; // \"o --> ' ' for a german keyboard + } else if (c == 228) { + return ' '; // \"a --> ' ' -- / -- + } else if (c == 252) { + return ' '; // \"u --> ' ' -- / -- + } else if (c >= 'a' && c <= 'z') { + // NOTE: islower() does not do the right thing for us on Linux so we + // do this the same was as 5.7 and previous, so it works correctly on + // all systems. Specifically, the e.g. Delete and Arrow keys are + // munged and won't work if e.g. searching for Hebrew text. return (int)(map[CharOrdLow(c)] + p_aleph); - else + } else { return c; + } } else { switch (c) { case '`': return ';'; @@ -7411,7 +7446,7 @@ int hkmap(int c) case 'q': return '/'; case 'w': return '\''; - /* Hebrew letters - set offset from 'a' */ + // Hebrew letters - set offset from 'a' case ',': c = '{'; break; case '.': c = 'v'; break; case ';': c = 't'; break; @@ -7441,10 +7476,10 @@ static void ins_reg(void) */ pc_status = PC_STATUS_UNSET; if (redrawing() && !char_avail()) { - /* may need to redraw when no more chars available now */ - ins_redraw(FALSE); + // may need to redraw when no more chars available now + ins_redraw(false); - edit_putchar('"', TRUE); + edit_putchar('"', true); add_to_showcmd_c(Ctrl_R); } @@ -7457,7 +7492,7 @@ static void ins_reg(void) regname = plain_vgetc(); LANGMAP_ADJUST(regname, TRUE); if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P) { - /* Get a third key for literal register insertion */ + // Get a third key for literal register insertion literally = regname; add_to_showcmd_c(literally); regname = plain_vgetc(); @@ -7465,9 +7500,9 @@ static void ins_reg(void) } --no_mapping; - /* Don't call u_sync() while typing the expression or giving an error - * message for it. Only call it explicitly. */ - ++no_u_sync; + // Don't call u_sync() while typing the expression or giving an error + // message for it. Only call it explicitly. + no_u_sync++; if (regname == '=') { pos_T curpos = curwin->w_cursor; @@ -7486,7 +7521,7 @@ static void ins_reg(void) need_redraw = true; // remove the '"' } else { if (literally == Ctrl_O || literally == Ctrl_P) { - /* Append the command to the redo buffer. */ + // Append the command to the redo buffer. AppendCharToRedobuff(Ctrl_R); AppendCharToRedobuff(literally); AppendCharToRedobuff(regname); @@ -7503,19 +7538,22 @@ static void ins_reg(void) need_redraw = true; } } - --no_u_sync; - if (u_sync_once == 1) - ins_need_undo = TRUE; + no_u_sync--; + if (u_sync_once == 1) { + ins_need_undo = true; + } u_sync_once = 0; clear_showcmd(); - /* If the inserted register is empty, we need to remove the '"' */ - if (need_redraw || stuff_empty()) + // If the inserted register is empty, we need to remove the '"' + if (need_redraw || stuff_empty()) { edit_unputchar(); + } - /* Disallow starting Visual mode here, would get a weird mode. */ - if (!vis_active && VIsual_active) + // Disallow starting Visual mode here, would get a weird mode. + if (!vis_active && VIsual_active) { end_visual_mode(); + } } /* @@ -7525,7 +7563,7 @@ static void ins_ctrl_g(void) { int c; - /* Right after CTRL-X the cursor will be after the ruler. */ + // Right after CTRL-X the cursor will be after the ruler. setcursor(); /* @@ -7536,24 +7574,25 @@ static void ins_ctrl_g(void) c = plain_vgetc(); --no_mapping; switch (c) { - /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */ + // CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col case K_UP: case Ctrl_K: case 'k': ins_up(TRUE); break; - /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */ + // CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col case K_DOWN: case Ctrl_J: case 'j': ins_down(TRUE); break; - /* CTRL-G u: start new undoable edit */ - case 'u': u_sync(TRUE); - ins_need_undo = TRUE; + // CTRL-G u: start new undoable edit + case 'u': + u_sync(true); + ins_need_undo = true; - /* Need to reset Insstart, esp. because a BS that joins - * a line to the previous one must save for undo. */ + // Need to reset Insstart, esp. because a BS that joins + // a line to the previous one must save for undo. update_Insstart_orig = false; Insstart = curwin->w_cursor; break; @@ -7565,7 +7604,7 @@ static void ins_ctrl_g(void) dont_sync_undo = kNone; break; - /* Unknown CTRL-G command, reserved for future expansion. */ + // Unknown CTRL-G command, reserved for future expansion. default: vim_beep(BO_CTRLG); } } @@ -7587,7 +7626,7 @@ static void ins_ctrl_hat(void) } set_iminsert_global(); showmode(); - /* Show/unshow value of 'keymap' in status lines. */ + // Show/unshow value of 'keymap' in status lines. status_redraw_curbuf(); } @@ -7628,10 +7667,11 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) *count = 0; } - if (--*count > 0) { /* repeat what was typed */ - /* Vi repeats the insert without replacing characters. */ - if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL) + if (--*count > 0) { // repeat what was typed + // Vi repeats the insert without replacing characters. + if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL) { State &= ~REPLACE_FLAG; + } (void)start_redo_ins(); if (cmdchar == 'r' || cmdchar == 'v') { @@ -7646,12 +7686,13 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) undisplay_dollar(); } - /* When an autoindent was removed, curswant stays after the - * indent */ - if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col) - curwin->w_set_curswant = TRUE; + // When an autoindent was removed, curswant stays after the + // indent + if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col) { + curwin->w_set_curswant = true; + } - /* Remember the last Insert position in the '^ mark. */ + // Remember the last Insert position in the '^ mark. if (!cmdmod.keepjumps) { RESET_FMARK(&curbuf->b_last_insert, curwin->w_cursor, curbuf->b_fnum); } @@ -7672,23 +7713,23 @@ static bool ins_esc(long *count, int cmdchar, bool nomove) ) { if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL) { oneleft(); - if (restart_edit != NUL) - ++curwin->w_cursor.coladd; + if (restart_edit != NUL) { + curwin->w_cursor.coladd++; + } } else { - --curwin->w_cursor.col; - /* Correct cursor for multi-byte character. */ - if (has_mbyte) - mb_adjust_cursor(); + curwin->w_cursor.col--; + // Correct cursor for multi-byte character. + mb_adjust_cursor(); } } State = NORMAL; - /* need to position cursor again (e.g. when on a TAB ) */ + // need to position cursor again (e.g. when on a TAB ) changed_cline_bef_curs(); setmouse(); - ui_cursor_shape(); /* may show different cursor shape */ + ui_cursor_shape(); // may show different cursor shape // When recording or for CTRL-O, need to display the new mode. // Otherwise remove the mode message. @@ -7784,7 +7825,7 @@ static void ins_insert(int replaceState) } AppendCharToRedobuff(K_INS); showmode(); - ui_cursor_shape(); /* may show different cursor shape */ + ui_cursor_shape(); // may show different cursor shape } /* @@ -7798,10 +7839,11 @@ static void ins_ctrl_o(void) restart_edit = 'R'; else restart_edit = 'I'; - if (virtual_active()) - ins_at_eol = FALSE; /* cursor always keeps its column */ - else + if (virtual_active()) { + ins_at_eol = false; // cursor always keeps its column + } else { ins_at_eol = (gchar_cursor() == NUL); + } } /* @@ -7883,11 +7925,12 @@ static void ins_bs_one(colnr_T *vcolp) dec_cursor(); getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL); if (State & REPLACE_FLAG) { - /* Don't delete characters before the insert point when in - * Replace mode */ + // Don't delete characters before the insert point when in + // Replace mode if (curwin->w_cursor.lnum != Insstart.lnum - || curwin->w_cursor.col >= Insstart.col) + || curwin->w_cursor.col >= Insstart.col) { replace_do_bs(-1); + } } else { (void)del_char(false); } @@ -7906,13 +7949,13 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) { linenr_T lnum; int cc; - int temp = 0; /* init for GCC */ + int temp = 0; // init for GCC colnr_T save_col; colnr_T mincol; bool did_backspace = false; int in_indent; int oldState; - int cpc[MAX_MCO]; /* composing characters */ + int cpc[MAX_MCO]; // composing characters // can't delete anything in an empty file // can't backup past first character in buffer @@ -7976,23 +8019,22 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) * cc >= 0: NL was replaced, put original characters back */ cc = -1; - if (State & REPLACE_FLAG) - cc = replace_pop(); /* returns -1 if NL was inserted */ - /* - * In replace mode, in the line we started replacing, we only move the - * cursor. - */ + if (State & REPLACE_FLAG) { + cc = replace_pop(); // returns -1 if NL was inserted + } + // In replace mode, in the line we started replacing, we only move the + // cursor. if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum) { dec_cursor(); } else { if (!(State & VREPLACE_FLAG) || curwin->w_cursor.lnum > orig_line_count) { - temp = gchar_cursor(); /* remember current char */ - --curwin->w_cursor.lnum; + temp = gchar_cursor(); // remember current char + curwin->w_cursor.lnum--; - /* When "aw" is in 'formatoptions' we must delete the space at - * the end of the line, otherwise the line will be broken - * again when auto-formatting. */ + // When "aw" is in 'formatoptions' we must delete the space at + // the end of the line, otherwise the line will be broken + // again when auto-formatting. if (has_format_option(FO_AUTO) && has_format_option(FO_WHITE_PAR)) { char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, @@ -8033,20 +8075,19 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) curwin->w_cursor.col = save_col; cc = replace_pop(); } - /* restore the characters that NL replaced */ + // restore the characters that NL replaced replace_pop_ins(); State = oldState; } } did_ai = false; } else { - /* - * Delete character(s) before the cursor. - */ - if (revins_on) /* put cursor on last inserted char */ + // Delete character(s) before the cursor. + if (revins_on) { // put cursor on last inserted char dec_cursor(); + } mincol = 0; - /* keep indent */ + // keep indent if (mode == BACKSPACE_LINE && (curbuf->b_p_ai || cindent_on() @@ -8081,9 +8122,9 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) ts = get_sw_value(curbuf); else ts = get_sts_value(); - /* Compute the virtual column where we want to be. Since - * 'showbreak' may get in the way, need to get the last column of - * the previous character. */ + // Compute the virtual column where we want to be. Since + // 'showbreak' may get in the way, need to get the last column of + // the previous character. getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); start_vcol = vcol; dec_cursor(); @@ -8091,14 +8132,15 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) inc_cursor(); want_vcol = (want_vcol / ts) * ts; - /* delete characters until we are at or before want_vcol */ + // delete characters until we are at or before want_vcol while (vcol > want_vcol - && (cc = *(get_cursor_pos_ptr() - 1), ascii_iswhite(cc))) + && (cc = *(get_cursor_pos_ptr() - 1), ascii_iswhite(cc))) { ins_bs_one(&vcol); + } - /* insert extra spaces until we are at want_vcol */ + // insert extra spaces until we are at want_vcol while (vcol < want_vcol) { - /* Remember the first char we inserted */ + // Remember the first char we inserted if (curwin->w_cursor.lnum == Insstart_orig.lnum && curwin->w_cursor.col < Insstart_orig.col) { Insstart_orig.col = curwin->w_cursor.col; @@ -8114,18 +8156,16 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); } - /* If we are now back where we started delete one character. Can - * happen when using 'sts' and 'linebreak'. */ - if (vcol >= start_vcol) + // If we are now back where we started delete one character. Can + // happen when using 'sts' and 'linebreak'. + if (vcol >= start_vcol) { ins_bs_one(&vcol); - - // Delete upto starting point, start of line or previous word. + } } else { - int cclass = 0, prev_cclass = 0; + // Delete upto starting point, start of line or previous word. + int prev_cclass = 0; - if (has_mbyte) { - cclass = mb_get_class(get_cursor_pos_ptr()); - } + int cclass = mb_get_class(get_cursor_pos_ptr()); do { if (!revins_on) { // put cursor on char to be deleted dec_cursor(); @@ -8193,21 +8233,22 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // with. AppendCharToRedobuff(c); - /* If deleted before the insertion point, adjust it */ + // If deleted before the insertion point, adjust it if (curwin->w_cursor.lnum == Insstart_orig.lnum && curwin->w_cursor.col < Insstart_orig.col) { Insstart_orig.col = curwin->w_cursor.col; } - /* vi behaviour: the cursor moves backward but the character that - * was there remains visible - * Vim behaviour: the cursor moves backward and the character that - * was there is erased from the screen. - * We can emulate the vi behaviour by pretending there is a dollar - * displayed even when there isn't. - * --pkv Sun Jan 19 01:56:40 EST 2003 */ - if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1) + // vi behaviour: the cursor moves backward but the character that + // was there remains visible + // Vim behaviour: the cursor moves backward and the character that + // was there is erased from the screen. + // We can emulate the vi behaviour by pretending there is a dollar + // displayed even when there isn't. + // --pkv Sun Jan 19 01:56:40 EST 2003 + if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1) { dollar_vcol = curwin->w_virtcol; + } // When deleting a char the cursor line must never be in a closed fold. // E.g., when 'foldmethod' is indent and deleting the first non-white @@ -8249,7 +8290,7 @@ static void ins_mouse(int c) can_cindent = true; } - /* redraw status lines (in case another window became active) */ + // redraw status lines (in case another window became active) redraw_statuslines(); } @@ -8272,7 +8313,7 @@ static void ins_mousescroll(int dir) if (curwin == old_curwin) undisplay_dollar(); - /* Don't scroll the window in which completion is being done. */ + // Don't scroll the window in which completion is being done. if (!pum_visible() || curwin != old_curwin ) { @@ -8314,9 +8355,10 @@ static void ins_left(void) if (!end_change) { AppendCharToRedobuff(K_LEFT); } - /* If exit reversed string, position is fixed */ - if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol) + // If exit reversed string, position is fixed + if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol) { revins_legal++; + } revins_chars++; } else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) { // if 'whichwrap' set for cursor in insert mode may go to previous line. @@ -8409,14 +8451,13 @@ static void ins_right(void) revins_legal++; if (revins_chars) revins_chars--; - } - /* if 'whichwrap' set for cursor in insert mode, may move the - * cursor to the next line */ - else if (vim_strchr(p_ww, ']') != NULL - && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { + } else if (vim_strchr(p_ww, ']') != NULL + && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { + // if 'whichwrap' set for cursor in insert mode, may move the + // cursor to the next line start_arrow(&curwin->w_cursor); - curwin->w_set_curswant = TRUE; - ++curwin->w_cursor.lnum; + curwin->w_set_curswant = true; + curwin->w_cursor.lnum++; curwin->w_cursor.col = 0; } else { vim_beep(BO_CRSR); @@ -8445,9 +8486,8 @@ static void ins_s_right(void) dont_sync_undo = kFalse; } -static void -ins_up ( - int startcol /* when TRUE move to Insstart.col */ +static void ins_up( + bool startcol // when true move to Insstart.col ) { pos_T tpos; @@ -8477,7 +8517,7 @@ static void ins_pageup(void) undisplay_dollar(); if (mod_mask & MOD_MASK_CTRL) { - /* <C-PageUp>: tab page back */ + // <C-PageUp>: tab page back if (first_tabpage->tp_next != NULL) { start_arrow(&curwin->w_cursor); goto_tabpage(-1); @@ -8494,9 +8534,8 @@ static void ins_pageup(void) } } -static void -ins_down ( - int startcol /* when TRUE move to Insstart.col */ +static void ins_down( + bool startcol // when true move to Insstart.col ) { pos_T tpos; @@ -8526,7 +8565,7 @@ static void ins_pagedown(void) undisplay_dollar(); if (mod_mask & MOD_MASK_CTRL) { - /* <C-PageDown>: tab page forward */ + // <C-PageDown>: tab page forward if (first_tabpage->tp_next != NULL) { start_arrow(&curwin->w_cursor); goto_tabpage(0); @@ -8613,7 +8652,7 @@ static bool ins_tab(void) */ if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind))) { char_u *ptr; - char_u *saved_line = NULL; /* init for GCC */ + char_u *saved_line = NULL; // init for GCC pos_T pos; pos_T fpos; pos_T *cursor; @@ -8635,18 +8674,19 @@ static bool ins_tab(void) cursor = &curwin->w_cursor; } - /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */ - if (vim_strchr(p_cpo, CPO_LISTWM) == NULL) - curwin->w_p_list = FALSE; + // When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. + if (vim_strchr(p_cpo, CPO_LISTWM) == NULL) { + curwin->w_p_list = false; + } - /* Find first white before the cursor */ + // Find first white before the cursor fpos = curwin->w_cursor; while (fpos.col > 0 && ascii_iswhite(ptr[-1])) { --fpos.col; --ptr; } - /* In Replace mode, don't change characters before the insert point. */ + // In Replace mode, don't change characters before the insert point. if ((State & REPLACE_FLAG) && fpos.lnum == Insstart.lnum && fpos.col < Insstart.col) { @@ -8654,12 +8694,12 @@ static bool ins_tab(void) fpos.col = Insstart.col; } - /* compute virtual column numbers of first white and cursor */ + // compute virtual column numbers of first white and cursor getvcol(curwin, &fpos, &vcol, NULL, NULL); getvcol(curwin, cursor, &want_vcol, NULL, NULL); - /* Use as many TABs as possible. Beware of 'breakindent', 'showbreak' - and 'linebreak' adding extra virtual columns. */ + // Use as many TABs as possible. Beware of 'breakindent', 'showbreak' + // and 'linebreak' adding extra virtual columns. while (ascii_iswhite(*ptr)) { i = lbr_chartabsize(NULL, (char_u *)"\t", vcol); if (vcol + i > want_vcol) @@ -8667,10 +8707,11 @@ static bool ins_tab(void) if (*ptr != TAB) { *ptr = TAB; if (change_col < 0) { - change_col = fpos.col; /* Column of first change */ - /* May have to adjust Insstart */ - if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col) + change_col = fpos.col; // Column of first change + // May have to adjust Insstart + if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col) { Insstart.col = fpos.col; + } } } ++fpos.col; @@ -8682,29 +8723,30 @@ static bool ins_tab(void) int repl_off = 0; char_u *line = ptr; - /* Skip over the spaces we need. */ + // Skip over the spaces we need. while (vcol < want_vcol && *ptr == ' ') { vcol += lbr_chartabsize(line, ptr, vcol); ++ptr; ++repl_off; } if (vcol > want_vcol) { - /* Must have a char with 'showbreak' just before it. */ - --ptr; - --repl_off; + // Must have a char with 'showbreak' just before it. + ptr--; + repl_off--; } fpos.col += repl_off; - /* Delete following spaces. */ + // Delete following spaces. i = cursor->col - fpos.col; if (i > 0) { STRMOVE(ptr, ptr + i); - /* correct replace stack. */ + // correct replace stack. if ((State & REPLACE_FLAG) - && !(State & VREPLACE_FLAG) - ) - for (temp = i; --temp >= 0; ) + && !(State & VREPLACE_FLAG)) { + for (temp = i; --temp >= 0; ) { replace_join(repl_off); + } + } } cursor->col -= i; @@ -8714,11 +8756,11 @@ static bool ins_tab(void) * spacing. */ if (State & VREPLACE_FLAG) { - /* Backspace from real cursor to change_col */ + // Backspace from real cursor to change_col backspace_until_column(change_col); - /* Insert each char in saved_line from changed_col to - * ptr-cursor */ + // Insert each char in saved_line from changed_col to + // ptr-cursor ins_bytes_len(saved_line + change_col, cursor->col - change_col); } @@ -8762,10 +8804,11 @@ static bool ins_eol(int c) * in open_line(). */ - /* Put cursor on NUL if on the last char and coladd is 1 (happens after - * CTRL-O). */ - if (virtual_active() && curwin->w_cursor.coladd > 0) + // Put cursor on NUL if on the last char and coladd is 1 (happens after + // CTRL-O). + if (virtual_active() && curwin->w_cursor.coladd > 0) { coladvance(getviscol()); + } // NL in reverse insert will always start in the end of current line. if (revins_on) { @@ -8793,15 +8836,15 @@ static int ins_digraph(void) { int c; int cc; - int did_putchar = FALSE; + bool did_putchar = false; pc_status = PC_STATUS_UNSET; if (redrawing() && !char_avail()) { - /* may need to redraw when no more chars available now */ - ins_redraw(FALSE); + // may need to redraw when no more chars available now + ins_redraw(false); - edit_putchar('?', TRUE); - did_putchar = TRUE; + edit_putchar('?', true); + did_putchar = true; add_to_showcmd_c(Ctrl_K); } @@ -8817,21 +8860,21 @@ static int ins_digraph(void) edit_unputchar(); } - if (IS_SPECIAL(c) || mod_mask) { /* special key */ + if (IS_SPECIAL(c) || mod_mask) { // special key clear_showcmd(); insert_special(c, TRUE, FALSE); return NUL; } if (c != ESC) { - did_putchar = FALSE; + did_putchar = false; if (redrawing() && !char_avail()) { - /* may need to redraw when no more chars available now */ - ins_redraw(FALSE); + // may need to redraw when no more chars available now + ins_redraw(false); if (char2cells(c) == 1) { - ins_redraw(FALSE); - edit_putchar(c, TRUE); - did_putchar = TRUE; + ins_redraw(false); + edit_putchar(c, true); + did_putchar = true; } add_to_showcmd_c(c); } @@ -8870,7 +8913,7 @@ int ins_copychar(linenr_T lnum) return NUL; } - /* try to advance to the cursor column */ + // try to advance to the cursor column temp = 0; line = ptr = ml_get(lnum); prev_ptr = ptr; @@ -8920,8 +8963,8 @@ static int ins_ctrl_ey(int tc) curbuf->b_p_tw = tw_save; revins_chars++; revins_legal++; - c = Ctrl_V; /* pretend CTRL-V is last character */ - auto_format(FALSE, TRUE); + c = Ctrl_V; // pretend CTRL-V is last character + auto_format(false, true); } } return c; @@ -8956,9 +8999,10 @@ static void ins_try_si(int c) */ ptr = ml_get(pos->lnum); i = pos->col; - if (i > 0) /* skip blanks before '{' */ - while (--i > 0 && ascii_iswhite(ptr[i])) - ; + if (i > 0) { // skip blanks before '{' + while (--i > 0 && ascii_iswhite(ptr[i])) { + } + } curwin->w_cursor.lnum = pos->lnum; curwin->w_cursor.col = i; if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) @@ -8981,9 +9025,10 @@ static void ins_try_si(int c) while (curwin->w_cursor.lnum > 1) { ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum))); - /* ignore empty lines and lines starting with '#'. */ - if (*ptr != '#' && *ptr != NUL) + // ignore empty lines and lines starting with '#'. + if (*ptr != '#' && *ptr != NUL) { break; + } } if (get_indent() >= i) temp = FALSE; @@ -8998,14 +9043,15 @@ static void ins_try_si(int c) * set indent of '#' always to 0 */ if (curwin->w_cursor.col > 0 && can_si && c == '#') { - /* remember current indent for next line */ + // remember current indent for next line old_indent = get_indent(); (void)set_indent(0, SIN_CHANGED); } - /* Adjust ai_col, the char at this position can be deleted. */ - if (ai_col > curwin->w_cursor.col) + // Adjust ai_col, the char at this position can be deleted. + if (ai_col > curwin->w_cursor.col) { ai_col = curwin->w_cursor.col; + } } /* diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3757dc6c04..8ec1e51297 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -55,7 +55,7 @@ // TODO(ZyX-I): Remove DICT_MAXNEST, make users be non-recursive instead -#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */ +#define DICT_MAXNEST 100 // maximum nesting of lists and dicts static char *e_letunexp = N_("E18: Unexpected characters in :let"); @@ -97,7 +97,7 @@ static garray_T ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL}; #define SCRIPT_SV(id) (((scriptvar_T **)ga_scripts.ga_data)[(id) - 1]) #define SCRIPT_VARS(id) (SCRIPT_SV(id)->sv_dict.dv_hashtab) -static int echo_attr = 0; /* attributes used for ":echo" */ +static int echo_attr = 0; // attributes used for ":echo" // The names of packages that once were loaded are remembered. static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL }; @@ -106,16 +106,16 @@ static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL }; * Info used by a ":for" loop. */ typedef struct { - int fi_semicolon; /* TRUE if ending in '; var]' */ - int fi_varcount; /* nr of variables in the list */ - listwatch_T fi_lw; /* keep an eye on the item used. */ - list_T *fi_list; /* list being used */ + int fi_semicolon; // TRUE if ending in '; var]' + int fi_varcount; // nr of variables in the list + listwatch_T fi_lw; // keep an eye on the item used. + list_T *fi_list; // list being used } forinfo_T; -/* values for vv_flags: */ -#define VV_COMPAT 1 /* compatible, also used without "v:" */ -#define VV_RO 2 /* read-only */ -#define VV_RO_SBX 4 /* read-only in the sandbox */ +// values for vv_flags: +#define VV_COMPAT 1 // compatible, also used without "v:" +#define VV_RO 2 // read-only +#define VV_RO_SBX 4 // read-only in the sandbox #define VV(idx, name, type, flags) \ [idx] = { \ @@ -232,7 +232,7 @@ static struct vimvar { }; #undef VV -/* shorthand */ +// shorthand #define vv_type vv_di.di_tv.v_type #define vv_nr vv_di.di_tv.vval.v_number #define vv_special vv_di.di_tv.vval.v_special @@ -337,12 +337,14 @@ void eval_init(void) else p->vv_di.di_flags = DI_FLAGS_FIX; - /* add to v: scope dict, unless the value is not always available */ - if (p->vv_type != VAR_UNKNOWN) + // add to v: scope dict, unless the value is not always available + if (p->vv_type != VAR_UNKNOWN) { hash_add(&vimvarht, p->vv_di.di_key); - if (p->vv_flags & VV_COMPAT) - /* add to compat scope dict */ + } + if (p->vv_flags & VV_COMPAT) { + // add to compat scope dict hash_add(&compat_hashtab, p->vv_di.di_key); + } } vimvars[VV_VERSION].vv_nr = VIM_VERSION_100; @@ -416,16 +418,16 @@ void eval_clear(void) } } hash_clear(&vimvarht); - hash_init(&vimvarht); /* garbage_collect() will access it */ + hash_init(&vimvarht); // garbage_collect() will access it hash_clear(&compat_hashtab); free_scriptnames(); free_locales(); - /* global variables */ + // global variables vars_clear(&globvarht); - /* autoloaded script names */ + // autoloaded script names ga_clear_strings(&ga_loaded); /* Script-local variables. First clear all the variables and in a second @@ -472,25 +474,25 @@ static char_u *redir_varname = NULL; int var_redir_start( char_u *name, - int append /* append to an existing variable */ + int append // append to an existing variable ) { int save_emsg; int err; typval_T tv; - /* Catch a bad name early. */ + // Catch a bad name early. if (!eval_isnamec1(*name)) { EMSG(_(e_invarg)); return FAIL; } - /* Make a copy of the name, it is used in redir_lval until redir ends. */ + // Make a copy of the name, it is used in redir_lval until redir ends. redir_varname = vim_strsave(name); redir_lval = xcalloc(1, sizeof(lval_T)); - /* The output is stored in growarray "redir_ga" until redirection ends. */ + // The output is stored in growarray "redir_ga" until redirection ends. ga_init(&redir_ga, (int)sizeof(char), 500); // Parse the variable name (can be a dict or list entry). @@ -499,12 +501,13 @@ var_redir_start( if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL) { clear_lval(redir_lval); - if (redir_endp != NULL && *redir_endp != NUL) - /* Trailing characters are present after the variable name */ + if (redir_endp != NULL && *redir_endp != NUL) { + // Trailing characters are present after the variable name EMSG(_(e_trailing)); - else + } else { EMSG(_(e_invarg)); - redir_endp = NULL; /* don't store a value, only cleanup */ + } + redir_endp = NULL; // don't store a value, only cleanup var_redir_stop(); return FAIL; } @@ -524,7 +527,7 @@ var_redir_start( err = did_emsg; did_emsg |= save_emsg; if (err) { - redir_endp = NULL; /* don't store a value, only cleanup */ + redir_endp = NULL; // don't store a value, only cleanup var_redir_stop(); return FAIL; } @@ -548,10 +551,11 @@ void var_redir_str(char_u *value, int value_len) if (redir_lval == NULL) return; - if (value_len == -1) - len = (int)STRLEN(value); /* Append the entire string */ - else - len = value_len; /* Append only "value_len" characters */ + if (value_len == -1) { + len = (int)STRLEN(value); // Append the entire string + } else { + len = value_len; // Append only "value_len" characters + } ga_grow(&redir_ga, len); memmove((char *)redir_ga.ga_data + redir_ga.ga_len, value, len); @@ -567,9 +571,9 @@ void var_redir_stop(void) typval_T tv; if (redir_lval != NULL) { - /* If there was no error: assign the text to the variable. */ + // If there was no error: assign the text to the variable. if (redir_endp != NULL) { - ga_append(&redir_ga, NUL); /* Append the trailing NUL. */ + ga_append(&redir_ga, NUL); // Append the trailing NUL. tv.v_type = VAR_STRING; tv.vval.v_string = redir_ga.ga_data; // Call get_lval() again, if it's inside a Dict or List it may @@ -670,7 +674,7 @@ eval_to_bool( char_u *arg, bool *error, char_u **nextcmd, - int skip /* only parse, don't execute */ + int skip // only parse, don't execute ) { typval_T tv; @@ -1125,8 +1129,9 @@ void *call_func_retlist(const char_u *func, int argc, typval_T *argv) * counted for the script/function itself. * Should always be called in pair with prof_child_exit(). */ -void prof_child_enter(proftime_T *tm /* place to store waittime */ - ) +void prof_child_enter( + proftime_T *tm // place to store waittime +) { funccall_T *fc = get_current_funccal(); @@ -1141,8 +1146,9 @@ void prof_child_enter(proftime_T *tm /* place to store waittime */ * Take care of time spent in a child. * Should always be called after prof_child_enter(). */ -void prof_child_exit(proftime_T *tm /* where waittime was stored */ - ) +void prof_child_exit( + proftime_T *tm // where waittime was stored +) { funccall_T *fc = get_current_funccal(); @@ -1167,7 +1173,6 @@ int eval_foldexpr(char_u *arg, int *cp) { typval_T tv; varnumber_T retval; - char_u *s; int use_sandbox = was_set_insecurely((char_u *)"foldexpr", OPT_LOCAL); @@ -1176,20 +1181,21 @@ int eval_foldexpr(char_u *arg, int *cp) ++sandbox; ++textlock; *cp = NUL; - if (eval0(arg, &tv, NULL, TRUE) == FAIL) + if (eval0(arg, &tv, NULL, true) == FAIL) { retval = 0; - else { - /* If the result is a number, just return the number. */ - if (tv.v_type == VAR_NUMBER) + } else { + // If the result is a number, just return the number. + if (tv.v_type == VAR_NUMBER) { retval = tv.vval.v_number; - else if (tv.v_type != VAR_STRING || tv.vval.v_string == NULL) + } else if (tv.v_type != VAR_STRING || tv.vval.v_string == NULL) { retval = 0; - else { - /* If the result is a string, check if there is a non-digit before - * the number. */ - s = tv.vval.v_string; - if (!ascii_isdigit(*s) && *s != '-') + } else { + // If the result is a string, check if there is a non-digit before + // the number. + char_u *s = tv.vval.v_string; + if (!ascii_isdigit(*s) && *s != '-') { *cp = *s++; + } retval = atol((char *)s); } tv_clear(&tv); @@ -1529,10 +1535,10 @@ static const char_u *skip_var_list(const char_u *arg, int *var_count, const char_u *s; if (*arg == '[') { - /* "[var, var]": find the matching ']'. */ + // "[var, var]": find the matching ']'. p = arg; for (;; ) { - p = skipwhite(p + 1); /* skip whites after '[', ';' or ',' */ + p = skipwhite(p + 1); // skip whites after '[', ';' or ',' s = skip_var_one(p); if (s == p) { EMSG2(_(e_invarg2), p); @@ -1959,7 +1965,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, hashtab_T *ht; int quiet = flags & GLV_QUIET; - /* Clear everything in "lp". */ + // Clear everything in "lp". memset(lp, 0, sizeof(lval_T)); if (skip) { @@ -1977,7 +1983,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, (const char_u **)&expr_end, fne_flags); if (expr_start != NULL) { - /* Don't expand the name when we already know there is an error. */ + // Don't expand the name when we already know there is an error. if (unlet && !ascii_iswhite(*p) && !ends_excmd(*p) && *p != '[' && *p != '.') { EMSG(_(e_trailing)); @@ -2057,7 +2063,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, } p = key + len; } else { - /* Get the index [expr] or the first index [expr: ]. */ + // Get the index [expr] or the first index [expr: ]. p = skipwhite(p + 1); if (*p == ':') { empty1 = true; @@ -2073,7 +2079,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, } } - /* Optionally get the second index [ :expr]. */ + // Optionally get the second index [ :expr]. if (*p == ':') { if (lp->ll_tv->v_type == VAR_DICT) { if (!quiet) { @@ -2119,8 +2125,8 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, return NULL; } - /* Skip to past ']'. */ - ++p; + // Skip to past ']'. + p++; } if (lp->ll_tv->v_type == VAR_DICT) { @@ -2546,7 +2552,7 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) if (cmdidx == CMD_let || cmdidx == CMD_const) { xp->xp_context = EXPAND_USER_VARS; if (vim_strpbrk(arg, (char_u *)"\"'+-*/%.=!?~|&$([<>,#") == NULL) { - /* ":let var1 var2 ...": find last space. */ + // ":let var1 var2 ...": find last space. for (p = arg + STRLEN(arg); p >= arg; ) { xp->xp_pattern = p; MB_PTR_BACK(arg, p); @@ -2575,7 +2581,7 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) } } else if (c == '$') { - /* environment variable */ + // environment variable xp->xp_context = EXPAND_ENV_VARS; } else if (c == '=') { got_eq = TRUE; @@ -2587,18 +2593,20 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) } else if ((c == '<' || c == '#') && xp->xp_context == EXPAND_FUNCTIONS && vim_strchr(xp->xp_pattern, '(') == NULL) { - /* Function name can start with "<SNR>" and contain '#'. */ + // Function name can start with "<SNR>" and contain '#'. break; } else if (cmdidx != CMD_let || got_eq) { - if (c == '"') { /* string */ - while ((c = *++xp->xp_pattern) != NUL && c != '"') - if (c == '\\' && xp->xp_pattern[1] != NUL) - ++xp->xp_pattern; + if (c == '"') { // string + while ((c = *++xp->xp_pattern) != NUL && c != '"') { + if (c == '\\' && xp->xp_pattern[1] != NUL) { + xp->xp_pattern++; + } + } xp->xp_context = EXPAND_NOTHING; - } else if (c == '\'') { /* literal string */ - /* Trick: '' is like stopping and starting a literal string. */ - while ((c = *++xp->xp_pattern) != NUL && c != '\'') - /* skip */; + } else if (c == '\'') { // literal string + // Trick: '' is like stopping and starting a literal string. + while ((c = *++xp->xp_pattern) != NUL && c != '\'') { + } xp->xp_context = EXPAND_NOTHING; } else if (c == '|') { if (xp->xp_pattern[1] == '|') { @@ -2613,15 +2621,14 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) * anyway. */ xp->xp_context = EXPAND_EXPRESSION; arg = xp->xp_pattern; - if (*arg != NUL) - while ((c = *++arg) != NUL && (c == ' ' || c == '\t')) - /* skip */; + if (*arg != NUL) { + while ((c = *++arg) != NUL && (c == ' ' || c == '\t')) { + } + } } xp->xp_pattern = arg; } -// TODO(ZyX-I): move to eval/ex_cmds - /* * ":unlet[!] var1 ... " command. */ @@ -2811,8 +2818,7 @@ int do_unlet(const char *const name, const size_t name_len, const int forceit) if (ht != NULL && *varname != NUL) { dict_T *d = get_current_funccal_dict(ht); - if (d == NULL) - { + if (d == NULL) { if (ht == &globvarht) { d = &globvardict; } else if (ht == &compat_hashtab) { @@ -2905,7 +2911,7 @@ static int do_lock_var(lval_T *lp, char_u *const name_end, const int deep, } else if (lp->ll_range) { listitem_T *li = lp->ll_li; - /* (un)lock a range of List items. */ + // (un)lock a range of List items. while (li != NULL && (lp->ll_empty2 || lp->ll_n2 >= lp->ll_n1)) { tv_item_lock(TV_LIST_ITEM_TV(li), deep, lock); li = TV_LIST_ITEM_NEXT(lp->ll_list, li); @@ -2955,7 +2961,7 @@ static char_u *cat_prefix_varname(int prefix, char_u *name) if (len > varnamebuflen) { xfree(varnamebuf); - len += 10; /* some additional space */ + len += 10; // some additional space varnamebuf = xmalloc(len); varnamebuflen = len; } @@ -2984,7 +2990,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) tdone = 0; } - /* Global variables */ + // Global variables if (gdone < globvarht.ht_used) { if (gdone++ == 0) hi = globvarht.ht_array; @@ -2997,7 +3003,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) return hi->hi_key; } - /* b: variables */ + // b: variables ht = &curbuf->b_vars->dv_hashtab; if (bdone < ht->ht_used) { if (bdone++ == 0) @@ -3009,7 +3015,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) return cat_prefix_varname('b', hi->hi_key); } - /* w: variables */ + // w: variables ht = &curwin->w_vars->dv_hashtab; if (wdone < ht->ht_used) { if (wdone++ == 0) @@ -3021,7 +3027,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) return cat_prefix_varname('w', hi->hi_key); } - /* t: variables */ + // t: variables ht = &curtab->tp_vars->dv_hashtab; if (tdone < ht->ht_used) { if (tdone++ == 0) @@ -3047,7 +3053,7 @@ char_u *get_user_var_name(expand_T *xp, int idx) /// Return TRUE if "pat" matches "text". /// Does not use 'cpo' and always uses 'magic'. -static int pattern_match(char_u *pat, char_u *text, int ic) +static int pattern_match(char_u *pat, char_u *text, bool ic) { int matches = 0; regmatch_T regmatch; @@ -3162,8 +3168,9 @@ int eval1(char_u **arg, typval_T *rettv, int evaluate) * Get the second variable. */ *arg = skipwhite(*arg + 1); - if (eval1(arg, rettv, evaluate && result) == FAIL) /* recursive! */ + if (eval1(arg, rettv, evaluate && result) == FAIL) { // recursive! return FAIL; + } /* * Check for the ":". @@ -3357,10 +3364,10 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) char_u *p; int i; exptype_T type = TYPE_UNKNOWN; - int type_is = FALSE; /* TRUE for "is" and "isnot" */ + bool type_is = false; // true for "is" and "isnot" int len = 2; varnumber_T n1, n2; - int ic; + bool ic; /* * Get the first variable. @@ -3398,7 +3405,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) } if (!isalnum(p[len]) && p[len] != '_') { type = len == 2 ? TYPE_EQUAL : TYPE_NEQUAL; - type_is = TRUE; + type_is = true; } } break; @@ -3408,23 +3415,18 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) * If there is a comparative operator, use it. */ if (type != TYPE_UNKNOWN) { - /* extra question mark appended: ignore case */ + // extra question mark appended: ignore case if (p[len] == '?') { - ic = TRUE; - ++len; - } - /* extra '#' appended: match case */ - else if (p[len] == '#') { - ic = FALSE; - ++len; - } - /* nothing appended: use 'ignorecase' */ - else + ic = true; + len++; + } else if (p[len] == '#') { // extra '#' appended: match case + ic = false; + len++; + } else { // nothing appended: use 'ignorecase' ic = p_ic; + } - /* - * Get the second variable. - */ + // Get the second variable. *arg = skipwhite(p + len); if (eval5(arg, &var2, evaluate) == FAIL) { tv_clear(rettv); @@ -3569,7 +3571,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate) const char *const s1 = tv_get_string_buf(rettv, buf1); const char *const s2 = tv_get_string_buf(&var2, buf2); if (type != TYPE_MATCH && type != TYPE_NOMATCH) { - i = mb_strcmp_ic((bool)ic, s1, s2); + i = mb_strcmp_ic(ic, s1, s2); } else { i = 0; } @@ -3730,7 +3732,7 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate) } tv_clear(rettv); - /* If there is a float on either side the result is a float. */ + // If there is a float on either side the result is a float. if (rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT) { if (op == '+') f1 = f1 + f2; @@ -4169,7 +4171,7 @@ eval_index( char_u **arg, typval_T *rettv, int evaluate, - int verbose /* give error messages */ + int verbose // give error messages ) { bool empty1 = false; @@ -4265,7 +4267,7 @@ eval_index( } } - /* Check for the ']'. */ + // Check for the ']'. if (**arg != ']') { if (verbose) { EMSG(_(e_missbrac)); @@ -4276,7 +4278,7 @@ eval_index( } return FAIL; } - *arg = skipwhite(*arg + 1); /* skip the ']' */ + *arg = skipwhite(*arg + 1); // skip the ']' } if (evaluate) { @@ -4468,28 +4470,29 @@ int get_option_tv(const char **const arg, typval_T *const rettv, opt_type = get_option_value((char_u *)(*arg), &numval, rettv == NULL ? NULL : &stringval, opt_flags); - if (opt_type == -3) { /* invalid name */ - if (rettv != NULL) + if (opt_type == -3) { // invalid name + if (rettv != NULL) { EMSG2(_("E113: Unknown option: %s"), *arg); + } ret = FAIL; } else if (rettv != NULL) { - if (opt_type == -2) { /* hidden string option */ + if (opt_type == -2) { // hidden string option rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; - } else if (opt_type == -1) { /* hidden number option */ + } else if (opt_type == -1) { // hidden number option rettv->v_type = VAR_NUMBER; rettv->vval.v_number = 0; - } else if (opt_type == 1) { /* number option */ + } else if (opt_type == 1) { // number option rettv->v_type = VAR_NUMBER; rettv->vval.v_number = numval; - } else { /* string option */ + } else { // string option rettv->v_type = VAR_STRING; rettv->vval.v_string = stringval; } } else if (working && (opt_type == -2 || opt_type == -1)) ret = FAIL; - *option_end = c; /* put back for error messages */ + *option_end = c; // put back for error messages *arg = option_end; return ret; @@ -4523,7 +4526,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) return FAIL; } - /* If only parsing, set *arg and return here */ + // If only parsing, set *arg and return here if (!evaluate) { *arg = p + 1; return OK; @@ -4547,9 +4550,9 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) case 'r': *name++ = CAR; ++p; break; case 't': *name++ = TAB; ++p; break; - case 'X': /* hex: "\x1", "\x12" */ + case 'X': // hex: "\x1", "\x12" case 'x': - case 'u': /* Unicode: "\u0023" */ + case 'u': // Unicode: "\u0023" case 'U': if (ascii_isxdigit(p[1])) { int n, nr; @@ -4578,7 +4581,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) } break; - /* octal: "\1", "\12", "\123" */ + // octal: "\1", "\12", "\123" case '0': case '1': case '2': @@ -4647,7 +4650,7 @@ static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate) return FAIL; } - /* If only parsing return after setting "*arg" */ + // If only parsing return after setting "*arg" if (!evaluate) { *arg = p + 1; return OK; @@ -5346,10 +5349,12 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate) * But {} is an empty Dictionary. */ if (*start != '}') { - if (eval1(&start, &tv, FALSE) == FAIL) /* recursive! */ + if (eval1(&start, &tv, false) == FAIL) { // recursive! return FAIL; - if (*start == '}') + } + if (*start == '}') { return NOTDONE; + } } if (evaluate) { @@ -5360,8 +5365,9 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate) *arg = skipwhite(*arg + 1); while (**arg != '}' && **arg != NUL) { - if (eval1(arg, &tvkey, evaluate) == FAIL) /* recursive! */ + if (eval1(arg, &tvkey, evaluate) == FAIL) { // recursive! goto failret; + } if (**arg != ':') { EMSG2(_("E720: Missing colon in Dictionary: %s"), *arg); tv_clear(&tvkey); @@ -6109,6 +6115,10 @@ void common_function(typval_T *argvars, typval_T *rettv, list = argvars[arg_idx].vval.v_list; if (tv_list_len(list) == 0) { arg_idx = 0; + } else if (tv_list_len(list) > MAX_FUNC_ARGS) { + emsg_funcname((char *)e_toomanyarg, name); + xfree(name); + goto theend; } } } @@ -6312,7 +6322,7 @@ dict_T *get_win_info(win_T *wp, int16_t tpnr, int16_t winnr) win_T * find_win_by_nr( typval_T *vp, - tabpage_T *tp /* NULL for current tab page */ + tabpage_T *tp // NULL for current tab page ) { int nr = (int)tv_get_number_chk(vp, NULL); @@ -6375,7 +6385,7 @@ void getwinvar( typval_T *argvars, typval_T *rettv, - int off /* 1 for gettabwinvar() */ + int off // 1 for gettabwinvar() ) { win_T *win, *oldcurwin; @@ -7102,10 +7112,16 @@ void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv, bool callback_from_typval(Callback *const callback, typval_T *const arg) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { + int r = OK; + if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) { callback->data.partial = arg->vval.v_partial; callback->data.partial->pt_refcount++; callback->type = kCallbackPartial; + } else if (arg->v_type == VAR_STRING + && arg->vval.v_string != NULL + && ascii_isdigit(*arg->vval.v_string)) { + r = FAIL; } else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) { char_u *name = arg->vval.v_string; func_ref(name); @@ -7114,6 +7130,10 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg) } else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) { callback->type = kCallbackNone; } else { + r = FAIL; + } + + if (r == FAIL) { EMSG(_("E921: Invalid callback argument")); return false; } @@ -7592,19 +7612,19 @@ pos_T *var2fpos(const typval_T *const tv, const int dollar_lnum, if (name[0] == 'w' && dollar_lnum) { pos.col = 0; - if (name[1] == '0') { /* "w0": first visible line */ + if (name[1] == '0') { // "w0": first visible line update_topline(); // In silent Ex mode topline is zero, but that's not a valid line // number; use one instead. pos.lnum = curwin->w_topline > 0 ? curwin->w_topline : 1; return &pos; - } else if (name[1] == '$') { /* "w$": last visible line */ + } else if (name[1] == '$') { // "w$": last visible line validate_botline(); // In silent Ex mode botline is zero, return zero then. pos.lnum = curwin->w_botline > 0 ? curwin->w_botline - 1 : 0; return &pos; } - } else if (name[0] == '$') { /* last column or line */ + } else if (name[0] == '$') { // last column or line if (dollar_lnum) { pos.lnum = curbuf->b_ml.ml_line_count; pos.col = 0; @@ -7744,7 +7764,7 @@ int get_name_len(const char **const arg, { int len; - *alias = NULL; /* default to no alias */ + *alias = NULL; // default to no alias if ((*arg)[0] == (char)K_SPECIAL && (*arg)[1] == (char)KS_EXTRA && (*arg)[2] == (char)KE_SNR) { @@ -7754,7 +7774,7 @@ int get_name_len(const char **const arg, } len = eval_fname_script(*arg); if (len > 0) { - /* literal "<SID>", "s:" or "<SNR>" */ + // literal "<SID>", "s:" or "<SNR>" *arg += len; } @@ -7803,7 +7823,7 @@ int get_name_len(const char **const arg, // Return a pointer to just after the name. Equal to "arg" if there is no // valid name. const char_u *find_name_end(const char_u *arg, const char_u **expr_start, - const char_u **expr_end, int flags) + const char_u **expr_end, int flags) { int mb_nest = 0; int br_nest = 0; @@ -7917,7 +7937,7 @@ static char_u *make_expanded_name(const char_u *in_start, char_u *expr_start, } xfree(temp_result); - *in_end = c1; /* put char back for error messages */ + *in_end = c1; // put char back for error messages *expr_start = '{'; *expr_end = '}'; @@ -7926,7 +7946,7 @@ static char_u *make_expanded_name(const char_u *in_start, char_u *expr_start, (const char_u **)&expr_start, (const char_u **)&expr_end, 0); if (expr_start != NULL) { - /* Further expansion! */ + // Further expansion! temp_result = make_expanded_name(retval, expr_start, expr_end, temp_result); xfree(retval); @@ -8140,10 +8160,7 @@ char_u *v_throwpoint(char_u *oldval) */ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) { - char_u *oldval; - char_u *newval; - - oldval = vimvars[VV_CMDARG].vv_str; + char_u *oldval = vimvars[VV_CMDARG].vv_str; if (eap == NULL) { xfree(oldval); vimvars[VV_CMDARG].vv_str = oldarg; @@ -8159,14 +8176,18 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) if (eap->read_edit) len += 7; - if (eap->force_ff != 0) - len += STRLEN(eap->cmd + eap->force_ff) + 6; - if (eap->force_enc != 0) + if (eap->force_ff != 0) { + len += 10; // " ++ff=unix" + } + if (eap->force_enc != 0) { len += STRLEN(eap->cmd + eap->force_enc) + 7; - if (eap->bad_char != 0) - len += 7 + 4; /* " ++bad=" + "keep" or "drop" */ + } + if (eap->bad_char != 0) { + len += 7 + 4; // " ++bad=" + "keep" or "drop" + } - newval = xmalloc(len + 1); + const size_t newval_len = len + 1; + char_u *newval = xmalloc(newval_len); if (eap->force_bin == FORCE_BIN) sprintf((char *)newval, " ++bin"); @@ -8178,18 +8199,23 @@ char_u *set_cmdarg(exarg_T *eap, char_u *oldarg) if (eap->read_edit) STRCAT(newval, " ++edit"); - if (eap->force_ff != 0) - sprintf((char *)newval + STRLEN(newval), " ++ff=%s", - eap->cmd + eap->force_ff); - if (eap->force_enc != 0) - sprintf((char *)newval + STRLEN(newval), " ++enc=%s", - eap->cmd + eap->force_enc); - if (eap->bad_char == BAD_KEEP) + if (eap->force_ff != 0) { + snprintf((char *)newval + STRLEN(newval), newval_len, " ++ff=%s", + eap->force_ff == 'u' ? "unix" : + eap->force_ff == 'd' ? "dos" : "mac"); + } + if (eap->force_enc != 0) { + snprintf((char *)newval + STRLEN(newval), newval_len, " ++enc=%s", + eap->cmd + eap->force_enc); + } + if (eap->bad_char == BAD_KEEP) { STRCPY(newval + STRLEN(newval), " ++bad=keep"); - else if (eap->bad_char == BAD_DROP) + } else if (eap->bad_char == BAD_DROP) { STRCPY(newval + STRLEN(newval), " ++bad=drop"); - else if (eap->bad_char != 0) - sprintf((char *)newval + STRLEN(newval), " ++bad=%c", eap->bad_char); + } else if (eap->bad_char != 0) { + snprintf((char *)newval + STRLEN(newval), newval_len, " ++bad=%c", + eap->bad_char); + } vimvars[VV_CMDARG].vv_str = newval; return oldval; } @@ -8282,8 +8308,8 @@ int handle_subscript( const char **const arg, typval_T *rettv, - int evaluate, /* do more than finding the end */ - int verbose /* give error messages */ + int evaluate, // do more than finding the end + int verbose // give error messages ) { int ret = OK; @@ -8393,6 +8419,27 @@ void set_selfdict(typval_T *const rettv, dict_T *const selfdict) make_partial(selfdict, rettv); } +// Turn a typeval into a string. Similar to tv_get_string_buf() but uses +// string() on Dict, List, etc. +static const char *tv_stringify(typval_T *varp, char *buf) + FUNC_ATTR_NONNULL_ALL +{ + if (varp->v_type == VAR_LIST + || varp->v_type == VAR_DICT + || varp->v_type == VAR_FUNC + || varp->v_type == VAR_PARTIAL + || varp->v_type == VAR_FLOAT) { + typval_T tmp; + + f_string(varp, &tmp, NULL); + const char *const res = tv_get_string_buf(&tmp, buf); + tv_clear(varp); + *varp = tmp; + return res; + } + return tv_get_string_buf(varp, buf); +} + // Find variable "name" in the list of variables. // Return a pointer to it if found, NULL if not found. // Careful: "a:0" variables don't have a name. @@ -8421,7 +8468,8 @@ dictitem_T *find_var(const char *const name, const size_t name_len, return find_var_in_scoped_ht(name, name_len, no_autoload || htp != NULL); } -/// Find variable in hashtab +/// Find variable in hashtab. +/// When "varname" is empty returns curwin/curtab/etc vars dictionary. /// /// @param[in] ht Hashtab to find variable in. /// @param[in] htname Hashtab name (first character). @@ -9107,10 +9155,10 @@ int var_item_copy(const vimconv_T *const conv, case VAR_DICT: to->v_type = VAR_DICT; to->v_lock = 0; - if (from->vval.v_dict == NULL) + if (from->vval.v_dict == NULL) { to->vval.v_dict = NULL; - else if (copyID != 0 && from->vval.v_dict->dv_copyID == copyID) { - /* use the copy made earlier */ + } else if (copyID != 0 && from->vval.v_dict->dv_copyID == copyID) { + // use the copy made earlier to->vval.v_dict = from->vval.v_dict->dv_copydict; ++to->vval.v_dict->dv_refcount; } else { @@ -9243,7 +9291,10 @@ void ex_execute(exarg_T *eap) } if (!eap->skip) { - const char *const argstr = tv_get_string(&rettv); + char buf[NUMBUFLEN]; + const char *const argstr = eap->cmdidx == CMD_execute + ? tv_get_string_buf(&rettv, buf) + : tv_stringify(&rettv, buf); const size_t len = strlen(argstr); ga_grow(&ga, len + 2); if (!GA_EMPTY(&ga)) { @@ -9270,7 +9321,7 @@ void ex_execute(exarg_T *eap) MSG_ATTR(ga.ga_data, echo_attr); ui_flush(); } else if (eap->cmdidx == CMD_echoerr) { - /* We don't want to abort following commands, restore did_emsg. */ + // We don't want to abort following commands, restore did_emsg. save_did_emsg = did_emsg; msg_ext_set_kind("echoerr"); EMSG((char_u *)ga.ga_data); @@ -9325,10 +9376,7 @@ static const char *find_option_end(const char **const arg, int *const opt_flags) return p; } - -/* - * Start profiling function "fp". - */ +/// Start profiling function "fp". void func_do_profile(ufunc_T *fp) { int len = fp->uf_lines.ga_len; @@ -9372,8 +9420,9 @@ void func_dump_profile(FILE *fd) int st_len = 0; todo = (int)func_hashtab.ht_used; - if (todo == 0) - return; /* nothing to dump */ + if (todo == 0) { + return; // nothing to dump + } sorttab = xmalloc(sizeof(ufunc_T *) * todo); @@ -9442,7 +9491,7 @@ prof_sort_list( ufunc_T **sorttab, int st_len, char *title, - int prefer_self /* when equal print only self time */ + int prefer_self // when equal print only self time ) { int i; @@ -9470,8 +9519,8 @@ static void prof_func_line( int count, proftime_T *total, proftime_T *self, - int prefer_self /* when equal print only self time */ - ) + int prefer_self // when equal print only self time +) { if (count > 0) { fprintf(fd, "%5d ", count); @@ -9507,6 +9556,33 @@ static int prof_self_cmp(const void *s1, const void *s2) return profile_cmp(p1->uf_tm_self, p2->uf_tm_self); } +/// Return the autoload script name for a function or variable name +/// Caller must make sure that "name" contains AUTOLOAD_CHAR. +/// +/// @param[in] name Variable/function name. +/// @param[in] name_len Name length. +/// +/// @return [allocated] autoload script name. +char *autoload_name(const char *const name, const size_t name_len) + FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT +{ + // Get the script file name: replace '#' with '/', append ".vim". + char *const scriptname = xmalloc(name_len + sizeof("autoload/.vim")); + memcpy(scriptname, "autoload/", sizeof("autoload/") - 1); + memcpy(scriptname + sizeof("autoload/") - 1, name, name_len); + size_t auchar_idx = 0; + for (size_t i = sizeof("autoload/") - 1; + i - sizeof("autoload/") + 1 < name_len; + i++) { + if (scriptname[i] == AUTOLOAD_CHAR) { + scriptname[i] = '/'; + auchar_idx = i; + } + } + memcpy(scriptname + auchar_idx, ".vim", sizeof(".vim")); + + return scriptname; +} /// If name has a package name try autoloading the script for it /// @@ -9516,7 +9592,7 @@ static int prof_self_cmp(const void *s1, const void *s2) /// /// @return true if a package was loaded. bool script_autoload(const char *const name, const size_t name_len, - const bool reload) + const bool reload) { // If there is no '#' after name[0] there is no package name. const char *p = memchr(name, AUTOLOAD_CHAR, name_len); @@ -9555,34 +9631,6 @@ bool script_autoload(const char *const name, const size_t name_len, return ret; } -/// Return the autoload script name for a function or variable name -/// Caller must make sure that "name" contains AUTOLOAD_CHAR. -/// -/// @param[in] name Variable/function name. -/// @param[in] name_len Name length. -/// -/// @return [allocated] autoload script name. -char *autoload_name(const char *const name, const size_t name_len) - FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT -{ - // Get the script file name: replace '#' with '/', append ".vim". - char *const scriptname = xmalloc(name_len + sizeof("autoload/.vim")); - memcpy(scriptname, "autoload/", sizeof("autoload/") - 1); - memcpy(scriptname + sizeof("autoload/") - 1, name, name_len); - size_t auchar_idx = 0; - for (size_t i = sizeof("autoload/") - 1; - i - sizeof("autoload/") + 1 < name_len; - i++) { - if (scriptname[i] == AUTOLOAD_CHAR) { - scriptname[i] = '/'; - auchar_idx = i; - } - } - memcpy(scriptname + auchar_idx, ".vim", sizeof(".vim")); - - return scriptname; -} - /* * Called when starting to read a function line. * "sourcing_lnum" must be correct! @@ -9597,10 +9645,11 @@ void func_line_start(void *cookie) if (fp->uf_profiling && sourcing_lnum >= 1 && sourcing_lnum <= fp->uf_lines.ga_len) { fp->uf_tml_idx = sourcing_lnum - 1; - /* Skip continuation lines. */ - while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL) - --fp->uf_tml_idx; - fp->uf_tml_execed = FALSE; + // Skip continuation lines. + while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL) { + fp->uf_tml_idx--; + } + fp->uf_tml_execed = false; fp->uf_tml_start = profile_start(); fp->uf_tml_children = profile_zero(); fp->uf_tml_wait = profile_get_wait(); @@ -9822,14 +9871,14 @@ modify_fname( int has_fullname = 0; repeat: - /* ":p" - full path/file_name */ + // ":p" - full path/file_name if (src[*usedlen] == ':' && src[*usedlen + 1] == 'p') { has_fullname = 1; valid |= VALID_PATH; *usedlen += 2; - /* Expand "~/path" for all systems and "~user/path" for Unix */ + // Expand "~/path" for all systems and "~user/path" for Unix if ((*fnamep)[0] == '~' #if !defined(UNIX) && ((*fnamep)[1] == '/' @@ -9841,7 +9890,7 @@ repeat: && !(tilde_file && (*fnamep)[1] == NUL) ) { *fnamep = expand_env_save(*fnamep); - xfree(*bufp); /* free any allocated file name */ + xfree(*bufp); // free any allocated file name *bufp = *fnamep; if (*fnamep == NULL) return -1; @@ -9859,20 +9908,20 @@ repeat: } } - /* FullName_save() is slow, don't use it when not needed. */ + // FullName_save() is slow, don't use it when not needed. if (*p != NUL || !vim_isAbsName(*fnamep)) { - *fnamep = (char_u *)FullName_save((char *)*fnamep, *p != NUL); - xfree(*bufp); /* free any allocated file name */ + *fnamep = (char_u *)FullName_save((char *)(*fnamep), *p != NUL); + xfree(*bufp); // free any allocated file name *bufp = *fnamep; if (*fnamep == NULL) return -1; } - /* Append a path separator to a directory. */ + // Append a path separator to a directory. if (os_isdir(*fnamep)) { - /* Make room for one or two extra characters. */ + // Make room for one or two extra characters. *fnamep = vim_strnsave(*fnamep, STRLEN(*fnamep) + 2); - xfree(*bufp); /* free any allocated file name */ + xfree(*bufp); // free any allocated file name *bufp = *fnamep; if (*fnamep == NULL) return -1; @@ -9880,9 +9929,9 @@ repeat: } } - /* ":." - path relative to the current directory */ - /* ":~" - path relative to the home directory */ - /* ":8" - shortname path - postponed till after */ + // ":." - path relative to the current directory + // ":~" - path relative to the home directory + // ":8" - shortname path - postponed till after while (src[*usedlen] == ':' && ((c = src[*usedlen + 1]) == '.' || c == '~' || c == '8')) { *usedlen += 2; @@ -9890,7 +9939,7 @@ repeat: continue; } pbuf = NULL; - /* Need full path first (use expand_env() to remove a "~/") */ + // Need full path first (use expand_env() to remove a "~/") if (!has_fullname) { if (c == '.' && **fnamep == '~') p = pbuf = expand_env_save(*fnamep); @@ -9908,14 +9957,14 @@ repeat: if (s != NULL) { *fnamep = s; if (pbuf != NULL) { - xfree(*bufp); /* free any allocated file name */ + xfree(*bufp); // free any allocated file name *bufp = pbuf; pbuf = NULL; } } } else { - home_replace(NULL, p, dirname, MAXPATHL, TRUE); - /* Only replace it when it starts with '~' */ + home_replace(NULL, p, dirname, MAXPATHL, true); + // Only replace it when it starts with '~' if (*dirname == '~') { s = vim_strsave(dirname); *fnamep = s; @@ -9930,8 +9979,8 @@ repeat: tail = path_tail(*fnamep); *fnamelen = STRLEN(*fnamep); - /* ":h" - head, remove "/file_name", can be repeated */ - /* Don't remove the first "/" or "c:\" */ + // ":h" - head, remove "/file_name", can be repeated + // Don't remove the first "/" or "c:\" while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') { valid |= VALID_HEAD; *usedlen += 2; @@ -9941,7 +9990,7 @@ repeat: } *fnamelen = (size_t)(tail - *fnamep); if (*fnamelen == 0) { - /* Result is empty. Turn it into "." to make ":cd %:h" work. */ + // Result is empty. Turn it into "." to make ":cd %:h" work. xfree(*bufp); *bufp = *fnamep = tail = vim_strsave((char_u *)"."); *fnamelen = 1; @@ -9952,21 +10001,21 @@ repeat: } } - /* ":8" - shortname */ + // ":8" - shortname if (src[*usedlen] == ':' && src[*usedlen + 1] == '8') { *usedlen += 2; } - /* ":t" - tail, just the basename */ + // ":t" - tail, just the basename if (src[*usedlen] == ':' && src[*usedlen + 1] == 't') { *usedlen += 2; *fnamelen -= (size_t)(tail - *fnamep); *fnamep = tail; } - /* ":e" - extension, can be repeated */ - /* ":r" - root, without extension, can be repeated */ + // ":e" - extension, can be repeated + // ":r" - root, without extension, can be repeated while (src[*usedlen] == ':' && (src[*usedlen + 1] == 'e' || src[*usedlen + 1] == 'r')) { /* find a '.' in the tail: @@ -10018,8 +10067,8 @@ repeat: *usedlen += 2; } - /* ":s?pat?foo?" - substitute */ - /* ":gs?pat?foo?" - global substitute */ + // ":s?pat?foo?" - substitute + // ":gs?pat?foo?" - global substitute if (src[*usedlen] == ':' && (src[*usedlen + 1] == 's' || (src[*usedlen + 1] == 'g' && src[*usedlen + 2] == 's'))) { @@ -10039,12 +10088,12 @@ repeat: sep = *s++; if (sep) { - /* find end of pattern */ + // find end of pattern p = vim_strchr(s, sep); if (p != NULL) { pat = vim_strnsave(s, (int)(p - s)); s = p + 1; - /* find end of substitution */ + // find end of substitution p = vim_strchr(s, sep); if (p != NULL) { sub = vim_strnsave(s, (int)(p - s)); @@ -10061,9 +10110,10 @@ repeat: } xfree(pat); } - /* after using ":s", repeat all the modifiers */ - if (didit) + // after using ":s", repeat all the modifiers + if (didit) { goto repeat; + } } } @@ -10102,7 +10152,7 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *save_cpo; char_u *zero_width = NULL; - /* Make 'cpoptions' empty, so that the 'l' flag doesn't work here */ + // Make 'cpoptions' empty, so that the 'l' flag doesn't work here save_cpo = p_cpo; p_cpo = empty_option; @@ -10116,7 +10166,7 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, tail = str; end = str + STRLEN(str); while (vim_regexec_nl(®match, str, (colnr_T)(tail - str))) { - /* Skip empty match except for first match. */ + // Skip empty match except for first match. if (regmatch.startp[0] == regmatch.endp[0]) { if (zero_width == regmatch.startp[0]) { // avoid getting stuck on a match with an empty string @@ -10138,7 +10188,7 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, ga_grow(&ga, (int)((end - tail) + sublen - (regmatch.endp[0] - regmatch.startp[0]))); - /* copy the text up to where the match is */ + // copy the text up to where the match is int i = (int)(regmatch.startp[0] - tail); memmove((char_u *)ga.ga_data + ga.ga_len, tail, (size_t)i); // add the substituted text diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 17d9cc56aa..d3e769a7ef 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -102,6 +102,7 @@ return { exists={args=1}, exp={args=1, func="float_op_wrapper", data="&exp"}, expand={args={1, 3}}, + expandcmd={args=1}, extend={args={2, 3}}, feedkeys={args={1, 2}}, file_readable={args=1, func='f_filereadable'}, -- obsolete @@ -214,6 +215,7 @@ return { line={args=1}, line2byte={args=1}, lispindent={args=1}, + list2str={args={1, 2}}, localtime={}, log={args=1, func="float_op_wrapper", data="&log"}, log10={args=1, func="float_op_wrapper", data="&log10"}, @@ -321,6 +323,7 @@ return { sqrt={args=1, func="float_op_wrapper", data="&sqrt"}, stdpath={args=1}, str2float={args=1}, + str2list={args={1, 2}}, str2nr={args={1, 2}}, strcharpart={args={2, 3}}, strchars={args={1,2}}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b7e02d2ce7..10f9d51599 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -972,15 +972,16 @@ static void f_col(typval_T *argvars, typval_T *rettv, FunPtr fptr) fp = var2fpos(&argvars[0], FALSE, &fnum); if (fp != NULL && fnum == curbuf->b_fnum) { if (fp->col == MAXCOL) { - /* '> can be MAXCOL, get the length of the line then */ - if (fp->lnum <= curbuf->b_ml.ml_line_count) + // '> can be MAXCOL, get the length of the line then + if (fp->lnum <= curbuf->b_ml.ml_line_count) { col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1; - else + } else { col = MAXCOL; + } } else { col = fp->col + 1; - /* col(".") when the cursor is on the NUL at the end of the line - * because of "coladd" can be seen as an extra column. */ + // col(".") when the cursor is on the NUL at the end of the line + // because of "coladd" can be seen as an extra column. if (virtual_active() && fp == &curwin->w_cursor) { char_u *p = get_cursor_pos_ptr(); @@ -1665,25 +1666,29 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, FunPtr fptr) int filler_lines; int col; - if (lnum < 0) /* ignore type error in {lnum} arg */ + if (lnum < 0) { // ignore type error in {lnum} arg lnum = 0; + } if (lnum != prev_lnum || changedtick != buf_get_changedtick(curbuf) || fnum != curbuf->b_fnum) { - /* New line, buffer, change: need to get the values. */ + // New line, buffer, change: need to get the values. filler_lines = diff_check(curwin, lnum); if (filler_lines < 0) { if (filler_lines == -1) { change_start = MAXCOL; change_end = -1; - if (diff_find_change(curwin, lnum, &change_start, &change_end)) - hlID = HLF_ADD; /* added line */ - else - hlID = HLF_CHD; /* changed line */ - } else - hlID = HLF_ADD; /* added line */ - } else + if (diff_find_change(curwin, lnum, &change_start, &change_end)) { + hlID = HLF_ADD; // added line + } else { + hlID = HLF_CHD; // changed line + } + } else { + hlID = HLF_ADD; // added line + } + } else { hlID = (hlf_T)0; + } prev_lnum = lnum; changedtick = buf_get_changedtick(curbuf); fnum = curbuf->b_fnum; @@ -2061,8 +2066,8 @@ static void f_expand(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else rettv->vval.v_string = result; } else { - /* When the optional second argument is non-zero, don't remove matches - * for 'wildignore' and don't put matches for 'suffixes' at the end. */ + // When the optional second argument is non-zero, don't remove matches + // for 'wildignore' and don't put matches for 'suffixes' at the end. if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number_chk(&argvars[1], &error)) { options |= WILD_KEEP_ALL; @@ -2104,6 +2109,31 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) menu_get((char_u *)tv_get_string(&argvars[0]), modes, rettv->vval.v_list); } +// "expandcmd()" function +// Expand all the special characters in a command string. +static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + char_u *errormsg = NULL; + + rettv->v_type = VAR_STRING; + char_u *cmdstr = (char_u *)xstrdup(tv_get_string(&argvars[0])); + + exarg_T eap = { + .cmd = cmdstr, + .arg = cmdstr, + .usefilter = false, + .nextcmd = NULL, + .cmdidx = CMD_USER, + }; + eap.argt |= NOSPC; + + expand_filename(&eap, &cmdstr, &errormsg); + if (errormsg != NULL && *errormsg != NUL) { + EMSG(errormsg); + } + rettv->vval.v_string = cmdstr; +} + /* * "extend(list, list [, idx])" function * "extend(dict, dict [, action])" function @@ -2456,9 +2486,9 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } - /* Find interesting text in this line. */ + // Find interesting text in this line. s = skipwhite(ml_get(lnum)); - /* skip C comment-start */ + // skip C comment-start if (s[0] == '/' && (s[1] == '*' || s[1] == '/')) { s = skipwhite(s + 2); if (*skipwhite(s) == NUL && lnum + 1 < foldend) { @@ -2476,7 +2506,7 @@ static void f_foldtext(typval_T *argvars, typval_T *rettv, FunPtr fptr) sprintf((char *)r, txt, dashes, count); len = (int)STRLEN(r); STRCAT(r, s); - /* remove 'foldmarker' and 'commentstring' */ + // remove 'foldmarker' and 'commentstring' foldtext_cleanup(r + len); rettv->vval.v_string = r; } @@ -2778,11 +2808,12 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) buf_T *const buf = tv_get_buf(&argvars[0], false); if (buf != NULL && varname != NULL) { - // set curbuf to be our buf, temporarily - buf_T *const save_curbuf = curbuf; - curbuf = buf; - if (*varname == '&') { // buffer-local-option + buf_T *const save_curbuf = curbuf; + + // set curbuf to be our buf, temporarily + curbuf = buf; + if (varname[1] == NUL) { // get all buffer-local options in a dict dict_T *opts = get_winbuf_options(true); @@ -2795,19 +2826,21 @@ static void f_getbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) // buffer-local-option done = true; } + + // restore previous notion of curbuf + curbuf = save_curbuf; } else { // Look up the variable. // Let getbufvar({nr}, "") return the "b:" dictionary. - dictitem_T *const v = find_var_in_ht(&curbuf->b_vars->dv_hashtab, 'b', - varname, strlen(varname), false); + dictitem_T *const v = *varname == NUL + ? (dictitem_T *)&buf->b_bufvar + : find_var_in_ht(&buf->b_vars->dv_hashtab, 'b', + varname, strlen(varname), false); if (v != NULL) { tv_copy(&v->di_tv, rettv); done = true; } } - - // restore previous notion of curbuf - curbuf = save_curbuf; } emsg_off--; @@ -2901,10 +2934,10 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = n; if (IS_SPECIAL(n) || mod_mask != 0) { - char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */ + char_u temp[10]; // modifier: 3, mbyte-char: 6, NUL: 1 int i = 0; - /* Turn a special key into three bytes, plus modifier. */ + // Turn a special key into three bytes, plus modifier. if (mod_mask != 0) { temp[i++] = K_SPECIAL; temp[i++] = KS_MODIFIER; @@ -3253,7 +3286,7 @@ static void f_getfsize(typval_T *argvars, typval_T *rettv, FunPtr fptr) } else { rettv->vval.v_number = (varnumber_T)filesize; - /* non-perfect check for overflow */ + // non-perfect check for overflow if ((uint64_t)rettv->vval.v_number != filesize) { rettv->vval.v_number = -2; } @@ -4002,7 +4035,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) "dialog_con", "diff", "digraphs", - "eval", /* always present, of course! */ + "eval", // always present, of course! "ex_extra", "extra_search", "file_in_path", @@ -4070,7 +4103,7 @@ static void f_has(typval_T *argvars, typval_T *rettv, FunPtr fptr) "textobjects", "timers", "title", - "user-commands", /* was accidentally included in 5.4 */ + "user-commands", // was accidentally included in 5.4 "user_commands", "vertsplit", "virtualedit", @@ -4293,7 +4326,7 @@ static void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) HistoryType histype; rettv->vval.v_number = false; - if (check_restricted() || check_secure()) { + if (check_secure()) { return; } const char *str = tv_get_string_chk(&argvars[0]); // NULL on type error @@ -4526,9 +4559,9 @@ static void f_inputlist(typval_T *argvars, typval_T *rettv, FunPtr fptr) } msg_start(); - msg_row = Rows - 1; /* for when 'cmdheight' > 1 */ - lines_left = Rows; /* avoid more prompt */ - msg_scroll = TRUE; + msg_row = Rows - 1; // for when 'cmdheight' > 1 + lines_left = Rows; // avoid more prompt + msg_scroll = true; msg_clr_eos(); TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, { @@ -5247,6 +5280,35 @@ static void f_lispindent(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } +// "list2str()" function +static void f_list2str(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + garray_T ga; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + if (argvars[0].v_type != VAR_LIST) { + EMSG(_(e_invarg)); + return; + } + + list_T *const l = argvars[0].vval.v_list; + if (l == NULL) { + return; // empty list results in empty string + } + + ga_init(&ga, 1, 80); + char_u buf[MB_MAXBYTES + 1]; + + TV_LIST_ITER_CONST(l, li, { + buf[utf_char2bytes(tv_get_number(TV_LIST_ITEM_TV(li)), buf)] = NUL; + ga_concat(&ga, buf); + }); + ga_append(&ga, NUL); + + rettv->vval.v_string = ga.ga_data; +} + /* * "localtime()" function */ @@ -5373,7 +5435,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, long idx = 0; char_u *tofree = NULL; - /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ + // Make 'cpoptions' empty, the 'l' flag should not be used here. save_cpo = p_cpo; p_cpo = (char_u *)""; @@ -5439,12 +5501,12 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, start = 0; if (start > len) goto theend; - /* When "count" argument is there ignore matches before "start", - * otherwise skip part of the string. Differs when pattern is "^" - * or "\<". */ - if (argvars[3].v_type != VAR_UNKNOWN) + // When "count" argument is there ignore matches before "start", + // otherwise skip part of the string. Differs when pattern is "^" + // or "\<". + if (argvars[3].v_type != VAR_UNKNOWN) { startcol = start; - else { + } else { str += start; len -= start; } @@ -5483,7 +5545,7 @@ static void find_some_match(typval_T *const argvars, typval_T *const rettv, if (l == NULL && !match) break; - /* Advance to just after the match. */ + // Advance to just after the match. if (l != NULL) { li = TV_LIST_ITEM_NEXT(l, li); idx++; @@ -5590,8 +5652,11 @@ static void f_matchadd(typval_T *argvars, typval_T *rettv, FunPtr fptr) { char grpbuf[NUMBUFLEN]; char patbuf[NUMBUFLEN]; + // group const char *const grp = tv_get_string_buf_chk(&argvars[0], grpbuf); + // pattern const char *const pat = tv_get_string_buf_chk(&argvars[1], patbuf); + // default priority int prio = 10; int id = -1; bool error = false; @@ -6256,12 +6321,12 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) { bool binary = false; FILE *fd; - char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */ + char_u buf[(IOSIZE/256) * 256]; // rounded to avoid odd + 1 int io_size = sizeof(buf); - int readlen; /* size of last fread() */ - char_u *prev = NULL; /* previously read bytes, if any */ - long prevlen = 0; /* length of data in prev */ - long prevsize = 0; /* size of prev buffer */ + int readlen; // size of last fread() + char_u *prev = NULL; // previously read bytes, if any + long prevlen = 0; // length of data in prev + long prevsize = 0; // size of prev buffer long maxline = MAXLNUM; if (argvars[1].v_type != VAR_UNKNOWN) { @@ -6300,14 +6365,17 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) char_u *s = NULL; size_t len = p - start; - /* Finished a line. Remove CRs before NL. */ + // Finished a line. Remove CRs before NL. if (readlen > 0 && !binary) { - while (len > 0 && start[len - 1] == '\r') - --len; - /* removal may cross back to the "prev" string */ - if (len == 0) - while (prevlen > 0 && prev[prevlen - 1] == '\r') - --prevlen; + while (len > 0 && start[len - 1] == '\r') { + len--; + } + // removal may cross back to the "prev" string + if (len == 0) { + while (prevlen > 0 && prev[prevlen - 1] == '\r') { + prevlen--; + } + } } if (prevlen == 0) { assert(len < INT_MAX); @@ -6319,7 +6387,7 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) s = xrealloc(prev, prevlen + len + 1); memcpy(s + prevlen, start, len); s[prevlen + len] = NUL; - prev = NULL; /* the list will own the string */ + prev = NULL; // the list will own the string prevlen = prevsize = 0; } @@ -6358,13 +6426,12 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (back2 == 0xef && back1 == 0xbb) { char_u *dest = p - 2; - /* Usually a BOM is at the beginning of a file, and so at - * the beginning of a line; then we can just step over it. - */ - if (start == dest) + // Usually a BOM is at the beginning of a file, and so at + // the beginning of a line; then we can just step over it. + if (start == dest) { start = p + 1; - else { - /* have to shuffle buf to close gap */ + } else { + // have to shuffle buf to close gap int adjust_prevlen = 0; if (dest < buf) { // -V782 @@ -6380,13 +6447,13 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } } - } /* for */ + } // for if ((maxline >= 0 && tv_list_len(l) >= maxline) || readlen <= 0) { break; } if (start < p) { - /* There's part of a line in buf, store it in "prev". */ + // There's part of a line in buf, store it in "prev". if (p - start + prevlen >= prevsize) { /* A common use case is ordinary text files and "prev" gets a * fragment of a line, so the first allocation is made @@ -6401,11 +6468,11 @@ static void f_readfile(typval_T *argvars, typval_T *rettv, FunPtr fptr) } prev = xrealloc(prev, prevsize); } - /* Add the line part to end of "prev". */ + // Add the line part to end of "prev". memmove(prev + prevlen, start, p - start); prevlen += (long)(p - start); } - } /* while */ + } // while xfree(prev); fclose(fd); @@ -6656,7 +6723,12 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->v_type = VAR_STRING; const char *fname = tv_get_string(&argvars[0]); #ifdef WIN32 - char *const v = os_resolve_shortcut(fname); + char *v = os_resolve_shortcut(fname); + if (v == NULL) { + if (os_is_reparse_point_include(fname)) { + v = os_realpath(fname, v); + } + } rettv->vval.v_string = (char_u *)(v == NULL ? xstrdup(fname) : v); #else # ifdef HAVE_READLINK @@ -6897,7 +6969,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) pos_T save_cursor; bool save_p_ws = p_ws; int dir; - int retval = 0; /* default: FAIL */ + int retval = 0; // default: FAIL long lnum_stop = 0; proftime_T tm; long time_limit = 0; @@ -6921,7 +6993,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) options |= SEARCH_COL; } - /* Optional arguments: line number to stop searching and timeout. */ + // Optional arguments: line number to stop searching and timeout. if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) { lnum_stop = tv_get_number_chk(&argvars[2], NULL); if (lnum_stop < 0) { @@ -6935,7 +7007,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) } } - /* Set the time limit, if there is one. */ + // Set the time limit, if there is one. tm = profile_setlimit(time_limit); /* @@ -6965,20 +7037,21 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) setpcmark(); curwin->w_cursor = pos; if (match_pos != NULL) { - /* Store the match cursor position */ + // Store the match cursor position match_pos->lnum = pos.lnum; match_pos->col = pos.col + 1; } - /* "/$" will put the cursor after the end of the line, may need to - * correct that here */ + // "/$" will put the cursor after the end of the line, may need to + // correct that here check_cursor(); } - /* If 'n' flag is used: restore cursor position. */ - if (flags & SP_NOMOVE) + // If 'n' flag is used: restore cursor position. + if (flags & SP_NOMOVE) { curwin->w_cursor = save_cursor; - else - curwin->w_set_curswant = TRUE; + } else { + curwin->w_set_curswant = true; + } theend: p_ws = save_p_ws; @@ -7317,7 +7390,7 @@ static void f_searchdecl(typval_T *argvars, typval_T *rettv, FunPtr fptr) int thisblock = 0; bool error = false; - rettv->vval.v_number = 1; /* default: FAIL */ + rettv->vval.v_number = 1; // default: FAIL const char *const name = tv_get_string_chk(&argvars[0]); if (argvars[1].v_type != VAR_UNKNOWN) { @@ -7475,11 +7548,11 @@ do_searchpair( size_t pat2_len; size_t pat3_len; - /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ + // Make 'cpoptions' empty, the 'l' flag should not be used here. save_cpo = p_cpo; p_cpo = empty_option; - /* Set the time limit, if there is one. */ + // Set the time limit, if there is one. tm = profile_setlimit(time_limit); // Make two search patterns: start/end (pat2, for in nested pairs) and @@ -7527,17 +7600,18 @@ do_searchpair( if (firstpos.lnum == 0) firstpos = pos; if (equalpos(pos, foundpos)) { - /* Found the same position again. Can happen with a pattern that - * has "\zs" at the end and searching backwards. Advance one - * character and try again. */ - if (dir == BACKWARD) + // Found the same position again. Can happen with a pattern that + // has "\zs" at the end and searching backwards. Advance one + // character and try again. + if (dir == BACKWARD) { decl(&pos); - else + } else { incl(&pos); + } } foundpos = pos; - /* clear the start flag to avoid getting stuck here */ + // clear the start flag to avoid getting stuck here options &= ~SEARCH_START; // If the skip pattern matches, ignore this match. @@ -7548,7 +7622,7 @@ do_searchpair( const bool r = eval_expr_to_bool(skip, &err); curwin->w_cursor = save_pos; if (err) { - /* Evaluating {skip} caused an error, break here. */ + // Evaluating {skip} caused an error, break here. curwin->w_cursor = save_cursor; retval = -1; break; @@ -7558,49 +7632,54 @@ do_searchpair( } if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2)) { - /* Found end when searching backwards or start when searching - * forward: nested pair. */ - ++nest; - pat = pat2; /* nested, don't search for middle */ + // Found end when searching backwards or start when searching + // forward: nested pair. + nest++; + pat = pat2; // nested, don't search for middle } else { - /* Found end when searching forward or start when searching - * backward: end of (nested) pair; or found middle in outer pair. */ - if (--nest == 1) - pat = pat3; /* outer level, search for middle */ + // Found end when searching forward or start when searching + // backward: end of (nested) pair; or found middle in outer pair. + if (--nest == 1) { + pat = pat3; // outer level, search for middle + } } if (nest == 0) { - /* Found the match: return matchcount or line number. */ - if (flags & SP_RETCOUNT) - ++retval; - else + // Found the match: return matchcount or line number. + if (flags & SP_RETCOUNT) { + retval++; + } else { retval = pos.lnum; - if (flags & SP_SETPCMARK) + } + if (flags & SP_SETPCMARK) { setpcmark(); + } curwin->w_cursor = pos; if (!(flags & SP_REPEAT)) break; - nest = 1; /* search for next unmatched */ + nest = 1; // search for next unmatched } } if (match_pos != NULL) { - /* Store the match cursor position */ + // Store the match cursor position match_pos->lnum = curwin->w_cursor.lnum; match_pos->col = curwin->w_cursor.col + 1; } - /* If 'n' flag is used or search failed: restore cursor position. */ - if ((flags & SP_NOMOVE) || retval == 0) + // If 'n' flag is used or search failed: restore cursor position. + if ((flags & SP_NOMOVE) || retval == 0) { curwin->w_cursor = save_cursor; + } xfree(pat2); xfree(pat3); - if (p_cpo == empty_option) + if (p_cpo == empty_option) { p_cpo = save_cpo; - else - /* Darn, evaluating the {skip} expression changed the value. */ + } else { + // Darn, evaluating the {skip} expression changed the value. free_string_option(save_cpo); + } return retval; } @@ -7726,8 +7805,7 @@ static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) */ static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - if (check_restricted() - || check_secure() + if (check_secure() || !tv_check_str_or_nr(&argvars[0])) { return; } @@ -7755,10 +7833,9 @@ static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) // reset notion of buffer aucmd_restbuf(&aco); } else { - buf_T *save_curbuf = curbuf; - const size_t varname_len = STRLEN(varname); char *const bufvarname = xmalloc(varname_len + 3); + buf_T *const save_curbuf = curbuf; curbuf = buf; memcpy(bufvarname, "b:", 2); memcpy(bufvarname + 2, varname, varname_len + 1); @@ -8231,7 +8308,7 @@ static void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) { rettv->vval.v_number = 0; - if (check_restricted() || check_secure()) { + if (check_secure()) { return; } @@ -8979,7 +9056,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort) info.item_compare_selfdict = NULL; if (argvars[1].v_type != VAR_UNKNOWN) { - /* optional second argument: {func} */ + // optional second argument: {func} if (argvars[1].v_type == VAR_FUNC) { info.item_compare_func = (const char *)argvars[1].vval.v_string; } else if (argvars[1].v_type == VAR_PARTIAL) { @@ -9240,7 +9317,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, FunPtr fptr) bool keepempty = false; bool typeerr = false; - /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ + // Make 'cpoptions' empty, the 'l' flag should not be used here. save_cpo = p_cpo; p_cpo = (char_u *)""; @@ -9354,6 +9431,17 @@ static void f_str2float(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->v_type = VAR_FLOAT; } +// "str2list()" function +static void f_str2list(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + tv_list_alloc_ret(rettv, kListLenUnknown); + const char_u *p = (const char_u *)tv_get_string(&argvars[0]); + + for (; *p != NUL; p += utf_ptr2len(p)) { + tv_list_append_number(rettv->vval.v_list, utf_ptr2char(p)); + } +} + // "str2nr()" function static void f_str2nr(typval_T *argvars, typval_T *rettv, FunPtr fptr) { @@ -9417,10 +9505,10 @@ static void f_strftime(typval_T *argvars, typval_T *rettv, FunPtr fptr) struct tm curtime; struct tm *curtime_ptr = os_localtime_r(&seconds, &curtime); - /* MSVC returns NULL for an invalid value of seconds. */ - if (curtime_ptr == NULL) + // MSVC returns NULL for an invalid value of seconds. + if (curtime_ptr == NULL) { rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)")); - else { + } else { vimconv_T conv; char_u *enc; @@ -9518,7 +9606,7 @@ static void f_stridx(typval_T *argvars, typval_T *rettv, FunPtr fptr) /* * "string()" function */ -static void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr) +void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr) { rettv->v_type = VAR_STRING; rettv->vval.v_string = (char_u *)encode_tv2string(&argvars[0], NULL); @@ -10117,7 +10205,7 @@ static int get_winnr(tabpage_T *tp, typval_T *argvar) for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin; wp != twin; wp = wp->w_next) { if (wp == NULL) { - /* didn't find it in this tabpage */ + // didn't find it in this tabpage nr = 0; break; } @@ -10706,9 +10794,10 @@ static void f_visualmode(typval_T *argvars, typval_T *rettv, FunPtr fptr) str[1] = NUL; rettv->vval.v_string = vim_strsave(str); - /* A non-zero number or non-empty string argument: reset mode. */ - if (non_zero_arg(&argvars[0])) + // A non-zero number or non-empty string argument: reset mode. + if (non_zero_arg(&argvars[0])) { curbuf->b_visual_mode_eval = NUL; + } } /* @@ -10941,7 +11030,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr) { rettv->vval.v_number = -1; - if (check_restricted() || check_secure()) { + if (check_secure()) { return; } diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index cc12ad08fa..4390db1b71 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -33,7 +33,7 @@ typedef double float_T; enum { DO_NOT_FREE_CNT = (INT_MAX / 2) }; /// Additional values for tv_list_alloc() len argument -enum { +enum ListLenSpecials { /// List length is not known in advance /// /// To be used when there is neither a way to know how many elements will be @@ -49,7 +49,7 @@ enum { /// /// To be used when it looks impractical to determine list length. kListLenMayKnow = -3, -} ListLenSpecials; +}; /// Maximal possible value of varnumber_T variable #define VARNUMBER_MAX INT64_MAX diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 2c1cf3eedf..c55a29c67c 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -42,7 +42,7 @@ hashtab_T func_hashtab; // Used by get_func_tv() static garray_T funcargs = GA_EMPTY_INIT_VALUE; -/* pointer to funccal for currently active function */ +// pointer to funccal for currently active function funccall_T *current_funccal = NULL; // Pointer to list of previously used funccal, still around because some @@ -333,7 +333,7 @@ char_u *deref_func_name(const char *name, int *lenp, /// /// @param ermsg must be passed without translation (use N_() instead of _()). /// @param name function name -static void emsg_funcname(char *ermsg, const char_u *name) +void emsg_funcname(char *ermsg, const char_u *name) { char_u *p; @@ -547,7 +547,7 @@ static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr) static void free_funccal( funccall_T *fc, - int free_val /* a: vars were allocated */ + int free_val // a: vars were allocated ) { for (int i = 0; i < fc->fc_funcs.ga_len; i++) { @@ -726,7 +726,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, int save_did_emsg; static int depth = 0; dictitem_T *v; - int fixvar_idx = 0; /* index in fixvar[] */ + int fixvar_idx = 0; // index in fixvar[] int ai; bool islambda = false; char_u numbuf[NUMBUFLEN]; @@ -737,7 +737,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, bool did_save_redo = false; save_redo_T save_redo; - /* If depth of calling is getting too high, don't execute the function */ + // If depth of calling is getting too high, don't execute the function if (depth >= p_mfd) { EMSG(_("E132: Function call depth is higher than 'maxfuncdepth'")); rettv->v_type = VAR_NUMBER; @@ -764,8 +764,8 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, fc->linenr = 0; fc->returned = FALSE; fc->level = ex_nesting_level; - /* Check if this function has a breakpoint. */ - fc->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0); + // Check if this function has a breakpoint. + fc->breakpoint = dbg_find_breakpoint(false, fp->uf_name, (linenr_T)0); fc->dbg_tick = debug_tick; // Set up fields for closure. @@ -876,8 +876,8 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, } } - /* Don't redraw while executing the function. */ - ++RedrawingDisabled; + // Don't redraw while executing the function. + RedrawingDisabled++; save_sourcing_name = sourcing_name; save_sourcing_lnum = sourcing_lnum; sourcing_lnum = 1; @@ -979,7 +979,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, save_did_emsg = did_emsg; did_emsg = FALSE; - /* call do_cmdline() to execute the lines */ + // call do_cmdline() to execute the lines do_cmdline(NULL, get_func_line, (void *)fc, DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT); @@ -1011,7 +1011,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, } } - /* when being verbose, mention the return value */ + // when being verbose, mention the return value if (p_verbose >= 12) { ++no_wait_return; verbose_enter_scroll(); @@ -1298,6 +1298,10 @@ call_func( } if (error == ERROR_NONE && partial->pt_argc > 0) { for (argv_clear = 0; argv_clear < partial->pt_argc; argv_clear++) { + if (argv_clear + argcount_in >= MAX_FUNC_ARGS) { + error = ERROR_TOOMANY; + goto theend; + } tv_copy(&partial->pt_argv[argv_clear], &argv[argv_clear]); } for (int i = 0; i < argcount_in; i++) { @@ -1311,12 +1315,12 @@ call_func( if (error == ERROR_NONE && evaluate) { char_u *rfname = fname; - /* Ignore "g:" before a function name. */ + // Ignore "g:" before a function name. if (fname[0] == 'g' && fname[1] == ':') { rfname = fname + 2; } - rettv->v_type = VAR_NUMBER; /* default rettv is number zero */ + rettv->v_type = VAR_NUMBER; // default rettv is number zero rettv->vval.v_number = 0; error = ERROR_UNKNOWN; @@ -1338,7 +1342,7 @@ call_func( if (fp == NULL && apply_autocmds(EVENT_FUNCUNDEFINED, rfname, rfname, TRUE, NULL) && !aborting()) { - /* executed an autocommand, search for the function again */ + // executed an autocommand, search for the function again fp = find_func(rfname); } // Try loading a package. @@ -1352,7 +1356,9 @@ call_func( error = ERROR_DELETED; } else if (fp != NULL) { if (argv_func != NULL) { - argcount = argv_func(argcount, argvars, fp->uf_args.ga_len); + // postponed filling in the arguments, do it now + argcount = argv_func(argcount, argvars, argv_clear, + fp->uf_args.ga_len); } if (fp->uf_flags & FC_RANGE) { *doesrange = true; @@ -1400,10 +1406,9 @@ call_func( if (error == ERROR_NONE) ret = OK; - /* - * Report an error unless the argument evaluation or function call has been - * cancelled due to an aborting error, an interrupt, or an exception. - */ +theend: + // Report an error unless the argument evaluation or function call has been + // cancelled due to an aborting error, an interrupt, or an exception. if (!aborting()) { switch (error) { case ERROR_UNKNOWN: @@ -1735,7 +1740,7 @@ void ex_function(exarg_T *eap) int nesting; dictitem_T *v; funcdict_T fudi; - static int func_nr = 0; /* number for nameless function */ + static int func_nr = 0; // number for nameless function int paren; hashtab_T *ht; int todo; @@ -1898,9 +1903,10 @@ void ex_function(exarg_T *eap) EMSG2(_("E124: Missing '(': %s"), eap->arg); goto ret_free; } - /* attempt to continue by skipping some text */ - if (vim_strchr(p, '(') != NULL) + // attempt to continue by skipping some text + if (vim_strchr(p, '(') != NULL) { p = vim_strchr(p, '('); + } } p = skipwhite(p + 1); @@ -1922,9 +1928,10 @@ void ex_function(exarg_T *eap) if (arg[j] != NUL) emsg_funcname((char *)e_invarg2, arg); } - /* Disallow using the g: dict. */ - if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE) + // Disallow using the g: dict. + if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE) { EMSG(_("E862: Cannot use g: here")); + } } if (get_function_args(&p, ')', &newargs, &varargs, eap->skip) == FAIL) { @@ -2006,7 +2013,7 @@ void ex_function(exarg_T *eap) need_wait_return = false; if (line_arg != NULL) { - /* Use eap->arg, split up in parts by line breaks. */ + // Use eap->arg, split up in parts by line breaks. theline = line_arg; p = vim_strchr(theline, '\n'); if (p == NULL) @@ -2069,11 +2076,11 @@ void ex_function(exarg_T *eap) } } } else { - /* skip ':' and blanks*/ - for (p = theline; ascii_iswhite(*p) || *p == ':'; ++p) - ; + // skip ':' and blanks + for (p = theline; ascii_iswhite(*p) || *p == ':'; p++) { + } - /* Check for "endfunction". */ + // Check for "endfunction". if (checkforcmd(&p, "endfunction", 4) && nesting-- == 0) { if (*p == '!') { p++; @@ -2111,7 +2118,7 @@ void ex_function(exarg_T *eap) || STRNCMP(p, "try", 3) == 0) indent += 2; - /* Check for defining a function inside this function. */ + // Check for defining a function inside this function. if (checkforcmd(&p, "function", 2)) { if (*p == '!') { p = skipwhite(p + 1); @@ -2156,9 +2163,8 @@ void ex_function(exarg_T *eap) || (p[0] == 'r' && p[1] == 'u' && p[2] == 'b' && (!ASCII_ISALPHA(p[3]) || p[3] == 'y')) || (p[0] == 'm' && p[1] == 'z' - && (!ASCII_ISALPHA(p[2]) || p[2] == 's')) - )) { - /* ":python <<" continues until a dot, like ":append" */ + && (!ASCII_ISALPHA(p[2]) || p[2] == 's')))) { + // ":python <<" continues until a dot, like ":append" p = skipwhite(arg + 2); if (*p == NUL) skip_until = vim_strsave((char_u *)"."); @@ -2195,7 +2201,7 @@ void ex_function(exarg_T *eap) } } - /* Add the line to the function. */ + // Add the line to the function. ga_grow(&newlines, 1 + sourcing_lnum_off); /* Copy the line to newly allocated memory. get_one_sourceline() @@ -2209,9 +2215,10 @@ void ex_function(exarg_T *eap) while (sourcing_lnum_off-- > 0) ((char_u **)(newlines.ga_data))[newlines.ga_len++] = NULL; - /* Check for end of eap->arg. */ - if (line_arg != NULL && *line_arg == NUL) + // Check for end of eap->arg. + if (line_arg != NULL && *line_arg == NUL) { line_arg = NULL; + } } /* Don't define the function when skipping commands or when an error was @@ -2292,7 +2299,7 @@ void ex_function(exarg_T *eap) int slen, plen; char_u *scriptname; - /* Check that the autoload name matches the script name. */ + // Check that the autoload name matches the script name. int j = FAIL; if (sourcing_name != NULL) { scriptname = (char_u *)autoload_name((const char *)name, STRLEN(name)); @@ -2330,11 +2337,11 @@ void ex_function(exarg_T *eap) fudi.fd_di->di_tv.v_type = VAR_FUNC; fudi.fd_di->di_tv.vval.v_string = vim_strsave(name); - /* behave like "dict" was used */ + // behave like "dict" was used flags |= FC_DICT; } - /* insert the new function in the function list */ + // insert the new function in the function list STRCPY(fp->uf_name, name); if (overwrite) { hi = hash_find(&func_hashtab, name); @@ -2688,10 +2695,11 @@ void ex_return(exarg_T *eap) /* When skipping or the return gets pending, advance to the next command * in this line (!returning). Otherwise, ignore the rest of the line. * Following lines will be ignored by get_func_line(). */ - if (returning) + if (returning) { eap->nextcmd = NULL; - else if (eap->nextcmd == NULL) /* no argument */ + } else if (eap->nextcmd == NULL) { // no argument eap->nextcmd = check_nextcmd(arg); + } if (eap->skip) --emsg_skip; @@ -2803,7 +2811,8 @@ void ex_call(exarg_T *eap) } } - if (!failed) { + // When inside :try we need to check for following "| catch". + if (!failed || eap->cstack->cs_trylevel > 0) { // Check for trailing illegal characters and a following command. if (!ends_excmd(*arg)) { emsg_severe = TRUE; @@ -2831,9 +2840,10 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) int idx; cstack_T *const cstack = eap->cstack; - if (reanimate) - /* Undo the return. */ - current_funccal->returned = FALSE; + if (reanimate) { + // Undo the return. + current_funccal->returned = false; + } /* * Cleanup (and inactivate) conditionals, but stop when a try conditional @@ -2859,7 +2869,7 @@ int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv) } if (rettv != NULL) { - /* Store the value of the pending return. */ + // Store the value of the pending return. cstack->cs_rettv[idx] = xcalloc(1, sizeof(typval_T)); *(typval_T *)cstack->cs_rettv[idx] = *(typval_T *)rettv; } else @@ -2925,9 +2935,9 @@ char_u *get_func_line(int c, void *cookie, int indent, bool do_concat) funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->func; char_u *retval; - garray_T *gap; /* growarray with function lines */ + garray_T *gap; // growarray with function lines - /* If breakpoints have been added/deleted need to check for it. */ + // If breakpoints have been added/deleted need to check for it. if (fcp->dbg_tick != debug_tick) { fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, sourcing_lnum); @@ -2938,16 +2948,17 @@ char_u *get_func_line(int c, void *cookie, int indent, bool do_concat) gap = &fp->uf_lines; if (((fp->uf_flags & FC_ABORT) && did_emsg && !aborted_in_try()) - || fcp->returned) + || fcp->returned) { retval = NULL; - else { - /* Skip NULL lines (continuation lines). */ + } else { + // Skip NULL lines (continuation lines). while (fcp->linenr < gap->ga_len - && ((char_u **)(gap->ga_data))[fcp->linenr] == NULL) - ++fcp->linenr; - if (fcp->linenr >= gap->ga_len) + && ((char_u **)(gap->ga_data))[fcp->linenr] == NULL) { + fcp->linenr++; + } + if (fcp->linenr >= gap->ga_len) { retval = NULL; - else { + } else { retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]); sourcing_lnum = fcp->linenr; if (do_profiling == PROF_YES) @@ -2955,12 +2966,12 @@ char_u *get_func_line(int c, void *cookie, int indent, bool do_concat) } } - /* Did we encounter a breakpoint? */ + // Did we encounter a breakpoint? if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum) { dbg_breakpoint(fp->uf_name, sourcing_lnum); - /* Find next breakpoint. */ - fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, - sourcing_lnum); + // Find next breakpoint. + fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, + sourcing_lnum); fcp->dbg_tick = debug_tick; } diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h index db4e02ee98..ad8e071548 100644 --- a/src/nvim/eval/userfunc.h +++ b/src/nvim/eval/userfunc.h @@ -24,7 +24,7 @@ typedef enum { ERROR_DELETED, } FnameTransError; -typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, +typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int argskip, int called_func_argcount); #define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j] diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c index c2be472acd..e341513ae1 100644 --- a/src/nvim/event/loop.c +++ b/src/nvim/event/loop.c @@ -116,6 +116,20 @@ void loop_on_put(MultiQueue *queue, void *data) uv_stop(&loop->uv); } +#if !defined(EXITFREE) +static void loop_walk_cb(uv_handle_t *handle, void *arg) +{ + if (!uv_is_closing(handle)) { + uv_close(handle, NULL); + } +} +#endif + +/// Closes `loop` and its handles, and frees its structures. +/// +/// @param loop Loop to destroy +/// @param wait Wait briefly for handles to deref +/// /// @returns false if the loop could not be closed gracefully bool loop_close(Loop *loop, bool wait) { @@ -126,18 +140,34 @@ bool loop_close(Loop *loop, bool wait) uv_close((uv_handle_t *)&loop->poll_timer, timer_close_cb); uv_close((uv_handle_t *)&loop->async, NULL); uint64_t start = wait ? os_hrtime() : 0; + bool didstop = false; while (true) { - uv_run(&loop->uv, wait ? UV_RUN_DEFAULT : UV_RUN_NOWAIT); - if (!uv_loop_close(&loop->uv) || !wait) { + // Run the loop to tickle close-callbacks (which should then free memory). + // Use UV_RUN_NOWAIT to avoid a hang. #11820 + uv_run(&loop->uv, didstop ? UV_RUN_DEFAULT : UV_RUN_NOWAIT); + if ((uv_loop_close(&loop->uv) != UV_EBUSY) || !wait) { break; } - if (os_hrtime() - start >= 2 * 1000000000) { + uint64_t elapsed_s = (os_hrtime() - start) / 1000000000; // seconds + if (elapsed_s >= 2) { // Some libuv resource was not correctly deref'd. Log and bail. rv = false; ELOG("uv_loop_close() hang?"); log_uv_handles(&loop->uv); break; } +#if defined(EXITFREE) + (void)didstop; +#else + if (!didstop) { + // Loop won’t block for I/O after this. + uv_stop(&loop->uv); + // XXX: Close all (lua/luv!) handles. But loop_walk_cb() does not call + // resource-specific close-callbacks, so this leaks memory... + uv_walk(&loop->uv, loop_walk_cb, NULL); + didstop = true; + } +#endif } multiqueue_free(loop->fast_events); multiqueue_free(loop->thread_events); diff --git a/src/nvim/event/stream.c b/src/nvim/event/stream.c index d1a53fa4b6..0e87f7c6c1 100644 --- a/src/nvim/event/stream.c +++ b/src/nvim/event/stream.c @@ -16,6 +16,11 @@ # include "event/stream.c.generated.h" #endif +// For compatbility with libuv < 1.19.0 (tested on 1.18.0) +#if UV_VERSION_MINOR < 19 +#define uv_stream_get_write_queue_size(stream) stream->write_queue_size +#endif + /// Sets the stream associated with `fd` to "blocking" mode. /// /// @return `0` on success, or libuv error code on failure. diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index bc6821f60f..d26d3387f8 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -882,7 +882,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) mark_adjust_nofold(line2 + 1, dest, -num_lines, 0L, kExtmarkNOOP); FOR_ALL_TAB_WINDOWS(tab, win) { if (win->w_buffer == curbuf) { - foldMoveRange(&win->w_folds, line1, line2, dest); + foldMoveRange(win, &win->w_folds, line1, line2, dest); } } curbuf->b_op_start.lnum = dest - num_lines + 1; @@ -891,7 +891,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) mark_adjust_nofold(dest + 1, line1 - 1, num_lines, 0L, kExtmarkNOOP); FOR_ALL_TAB_WINDOWS(tab, win) { if (win->w_buffer == curbuf) { - foldMoveRange(&win->w_folds, dest + 1, line1 - 1, line2); + foldMoveRange(win, &win->w_folds, dest + 1, line1 - 1, line2); } } curbuf->b_op_start.lnum = dest + 1; @@ -2177,6 +2177,7 @@ int do_ecmd( int did_get_winopts = FALSE; int readfile_flags = 0; bool did_inc_redrawing_disabled = false; + long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; if (eap != NULL) command = eap->do_ecmd_cmd; @@ -2678,13 +2679,14 @@ int do_ecmd( RedrawingDisabled--; did_inc_redrawing_disabled = false; if (!skip_redraw) { - n = p_so; - if (topline == 0 && command == NULL) - p_so = 999; // force cursor to be vertically centered in the window + n = *so_ptr; + if (topline == 0 && command == NULL) { + *so_ptr = 999; // force cursor to be vertically centered in the window + } update_topline(); curwin->w_scbind_pos = curwin->w_topline; - p_so = n; - redraw_curbuf_later(NOT_VALID); /* redraw this buffer later */ + *so_ptr = n; + redraw_curbuf_later(NOT_VALID); // redraw this buffer later } if (p_im) @@ -3008,18 +3010,18 @@ void ex_z(exarg_T *eap) ex_no_reprint = true; } -/* - * Check if the restricted flag is set. - * If so, give an error message and return TRUE. - * Otherwise, return FALSE. - */ -int check_restricted(void) +// Check if the restricted flag is set. +// If so, give an error message and return true. +// Otherwise, return false. +bool check_restricted(void) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (restricted) { - EMSG(_("E145: Shell commands not allowed in restricted mode")); - return TRUE; + EMSG(_("E145: Shell commands and some functionality not allowed" + " in restricted mode")); + return true; } - return FALSE; + return false; } /* @@ -4482,8 +4484,9 @@ prepare_tagpreview ( curwin->w_p_wfh = TRUE; RESET_BINDING(curwin); /* don't take over 'scrollbind' and 'cursorbind' */ - curwin->w_p_diff = FALSE; /* no 'diff' */ - curwin->w_p_fdc = 0; /* no 'foldcolumn' */ + curwin->w_p_diff = false; // no 'diff' + set_string_option_direct((char_u *)"fdc", -1, // no 'foldcolumn' + (char_u *)"0", OPT_FREE, SID_NONE); return true; } } diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index f7aa8a994a..252af409c0 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -24,6 +24,7 @@ local SBOXOK = 0x80000 local CMDWIN = 0x100000 local MODIFY = 0x200000 local EXFLAGS = 0x400000 +local RESTRICT = 0x800000 local FILES = bit.bor(XFILE, EXTRA) local WORD1 = bit.bor(EXTRA, NOSPC) local FILE1 = bit.bor(FILES, NOSPC) @@ -1582,19 +1583,19 @@ return { }, { command='lua', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_lua', }, { command='luado', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_luado', }, { command='luafile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_luafile', }, @@ -1924,13 +1925,13 @@ return { }, { command='perl', - flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, SBOXOK, CMDWIN), + flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, SBOXOK, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_script_ni', }, { command='perldo', - flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_ni', }, @@ -2056,67 +2057,67 @@ return { }, { command='python', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_python', }, { command='pydo', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_pydo', }, { command='pyfile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_pyfile', }, { command='py3', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_python3', }, { command='py3do', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_pydo3', }, { command='python3', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_python3', }, { command='py3file', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_py3file', }, { command='pyx', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_pyx', }, { command='pyxdo', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_pyxdo', }, { command='pythonx', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_pyx', }, { command='pyxfile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_pyxfile', }, @@ -2242,19 +2243,19 @@ return { }, { command='ruby', - flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_ruby', }, { command='rubydo', - flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_rubydo', }, { command='rubyfile', - flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN), + flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT), addr_type=ADDR_LINES, func='ex_rubyfile', }, diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 4a40cc54b4..1f0560ae48 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -36,35 +36,36 @@ // 4. Add documentation in ../doc/xxx.txt. Add a tag for both the short and // long name of the command. -#define RANGE 0x001 /* allow a linespecs */ -#define BANG 0x002 /* allow a ! after the command name */ -#define EXTRA 0x004 /* allow extra args after command name */ -#define XFILE 0x008 /* expand wildcards in extra part */ -#define NOSPC 0x010 /* no spaces allowed in the extra part */ -#define DFLALL 0x020 /* default file range is 1,$ */ -#define WHOLEFOLD 0x040 /* extend range to include whole fold also - when less than two numbers given */ -#define NEEDARG 0x080 /* argument required */ -#define TRLBAR 0x100 /* check for trailing vertical bar */ -#define REGSTR 0x200 /* allow "x for register designation */ -#define COUNT 0x400 /* allow count in argument, after command */ -#define NOTRLCOM 0x800 /* no trailing comment allowed */ -#define ZEROR 0x1000 /* zero line number allowed */ -#define USECTRLV 0x2000 /* do not remove CTRL-V from argument */ -#define NOTADR 0x4000 /* number before command is not an address */ -#define EDITCMD 0x8000 /* allow "+command" argument */ -#define BUFNAME 0x10000 /* accepts buffer name */ -#define BUFUNL 0x20000 /* accepts unlisted buffer too */ -#define ARGOPT 0x40000 /* allow "++opt=val" argument */ -#define SBOXOK 0x80000 /* allowed in the sandbox */ -#define CMDWIN 0x100000 /* allowed in cmdline window; when missing - * disallows editing another buffer when - * curbuf_lock is set */ -#define MODIFY 0x200000 /* forbidden in non-'modifiable' buffer */ -#define EXFLAGS 0x400000 /* allow flags after count in argument */ -#define FILES (XFILE | EXTRA) /* multiple extra files allowed */ -#define WORD1 (EXTRA | NOSPC) /* one extra word allowed */ -#define FILE1 (FILES | NOSPC) /* 1 file allowed, defaults to current file */ +#define RANGE 0x001 // allow a linespecs +#define BANG 0x002 // allow a ! after the command name +#define EXTRA 0x004 // allow extra args after command name +#define XFILE 0x008 // expand wildcards in extra part +#define NOSPC 0x010 // no spaces allowed in the extra part +#define DFLALL 0x020 // default file range is 1,$ +#define WHOLEFOLD 0x040 // extend range to include whole fold also + // when less than two numbers given +#define NEEDARG 0x080 // argument required +#define TRLBAR 0x100 // check for trailing vertical bar +#define REGSTR 0x200 // allow "x for register designation +#define COUNT 0x400 // allow count in argument, after command +#define NOTRLCOM 0x800 // no trailing comment allowed +#define ZEROR 0x1000 // zero line number allowed +#define USECTRLV 0x2000 // do not remove CTRL-V from argument +#define NOTADR 0x4000 // number before command is not an address +#define EDITCMD 0x8000 // allow "+command" argument +#define BUFNAME 0x10000 // accepts buffer name +#define BUFUNL 0x20000 // accepts unlisted buffer too +#define ARGOPT 0x40000 // allow "++opt=val" argument +#define SBOXOK 0x80000 // allowed in the sandbox +#define CMDWIN 0x100000 // allowed in cmdline window; when missing + // disallows editing another buffer when + // curbuf_lock is set +#define MODIFY 0x200000 // forbidden in non-'modifiable' buffer +#define EXFLAGS 0x400000 // allow flags after count in argument +#define RESTRICT 0x800000L // forbidden in restricted mode +#define FILES (XFILE | EXTRA) // multiple extra files allowed +#define WORD1 (EXTRA | NOSPC) // one extra word allowed +#define FILE1 (FILES | NOSPC) // 1 file allowed, defaults to current file // values for cmd_addr_type #define ADDR_LINES 0 @@ -160,7 +161,7 @@ struct exarg { int regname; ///< register name (NUL if none) int force_bin; ///< 0, FORCE_BIN or FORCE_NOBIN int read_edit; ///< ++edit argument - int force_ff; ///< ++ff= argument (index in cmd[]) + int force_ff; ///< ++ff= argument (first char of argument) int force_enc; ///< ++enc= argument (index in cmd[]) int bad_char; ///< BAD_KEEP, BAD_DROP or replacement byte int useridx; ///< user command index diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index fa01e06471..362163aaf0 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -198,7 +198,7 @@ static void save_dbg_stuff(struct dbg_stuff *dsp) static void restore_dbg_stuff(struct dbg_stuff *dsp) { - suppress_errthrow = FALSE; + suppress_errthrow = false; trylevel = dsp->trylevel; force_abort = dsp->force_abort; caught_stack = dsp->caught_stack; @@ -395,8 +395,8 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, * Initialize "force_abort" and "suppress_errthrow" at the top level. */ if (!recursive) { - force_abort = FALSE; - suppress_errthrow = FALSE; + force_abort = false; + suppress_errthrow = false; } // If requested, store and reset the global values controlling the @@ -880,16 +880,14 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, xfree(sourcing_name); sourcing_name = saved_sourcing_name; sourcing_lnum = saved_sourcing_lnum; + } else if (got_int || (did_emsg && force_abort)) { + // On an interrupt or an aborting error not converted to an exception, + // disable the conversion of errors to exceptions. (Interrupts are not + // converted any more, here.) This enables also the interrupt message + // when force_abort is set and did_emsg unset in case of an interrupt + // from a finally clause after an error. + suppress_errthrow = true; } - /* - * On an interrupt or an aborting error not converted to an exception, - * disable the conversion of errors to exceptions. (Interrupts are not - * converted any more, here.) This enables also the interrupt message - * when force_abort is set and did_emsg unset in case of an interrupt - * from a finally clause after an error. - */ - else if (got_int || (did_emsg && force_abort)) - suppress_errthrow = TRUE; } // The current cstack will be freed when do_cmdline() returns. An uncaught @@ -1784,10 +1782,14 @@ static char_u * do_one_cmd(char_u **cmdlinep, if (!ea.skip) { if (sandbox != 0 && !(ea.argt & SBOXOK)) { - /* Command not allowed in sandbox. */ + // Command not allowed in sandbox. errormsg = (char_u *)_(e_sandbox); goto doend; } + if (restricted != 0 && (ea.argt & RESTRICT)) { + errormsg = (char_u *)_("E981: Command not allowed in restricted mode"); + goto doend; + } if (!MODIFIABLE(curbuf) && (ea.argt & MODIFY) // allow :put in terminals && (!curbuf->terminal || ea.cmdidx != CMD_put)) { @@ -4374,7 +4376,7 @@ int expand_filename(exarg_T *eap, char_u **cmdlinep, char_u **errormsgp) if (has_wildcards) { expand_T xpc; - int options = WILD_LIST_NOTFOUND|WILD_ADD_SLASH; + int options = WILD_LIST_NOTFOUND | WILD_NOERROR | WILD_ADD_SLASH; ExpandInit(&xpc); xpc.xp_context = EXPAND_FILES; @@ -4539,6 +4541,21 @@ skip_cmd_arg ( return p; } +int get_bad_opt(const char_u *p, exarg_T *eap) + FUNC_ATTR_NONNULL_ALL +{ + if (STRICMP(p, "keep") == 0) { + eap->bad_char = BAD_KEEP; + } else if (STRICMP(p, "drop") == 0) { + eap->bad_char = BAD_DROP; + } else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) { + eap->bad_char = *p; + } else { + return FAIL; + } + return OK; +} + /* * Get "++opt=arg" argument. * Return FAIL or OK. @@ -4597,8 +4614,10 @@ static int getargopt(exarg_T *eap) *arg = NUL; if (pp == &eap->force_ff) { - if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) + if (check_ff_value(eap->cmd + eap->force_ff) == FAIL) { return FAIL; + } + eap->force_ff = eap->cmd[eap->force_ff]; } else if (pp == &eap->force_enc) { /* Make 'fileencoding' lower case. */ for (p = eap->cmd + eap->force_enc; *p != NUL; ++p) @@ -4606,15 +4625,9 @@ static int getargopt(exarg_T *eap) } else { /* Check ++bad= argument. Must be a single-byte character, "keep" or * "drop". */ - p = eap->cmd + bad_char_idx; - if (STRICMP(p, "keep") == 0) - eap->bad_char = BAD_KEEP; - else if (STRICMP(p, "drop") == 0) - eap->bad_char = BAD_DROP; - else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) - eap->bad_char = *p; - else + if (get_bad_opt(eap->cmd + bad_char_idx, eap) == FAIL) { return FAIL; + } } return OK; @@ -5131,9 +5144,8 @@ static char *get_command_complete(int arg) static void uc_list(char_u *name, size_t name_len) { int i, j; - int found = FALSE; + bool found = false; ucmd_T *cmd; - int len; uint32_t a; // In cmdwin, the alternative buffer should be used. @@ -5152,62 +5164,96 @@ static void uc_list(char_u *name, size_t name_len) continue; } - /* Put out the title first time */ - if (!found) - MSG_PUTS_TITLE(_("\n Name Args Address Complete Definition")); - found = TRUE; + // Put out the title first time + if (!found) { + MSG_PUTS_TITLE(_("\n Name Args Address " + "Complete Definition")); + } + found = true; msg_putchar('\n'); if (got_int) break; - /* Special cases */ - msg_putchar(a & BANG ? '!' : ' '); - msg_putchar(a & REGSTR ? '"' : ' '); - msg_putchar(gap != &ucmds ? 'b' : ' '); - msg_putchar(' '); + // Special cases + int len = 4; + if (a & BANG) { + msg_putchar('!'); + len--; + } + if (a & REGSTR) { + msg_putchar('"'); + len--; + } + if (gap != &ucmds) { + msg_putchar('b'); + len--; + } + if (a & TRLBAR) { + msg_putchar('|'); + len--; + } + while (len-- > 0) { + msg_putchar(' '); + } msg_outtrans_attr(cmd->uc_name, HL_ATTR(HLF_D)); len = (int)STRLEN(cmd->uc_name) + 4; do { msg_putchar(' '); - ++len; - } while (len < 16); + len++; + } while (len < 22); + // "over" is how much longer the name is than the column width for + // the name, we'll try to align what comes after. + const int over = len - 22; len = 0; - /* Arguments */ + // Arguments switch (a & (EXTRA|NOSPC|NEEDARG)) { - case 0: IObuff[len++] = '0'; break; - case (EXTRA): IObuff[len++] = '*'; break; - case (EXTRA|NOSPC): IObuff[len++] = '?'; break; - case (EXTRA|NEEDARG): IObuff[len++] = '+'; break; - case (EXTRA|NOSPC|NEEDARG): IObuff[len++] = '1'; break; + case 0: + IObuff[len++] = '0'; + break; + case (EXTRA): + IObuff[len++] = '*'; + break; + case (EXTRA|NOSPC): + IObuff[len++] = '?'; + break; + case (EXTRA|NEEDARG): + IObuff[len++] = '+'; + break; + case (EXTRA|NOSPC|NEEDARG): + IObuff[len++] = '1'; + break; } do { IObuff[len++] = ' '; - } while (len < 5); + } while (len < 5 - over); - /* Range */ + // Address / Range if (a & (RANGE|COUNT)) { if (a & COUNT) { - /* -count=N */ - sprintf((char *)IObuff + len, "%" PRId64 "c", (int64_t)cmd->uc_def); + // -count=N + snprintf((char *)IObuff + len, IOSIZE, "%" PRId64 "c", + (int64_t)cmd->uc_def); len += (int)STRLEN(IObuff + len); - } else if (a & DFLALL) + } else if (a & DFLALL) { IObuff[len++] = '%'; - else if (cmd->uc_def >= 0) { - /* -range=N */ - sprintf((char *)IObuff + len, "%" PRId64 "", (int64_t)cmd->uc_def); + } else if (cmd->uc_def >= 0) { + // -range=N + snprintf((char *)IObuff + len, IOSIZE, "%" PRId64 "", + (int64_t)cmd->uc_def); len += (int)STRLEN(IObuff + len); - } else + } else { IObuff[len++] = '.'; + } } do { IObuff[len++] = ' '; - } while (len < 11); + } while (len < 9 - over); // Address Type for (j = 0; addr_type_complete[j].expand != -1; j++) { @@ -5221,7 +5267,7 @@ static void uc_list(char_u *name, size_t name_len) do { IObuff[len++] = ' '; - } while (len < 21); + } while (len < 13 - over); // Completion char *cmd_compl = get_command_complete(cmd->uc_compl); @@ -5232,12 +5278,13 @@ static void uc_list(char_u *name, size_t name_len) do { IObuff[len++] = ' '; - } while (len < 35); + } while (len < 24 - over); IObuff[len] = '\0'; msg_outtrans(IObuff); - msg_outtrans_special(cmd->uc_rep, false); + msg_outtrans_special(cmd->uc_rep, false, + name_len == 0 ? Columns - 46 : 0); if (p_verbose > 0) { last_set_msg(cmd->uc_script_ctx); } @@ -5425,9 +5472,8 @@ static void ex_command(exarg_T *eap) end = p; name_len = (int)(end - name); - /* If there is nothing after the name, and no attributes were specified, - * we are listing commands - */ + // If there is nothing after the name, and no attributes were specified, + // we are listing commands p = skipwhite(end); if (!has_attr && ends_excmd(*p)) { uc_list(name, end - name); @@ -7320,7 +7366,7 @@ static void ex_syncbind(exarg_T *eap) topline = curwin->w_topline; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_p_scb && wp->w_buffer) { - y = wp->w_buffer->b_ml.ml_line_count - p_so; + y = wp->w_buffer->b_ml.ml_line_count - get_scrolloff_value(); if (topline > y) { topline = y; } @@ -9246,8 +9292,9 @@ static void ex_match(exarg_T *eap) static void ex_fold(exarg_T *eap) { - if (foldManualAllowed(TRUE)) - foldCreate(eap->line1, eap->line2); + if (foldManualAllowed(true)) { + foldCreate(curwin, eap->line1, eap->line2); + } } static void ex_foldopen(exarg_T *eap) diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 3f1270692e..81274fcf2a 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -508,7 +508,7 @@ static int throw_exception(void *value, except_type_T type, char_u *cmdname) nomem: xfree(excp); - suppress_errthrow = TRUE; + suppress_errthrow = true; EMSG(_(e_outofmem)); fail: current_exception = NULL; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index e02443e061..581be96364 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -622,6 +622,16 @@ static int command_line_execute(VimState *state, int key) s->c = Ctrl_N; } } + if (compl_match_array || s->did_wild_list) { + if (s->c == Ctrl_E) { + s->res = nextwild(&s->xpc, WILD_CANCEL, WILD_NO_BEEP, + s->firstc != '@'); + } else if (s->c == Ctrl_Y) { + s->res = nextwild(&s->xpc, WILD_APPLY, WILD_NO_BEEP, + s->firstc != '@'); + s->c = Ctrl_E; + } + } // Hitting CR after "emenu Name.": complete submenu if (s->xpc.xp_context == EXPAND_MENUNAMES && p_wmnu @@ -2438,9 +2448,10 @@ redraw: /* make following messages go to the next line */ msg_didout = FALSE; msg_col = 0; - if (msg_row < Rows - 1) - ++msg_row; - emsg_on_display = FALSE; /* don't want os_delay() */ + if (msg_row < Rows - 1) { + msg_row++; + } + emsg_on_display = false; // don't want os_delay() if (got_int) ga_clear(&line_ga); @@ -2702,7 +2713,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline) goto color_cmdline_error; } if (tv.v_type != VAR_LIST) { - PRINT_ERRMSG(_("E5400: Callback should return list")); + PRINT_ERRMSG("%s", _("E5400: Callback should return list")); goto color_cmdline_error; } if (tv.vval.v_list == NULL) { @@ -3791,6 +3802,12 @@ ExpandOne ( return NULL; } + if (mode == WILD_CANCEL) { + ss = vim_strsave(orig_save); + } else if (mode == WILD_APPLY) { + ss = vim_strsave(findex == -1 ? orig_save : xp->xp_files[findex]); + } + /* free old names */ if (xp->xp_numfiles != -1 && mode != WILD_ALL && mode != WILD_LONGEST) { FreeWild(xp->xp_numfiles, xp->xp_files); @@ -3802,7 +3819,7 @@ ExpandOne ( if (mode == WILD_FREE) /* only release file name */ return NULL; - if (xp->xp_numfiles == -1) { + if (xp->xp_numfiles == -1 && mode != WILD_APPLY && mode != WILD_CANCEL) { xfree(orig_save); orig_save = orig; orig_saved = TRUE; @@ -4694,6 +4711,9 @@ ExpandFromContext ( flags |= EW_KEEPALL; if (options & WILD_SILENT) flags |= EW_SILENT; + if (options & WILD_NOERROR) { + flags |= EW_NOERROR; + } if (options & WILD_ALLLINKS) { flags |= EW_ALLLINKS; } diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h index 99d5a7786d..84b2b41f30 100644 --- a/src/nvim/ex_getln.h +++ b/src/nvim/ex_getln.h @@ -16,6 +16,8 @@ #define WILD_ALL 6 #define WILD_LONGEST 7 #define WILD_ALL_KEEP 8 +#define WILD_CANCEL 9 +#define WILD_APPLY 10 #define WILD_LIST_NOTFOUND 0x01 #define WILD_HOME_REPLACE 0x02 diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index b8f2927480..1b797c6168 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -799,7 +799,7 @@ static int makeopens(FILE *fd, char_u *dirnow) // if (fprintf(fd, "%s", "let s:sx = expand(\"<sfile>:p:r\").\"x.vim\"\n" - "if file_readable(s:sx)\n" + "if filereadable(s:sx)\n" " exe \"source \" . fnameescape(s:sx)\n" "endif\n") < 0) { return FAIL; diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index d00943c1be..1457a1172d 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -86,7 +86,7 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id, extmark_del(buf, ns_id, id); } else { // TODO(bfredl): we need to do more if "revising" a decoration mark. - MarkTreeIter itr[1]; + MarkTreeIter itr[1] = { 0 }; old_pos = marktree_lookup(buf->b_marktree, old_mark, itr); assert(itr->node); if (old_pos.row == row && old_pos.col == col) { @@ -119,7 +119,7 @@ revised: static bool extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col) { - MarkTreeIter itr[1]; + MarkTreeIter itr[1] = { 0 }; mtpos_t pos = marktree_lookup(buf->b_marktree, mark, itr); if (pos.row == -1) { return false; @@ -147,7 +147,7 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id) return false; } - MarkTreeIter itr[1]; + MarkTreeIter itr[1] = { 0 }; mtpos_t pos = marktree_lookup(buf->b_marktree, mark, itr); assert(pos.row >= 0); marktree_del_itr(buf->b_marktree, itr, false); @@ -207,7 +207,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id, delete_set = map_new(uint64_t, uint64_t)(); } - MarkTreeIter itr[1]; + MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, l_row, l_col, itr); while (true) { mtmark_t mark = marktree_itr_current(itr); @@ -276,7 +276,7 @@ ExtmarkArray extmark_get(buf_T *buf, uint64_t ns_id, int64_t amount, bool reverse) { ExtmarkArray array = KV_INITIAL_VALUE; - MarkTreeIter itr[1]; + MarkTreeIter itr[1] = { 0 }; // Find all the marks marktree_itr_get_ext(buf->b_marktree, (mtpos_t){ l_row, l_col }, itr, reverse, false, NULL); @@ -396,7 +396,7 @@ void u_extmark_copy(buf_T *buf, ExtmarkUndoObject undo; - MarkTreeIter itr[1]; + MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, l_row, l_col, itr); while (true) { mtmark_t mark = marktree_itr_current(itr); @@ -578,6 +578,15 @@ void extmark_splice(buf_T *buf, } } +void extmark_splice_cols(buf_T *buf, + int start_row, colnr_T start_col, + colnr_T old_col, colnr_T new_col, + ExtmarkOp undo) +{ + extmark_splice(buf, start_row, start_col, + 0, old_col, + 0, new_col, undo); +} void extmark_move_region(buf_T *buf, int start_row, colnr_T start_col, @@ -738,7 +747,7 @@ void clear_virttext(VirtText *text) VirtText *extmark_find_virttext(buf_T *buf, int row, uint64_t ns_id) { - MarkTreeIter itr[1]; + MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, row, 0, itr); while (true) { mtmark_t mark = marktree_itr_current(itr); @@ -789,7 +798,7 @@ bool decorations_redraw_start(buf_T *buf, int top_row, ExtmarkItem *item = map_ref(uint64_t, ExtmarkItem)(buf->b_extmark_index, start_id, false); if ((!(mark.id&MARKTREE_END_FLAG) && altpos.row < top_row - && !kv_size(item->virt_text)) + && item && !kv_size(item->virt_text)) || ((mark.id&MARKTREE_END_FLAG) && altpos.row >= top_row)) { goto next_mark; } @@ -854,7 +863,7 @@ int decorations_redraw_col(buf_T *buf, int col, DecorationRedrawState *state) if (endpos.row < mark.row || (endpos.row == mark.row && endpos.col <= mark.col)) { - if (!kv_size(item->virt_text)) { + if (item && !kv_size(item->virt_text)) { goto next_mark; } } diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 2443fa000d..2335aba6dd 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -62,6 +62,11 @@ #define BUFSIZE 8192 /* size of normal write buffer */ #define SMBUFSIZE 256 /* size of emergency write buffer */ +// For compatibility with libuv < 1.20.0 (tested on 1.18.0) +#ifndef UV_FS_COPYFILE_FICLONE +#define UV_FS_COPYFILE_FICLONE 0 +#endif + // // The autocommands are stored in a list for each event. // Autocommands for the same pattern, that are consecutive, are joined @@ -407,11 +412,27 @@ readfile( if (newfile) { if (apply_autocmds_exarg(EVENT_BUFREADCMD, NULL, sfname, - FALSE, curbuf, eap)) - return aborting() ? FAIL : OK; + false, curbuf, eap)) { + int status = OK; + + if (aborting()) { + status = FAIL; + } + + // The BufReadCmd code usually uses ":read" to get the text and + // perhaps ":file" to change the buffer name. But we should + // consider this to work like ":edit", thus reset the + // BF_NOTEDITED flag. Then ":write" will work to overwrite the + // same file. + if (status == OK) { + curbuf->b_flags &= ~BF_NOTEDITED; + } + return status; + } } else if (apply_autocmds_exarg(EVENT_FILEREADCMD, sfname, sfname, - FALSE, NULL, eap)) + false, NULL, eap)) { return aborting() ? FAIL : OK; + } curbuf->b_op_start = pos; } @@ -2032,14 +2053,16 @@ readfile_linenr( * Fill "*eap" to force the 'fileencoding', 'fileformat' and 'binary to be * equal to the buffer "buf". Used for calling readfile(). */ -void prep_exarg(exarg_T *eap, buf_T *buf) +void prep_exarg(exarg_T *eap, const buf_T *buf) + FUNC_ATTR_NONNULL_ALL { - eap->cmd = xmalloc(STRLEN(buf->b_p_ff) + STRLEN(buf->b_p_fenc) + 15); + const size_t cmd_len = 15 + STRLEN(buf->b_p_fenc); + eap->cmd = xmalloc(cmd_len); - sprintf((char *)eap->cmd, "e ++ff=%s ++enc=%s", buf->b_p_ff, buf->b_p_fenc); - eap->force_enc = 14 + (int)STRLEN(buf->b_p_ff); + snprintf((char *)eap->cmd, cmd_len, "e ++enc=%s", buf->b_p_fenc); + eap->force_enc = 8; eap->bad_char = buf->b_bad_char; - eap->force_ff = 7; + eap->force_ff = *buf->b_p_ff; eap->force_bin = buf->b_p_bin ? FORCE_BIN : FORCE_NOBIN; eap->read_edit = FALSE; diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 331d7f9e29..61a85171e8 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -539,12 +539,10 @@ int foldManualAllowed(int create) return FALSE; } -/* foldCreate() {{{2 */ -/* - * Create a fold from line "start" to line "end" (inclusive) in the current - * window. - */ -void foldCreate(linenr_T start, linenr_T end) +// foldCreate() {{{2 +/// Create a fold from line "start" to line "end" (inclusive) in the current +/// window. +void foldCreate(win_T *wp, linenr_T start, linenr_T end) { fold_T *fp; garray_T *gap; @@ -565,16 +563,16 @@ void foldCreate(linenr_T start, linenr_T end) end_rel = end; } - /* When 'foldmethod' is "marker" add markers, which creates the folds. */ - if (foldmethodIsMarker(curwin)) { - foldCreateMarkers(start, end); + // When 'foldmethod' is "marker" add markers, which creates the folds. + if (foldmethodIsMarker(wp)) { + foldCreateMarkers(wp, start, end); return; } - checkupdate(curwin); + checkupdate(wp); - /* Find the place to insert the new fold. */ - gap = &curwin->w_folds; + // Find the place to insert the new fold + gap = &wp->w_folds; for (;; ) { if (!foldFind(gap, start_rel, &fp)) break; @@ -584,12 +582,14 @@ void foldCreate(linenr_T start, linenr_T end) start_rel -= fp->fd_top; end_rel -= fp->fd_top; if (use_level || fp->fd_flags == FD_LEVEL) { - use_level = TRUE; - if (level >= curwin->w_p_fdl) - closed = TRUE; - } else if (fp->fd_flags == FD_CLOSED) - closed = TRUE; - ++level; + use_level = true; + if (level >= wp->w_p_fdl) { + closed = true; + } + } else if (fp->fd_flags == FD_CLOSED) { + closed = true; + } + level++; } else { /* This fold and new fold overlap: Insert here and move some folds * inside the new fold. */ @@ -642,26 +642,28 @@ void foldCreate(linenr_T start, linenr_T end) /* We want the new fold to be closed. If it would remain open because * of using 'foldlevel', need to adjust fd_flags of containing folds. */ - if (use_level && !closed && level < curwin->w_p_fdl) + if (use_level && !closed && level < wp->w_p_fdl) { closeFold(start, 1L); - if (!use_level) - curwin->w_fold_manual = true; + } + if (!use_level) { + wp->w_fold_manual = true; + } fp->fd_flags = FD_CLOSED; fp->fd_small = kNone; - /* redraw */ - changed_window_setting(); + // redraw + changed_window_setting_win(wp); } } -/* deleteFold() {{{2 */ -/* - * Delete a fold at line "start" in the current window. - * When "end" is not 0, delete all folds from "start" to "end". - * When "recursive" is TRUE delete recursively. - */ +// deleteFold() {{{2 +/// @param start delete all folds from start to end when not 0 +/// @param end delete all folds from start to end when not 0 +/// @param recursive delete recursively if true +/// @param had_visual true when Visual selection used void deleteFold( + win_T *const wp, const linenr_T start, const linenr_T end, const int recursive, @@ -678,11 +680,11 @@ void deleteFold( linenr_T first_lnum = MAXLNUM; linenr_T last_lnum = 0; - checkupdate(curwin); + checkupdate(wp); while (lnum <= end) { // Find the deepest fold for "start". - garray_T *gap = &curwin->w_folds; + garray_T *gap = &wp->w_folds; garray_T *found_ga = NULL; linenr_T lnum_off = 0; bool use_level = false; @@ -694,10 +696,11 @@ void deleteFold( found_fp = fp; found_off = lnum_off; - /* if "lnum" is folded, don't check nesting */ - if (check_closed(curwin, fp, &use_level, level, - &maybe_small, lnum_off)) + // if "lnum" is folded, don't check nesting + if (check_closed(wp, fp, &use_level, level, + &maybe_small, lnum_off)) { break; + } /* check nested folds */ gap = &fp->fd_nested; @@ -709,34 +712,41 @@ void deleteFold( } else { lnum = found_fp->fd_top + found_fp->fd_len + found_off; - if (foldmethodIsManual(curwin)) - deleteFoldEntry(found_ga, - (int)(found_fp - (fold_T *)found_ga->ga_data), recursive); - else { - if (first_lnum > found_fp->fd_top + found_off) + if (foldmethodIsManual(wp)) { + deleteFoldEntry(wp, found_ga, + (int)(found_fp - (fold_T *)found_ga->ga_data), + recursive); + } else { + if (first_lnum > found_fp->fd_top + found_off) { first_lnum = found_fp->fd_top + found_off; - if (last_lnum < lnum) + } + if (last_lnum < lnum) { last_lnum = lnum; - if (!did_one) - parseMarker(curwin); - deleteFoldMarkers(found_fp, recursive, found_off); + } + if (!did_one) { + parseMarker(wp); + } + deleteFoldMarkers(wp, found_fp, recursive, found_off); } did_one = true; - /* redraw window */ - changed_window_setting(); + // redraw window + changed_window_setting_win(wp); } } if (!did_one) { EMSG(_(e_nofold)); - /* Force a redraw to remove the Visual highlighting. */ - if (had_visual) - redraw_curbuf_later(INVERTED); - } else - /* Deleting markers may make cursor column invalid. */ - check_cursor_col(); + // Force a redraw to remove the Visual highlighting. + if (had_visual) { + redraw_buf_later(wp->w_buffer, INVERTED); + } + } else { + // Deleting markers may make cursor column invalid + check_cursor_col_win(wp); + } if (last_lnum > 0) { + // TODO(teto): pass the buffer changed_lines(first_lnum, (colnr_T)0, last_lnum, 0L, false); // send one nvim_buf_lines_event at the end @@ -745,7 +755,7 @@ void deleteFold( // the modification of the *first* line of the fold, but we send through a // notification that includes every line that was part of the fold int64_t num_changed = last_lnum - first_lnum; - buf_updates_send_changes(curbuf, first_lnum, num_changed, + buf_updates_send_changes(wp->w_buffer, first_lnum, num_changed, num_changed, true); } } @@ -1048,7 +1058,7 @@ void cloneFoldGrowArray(garray_T *from, garray_T *to) * the first fold below it (careful: it can be beyond the end of the array!). * Returns FALSE when there is no fold that contains "lnum". */ -static int foldFind(garray_T *gap, linenr_T lnum, fold_T **fpp) +static int foldFind(const garray_T *gap, linenr_T lnum, fold_T **fpp) { linenr_T low, high; fold_T *fp; @@ -1297,7 +1307,7 @@ static void foldOpenNested(fold_T *fpr) // Delete fold "idx" from growarray "gap". // When "recursive" is true also delete all the folds contained in it. // When "recursive" is false contained folds are moved one level up. -static void deleteFoldEntry(garray_T *const gap, const int idx, +static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx, const bool recursive) { fold_T *fp = (fold_T *)gap->ga_data + idx; @@ -1363,13 +1373,17 @@ void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long line2 = line1 - amount_after - 1; /* If appending a line in Insert mode, it should be included in the fold * just above the line. */ - if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM) - --line1; - foldMarkAdjustRecurse(&wp->w_folds, line1, line2, amount, amount_after); + if ((State & INSERT) && amount == (linenr_T)1 && line2 == MAXLNUM) { + line1--; + } + foldMarkAdjustRecurse(wp, &wp->w_folds, line1, line2, amount, amount_after); } -/* foldMarkAdjustRecurse() {{{2 */ -static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2, long amount, long amount_after) +// foldMarkAdjustRecurse() {{{2 +static void foldMarkAdjustRecurse( + win_T *wp, garray_T *gap, + linenr_T line1, linenr_T line2, long amount, long amount_after +) { fold_T *fp; linenr_T last; @@ -1417,7 +1431,7 @@ static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2, // 4. fold completely contained in range if (amount == MAXLNUM) { // Deleting lines: delete the fold completely - deleteFoldEntry(gap, i, true); + deleteFoldEntry(wp, gap, i, true); i--; // adjust index for deletion fp--; } else { @@ -1425,9 +1439,9 @@ static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2, } } else { if (fp->fd_top < top) { - /* 2 or 3: need to correct nested folds too */ - foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top, - line2 - fp->fd_top, amount, amount_after); + // 2 or 3: need to correct nested folds too + foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top, + line2 - fp->fd_top, amount, amount_after); if (last <= line2) { /* 2. fold contains line1, line2 is below fold */ if (amount == MAXLNUM) @@ -1442,13 +1456,13 @@ static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2, /* 5. fold is below line1 and contains line2; need to * correct nested folds too */ if (amount == MAXLNUM) { - foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top, + foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top, line2 - fp->fd_top, amount, amount_after + (fp->fd_top - top)); fp->fd_len -= line2 - fp->fd_top + 1; fp->fd_top = line1; } else { - foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top, + foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top, line2 - fp->fd_top, amount, amount_after - amount); fp->fd_len += amount_after - amount; @@ -1465,10 +1479,10 @@ static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2, * Get the lowest 'foldlevel' value that makes the deepest nested fold in the * current window open. */ -int getDeepestNesting(void) +int getDeepestNesting(win_T *wp) { - checkupdate(curwin); - return getDeepestNestingRecurse(&curwin->w_folds); + checkupdate(wp); + return getDeepestNestingRecurse(&wp->w_folds); } static int getDeepestNestingRecurse(garray_T *gap) @@ -1487,17 +1501,22 @@ static int getDeepestNestingRecurse(garray_T *gap) return maxlevel; } -/* check_closed() {{{2 */ -/* - * Check if a fold is closed and update the info needed to check nested folds. - */ +// check_closed() {{{2 +/// Check if a fold is closed and update the info needed to check nested folds. +/// +/// @param[in,out] use_levelp true: outer fold had FD_LEVEL +/// @param[in,out] fp fold to check +/// @param level folding depth +/// @param[out] maybe_smallp true: outer this had fd_small == kNone +/// @param lnum_off line number offset for fp->fd_top +/// @return true if fold is closed static bool check_closed( - win_T *const win, + win_T *const wp, fold_T *const fp, - bool *const use_levelp, // true: outer fold had FD_LEVEL - const int level, // folding depth - bool *const maybe_smallp, // true: outer this had fd_small == kNone - const linenr_T lnum_off // line number offset for fp->fd_top + bool *const use_levelp, + const int level, + bool *const maybe_smallp, + const linenr_T lnum_off ) { bool closed = false; @@ -1506,7 +1525,7 @@ static bool check_closed( * fold and all folds it contains depend on 'foldlevel'. */ if (*use_levelp || fp->fd_flags == FD_LEVEL) { *use_levelp = true; - if (level >= win->w_p_fdl) { + if (level >= wp->w_p_fdl) { closed = true; } } else if (fp->fd_flags == FD_CLOSED) { @@ -1521,7 +1540,7 @@ static bool check_closed( if (*maybe_smallp) { fp->fd_small = kNone; } - checkSmall(win, fp, lnum_off); + checkSmall(wp, fp, lnum_off); if (fp->fd_small == kTrue) { closed = false; } @@ -1529,10 +1548,9 @@ static bool check_closed( return closed; } -/* checkSmall() {{{2 */ -/* - * Update fd_small field of fold "fp". - */ +// checkSmall() {{{2 +/// Update fd_small field of fold "fp". +/// @param lnum_off offset for fp->fd_top static void checkSmall( win_T *const wp, @@ -1544,13 +1562,13 @@ checkSmall( // Mark any nested folds to maybe-small setSmallMaybe(&fp->fd_nested); - if (fp->fd_len > curwin->w_p_fml) { + if (fp->fd_len > wp->w_p_fml) { fp->fd_small = kFalse; } else { int count = 0; for (int n = 0; n < fp->fd_len; n++) { count += plines_win_nofold(wp, fp->fd_top + lnum_off + n); - if (count > curwin->w_p_fml) { + if (count > wp->w_p_fml) { fp->fd_small = kFalse; return; } @@ -1575,42 +1593,45 @@ static void setSmallMaybe(garray_T *gap) * Create a fold from line "start" to line "end" (inclusive) in the current * window by adding markers. */ -static void foldCreateMarkers(linenr_T start, linenr_T end) +static void foldCreateMarkers(win_T *wp, linenr_T start, linenr_T end) { - if (!MODIFIABLE(curbuf)) { + buf_T *buf = wp->w_buffer; + if (!MODIFIABLE(buf)) { EMSG(_(e_modifiable)); return; } - parseMarker(curwin); + parseMarker(wp); - foldAddMarker(start, curwin->w_p_fmr, foldstartmarkerlen); - foldAddMarker(end, foldendmarker, foldendmarkerlen); + foldAddMarker(buf, start, wp->w_p_fmr, foldstartmarkerlen); + foldAddMarker(buf, end, foldendmarker, foldendmarkerlen); /* Update both changes here, to avoid all folds after the start are * changed when the start marker is inserted and the end isn't. */ + // TODO(teto): pass the buffer changed_lines(start, (colnr_T)0, end, 0L, false); // Note: foldAddMarker() may not actually change start and/or end if // u_save() is unable to save the buffer line, but we send the // nvim_buf_lines_event anyway since it won't do any harm. int64_t num_changed = 1 + end - start; - buf_updates_send_changes(curbuf, start, num_changed, num_changed, true); + buf_updates_send_changes(buf, start, num_changed, num_changed, true); } /* foldAddMarker() {{{2 */ /* * Add "marker[markerlen]" in 'commentstring' to line "lnum". */ -static void foldAddMarker(linenr_T lnum, const char_u *marker, size_t markerlen) +static void foldAddMarker( + buf_T *buf, linenr_T lnum, const char_u *marker, size_t markerlen) { - char_u *cms = curbuf->b_p_cms; + char_u *cms = buf->b_p_cms; char_u *line; char_u *newline; - char_u *p = (char_u *)strstr((char *)curbuf->b_p_cms, "%s"); + char_u *p = (char_u *)strstr((char *)buf->b_p_cms, "%s"); bool line_is_comment = false; // Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end - line = ml_get(lnum); + line = ml_get_buf(buf, lnum, false); size_t line_len = STRLEN(line); size_t added = 0; @@ -1629,11 +1650,10 @@ static void foldAddMarker(linenr_T lnum, const char_u *marker, size_t markerlen) STRCPY(newline + line_len + (p - cms) + markerlen, p + 2); added = markerlen + STRLEN(cms)-2; } - ml_replace(lnum, newline, false); + ml_replace_buf(buf, lnum, newline, false); if (added) { - extmark_splice(curbuf, (int)lnum-1, (int)line_len, - 0, 0, - 0, (int)added, kExtmarkUndo); + extmark_splice_cols(buf, (int)lnum-1, (int)line_len, + 0, (int)added, kExtmarkUndo); } } } @@ -1644,20 +1664,22 @@ static void foldAddMarker(linenr_T lnum, const char_u *marker, size_t markerlen) */ static void deleteFoldMarkers( + win_T *wp, fold_T *fp, int recursive, linenr_T lnum_off // offset for fp->fd_top ) { if (recursive) { - for (int i = 0; i < fp->fd_nested.ga_len; ++i) { - deleteFoldMarkers((fold_T *)fp->fd_nested.ga_data + i, TRUE, + for (int i = 0; i < fp->fd_nested.ga_len; i++) { + deleteFoldMarkers(wp, (fold_T *)fp->fd_nested.ga_data + i, true, lnum_off + fp->fd_top); } } - foldDelMarker(fp->fd_top + lnum_off, curwin->w_p_fmr, foldstartmarkerlen); - foldDelMarker(fp->fd_top + lnum_off + fp->fd_len - 1, foldendmarker, - foldendmarkerlen); + foldDelMarker(wp->w_buffer, fp->fd_top+lnum_off, wp->w_p_fmr, + foldstartmarkerlen); + foldDelMarker(wp->w_buffer, fp->fd_top + lnum_off + fp->fd_len - 1, + foldendmarker, foldendmarkerlen); } // foldDelMarker() {{{2 @@ -1666,18 +1688,20 @@ deleteFoldMarkers( // Delete 'commentstring' if it matches. // If the marker is not found, there is no error message. Could be a missing // close-marker. -static void foldDelMarker(linenr_T lnum, char_u *marker, size_t markerlen) +static void foldDelMarker( + buf_T *buf, linenr_T lnum, char_u *marker, size_t markerlen +) { char_u *newline; - char_u *cms = curbuf->b_p_cms; + char_u *cms = buf->b_p_cms; char_u *cms2; // end marker may be missing and fold extends below the last line - if (lnum > curbuf->b_ml.ml_line_count) { + if (lnum > buf->b_ml.ml_line_count) { return; } - char_u *line = ml_get(lnum); - for (char_u *p = line; *p != NUL; ++p) { + char_u *line = ml_get_buf(buf, lnum, false); + for (char_u *p = line; *p != NUL; p++) { if (STRNCMP(p, marker, markerlen) != 0) { continue; } @@ -1701,10 +1725,10 @@ static void foldDelMarker(linenr_T lnum, char_u *marker, size_t markerlen) assert(p >= line); memcpy(newline, line, (size_t)(p - line)); STRCPY(newline + (p - line), p + len); - ml_replace(lnum, newline, false); - extmark_splice(curbuf, (int)lnum-1, (int)(p - line), - 0, (int)len, - 0, 0, kExtmarkUndo); + ml_replace_buf(buf, lnum, newline, false); + extmark_splice_cols(buf, (int)lnum-1, (int)(p - line), + (int)len, + 0, kExtmarkUndo); } break; } @@ -1892,12 +1916,12 @@ void foldtext_cleanup(char_u *str) /* foldUpdateIEMS() {{{2 */ /* * Update the folding for window "wp", at least from lines "top" to "bot". - * Return TRUE if any folds did change. + * IEMS = "Indent Expr Marker Syntax" */ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) { fline_T fline; - void (*getlevel)(fline_T *); + LevelGetter getlevel = NULL; fold_T *fp; /* Avoid problems when being called recursively. */ @@ -2079,8 +2103,8 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) } } - /* There can't be any folds from start until end now. */ - foldRemove(&wp->w_folds, start, end); + // There can't be any folds from start until end now. + foldRemove(wp, &wp->w_folds, start, end); /* If some fold changed, need to redraw and position cursor. */ if (fold_changed && wp->w_p_fen) @@ -2260,12 +2284,12 @@ static linenr_T foldUpdateIEMSRecurse( if (fp->fd_top > firstlnum) { // We will move the start of this fold up, hence we move all // nested folds (with relative line numbers) down. - foldMarkAdjustRecurse(&fp->fd_nested, + foldMarkAdjustRecurse(flp->wp, &fp->fd_nested, (linenr_T)0, (linenr_T)MAXLNUM, (long)(fp->fd_top - firstlnum), 0L); } else { // Will move fold down, move nested folds relatively up. - foldMarkAdjustRecurse(&fp->fd_nested, + foldMarkAdjustRecurse(flp->wp, &fp->fd_nested, (linenr_T)0, (long)(firstlnum - fp->fd_top - 1), (linenr_T)MAXLNUM, @@ -2295,10 +2319,10 @@ static linenr_T foldUpdateIEMSRecurse( breakstart = flp->lnum; breakend = flp->lnum; } - foldRemove(&fp->fd_nested, breakstart - fp->fd_top, + foldRemove(flp->wp, &fp->fd_nested, breakstart - fp->fd_top, breakend - fp->fd_top); i = (int)(fp - (fold_T *)gap->ga_data); - foldSplit(gap, i, breakstart, breakend - 1); + foldSplit(flp->wp->w_buffer, gap, i, breakstart, breakend - 1); fp = (fold_T *)gap->ga_data + i + 1; /* If using the "marker" or "syntax" method, we * need to continue until the end of the fold is @@ -2314,7 +2338,7 @@ static linenr_T foldUpdateIEMSRecurse( if (i != 0) { fp2 = fp - 1; if (fp2->fd_top + fp2->fd_len == fp->fd_top) { - foldMerge(fp2, gap, fp); + foldMerge(flp->wp, fp2, gap, fp); fp = fp2; } } @@ -2325,12 +2349,13 @@ static linenr_T foldUpdateIEMSRecurse( // A fold that starts at or after startlnum and stops // before the new fold must be deleted. Continue // looking for the next one. - deleteFoldEntry(gap, (int)(fp - (fold_T *)gap->ga_data), true); + deleteFoldEntry(flp->wp, gap, + (int)(fp - (fold_T *)gap->ga_data), true); } else { /* A fold has some lines above startlnum, truncate it * to stop just above startlnum. */ fp->fd_len = startlnum - fp->fd_top; - foldMarkAdjustRecurse(&fp->fd_nested, + foldMarkAdjustRecurse(flp->wp, &fp->fd_nested, (linenr_T)fp->fd_len, (linenr_T)MAXLNUM, (linenr_T)MAXLNUM, 0L); fold_changed = true; @@ -2459,8 +2484,8 @@ static linenr_T foldUpdateIEMSRecurse( // Delete contained folds from the end of the last one found until where // we stopped looking. - foldRemove(&fp->fd_nested, startlnum2 - fp->fd_top, - flp->lnum - 1 - fp->fd_top); + foldRemove(flp->wp, &fp->fd_nested, startlnum2 - fp->fd_top, + flp->lnum - 1 - fp->fd_top); if (lvl < level) { // End of fold found, update the length when it got shorter. @@ -2478,7 +2503,7 @@ static linenr_T foldUpdateIEMSRecurse( // indent or expr method: split fold to create a new one // below bot i = (int)(fp - (fold_T *)gap->ga_data); - foldSplit(gap, i, flp->lnum, bot); + foldSplit(flp->wp->w_buffer, gap, i, flp->lnum, bot); fp = (fold_T *)gap->ga_data + i; } } else { @@ -2496,23 +2521,23 @@ static linenr_T foldUpdateIEMSRecurse( break; if (fp2->fd_top + fp2->fd_len > flp->lnum) { if (fp2->fd_top < flp->lnum) { - /* Make fold that includes lnum start at lnum. */ - foldMarkAdjustRecurse(&fp2->fd_nested, - (linenr_T)0, (long)(flp->lnum - fp2->fd_top - 1), - (linenr_T)MAXLNUM, (long)(fp2->fd_top - flp->lnum)); + // Make fold that includes lnum start at lnum. + foldMarkAdjustRecurse(flp->wp, &fp2->fd_nested, + (linenr_T)0, (long)(flp->lnum - fp2->fd_top - 1), + (linenr_T)MAXLNUM, (long)(fp2->fd_top-flp->lnum)); fp2->fd_len -= flp->lnum - fp2->fd_top; fp2->fd_top = flp->lnum; fold_changed = true; } if (lvl >= level) { - /* merge new fold with existing fold that follows */ - foldMerge(fp, gap, fp2); + // merge new fold with existing fold that follows + foldMerge(flp->wp, fp, gap, fp2); } break; } fold_changed = true; - deleteFoldEntry(gap, (int)(fp2 - (fold_T *)gap->ga_data), true); + deleteFoldEntry(flp->wp, gap, (int)(fp2 - (fold_T *)gap->ga_data), true); } /* Need to redraw the lines we inspected, which might be further down than @@ -2548,8 +2573,10 @@ static void foldInsert(garray_T *gap, int i) * The caller must first have taken care of any nested folds from "top" to * "bot"! */ -static void foldSplit(garray_T *const gap, const int i, const linenr_T top, - const linenr_T bot) +static void foldSplit(buf_T *buf, garray_T *const gap, + const int i, const linenr_T top, + const linenr_T bot + ) { fold_T *fp2; @@ -2604,7 +2631,9 @@ static void foldSplit(garray_T *const gap, const int i, const linenr_T top, * 5: made to start below "bot". * 6: not changed */ -static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot) +static void foldRemove( + win_T *const wp, garray_T *gap, linenr_T top, linenr_T bot +) { fold_T *fp = NULL; @@ -2616,10 +2645,11 @@ static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot) // Find fold that includes top or a following one. if (foldFind(gap, top, &fp) && fp->fd_top < top) { // 2: or 3: need to delete nested folds - foldRemove(&fp->fd_nested, top - fp->fd_top, bot - fp->fd_top); + foldRemove(wp, &fp->fd_nested, top - fp->fd_top, bot - fp->fd_top); if (fp->fd_top + fp->fd_len - 1 > bot) { // 3: need to split it. - foldSplit(gap, (int)(fp - (fold_T *)gap->ga_data), top, bot); + foldSplit(wp->w_buffer, gap, + (int)(fp - (fold_T *)gap->ga_data), top, bot); } else { // 2: truncate fold at "top". fp->fd_len = top - fp->fd_top; @@ -2637,7 +2667,8 @@ static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot) fold_changed = true; if (fp->fd_top + fp->fd_len - 1 > bot) { // 5: Make fold that includes bot start below bot. - foldMarkAdjustRecurse(&fp->fd_nested, + foldMarkAdjustRecurse( + wp, &fp->fd_nested, (linenr_T)0, (long)(bot - fp->fd_top), (linenr_T)MAXLNUM, (long)(fp->fd_top - bot - 1)); fp->fd_len -= bot - fp->fd_top + 1; @@ -2646,7 +2677,7 @@ static void foldRemove(garray_T *gap, linenr_T top, linenr_T bot) } // 4: Delete completely contained fold. - deleteFoldEntry(gap, (int)(fp - (fold_T *)gap->ga_data), true); + deleteFoldEntry(wp, gap, (int)(fp - (fold_T *)gap->ga_data), true); } } } @@ -2698,19 +2729,22 @@ static void foldReverseOrder( // 8. truncated below dest and shifted up. // 9. shifted up // 10. not changed -static void truncate_fold(fold_T *fp, linenr_T end) +static void truncate_fold(win_T *const wp, fold_T *fp, linenr_T end) { // I want to stop *at here*, foldRemove() stops *above* top end += 1; - foldRemove(&fp->fd_nested, end - fp->fd_top, MAXLNUM); + foldRemove(wp, &fp->fd_nested, end - fp->fd_top, MAXLNUM); fp->fd_len = end - fp->fd_top; } #define FOLD_END(fp) ((fp)->fd_top + (fp)->fd_len - 1) #define VALID_FOLD(fp, gap) ((fp) < ((fold_T *)(gap)->ga_data + (gap)->ga_len)) #define FOLD_INDEX(fp, gap) ((size_t)(fp - ((fold_T *)(gap)->ga_data))) -void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2, - const linenr_T dest) +void foldMoveRange( + win_T *const wp, garray_T *gap, + const linenr_T line1, const linenr_T line2, + const linenr_T dest +) { fold_T *fp; const linenr_T range_len = line2 - line1 + 1; @@ -2721,20 +2755,20 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2, if (FOLD_END(fp) > dest) { // Case 4 -- don't have to change this fold, but have to move nested // folds. - foldMoveRange(&fp->fd_nested, line1 - fp->fd_top, line2 - + foldMoveRange(wp, &fp->fd_nested, line1 - fp->fd_top, line2 - fp->fd_top, dest - fp->fd_top); return; } else if (FOLD_END(fp) > line2) { // Case 3 -- Remove nested folds between line1 and line2 & reduce the // length of fold by "range_len". // Folds after this one must be dealt with. - foldMarkAdjustRecurse(&fp->fd_nested, line1 - fp->fd_top, + foldMarkAdjustRecurse(wp, &fp->fd_nested, line1 - fp->fd_top, line2 - fp->fd_top, MAXLNUM, -range_len); fp->fd_len -= range_len; } else { // Case 2 -- truncate fold *above* line1. // Folds after this one must be dealt with. - truncate_fold(fp, line1 - 1); + truncate_fold(wp, fp, line1 - 1); } // Look at the next fold, and treat that one as if it were the first after // "line1" (because now it is). @@ -2752,13 +2786,13 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2, } if (VALID_FOLD(fp, gap) && fp->fd_top <= dest) { // Case 8. -- ensure truncated at dest, shift up - truncate_fold(fp, dest); + truncate_fold(wp, fp, dest); fp->fd_top -= range_len; } return; } else if (FOLD_END(fp) > dest) { // Case 7 -- remove nested folds and shrink - foldMarkAdjustRecurse(&fp->fd_nested, line2 + 1 - fp->fd_top, + foldMarkAdjustRecurse(wp, &fp->fd_nested, line2 + 1 - fp->fd_top, dest - fp->fd_top, MAXLNUM, -move_len); fp->fd_len -= move_len; fp->fd_top += move_len; @@ -2774,7 +2808,7 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2, // 5, or 6 if (FOLD_END(fp) > line2) { // 6, truncate before moving - truncate_fold(fp, line2); + truncate_fold(wp, fp, line2); } fp->fd_top += move_len; continue; @@ -2786,7 +2820,7 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2, } if (FOLD_END(fp) > dest) { - truncate_fold(fp, dest); + truncate_fold(wp, fp, dest); } fp->fd_top -= range_len; @@ -2818,7 +2852,7 @@ void foldMoveRange(garray_T *gap, const linenr_T line1, const linenr_T line2, * The resulting fold is "fp1", nested folds are moved from "fp2" to "fp1". * Fold entry "fp2" in "gap" is deleted. */ -static void foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2) +static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2) { fold_T *fp3; fold_T *fp4; @@ -2828,8 +2862,9 @@ static void foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2) /* If the last nested fold in fp1 touches the first nested fold in fp2, * merge them recursively. */ - if (foldFind(gap1, fp1->fd_len - 1L, &fp3) && foldFind(gap2, 0L, &fp4)) - foldMerge(fp3, gap2, fp4); + if (foldFind(gap1, fp1->fd_len - 1L, &fp3) && foldFind(gap2, 0L, &fp4)) { + foldMerge(wp, fp3, gap2, fp4); + } /* Move nested folds in fp2 to the end of fp1. */ if (!GA_EMPTY(gap2)) { @@ -2844,7 +2879,7 @@ static void foldMerge(fold_T *fp1, garray_T *gap, fold_T *fp2) } fp1->fd_len += fp2->fd_len; - deleteFoldEntry(gap, (int)(fp2 - (fold_T *)gap->ga_data), true); + deleteFoldEntry(wp, gap, (int)(fp2 - (fold_T *)gap->ga_data), true); fold_changed = true; } diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index d70d04cb4b..0debd39555 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -3361,7 +3361,7 @@ showmap ( msg_putchar(' '); // Display the LHS. Get length of what we write. - len = (size_t)msg_outtrans_special(mp->m_keys, true); + len = (size_t)msg_outtrans_special(mp->m_keys, true, 0); do { msg_putchar(' '); /* padd with blanks */ ++len; @@ -3389,7 +3389,7 @@ showmap ( // as typeahead. char_u *s = vim_strsave(mp->m_str); vim_unescape_csi(s); - msg_outtrans_special(s, FALSE); + msg_outtrans_special(s, false, 0); xfree(s); } if (p_verbose > 0) { diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h index 01f60ccf49..f0b52079aa 100644 --- a/src/nvim/getchar.h +++ b/src/nvim/getchar.h @@ -10,12 +10,12 @@ /// Values for "noremap" argument of ins_typebuf() /// /// Also used for map->m_noremap and menu->noremap[]. -enum { +enum RemapValues { REMAP_YES = 0, ///< Allow remapping. REMAP_NONE = -1, ///< No remapping. REMAP_SCRIPT = -2, ///< Remap script-local mappings only. REMAP_SKIP = -3, ///< No remapping for first char. -} RemapValues; +}; // Argument for flush_buffers(). typedef enum { diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 323c6cf9c3..f102c3ddd8 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -120,24 +120,20 @@ typedef off_t off_T; # endif #endif -/* - * When vgetc() is called, it sets mod_mask to the set of modifiers that are - * held down based on the MOD_MASK_* symbols that are read first. - */ -EXTERN int mod_mask INIT(= 0x0); /* current key modifiers */ +// When vgetc() is called, it sets mod_mask to the set of modifiers that are +// held down based on the MOD_MASK_* symbols that are read first. +EXTERN int mod_mask INIT(= 0x0); // current key modifiers EXTERN bool lua_attr_active INIT(= false); -/* - * Cmdline_row is the row where the command line starts, just below the - * last window. - * When the cmdline gets longer than the available space the screen gets - * scrolled up. After a CTRL-D (show matches), after hitting ':' after - * "hit return", and for the :global command, the command line is - * temporarily moved. The old position is restored with the next call to - * update_screen(). - */ +// Cmdline_row is the row where the command line starts, just below the +// last window. +// When the cmdline gets longer than the available space the screen gets +// scrolled up. After a CTRL-D (show matches), after hitting ':' after +// "hit return", and for the :global command, the command line is +// temporarily moved. The old position is restored with the next call to +// update_screen(). EXTERN int cmdline_row; EXTERN int redraw_cmdline INIT(= false); // cmdline must be redrawn @@ -149,42 +145,38 @@ EXTERN int cmdline_was_last_drawn INIT(= false); // cmdline was last drawn EXTERN int exec_from_reg INIT(= false); // executing register -/* - * When '$' is included in 'cpoptions' option set: - * When a change command is given that deletes only part of a line, a dollar - * is put at the end of the changed text. dollar_vcol is set to the virtual - * column of this '$'. -1 is used to indicate no $ is being displayed. - */ +// When '$' is included in 'cpoptions' option set: +// When a change command is given that deletes only part of a line, a dollar +// is put at the end of the changed text. dollar_vcol is set to the virtual +// column of this '$'. -1 is used to indicate no $ is being displayed. EXTERN colnr_T dollar_vcol INIT(= -1); -/* - * Variables for Insert mode completion. - */ +// Variables for Insert mode completion. -/* Length in bytes of the text being completed (this is deleted to be replaced - * by the match.) */ +// Length in bytes of the text being completed (this is deleted to be replaced +// by the match.) EXTERN int compl_length INIT(= 0); -/* Set when character typed while looking for matches and it means we should - * stop looking for matches. */ -EXTERN int compl_interrupted INIT(= FALSE); +// Set when character typed while looking for matches and it means we should +// stop looking for matches. +EXTERN int compl_interrupted INIT(= false); // Set when doing something for completion that may call edit() recursively, // which is not allowed. Also used to disable folding during completion EXTERN int compl_busy INIT(= false); -/* List of flags for method of completion. */ +// List of flags for method of completion. EXTERN int compl_cont_status INIT(= 0); -# define CONT_ADDING 1 /* "normal" or "adding" expansion */ -# define CONT_INTRPT (2 + 4) /* a ^X interrupted the current expansion */ - /* it's set only iff N_ADDS is set */ -# define CONT_N_ADDS 4 /* next ^X<> will add-new or expand-current */ -# define CONT_S_IPOS 8 /* next ^X<> will set initial_pos? - * if so, word-wise-expansion will set SOL */ -# define CONT_SOL 16 /* pattern includes start of line, just for - * word-wise expansion, not set for ^X^L */ -# define CONT_LOCAL 32 /* for ctrl_x_mode 0, ^X^P/^X^N do a local - * expansion, (eg use complete=.) */ +# define CONT_ADDING 1 // "normal" or "adding" expansion +# define CONT_INTRPT (2 + 4) // a ^X interrupted the current expansion + // it's set only iff N_ADDS is set +# define CONT_N_ADDS 4 // next ^X<> will add-new or expand-current +# define CONT_S_IPOS 8 // next ^X<> will set initial_pos? + // if so, word-wise-expansion will set SOL +# define CONT_SOL 16 // pattern includes start of line, just for + // word-wise expansion, not set for ^X^L +# define CONT_LOCAL 32 // for ctrl_x_mode 0, ^X^P/^X^N do a local + // expansion, (eg use complete=.) // state for putting characters in the message area EXTERN int cmdmsg_rl INIT(= false); // cmdline is drawn right to left @@ -200,49 +192,49 @@ EXTERN bool msg_scrolled_ign INIT(= false); EXTERN bool msg_did_scroll INIT(= false); -EXTERN char_u *keep_msg INIT(= NULL); /* msg to be shown after redraw */ -EXTERN int keep_msg_attr INIT(= 0); /* highlight attr for keep_msg */ -EXTERN int keep_msg_more INIT(= FALSE); /* keep_msg was set by msgmore() */ -EXTERN int need_fileinfo INIT(= FALSE); /* do fileinfo() after redraw */ -EXTERN int msg_scroll INIT(= FALSE); /* msg_start() will scroll */ -EXTERN int msg_didout INIT(= FALSE); /* msg_outstr() was used in line */ -EXTERN int msg_didany INIT(= FALSE); /* msg_outstr() was used at all */ -EXTERN int msg_nowait INIT(= FALSE); /* don't wait for this msg */ -EXTERN int emsg_off INIT(= 0); /* don't display errors for now, - unless 'debug' is set. */ -EXTERN int info_message INIT(= FALSE); /* printing informative message */ -EXTERN int msg_hist_off INIT(= FALSE); /* don't add messages to history */ -EXTERN int need_clr_eos INIT(= FALSE); /* need to clear text before - displaying a message. */ -EXTERN int emsg_skip INIT(= 0); /* don't display errors for - expression that is skipped */ -EXTERN int emsg_severe INIT(= FALSE); /* use message of next of several - emsg() calls for throw */ -EXTERN int did_endif INIT(= FALSE); /* just had ":endif" */ -EXTERN dict_T vimvardict; /* Dictionary with v: variables */ -EXTERN dict_T globvardict; /* Dictionary with g: variables */ -EXTERN int did_emsg; /* set by emsg() when the message - is displayed or thrown */ +EXTERN char_u *keep_msg INIT(= NULL); // msg to be shown after redraw +EXTERN int keep_msg_attr INIT(= 0); // highlight attr for keep_msg +EXTERN int keep_msg_more INIT(= false); // keep_msg was set by msgmore() +EXTERN int need_fileinfo INIT(= false); // do fileinfo() after redraw +EXTERN int msg_scroll INIT(= false); // msg_start() will scroll +EXTERN int msg_didout INIT(= false); // msg_outstr() was used in line +EXTERN int msg_didany INIT(= false); // msg_outstr() was used at all +EXTERN int msg_nowait INIT(= false); // don't wait for this msg +EXTERN int emsg_off INIT(= 0); // don't display errors for now, + // unless 'debug' is set. +EXTERN int info_message INIT(= false); // printing informative message +EXTERN int msg_hist_off INIT(= false); // don't add messages to history +EXTERN int need_clr_eos INIT(= false); // need to clear text before + // displaying a message. +EXTERN int emsg_skip INIT(= 0); // don't display errors for + // expression that is skipped +EXTERN int emsg_severe INIT(= false); // use message of next of several + // emsg() calls for throw +EXTERN int did_endif INIT(= false); // just had ":endif" +EXTERN dict_T vimvardict; // Dictionary with v: variables +EXTERN dict_T globvardict; // Dictionary with g: variables +EXTERN int did_emsg; // set by emsg() when the message + // is displayed or thrown EXTERN bool called_vim_beep; // set if vim_beep() is called -EXTERN int did_emsg_syntax; /* did_emsg set because of a - syntax error */ -EXTERN int called_emsg; /* always set by emsg() */ -EXTERN int ex_exitval INIT(= 0); /* exit value for ex mode */ -EXTERN int emsg_on_display INIT(= FALSE); /* there is an error message */ -EXTERN int rc_did_emsg INIT(= FALSE); /* vim_regcomp() called emsg() */ - -EXTERN int no_wait_return INIT(= 0); /* don't wait for return for now */ -EXTERN int need_wait_return INIT(= 0); /* need to wait for return later */ -EXTERN int did_wait_return INIT(= FALSE); /* wait_return() was used and - nothing written since then */ -EXTERN int need_maketitle INIT(= TRUE); /* call maketitle() soon */ +EXTERN int did_emsg_syntax; // did_emsg set because of a + // syntax error +EXTERN int called_emsg; // always set by emsg() +EXTERN int ex_exitval INIT(= 0); // exit value for ex mode +EXTERN bool emsg_on_display INIT(= false); // there is an error message +EXTERN int rc_did_emsg INIT(= false); // vim_regcomp() called emsg() + +EXTERN int no_wait_return INIT(= 0); // don't wait for return for now +EXTERN int need_wait_return INIT(= 0); // need to wait for return later +EXTERN int did_wait_return INIT(= false); // wait_return() was used and + // nothing written since then +EXTERN int need_maketitle INIT(= true); // call maketitle() soon EXTERN int quit_more INIT(= false); // 'q' hit at "--more--" msg EXTERN int ex_keep_indent INIT(= false); // getexmodeline(): keep indent EXTERN int vgetc_busy INIT(= 0); // when inside vgetc() then > 0 -EXTERN int didset_vim INIT(= FALSE); /* did set $VIM ourselves */ -EXTERN int didset_vimruntime INIT(= FALSE); /* idem for $VIMRUNTIME */ +EXTERN int didset_vim INIT(= false); // did set $VIM ourselves +EXTERN int didset_vimruntime INIT(= false); // idem for $VIMRUNTIME /// Lines left before a "more" message. Ex mode needs to be able to reset this /// after you type something. @@ -250,8 +242,8 @@ EXTERN int lines_left INIT(= -1); // lines left for listing EXTERN int msg_no_more INIT(= false); // don't use more prompt, truncate // messages -EXTERN char_u *sourcing_name INIT( = NULL); /* name of error message source */ -EXTERN linenr_T sourcing_lnum INIT(= 0); /* line number of the source file */ +EXTERN char_u *sourcing_name INIT(= NULL); // name of error message source +EXTERN linenr_T sourcing_lnum INIT(= 0); // line number of the source file EXTERN int ex_nesting_level INIT(= 0); // nesting level EXTERN int debug_break_level INIT(= -1); // break below this level @@ -282,11 +274,11 @@ EXTERN int check_cstack INIT(= false); /// commands). EXTERN int trylevel INIT(= 0); -/// When "force_abort" is TRUE, always skip commands after an error message, +/// When "force_abort" is true, always skip commands after an error message, /// even after the outermost ":endif", ":endwhile" or ":endfor" or for a -/// function without the "abort" flag. It is set to TRUE when "trylevel" is +/// function without the "abort" flag. It is set to true when "trylevel" is /// non-zero (and ":silent!" was not used) or an exception is being thrown at -/// the time an error is detected. It is set to FALSE when "trylevel" gets +/// the time an error is detected. It is set to false when "trylevel" gets /// zero again and there was no error or interrupt or throw. EXTERN int force_abort INIT(= false); @@ -304,7 +296,7 @@ EXTERN struct msglist **msg_list INIT(= NULL); /// interrupt message or reporting an exception that is still uncaught at the /// top level (which has already been discarded then). Also used for the error /// message when no exception can be thrown. -EXTERN int suppress_errthrow INIT(= false); +EXTERN bool suppress_errthrow INIT(= false); /// The stack of all caught and not finished exceptions. The exception on the /// top of the stack is the one got by evaluation of v:exception. The complete @@ -357,41 +349,38 @@ EXTERN int provider_call_nesting INIT(= 0); EXTERN int t_colors INIT(= 256); // int value of T_CCO -/* - * When highlight_match is TRUE, highlight a match, starting at the cursor - * position. Search_match_lines is the number of lines after the match (0 for - * a match within one line), search_match_endcol the column number of the - * character just after the match in the last line. - */ -EXTERN int highlight_match INIT(= FALSE); /* show search match pos */ -EXTERN linenr_T search_match_lines; /* lines of of matched string */ -EXTERN colnr_T search_match_endcol; /* col nr of match end */ - -EXTERN int no_smartcase INIT(= FALSE); /* don't use 'smartcase' once */ - -EXTERN int need_check_timestamps INIT(= FALSE); /* need to check file - timestamps asap */ -EXTERN int did_check_timestamps INIT(= FALSE); /* did check timestamps - recently */ -EXTERN int no_check_timestamps INIT(= 0); /* Don't check timestamps */ - -EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */ -EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */ -EXTERN int autocmd_no_leave INIT(= FALSE); /* *Leave autocmds disabled */ -EXTERN int modified_was_set; /* did ":set modified" */ -EXTERN int did_filetype INIT(= FALSE); /* FileType event found */ -EXTERN int keep_filetype INIT(= FALSE); /* value for did_filetype when - starting to execute - autocommands */ +// When highlight_match is true, highlight a match, starting at the cursor +// position. Search_match_lines is the number of lines after the match (0 for +// a match within one line), search_match_endcol the column number of the +// character just after the match in the last line. +EXTERN int highlight_match INIT(= false); // show search match pos +EXTERN linenr_T search_match_lines; // lines of of matched string +EXTERN colnr_T search_match_endcol; // col nr of match end + +EXTERN int no_smartcase INIT(= false); // don't use 'smartcase' once + +EXTERN int need_check_timestamps INIT(= false); // need to check file + // timestamps asap +EXTERN int did_check_timestamps INIT(= false); // did check timestamps + // recently +EXTERN int no_check_timestamps INIT(= 0); // Don't check timestamps + +EXTERN int autocmd_busy INIT(= false); // Is apply_autocmds() busy? +EXTERN int autocmd_no_enter INIT(= false); // *Enter autocmds disabled +EXTERN int autocmd_no_leave INIT(= false); // *Leave autocmds disabled +EXTERN int modified_was_set; // did ":set modified" +EXTERN int did_filetype INIT(= false); // FileType event found +// value for did_filetype when starting to execute autocommands +EXTERN int keep_filetype INIT(= false); // When deleting the current buffer, another one must be loaded. // If we know which one is preferred, au_new_curbuf is set to it. EXTERN bufref_T au_new_curbuf INIT(= { NULL, 0, 0 }); -// When deleting a buffer/window and autocmd_busy is TRUE, do not free the +// When deleting a buffer/window and autocmd_busy is true, do not free the // buffer/window. but link it in the list starting with // au_pending_free_buf/ap_pending_free_win, using b_next/w_next. -// Free the buffer/window when autocmd_busy is being set to FALSE. +// Free the buffer/window when autocmd_busy is being set to false. EXTERN buf_T *au_pending_free_buf INIT(= NULL); EXTERN win_T *au_pending_free_win INIT(= NULL); @@ -399,31 +388,27 @@ EXTERN win_T *au_pending_free_win INIT(= NULL); EXTERN int mouse_grid; EXTERN int mouse_row; EXTERN int mouse_col; -EXTERN bool mouse_past_bottom INIT(= false); /* mouse below last line */ -EXTERN bool mouse_past_eol INIT(= false); /* mouse right of line */ -EXTERN int mouse_dragging INIT(= 0); /* extending Visual area with - mouse dragging */ +EXTERN bool mouse_past_bottom INIT(= false); // mouse below last line +EXTERN bool mouse_past_eol INIT(= false); // mouse right of line +EXTERN int mouse_dragging INIT(= 0); // extending Visual area with + // mouse dragging -/* The root of the menu hierarchy. */ +// The root of the menu hierarchy. EXTERN vimmenu_T *root_menu INIT(= NULL); -/* - * While defining the system menu, sys_menu is TRUE. This avoids - * overruling of menus that the user already defined. - */ -EXTERN int sys_menu INIT(= FALSE); - -/* While redrawing the screen this flag is set. It means the screen size - * ('lines' and 'rows') must not be changed. */ -EXTERN int updating_screen INIT(= FALSE); - -/* - * All windows are linked in a list. firstwin points to the first entry, - * lastwin to the last entry (can be the same as firstwin) and curwin to the - * currently active window. - */ -EXTERN win_T *firstwin; /* first window */ -EXTERN win_T *lastwin; /* last window */ -EXTERN win_T *prevwin INIT(= NULL); /* previous window */ +// While defining the system menu, sys_menu is true. This avoids +// overruling of menus that the user already defined. +EXTERN int sys_menu INIT(= false); + +// While redrawing the screen this flag is set. It means the screen size +// ('lines' and 'rows') must not be changed. +EXTERN int updating_screen INIT(= 0); + +// All windows are linked in a list. firstwin points to the first entry, +// lastwin to the last entry (can be the same as firstwin) and curwin to the +// currently active window. +EXTERN win_T *firstwin; // first window +EXTERN win_T *lastwin; // last window +EXTERN win_T *prevwin INIT(= NULL); // previous window # define ONE_WINDOW (firstwin == lastwin) # define FOR_ALL_FRAMES(frp, first_frame) \ for (frp = first_frame; frp != NULL; frp = frp->fr_next) // NOLINT @@ -439,33 +424,27 @@ EXTERN win_T *prevwin INIT(= NULL); /* previous window */ for (win_T *wp = ((tp) == curtab) \ ? firstwin : (tp)->tp_firstwin; wp != NULL; wp = wp->w_next) -EXTERN win_T *curwin; /* currently active window */ +EXTERN win_T *curwin; // currently active window -EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */ -EXTERN int aucmd_win_used INIT(= FALSE); /* aucmd_win is being used */ +EXTERN win_T *aucmd_win; // window used in aucmd_prepbuf() +EXTERN int aucmd_win_used INIT(= false); // aucmd_win is being used -/* - * The window layout is kept in a tree of frames. topframe points to the top - * of the tree. - */ -EXTERN frame_T *topframe; /* top of the window frame tree */ +// The window layout is kept in a tree of frames. topframe points to the top +// of the tree. +EXTERN frame_T *topframe; // top of the window frame tree -/* - * Tab pages are alternative topframes. "first_tabpage" points to the first - * one in the list, "curtab" is the current one. - */ +// Tab pages are alternative topframes. "first_tabpage" points to the first +// one in the list, "curtab" is the current one. EXTERN tabpage_T *first_tabpage; EXTERN tabpage_T *lastused_tabpage; EXTERN tabpage_T *curtab; -EXTERN int redraw_tabline INIT(= FALSE); /* need to redraw tabline */ +EXTERN int redraw_tabline INIT(= false); // need to redraw tabline // Iterates over all tabs in the tab list # define FOR_ALL_TABS(tp) for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) -/* - * All buffers are linked in a list. 'firstbuf' points to the first entry, - * 'lastbuf' to the last entry and 'curbuf' to the currently active buffer. - */ +// All buffers are linked in a list. 'firstbuf' points to the first entry, +// 'lastbuf' to the last entry and 'curbuf' to the currently active buffer. EXTERN buf_T *firstbuf INIT(= NULL); // first buffer EXTERN buf_T *lastbuf INIT(= NULL); // last buffer EXTERN buf_T *curbuf INIT(= NULL); // currently active buffer @@ -481,23 +460,19 @@ EXTERN buf_T *curbuf INIT(= NULL); // currently active buffer for (sign = buf->b_signlist; sign != NULL; sign = sign->next) // NOLINT -/* - * List of files being edited (global argument list). curwin->w_alist points - * to this when the window is using the global argument list. - */ -EXTERN alist_T global_alist; /* global argument list */ +// List of files being edited (global argument list). curwin->w_alist points +// to this when the window is using the global argument list. +EXTERN alist_T global_alist; // global argument list EXTERN int max_alist_id INIT(= 0); ///< the previous argument list id EXTERN bool arg_had_last INIT(= false); // accessed last file in // global_alist -EXTERN int ru_col; /* column for ruler */ -EXTERN int ru_wid; /* 'rulerfmt' width of ruler when non-zero */ -EXTERN int sc_col; /* column for shown command */ +EXTERN int ru_col; // column for ruler +EXTERN int ru_wid; // 'rulerfmt' width of ruler when non-zero +EXTERN int sc_col; // column for shown command -// // When starting or exiting some things are done differently (e.g. screen // updating). -// // First NO_SCREEN, then NO_BUFFERS, then 0 when startup finished. EXTERN int starting INIT(= NO_SCREEN); @@ -546,98 +521,78 @@ EXTERN int VIsual_select INIT(= false); EXTERN int VIsual_reselect; /// Type of Visual mode. EXTERN int VIsual_mode INIT(= 'v'); -/// TRUE when redoing Visual. +/// true when redoing Visual. EXTERN int redo_VIsual_busy INIT(= false); /// When pasting text with the middle mouse button in visual mode with /// restart_edit set, remember where it started so we can set Insstart. EXTERN pos_T where_paste_started; -/* - * This flag is used to make auto-indent work right on lines where only a - * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and - * reset when any other editing is done on the line. If an <ESC> or <RETURN> - * is received, and did_ai is TRUE, the line is truncated. - */ +// This flag is used to make auto-indent work right on lines where only a +// <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and +// reset when any other editing is done on the line. If an <ESC> or <RETURN> +// is received, and did_ai is true, the line is truncated. EXTERN bool did_ai INIT(= false); -/* - * Column of first char after autoindent. 0 when no autoindent done. Used - * when 'backspace' is 0, to avoid backspacing over autoindent. - */ +// Column of first char after autoindent. 0 when no autoindent done. Used +// when 'backspace' is 0, to avoid backspacing over autoindent. EXTERN colnr_T ai_col INIT(= 0); -/* - * This is a character which will end a start-middle-end comment when typed as - * the first character on a new line. It is taken from the last character of - * the "end" comment leader when the COM_AUTO_END flag is given for that - * comment end in 'comments'. It is only valid when did_ai is TRUE. - */ +// This is a character which will end a start-middle-end comment when typed as +// the first character on a new line. It is taken from the last character of +// the "end" comment leader when the COM_AUTO_END flag is given for that +// comment end in 'comments'. It is only valid when did_ai is true. EXTERN int end_comment_pending INIT(= NUL); -/* - * This flag is set after a ":syncbind" to let the check_scrollbind() function - * know that it should not attempt to perform scrollbinding due to the scroll - * that was a result of the ":syncbind." (Otherwise, check_scrollbind() will - * undo some of the work done by ":syncbind.") -ralston - */ -EXTERN int did_syncbind INIT(= FALSE); - -/* - * This flag is set when a smart indent has been performed. When the next typed - * character is a '{' the inserted tab will be deleted again. - */ +// This flag is set after a ":syncbind" to let the check_scrollbind() function +// know that it should not attempt to perform scrollbinding due to the scroll +// that was a result of the ":syncbind." (Otherwise, check_scrollbind() will +// undo some of the work done by ":syncbind.") -ralston +EXTERN int did_syncbind INIT(= false); + +// This flag is set when a smart indent has been performed. When the next typed +// character is a '{' the inserted tab will be deleted again. EXTERN bool did_si INIT(= false); -/* - * This flag is set after an auto indent. If the next typed character is a '}' - * one indent will be removed. - */ +// This flag is set after an auto indent. If the next typed character is a '}' +// one indent will be removed. EXTERN bool can_si INIT(= false); -/* - * This flag is set after an "O" command. If the next typed character is a '{' - * one indent will be removed. - */ +// This flag is set after an "O" command. If the next typed character is a '{' +// one indent will be removed. EXTERN bool can_si_back INIT(= false); // w_cursor before formatting text. EXTERN pos_T saved_cursor INIT(= { 0, 0, 0 }); -/* - * Stuff for insert mode. - */ -EXTERN pos_T Insstart; /* This is where the latest - * insert/append mode started. */ +// Stuff for insert mode. +EXTERN pos_T Insstart; // This is where the latest + // insert/append mode started. // This is where the latest insert/append mode started. In contrast to // Insstart, this won't be reset by certain keys and is needed for // op_insert(), to detect correctly where inserting by the user started. EXTERN pos_T Insstart_orig; -/* - * Stuff for VREPLACE mode. - */ -EXTERN int orig_line_count INIT(= 0); /* Line count when "gR" started */ -EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */ +// Stuff for VREPLACE mode. +EXTERN int orig_line_count INIT(= 0); // Line count when "gR" started +EXTERN int vr_lines_changed INIT(= 0); // #Lines changed by "gR" so far // increase around internal delete/replace EXTERN int inhibit_delete_count INIT(= 0); -/* - * These flags are set based upon 'fileencoding'. - * Note that "enc_utf8" is also set for "unicode", because the characters are - * internally stored as UTF-8 (to avoid trouble with NUL bytes). - */ -# define DBCS_JPN 932 /* japan */ -# define DBCS_JPNU 9932 /* euc-jp */ -# define DBCS_KOR 949 /* korea */ -# define DBCS_KORU 9949 /* euc-kr */ -# define DBCS_CHS 936 /* chinese */ -# define DBCS_CHSU 9936 /* euc-cn */ -# define DBCS_CHT 950 /* taiwan */ -# define DBCS_CHTU 9950 /* euc-tw */ -# define DBCS_2BYTE 1 /* 2byte- */ +// These flags are set based upon 'fileencoding'. +// Note that "enc_utf8" is also set for "unicode", because the characters are +// internally stored as UTF-8 (to avoid trouble with NUL bytes). +# define DBCS_JPN 932 // japan +# define DBCS_JPNU 9932 // euc-jp +# define DBCS_KOR 949 // korea +# define DBCS_KORU 9949 // euc-kr +# define DBCS_CHS 936 // chinese +# define DBCS_CHSU 9936 // euc-cn +# define DBCS_CHT 950 // taiwan +# define DBCS_CHTU 9950 // euc-tw +# define DBCS_2BYTE 1 // 2byte- # define DBCS_DEBUG -1 // mbyte flags that used to depend on 'encoding'. These are now deprecated, as @@ -678,40 +633,40 @@ EXTERN int u_sync_once INIT(= 0); // Call u_sync() once when evaluating EXTERN bool force_restart_edit INIT(= false); // force restart_edit after // ex_normal returns -EXTERN int restart_edit INIT(= 0); /* call edit when next cmd finished */ -EXTERN int arrow_used; /* Normally FALSE, set to TRUE after - * hitting cursor key in insert mode. - * Used by vgetorpeek() to decide when - * to call u_sync() */ -EXTERN int ins_at_eol INIT(= FALSE); /* put cursor after eol when - restarting edit after CTRL-O */ +EXTERN int restart_edit INIT(= 0); // call edit when next cmd finished +EXTERN int arrow_used; // Normally false, set to true after + // hitting cursor key in insert mode. + // Used by vgetorpeek() to decide when + // to call u_sync() +EXTERN bool ins_at_eol INIT(= false); // put cursor after eol when + // restarting edit after CTRL-O EXTERN char_u *edit_submode INIT(= NULL); // msg for CTRL-X submode EXTERN char_u *edit_submode_pre INIT(= NULL); // prepended to edit_submode EXTERN char_u *edit_submode_extra INIT(= NULL); // appended to edit_submode EXTERN hlf_T edit_submode_highl; // highl. method for extra info -EXTERN int no_abbr INIT(= TRUE); /* TRUE when no abbreviations loaded */ +EXTERN int no_abbr INIT(= true); // true when no abbreviations loaded EXTERN int mapped_ctrl_c INIT(= 0); // Modes where CTRL-C is mapped. -EXTERN cmdmod_T cmdmod; /* Ex command modifiers */ +EXTERN cmdmod_T cmdmod; // Ex command modifiers EXTERN int msg_silent INIT(= 0); // don't print messages EXTERN int emsg_silent INIT(= 0); // don't print error messages EXTERN bool emsg_noredir INIT(= false); // don't redirect error messages EXTERN bool cmd_silent INIT(= false); // don't echo the command line -/* Values for swap_exists_action: what to do when swap file already exists */ -#define SEA_NONE 0 /* don't use dialog */ -#define SEA_DIALOG 1 /* use dialog when possible */ -#define SEA_QUIT 2 /* quit editing the file */ -#define SEA_RECOVER 3 /* recover the file */ +// Values for swap_exists_action: what to do when swap file already exists +#define SEA_NONE 0 // don't use dialog +#define SEA_DIALOG 1 // use dialog when possible +#define SEA_QUIT 2 // quit editing the file +#define SEA_RECOVER 3 // recover the file EXTERN int swap_exists_action INIT(= SEA_NONE); -/* For dialog when swap file already - * exists. */ -EXTERN int swap_exists_did_quit INIT(= FALSE); -/* Selected "quit" at the dialog. */ +// For dialog when swap file already +// exists. +EXTERN int swap_exists_did_quit INIT(= false); +// Selected "quit" at the dialog. EXTERN char_u IObuff[IOSIZE]; ///< Buffer for sprintf, I/O, etc. EXTERN char_u NameBuff[MAXPATHL]; ///< Buffer for expanding file names @@ -724,11 +679,11 @@ IOSIZE #endif ]; -/* When non-zero, postpone redrawing. */ +// When non-zero, postpone redrawing. EXTERN int RedrawingDisabled INIT(= 0); -EXTERN int readonlymode INIT(= FALSE); /* Set to TRUE for "view" */ -EXTERN int recoverymode INIT(= FALSE); /* Set to TRUE for "-r" option */ +EXTERN int readonlymode INIT(= false); // Set to true for "view" +EXTERN int recoverymode INIT(= false); // Set to true for "-r" option // typeahead buffer EXTERN typebuf_T typebuf INIT(= { NULL, NULL, 0, 0, 0, 0, 0, 0, 0 }); @@ -738,7 +693,7 @@ EXTERN int ex_normal_lock INIT(= 0); // forbid use of ex_normal() EXTERN int ignore_script INIT(= false); // ignore script input EXTERN int stop_insert_mode; // for ":stopinsert" and 'insertmode' EXTERN bool KeyTyped; // true if user typed current char -EXTERN int KeyStuffed; // TRUE if current char from stuffbuf +EXTERN int KeyStuffed; // true if current char from stuffbuf EXTERN int maptick INIT(= 0); // tick for each non-mapped char EXTERN int must_redraw INIT(= 0); // type of redraw necessary @@ -754,15 +709,15 @@ EXTERN FILE *scriptout INIT(= NULL); ///< Stream to write script to. // volatile because it is used in a signal handler. EXTERN volatile int got_int INIT(= false); // set to true when interrupt // signal occurred -EXTERN int bangredo INIT(= FALSE); /* set to TRUE with ! command */ -EXTERN int searchcmdlen; /* length of previous search cmd */ -EXTERN int reg_do_extmatch INIT(= 0); /* Used when compiling regexp: - * REX_SET to allow \z\(...\), - * REX_USE to allow \z\1 et al. */ -EXTERN reg_extmatch_T *re_extmatch_in INIT(= NULL); /* Used by vim_regexec(): - * strings for \z\1...\z\9 */ -EXTERN reg_extmatch_T *re_extmatch_out INIT(= NULL); /* Set by vim_regexec() - * to store \z\(...\) matches */ +EXTERN int bangredo INIT(= false); // set to true with ! command +EXTERN int searchcmdlen; // length of previous search cmd +EXTERN int reg_do_extmatch INIT(= 0); // Used when compiling regexp: + // REX_SET to allow \z\(...\), + // REX_USE to allow \z\1 et al. +// Used by vim_regexec(): strings for \z\1...\z\9 +EXTERN reg_extmatch_T *re_extmatch_in INIT(= NULL); +// Set by vim_regexec() to store \z\(...\) matches +EXTERN reg_extmatch_T *re_extmatch_out INIT(= NULL); EXTERN int did_outofmem_msg INIT(= false); // set after out of memory msg @@ -781,11 +736,11 @@ EXTERN int autocmd_bufnr INIT(= 0); // fnum for <abuf> on cmdline EXTERN char_u *autocmd_match INIT(= NULL); // name for <amatch> on cmdline EXTERN int did_cursorhold INIT(= false); // set when CursorHold t'gerd -EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */ -EXTERN int postponed_split_flags INIT(= 0); /* args for win_split() */ -EXTERN int postponed_split_tab INIT(= 0); /* cmdmod.tab */ -EXTERN int g_do_tagpreview INIT(= 0); /* for tag preview commands: - height of preview window */ +EXTERN int postponed_split INIT(= 0); // for CTRL-W CTRL-] command +EXTERN int postponed_split_flags INIT(= 0); // args for win_split() +EXTERN int postponed_split_tab INIT(= 0); // cmdmod.tab +EXTERN int g_do_tagpreview INIT(= 0); // for tag preview commands: + // height of preview window EXTERN int g_tag_at_cursor INIT(= false); // whether the tag command comes // from the command line (0) or was // invoked as a normal command (1) @@ -793,15 +748,13 @@ EXTERN int g_tag_at_cursor INIT(= false); // whether the tag command comes EXTERN int replace_offset INIT(= 0); // offset for replace_push() EXTERN char_u *escape_chars INIT(= (char_u *)" \t\\\"|"); -/* need backslash in cmd line */ +// need backslash in cmd line -EXTERN int keep_help_flag INIT(= FALSE); /* doing :ta from help file */ +EXTERN int keep_help_flag INIT(= false); // doing :ta from help file -/* - * When a string option is NULL (which only happens in out-of-memory - * situations), it is set to empty_option, to avoid having to check for NULL - * everywhere. - */ +// When a string option is NULL (which only happens in out-of-memory +// situations), it is set to empty_option, to avoid having to check for NULL +// everywhere. EXTERN char_u *empty_option INIT(= (char_u *)""); EXTERN int redir_off INIT(= false); // no redirection for a moment @@ -810,10 +763,10 @@ EXTERN int redir_reg INIT(= 0); // message redirection register EXTERN int redir_vname INIT(= 0); // message redirection variable EXTERN garray_T *capture_ga INIT(= NULL); // captured output for execute() -EXTERN char_u langmap_mapchar[256]; /* mapping for language keys */ +EXTERN char_u langmap_mapchar[256]; // mapping for language keys -EXTERN int save_p_ls INIT(= -1); /* Save 'laststatus' setting */ -EXTERN int save_p_wmh INIT(= -1); /* Save 'winminheight' setting */ +EXTERN int save_p_ls INIT(= -1); // Save 'laststatus' setting +EXTERN int save_p_wmh INIT(= -1); // Save 'winminheight' setting EXTERN int wild_menu_showing INIT(= 0); enum { WM_SHOWN = 1, ///< wildmenu showing @@ -822,10 +775,8 @@ enum { }; -/* - * Some file names are stored in pathdef.c, which is generated from the - * Makefile to make their value depend on the Makefile. - */ +// Some file names are stored in pathdef.c, which is generated from the +// Makefile to make their value depend on the Makefile. #ifdef HAVE_PATHDEF extern char *default_vim_dir; extern char *default_vimruntime_dir; @@ -834,14 +785,14 @@ extern char_u *compiled_user; extern char_u *compiled_sys; #endif -/* When a window has a local directory, the absolute path of the global - * current directory is stored here (in allocated memory). If the current - * directory is not a local directory, globaldir is NULL. */ +// When a window has a local directory, the absolute path of the global +// current directory is stored here (in allocated memory). If the current +// directory is not a local directory, globaldir is NULL. EXTERN char_u *globaldir INIT(= NULL); -/* Whether 'keymodel' contains "stopsel" and "startsel". */ -EXTERN int km_stopsel INIT(= FALSE); -EXTERN int km_startsel INIT(= FALSE); +// Whether 'keymodel' contains "stopsel" and "startsel". +EXTERN int km_stopsel INIT(= false); +EXTERN int km_startsel INIT(= false); EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0 @@ -850,18 +801,16 @@ EXTERN int cmdwin_level INIT(= 0); ///< cmdline recursion level EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--")); -/* - * When ":global" is used to number of substitutions and changed lines is - * accumulated until it's finished. - * Also used for ":spellrepall". - */ -EXTERN long sub_nsubs; /* total number of substitutions */ -EXTERN linenr_T sub_nlines; /* total number of lines changed */ +// When ":global" is used to number of substitutions and changed lines is +// accumulated until it's finished. +// Also used for ":spellrepall". +EXTERN long sub_nsubs; // total number of substitutions +EXTERN linenr_T sub_nlines; // total number of lines changed -/* table to store parsed 'wildmode' */ +// table to store parsed 'wildmode' EXTERN char_u wim_flags[4]; -/* whether titlestring and iconstring contains statusline syntax */ +// whether titlestring and iconstring contains statusline syntax # define STL_IN_ICON 1 # define STL_IN_TITLE 2 EXTERN int stl_syntax INIT(= 0); @@ -869,7 +818,7 @@ EXTERN int stl_syntax INIT(= 0); // don't use 'hlsearch' temporarily EXTERN bool no_hlsearch INIT(= false); -/* Page number used for %N in 'pageheader' and 'guitablabel'. */ +// Page number used for %N in 'pageheader' and 'guitablabel'. EXTERN linenr_T printer_page_num; @@ -887,18 +836,16 @@ EXTERN char pseps[2] INIT(= { '\\', 0 }); // normal path separator string // kNone when no operator is being executed, kFalse otherwise. EXTERN TriState virtual_op INIT(= kNone); -/* Display tick, incremented for each call to update_screen() */ +// Display tick, incremented for each call to update_screen() EXTERN disptick_T display_tick INIT(= 0); -/* Line in which spell checking wasn't highlighted because it touched the - * cursor position in Insert mode. */ +// Line in which spell checking wasn't highlighted because it touched the +// cursor position in Insert mode. EXTERN linenr_T spell_redraw_lnum INIT(= 0); -/* - * The error messages that can be shared are included here. - * Excluded are errors that are only used once and debugging messages. - */ +// The error messages that can be shared are included here. +// Excluded are errors that are only used once and debugging messages. EXTERN char_u e_abort[] INIT(= N_("E470: Command aborted")); EXTERN char_u e_afterinit[] INIT(= N_( "E905: Cannot set this option after startup")); @@ -1070,7 +1017,7 @@ EXTERN char line_msg[] INIT(= N_(" line ")); // For undo we need to know the lowest time possible. EXTERN time_t starttime; -EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */ +EXTERN FILE *time_fd INIT(= NULL); // where to write startup timing // Some compilers warn for not using a return value, but in some situations we // can't do anything useful with the value. Assign to this variable to avoid @@ -1106,4 +1053,4 @@ typedef enum { #define MIN_CD_SCOPE kCdScopeWindow #define MAX_CD_SCOPE kCdScopeGlobal -#endif /* NVIM_GLOBALS_H */ +#endif // NVIM_GLOBALS_H diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index cb5c5338a1..f1f84e63be 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -162,21 +162,21 @@ static option_table_T mbfont_opts[OPT_MBFONT_NUM_OPTIONS] = * These values determine the print position on a page. */ typedef struct { - int lead_spaces; /* remaining spaces for a TAB */ - int print_pos; /* virtual column for computing TABs */ - colnr_T column; /* byte column */ - linenr_T file_line; /* line nr in the buffer */ - size_t bytes_printed; /* bytes printed so far */ - int ff; /* seen form feed character */ + int lead_spaces; // remaining spaces for a TAB + int print_pos; // virtual column for computing TABs + colnr_T column; // byte column + linenr_T file_line; // line nr in the buffer + size_t bytes_printed; // bytes printed so far + int ff; // seen form feed character } prt_pos_T; struct prt_mediasize_S { char *name; - double width; /* width and height in points for portrait */ + double width; // width and height in points for portrait double height; }; -/* PS font names, must be in Roman, Bold, Italic, Bold-Italic order */ +// PS font names, must be in Roman, Bold, Italic, Bold-Italic order struct prt_ps_font_S { int wx; int uline_offset; @@ -200,7 +200,7 @@ struct prt_ps_charset_S { int has_charset; }; -/* Collections of encodings and charsets for multi-byte printing */ +// Collections of encodings and charsets for multi-byte printing struct prt_ps_mbfont_S { int num_encodings; struct prt_ps_encoding_S *encodings; @@ -361,9 +361,10 @@ static uint32_t darken_rgb(uint32_t rgb) static uint32_t prt_get_term_color(int colorindex) { - /* TODO: Should check for xterm with 88 or 256 colors. */ - if (t_colors > 8) + // TODO(vim): Should check for xterm with 88 or 256 colors. + if (t_colors > 8) { return cterm_color_16[colorindex % 16]; + } return cterm_color_8[colorindex % 8]; } @@ -535,7 +536,7 @@ static void prt_header(prt_settings_T *const psettings, const int pagenum, p_header, use_sandbox, ' ', width, NULL, NULL); - /* Reset line numbers */ + // Reset line numbers curwin->w_cursor.lnum = tmp_lnum; curwin->w_topline = tmp_topline; curwin->w_botline = tmp_botline; @@ -602,7 +603,7 @@ void ex_hardcopy(exarg_T *eap) if (*eap->arg == '>') { char_u *errormsg = NULL; - /* Expand things like "%.ps". */ + // Expand things like "%.ps". if (expand_filename(eap, eap->cmdlinep, &errormsg) == FAIL) { if (errormsg != NULL) EMSG(errormsg); @@ -666,7 +667,7 @@ void ex_hardcopy(exarg_T *eap) goto print_fail_no_begin; } - /* Set colors and font to normal. */ + // Set colors and font to normal. curr_bg = 0xffffffff; curr_fg = 0xffffffff; curr_italic = kNone; @@ -691,8 +692,8 @@ void ex_hardcopy(exarg_T *eap) for (collated_copies = 0; collated_copies < settings.n_collated_copies; collated_copies++) { - prt_pos_T prtpos; /* current print position */ - prt_pos_T page_prtpos; /* print position at page start */ + prt_pos_T prtpos; // current print position + prt_pos_T page_prtpos; // print position at page start int side; memset(&page_prtpos, 0, sizeof(prt_pos_T)); @@ -700,7 +701,7 @@ void ex_hardcopy(exarg_T *eap) prtpos = page_prtpos; if (jobsplit && collated_copies > 0) { - /* Splitting jobs: Stop a previous job and start a new one. */ + // Splitting jobs: Stop a previous job and start a new one. mch_print_end(&settings); if (!mch_print_begin(&settings)) goto print_fail_no_begin; @@ -717,7 +718,7 @@ void ex_hardcopy(exarg_T *eap) for (uncollated_copies = 0; uncollated_copies < settings.n_uncollated_copies; uncollated_copies++) { - /* Set the print position to the start of this page. */ + // Set the print position to the start of this page. prtpos = page_prtpos; /* @@ -728,7 +729,7 @@ void ex_hardcopy(exarg_T *eap) * Print one page. */ - /* Check for interrupt character every page. */ + // Check for interrupt character every page. os_breakcheck(); if (got_int || settings.user_abort) goto print_fail; @@ -759,11 +760,12 @@ void ex_hardcopy(exarg_T *eap) prtpos.column = hardcopy_line(&settings, page_line, &prtpos); if (prtpos.column == 0) { - /* finished a file line */ + // finished a file line prtpos.bytes_printed += STRLEN(skipwhite(ml_get(prtpos.file_line))); - if (++prtpos.file_line > eap->line2) - break; /* reached the end */ + if (++prtpos.file_line > eap->line2) { + break; // reached the end + } } else if (prtpos.ff) { /* Line had a formfeed in it - start new page but * stay on the current line */ @@ -771,10 +773,12 @@ void ex_hardcopy(exarg_T *eap) } } - if (!mch_print_end_page()) + if (!mch_print_end_page()) { goto print_fail; - if (prtpos.file_line > eap->line2) - break; /* reached the end */ + } + if (prtpos.file_line > eap->line2) { + break; // reached the end + } } /* @@ -791,7 +795,7 @@ void ex_hardcopy(exarg_T *eap) if (settings.duplex && prtpos.file_line <= eap->line2) ++page_count; - /* Remember the position where the next page starts. */ + // Remember the position where the next page starts. page_prtpos = prtpos; } @@ -855,7 +859,7 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T id = syn_get_final_id(id); else id = 0; - /* Get the line again, a multi-line regexp may invalidate it. */ + // Get the line again, a multi-line regexp may invalidate it. line = ml_get(ppos->file_line); if (id != current_syn_id) { @@ -881,9 +885,10 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T if (need_break) break; } - /* Keep the TAB if we didn't finish it. */ - if (need_break && tab_spaces > 0) + // Keep the TAB if we didn't finish it. + if (need_break && tab_spaces > 0) { break; + } } else if (line[col] == FF && printer_opts[OPT_PRINT_FORMFEED].present && TOLOWER_ASC(printer_opts[OPT_PRINT_FORMFEED].string[0]) @@ -942,7 +947,7 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T * http://www.adobe.com */ -#define PRT_PS_DEFAULT_DPI (72) /* Default user space resolution */ +#define PRT_PS_DEFAULT_DPI (72) // Default user space resolution #define PRT_PS_DEFAULT_FONTSIZE (10) #define PRT_PS_DEFAULT_BUFFER_SIZE (80) @@ -951,20 +956,20 @@ static colnr_T hardcopy_line(prt_settings_T *psettings, int page_line, prt_pos_T static struct prt_mediasize_S prt_mediasize[] = { - {"A4", 595.0, 842.0}, - {"letter", 612.0, 792.0}, - {"10x14", 720.0, 1008.0}, - {"A3", 842.0, 1191.0}, - {"A5", 420.0, 595.0}, - {"B4", 729.0, 1032.0}, - {"B5", 516.0, 729.0}, - {"executive", 522.0, 756.0}, - {"folio", 595.0, 935.0}, - {"ledger", 1224.0, 792.0}, /* Yes, it is wider than taller! */ - {"legal", 612.0, 1008.0}, - {"quarto", 610.0, 780.0}, - {"statement", 396.0, 612.0}, - {"tabloid", 792.0, 1224.0} + { "A4", 595.0, 842.0 }, + { "letter", 612.0, 792.0 }, + { "10x14", 720.0, 1008.0 }, + { "A3", 842.0, 1191.0 }, + { "A5", 420.0, 595.0 }, + { "B4", 729.0, 1032.0 }, + { "B5", 516.0, 729.0 }, + { "executive", 522.0, 756.0 }, + { "folio", 595.0, 935.0 }, + { "ledger", 1224.0, 792.0 }, // Yes, it is wider than taller! + { "legal", 612.0, 1008.0 }, + { "quarto", 610.0, 780.0 }, + { "statement", 396.0, 612.0 }, + { "tabloid", 792.0, 1224.0 } }; #define PRT_PS_FONT_ROMAN (0) @@ -972,7 +977,7 @@ static struct prt_mediasize_S prt_mediasize[] = #define PRT_PS_FONT_OBLIQUE (2) #define PRT_PS_FONT_BOLDOBLIQUE (3) -/* Standard font metrics for Courier family */ +// Standard font metrics for Courier family static struct prt_ps_font_S prt_ps_courier_font = { 600, @@ -981,7 +986,7 @@ static struct prt_ps_font_S prt_ps_courier_font = {"Courier", "Courier-Bold", "Courier-Oblique", "Courier-BoldOblique"} }; -/* Generic font metrics for multi-byte fonts */ +// Generic font metrics for multi-byte fonts static struct prt_ps_font_S prt_ps_mb_font = { 1000, @@ -990,9 +995,8 @@ static struct prt_ps_font_S prt_ps_mb_font = {NULL, NULL, NULL, NULL} }; -/* Pointer to current font set being used */ -static struct prt_ps_font_S* prt_ps_font; - +// Pointer to current font set being used +static struct prt_ps_font_S *prt_ps_font; #define CS_JIS_C_1978 (0x01) #define CS_JIS_X_1983 (0x02) @@ -1003,7 +1007,7 @@ static struct prt_ps_font_S* prt_ps_font; #define CS_KANJITALK6 (0x40) #define CS_KANJITALK7 (0x80) -/* Japanese encodings and charsets */ +// Japanese encodings and charsets static struct prt_ps_encoding_S j_encodings[] = { {"iso-2022-jp", NULL, (CS_JIS_C_1978|CS_JIS_X_1983|CS_JIS_X_1990| @@ -1035,7 +1039,7 @@ static struct prt_ps_charset_S j_charsets[] = #define CS_GBK (0x20) #define CS_SC_ISO10646 (0x40) -/* Simplified Chinese encodings and charsets */ +// Simplified Chinese encodings and charsets static struct prt_ps_encoding_S sc_encodings[] = { {"iso-2022", NULL, (CS_GB_2312_80|CS_GBT_12345_90)}, @@ -1071,7 +1075,7 @@ static struct prt_ps_charset_S sc_charsets[] = #define CS_DLHKS (0x800) #define CS_TC_ISO10646 (0x1000) -/* Traditional Chinese encodings and charsets */ +// Traditional Chinese encodings and charsets static struct prt_ps_encoding_S tc_encodings[] = { {"iso-2022", NULL, (CS_CNS_PLANE_1|CS_CNS_PLANE_2)}, @@ -1108,7 +1112,7 @@ static struct prt_ps_charset_S tc_charsets[] = #define CS_KR_X_1992_MS (0x04) #define CS_KR_ISO10646 (0x08) -/* Korean encodings and charsets */ +// Korean encodings and charsets static struct prt_ps_encoding_S k_encodings[] = { {"iso-2022-kr", NULL, CS_KR_X_1992}, @@ -1167,7 +1171,7 @@ static struct prt_ps_mbfont_S prt_ps_mbfonts[] = } }; -/* Types of PS resource file currently used */ +// Types of PS resource file currently used #define PRT_RESOURCE_TYPE_PROCSET (0) #define PRT_RESOURCE_TYPE_ENCODING (1) #define PRT_RESOURCE_TYPE_CMAP (2) @@ -1195,7 +1199,7 @@ static char *prt_resource_types[] = "cmap" }; -/* Strings to look for in a PS resource file */ +// Strings to look for in a PS resource file #define PRT_RESOURCE_HEADER "%!PS-Adobe-" #define PRT_RESOURCE_RESOURCE "Resource-" #define PRT_RESOURCE_PROCSET "ProcSet" @@ -1255,20 +1259,20 @@ static double prt_pos_y_moveto = 0.0; * Various control variables used to decide when and how to change the * PostScript graphics state. */ -static int prt_need_moveto; -static int prt_do_moveto; -static int prt_need_font; +static bool prt_need_moveto; +static bool prt_do_moveto; +static bool prt_need_font; static int prt_font; -static int prt_need_underline; +static bool prt_need_underline; static TriState prt_underline; static TriState prt_do_underline; -static int prt_need_fgcol; +static bool prt_need_fgcol; static uint32_t prt_fgcol; -static int prt_need_bgcol; -static int prt_do_bgcol; +static bool prt_need_bgcol; +static bool prt_do_bgcol; static uint32_t prt_bgcol; static uint32_t prt_new_bgcol; -static int prt_attribute_change; +static bool prt_attribute_change; static double prt_text_run; static int prt_page_num; static int prt_bufsiz; @@ -1296,8 +1300,8 @@ static int prt_out_mbyte; static int prt_custom_cmap; static char prt_cmap[80]; static int prt_use_courier; -static int prt_in_ascii; -static int prt_half_width; +static bool prt_in_ascii; +static bool prt_half_width; static char *prt_ascii_encoding; static char_u prt_hexchar[] = "0123456789abcdef"; @@ -1416,18 +1420,19 @@ static void prt_write_real(double val, int prec) int fraction; prt_real_bits(val, prec, &integer, &fraction); - /* Emit integer part */ - sprintf((char *)prt_line_buffer, "%d", integer); + // Emit integer part + snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%d", integer); prt_write_file(prt_line_buffer); - /* Only emit fraction if necessary */ + // Only emit fraction if necessary if (fraction != 0) { - /* Remove any trailing zeros */ + // Remove any trailing zeros while ((fraction % 10) == 0) { prec--; fraction /= 10; } - /* Emit fraction left padded with zeros */ - sprintf((char *)prt_line_buffer, ".%0*d", prec, fraction); + // Emit fraction left padded with zeros + snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), ".%0*d", + prec, fraction); prt_write_file(prt_line_buffer); } sprintf((char *)prt_line_buffer, " "); @@ -1447,13 +1452,13 @@ static void prt_def_var(char *name, double value, int prec) prt_write_file(prt_line_buffer); } -/* Convert size from font space to user space at current font scale */ +// Convert size from font space to user space at current font scale #define PRT_PS_FONT_TO_USER(scale, size) ((size) * ((scale)/1000.0)) static void prt_flush_buffer(void) { if (!GA_EMPTY(&prt_ps_buffer)) { - /* Any background color must be drawn first */ + // Any background color must be drawn first if (prt_do_bgcol && (prt_new_bgcol != PRCOLOR_WHITE)) { unsigned int r, g, b; @@ -1461,14 +1466,14 @@ static void prt_flush_buffer(void) prt_write_real(prt_pos_x_moveto, 2); prt_write_real(prt_pos_y_moveto, 2); prt_write_string("m\n"); - prt_do_moveto = FALSE; + prt_do_moveto = false; } - /* Size of rect of background color on which text is printed */ + // Size of rect of background color on which text is printed prt_write_real(prt_text_run, 2); prt_write_real(prt_line_height, 2); - /* Lastly add the color of the background */ + // Lastly add the color of the background r = (prt_new_bgcol & 0xff0000) >> 16; g = (prt_new_bgcol & 0xff00) >> 8; b = prt_new_bgcol & 0xff; @@ -1485,10 +1490,10 @@ static void prt_flush_buffer(void) prt_write_real(prt_pos_x_moveto, 2); prt_write_real(prt_pos_y_moveto, 2); prt_write_string("m\n"); - prt_do_moveto = FALSE; + prt_do_moveto = false; } - /* Underline length of text run */ + // Underline length of text run prt_write_real(prt_text_run, 2); prt_write_string("ul\n"); } @@ -1503,16 +1508,16 @@ static void prt_flush_buffer(void) prt_write_string(">"); else prt_write_string(")"); - /* Add a moveto if need be and use the appropriate show procedure */ + // Add a moveto if need be and use the appropriate show procedure if (prt_do_moveto) { prt_write_real(prt_pos_x_moveto, 2); prt_write_real(prt_pos_y_moveto, 2); - /* moveto and a show */ + // moveto and a show prt_write_string("ms\n"); - prt_do_moveto = FALSE; - } else /* Simple show */ + prt_do_moveto = false; + } else { // Simple show prt_write_string("s\n"); - + } ga_clear(&prt_ps_buffer); ga_init(&prt_ps_buffer, (int)sizeof(char), prt_bufsiz); } @@ -1536,7 +1541,7 @@ static int prt_find_resource(char *name, struct prt_ps_resource_S *resource) buffer = xmallocz(MAXPATHL); STRLCPY(resource->name, name, 64); - /* Look for named resource file in runtimepath */ + // Look for named resource file in runtimepath STRCPY(buffer, "print"); add_pathsep((char *)buffer); xstrlcat((char *)buffer, name, MAXPATHL); @@ -1548,7 +1553,7 @@ static int prt_find_resource(char *name, struct prt_ps_resource_S *resource) return retval; } -/* PS CR and LF characters have platform independent values */ +// PS CR and LF characters have platform independent values #define PSLF (0x0a) #define PSCR (0x0d) @@ -1558,7 +1563,7 @@ static int prt_resfile_next_line(void) { int idx; - /* Move to start of next line and then find end of line */ + // Move to start of next line and then find end of line idx = prt_resfile.line_end + 1; while (idx < prt_resfile.len) { if (prt_resfile.buffer[idx] != PSLF && prt_resfile.buffer[idx] != PSCR) @@ -1577,12 +1582,13 @@ static int prt_resfile_next_line(void) return idx < prt_resfile.len; } -static int prt_resfile_strncmp(int offset, char *string, int len) +static int prt_resfile_strncmp(int offset, const char *string, int len) + FUNC_ATTR_NONNULL_ALL { - /* Force not equal if string is longer than remainder of line */ - if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset))) + // Force not equal if string is longer than remainder of line + if (len > (prt_resfile.line_end - (prt_resfile.line_start + offset))) { return 1; - + } return STRNCMP(&prt_resfile.buffer[prt_resfile.line_start + offset], string, len); } @@ -1615,178 +1621,182 @@ static int prt_resfile_skip_ws(int offset) /* prt_next_dsc() - returns detail on next DSC comment line found. Returns true * if a DSC comment is found, else false */ -static int prt_next_dsc(struct prt_dsc_line_S *p_dsc_line) +static bool prt_next_dsc(struct prt_dsc_line_S *p_dsc_line) + FUNC_ATTR_NONNULL_ALL { int comment; int offset; - /* Move to start of next line */ - if (!prt_resfile_next_line()) - return FALSE; - - /* DSC comments always start %% */ - if (prt_resfile_strncmp(0, "%%", 2) != 0) - return FALSE; - - /* Find type of DSC comment */ - for (comment = 0; comment < (int)ARRAY_SIZE(prt_dsc_table); comment++) + // Move to start of next line + if (!prt_resfile_next_line()) { + return false; + } + // DSC comments always start %% + if (prt_resfile_strncmp(0, "%%", 2) != 0) { + return false; + } + // Find type of DSC comment + for (comment = 0; comment < (int)ARRAY_SIZE(prt_dsc_table); comment++) { if (prt_resfile_strncmp(0, prt_dsc_table[comment].string, - prt_dsc_table[comment].len) == 0) + prt_dsc_table[comment].len) == 0) { break; - + } + } if (comment != ARRAY_SIZE(prt_dsc_table)) { - /* Return type of comment */ + // Return type of comment p_dsc_line->type = prt_dsc_table[comment].type; offset = prt_dsc_table[comment].len; } else { - /* Unrecognised DSC comment, skip to ws after comment leader */ + // Unrecognised DSC comment, skip to ws after comment leader p_dsc_line->type = PRT_DSC_MISC_TYPE; offset = prt_resfile_skip_nonws(0); - if (offset == -1) - return FALSE; + if (offset == -1) { + return false; + } } - /* Skip ws to comment value */ + // Skip ws to comment value offset = prt_resfile_skip_ws(offset); - if (offset == -1) - return FALSE; - + if (offset == -1) { + return false; + } p_dsc_line->string = &prt_resfile.buffer[prt_resfile.line_start + offset]; p_dsc_line->len = prt_resfile.line_end - (prt_resfile.line_start + offset); - return TRUE; + return true; } /* Improved hand crafted parser to get the type, title, and version number of a * PS resource file so the file details can be added to the DSC header comments. */ -static int prt_open_resource(struct prt_ps_resource_S *resource) +static bool prt_open_resource(struct prt_ps_resource_S *resource) + FUNC_ATTR_NONNULL_ALL { - int offset; - int seen_all; - int seen_title; - int seen_version; - FILE *fd_resource; struct prt_dsc_line_S dsc_line; - fd_resource = os_fopen((char *)resource->filename, READBIN); + FILE *fd_resource = os_fopen((char *)resource->filename, READBIN); if (fd_resource == NULL) { EMSG2(_("E624: Can't open file \"%s\""), resource->filename); - return FALSE; + return false; } memset(prt_resfile.buffer, NUL, PRT_FILE_BUFFER_LEN); - /* Parse first line to ensure valid resource file */ + // Parse first line to ensure valid resource file prt_resfile.len = (int)fread((char *)prt_resfile.buffer, sizeof(char_u), PRT_FILE_BUFFER_LEN, fd_resource); if (ferror(fd_resource)) { EMSG2(_("E457: Can't read PostScript resource file \"%s\""), resource->filename); fclose(fd_resource); - return FALSE; + return false; } fclose(fd_resource); prt_resfile.line_end = -1; prt_resfile.line_start = 0; - if (!prt_resfile_next_line()) - return FALSE; - - offset = 0; + if (!prt_resfile_next_line()) { + return false; + } + int offset = 0; if (prt_resfile_strncmp(offset, PRT_RESOURCE_HEADER, (int)STRLEN(PRT_RESOURCE_HEADER)) != 0) { EMSG2(_("E618: file \"%s\" is not a PostScript resource file"), - resource->filename); - return FALSE; + resource->filename); + return false; } - /* Skip over any version numbers and following ws */ + // Skip over any version numbers and following ws offset += (int)STRLEN(PRT_RESOURCE_HEADER); offset = prt_resfile_skip_nonws(offset); - if (offset == -1) - return FALSE; + if (offset == -1) { + return false; + } offset = prt_resfile_skip_ws(offset); - if (offset == -1) - return FALSE; - + if (offset == -1) { + return false; + } if (prt_resfile_strncmp(offset, PRT_RESOURCE_RESOURCE, (int)STRLEN(PRT_RESOURCE_RESOURCE)) != 0) { EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), - resource->filename); - return FALSE; + resource->filename); + return false; } offset += (int)STRLEN(PRT_RESOURCE_RESOURCE); - /* Decide type of resource in the file */ + // Decide type of resource in the file if (prt_resfile_strncmp(offset, PRT_RESOURCE_PROCSET, - (int)STRLEN(PRT_RESOURCE_PROCSET)) == 0) + (int)STRLEN(PRT_RESOURCE_PROCSET)) == 0) { resource->type = PRT_RESOURCE_TYPE_PROCSET; - else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING, - (int)STRLEN(PRT_RESOURCE_ENCODING)) == 0) + } else if (prt_resfile_strncmp(offset, PRT_RESOURCE_ENCODING, + (int)STRLEN(PRT_RESOURCE_ENCODING)) == 0) { resource->type = PRT_RESOURCE_TYPE_ENCODING; - else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP, - (int)STRLEN(PRT_RESOURCE_CMAP)) == 0) + } else if (prt_resfile_strncmp(offset, PRT_RESOURCE_CMAP, + (int)STRLEN(PRT_RESOURCE_CMAP)) == 0) { resource->type = PRT_RESOURCE_TYPE_CMAP; - else { + } else { EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), - resource->filename); - return FALSE; + resource->filename); + return false; } - /* Look for title and version of resource */ + // Look for title and version of resource resource->title[0] = '\0'; resource->version[0] = '\0'; - seen_title = FALSE; - seen_version = FALSE; - seen_all = FALSE; + bool seen_title = false; + bool seen_version = false; + bool seen_all = false; while (!seen_all && prt_next_dsc(&dsc_line)) { switch (dsc_line.type) { case PRT_DSC_TITLE_TYPE: STRLCPY(resource->title, dsc_line.string, dsc_line.len + 1); - seen_title = TRUE; - if (seen_version) - seen_all = TRUE; + seen_title = true; + if (seen_version) { + seen_all = true; + } break; case PRT_DSC_VERSION_TYPE: STRLCPY(resource->version, dsc_line.string, dsc_line.len + 1); - seen_version = TRUE; - if (seen_title) - seen_all = TRUE; + seen_version = true; + if (seen_title) { + seen_all = true; + } break; case PRT_DSC_ENDCOMMENTS_TYPE: - /* Wont find title or resource after this comment, stop searching */ - seen_all = TRUE; + // Wont find title or resource after this comment, stop searching + seen_all = true; break; case PRT_DSC_MISC_TYPE: - /* Not interested in whatever comment this line had */ + // Not interested in whatever comment this line had break; } } if (!seen_title || !seen_version) { EMSG2(_("E619: file \"%s\" is not a supported PostScript resource file"), - resource->filename); - return FALSE; + resource->filename); + return false; } - return TRUE; + return true; } -static int prt_check_resource(struct prt_ps_resource_S *resource, char_u *version) +static bool prt_check_resource(const struct prt_ps_resource_S *resource, + const char_u *version) + FUNC_ATTR_NONNULL_ALL { - /* Version number m.n should match, the revision number does not matter */ + // Version number m.n should match, the revision number does not matter if (STRNCMP(resource->version, version, STRLEN(version))) { EMSG2(_("E621: \"%s\" resource file has wrong version"), - resource->name); - return FALSE; + resource->name); + return false; } - /* Other checks to be added as needed */ - return TRUE; + // Other checks to be added as needed + return true; } static void prt_dsc_start(void) @@ -1810,7 +1820,7 @@ static void prt_dsc_textline(char *comment, char *text) static void prt_dsc_text(char *comment, char *text) { - /* TODO - should scan 'text' for any chars needing escaping! */ + // TODO(vim): - should scan 'text' for any chars needing escaping! vim_snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%%%%%s: (%s)\n", comment, text); prt_write_file(prt_line_buffer); @@ -1834,9 +1844,8 @@ static void prt_dsc_ints(char *comment, int count, int *ints) prt_write_string("\n"); } -static void -prt_dsc_resources ( - char *comment, /* if NULL add to previous */ +static void prt_dsc_resources( + char *comment, // if NULL add to previous char *type, char *string ) @@ -1887,8 +1896,9 @@ static void prt_dsc_requirements(int duplex, int tumble, int collate, int color, prt_write_string(" color"); if (num_copies > 1) { prt_write_string(" numcopies("); - /* Note: no space wanted so don't use prt_write_int() */ - sprintf((char *)prt_line_buffer, "%d", num_copies); + // Note: no space wanted so don't use prt_write_int() + snprintf((char *)prt_line_buffer, sizeof(prt_line_buffer), "%d", + num_copies); prt_write_file(prt_line_buffer); prt_write_string(")"); } @@ -2038,13 +2048,13 @@ static int prt_get_lpp(void) prt_ps_font->bbox_min_y)) / 2); } - /* Get height for topmost line based on background rect offset. */ + // Get height for topmost line based on background rect offset. prt_first_line_height = prt_line_height + prt_bgcol_offset; - /* Calculate lpp */ + // Calculate lpp lpp = (int)((prt_top_margin - prt_bottom_margin) / prt_line_height); - /* Adjust top margin if there is a header */ + // Adjust top margin if there is a header prt_top_margin -= prt_line_height * prt_header_height(); return lpp - prt_header_height(); @@ -2057,7 +2067,7 @@ static int prt_match_encoding(char *p_encoding, struct prt_ps_mbfont_S *p_cmap, struct prt_ps_encoding_S *p_mbenc; *pp_mbenc = NULL; - /* Look for recognised encoding */ + // Look for recognised encoding enc_len = (int)STRLEN(p_encoding); p_mbenc = p_cmap->encodings; for (mbenc = 0; mbenc < p_cmap->num_encodings; mbenc++) { @@ -2076,9 +2086,10 @@ static int prt_match_charset(char *p_charset, struct prt_ps_mbfont_S *p_cmap, st int char_len; struct prt_ps_charset_S *p_mbchar; - /* Look for recognised character set, using default if one is not given */ - if (*p_charset == NUL) + // Look for recognised character set, using default if one is not given + if (*p_charset == NUL) { p_charset = p_cmap->defcs; + } char_len = (int)STRLEN(p_charset); p_mbchar = p_cmap->charsets; for (mbchar = 0; mbchar < p_cmap->num_charsets; mbchar++) { @@ -2133,7 +2144,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) break; } - /* Use first encoding matched if no charset matched */ + // Use first encoding matched if no charset matched if (p_mbenc_first != NULL && p_mbchar == NULL) { p_mbenc = p_mbenc_first; cmap = effective_cmap; @@ -2144,24 +2155,24 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) prt_out_mbyte = (p_mbenc != NULL); if (prt_out_mbyte) { - /* Build CMap name - will be same for all multi-byte fonts used */ + // Build CMap name - will be same for all multi-byte fonts used prt_cmap[0] = NUL; prt_custom_cmap = (p_mbchar == NULL); if (!prt_custom_cmap) { - /* Check encoding and character set are compatible */ + // Check encoding and character set are compatible if ((p_mbenc->needs_charset & p_mbchar->has_charset) == 0) { EMSG(_("E673: Incompatible multi-byte encoding and character set.")); return FALSE; } - /* Add charset name if not empty */ + // Add charset name if not empty if (p_mbchar->cmap_charset != NULL) { STRLCPY(prt_cmap, p_mbchar->cmap_charset, sizeof(prt_cmap) - 2); STRCAT(prt_cmap, "-"); } } else { - /* Add custom CMap character set name */ + // Add custom CMap character set name if (*p_pmcs == NUL) { EMSG(_("E674: printmbcharset cannot be empty with multi-byte encoding.")); return FALSE; @@ -2170,7 +2181,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) STRCAT(prt_cmap, "-"); } - /* CMap name ends with (optional) encoding name and -H for horizontal */ + // CMap name ends with (optional) encoding name and -H for horizontal if (p_mbenc->cmap_encoding != NULL && STRLEN(prt_cmap) + STRLEN(p_mbenc->cmap_encoding) + 3 < sizeof(prt_cmap)) { STRCAT(prt_cmap, p_mbenc->cmap_encoding); @@ -2183,7 +2194,7 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) return FALSE; } - /* Derive CID font names with fallbacks if not defined */ + // Derive CID font names with fallbacks if not defined prt_build_cid_fontname(PRT_PS_FONT_ROMAN, mbfont_opts[OPT_MBFONT_REGULAR].string, mbfont_opts[OPT_MBFONT_REGULAR].strlen); @@ -2288,9 +2299,10 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) psettings->chars_per_line = prt_get_cpl(); psettings->lines_per_page = prt_get_lpp(); - /* Catch margin settings that leave no space for output! */ - if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0) + // Catch margin settings that leave no space for output! + if (psettings->chars_per_line <= 0 || psettings->lines_per_page <= 0) { return FAIL; + } /* * Sort out the number of copies to be printed. PS by default will do @@ -2329,10 +2341,10 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) prt_tumble = TRUE; } - /* For now user abort not supported */ + // For now user abort not supported psettings->user_abort = 0; - /* If the user didn't specify a file name, use a temp file. */ + // If the user didn't specify a file name, use a temp file. if (psettings->outfile == NULL) { prt_ps_file_name = vim_tempname(); if (prt_ps_file_name == NULL) { @@ -2360,12 +2372,12 @@ int mch_print_init(prt_settings_T *psettings, char_u *jobname, int forceit) prt_page_num = 0; - prt_attribute_change = FALSE; - prt_need_moveto = FALSE; - prt_need_font = FALSE; - prt_need_fgcol = FALSE; - prt_need_bgcol = FALSE; - prt_need_underline = FALSE; + prt_attribute_change = false; + prt_need_moveto = false; + prt_need_font = false; + prt_need_fgcol = false; + prt_need_bgcol = false; + prt_need_underline = false; prt_file_error = FALSE; @@ -2416,9 +2428,7 @@ static int prt_add_resource(struct prt_ps_resource_S *resource) int mch_print_begin(prt_settings_T *psettings) { - time_t now; int bbox[4]; - char *p_time; double left; double right; double top; @@ -2442,10 +2452,10 @@ int mch_print_begin(prt_settings_T *psettings) } prt_dsc_textline("For", buffer); prt_dsc_textline("Creator", longVersion); - /* Note: to ensure Clean8bit I don't think we can use LC_TIME */ - now = time(NULL); - p_time = ctime(&now); - /* Note: ctime() adds a \n so we have to remove it :-( */ + // Note: to ensure Clean8bit I don't think we can use LC_TIME + char ctime_buf[50]; + char *p_time = os_ctime(ctime_buf, sizeof(ctime_buf)); + // Note: os_ctime() adds a \n so we have to remove it :-( p = vim_strchr((char_u *)p_time, '\n'); if (p != NULL) *p = NUL; @@ -2483,14 +2493,15 @@ int mch_print_begin(prt_settings_T *psettings) + 0.5); } prt_dsc_ints("BoundingBox", 4, bbox); - /* The media width and height does not change with landscape printing! */ + // The media width and height does not change with landscape printing! prt_dsc_docmedia(prt_mediasize[prt_media].name, - prt_mediasize[prt_media].width, - prt_mediasize[prt_media].height, - (double)0, NULL, NULL); - /* Define fonts needed */ - if (!prt_out_mbyte || prt_use_courier) + prt_mediasize[prt_media].width, + prt_mediasize[prt_media].height, + (double)0, NULL, NULL); + // Define fonts needed + if (!prt_out_mbyte || prt_use_courier) { prt_dsc_font_resource("DocumentNeededResources", &prt_ps_courier_font); + } if (prt_out_mbyte) { prt_dsc_font_resource((prt_use_courier ? NULL : "DocumentNeededResources"), &prt_ps_mb_font); @@ -2498,7 +2509,7 @@ int mch_print_begin(prt_settings_T *psettings) prt_dsc_resources(NULL, "cmap", prt_cmap); } - /* Search for external resources VIM supplies */ + // Search for external resources VIM supplies if (!prt_find_resource("prolog", &res_prolog)) { EMSG(_("E456: Can't find PostScript resource file \"prolog.ps\"")); return FALSE; @@ -2508,7 +2519,7 @@ int mch_print_begin(prt_settings_T *psettings) if (!prt_check_resource(&res_prolog, PRT_PROLOG_VERSION)) return FALSE; if (prt_out_mbyte) { - /* Look for required version of multi-byte printing procset */ + // Look for required version of multi-byte printing procset if (!prt_find_resource("cidfont", &res_cidfont)) { EMSG(_("E456: Can't find PostScript resource file \"cidfont.ps\"")); return FALSE; @@ -2528,15 +2539,15 @@ int mch_print_begin(prt_settings_T *psettings) p_encoding = enc_skip(p_penc); if (*p_encoding == NUL || !prt_find_resource((char *)p_encoding, &res_encoding)) { - /* 'printencoding' not set or not supported - find alternate */ + // 'printencoding' not set or not supported - find alternate int props; p_encoding = enc_skip(p_enc); props = enc_canon_props(p_encoding); if (!(props & ENC_8BIT) || !prt_find_resource((char *)p_encoding, &res_encoding)) { - /* 8-bit 'encoding' is not supported */ - /* Use latin1 as default printing encoding */ + // 8-bit 'encoding' is not supported + // Use latin1 as default printing encoding p_encoding = (char_u *)"latin1"; if (!prt_find_resource((char *)p_encoding, &res_encoding)) { EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), @@ -2554,7 +2565,7 @@ int mch_print_begin(prt_settings_T *psettings) if (*p_encoding == NUL) p_encoding = enc_skip(p_enc); if (prt_use_courier) { - /* Include ASCII range encoding vector */ + // Include ASCII range encoding vector if (!prt_find_resource(prt_ascii_encoding, &res_encoding)) { EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), prt_ascii_encoding); @@ -2579,7 +2590,7 @@ int mch_print_begin(prt_settings_T *psettings) prt_do_conv = prt_conv.vc_type != CONV_NONE; if (prt_out_mbyte && prt_custom_cmap) { - /* Find user supplied CMap */ + // Find user supplied CMap if (!prt_find_resource(prt_cmap, &res_cmap)) { EMSG2(_("E456: Can't find PostScript resource file \"%s.ps\""), prt_cmap); @@ -2589,7 +2600,7 @@ int mch_print_begin(prt_settings_T *psettings) return FALSE; } - /* List resources supplied */ + // List resources supplied STRCPY(buffer, res_prolog.title); STRCAT(buffer, " "); STRCAT(buffer, res_prolog.version); @@ -2623,9 +2634,10 @@ int mch_print_begin(prt_settings_T *psettings) */ prt_dsc_noarg("BeginDefaults"); - /* List font resources most likely common to all pages */ - if (!prt_out_mbyte || prt_use_courier) + // List font resources most likely common to all pages + if (!prt_out_mbyte || prt_use_courier) { prt_dsc_font_resource("PageResources", &prt_ps_courier_font); + } if (prt_out_mbyte) { prt_dsc_font_resource((prt_use_courier ? NULL : "PageResources"), &prt_ps_mb_font); @@ -2633,7 +2645,7 @@ int mch_print_begin(prt_settings_T *psettings) prt_dsc_resources(NULL, "cmap", prt_cmap); } - /* Paper will be used for all pages */ + // Paper will be used for all pages prt_dsc_textline("PageMedia", prt_mediasize[prt_media].name); prt_dsc_noarg("EndDefaults"); @@ -2643,15 +2655,18 @@ int mch_print_begin(prt_settings_T *psettings) */ prt_dsc_noarg("BeginProlog"); - /* Add required procsets - NOTE: order is important! */ - if (!prt_add_resource(&res_prolog)) - return FALSE; + // Add required procsets - NOTE: order is important! + if (!prt_add_resource(&res_prolog)) { + return false; + } if (prt_out_mbyte) { - /* Add CID font procset, and any user supplied CMap */ - if (!prt_add_resource(&res_cidfont)) - return FALSE; - if (prt_custom_cmap && !prt_add_resource(&res_cmap)) - return FALSE; + // Add CID font procset, and any user supplied CMap + if (!prt_add_resource(&res_cidfont)) { + return false; + } + if (prt_custom_cmap && !prt_add_resource(&res_cmap)) { + return false; + } } if (!prt_out_mbyte || prt_use_courier) @@ -2667,7 +2682,7 @@ int mch_print_begin(prt_settings_T *psettings) */ prt_dsc_noarg("BeginSetup"); - /* Device setup - page size and number of uncollated copies */ + // Device setup - page size and number of uncollated copies prt_write_int((int)prt_mediasize[prt_media].width); prt_write_int((int)prt_mediasize[prt_media].height); prt_write_int(0); @@ -2680,7 +2695,7 @@ int mch_print_begin(prt_settings_T *psettings) prt_write_boolean(prt_collate); prt_write_string("c\n"); - /* Font resource inclusion and definition */ + // Font resource inclusion and definition if (!prt_out_mbyte || prt_use_courier) { /* When using Courier for ASCII range when printing multi-byte, need to * pick up ASCII encoding to use with it. */ @@ -2723,35 +2738,36 @@ int mch_print_begin(prt_settings_T *psettings) if (!prt_custom_cmap) prt_dsc_resources("IncludeResource", "cmap", prt_cmap); prt_def_cidfont("CF1", (int)prt_line_height, - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]); - } else - /* Use ROMAN for BOLD */ + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLD]); + } else { + // Use ROMAN for BOLD prt_dup_cidfont("CF0", "CF1"); - + } if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE] != NULL) { prt_dsc_resources("IncludeResource", "font", prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); if (!prt_custom_cmap) prt_dsc_resources("IncludeResource", "cmap", prt_cmap); prt_def_cidfont("CF2", (int)prt_line_height, - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); - } else - /* Use ROMAN for OBLIQUE */ + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_OBLIQUE]); + } else { + // Use ROMAN for OBLIQUE prt_dup_cidfont("CF0", "CF2"); - + } if (prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE] != NULL) { prt_dsc_resources("IncludeResource", "font", prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); if (!prt_custom_cmap) prt_dsc_resources("IncludeResource", "cmap", prt_cmap); prt_def_cidfont("CF3", (int)prt_line_height, - prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); - } else - /* Use BOLD for BOLDOBLIQUE */ + prt_ps_mb_font.ps_fontname[PRT_PS_FONT_BOLDOBLIQUE]); + } else { + // Use BOLD for BOLDOBLIQUE prt_dup_cidfont("CF1", "CF3"); + } } - /* Misc constant vars used for underlining and background rects */ + // Misc constant vars used for underlining and background rects prt_def_var("UO", PRT_PS_FONT_TO_USER(prt_line_height, prt_ps_font->uline_offset), 2); prt_def_var("UW", PRT_PS_FONT_TO_USER(prt_line_height, @@ -2760,7 +2776,7 @@ int mch_print_begin(prt_settings_T *psettings) prt_dsc_noarg("EndSetup"); - /* Fail if any problems writing out to the PS file */ + // Fail if any problems writing out to the PS file retval = !prt_file_error; return retval; @@ -2783,7 +2799,7 @@ void mch_print_end(prt_settings_T *psettings) if (!prt_file_error && psettings->outfile == NULL && !got_int && !psettings->user_abort) { - /* Close the file first. */ + // Close the file first. if (prt_ps_fd != NULL) { fclose(prt_ps_fd); prt_ps_fd = NULL; @@ -2834,7 +2850,7 @@ int mch_print_begin_page(char_u *str) prt_bgcol = PRCOLOR_WHITE; prt_font = PRT_PS_FONT_ROMAN; - /* Set up page transformation for landscape printing. */ + // Set up page transformation for landscape printing. if (!prt_portrait) { prt_write_int(-((int)prt_mediasize[prt_media].width)); prt_write_string("sl\n"); @@ -2842,7 +2858,7 @@ int mch_print_begin_page(char_u *str) prt_dsc_noarg("EndPageSetup"); - /* We have reset the font attributes, force setting them again. */ + // We have reset the font attributes, force setting them again. curr_bg = 0xffffffff; curr_fg = 0xffffffff; curr_bold = kNone; @@ -2868,9 +2884,9 @@ void mch_print_start_line(const bool margin, const int page_line) prt_pos_y = prt_top_margin - prt_first_line_height - page_line * prt_line_height; - prt_attribute_change = TRUE; - prt_need_moveto = TRUE; - prt_half_width = FALSE; + prt_attribute_change = true; + prt_need_moveto = true; + prt_half_width = false; } int mch_print_text_out(char_u *const textp, size_t len) @@ -2892,16 +2908,16 @@ int mch_print_text_out(char_u *const textp, size_t len) const bool in_ascii = (len == 1 && *p < 0x80); if (prt_in_ascii) { if (!in_ascii) { - /* No longer in ASCII range - need to switch font */ - prt_in_ascii = FALSE; - prt_need_font = TRUE; - prt_attribute_change = TRUE; + // No longer in ASCII range - need to switch font + prt_in_ascii = false; + prt_need_font = true; + prt_attribute_change = true; } } else if (in_ascii) { - /* Now in ASCII range - need to switch font */ - prt_in_ascii = TRUE; - prt_need_font = TRUE; - prt_attribute_change = TRUE; + // Now in ASCII range - need to switch font + prt_in_ascii = true; + prt_need_font = true; + prt_attribute_change = true; } } if (prt_out_mbyte) { @@ -2911,16 +2927,16 @@ int mch_print_text_out(char_u *const textp, size_t len) } if (prt_half_width) { if (!half_width) { - prt_half_width = FALSE; + prt_half_width = false; prt_pos_x += prt_char_width/4; - prt_need_moveto = TRUE; - prt_attribute_change = TRUE; + prt_need_moveto = true; + prt_attribute_change = true; } } else if (half_width) { - prt_half_width = TRUE; + prt_half_width = true; prt_pos_x += prt_char_width/4; - prt_need_moveto = TRUE; - prt_attribute_change = TRUE; + prt_need_moveto = true; + prt_attribute_change = true; } } @@ -2929,24 +2945,25 @@ int mch_print_text_out(char_u *const textp, size_t len) */ if (prt_attribute_change) { prt_flush_buffer(); - /* Reset count of number of chars that will be printed */ + // Reset count of number of chars that will be printed prt_text_run = 0; if (prt_need_moveto) { prt_pos_x_moveto = prt_pos_x; prt_pos_y_moveto = prt_pos_y; - prt_do_moveto = TRUE; + prt_do_moveto = true; - prt_need_moveto = FALSE; + prt_need_moveto = false; } if (prt_need_font) { - if (!prt_in_ascii) + if (!prt_in_ascii) { prt_write_string("CF"); - else + } else { prt_write_string("F"); + } prt_write_int(prt_font); prt_write_string("sf\n"); - prt_need_font = FALSE; + prt_need_font = false; } if (prt_need_fgcol) { unsigned int r, g, b; @@ -2962,22 +2979,24 @@ int mch_print_text_out(char_u *const textp, size_t len) prt_write_real(b / 255.0, 3); prt_write_string("r\n"); } - prt_need_fgcol = FALSE; + prt_need_fgcol = false; } if (prt_bgcol != PRCOLOR_WHITE) { prt_new_bgcol = prt_bgcol; - if (prt_need_bgcol) - prt_do_bgcol = TRUE; - } else - prt_do_bgcol = FALSE; - prt_need_bgcol = FALSE; + if (prt_need_bgcol) { + prt_do_bgcol = true; + } + } else { + prt_do_bgcol = false; + } + prt_need_bgcol = false; if (prt_need_underline) prt_do_underline = prt_underline; - prt_need_underline = FALSE; + prt_need_underline = false; - prt_attribute_change = FALSE; + prt_attribute_change = false; } if (prt_do_conv) { @@ -3062,29 +3081,29 @@ void mch_print_set_font(const TriState iBold, const TriState iItalic, if (font != prt_font) { prt_font = font; - prt_attribute_change = TRUE; - prt_need_font = TRUE; + prt_attribute_change = true; + prt_need_font = true; } if (prt_underline != iUnderline) { prt_underline = iUnderline; - prt_attribute_change = TRUE; - prt_need_underline = TRUE; + prt_attribute_change = true; + prt_need_underline = true; } } void mch_print_set_bg(uint32_t bgcol) { prt_bgcol = bgcol; - prt_attribute_change = TRUE; - prt_need_bgcol = TRUE; + prt_attribute_change = true; + prt_need_bgcol = true; } void mch_print_set_fg(uint32_t fgcol) { if (fgcol != prt_fgcol) { prt_fgcol = fgcol; - prt_attribute_change = TRUE; - prt_need_fgcol = TRUE; + prt_attribute_change = true; + prt_need_fgcol = true; } } diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 0f9984ec38..2af09f10cb 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -71,10 +71,10 @@ static void cs_usage_msg(csid_e x) static enum { - EXP_CSCOPE_SUBCMD, /* expand ":cscope" sub-commands */ - EXP_SCSCOPE_SUBCMD, /* expand ":scscope" sub-commands */ - EXP_CSCOPE_FIND, /* expand ":cscope find" arguments */ - EXP_CSCOPE_KILL /* expand ":cscope kill" arguments */ + EXP_CSCOPE_SUBCMD, // expand ":cscope" sub-commands + EXP_SCSCOPE_SUBCMD, // expand ":scscope" sub-commands + EXP_CSCOPE_FIND, // expand ":cscope find" arguments + EXP_CSCOPE_KILL // expand ":cscope kill" arguments } expand_what; /* @@ -87,13 +87,13 @@ char_u *get_cscope_name(expand_T *xp, int idx) switch (expand_what) { case EXP_CSCOPE_SUBCMD: - /* Complete with sub-commands of ":cscope": - * add, find, help, kill, reset, show */ + // Complete with sub-commands of ":cscope": + // add, find, help, kill, reset, show return (char_u *)cs_cmds[idx].name; case EXP_SCSCOPE_SUBCMD: { - /* Complete with sub-commands of ":scscope": same sub-commands as - * ":cscope" but skip commands which don't support split windows */ + // Complete with sub-commands of ":scscope": same sub-commands as + // ":cscope" but skip commands which don't support split windows int i; for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++) if (cs_cmds[i].cansplit) @@ -118,10 +118,10 @@ char_u *get_cscope_name(expand_T *xp, int idx) { static char connection[5]; - /* ":cscope kill" accepts connection numbers or partial names of - * the pathname of the cscope database as argument. Only complete - * with connection numbers. -1 can also be used to kill all - * connections. */ + // ":cscope kill" accepts connection numbers or partial names of + // the pathname of the cscope database as argument. Only complete + // with connection numbers. -1 can also be used to kill all + // connections. size_t i; for (i = 0, current_idx = 0; i < csinfo_size; i++) { if (csinfo[i].fname == NULL) @@ -149,7 +149,7 @@ void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx) expand_what = ((cmdidx == CMD_scscope) ? EXP_SCSCOPE_SUBCMD : EXP_CSCOPE_SUBCMD); - /* (part of) subcommand already typed */ + // (part of) subcommand already typed if (*arg != NUL) { const char *p = (const char *)skiptowhite((const char_u *)arg); if (*p != NUL) { // Past first word. @@ -175,7 +175,7 @@ void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx) static void do_cscope_general( exarg_T *eap, - int make_split /* whether to split window */ + int make_split // whether to split window ) { cscmd_T *cmdp; @@ -276,17 +276,19 @@ void ex_cstag(exarg_T *eap) /// This simulates a vim_fgets(), but for cscope, returns the next line /// from the cscope output. should only be called from find_tags() /// -/// @return TRUE if eof, FALSE otherwise -int cs_fgets(char_u *buf, int size) +/// @return true if eof, FALSE otherwise +bool cs_fgets(char_u *buf, int size) + FUNC_ATTR_NONNULL_ALL { char *p; - if ((p = cs_manage_matches(NULL, NULL, 0, Get)) == NULL) + if ((p = cs_manage_matches(NULL, NULL, 0, Get)) == NULL) { return true; + } STRLCPY(buf, p, size); - return FALSE; -} /* cs_fgets */ + return false; +} /// Called only from do_tag(), when popping the tag stack. @@ -328,48 +330,53 @@ void cs_print_tags(void) * * Note: All string comparisons are case sensitive! */ -int cs_connection(int num, char_u *dbpath, char_u *ppath) +bool cs_connection(int num, char_u *dbpath, char_u *ppath) { - if (num < 0 || num > 4 || (num > 0 && !dbpath)) + if (num < 0 || num > 4 || (num > 0 && !dbpath)) { return false; + } for (size_t i = 0; i < csinfo_size; i++) { - if (!csinfo[i].fname) + if (!csinfo[i].fname) { continue; - - if (num == 0) - return TRUE; - + } + if (num == 0) { + return true; + } switch (num) { case 1: - if (strstr(csinfo[i].fname, (char *)dbpath)) - return TRUE; + if (strstr(csinfo[i].fname, (char *)dbpath)) { + return true; + } break; case 2: - if (strcmp(csinfo[i].fname, (char *)dbpath) == 0) - return TRUE; + if (strcmp(csinfo[i].fname, (char *)dbpath) == 0) { + return true; + } break; case 3: if (strstr(csinfo[i].fname, (char *)dbpath) && ((!ppath && !csinfo[i].ppath) || (ppath && csinfo[i].ppath - && strstr(csinfo[i].ppath, (char *)ppath)))) - return TRUE; + && strstr(csinfo[i].ppath, (char *)ppath)))) { + return true; + } break; case 4: if ((strcmp(csinfo[i].fname, (char *)dbpath) == 0) && ((!ppath && !csinfo[i].ppath) || (ppath && csinfo[i].ppath - && (strcmp(csinfo[i].ppath, (char *)ppath) == 0)))) - return TRUE; + && (strcmp(csinfo[i].ppath, (char *)ppath) == 0)))) { + return true; + } break; } } - return FALSE; -} /* cs_connection */ + return false; +} // cs_connection /* @@ -419,7 +426,7 @@ cs_add_common( size_t usedlen = 0; char_u *fbuf = NULL; - /* get the filename (arg1), expand it, and try to stat it */ + // get the filename (arg1), expand it, and try to stat it fname = xmalloc(MAXPATHL + 1); expand_env((char_u *)arg1, (char_u *)fname, MAXPATHL); @@ -451,7 +458,7 @@ staterr: } int i; - /* if filename is a directory, append the cscope database name to it */ + // if filename is a directory, append the cscope database name to it if ((file_info.stat.st_mode & S_IFMT) == S_IFDIR) { fname2 = (char *)xmalloc(strlen(CSCOPE_DBFILE) + strlen(fname) + 2); @@ -512,18 +519,18 @@ add_err: xfree(fname); xfree(ppath); return CSCOPE_FAILURE; -} /* cs_add_common */ +} static int cs_check_for_connections(void) { return cs_cnt_connections() > 0; -} /* cs_check_for_connections */ +} static int cs_check_for_tags(void) { return p_tags[0] != NUL && curbuf->b_p_tags != NULL; -} /* cs_check_for_tags */ +} /// Count the number of cscope connections. static size_t cs_cnt_connections(void) @@ -535,10 +542,10 @@ static size_t cs_cnt_connections(void) cnt++; } return cnt; -} /* cs_cnt_connections */ +} static void cs_reading_emsg( - size_t idx /* connection index */ + size_t idx // connection index ) { EMSGU(_("E262: error reading cscope connection %" PRIu64), idx); @@ -602,7 +609,7 @@ static int cs_cnt_matches(size_t idx) xfree(buf); return nlines; -} /* cs_cnt_matches */ +} /// Creates the actual cscope command query from what the user entered. @@ -646,8 +653,8 @@ static char *cs_create_cmd(char *csoption, char *pattern) return NULL; } - /* Skip white space before the patter, except for text and pattern search, - * they may want to use the leading white space. */ + // Skip white space before the patter, except for text and pattern search, + // they may want to use the leading white space. pat = pattern; if (search != 4 && search != 6) while (ascii_iswhite(*pat)) @@ -658,7 +665,7 @@ static char *cs_create_cmd(char *csoption, char *pattern) (void)sprintf(cmd, "%d%s", search, pat); return cmd; -} /* cs_create_cmd */ +} /// This piece of code was taken/adapted from nvi. do we need to add @@ -694,15 +701,18 @@ err_closing: case -1: (void)EMSG(_("E622: Could not fork for cscope")); goto err_closing; - case 0: /* child: run cscope. */ - if (dup2(to_cs[0], STDIN_FILENO) == -1) + case 0: // child: run cscope. + if (dup2(to_cs[0], STDIN_FILENO) == -1) { PERROR("cs_create_connection 1"); - if (dup2(from_cs[1], STDOUT_FILENO) == -1) + } + if (dup2(from_cs[1], STDOUT_FILENO) == -1) { PERROR("cs_create_connection 2"); - if (dup2(from_cs[1], STDERR_FILENO) == -1) + } + if (dup2(from_cs[1], STDERR_FILENO) == -1) { PERROR("cs_create_connection 3"); + } - /* close unused */ + // close unused (void)close(to_cs[1]); (void)close(from_cs[0]); #else @@ -735,14 +745,14 @@ err_closing: return CSCOPE_FAILURE; } #endif - /* expand the cscope exec for env var's */ + // expand the cscope exec for env var's prog = xmalloc(MAXPATHL + 1); expand_env(p_csprg, (char_u *)prog, MAXPATHL); - /* alloc space to hold the cscope command */ + // alloc space to hold the cscope command size_t len = strlen(prog) + strlen(csinfo[i].fname) + 32; if (csinfo[i].ppath) { - /* expand the prepend path for env var's */ + // expand the prepend path for env var's ppath = xmalloc(MAXPATHL + 1); expand_env((char_u *)csinfo[i].ppath, (char_u *)ppath, MAXPATHL); @@ -754,12 +764,12 @@ err_closing: cmd = xmalloc(len); - /* run the cscope command; is there execl for non-unix systems? */ + // run the cscope command; is there execl for non-unix systems? #if defined(UNIX) - (void)sprintf(cmd, "exec %s -dl -f %s", prog, csinfo[i].fname); + (void)snprintf(cmd, len, "exec %s -dl -f %s", prog, csinfo[i].fname); #else - /* WIN32 */ - (void)sprintf(cmd, "%s -dl -f %s", prog, csinfo[i].fname); + // WIN32 + (void)snprintf(cmd, len, "%s -dl -f %s", prog, csinfo[i].fname); #endif if (csinfo[i].ppath != NULL) { (void)strcat(cmd, " -P"); @@ -770,14 +780,14 @@ err_closing: (void)strcat(cmd, csinfo[i].flags); } # ifdef UNIX - /* on Win32 we still need prog */ + // on Win32 we still need prog xfree(prog); # endif xfree(ppath); #if defined(UNIX) # if defined(HAVE_SETSID) || defined(HAVE_SETPGID) - /* Change our process group to avoid cscope receiving SIGWINCH. */ + // Change our process group to avoid cscope receiving SIGWINCH. # if defined(HAVE_SETSID) (void)setsid(); # else @@ -789,18 +799,18 @@ err_closing: PERROR(_("cs_create_connection exec failed")); exit(127); - /* NOTREACHED */ - default: /* parent. */ - /* - * Save the file descriptors for later duplication, and - * reopen as streams. - */ - if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL) + // NOTREACHED + default: // parent. + // Save the file descriptors for later duplication, and + // reopen as streams. + if ((csinfo[i].to_fp = fdopen(to_cs[1], "w")) == NULL) { PERROR(_("cs_create_connection: fdopen for to_fp failed")); - if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL) + } + if ((csinfo[i].fr_fp = fdopen(from_cs[0], "r")) == NULL) { PERROR(_("cs_create_connection: fdopen for fr_fp failed")); + } - /* close unused */ + // close unused (void)close(to_cs[0]); (void)close(from_cs[1]); @@ -808,11 +818,11 @@ err_closing: } #else - /* WIN32 */ - /* Create a new process to run cscope and use pipes to talk with it */ + // WIN32 + // Create a new process to run cscope and use pipes to talk with it GetStartupInfo(&si); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; /* Hide child application window */ + si.wShowWindow = SW_HIDE; // Hide child application window si.hStdOutput = stdout_wr; si.hStdError = stdout_wr; si.hStdInput = stdin_rd; @@ -826,7 +836,7 @@ err_closing: (void)EMSG(_("E623: Could not spawn cscope process")); goto err_closing; } - /* else */ + // else csinfo[i].pid = pi.dwProcessId; csinfo[i].hProc = pi.hProcess; CloseHandle(pi.hThread); @@ -844,10 +854,10 @@ err_closing: CloseHandle(stdin_rd); CloseHandle(stdout_wr); -#endif /* !UNIX */ +#endif // !UNIX return CSCOPE_SUCCESS; -} /* cs_create_connection */ +} /// Query cscope using command line interface. Parse the output and use tselect @@ -882,9 +892,9 @@ static int cs_find(exarg_T *eap) if (NUL == eap->arg[i]) eap->arg[i] = ' '; - return cs_find_common(opt, pat, eap->forceit, TRUE, - eap->cmdidx == CMD_lcscope, *eap->cmdlinep); -} /* cs_find */ + return cs_find_common(opt, pat, eap->forceit, true, + eap->cmdidx == CMD_lcscope, *eap->cmdlinep); +} /// Common code for cscope find, shared by cs_find() and ex_cstag(). @@ -897,7 +907,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, char cmdletter; char *qfpos; - /* get cmd letter */ + // get cmd letter switch (opt[0]) { case '0': cmdletter = 's'; @@ -933,10 +943,10 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, qfpos = (char *)vim_strchr(p_csqf, cmdletter); if (qfpos != NULL) { qfpos++; - /* next symbol must be + or - */ + // next symbol must be + or - if (strchr(CSQF_FLAGS, *qfpos) == NULL) { char *nf = _("E469: invalid cscopequickfix flag %c for %c"); - /* strlen will be enough because we use chars */ + // strlen will be enough because we use chars char *buf = xmalloc(strlen(nf)); sprintf(buf, nf, *qfpos, *(qfpos-1)); @@ -954,23 +964,24 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, } } - /* create the actual command to send to cscope */ + // create the actual command to send to cscope cmd = cs_create_cmd(opt, pat); if (cmd == NULL) return FALSE; nummatches = xmalloc(sizeof(int) * csinfo_size); - /* Send query to all open connections, then count the total number - * of matches so we can alloc all in one swell foop. */ - for (size_t i = 0; i < csinfo_size; i++) + // Send query to all open connections, then count the total number + // of matches so we can alloc all in one swell foop. + for (size_t i = 0; i < csinfo_size; i++) { nummatches[i] = 0; + } totmatches = 0; for (size_t i = 0; i < csinfo_size; i++) { if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL) continue; - /* send cmd to cscope */ + // send cmd to cscope (void)fprintf(csinfo[i].to_fp, "%s\n", cmd); (void)fflush(csinfo[i].to_fp); @@ -1014,8 +1025,9 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, } else { cs_file_results(f, nummatches); fclose(f); - if (use_ll) /* Use location list */ + if (use_ll) { // Use location list wp = curwin; + } // '-' starts a new error list if (qf_init(wp, tmp, (char_u *)"%f%*\\t%l%*\\t%m", *qfpos == '-', cmdline, NULL) > 0) { @@ -1046,7 +1058,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, char **matches = NULL, **contexts = NULL; size_t matched = 0; - /* read output */ + // read output cs_fill_results((char *)pat, totmatches, nummatches, &matches, &contexts, &matched); xfree(nummatches); @@ -1057,8 +1069,7 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, return do_tag((char_u *)pat, DT_CSCOPE, 0, forceit, verbose); } - -} /* cs_find_common */ +} /// Print help. static int cs_help(exarg_T *eap) @@ -1070,9 +1081,10 @@ static int cs_help(exarg_T *eap) char *help = _(cmdp->help); int space_cnt = 30 - vim_strsize((char_u *)help); - /* Use %*s rather than %30s to ensure proper alignment in utf-8 */ - if (space_cnt < 0) + // Use %*s rather than %30s to ensure proper alignment in utf-8 + if (space_cnt < 0) { space_cnt = 0; + } (void)smsg(_("%-5s: %s%*s (Usage: %s)"), cmdp->name, help, space_cnt, " ", @@ -1094,7 +1106,7 @@ static int cs_help(exarg_T *eap) wait_return(TRUE); return CSCOPE_SUCCESS; -} /* cs_help */ +} static void clear_csinfo(size_t i) @@ -1124,7 +1136,7 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, } if (csinfo[j].fname == NULL && !empty_found) { - i = j; /* remember first empty entry */ + i = j; // remember first empty entry empty_found = true; } } @@ -1132,13 +1144,13 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, if (!empty_found) { i = csinfo_size; if (csinfo_size == 0) { - /* First time allocation: allocate only 1 connection. It should - * be enough for most users. If more is needed, csinfo will be - * reallocated. */ + // First time allocation: allocate only 1 connection. It should + // be enough for most users. If more is needed, csinfo will be + // reallocated. csinfo_size = 1; csinfo = xcalloc(1, sizeof(csinfo_T)); } else { - /* Reallocate space for more connections. */ + // Reallocate space for more connections. csinfo_size *= 2; csinfo = xrealloc(csinfo, sizeof(csinfo_T)*csinfo_size); } @@ -1165,7 +1177,7 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, os_fileinfo_id(file_info, &(csinfo[i].file_id)); assert(i <= INT_MAX); return (int)i; -} /* cs_insert_filelist */ +} /// Find cscope command in command table. @@ -1178,7 +1190,7 @@ static cscmd_T * cs_lookup_cmd(exarg_T *eap) if (eap->arg == NULL) return NULL; - /* Store length of eap->arg before it gets modified by strtok(). */ + // Store length of eap->arg before it gets modified by strtok(). eap_arg_len = (int)STRLEN(eap->arg); if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL) @@ -1190,7 +1202,7 @@ static cscmd_T * cs_lookup_cmd(exarg_T *eap) return cmdp; } return NULL; -} /* cs_lookup_cmd */ +} /// Nuke em. @@ -1247,13 +1259,13 @@ static int cs_kill(exarg_T *eap) } return CSCOPE_SUCCESS; -} /* cs_kill */ +} /// Actually kills a specific cscope connection. static void cs_kill_execute( - size_t i, /* cscope table index */ - char *cname /* cscope database name */ + size_t i, // cscope table index + char *cname // cscope database name ) { if (p_csverbose) { @@ -1284,17 +1296,16 @@ static void cs_kill_execute( static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, char *tagstr) { - /* vim style is ctags: - * - * <tagstr>\t<filename>\t<linenum_or_search>"\t<extra> - * - * but as mentioned above, we'll always use the line number and - * put the search pattern (if one exists) as "extra" - * - * buf is used as part of vim's method of handling tags, and - * (i think) vim frees it when you pop your tags and get replaced - * by new ones on the tag stack. - */ + // vim style is ctags: + // + // <tagstr>\t<filename>\t<linenum_or_search>"\t<extra> + // + // but as mentioned above, we'll always use the line number and + // put the search pattern (if one exists) as "extra" + // + // buf is used as part of vim's method of handling tags, and + // (i think) vim frees it when you pop your tags and get replaced + // by new ones on the tag stack. char *buf; size_t amt; @@ -1311,7 +1322,7 @@ static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, } return buf; -} /* cs_make_vim_style_matches */ +} /// This is kind of hokey, but i don't see an easy way round this. @@ -1381,7 +1392,7 @@ static char *cs_manage_matches(char **matches, char **contexts, } return p; -} /* cs_manage_matches */ +} /// Parse cscope output. @@ -1408,7 +1419,7 @@ retry: return NULL; } - /* If the line's too long for the buffer, discard it. */ + // If the line's too long for the buffer, discard it. if ((p = strchr(buf, '\n')) == NULL) { while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n') ; @@ -1427,15 +1438,15 @@ retry: return NULL; if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL) return NULL; - *search = *linenumber + strlen(*linenumber) + 1; /* +1 to skip \0 */ + *search = *linenumber + strlen(*linenumber) + 1; // +1 to skip \0 - /* --- nvi --- - * If the file is older than the cscope database, that is, - * the database was built since the file was last modified, - * or there wasn't a search string, use the line number. - */ - if (strcmp(*search, "<unknown>") == 0) + // --- nvi --- + // If the file is older than the cscope database, that is, + // the database was built since the file was last modified, + // or there wasn't a search string, use the line number. + if (strcmp(*search, "<unknown>") == 0) { *search = NULL; + } name = cs_resolve_file(cnumber, name); return name; @@ -1474,11 +1485,10 @@ static void cs_file_results(FILE *f, int *nummatches_a) xfree(context); xfree(fullname); - } /* for all matches */ + } // for all matches (void)cs_read_prompt(i); - - } /* for all cscope connections */ + } // for all cscope connections xfree(buf); } @@ -1539,10 +1549,10 @@ static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a, *cntxts_p = cntxts; xfree(buf); -} // cs_fill_results +} -/* get the requested path components */ +// get the requested path components static char *cs_pathcomponents(char *path) { if (p_cspc == 0) { @@ -1688,7 +1698,7 @@ static int cs_read_prompt(size_t i) static char *eprompt = "Press the RETURN key to continue:"; size_t epromptlen = strlen(eprompt); - /* compute maximum allowed len for Cscope error message */ + // compute maximum allowed len for Cscope error message assert(IOSIZE >= cs_emsg_len); size_t maxlen = IOSIZE - cs_emsg_len; @@ -1738,11 +1748,12 @@ static int cs_read_prompt(size_t i) } if (ch == EOF) { PERROR("cs_read_prompt EOF"); - if (buf != NULL && buf[0] != NUL) + if (buf != NULL && buf[0] != NUL) { (void)EMSG2(cs_emsg, buf); - else if (p_csverbose) - cs_reading_emsg(i); /* don't have additional information */ - cs_release_csp(i, TRUE); + } else if (p_csverbose) { + cs_reading_emsg(i); // don't have additional information + } + cs_release_csp(i, true); xfree(buf); return CSCOPE_FAILURE; } @@ -1753,9 +1764,10 @@ static int cs_read_prompt(size_t i) } } - if (ch == EOF) - continue; /* didn't find the prompt */ - break; /* did find the prompt */ + if (ch == EOF) { + continue; // didn't find the prompt + } + break; // did find the prompt } xfree(buf); @@ -1766,8 +1778,9 @@ static int cs_read_prompt(size_t i) /* * Used to catch and ignore SIGALRM below. */ -static void sig_handler(int s) { - /* do nothing */ +static void sig_handler(int s) +{ + // do nothing return; } @@ -1775,7 +1788,7 @@ static void sig_handler(int s) { /// Does the actual free'ing for the cs ptr with an optional flag of whether /// or not to free the filename. Called by cs_kill and cs_reset. -static void cs_release_csp(size_t i, int freefnpp) +static void cs_release_csp(size_t i, bool freefnpp) { // Trying to exit normally (not sure whether it is fit to Unix cscope) if (csinfo[i].to_fp != NULL) { @@ -1791,7 +1804,7 @@ static void cs_release_csp(size_t i, int freefnpp) # if defined(HAVE_SIGACTION) struct sigaction sa, old; - /* Use sigaction() to limit the waiting time to two seconds. */ + // Use sigaction() to limit the waiting time to two seconds. sigemptyset(&sa.sa_mask); sa.sa_handler = sig_handler; # ifdef SA_NODEFER @@ -1800,27 +1813,28 @@ static void cs_release_csp(size_t i, int freefnpp) sa.sa_flags = 0; # endif sigaction(SIGALRM, &sa, &old); - alarm(2); /* 2 sec timeout */ + alarm(2); // 2 sec timeout - /* Block until cscope exits or until timer expires */ + // Block until cscope exits or until timer expires pid = waitpid(csinfo[i].pid, &pstat, 0); waitpid_errno = errno; - /* cancel pending alarm if still there and restore signal */ + // cancel pending alarm if still there and restore signal alarm(0); sigaction(SIGALRM, &old, NULL); # else int waited; - /* Can't use sigaction(), loop for two seconds. First yield the CPU - * to give cscope a chance to exit quickly. */ + // Can't use sigaction(), loop for two seconds. First yield the CPU + // to give cscope a chance to exit quickly. sleep(0); for (waited = 0; waited < 40; ++waited) { pid = waitpid(csinfo[i].pid, &pstat, WNOHANG); waitpid_errno = errno; - if (pid != 0) - break; /* break unless the process is still running */ - os_delay(50L, false); /* sleep 50 ms */ + if (pid != 0) { + break; // break unless the process is still running + } + os_delay(50L, false); // sleep 50 ms } # endif /* @@ -1830,7 +1844,7 @@ static void cs_release_csp(size_t i, int freefnpp) */ if (pid < 0 && csinfo[i].pid > 1) { # ifdef ECHILD - int alive = TRUE; + bool alive = true; if (waitpid_errno == ECHILD) { /* @@ -1845,13 +1859,13 @@ static void cs_release_csp(size_t i, int freefnpp) int waited; sleep(0); - for (waited = 0; waited < 40; ++waited) { - /* Check whether cscope process is still alive */ + for (waited = 0; waited < 40; waited++) { + // Check whether cscope process is still alive if (kill(csinfo[i].pid, 0) != 0) { - alive = FALSE; /* cscope process no longer exists */ + alive = false; // cscope process no longer exists break; } - os_delay(50L, false); /* sleep 50ms */ + os_delay(50L, false); // sleep 50ms } } if (alive) @@ -1862,11 +1876,12 @@ static void cs_release_csp(size_t i, int freefnpp) } } } -#else /* !UNIX */ +#else // !UNIX if (csinfo[i].hProc != NULL) { - /* Give cscope a chance to exit normally */ - if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT) + // Give cscope a chance to exit normally + if (WaitForSingleObject(csinfo[i].hProc, 1000) == WAIT_TIMEOUT) { TerminateProcess(csinfo[i].hProc, 0); + } CloseHandle(csinfo[i].hProc); } #endif @@ -1883,7 +1898,7 @@ static void cs_release_csp(size_t i, int freefnpp) } clear_csinfo(i); -} /* cs_release_csp */ +} /// Calls cs_kill on all cscope connections then reinits. @@ -1895,7 +1910,7 @@ static int cs_reset(exarg_T *eap) if (csinfo_size == 0) return CSCOPE_SUCCESS; - /* malloc our db and ppath list */ + // malloc our db and ppath list dblist = xmalloc(csinfo_size * sizeof(char *)); pplist = xmalloc(csinfo_size * sizeof(char *)); fllist = xmalloc(csinfo_size * sizeof(char *)); @@ -1908,15 +1923,14 @@ static int cs_reset(exarg_T *eap) cs_release_csp(i, FALSE); } - /* rebuild the cscope connection list */ + // rebuild the cscope connection list for (size_t i = 0; i < csinfo_size; i++) { if (dblist[i] != NULL) { cs_add_common(dblist[i], pplist[i], fllist[i]); if (p_csverbose) { - /* don't use smsg_attr() because we want to display the - * connection number in the same line as - * "Added cscope database..." - */ + // don't use smsg_attr() because we want to display the + // connection number in the same line as + // "Added cscope database..." snprintf(buf, ARRAY_SIZE(buf), " (#%zu)", i); MSG_PUTS_ATTR(buf, HL_ATTR(HLF_R)); } @@ -1933,7 +1947,7 @@ static int cs_reset(exarg_T *eap) msg_attr(_("All cscope databases reset"), HL_ATTR(HLF_R) | MSG_HIST); } return CSCOPE_SUCCESS; -} /* cs_reset */ +} /// Construct the full pathname to a file found in the cscope database. @@ -1954,11 +1968,11 @@ static char *cs_resolve_file(size_t i, char *name) * copied into the tag buffer used by Vim. */ size_t len = strlen(name) + 2; - if (csinfo[i].ppath != NULL) + if (csinfo[i].ppath != NULL) { len += strlen(csinfo[i].ppath); - else if (p_csre && csinfo[i].fname != NULL) { - /* If 'cscoperelative' is set and ppath is not set, use cscope.out - * path in path resolution. */ + } else if (p_csre && csinfo[i].fname != NULL) { + // If 'cscoperelative' is set and ppath is not set, use cscope.out + // path in path resolution. csdir = xmalloc(MAXPATHL); STRLCPY(csdir, csinfo[i].fname, path_tail((char_u *)csinfo[i].fname) @@ -1966,9 +1980,9 @@ static char *cs_resolve_file(size_t i, char *name) len += STRLEN(csdir); } - /* Note/example: this won't work if the cscope output already starts - * "../.." and the prefix path is also "../..". if something like this - * happens, you are screwed up and need to fix how you're using cscope. */ + // Note/example: this won't work if the cscope output already starts + // "../.." and the prefix path is also "../..". if something like this + // happens, you are screwed up and need to fix how you're using cscope. if (csinfo[i].ppath != NULL && (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0) && (name[0] != '/') @@ -1976,9 +1990,9 @@ static char *cs_resolve_file(size_t i, char *name) fullname = xmalloc(len); (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name); } else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL) { - /* Check for csdir to be non empty to avoid empty path concatenated to - * cscope output. */ - fullname = concat_fnames((char *)csdir, name, TRUE); + // Check for csdir to be non empty to avoid empty path concatenated to + // cscope output. + fullname = concat_fnames((char *)csdir, name, true); } else { fullname = xstrdup(name); } @@ -2013,7 +2027,7 @@ static int cs_show(exarg_T *eap) wait_return(TRUE); return CSCOPE_SUCCESS; -} /* cs_show */ +} /// Only called when VIM exits to quit any cscope sessions. @@ -2025,4 +2039,4 @@ void cs_end(void) csinfo_size = 0; } -/* the end */ +// the end diff --git a/src/nvim/if_cscope_defs.h b/src/nvim/if_cscope_defs.h index fa18866840..d2d8b0fb62 100644 --- a/src/nvim/if_cscope_defs.h +++ b/src/nvim/if_cscope_defs.h @@ -1,19 +1,16 @@ #ifndef NVIM_IF_CSCOPE_DEFS_H #define NVIM_IF_CSCOPE_DEFS_H -/* - * CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com> - * Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com> - * - * 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. If this is a problem and requires inclusion of the annoying - * BSD license, then sue me; I'm not worth much anyway. - */ - +// CSCOPE support for Vim added by Andy Kahn <kahn@zk3.dec.com> +// Ported to Win32 by Sergey Khorev <sergey.khorev@gmail.com> +// +// 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. If this is a problem and requires inclusion of the annoying +// BSD license, then sue me; I'm not worth much anyway. #if defined(UNIX) -# include <sys/types.h> /* pid_t */ +# include <sys/types.h> // pid_t #endif #include "nvim/os/os_defs.h" @@ -33,13 +30,13 @@ typedef struct { int (*func)(exarg_T *eap); char * help; char * usage; - int cansplit; /* if supports splitting window */ + int cansplit; // if supports splitting window } cscmd_T; typedef struct csi { - char * fname; /* cscope db name */ - char * ppath; /* path to prepend (the -P option) */ - char * flags; /* additional cscope flags/options (e.g, -p2) */ + char * fname; // cscope db name + char * ppath; // path to prepend (the -P option) + char * flags; // additional cscope flags/options (e.g, -p2) #if defined(UNIX) pid_t pid; // PID of the connected cscope process #else @@ -51,8 +48,8 @@ typedef struct csi { #endif FileID file_id; - FILE * fr_fp; /* from cscope: FILE. */ - FILE * to_fp; /* to cscope: FILE. */ + FILE * fr_fp; // from cscope: FILE. + FILE * to_fp; // to cscope: FILE. } csinfo_T; typedef enum { Add, Find, Help, Kill, Reset, Show } csid_e; diff --git a/src/nvim/indent.c b/src/nvim/indent.c index f8018c039d..7f17fb0035 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -56,7 +56,8 @@ int get_indent_buf(buf_T *buf, linenr_T lnum) // Count the size (in window cells) of the indent in line "ptr", with // 'tabstop' at "ts". // If @param list is TRUE, count only screen size for tabs. -int get_indent_str(char_u *ptr, int ts, int list) +int get_indent_str(const char_u *ptr, int ts, int list) + FUNC_ATTR_NONNULL_ALL { int count = 0; @@ -375,12 +376,12 @@ int get_number_indent(linenr_T lnum) * parameters into account. Window must be specified, since it is not * necessarily always the current one. */ -int get_breakindent_win(win_T *wp, char_u *line) - FUNC_ATTR_NONNULL_ARG(1) +int get_breakindent_win(win_T *wp, const char_u *line) + FUNC_ATTR_NONNULL_ALL { static int prev_indent = 0; // Cached indent value. static long prev_ts = 0; // Cached tabstop value. - static char_u *prev_line = NULL; // cached pointer to line. + static const char_u *prev_line = NULL; // cached pointer to line. static varnumber_T prev_tick = 0; // Changedtick of cached value. int bri = 0; // window width minus window margin space, i.e. what rests for text @@ -389,7 +390,7 @@ int get_breakindent_win(win_T *wp, char_u *line) && (vim_strchr(p_cpo, CPO_NUMCOL) == NULL) ? number_width(wp) + 1 : 0); - /* used cached indent, unless pointer or 'tabstop' changed */ + // used cached indent, unless pointer or 'tabstop' changed if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts || prev_tick != buf_get_changedtick(wp->w_buffer)) { prev_line = line; @@ -399,21 +400,22 @@ int get_breakindent_win(win_T *wp, char_u *line) } bri = prev_indent + wp->w_p_brishift; - /* indent minus the length of the showbreak string */ - if (wp->w_p_brisbr) + // indent minus the length of the showbreak string + if (wp->w_p_brisbr) { bri -= vim_strsize(p_sbr); - - /* Add offset for number column, if 'n' is in 'cpoptions' */ + } + // Add offset for number column, if 'n' is in 'cpoptions' bri += win_col_off2(wp); - /* never indent past left window margin */ - if (bri < 0) + // never indent past left window margin + if (bri < 0) { bri = 0; - /* always leave at least bri_min characters on the left, - * if text width is sufficient */ - else if (bri > eff_wwidth - wp->w_p_brimin) + } else if (bri > eff_wwidth - wp->w_p_brimin) { + // always leave at least bri_min characters on the left, + // if text width is sufficient bri = (eff_wwidth - wp->w_p_brimin < 0) ? 0 : eff_wwidth - wp->w_p_brimin; + } return bri; } diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index 67a7e58ed7..bb443161ef 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -3372,11 +3372,9 @@ term_again: continue; } - /* - * Are we at the start of a cpp base class declaration or - * constructor initialization? - */ /* XXX */ - n = false; + // Are we at the start of a cpp base class declaration or + // constructor initialization? XXX + n = 0; if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{') { n = cin_is_cpp_baseclass(&cache_cpp_baseclass); l = get_cursor_line_ptr(); @@ -3409,7 +3407,6 @@ term_again: * } foo, * bar; */ - n = 0; if (cin_ends_in(l, (char_u *)",", NULL) || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\')) { /* take us back to opening paren */ diff --git a/src/nvim/keymap.h b/src/nvim/keymap.h index d3e887badc..ada9bc5780 100644 --- a/src/nvim/keymap.h +++ b/src/nvim/keymap.h @@ -13,7 +13,7 @@ * For MSDOS some keys produce codes larger than 0xff. They are split into two * chars, the first one is K_NUL. */ -#define K_NUL (0xce) /* for MSDOS: special key follows */ +#define K_NUL (0xce) // for MSDOS: special key follows /* * K_SPECIAL is the first byte of a special key code and is always followed by @@ -78,13 +78,13 @@ #define KS_SELECT 245 #define K_SELECT_STRING (char_u *)"\200\365X" -/* Used a termcap entry that produces a normal character. */ +// Used a termcap entry that produces a normal character. #define KS_KEY 242 -/* Used for click in a tab pages label. */ +// Used for click in a tab pages label. #define KS_TABLINE 240 -/* Used for menu in a tab pages line. */ +// Used for menu in a tab pages line. #define KS_TABMENU 239 /* @@ -274,13 +274,13 @@ enum key_extra { #define K_TAB TERMCAP2KEY(KS_EXTRA, KE_TAB) #define K_S_TAB TERMCAP2KEY('k', 'B') -/* extra set of function keys F1-F4, for vt100 compatible xterm */ +// extra set of function keys F1-F4, for vt100 compatible xterm #define K_XF1 TERMCAP2KEY(KS_EXTRA, KE_XF1) #define K_XF2 TERMCAP2KEY(KS_EXTRA, KE_XF2) #define K_XF3 TERMCAP2KEY(KS_EXTRA, KE_XF3) #define K_XF4 TERMCAP2KEY(KS_EXTRA, KE_XF4) -/* extra set of cursor keys for vt100 compatible xterm */ +// extra set of cursor keys for vt100 compatible xterm #define K_XUP TERMCAP2KEY(KS_EXTRA, KE_XUP) #define K_XDOWN TERMCAP2KEY(KS_EXTRA, KE_XDOWN) #define K_XLEFT TERMCAP2KEY(KS_EXTRA, KE_XLEFT) @@ -327,7 +327,7 @@ enum key_extra { #define K_F36 TERMCAP2KEY('F', 'Q') #define K_F37 TERMCAP2KEY('F', 'R') -/* extra set of shifted function keys F1-F4, for vt100 compatible xterm */ +// extra set of shifted function keys F1-F4, for vt100 compatible xterm #define K_S_XF1 TERMCAP2KEY(KS_EXTRA, KE_S_XF1) #define K_S_XF2 TERMCAP2KEY(KS_EXTRA, KE_S_XF2) #define K_S_XF3 TERMCAP2KEY(KS_EXTRA, KE_S_XF3) @@ -346,7 +346,7 @@ enum key_extra { #define K_S_F11 TERMCAP2KEY(KS_EXTRA, KE_S_F11) #define K_S_F12 TERMCAP2KEY(KS_EXTRA, KE_S_F12) -/* K_S_F13 to K_S_F37 are currently not used */ +// K_S_F13 to K_S_F37 are currently not used #define K_HELP TERMCAP2KEY('%', '1') #define K_UNDO TERMCAP2KEY('&', '8') @@ -443,8 +443,8 @@ enum key_extra { #define K_EVENT TERMCAP2KEY(KS_EXTRA, KE_EVENT) #define K_COMMAND TERMCAP2KEY(KS_EXTRA, KE_COMMAND) -/* Bits for modifier mask */ -/* 0x01 cannot be used, because the modifier must be 0x02 or higher */ +// Bits for modifier mask +// 0x01 cannot be used, because the modifier must be 0x02 or higher #define MOD_MASK_SHIFT 0x02 #define MOD_MASK_CTRL 0x04 #define MOD_MASK_ALT 0x08 // aka META diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 632832416b..144646fca2 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -11,6 +11,7 @@ #include "nvim/func_attr.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/handle.h" #include "nvim/api/vim.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/vim.h" @@ -19,6 +20,7 @@ #include "nvim/message.h" #include "nvim/memline.h" #include "nvim/buffer_defs.h" +#include "nvim/regexp.h" #include "nvim/macros.h" #include "nvim/screen.h" #include "nvim/cursor.h" @@ -245,6 +247,14 @@ static int nlua_schedule(lua_State *const lstate) return 0; } +static struct luaL_Reg regex_meta[] = { + { "__gc", regex_gc }, + { "__tostring", regex_tostring }, + { "match_str", regex_match_str }, + { "match_line", regex_match_line }, + { NULL, NULL } +}; + /// Initialize lua interpreter state /// /// Called by lua interpreter itself to initialize state. @@ -292,6 +302,15 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL // call lua_pushcfunction(lstate, &nlua_call); lua_setfield(lstate, -2, "call"); + // regex + lua_pushcfunction(lstate, &nlua_regex); + lua_setfield(lstate, -2, "regex"); + + luaL_newmetatable(lstate, "nvim_regex"); + luaL_register(lstate, NULL, regex_meta); + lua_pushvalue(lstate, -1); // [meta, meta] + lua_setfield(lstate, -2, "__index"); // [meta] + lua_pop(lstate, 1); // don't use metatable now // rpcrequest lua_pushcfunction(lstate, &nlua_rpcrequest); @@ -1038,3 +1057,136 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, ts_lua_parse_query); lua_setfield(lstate, -2, "_ts_parse_query"); } + +static int nlua_regex(lua_State *lstate) +{ + Error err = ERROR_INIT; + const char *text = luaL_checkstring(lstate, 1); + regprog_T *prog = NULL; + + TRY_WRAP({ + try_start(); + prog = vim_regcomp((char_u *)text, RE_AUTO | RE_MAGIC | RE_STRICT); + try_end(&err); + }); + + if (ERROR_SET(&err)) { + return luaL_error(lstate, "couldn't parse regex: %s", err.msg); + } + assert(prog); + + regprog_T **p = lua_newuserdata(lstate, sizeof(regprog_T *)); + *p = prog; + + lua_getfield(lstate, LUA_REGISTRYINDEX, "nvim_regex"); // [udata, meta] + lua_setmetatable(lstate, -2); // [udata] + return 1; +} + +static regprog_T **regex_check(lua_State *L) +{ + return luaL_checkudata(L, 1, "nvim_regex"); +} + + +static int regex_gc(lua_State *lstate) +{ + regprog_T **prog = regex_check(lstate); + vim_regfree(*prog); + return 0; +} + +static int regex_tostring(lua_State *lstate) +{ + lua_pushstring(lstate, "<regex>"); + return 1; +} + +static int regex_match(lua_State *lstate, regprog_T **prog, char_u *str) +{ + regmatch_T rm; + rm.regprog = *prog; + rm.rm_ic = false; + bool match = vim_regexec(&rm, str, 0); + *prog = rm.regprog; + + if (match) { + lua_pushinteger(lstate, (lua_Integer)(rm.startp[0]-str)); + lua_pushinteger(lstate, (lua_Integer)(rm.endp[0]-str)); + return 2; + } + return 0; +} + +static int regex_match_str(lua_State *lstate) +{ + regprog_T **prog = regex_check(lstate); + const char *str = luaL_checkstring(lstate, 2); + int nret = regex_match(lstate, prog, (char_u *)str); + + if (!*prog) { + return luaL_error(lstate, "regex: internal error"); + } + + return nret; +} + +static int regex_match_line(lua_State *lstate) +{ + regprog_T **prog = regex_check(lstate); + + int narg = lua_gettop(lstate); + if (narg < 3) { + return luaL_error(lstate, "not enough args"); + } + + long bufnr = luaL_checkinteger(lstate, 2); + long rownr = luaL_checkinteger(lstate, 3); + long start = 0, end = -1; + if (narg >= 4) { + start = luaL_checkinteger(lstate, 4); + } + if (narg >= 5) { + end = luaL_checkinteger(lstate, 5); + if (end < 0) { + return luaL_error(lstate, "invalid end"); + } + } + + buf_T *buf = bufnr ? handle_get_buffer((int)bufnr) : curbuf; + if (!buf || buf->b_ml.ml_mfp == NULL) { + return luaL_error(lstate, "invalid buffer"); + } + + if (rownr >= buf->b_ml.ml_line_count) { + return luaL_error(lstate, "invalid row"); + } + + char_u *line = ml_get_buf(buf, rownr+1, false); + size_t len = STRLEN(line); + + if (start < 0 || (size_t)start > len) { + return luaL_error(lstate, "invalid start"); + } + + char_u save = NUL; + if (end >= 0) { + if ((size_t)end > len || end < start) { + return luaL_error(lstate, "invalid end"); + } + save = line[end]; + line[end] = NUL; + } + + int nret = regex_match(lstate, prog, line+start); + + if (end >= 0) { + line[end] = save; + } + + if (!*prog) { + return luaL_error(lstate, "regex: internal error"); + } + + return nret; +} diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index a420f79ffd..51d9549033 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -93,10 +93,7 @@ static PMap(cstr_t) *langs; static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) { if (luaL_newmetatable(L, tname)) { // [meta] - for (size_t i = 0; meta[i].name != NULL; i++) { - lua_pushcfunction(L, meta[i].func); // [meta, func] - lua_setfield(L, -2, meta[i].name); // [meta] - } + luaL_register(L, NULL, meta); lua_pushvalue(L, -1); // [meta, meta] lua_setfield(L, -2, "__index"); // [meta] @@ -274,17 +271,22 @@ static const char *input_cb(void *payload, uint32_t byte_index, } char_u *line = ml_get_buf(bp, position.row+1, false); size_t len = STRLEN(line); - size_t tocopy = MIN(len-position.column, BUFSIZE); - - memcpy(buf, line+position.column, tocopy); - // Translate embedded \n to NUL - memchrsub(buf, '\n', '\0', tocopy); - *bytes_read = (uint32_t)tocopy; - if (tocopy < BUFSIZE) { - // now add the final \n. If it didn't fit, input_cb will be called again - // on the same line with advanced column. - buf[tocopy] = '\n'; - (*bytes_read)++; + + if (position.column > len) { + *bytes_read = 0; + } else { + size_t tocopy = MIN(len-position.column, BUFSIZE); + + memcpy(buf, line+position.column, tocopy); + // Translate embedded \n to NUL + memchrsub(buf, '\n', '\0', tocopy); + *bytes_read = (uint32_t)tocopy; + if (tocopy < BUFSIZE) { + // now add the final \n. If it didn't fit, input_cb will be called again + // on the same line with advanced column. + buf[tocopy] = '\n'; + (*bytes_read)++; + } } return buf; #undef BUFSIZE diff --git a/src/nvim/macros.h b/src/nvim/macros.h index f6c8c0a4a0..3df7fa768d 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -36,38 +36,34 @@ #define BUFEMPTY() (curbuf->b_ml.ml_line_count == 1 && *ml_get((linenr_T)1) == \ NUL) -/* - * toupper() and tolower() that use the current locale. - * Careful: Only call TOUPPER_LOC() and TOLOWER_LOC() with a character in the - * range 0 - 255. toupper()/tolower() on some systems can't handle others. - * Note: It is often better to use mb_tolower() and mb_toupper(), because many - * toupper() and tolower() implementations only work for ASCII. - */ +// toupper() and tolower() that use the current locale. +// Careful: Only call TOUPPER_LOC() and TOLOWER_LOC() with a character in the +// range 0 - 255. toupper()/tolower() on some systems can't handle others. +// Note: It is often better to use mb_tolower() and mb_toupper(), because many +// toupper() and tolower() implementations only work for ASCII. #define TOUPPER_LOC toupper #define TOLOWER_LOC tolower -/* toupper() and tolower() for ASCII only and ignore the current locale. */ +// toupper() and tolower() for ASCII only and ignore the current locale. # define TOUPPER_ASC(c) (((c) < 'a' || (c) > 'z') ? (c) : (c) - ('a' - 'A')) # define TOLOWER_ASC(c) (((c) < 'A' || (c) > 'Z') ? (c) : (c) + ('a' - 'A')) -/* Like isalpha() but reject non-ASCII characters. Can't be used with a - * special key (negative value). */ +// Like isalpha() but reject non-ASCII characters. Can't be used with a +// special key (negative value). # define ASCII_ISLOWER(c) ((unsigned)(c) >= 'a' && (unsigned)(c) <= 'z') # define ASCII_ISUPPER(c) ((unsigned)(c) >= 'A' && (unsigned)(c) <= 'Z') # define ASCII_ISALPHA(c) (ASCII_ISUPPER(c) || ASCII_ISLOWER(c)) # define ASCII_ISALNUM(c) (ASCII_ISALPHA(c) || ascii_isdigit(c)) -/* Returns empty string if it is NULL. */ +// Returns empty string if it is NULL. #define EMPTY_IF_NULL(x) ((x) ? (x) : (char_u *)"") -/* - * Adjust chars in a language according to 'langmap' option. - * NOTE that there is no noticeable overhead if 'langmap' is not set. - * When set the overhead for characters < 256 is small. - * Don't apply 'langmap' if the character comes from the Stuff buffer or from a - * mapping and the langnoremap option was set. - * The do-while is just to ignore a ';' after the macro. - */ +// Adjust chars in a language according to 'langmap' option. +// NOTE that there is no noticeable overhead if 'langmap' is not set. +// When set the overhead for characters < 256 is small. +// Don't apply 'langmap' if the character comes from the Stuff buffer or from a +// mapping and the langnoremap option was set. +// The do-while is just to ignore a ';' after the macro. # define LANGMAP_ADJUST(c, condition) \ do { \ if (*p_langmap \ @@ -83,12 +79,12 @@ } \ } while (0) -#define WRITEBIN "wb" /* no CR-LF translation */ +#define WRITEBIN "wb" // no CR-LF translation #define READBIN "rb" #define APPENDBIN "ab" -/* mch_open_rw(): invoke os_open() with third argument for user R/W. */ -#if defined(UNIX) /* open in rw------- mode */ +// mch_open_rw(): invoke os_open() with third argument for user R/W. +#if defined(UNIX) // open in rw------- mode # define mch_open_rw(n, f) os_open((n), (f), (mode_t)0600) #elif defined(WIN32) # define mch_open_rw(n, f) os_open((n), (f), S_IREAD | S_IWRITE) @@ -100,7 +96,7 @@ # define UTF_COMPOSINGLIKE(p1, p2) utf_composinglike((p1), (p2)) -/* Whether to draw the vertical bar on the right side of the cell. */ +// Whether to draw the vertical bar on the right side of the cell. # define CURSOR_BAR_RIGHT (curwin->w_p_rl && (!(State & CMDLINE) || cmdmsg_rl)) // MB_PTR_ADV(): advance a pointer to the next character, taking care of diff --git a/src/nvim/main.c b/src/nvim/main.c index 56d9030a7f..4a9f2371a2 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -10,6 +10,7 @@ #include <msgpack.h> #include "nvim/ascii.h" +#include "nvim/channel.h" #include "nvim/vim.h" #include "nvim/main.h" #include "nvim/aucmd.h" diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 52e602cd94..6dd452b5af 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -197,7 +197,7 @@ static inline void split_node(MarkTree *b, mtnode_t *x, const int i) // x must not be a full node (even if there might be internal space) static inline void marktree_putp_aux(MarkTree *b, mtnode_t *x, mtkey_t k) { - int i = x->n - 1; + int i; if (x->level == 0) { i = marktree_getp_aux(x, k, 0); if (i != x->n - 1) { @@ -849,7 +849,8 @@ bool marktree_splice(MarkTree *b, bool same_line = old_extent.row == 0 && new_extent.row == 0; unrelative(start, &old_extent); unrelative(start, &new_extent); - MarkTreeIter itr[1], enditr[1]; + MarkTreeIter itr[1] = { 0 }; + MarkTreeIter enditr[1] = { 0 }; mtpos_t oldbase[MT_MAX_DEPTH]; @@ -905,7 +906,7 @@ continue_same_node: refkey(b, itr->node, itr->i); refkey(b, enditr->node, enditr->i); } else { - past_right = true; + past_right = true; // NOLINT break; } } @@ -1003,7 +1004,7 @@ void marktree_move_region(MarkTree *b, mtpos_t start = { start_row, start_col }, size = { extent_row, extent_col }; mtpos_t end = size; unrelative(start, &end); - MarkTreeIter itr[1]; + MarkTreeIter itr[1] = { 0 }; marktree_itr_get_ext(b, start, itr, false, true, NULL); kvec_t(mtkey_t) saved = KV_INITIAL_VALUE; while (itr->node) { diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 85e6697bfb..e67be60aa6 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -265,68 +265,70 @@ static struct { const char *name; int canon; } enc_alias_table[] = { - {"ansi", IDX_LATIN_1}, - {"iso-8859-1", IDX_LATIN_1}, - {"latin2", IDX_ISO_2}, - {"latin3", IDX_ISO_3}, - {"latin4", IDX_ISO_4}, - {"cyrillic", IDX_ISO_5}, - {"arabic", IDX_ISO_6}, - {"greek", IDX_ISO_7}, - {"hebrew", IDX_ISO_8}, - {"latin5", IDX_ISO_9}, - {"turkish", IDX_ISO_9}, /* ? */ - {"latin6", IDX_ISO_10}, - {"nordic", IDX_ISO_10}, /* ? */ - {"thai", IDX_ISO_11}, /* ? */ - {"latin7", IDX_ISO_13}, - {"latin8", IDX_ISO_14}, - {"latin9", IDX_ISO_15}, - {"utf8", IDX_UTF8}, - {"unicode", IDX_UCS2}, - {"ucs2", IDX_UCS2}, - {"ucs2be", IDX_UCS2}, - {"ucs-2be", IDX_UCS2}, - {"ucs2le", IDX_UCS2LE}, - {"utf16", IDX_UTF16}, - {"utf16be", IDX_UTF16}, - {"utf-16be", IDX_UTF16}, - {"utf16le", IDX_UTF16LE}, - {"ucs4", IDX_UCS4}, - {"ucs4be", IDX_UCS4}, - {"ucs-4be", IDX_UCS4}, - {"ucs4le", IDX_UCS4LE}, - {"utf32", IDX_UCS4}, - {"utf-32", IDX_UCS4}, - {"utf32be", IDX_UCS4}, - {"utf-32be", IDX_UCS4}, - {"utf32le", IDX_UCS4LE}, - {"utf-32le", IDX_UCS4LE}, - {"932", IDX_CP932}, - {"949", IDX_CP949}, - {"936", IDX_CP936}, - {"gbk", IDX_CP936}, - {"950", IDX_CP950}, - {"eucjp", IDX_EUC_JP}, - {"unix-jis", IDX_EUC_JP}, - {"ujis", IDX_EUC_JP}, - {"shift-jis", IDX_SJIS}, - {"pck", IDX_SJIS}, /* Sun: PCK */ - {"euckr", IDX_EUC_KR}, - {"5601", IDX_EUC_KR}, /* Sun: KS C 5601 */ - {"euccn", IDX_EUC_CN}, - {"gb2312", IDX_EUC_CN}, - {"euctw", IDX_EUC_TW}, - {"japan", IDX_EUC_JP}, - {"korea", IDX_EUC_KR}, - {"prc", IDX_EUC_CN}, - {"chinese", IDX_EUC_CN}, - {"taiwan", IDX_EUC_TW}, - {"cp950", IDX_BIG5}, - {"950", IDX_BIG5}, - {"mac", IDX_MACROMAN}, - {"mac-roman", IDX_MACROMAN}, - {NULL, 0} + { "ansi", IDX_LATIN_1 }, + { "iso-8859-1", IDX_LATIN_1 }, + { "latin2", IDX_ISO_2 }, + { "latin3", IDX_ISO_3 }, + { "latin4", IDX_ISO_4 }, + { "cyrillic", IDX_ISO_5 }, + { "arabic", IDX_ISO_6 }, + { "greek", IDX_ISO_7 }, + { "hebrew", IDX_ISO_8 }, + { "latin5", IDX_ISO_9 }, + { "turkish", IDX_ISO_9 }, // ? + { "latin6", IDX_ISO_10 }, + { "nordic", IDX_ISO_10 }, // ? + { "thai", IDX_ISO_11 }, // ? + { "latin7", IDX_ISO_13 }, + { "latin8", IDX_ISO_14 }, + { "latin9", IDX_ISO_15 }, + { "utf8", IDX_UTF8 }, + { "unicode", IDX_UCS2 }, + { "ucs2", IDX_UCS2 }, + { "ucs2be", IDX_UCS2 }, + { "ucs-2be", IDX_UCS2 }, + { "ucs2le", IDX_UCS2LE }, + { "utf16", IDX_UTF16 }, + { "utf16be", IDX_UTF16 }, + { "utf-16be", IDX_UTF16 }, + { "utf16le", IDX_UTF16LE }, + { "ucs4", IDX_UCS4 }, + { "ucs4be", IDX_UCS4 }, + { "ucs-4be", IDX_UCS4 }, + { "ucs4le", IDX_UCS4LE }, + { "utf32", IDX_UCS4 }, + { "utf-32", IDX_UCS4 }, + { "utf32be", IDX_UCS4 }, + { "utf-32be", IDX_UCS4 }, + { "utf32le", IDX_UCS4LE }, + { "utf-32le", IDX_UCS4LE }, + { "932", IDX_CP932 }, + { "949", IDX_CP949 }, + { "936", IDX_CP936 }, + { "gbk", IDX_CP936 }, + { "950", IDX_CP950 }, + { "eucjp", IDX_EUC_JP }, + { "unix-jis", IDX_EUC_JP }, + { "ujis", IDX_EUC_JP }, + { "shift-jis", IDX_SJIS }, + { "pck", IDX_SJIS }, // Sun: PCK + { "euckr", IDX_EUC_KR }, + { "5601", IDX_EUC_KR }, // Sun: KS C 5601 + { "euccn", IDX_EUC_CN }, + { "gb2312", IDX_EUC_CN }, + { "euctw", IDX_EUC_TW }, + { "japan", IDX_EUC_JP }, + { "korea", IDX_EUC_KR }, + { "prc", IDX_EUC_CN }, + { "zh-cn", IDX_EUC_CN }, + { "chinese", IDX_EUC_CN }, + { "zh-tw", IDX_EUC_TW }, + { "taiwan", IDX_EUC_TW }, + { "cp950", IDX_BIG5 }, + { "950", IDX_BIG5 }, + { "mac", IDX_MACROMAN }, + { "mac-roman", IDX_MACROMAN }, + { NULL, 0 } }; /* diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 922b684120..6e074b3249 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1504,16 +1504,15 @@ static time_t swapfile_info(char_u *fname) int fd; struct block0 b0; time_t x = (time_t)0; - char *p; #ifdef UNIX char uname[B0_UNAME_SIZE]; #endif - /* print the swap file date */ + // print the swap file date FileInfo file_info; if (os_fileinfo((char *)fname, &file_info)) { #ifdef UNIX - /* print name of owner of the file */ + // print name of owner of the file if (os_get_uname(file_info.stat.st_uid, uname, B0_UNAME_SIZE) == OK) { MSG_PUTS(_(" owned by: ")); msg_outtrans((char_u *)uname); @@ -1522,11 +1521,8 @@ static time_t swapfile_info(char_u *fname) #endif MSG_PUTS(_(" dated: ")); x = file_info.stat.st_mtim.tv_sec; - p = ctime(&x); // includes '\n' - if (p == NULL) - MSG_PUTS("(invalid)\n"); - else - MSG_PUTS(p); + char ctime_buf[50]; + MSG_PUTS(os_ctime_r(&x, ctime_buf, sizeof(ctime_buf))); } /* @@ -1863,7 +1859,10 @@ errorret: // Avoid giving this message for a recursive call, may happen // when the GUI redraws part of the text. recursive++; - IEMSGN(_("E316: ml_get: cannot find line %" PRId64), lnum); + get_trans_bufname(buf); + shorten_dir(NameBuff); + iemsgf(_("E316: ml_get: cannot find line %" PRId64 " in buffer %d %s"), + lnum, buf->b_fnum, NameBuff); recursive--; } goto errorret; @@ -2391,21 +2390,32 @@ static int ml_append_int( void ml_add_deleted_len(char_u *ptr, ssize_t len) { + ml_add_deleted_len_buf(curbuf, ptr, len); +} + +void ml_add_deleted_len_buf(buf_T *buf, char_u *ptr, ssize_t len) +{ if (inhibit_delete_count) { return; } if (len == -1) { len = STRLEN(ptr); } - curbuf->deleted_bytes += len+1; - if (curbuf->update_need_codepoints) { - mb_utflen(ptr, len, &curbuf->deleted_codepoints, - &curbuf->deleted_codeunits); - curbuf->deleted_codepoints++; // NL char - curbuf->deleted_codeunits++; + buf->deleted_bytes += len+1; + if (buf->update_need_codepoints) { + mb_utflen(ptr, len, &buf->deleted_codepoints, + &buf->deleted_codeunits); + buf->deleted_codepoints++; // NL char + buf->deleted_codeunits++; } } + +int ml_replace(linenr_T lnum, char_u *line, bool copy) +{ + return ml_replace_buf(curbuf, lnum, line, copy); +} + /* * Replace line lnum, with buffering, in current buffer. * @@ -2417,36 +2427,37 @@ void ml_add_deleted_len(char_u *ptr, ssize_t len) * * return FAIL for failure, OK otherwise */ -int ml_replace(linenr_T lnum, char_u *line, bool copy) +int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy) { if (line == NULL) /* just checking... */ return FAIL; - /* When starting up, we might still need to create the memfile */ - if (curbuf->b_ml.ml_mfp == NULL && open_buffer(FALSE, NULL, 0) == FAIL) + // When starting up, we might still need to create the memfile + if (buf->b_ml.ml_mfp == NULL && open_buffer(false, NULL, 0) == FAIL) { return FAIL; + } bool readlen = true; if (copy) { line = vim_strsave(line); } - if (curbuf->b_ml.ml_line_lnum != lnum) { // other line buffered - ml_flush_line(curbuf); // flush it - } else if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) { // same line allocated - ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, -1); + if (buf->b_ml.ml_line_lnum != lnum) { // other line buffered + ml_flush_line(buf); // flush it + } else if (buf->b_ml.ml_flags & ML_LINE_DIRTY) { // same line allocated + ml_add_deleted_len(buf->b_ml.ml_line_ptr, -1); readlen = false; // already added the length - xfree(curbuf->b_ml.ml_line_ptr); // free it + xfree(buf->b_ml.ml_line_ptr); // free it } - if (readlen && kv_size(curbuf->update_callbacks)) { - ml_add_deleted_len(ml_get_buf(curbuf, lnum, false), -1); + if (readlen && kv_size(buf->update_callbacks)) { + ml_add_deleted_len(ml_get_buf(buf, lnum, false), -1); } - curbuf->b_ml.ml_line_ptr = line; - curbuf->b_ml.ml_line_lnum = lnum; - curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; + buf->b_ml.ml_line_ptr = line; + buf->b_ml.ml_line_lnum = lnum; + buf->b_ml.ml_flags = (buf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; return OK; } @@ -3264,15 +3275,13 @@ attention_message ( ) { assert(buf->b_fname != NULL); - time_t x, sx; - char *p; ++no_wait_return; (void)EMSG(_("E325: ATTENTION")); MSG_PUTS(_("\nFound a swap file by the name \"")); msg_home_replace(fname); MSG_PUTS("\"\n"); - sx = swapfile_info(fname); + const time_t swap_mtime = swapfile_info(fname); MSG_PUTS(_("While opening file \"")); msg_outtrans(buf->b_fname); MSG_PUTS("\"\n"); @@ -3281,14 +3290,12 @@ attention_message ( MSG_PUTS(_(" CANNOT BE FOUND")); } else { MSG_PUTS(_(" dated: ")); - x = file_info.stat.st_mtim.tv_sec; - p = ctime(&x); // includes '\n' - if (p == NULL) - MSG_PUTS("(invalid)\n"); - else - MSG_PUTS(p); - if (sx != 0 && x > sx) + time_t x = file_info.stat.st_mtim.tv_sec; + char ctime_buf[50]; + MSG_PUTS(os_ctime_r(&x, ctime_buf, sizeof(ctime_buf))); + if (swap_mtime != 0 && x > swap_mtime) { MSG_PUTS(_(" NEWER than swap file!\n")); + } } /* Some of these messages are long to allow translation to * other languages. */ @@ -3994,8 +4001,8 @@ long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp, bool no_ff) int ffdos = !no_ff && (get_fileformat(buf) == EOL_DOS); int extra = 0; - /* take care of cached line first */ - ml_flush_line(curbuf); + // take care of cached line first + ml_flush_line(buf); if (buf->b_ml.ml_usedchunks == -1 || buf->b_ml.ml_chunksize == NULL diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 18c4f1fff1..a3e0130465 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -868,7 +868,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth) if (*menu->strings[bit] == NUL) { msg_puts_attr("<Nop>", HL_ATTR(HLF_8)); } else { - msg_outtrans_special(menu->strings[bit], false); + msg_outtrans_special(menu->strings[bit], false, 0); } } } else { diff --git a/src/nvim/message.c b/src/nvim/message.c index 94729dfd2a..a12e665099 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1521,7 +1521,8 @@ void msg_make(char_u *arg) /// the character/string -- webb int msg_outtrans_special( const char_u *strstart, - int from ///< true for LHS of a mapping + bool from, ///< true for LHS of a mapping + int maxlen ///< screen columns, 0 for unlimeted ) { if (strstart == NULL) { @@ -1541,6 +1542,9 @@ int msg_outtrans_special( string = str2special((const char **)&str, from, false); } const int len = vim_strsize((char_u *)string); + if (maxlen > 0 && retval + len >= maxlen) { + break; + } // Highlight special keys msg_puts_attr(string, (len > 1 && (*mb_ptr2len)((char_u *)string) <= 1 diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 8c19a2de66..e7fb38e801 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -73,7 +73,8 @@ static garray_T ga_users = GA_EMPTY_INIT_VALUE; * If "include_space" is set, include trailing whitespace while calculating the * length. */ -int get_leader_len(char_u *line, char_u **flags, int backward, int include_space) +int get_leader_len(char_u *line, char_u **flags, + bool backward, bool include_space) { int i, j; int result; diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index dab2e44890..32d8352d9b 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -73,6 +73,7 @@ int jump_to_mouse(int flags, int col = mouse_col; int grid = mouse_grid; int mouse_char; + int fdc = 0; mouse_past_bottom = false; mouse_past_eol = false; @@ -109,12 +110,12 @@ retnomove: if (flags & MOUSE_SETPOS) goto retnomove; // ugly goto... - // Remember the character under the mouse, it might be a '-' or '+' in the - // fold column. NB: only works for ASCII chars! + // Remember the character under the mouse, might be one of foldclose or + // foldopen fillchars in the fold column. if (row >= 0 && row < Rows && col >= 0 && col <= Columns && default_grid.chars != NULL) { - mouse_char = default_grid.chars[default_grid.line_offset[row] - + (unsigned)col][0]; + mouse_char = utf_ptr2char(default_grid.chars[default_grid.line_offset[row] + + (unsigned)col]); } else { mouse_char = ' '; } @@ -131,6 +132,7 @@ retnomove: if (wp == NULL) { return IN_UNKNOWN; } + fdc = win_fdccol_count(wp); dragwin = NULL; // winpos and height may change in win_enter()! if (grid == DEFAULT_GRID_HANDLE && row >= wp->w_height) { @@ -165,9 +167,8 @@ retnomove: || (!on_status_line && !on_sep_line && (wp->w_p_rl - ? col < wp->w_width_inner - wp->w_p_fdc - : col >= wp->w_p_fdc + (cmdwin_type == 0 && wp == curwin - ? 0 : 1)) + ? col < wp->w_width_inner - fdc + : col >= fdc + (cmdwin_type == 0 && wp == curwin ? 0 : 1)) && (flags & MOUSE_MAY_STOP_VIS)))) { end_visual_mode(); redraw_curbuf_later(INVERTED); // delete the inversion @@ -305,8 +306,8 @@ retnomove: } // Check for position outside of the fold column. - if (curwin->w_p_rl ? col < curwin->w_width_inner - curwin->w_p_fdc : - col >= curwin->w_p_fdc + (cmdwin_type == 0 ? 0 : 1)) { + if (curwin->w_p_rl ? col < curwin->w_width_inner - fdc : + col >= fdc + (cmdwin_type == 0 ? 0 : 1)) { mouse_char = ' '; } diff --git a/src/nvim/move.c b/src/nvim/move.c index 3ae4f32a83..d4f82bc601 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -86,6 +86,7 @@ static void comp_botline(win_T *wp) /* wp->w_botline is the line that is just below the window */ wp->w_botline = lnum; wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; + wp->w_viewport_invalid = true; set_empty_rows(wp, done); @@ -142,7 +143,8 @@ void update_topline(void) int old_topfill; bool check_topline = false; bool check_botline = false; - long save_so = p_so; + long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; + long save_so = *so_ptr; // If there is no valid screen and when the window height is zero just use // the cursor line. @@ -150,6 +152,7 @@ void update_topline(void) curwin->w_topline = curwin->w_cursor.lnum; curwin->w_botline = curwin->w_topline; curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; + curwin->w_viewport_invalid = true; curwin->w_scbind_pos = 1; return; } @@ -158,9 +161,10 @@ void update_topline(void) if (curwin->w_valid & VALID_TOPLINE) return; - /* When dragging with the mouse, don't scroll that quickly */ - if (mouse_dragging > 0) - p_so = mouse_dragging - 1; + // When dragging with the mouse, don't scroll that quickly + if (mouse_dragging > 0) { + *so_ptr = mouse_dragging - 1; + } old_topline = curwin->w_topline; old_topfill = curwin->w_topfill; @@ -173,6 +177,7 @@ void update_topline(void) curwin->w_topline = 1; curwin->w_botline = 2; curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; + curwin->w_viewport_invalid = true; curwin->w_scbind_pos = 1; } /* @@ -206,15 +211,17 @@ void update_topline(void) * scrolled). */ n = 0; for (linenr_T lnum = curwin->w_cursor.lnum; - lnum < curwin->w_topline + p_so; ++lnum) { - ++n; - /* stop at end of file or when we know we are far off */ - if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) + lnum < curwin->w_topline + *so_ptr; lnum++) { + n++; + // stop at end of file or when we know we are far off + if (lnum >= curbuf->b_ml.ml_line_count || n >= halfheight) { break; + } (void)hasFolding(lnum, NULL, &lnum); } - } else - n = curwin->w_topline + p_so - curwin->w_cursor.lnum; + } else { + n = curwin->w_topline + *so_ptr - curwin->w_cursor.lnum; + } /* If we weren't very close to begin with, we scroll to put the * cursor in the middle of the window. Otherwise put the cursor @@ -247,7 +254,7 @@ void update_topline(void) if (curwin->w_botline <= curbuf->b_ml.ml_line_count) { if (curwin->w_cursor.lnum < curwin->w_botline) { if (((long)curwin->w_cursor.lnum - >= (long)curwin->w_botline - p_so + >= (long)curwin->w_botline - *so_ptr || hasAnyFolding(curwin) )) { lineoff_T loff; @@ -266,13 +273,15 @@ void update_topline(void) && (loff.lnum + 1 < curwin->w_botline || loff.fill == 0) ) { n += loff.height; - if (n >= p_so) + if (n >= *so_ptr) { break; + } botline_forw(&loff); } - if (n >= p_so) - /* sufficient context, no need to scroll */ + if (n >= *so_ptr) { + // sufficient context, no need to scroll check_botline = false; + } } else { /* sufficient context, no need to scroll */ check_botline = false; @@ -285,7 +294,7 @@ void update_topline(void) * botline - p_so (approximation of how much will be * scrolled). */ for (linenr_T lnum = curwin->w_cursor.lnum; - lnum >= curwin->w_botline - p_so; lnum--) { + lnum >= curwin->w_botline - *so_ptr; lnum--) { line_count++; // stop at end of file or when we know we are far off if (lnum <= 0 || line_count > curwin->w_height_inner + 1) { @@ -295,7 +304,7 @@ void update_topline(void) } } else line_count = curwin->w_cursor.lnum - curwin->w_botline - + 1 + p_so; + + 1 + *so_ptr; if (line_count <= curwin->w_height_inner + 1) { scroll_cursor_bot(scrolljump_value(), false); } else { @@ -305,6 +314,7 @@ void update_topline(void) } } curwin->w_valid |= VALID_TOPLINE; + curwin->w_viewport_invalid = true; win_check_anchored_floats(curwin); /* @@ -324,7 +334,7 @@ void update_topline(void) validate_cursor(); } - p_so = save_so; + *so_ptr = save_so; } /* @@ -356,25 +366,28 @@ static int scrolljump_value(void) */ static bool check_top_offset(void) { - if (curwin->w_cursor.lnum < curwin->w_topline + p_so + long so = get_scrolloff_value(); + if (curwin->w_cursor.lnum < curwin->w_topline + so || hasAnyFolding(curwin) ) { lineoff_T loff; loff.lnum = curwin->w_cursor.lnum; loff.fill = 0; - int n = curwin->w_topfill; /* always have this context */ - /* Count the visible screen lines above the cursor line. */ - while (n < p_so) { + int n = curwin->w_topfill; // always have this context + // Count the visible screen lines above the cursor line. + while (n < so) { topline_back(&loff); - /* Stop when included a line above the window. */ + // Stop when included a line above the window. if (loff.lnum < curwin->w_topline || (loff.lnum == curwin->w_topline && loff.fill > 0) - ) + ) { break; + } n += loff.height; } - if (n < p_so) + if (n < so) { return true; + } } return false; } @@ -398,6 +411,7 @@ void check_cursor_moved(win_T *wp) |VALID_CHEIGHT|VALID_CROW|VALID_TOPLINE); wp->w_valid_cursor = wp->w_cursor; wp->w_valid_leftcol = wp->w_leftcol; + wp->w_viewport_invalid = true; } else if (wp->w_cursor.col != wp->w_valid_cursor.col || wp->w_leftcol != wp->w_valid_leftcol || wp->w_cursor.coladd != wp->w_valid_cursor.coladd @@ -406,6 +420,7 @@ void check_cursor_moved(win_T *wp) wp->w_valid_cursor.col = wp->w_cursor.col; wp->w_valid_leftcol = wp->w_leftcol; wp->w_valid_cursor.coladd = wp->w_cursor.coladd; + wp->w_viewport_invalid = true; } } @@ -674,7 +689,7 @@ int win_col_off(win_T *wp) { return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0) + (cmdwin_type == 0 || wp != curwin ? 0 : 1) - + (int)wp->w_p_fdc + + win_fdccol_count(wp) + (win_signcol_count(wp) * win_signcol_width(wp)); } @@ -714,6 +729,8 @@ void curs_columns( colnr_T startcol; colnr_T endcol; colnr_T prev_skipcol; + long so = get_scrolloff_value(); + long siso = get_sidescrolloff_value(); /* * First make sure that w_topline is valid (after moving the cursor). @@ -785,10 +802,10 @@ void curs_columns( * If we get closer to the edge than 'sidescrolloff', scroll a little * extra */ - assert(p_siso <= INT_MAX); - int off_left = startcol - curwin->w_leftcol - (int)p_siso; + assert(siso <= INT_MAX); + int off_left = startcol - curwin->w_leftcol - (int)siso; int off_right = - endcol - curwin->w_leftcol - curwin->w_width_inner + (int)p_siso + 1; + endcol - curwin->w_leftcol - curwin->w_width_inner + (int)siso + 1; if (off_left < 0 || off_right > 0) { int diff = (off_left < 0) ? -off_left: off_right; @@ -834,7 +851,7 @@ void curs_columns( int plines = 0; if ((curwin->w_wrow >= curwin->w_height_inner || ((prev_skipcol > 0 - || curwin->w_wrow + p_so >= curwin->w_height_inner) + || curwin->w_wrow + so >= curwin->w_height_inner) && (plines = plines_win_nofill(curwin, curwin->w_cursor.lnum, false)) - 1 >= curwin->w_height_inner)) @@ -850,17 +867,18 @@ void curs_columns( * 2: Less than "p_so" lines below * 3: both of them */ extra = 0; - if (curwin->w_skipcol + p_so * width > curwin->w_virtcol) + if (curwin->w_skipcol + so * width > curwin->w_virtcol) { extra = 1; - /* Compute last display line of the buffer line that we want at the - * bottom of the window. */ + } + // Compute last display line of the buffer line that we want at the + // bottom of the window. if (plines == 0) { plines = plines_win(curwin, curwin->w_cursor.lnum, false); } plines--; - if (plines > curwin->w_wrow + p_so) { - assert(p_so <= INT_MAX); - n = curwin->w_wrow + (int)p_so; + if (plines > curwin->w_wrow + so) { + assert(so <= INT_MAX); + n = curwin->w_wrow + (int)so; } else { n = plines; } @@ -868,7 +886,7 @@ void curs_columns( extra += 2; } - if (extra == 3 || plines < p_so * 2) { + if (extra == 3 || plines < so * 2) { // not enough room for 'scrolloff', put cursor in the middle n = curwin->w_virtcol / width; if (n > curwin->w_height_inner / 2) { @@ -882,9 +900,9 @@ void curs_columns( } curwin->w_skipcol = n * width; } else if (extra == 1) { - /* less then 'scrolloff' lines above, decrease skipcol */ - assert(p_so <= INT_MAX); - extra = (curwin->w_skipcol + (int)p_so * width - curwin->w_virtcol + // less then 'scrolloff' lines above, decrease skipcol + assert(so <= INT_MAX); + extra = (curwin->w_skipcol + (int)so * width - curwin->w_virtcol + width - 1) / width; if (extra > 0) { if ((colnr_T)(extra * width) > curwin->w_skipcol) @@ -1206,7 +1224,7 @@ void scrolldown_clamp(void) end_row += curwin->w_cline_height - 1 - curwin->w_virtcol / curwin->w_width_inner; } - if (end_row < curwin->w_height_inner - p_so) { + if (end_row < curwin->w_height_inner - get_scrolloff_value()) { if (can_fill) { ++curwin->w_topfill; check_topfill(curwin, true); @@ -1246,14 +1264,14 @@ void scrollup_clamp(void) validate_virtcol(); start_row -= curwin->w_virtcol / curwin->w_width_inner; } - if (start_row >= p_so) { - if (curwin->w_topfill > 0) - --curwin->w_topfill; - else { + if (start_row >= get_scrolloff_value()) { + if (curwin->w_topfill > 0) { + curwin->w_topfill--; + } else { (void)hasFolding(curwin->w_topline, NULL, &curwin->w_topline); - ++curwin->w_topline; + curwin->w_topline++; } - ++curwin->w_botline; /* approximate w_botline */ + curwin->w_botline++; // approximate w_botline curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); } } @@ -1349,8 +1367,7 @@ void scroll_cursor_top(int min_scroll, int always) linenr_T old_topline = curwin->w_topline; linenr_T old_topfill = curwin->w_topfill; linenr_T new_topline; - assert(p_so <= INT_MAX); - int off = (int)p_so; + int off = (int)get_scrolloff_value(); if (mouse_dragging > 0) off = mouse_dragging - 1; @@ -1447,6 +1464,7 @@ void scroll_cursor_top(int min_scroll, int always) curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); curwin->w_valid |= VALID_TOPLINE; + curwin->w_viewport_invalid = true; } } @@ -1492,7 +1510,8 @@ void scroll_cursor_bot(int min_scroll, int set_topbot) linenr_T old_botline = curwin->w_botline; int old_valid = curwin->w_valid; int old_empty_rows = curwin->w_empty_rows; - linenr_T cln = curwin->w_cursor.lnum; /* Cursor Line Number */ + linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number + long so = get_scrolloff_value(); if (set_topbot) { used = 0; @@ -1551,7 +1570,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot) /* Stop when scrolled nothing or at least "min_scroll", found "extra" * context for 'scrolloff' and counted all lines below the window. */ if ((((scrolled <= 0 || scrolled >= min_scroll) - && extra >= (mouse_dragging > 0 ? mouse_dragging - 1 : p_so)) + && extra >= (mouse_dragging > 0 ? mouse_dragging - 1 : so)) || boff.lnum + 1 > curbuf->b_ml.ml_line_count) && loff.lnum <= curwin->w_botline && (loff.lnum < curwin->w_botline @@ -1589,7 +1608,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot) if (used > curwin->w_height_inner) { break; } - if (extra < (mouse_dragging > 0 ? mouse_dragging - 1 : p_so) + if (extra < (mouse_dragging > 0 ? mouse_dragging - 1 : so) || scrolled < min_scroll) { extra += boff.height; if (boff.lnum >= curwin->w_botline @@ -1650,6 +1669,7 @@ void scroll_cursor_bot(int min_scroll, int set_topbot) curwin->w_valid = old_valid; } curwin->w_valid |= VALID_TOPLINE; + curwin->w_viewport_invalid = true; } /// Recompute topline to put the cursor halfway across the window @@ -1724,9 +1744,8 @@ void cursor_correct(void) * How many lines we would like to have above/below the cursor depends on * whether the first/last line of the file is on screen. */ - assert(p_so <= INT_MAX); - int above_wanted = (int)p_so; - int below_wanted = (int)p_so; + int above_wanted = (int)get_scrolloff_value(); + int below_wanted = (int)get_scrolloff_value(); if (mouse_dragging > 0) { above_wanted = mouse_dragging - 1; below_wanted = mouse_dragging - 1; @@ -1807,6 +1826,7 @@ void cursor_correct(void) } } curwin->w_valid |= VALID_TOPLINE; + curwin->w_viewport_invalid = true; } @@ -1821,6 +1841,7 @@ int onepage(Direction dir, long count) int retval = OK; lineoff_T loff; linenr_T old_topline = curwin->w_topline; + long so = get_scrolloff_value(); if (curbuf->b_ml.ml_line_count == 1) { /* nothing to do */ beep_flush(); @@ -1836,7 +1857,7 @@ int onepage(Direction dir, long count) * last line. */ if (dir == FORWARD - ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so) + ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so) && curwin->w_botline > curbuf->b_ml.ml_line_count) : (curwin->w_topline == 1 && curwin->w_topfill == diff --git a/src/nvim/msgpack_rpc/channel.h b/src/nvim/msgpack_rpc/channel.h index 9ff5abdc5f..90e1c7d48b 100644 --- a/src/nvim/msgpack_rpc/channel.h +++ b/src/nvim/msgpack_rpc/channel.h @@ -15,7 +15,7 @@ /// HACK: os/input.c drains this queue immediately before blocking for input. /// Events on this queue are async-safe, but they need the resolved state /// of os_inchar(), so they are processed "just-in-time". -MultiQueue *ch_before_blocking_events; +EXTERN MultiQueue *ch_before_blocking_events INIT(= NULL); #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c index 6168f097a7..062ea784ca 100644 --- a/src/nvim/msgpack_rpc/server.c +++ b/src/nvim/msgpack_rpc/server.c @@ -151,7 +151,7 @@ int server_start(const char *endpoint) result = socket_watcher_start(watcher, MAX_CONNECTIONS, connection_cb); if (result < 0) { - WLOG("Failed to start server: %s", uv_strerror(result)); + WLOG("Failed to start server: %s: %s", uv_strerror(result), watcher->addr); socket_watcher_close(watcher, free_server); return result; } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index c53348db0d..2cc492b652 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -615,7 +615,9 @@ static void normal_redraw_mode_message(NormalState *s) kmsg = keep_msg; keep_msg = NULL; - // showmode() will clear keep_msg, but we want to use it anyway + // Showmode() will clear keep_msg, but we want to use it anyway. + // First update w_topline. + setcursor(); update_screen(0); // now reset it, otherwise it's put in the history again keep_msg = kmsg; @@ -623,6 +625,7 @@ static void normal_redraw_mode_message(NormalState *s) xfree(kmsg); } setcursor(); + ui_cursor_shape(); // show different cursor shape ui_flush(); if (msg_scroll || emsg_on_display) { os_delay(1000L, true); // wait at least one second @@ -1964,8 +1967,8 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) break; case OP_FOLD: - VIsual_reselect = false; /* don't reselect now */ - foldCreate(oap->start.lnum, oap->end.lnum); + VIsual_reselect = false; // don't reselect now + foldCreate(curwin, oap->start.lnum, oap->end.lnum); break; case OP_FOLDOPEN: @@ -1983,9 +1986,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) case OP_FOLDDEL: case OP_FOLDDELREC: - VIsual_reselect = false; /* don't reselect now */ - deleteFold(oap->start.lnum, oap->end.lnum, - oap->op_type == OP_FOLDDELREC, oap->is_VIsual); + VIsual_reselect = false; // don't reselect now + deleteFold(curwin, oap->start.lnum, oap->end.lnum, + oap->op_type == OP_FOLDDELREC, oap->is_VIsual); break; case OP_NR_ADD: @@ -2584,12 +2587,13 @@ do_mouse ( /* Set global flag that we are extending the Visual area with mouse * dragging; temporarily minimize 'scrolloff'. */ - if (VIsual_active && is_drag && p_so) { - /* In the very first line, allow scrolling one line */ - if (mouse_row == 0) + if (VIsual_active && is_drag && get_scrolloff_value()) { + // In the very first line, allow scrolling one line + if (mouse_row == 0) { mouse_dragging = 2; - else + } else { mouse_dragging = 1; + } } /* When dragging the mouse above the window, scroll down. */ @@ -4089,9 +4093,9 @@ void scroll_redraw(int up, long count) scrollup(count, true); else scrolldown(count, true); - if (p_so) { - /* Adjust the cursor position for 'scrolloff'. Mark w_topline as - * valid, otherwise the screen jumps back at the end of the file. */ + if (get_scrolloff_value()) { + // Adjust the cursor position for 'scrolloff'. Mark w_topline as + // valid, otherwise the screen jumps back at the end of the file. cursor_correct(); check_cursor_moved(curwin); curwin->w_valid |= VALID_TOPLINE; @@ -4120,6 +4124,7 @@ void scroll_redraw(int up, long count) } if (curwin->w_cursor.lnum != prev_lnum) coladvance(curwin->w_curswant); + curwin->w_viewport_invalid = true; redraw_later(VALID); } @@ -4135,8 +4140,8 @@ static void nv_zet(cmdarg_T *cap) int old_fen = curwin->w_p_fen; bool undo = false; - assert(p_siso <= INT_MAX); - int l_p_siso = (int)p_siso; + int l_p_siso = (int)get_sidescrolloff_value(); + assert(l_p_siso <= INT_MAX); if (ascii_isdigit(nchar)) { /* @@ -4340,11 +4345,12 @@ dozet: /* "zD": delete fold at cursor recursively */ case 'd': case 'D': if (foldManualAllowed(false)) { - if (VIsual_active) + if (VIsual_active) { nv_operator(cap); - else - deleteFold(curwin->w_cursor.lnum, - curwin->w_cursor.lnum, nchar == 'D', false); + } else { + deleteFold(curwin, curwin->w_cursor.lnum, + curwin->w_cursor.lnum, nchar == 'D', false); + } } break; @@ -4352,11 +4358,11 @@ dozet: case 'E': if (foldmethodIsManual(curwin)) { clearFolding(curwin); changed_window_setting(); - } else if (foldmethodIsMarker(curwin)) - deleteFold((linenr_T)1, curbuf->b_ml.ml_line_count, - true, false); - else + } else if (foldmethodIsMarker(curwin)) { + deleteFold(curwin, (linenr_T)1, curbuf->b_ml.ml_line_count, true, false); + } else { EMSG(_("E352: Cannot erase folds with current 'foldmethod'")); + } break; /* "zn": fold none: reset 'foldenable' */ @@ -4458,16 +4464,16 @@ dozet: case 'r': curwin->w_p_fdl += cap->count1; { - int d = getDeepestNesting(); + int d = getDeepestNesting(curwin); if (curwin->w_p_fdl >= d) { curwin->w_p_fdl = d; } } break; - /* "zR": open all folds */ - case 'R': curwin->w_p_fdl = getDeepestNesting(); - old_fdl = -1; /* force an update */ + case 'R': // "zR": open all folds + curwin->w_p_fdl = getDeepestNesting(curwin); + old_fdl = -1; // force an update break; case 'j': /* "zj" move to next fold downwards */ diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 735a33ca97..a70224f98b 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -261,7 +261,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount) sprintf((char *)IObuff, _("%" PRId64 " lines %sed %d times"), (int64_t)oap->line_count, s, amount); } - msg(IObuff); + msg_attr_keep(IObuff, 0, true, false); } /* @@ -842,6 +842,15 @@ static bool is_append_register(int regname) return ASCII_ISUPPER(regname); } +/// @see get_yank_register +/// @returns true when register should be inserted literally +/// (selection or clipboard) +static inline bool is_literal_register(int regname) + FUNC_ATTR_CONST +{ + return regname == '*' || regname == '+'; +} + /// Returns a copy of contents in register `name` /// for use in do_put. Should be freed by caller. yankreg_T *copy_register(int name) @@ -1152,11 +1161,12 @@ static int put_in_typebuf( */ int insert_reg( int regname, - int literally /* insert literally, not as if typed */ + bool literally_arg // insert literally, not as if typed ) { int retval = OK; bool allocated; + const bool literally = literally_arg || is_literal_register(regname); /* * It is possible to get into an endless loop by having CTRL-R a in @@ -1326,12 +1336,14 @@ bool get_spec_reg( /// register contents will be interpreted as commands. /// /// @param regname Register name. -/// @param literally Insert text literally instead of "as typed". +/// @param literally_arg Insert text literally instead of "as typed". /// @param remcr When true, don't add CR characters. /// /// @returns FAIL for failure, OK otherwise -bool cmdline_paste_reg(int regname, bool literally, bool remcr) +bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr) { + const bool literally = literally_arg || is_literal_register(regname); + yankreg_T *reg = get_yank_register(regname, YREG_PASTE); if (reg->y_array == NULL) return FAIL; @@ -2534,7 +2546,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) case kMTCharWise: { colnr_T startcol = 0, endcol = MAXCOL; - int is_oneChar = FALSE; + int is_oneChar = false; colnr_T cs, ce; p = ml_get(lnum); bd.startspaces = 0; @@ -2565,8 +2577,8 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append) && utf_head_off(p, p + endcol) == 0)) { if (oap->start.lnum == oap->end.lnum && oap->start.col == oap->end.col) { - /* Special case: inside a single char */ - is_oneChar = TRUE; + // Special case: inside a single char + is_oneChar = true; bd.startspaces = oap->end.coladd - oap->start.coladd + oap->inclusive; endcol = startcol; @@ -4425,8 +4437,8 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bdp->textlen = 0; bdp->start_vcol = 0; bdp->end_vcol = 0; - bdp->is_short = FALSE; - bdp->is_oneChar = FALSE; + bdp->is_short = false; + bdp->is_oneChar = false; bdp->pre_whitesp = 0; bdp->pre_whitesp_c = 0; bdp->end_char_vcols = 0; @@ -4452,9 +4464,10 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bdp->start_char_vcols = incr; if (bdp->start_vcol < oap->start_vcol) { /* line too short */ bdp->end_vcol = bdp->start_vcol; - bdp->is_short = TRUE; - if (!is_del || oap->op_type == OP_APPEND) + bdp->is_short = true; + if (!is_del || oap->op_type == OP_APPEND) { bdp->endspaces = oap->end_vcol - oap->start_vcol + 1; + } } else { /* notice: this converts partly selected Multibyte characters to * spaces, too. */ @@ -4463,11 +4476,11 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, bdp->startspaces = bdp->start_char_vcols - bdp->startspaces; pend = pstart; bdp->end_vcol = bdp->start_vcol; - if (bdp->end_vcol > oap->end_vcol) { /* it's all in one character */ - bdp->is_oneChar = TRUE; - if (oap->op_type == OP_INSERT) + if (bdp->end_vcol > oap->end_vcol) { // it's all in one character + bdp->is_oneChar = true; + if (oap->op_type == OP_INSERT) { bdp->endspaces = bdp->start_char_vcols - bdp->startspaces; - else if (oap->op_type == OP_APPEND) { + } else if (oap->op_type == OP_APPEND) { bdp->startspaces += oap->end_vcol - oap->start_vcol + 1; bdp->endspaces = bdp->start_char_vcols - bdp->startspaces; } else { @@ -4492,17 +4505,16 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, if (bdp->end_vcol <= oap->end_vcol && (!is_del || oap->op_type == OP_APPEND - || oap->op_type == OP_REPLACE)) { /* line too short */ - bdp->is_short = TRUE; - /* Alternative: include spaces to fill up the block. - * Disadvantage: can lead to trailing spaces when the line is - * short where the text is put */ - /* if (!is_del || oap->op_type == OP_APPEND) */ - if (oap->op_type == OP_APPEND || virtual_op) + || oap->op_type == OP_REPLACE)) { // line too short + bdp->is_short = true; + // Alternative: include spaces to fill up the block. + // Disadvantage: can lead to trailing spaces when the line is + // short where the text is put + // if (!is_del || oap->op_type == OP_APPEND) + if (oap->op_type == OP_APPEND || virtual_op) { bdp->endspaces = oap->end_vcol - bdp->end_vcol + oap->inclusive; - else - bdp->endspaces = 0; /* replace doesn't add characters */ + } } else if (bdp->end_vcol > oap->end_vcol) { bdp->endspaces = bdp->end_vcol - oap->end_vcol - 1; if (!is_del && bdp->endspaces) { diff --git a/src/nvim/option.c b/src/nvim/option.c index 100902897a..25a8d432ee 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -315,6 +315,9 @@ static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2", "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9", "yes:1", "yes:2", "yes:3", "yes:4", "yes:5", "yes:6", "yes:7", "yes:8", "yes:9", NULL }; +static char *(p_fdc_values[]) = { "auto:1", "auto:2", + "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL }; /// All possible flags for 'shm'. static char_u SHM_ALL[] = { @@ -616,11 +619,9 @@ static void set_runtimepath_default(void) #undef NVIM_SIZE -/* - * Initialize the options, first part. - * - * Called only once from main(), just after creating the first buffer. - */ +/// Initialize the options, first part. +/// +/// Called only once from main(), just after creating the first buffer. void set_init_1(void) { int opt_idx; @@ -865,10 +866,8 @@ void set_init_1(void) set_helplang_default(get_mess_lang()); } -/* - * Set an option to its default value. - * This does not take care of side effects! - */ +/// Set an option to its default value. +/// This does not take care of side effects! static void set_option_default( int opt_idx, @@ -901,11 +900,19 @@ set_option_default( if (options[opt_idx].indir == PV_SCROLL) { win_comp_scroll(curwin); } else { - *(long *)varp = (long)(intptr_t)options[opt_idx].def_val[dvi]; + long def_val = (long)options[opt_idx].def_val[dvi]; + if ((long *)varp == &curwin->w_p_so + || (long *)varp == &curwin->w_p_siso) { + // 'scrolloff' and 'sidescrolloff' local values have a + // different default value than the global default. + *(long *)varp = -1; + } else { + *(long *)varp = def_val; + } // May also set global value for local option. if (both) { *(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = - *(long *)varp; + def_val; } } } else { // P_BOOL @@ -931,9 +938,7 @@ set_option_default( set_option_sctx_idx(opt_idx, opt_flags, current_sctx); } -/* - * Set all options (except terminal options) to their default value. - */ +/// Set all options (except terminal options) to their default value. static void set_options_default( int opt_flags // OPT_FREE, OPT_LOCAL and/or OPT_GLOBAL @@ -976,10 +981,8 @@ static void set_string_default(const char *name, char *val, bool allocated) } } -/* - * Set the Vi-default value of a number option. - * Used for 'lines' and 'columns'. - */ +/// Set the Vi-default value of a number option. +/// Used for 'lines' and 'columns'. void set_number_default(char *name, long val) { int opt_idx; @@ -1106,10 +1109,8 @@ void set_init_3(void) set_title_defaults(); // 'title', 'icon' } -/* - * When 'helplang' is still at its default value, set it to "lang". - * Only the first two characters of "lang" are used. - */ +/// When 'helplang' is still at its default value, set it to "lang". +/// Only the first two characters of "lang" are used. void set_helplang_default(const char *lang) { if (lang == NULL) { @@ -1141,13 +1142,11 @@ void set_helplang_default(const char *lang) } -/* - * 'title' and 'icon' only default to true if they have not been set or reset - * in .vimrc and we can read the old value. - * When 'title' and 'icon' have been reset in .vimrc, we won't even check if - * they can be reset. This reduces startup time when using X on a remote - * machine. - */ +/// 'title' and 'icon' only default to true if they have not been set or reset +/// in .vimrc and we can read the old value. +/// When 'title' and 'icon' have been reset in .vimrc, we won't even check if +/// they can be reset. This reduces startup time when using X on a remote +/// machine. void set_title_defaults(void) { int idx1; @@ -2012,10 +2011,8 @@ static char_u *illegal_char(char_u *errbuf, size_t errbuflen, int c) return errbuf; } -/* - * Convert a key name or string into a key value. - * Used for 'wildchar' and 'cedit' options. - */ +/// Convert a key name or string into a key value. +/// Used for 'wildchar' and 'cedit' options. static int string_to_key(char_u *arg) { if (*arg == '<') { @@ -2027,10 +2024,8 @@ static int string_to_key(char_u *arg) return *arg; } -/* - * Check value of 'cedit' and set cedit_key. - * Returns NULL if value is OK, error message otherwise. - */ +/// Check value of 'cedit' and set cedit_key. +/// Returns NULL if value is OK, error message otherwise. static char_u *check_cedit(void) { int n; @@ -2114,13 +2109,11 @@ void set_options_bin( } } -/* - * Find the parameter represented by the given character (eg ', :, ", or /), - * and return its associated value in the 'shada' string. - * Only works for number parameters, not for 'r' or 'n'. - * If the parameter is not specified in the string or there is no following - * number, return -1. - */ +/// Find the parameter represented by the given character (eg ', :, ", or /), +/// and return its associated value in the 'shada' string. +/// Only works for number parameters, not for 'r' or 'n'. +/// If the parameter is not specified in the string or there is no following +/// number, return -1. int get_shada_parameter(int type) { char_u *p; @@ -2132,11 +2125,9 @@ int get_shada_parameter(int type) return -1; } -/* - * Find the parameter represented by the given character (eg ''', ':', '"', or - * '/') in the 'shada' option and return a pointer to the string after it. - * Return NULL if the parameter is not specified in the string. - */ +/// Find the parameter represented by the given character (eg ''', ':', '"', or +/// '/') in the 'shada' option and return a pointer to the string after it. +/// Return NULL if the parameter is not specified in the string. char_u *find_shada_parameter(int type) { char_u *p; @@ -2156,12 +2147,10 @@ char_u *find_shada_parameter(int type) return NULL; } -/* - * Expand environment variables for some string options. - * These string options cannot be indirect! - * If "val" is NULL expand the current value of the option. - * Return pointer to NameBuff, or NULL when not expanded. - */ +/// Expand environment variables for some string options. +/// These string options cannot be indirect! +/// If "val" is NULL expand the current value of the option. +/// Return pointer to NameBuff, or NULL when not expanded. static char_u *option_expand(int opt_idx, char_u *val) { // if option doesn't need expansion nothing to do @@ -2245,9 +2234,7 @@ static void didset_options2(void) check_opt_wim(); } -/* - * Check for string options that are NULL (normally only termcap options). - */ +/// Check for string options that are NULL (normally only termcap options). void check_options(void) { int opt_idx; @@ -2259,9 +2246,7 @@ void check_options(void) } } -/* - * Check string options in a buffer for NULL value. - */ +/// Check string options in a buffer for NULL value. void check_buf_options(buf_T *buf) { check_string_option(&buf->b_p_bh); @@ -2314,13 +2299,11 @@ void check_buf_options(buf_T *buf) check_string_option(&buf->b_p_menc); } -/* - * Free the string allocated for an option. - * Checks for the string being empty_option. This may happen if we're out of - * memory, vim_strsave() returned NULL, which was replaced by empty_option by - * check_options(). - * Does NOT check for P_ALLOCED flag! - */ +/// Free the string allocated for an option. +/// Checks for the string being empty_option. This may happen if we're out of +/// memory, vim_strsave() returned NULL, which was replaced by empty_option by +/// check_options(). +/// Does NOT check for P_ALLOCED flag! void free_string_option(char_u *p) { if (p != empty_option) { @@ -2358,10 +2341,8 @@ int was_set_insecurely(char_u *opt, int opt_flags) return -1; } -/* - * Get a pointer to the flags used for the P_INSECURE flag of option - * "opt_idx". For some local options a local flags field is used. - */ +/// Get a pointer to the flags used for the P_INSECURE flag of option +/// "opt_idx". For some local options a local flags field is used. static uint32_t *insecure_flag(int opt_idx, int opt_flags) { if (opt_flags & OPT_LOCAL) @@ -2379,9 +2360,7 @@ static uint32_t *insecure_flag(int opt_idx, int opt_flags) } -/* - * Redraw the window title and/or tab page text later. - */ +/// Redraw the window title and/or tab page text later. static void redraw_titles(void) { need_maketitle = true; @@ -2462,9 +2441,7 @@ set_string_option_direct( } } -/* - * Set global value for string option when it's a local option. - */ +/// Set global value for string option when it's a local option. static void set_string_option_global( int opt_idx, // option index @@ -2565,7 +2542,7 @@ static bool valid_filetype(const char_u *val) bool valid_spellang(const char_u *val) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return valid_name(val, ".-_,"); + return valid_name(val, ".-_,@"); } /// Return true if "val" is a valid 'spellfile' value. @@ -3199,6 +3176,11 @@ ambw_end: if (check_opt_strings(*varp, p_scl_values, false) != OK) { errmsg = e_invarg; } + } else if (varp == &curwin->w_p_fdc || varp == &curwin->w_allbuf_opt.wo_fdc) { + // 'foldcolumn' + if (check_opt_strings(*varp, p_fdc_values, false) != OK) { + errmsg = e_invarg; + } } else if (varp == &p_pt) { // 'pastetoggle': translate key codes like in a mapping if (*p_pt) { @@ -3652,7 +3634,7 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set) } // first round: check for valid value, second round: assign values - for (round = 0; round <= set ? 1 : 0; round++) { + for (round = 0; round <= (set ? 1 : 0); round++) { if (round > 0) { // After checking that the value is valid: set defaults for (i = 0; i < entries; i++) { @@ -3726,10 +3708,8 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set) return NULL; // no error } -/* - * Check validity of options with the 'statusline' format. - * Return error message or NULL. - */ +/// Check validity of options with the 'statusline' format. +/// Return error message or NULL. char_u *check_stl_option(char_u *s) { int itemcnt = 0; @@ -3822,16 +3802,15 @@ static char_u *did_set_spell_option(bool is_spellfile) return errmsg; } -/* - * Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'. - * Return error message when failed, NULL when OK. - */ +/// Set curbuf->b_cap_prog to the regexp program for 'spellcapcheck'. +/// Return error message when failed, NULL when OK. static char_u *compile_cap_prog(synblock_T *synblock) + FUNC_ATTR_NONNULL_ALL { regprog_T *rp = synblock->b_cap_prog; char_u *re; - if (*synblock->b_p_spc == NUL) { + if (synblock->b_p_spc == NULL || *synblock->b_p_spc == NUL) { synblock->b_cap_prog = NULL; } else { // Prepend a ^ so that we only match at one column @@ -4341,7 +4320,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, } } else if (pp == &p_so) { if (value < 0 && full_screen) { - errmsg = e_scroll; + errmsg = e_positive; } } else if (pp == &p_siso) { if (value < 0 && full_screen) { @@ -4363,12 +4342,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, if (value < 0) { errmsg = e_positive; } - } else if (pp == &curwin->w_p_fdc || pp == &curwin->w_allbuf_opt.wo_fdc) { - if (value < 0) { - errmsg = e_positive; - } else if (value > 12) { - errmsg = e_invarg; - } } else if (pp == &curwin->w_p_cole || pp == &curwin->w_allbuf_opt.wo_cole) { if (value < 0) { errmsg = e_positive; @@ -4672,9 +4645,7 @@ static void trigger_optionsset_string(int opt_idx, int opt_flags, } } -/* - * Called after an option changed: check if something needs to be redrawn. - */ +/// Called after an option changed: check if something needs to be redrawn. static void check_redraw(uint32_t flags) { // Careful: P_RCLR and P_RALL are a combination of other P_ flags @@ -5129,10 +5100,8 @@ static int find_key_option(const char_u *arg, bool has_lt) return find_key_option_len(arg, STRLEN(arg), has_lt); } -/* - * if 'all' == 0: show changed options - * if 'all' == 1: show all normal options - */ +/// if 'all' == 0: show changed options +/// if 'all' == 1: show all normal options static void showoptions( int all, @@ -5281,10 +5250,8 @@ void ui_refresh_options(void) } } -/* - * showoneopt: show the value of one option - * must not be called with a hidden option! - */ +/// showoneopt: show the value of one option +/// must not be called with a hidden option! static void showoneopt( vimoption_T *p, @@ -5320,28 +5287,26 @@ showoneopt( info_message = false; } -/* - * Write modified options as ":set" commands to a file. - * - * There are three values for "opt_flags": - * OPT_GLOBAL: Write global option values and fresh values of - * buffer-local options (used for start of a session - * file). - * OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for - * curwin (used for a vimrc file). - * OPT_LOCAL: Write buffer-local option values for curbuf, fresh - * and local values for window-local options of - * curwin. Local values are also written when at the - * default value, because a modeline or autocommand - * may have set them when doing ":edit file" and the - * user has set them back at the default or fresh - * value. - * When "local_only" is true, don't write fresh - * values, only local values (for ":mkview"). - * (fresh value = value used for a new buffer or window for a local option). - * - * Return FAIL on error, OK otherwise. - */ +/// Write modified options as ":set" commands to a file. +/// +/// There are three values for "opt_flags": +/// OPT_GLOBAL: Write global option values and fresh values of +/// buffer-local options (used for start of a session +/// file). +/// OPT_GLOBAL + OPT_LOCAL: Idem, add fresh values of window-local options for +/// curwin (used for a vimrc file). +/// OPT_LOCAL: Write buffer-local option values for curbuf, fresh +/// and local values for window-local options of +/// curwin. Local values are also written when at the +/// default value, because a modeline or autocommand +/// may have set them when doing ":edit file" and the +/// user has set them back at the default or fresh +/// value. +/// When "local_only" is true, don't write fresh +/// values, only local values (for ":mkview"). +/// (fresh value = value used for a new buffer or window for a local option). +/// +/// Return FAIL on error, OK otherwise. int makeset(FILE *fd, int opt_flags, int local_only) { vimoption_T *p; @@ -5452,10 +5417,8 @@ int makeset(FILE *fd, int opt_flags, int local_only) return OK; } -/* - * Generate set commands for the local fold options only. Used when - * 'sessionoptions' or 'viewoptions' contains "folds" but not "options". - */ +/// Generate set commands for the local fold options only. Used when +/// 'sessionoptions' or 'viewoptions' contains "folds" but not "options". int makefoldset(FILE *fd) { if (put_setstring(fd, "setlocal", "fdm", &curwin->w_p_fdm, false) == FAIL @@ -5548,12 +5511,10 @@ static int put_setbool(FILE *fd, char *cmd, char *name, int value) return OK; } -/* - * Compute columns for ruler and shown command. 'sc_col' is also used to - * decide what the maximum length of a message on the status line can be. - * If there is a status line for the last window, 'sc_col' is independent - * of 'ru_col'. - */ +/// Compute columns for ruler and shown command. 'sc_col' is also used to +/// decide what the maximum length of a message on the status line can be. +/// If there is a status line for the last window, 'sc_col' is independent +/// of 'ru_col'. #define COL_RULER 17 // columns needed by standard ruler @@ -5632,6 +5593,12 @@ void unset_global_local_option(char *name, void *from) clear_string_option(&buf->b_p_tc); buf->b_tc_flags = 0; break; + case PV_SISO: + curwin->w_p_siso = -1; + break; + case PV_SO: + curwin->w_p_so = -1; + break; case PV_DEF: clear_string_option(&buf->b_p_def); break; @@ -5681,9 +5648,7 @@ void unset_global_local_option(char *name, void *from) } } -/* - * Get pointer to option variable, depending on local or global scope. - */ +/// Get pointer to option variable, depending on local or global scope. static char_u *get_varp_scope(vimoption_T *p, int opt_flags) { if ((opt_flags & OPT_GLOBAL) && p->indir != PV_NONE) { @@ -5704,6 +5669,8 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags) case PV_AR: return (char_u *)&(curbuf->b_p_ar); case PV_TAGS: return (char_u *)&(curbuf->b_p_tags); case PV_TC: return (char_u *)&(curbuf->b_p_tc); + case PV_SISO: return (char_u *)&(curwin->w_p_siso); + case PV_SO: return (char_u *)&(curwin->w_p_so); case PV_DEF: return (char_u *)&(curbuf->b_p_def); case PV_INC: return (char_u *)&(curbuf->b_p_inc); case PV_DICT: return (char_u *)&(curbuf->b_p_dict); @@ -5722,9 +5689,7 @@ static char_u *get_varp_scope(vimoption_T *p, int opt_flags) return get_varp(p); } -/* - * Get pointer to option variable. - */ +/// Get pointer to option variable. static char_u *get_varp(vimoption_T *p) { // hidden option, always return NULL @@ -5748,6 +5713,10 @@ static char_u *get_varp(vimoption_T *p) ? (char_u *)&(curbuf->b_p_tags) : p->var; case PV_TC: return *curbuf->b_p_tc != NUL ? (char_u *)&(curbuf->b_p_tc) : p->var; + case PV_SISO: return curwin->w_p_siso >= 0 + ? (char_u *)&(curwin->w_p_siso) : p->var; + case PV_SO: return curwin->w_p_so >= 0 + ? (char_u *)&(curwin->w_p_so) : p->var; case PV_BKC: return *curbuf->b_p_bkc != NUL ? (char_u *)&(curbuf->b_p_bkc) : p->var; case PV_DEF: return *curbuf->b_p_def != NUL @@ -5882,9 +5851,7 @@ static char_u *get_varp(vimoption_T *p) return (char_u *)&(curbuf->b_p_wm); } -/* - * Get the value of 'equalprg', either the buffer-local one or the global one. - */ +/// Get the value of 'equalprg', either the buffer-local one or the global one. char_u *get_equalprg(void) { if (*curbuf->b_p_ep == NUL) { @@ -5893,22 +5860,18 @@ char_u *get_equalprg(void) return curbuf->b_p_ep; } -/* - * Copy options from one window to another. - * Used when splitting a window. - */ +/// Copy options from one window to another. +/// Used when splitting a window. void win_copy_options(win_T *wp_from, win_T *wp_to) { copy_winopt(&wp_from->w_onebuf_opt, &wp_to->w_onebuf_opt); copy_winopt(&wp_from->w_allbuf_opt, &wp_to->w_allbuf_opt); } -/* - * Copy the options from one winopt_T to another. - * Doesn't free the old option values in "to", use clear_winopt() for that. - * The 'scroll' option is not copied, because it depends on the window height. - * The 'previewwindow' option is reset, there can be only one preview window. - */ +/// Copy the options from one winopt_T to another. +/// Doesn't free the old option values in "to", use clear_winopt() for that. +/// The 'scroll' option is not copied, because it depends on the window height. +/// The 'previewwindow' option is reset, there can be only one preview window. void copy_winopt(winopt_T *from, winopt_T *to) { to->wo_arab = from->wo_arab; @@ -5936,8 +5899,9 @@ void copy_winopt(winopt_T *from, winopt_T *to) to->wo_diff_saved = from->wo_diff_saved; to->wo_cocu = vim_strsave(from->wo_cocu); to->wo_cole = from->wo_cole; - to->wo_fdc = from->wo_fdc; - to->wo_fdc_save = from->wo_fdc_save; + to->wo_fdc = vim_strsave(from->wo_fdc); + to->wo_fdc_save = from->wo_diff_saved + ? vim_strsave(from->wo_fdc_save) : empty_option; to->wo_fen = from->wo_fen; to->wo_fen_save = from->wo_fen_save; to->wo_fdi = vim_strsave(from->wo_fdi); @@ -5959,20 +5923,18 @@ void copy_winopt(winopt_T *from, winopt_T *to) check_winopt(to); // don't want NULL pointers } -/* - * Check string options in a window for a NULL value. - */ +/// Check string options in a window for a NULL value. void check_win_options(win_T *win) { check_winopt(&win->w_onebuf_opt); check_winopt(&win->w_allbuf_opt); } -/* - * Check for NULL pointers in a winopt_T and replace them with empty_option. - */ +/// Check for NULL pointers in a winopt_T and replace them with empty_option. static void check_winopt(winopt_T *wop) { + check_string_option(&wop->wo_fdc); + check_string_option(&wop->wo_fdc_save); check_string_option(&wop->wo_fdi); check_string_option(&wop->wo_fdm); check_string_option(&wop->wo_fdm_save); @@ -5990,11 +5952,11 @@ static void check_winopt(winopt_T *wop) check_string_option(&wop->wo_lcs); } -/* - * Free the allocated memory inside a winopt_T. - */ +/// Free the allocated memory inside a winopt_T. void clear_winopt(winopt_T *wop) { + clear_string_option(&wop->wo_fdc); + clear_string_option(&wop->wo_fdc_save); clear_string_option(&wop->wo_fdi); clear_string_option(&wop->wo_fdm); clear_string_option(&wop->wo_fdm_save); @@ -6023,15 +5985,13 @@ void didset_window_options(win_T *wp) } -/* - * Copy global option values to local options for one buffer. - * Used when creating a new buffer and sometimes when entering a buffer. - * flags: - * BCO_ENTER We will enter the buf buffer. - * BCO_ALWAYS Always copy the options, but only set b_p_initialized when - * appropriate. - * BCO_NOHELP Don't copy the values to a help buffer. - */ +/// Copy global option values to local options for one buffer. +/// Used when creating a new buffer and sometimes when entering a buffer. +/// flags: +/// BCO_ENTER We will enter the buf buffer. +/// BCO_ALWAYS Always copy the options, but only set b_p_initialized when +/// appropriate. +/// BCO_NOHELP Don't copy the values to a help buffer. void buf_copy_options(buf_T *buf, int flags) { int should_copy = true; @@ -6073,10 +6033,8 @@ void buf_copy_options(buf_T *buf, int flags) save_p_isk = buf->b_p_isk; buf->b_p_isk = NULL; } - /* - * Always free the allocated strings. - * If not already initialized, set 'readonly' and copy 'fileformat'. - */ + // Always free the allocated strings. If not already initialized, + // reset 'readonly' and copy 'fileformat'. if (!buf->b_p_initialized) { free_buf_options(buf, true); buf->b_p_ro = false; // don't copy readonly @@ -6228,9 +6186,7 @@ void buf_copy_options(buf_T *buf, int flags) } } -/* - * Reset the 'modifiable' option and its default value. - */ +/// Reset the 'modifiable' option and its default value. void reset_modifiable(void) { int opt_idx; @@ -6243,17 +6199,13 @@ void reset_modifiable(void) } } -/* - * Set the global value for 'iminsert' to the local value. - */ +/// Set the global value for 'iminsert' to the local value. void set_iminsert_global(void) { p_iminsert = curbuf->b_p_iminsert; } -/* - * Set the global value for 'imsearch' to the local value. - */ +/// Set the global value for 'imsearch' to the local value. void set_imsearch_global(void) { p_imsearch = curbuf->b_p_imsearch; @@ -6555,10 +6507,8 @@ void ExpandOldSetting(int *num_file, char_u ***file) *num_file = 1; } -/* - * Get the value for the numeric or string option *opp in a nice format into - * NameBuff[]. Must not be called with a hidden option! - */ +/// Get the value for the numeric or string option///opp in a nice format into +/// NameBuff[]. Must not be called with a hidden option! static void option_value2string( vimoption_T *opp, @@ -6611,21 +6561,18 @@ static int wc_use_keyname(char_u *varp, long *wcp) return false; } -/* - * Any character has an equivalent 'langmap' character. This is used for - * keyboards that have a special language mode that sends characters above - * 128 (although other characters can be translated too). The "to" field is a - * Vim command character. This avoids having to switch the keyboard back to - * ASCII mode when leaving Insert mode. - * - * langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim - * commands. - * langmap_mapga.ga_data is a sorted table of langmap_entry_T. - * This does the same as langmap_mapchar[] for characters >= 256. - */ -/* - * With multi-byte support use growarray for 'langmap' chars >= 256 - */ +/// Any character has an equivalent 'langmap' character. This is used for +/// keyboards that have a special language mode that sends characters above +/// 128 (although other characters can be translated too). The "to" field is a +/// Vim command character. This avoids having to switch the keyboard back to +/// ASCII mode when leaving Insert mode. +/// +/// langmap_mapchar[] maps any of 256 chars to an ASCII char used for Vim +/// commands. +/// langmap_mapga.ga_data is a sorted table of langmap_entry_T. +/// This does the same as langmap_mapchar[] for characters >= 256. +/// +/// With multi-byte support use growarray for 'langmap' chars >= 256 typedef struct { int from; int to; @@ -6633,10 +6580,8 @@ typedef struct { static garray_T langmap_mapga = GA_EMPTY_INIT_VALUE; -/* - * Search for an entry in "langmap_mapga" for "from". If found set the "to" - * field. If not found insert a new entry at the appropriate location. - */ +/// Search for an entry in "langmap_mapga" for "from". If found set the "to" +/// field. If not found insert a new entry at the appropriate location. static void langmap_set_entry(int from, int to) { langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); @@ -6671,9 +6616,7 @@ static void langmap_set_entry(int from, int to) entries[0].to = to; } -/* - * Apply 'langmap' to multi-byte character "c" and return the result. - */ +/// Apply 'langmap' to multi-byte character "c" and return the result. int langmap_adjust_mb(int c) { langmap_entry_T *entries = (langmap_entry_T *)(langmap_mapga.ga_data); @@ -6704,10 +6647,8 @@ static void langmap_init(void) ga_init(&langmap_mapga, sizeof(langmap_entry_T), 8); } -/* - * Called when langmap option is set; the language map can be - * changed at any time! - */ +/// Called when langmap option is set; the language map can be +/// changed at any time! static void langmap_set(void) { char_u *p; @@ -6810,9 +6751,7 @@ bool shortmess(int x) && vim_strchr((char_u *)SHM_ALL_ABBREVIATIONS, x) != NULL))); } -/* - * paste_option_changed() - Called after p_paste was set or reset. - */ +/// paste_option_changed() - Called after p_paste was set or reset. static void paste_option_changed(void) { static int old_p_paste = false; @@ -6959,9 +6898,7 @@ void reset_option_was_set(const char *name) } } -/* - * fill_breakat_flags() -- called when 'breakat' changes value. - */ +/// fill_breakat_flags() -- called when 'breakat' changes value. static void fill_breakat_flags(void) { char_u *p; @@ -6978,12 +6915,10 @@ static void fill_breakat_flags(void) } } -/* - * Check an option that can be a range of string values. - * - * Return OK for correct value, FAIL otherwise. - * Empty is always OK. - */ +/// Check an option that can be a range of string values. +/// +/// Return OK for correct value, FAIL otherwise. +/// Empty is always OK. static int check_opt_strings( char_u *val, char **values, @@ -6993,13 +6928,11 @@ static int check_opt_strings( return opt_strings_flags(val, values, NULL, list); } -/* - * Handle an option that can be a range of string values. - * Set a flag in "*flagp" for each string present. - * - * Return OK for correct value, FAIL otherwise. - * Empty is always OK. - */ +/// Handle an option that can be a range of string values. +/// Set a flag in "*flagp" for each string present. +/// +/// Return OK for correct value, FAIL otherwise. +/// Empty is always OK. static int opt_strings_flags( char_u *val, // new value char **values, // array of valid string values @@ -7032,9 +6965,7 @@ static int opt_strings_flags( return OK; } -/* - * Read the 'wildmode' option, fill wim_flags[]. - */ +/// Read the 'wildmode' option, fill wim_flags[]. static int check_opt_wim(void) { char_u new_wim_flags[4]; @@ -7085,11 +7016,9 @@ static int check_opt_wim(void) return OK; } -/* - * Check if backspacing over something is allowed. - * The parameter what is one of the following: whatBS_INDENT, BS_EOL - * or BS_START - */ +/// Check if backspacing over something is allowed. +/// The parameter what is one of the following: whatBS_INDENT, BS_EOL +/// or BS_START bool can_bs(int what) { if (what == BS_START && bt_prompt(curbuf)) { @@ -7103,10 +7032,8 @@ bool can_bs(int what) return vim_strchr(p_bs, what) != NULL; } -/* - * Save the current values of 'fileformat' and 'fileencoding', so that we know - * the file must be considered changed when the value is different. - */ +/// Save the current values of 'fileformat' and 'fileencoding', so that we know +/// the file must be considered changed when the value is different. void save_file_ff(buf_T *buf) { buf->b_start_ffc = *buf->b_p_ff; @@ -7156,18 +7083,14 @@ bool file_ff_differs(buf_T *buf, bool ignore_empty) return STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0; } -/* - * return OK if "p" is a valid fileformat name, FAIL otherwise. - */ +/// return OK if "p" is a valid fileformat name, FAIL otherwise. int check_ff_value(char_u *p) { return check_opt_strings(p, p_ff_values, false); } -/* - * Return the effective shiftwidth value for current buffer, using the - * 'tabstop' value when 'shiftwidth' is zero. - */ +/// Return the effective shiftwidth value for current buffer, using the +/// 'tabstop' value when 'shiftwidth' is zero. int get_sw_value(buf_T *buf) { long result = buf->b_p_sw ? buf->b_p_sw : buf->b_p_ts; @@ -7175,8 +7098,8 @@ int get_sw_value(buf_T *buf) return (int)result; } -// Return the effective softtabstop value for the current buffer, -// using the effective shiftwidth value when 'softtabstop' is negative. +/// Return the effective softtabstop value for the current buffer, +/// using the effective shiftwidth value when 'softtabstop' is negative. int get_sts_value(void) { long result = curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts; @@ -7184,12 +7107,10 @@ int get_sts_value(void) return (int)result; } -/* - * Check matchpairs option for "*initc". - * If there is a match set "*initc" to the matching character and "*findc" to - * the opposite character. Set "*backwards" to the direction. - * When "switchit" is true swap the direction. - */ +/// Check matchpairs option for "*initc". +/// If there is a match set "*initc" to the matching character and "*findc" to +/// the opposite character. Set "*backwards" to the direction. +/// When "switchit" is true swap the direction. void find_mps_values(int *initc, int *findc, int *backwards, int switchit) { char_u *ptr = curbuf->b_p_mps; @@ -7294,12 +7215,13 @@ int get_fileformat(buf_T *buf) /// argument. /// /// @param eap can be NULL! -int get_fileformat_force(buf_T *buf, exarg_T *eap) +int get_fileformat_force(const buf_T *buf, const exarg_T *eap) + FUNC_ATTR_NONNULL_ARG(1) { int c; if (eap != NULL && eap->force_ff != 0) { - c = eap->cmd[eap->force_ff]; + c = eap->force_ff; } else { if ((eap != NULL && eap->force_bin != 0) ? (eap->force_bin == FORCE_BIN) : buf->b_p_bin) { @@ -7479,3 +7401,18 @@ dict_T *get_winbuf_options(const int bufopt) return d; } + +/// Return the effective 'scrolloff' value for the current window, using the +/// global value when appropriate. +long get_scrolloff_value(void) +{ + return curwin->w_p_so < 0 ? p_so : curwin->w_p_so; +} + +/// Return the effective 'sidescrolloff' value for the current window, using the +/// global value when appropriate. +long get_sidescrolloff_value(void) +{ + return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso; +} + diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index c5d8b134c4..192e57a642 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -835,6 +835,8 @@ enum { , WV_RLC , WV_SCBIND , WV_SCROLL + , WV_SISO + , WV_SO , WV_SPELL , WV_CUC , WV_CUL diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 7d080b8d56..e7c1a3fe88 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -831,10 +831,11 @@ return { }, { full_name='foldcolumn', abbreviation='fdc', - type='number', scope={'window'}, + type='string', scope={'window'}, vi_def=true, + alloced=true, redraw={'current_window'}, - defaults={if_true={vi=false}} + defaults={if_true={vi="0"}} }, { full_name='foldenable', abbreviation='fen', @@ -1989,7 +1990,7 @@ return { }, { full_name='scrolloff', abbreviation='so', - type='number', scope={'global'}, + type='number', scope={'global', 'window'}, vi_def=true, vim=true, redraw={'all_windows'}, @@ -2228,10 +2229,10 @@ return { }, { full_name='sidescrolloff', abbreviation='siso', - type='number', scope={'global'}, + type='number', scope={'global', 'window'}, vi_def=true, vim=true, - redraw={'current_buffer'}, + redraw={'all_windows'}, varname='p_siso', defaults={if_true={vi=0}} }, @@ -2586,6 +2587,7 @@ return { type='bool', scope={'global'}, vi_def=true, vim=true, + redraw={'ui_option'}, varname='p_ttimeout', defaults={if_true={vi=true}} }, @@ -2593,6 +2595,7 @@ return { full_name='ttimeoutlen', abbreviation='ttm', type='number', scope={'global'}, vi_def=true, + redraw={'ui_option'}, varname='p_ttm', defaults={if_true={vi=50}} }, diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index ae922e4040..873b611151 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -1147,6 +1147,30 @@ bool os_fileid_equal_fileinfo(const FileID *file_id, && file_id->device_id == file_info->stat.st_dev; } +/// Return the canonicalized absolute pathname. +/// +/// @param[in] name Filename to be canonicalized. +/// @param[out] buf Buffer to store the canonicalized values. A minimum length +// of MAXPATHL+1 is required. If it is NULL, memory is +// allocated. In that case, the caller should deallocate this +// buffer. +/// +/// @return pointer to the buf on success, or NULL. +char *os_realpath(const char *name, char *buf) + FUNC_ATTR_NONNULL_ARG(1) +{ + uv_fs_t request; + int result = uv_fs_realpath(&fs_loop, &request, name, NULL); + if (result == kLibuvSuccess) { + if (buf == NULL) { + buf = xmallocz(MAXPATHL); + } + xstrlcpy(buf, request.ptr, MAXPATHL + 1); + } + uv_fs_req_cleanup(&request); + return result == kLibuvSuccess ? buf : NULL; +} + #ifdef WIN32 # include <shlobj.h> @@ -1233,4 +1257,49 @@ shortcut_end: return rfname; } +#define is_path_sep(c) ((c) == L'\\' || (c) == L'/') +/// Returns true if the path contains a reparse point (junction or symbolic +/// link). Otherwise false in returned. +bool os_is_reparse_point_include(const char *path) +{ + wchar_t *p, *q, *utf16_path; + wchar_t buf[MAX_PATH]; + DWORD attr; + bool result = false; + + const int r = utf8_to_utf16(path, -1, &utf16_path); + if (r != 0) { + EMSG2("utf8_to_utf16 failed: %d", r); + return false; + } + + p = utf16_path; + if (isalpha(p[0]) && p[1] == L':' && is_path_sep(p[2])) { + p += 3; + } else if (is_path_sep(p[0]) && is_path_sep(p[1])) { + p += 2; + } + + while (*p != L'\0') { + q = wcspbrk(p, L"\\/"); + if (q == NULL) { + p = q = utf16_path + wcslen(utf16_path); + } else { + p = q + 1; + } + if (q - utf16_path >= MAX_PATH) { + break; + } + wcsncpy(buf, utf16_path, (size_t)(q - utf16_path)); + buf[q - utf16_path] = L'\0'; + attr = GetFileAttributesW(buf); + if (attr != INVALID_FILE_ATTRIBUTES + && (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + result = true; + break; + } + } + xfree(utf16_path); + return result; +} #endif diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 3b8470182a..6294d5e4e2 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -448,7 +448,6 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file, } else { buffer[len] = NUL; } - i = 0; for (p = buffer; p < buffer + len; p++) { if (*p == NUL || (*p == ' ' && check_spaces)) { // count entry i++; diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index ba6226ef9d..112de9fed8 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -50,22 +50,13 @@ void signal_init(void) signal_watcher_init(&main_loop, &shup, NULL); signal_watcher_init(&main_loop, &squit, NULL); signal_watcher_init(&main_loop, &sterm, NULL); -#ifdef SIGPIPE - signal_watcher_start(&spipe, on_signal, SIGPIPE); -#endif - signal_watcher_start(&shup, on_signal, SIGHUP); -#ifdef SIGQUIT - signal_watcher_start(&squit, on_signal, SIGQUIT); -#endif - signal_watcher_start(&sterm, on_signal, SIGTERM); #ifdef SIGPWR signal_watcher_init(&main_loop, &spwr, NULL); - signal_watcher_start(&spwr, on_signal, SIGPWR); #endif #ifdef SIGUSR1 signal_watcher_init(&main_loop, &susr1, NULL); - signal_watcher_start(&susr1, on_signal, SIGUSR1); #endif + signal_start(); } void signal_teardown(void) @@ -83,11 +74,33 @@ void signal_teardown(void) #endif } +void signal_start(void) +{ +#ifdef SIGPIPE + signal_watcher_start(&spipe, on_signal, SIGPIPE); +#endif + signal_watcher_start(&shup, on_signal, SIGHUP); +#ifdef SIGQUIT + signal_watcher_start(&squit, on_signal, SIGQUIT); +#endif + signal_watcher_start(&sterm, on_signal, SIGTERM); +#ifdef SIGPWR + signal_watcher_start(&spwr, on_signal, SIGPWR); +#endif +#ifdef SIGUSR1 + signal_watcher_start(&susr1, on_signal, SIGUSR1); +#endif +} + void signal_stop(void) { +#ifdef SIGPIPE signal_watcher_stop(&spipe); +#endif signal_watcher_stop(&shup); +#ifdef SIGQUIT signal_watcher_stop(&squit); +#endif signal_watcher_stop(&sterm); #ifdef SIGPWR signal_watcher_stop(&spwr); diff --git a/src/nvim/os/time.c b/src/nvim/os/time.c index 4dd0614fe2..346e40e02e 100644 --- a/src/nvim/os/time.c +++ b/src/nvim/os/time.c @@ -2,9 +2,6 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include <assert.h> -#include <stdint.h> -#include <stdbool.h> -#include <time.h> #include <limits.h> #include <uv.h> @@ -13,7 +10,7 @@ #include "nvim/os/time.h" #include "nvim/os/input.h" #include "nvim/event/loop.h" -#include "nvim/vim.h" +#include "nvim/os/os.h" #include "nvim/main.h" static uv_mutex_t delay_mutex; @@ -112,6 +109,10 @@ void os_microdelay(uint64_t us, bool ignoreinput) uv_mutex_unlock(&delay_mutex); } +// Cache of the current timezone name as retrieved from TZ, or an empty string +// where unset, up to 64 octets long including trailing null byte. +static char tz_cache[64]; + /// Portable version of POSIX localtime_r() /// /// @return NULL in case of error @@ -120,6 +121,19 @@ struct tm *os_localtime_r(const time_t *restrict clock, { #ifdef UNIX // POSIX provides localtime_r() as a thread-safe version of localtime(). + // + // Check to see if the environment variable TZ has changed since the last run. + // Call tzset(3) to update the global timezone variables if it has. + // POSIX standard doesn't require localtime_r() implementations to do that + // as it does with localtime(), and we don't want to call tzset() every time. + const char *tz = os_getenv("TZ"); + if (tz == NULL) { + tz = ""; + } + if (strncmp(tz_cache, tz, sizeof(tz_cache) - 1) != 0) { + tzset(); + xstrlcpy(tz_cache, tz, sizeof(tz_cache)); + } return localtime_r(clock, result); // NOLINT(runtime/threadsafe_fn) #else // Windows version of localtime() is thread-safe. @@ -144,6 +158,39 @@ struct tm *os_localtime(struct tm *result) FUNC_ATTR_NONNULL_ALL return os_localtime_r(&rawtime, result); } +/// Portable version of POSIX ctime_r() +/// +/// @param clock[in] +/// @param result[out] Pointer to a 'char' where the result should be placed +/// @param result_len length of result buffer +/// @return human-readable string of current local time +char *os_ctime_r(const time_t *restrict clock, char *restrict result, + size_t result_len) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET +{ + struct tm clock_local; + struct tm *clock_local_ptr = os_localtime_r(clock, &clock_local); + // MSVC returns NULL for an invalid value of seconds. + if (clock_local_ptr == NULL) { + snprintf(result, result_len, "%s\n", _("(Invalid)")); + } else { + strftime(result, result_len, "%a %b %d %H:%M:%S %Y\n", clock_local_ptr); + } + return result; +} + +/// Gets the current Unix timestamp and adjusts it to local time. +/// +/// @param result[out] Pointer to a 'char' where the result should be placed +/// @param result_len length of result buffer +/// @return human-readable string of current local time +char *os_ctime(char *result, size_t result_len) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET +{ + time_t rawtime = time(NULL); + return os_ctime_r(&rawtime, result, result_len); +} + /// Obtains the current Unix timestamp. /// /// @return Seconds since epoch. diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c index 4ba2a1032d..da34d85c00 100644 --- a/src/nvim/popupmnu.c +++ b/src/nvim/popupmnu.c @@ -38,7 +38,8 @@ static int pum_width; // width of displayed pum items static int pum_base_width; // width of pum items base static int pum_kind_width; // width of pum items kind column static int pum_extra_width; // width of extra stuff -static int pum_scrollbar; // TRUE when scrollbar present +static int pum_scrollbar; // one when scrollbar present, else zero +static bool pum_rl; // true when popupmenu is drawn 'rightleft' static int pum_anchor_grid; // grid where position is defined static int pum_row; // top row of pum @@ -110,6 +111,8 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, || (State == CMDLINE && ui_has(kUIWildmenu)); } + pum_rl = (curwin->w_p_rl && State != CMDLINE); + do { // Mark the pum as visible already here, // to avoid that must_redraw is set when 'cursorcolumn' is on. @@ -127,7 +130,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, } else { // anchor position: the start of the completed word pum_win_row = curwin->w_wrow; - if (curwin->w_p_rl) { + if (pum_rl) { cursor_col = curwin->w_width - curwin->w_wcol - 1; } else { cursor_col = curwin->w_wcol; @@ -270,16 +273,14 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, def_width = max_width; } - if ((((cursor_col < Columns - p_pw) - || (cursor_col < Columns - max_width)) - && !curwin->w_p_rl) - || (curwin->w_p_rl - && ((cursor_col > p_pw) || (cursor_col > max_width)))) { + if ((((cursor_col < Columns - p_pw) || (cursor_col < Columns - max_width)) + && !pum_rl) + || (pum_rl && ((cursor_col > p_pw) || (cursor_col > max_width)))) { // align pum with "cursor_col" pum_col = cursor_col; // start with the maximum space available - if (curwin->w_p_rl) { + if (pum_rl) { pum_width = pum_col - pum_scrollbar + 1; } else { assert(Columns - pum_col - pum_scrollbar >= INT_MIN @@ -297,19 +298,16 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, pum_width = (int)p_pw; } } - } else if (((cursor_col > p_pw || cursor_col > max_width) - && !curwin->w_p_rl) - || (curwin->w_p_rl - && (cursor_col < Columns - p_pw - || cursor_col < Columns - max_width))) { + } else if (((cursor_col > p_pw || cursor_col > max_width) && !pum_rl) + || (pum_rl && (cursor_col < Columns - p_pw + || cursor_col < Columns - max_width))) { // align pum edge with "cursor_col" - if (curwin->w_p_rl - && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1) { + if (pum_rl && W_ENDCOL(curwin) < max_width + pum_scrollbar + 1) { pum_col = cursor_col + max_width + pum_scrollbar + 1; if (pum_col >= Columns) { pum_col = Columns - 1; } - } else if (!curwin->w_p_rl) { + } else if (!pum_rl) { if (curwin->w_wincol > Columns - max_width - pum_scrollbar && max_width <= p_pw) { // use full width to end of the screen @@ -320,7 +318,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, } } - if (curwin->w_p_rl) { + if (pum_rl) { pum_width = pum_col - pum_scrollbar + 1; } else { pum_width = Columns - pum_col - pum_scrollbar; @@ -328,7 +326,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, if (pum_width < p_pw) { pum_width = (int)p_pw; - if (curwin->w_p_rl) { + if (pum_rl) { if (pum_width > pum_col) { pum_width = pum_col; } @@ -346,7 +344,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, } } else if (Columns < def_width) { // not enough room, will use what we have - if (curwin->w_p_rl) { + if (pum_rl) { assert(Columns - 1 >= INT_MIN); pum_col = (int)(Columns - 1); } else { @@ -360,7 +358,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, max_width = (int)p_pw; } - if (curwin->w_p_rl) { + if (pum_rl) { pum_col = max_width - 1; } else { assert(Columns - max_width >= INT_MIN @@ -399,7 +397,7 @@ void pum_redraw(void) int grid_width = pum_width; int col_off = 0; bool extra_space = false; - if (curwin->w_p_rl) { + if (pum_rl) { col_off = pum_width; if (pum_col < curwin->w_wincol + curwin->w_width - 1) { grid_width += 1; @@ -460,7 +458,7 @@ void pum_redraw(void) // prepend a space if there is room if (extra_space) { - if (curwin->w_p_rl) { + if (pum_rl) { grid_putchar(&pum_grid, ' ', row, col_off + 1, attr); } else { grid_putchar(&pum_grid, ' ', row, col_off - 1, attr); @@ -507,7 +505,7 @@ void pum_redraw(void) st = (char_u *)transstr((const char *)s); *p = saved; - if (curwin->w_p_rl) { + if (pum_rl) { char_u *rt = reverse_text(st); char_u *rt_start = rt; int size = vim_strsize(rt); @@ -542,7 +540,7 @@ void pum_redraw(void) } // Display two spaces for a Tab. - if (curwin->w_p_rl) { + if (pum_rl) { grid_puts_len(&pum_grid, (char_u *)" ", 2, row, col - 1, attr); col -= 2; @@ -577,7 +575,7 @@ void pum_redraw(void) break; } - if (curwin->w_p_rl) { + if (pum_rl) { grid_fill(&pum_grid, row, row + 1, col_off - pum_base_width - n + 1, col + 1, ' ', ' ', attr); col = col_off - pum_base_width - n + 1; @@ -589,7 +587,7 @@ void pum_redraw(void) totwidth = pum_base_width + n; } - if (curwin->w_p_rl) { + if (pum_rl) { grid_fill(&pum_grid, row, row + 1, col_off - pum_width + 1, col + 1, ' ', ' ', attr); } else { @@ -598,7 +596,7 @@ void pum_redraw(void) } if (pum_scrollbar > 0) { - if (curwin->w_p_rl) { + if (pum_rl) { grid_putchar(&pum_grid, ' ', row, col_off - pum_width, i >= thumb_pos && i < thumb_pos + thumb_heigth ? attr_thumb : attr_scroll); diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 71c6f06ac0..484168e798 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -3845,7 +3845,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last) *dirname = NUL; // Add one line for each error - if (old_last == NULL) { + if (old_last == NULL || old_last->qf_next == NULL) { qfp = qfl->qf_start; lnum = 0; } else { @@ -4775,10 +4775,10 @@ static void vgr_display_fname(char_u *fname) static buf_T *vgr_load_dummy_buf(char_u *fname, char_u *dirname_start, char_u *dirname_now) { - char_u *save_ei = NULL; - // Don't do Filetype autocommands to avoid loading syntax and // indent scripts, a great speed improvement. + char_u *save_ei = au_event_disable(",Filetype"); + long save_mls = p_mls; p_mls = 0; @@ -5134,6 +5134,7 @@ theend: // Restore current working directory to "dirname_start" if they differ, taking // into account whether it is set locally or globally. static void restore_start_dir(char_u *dirname_start) + FUNC_ATTR_NONNULL_ALL { char_u *dirname_now = xmalloc(MAXPATHL); @@ -5251,8 +5252,29 @@ load_dummy_buffer ( // directory to "dirname_start" prior to returning, if autocmds or the // 'autochdir' option have changed it. static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start) + FUNC_ATTR_NONNULL_ALL { - if (curbuf != buf) { // safety check + // If any autocommand opened a window on the dummy buffer, close that + // window. If we can't close them all then give up. + while (buf->b_nwindows > 0) { + bool did_one = false; + + if (firstwin->w_next != NULL) { + for (win_T *wp = firstwin; wp != NULL; wp = wp->w_next) { + if (wp->w_buffer == buf) { + if (win_close(wp, false) == OK) { + did_one = true; + } + break; + } + } + } + if (!did_one) { + return; + } + } + + if (curbuf != buf && buf->b_nwindows == 0) { // safety check cleanup_T cs; // Reset the error/interrupt/exception state here so that aborting() diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 42ea9a944d..34553fcec4 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -6492,20 +6492,24 @@ typedef struct { static regsubmatch_T rsm; // can only be used when can_f_submatch is true -/// Put the submatches in "argv[0]" which is a list passed into call_func() by -/// vim_regsub_both(). -static int fill_submatch_list(int argc, typval_T *argv, int argcount) +/// Put the submatches in "argv[argskip]" which is a list passed into +/// call_func() by vim_regsub_both(). +static int fill_submatch_list(int argc FUNC_ATTR_UNUSED, typval_T *argv, + int argskip, int argcount) + FUNC_ATTR_NONNULL_ALL { - if (argcount == 0) { - // called function doesn't take an argument - return 0; + typval_T *listarg = argv + argskip; + + if (argcount == argskip) { + // called function doesn't take a submatches argument + return argskip; } // Relies on sl_list to be the first item in staticList10_T. - tv_list_init_static10((staticList10_T *)argv->vval.v_list); + tv_list_init_static10((staticList10_T *)listarg->vval.v_list); // There are always 10 list items in staticList10_T. - listitem_T *li = tv_list_first(argv->vval.v_list); + listitem_T *li = tv_list_first(listarg->vval.v_list); for (int i = 0; i < 10; i++) { char_u *s = rsm.sm_match->startp[i]; if (s == NULL || rsm.sm_match->endp[i] == NULL) { @@ -6517,7 +6521,7 @@ static int fill_submatch_list(int argc, typval_T *argv, int argcount) TV_LIST_ITEM_TV(li)->vval.v_string = s; li = TV_LIST_ITEM_NEXT(argv->vval.v_list, li); } - return 1; + return argskip + 1; } static void clear_submatch_list(staticList10_T *sl) @@ -6680,10 +6684,15 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, // fill_submatch_list() was called. clear_submatch_list(&matchList); } - char buf[NUMBUFLEN]; - eval_result = (char_u *)tv_get_string_buf_chk(&rettv, buf); - if (eval_result != NULL) { - eval_result = vim_strsave(eval_result); + if (rettv.v_type == VAR_UNKNOWN) { + // something failed, no need to report another error + eval_result = NULL; + } else { + char buf[NUMBUFLEN]; + eval_result = (char_u *)tv_get_string_buf_chk(&rettv, buf); + if (eval_result != NULL) { + eval_result = vim_strsave(eval_result); + } } tv_clear(&rettv); } else { diff --git a/src/nvim/regexp_defs.h b/src/nvim/regexp_defs.h index 5e5b19b63f..116bfee91e 100644 --- a/src/nvim/regexp_defs.h +++ b/src/nvim/regexp_defs.h @@ -91,7 +91,7 @@ typedef struct { char_u *regmust; int regmlen; char_u reghasz; - char_u program[1]; /* actually longer.. */ + char_u program[1]; // actually longer.. } bt_regprog_T; // Structure representing a NFA state. @@ -102,7 +102,7 @@ struct nfa_state { nfa_state_T *out; nfa_state_T *out1; int id; - int lastlist[2]; /* 0: normal, 1: recursive */ + int lastlist[2]; // 0: normal, 1: recursive int val; }; @@ -116,19 +116,19 @@ typedef struct { unsigned re_engine; unsigned re_flags; ///< Second argument for vim_regcomp(). - nfa_state_T *start; /* points into state[] */ + nfa_state_T *start; // points into state[] - int reganch; /* pattern starts with ^ */ - int regstart; /* char at start of pattern */ - char_u *match_text; /* plain text to match with */ + int reganch; // pattern starts with ^ + int regstart; // char at start of pattern + char_u *match_text; // plain text to match with - int has_zend; /* pattern contains \ze */ - int has_backref; /* pattern contains \1 .. \9 */ + int has_zend; // pattern contains \ze + int has_backref; // pattern contains \1 .. \9 int reghasz; char_u *pattern; - int nsubexp; /* number of () */ + int nsubexp; // number of () int nstate; - nfa_state_T state[1]; /* actually longer.. */ + nfa_state_T state[1]; // actually longer.. } nfa_regprog_T; /* diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 5df279c0a7..9c590efdbc 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -334,10 +334,10 @@ int update_screen(int type) } return FAIL; } + updating_screen = 1; - updating_screen = TRUE; - ++display_tick; /* let syntax code know we're in a next round of - * display updating */ + display_tick++; // let syntax code know we're in a next round of + // display updating // Tricky: vim code can reset msg_scrolled behind our back, so need // separate bookkeeping for now. @@ -417,7 +417,7 @@ int update_screen(int type) need_wait_return = false; } - win_ui_flush_positions(); + win_ui_flush(); msg_ext_check_clear(); /* reset cmdline_row now (may have been changed temporarily) */ @@ -565,7 +565,7 @@ int update_screen(int type) wp->w_buffer->b_mod_set = false; } - updating_screen = FALSE; + updating_screen = 0; /* Clear or redraw the command line. Done last, because scrolling may * mess up the command line. */ @@ -1629,6 +1629,7 @@ static void win_update(win_T *wp) * changes are relevant). */ wp->w_valid |= VALID_BOTLINE; + wp->w_viewport_invalid = true; if (wp == curwin && wp->w_botline != old_botline && !recursive) { recursive = TRUE; curwin->w_valid &= ~VALID_TOPLINE; @@ -1648,7 +1649,7 @@ static void win_update(win_T *wp) /* restore got_int, unless CTRL-C was hit while redrawing */ if (!got_int) got_int = save_got_int; -} +} // NOLINT(readability/fn_size) /// Returns width of the signcolumn that should be used for the whole window /// @@ -1744,7 +1745,7 @@ static int advance_color_col(int vcol, int **color_cols) // space is available for window "wp", minus "col". static int compute_foldcolumn(win_T *wp, int col) { - int fdc = wp->w_p_fdc; + int fdc = win_fdccol_count(wp); int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw; int wwidth = wp->w_grid.Columns; @@ -2215,10 +2216,10 @@ win_line ( int n_skip = 0; /* nr of chars to skip for 'nowrap' */ - int fromcol = 0, tocol = 0; // start/end of inverting + int fromcol = -10; // start of inverting + int tocol = MAXCOL; // end of inverting int fromcol_prev = -2; // start of inverting after cursor - int noinvcur = false; // don't invert the cursor - pos_T *top, *bot; + bool noinvcur = false; // don't invert the cursor int lnum_in_visual_area = false; pos_T pos; long v; @@ -2416,27 +2417,28 @@ win_line ( capcol_lnum = 0; } - // - // handle visual active in this window - // - fromcol = -10; - tocol = MAXCOL; + // handle Visual active in this window if (VIsual_active && wp->w_buffer == curwin->w_buffer) { - // Visual is after curwin->w_cursor + pos_T *top, *bot; + if (ltoreq(curwin->w_cursor, VIsual)) { + // Visual is after curwin->w_cursor top = &curwin->w_cursor; bot = &VIsual; - } else { // Visual is before curwin->w_cursor + } else { + // Visual is before curwin->w_cursor top = &VIsual; bot = &curwin->w_cursor; } lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum); - if (VIsual_mode == Ctrl_V) { // block mode + if (VIsual_mode == Ctrl_V) { + // block mode if (lnum_in_visual_area) { fromcol = wp->w_old_cursor_fcol; tocol = wp->w_old_cursor_lcol; } - } else { // non-block mode + } else { + // non-block mode if (lnum > top->lnum && lnum <= bot->lnum) { fromcol = 0; } else if (lnum == top->lnum) { @@ -3159,8 +3161,8 @@ win_line ( shl->endcol += (*mb_ptr2len)(line + shl->endcol); } - /* Loop to check if the match starts at the - * current position */ + // Loop to check if the match starts at the + // current position continue; } } @@ -3647,8 +3649,9 @@ win_line ( tab_len += n_extra - tab_len; } - /* if n_extra > 0, it gives the number of chars to use for - * a tab, else we need to calculate the width for a tab */ + // if n_extra > 0, it gives the number of chars + // to use for a tab, else we need to calculate the width + // for a tab int len = (tab_len * mb_char2len(wp->w_p_lcs_chars.tab2)); if (n_extra > 0) { len += n_extra - tab_len; @@ -3660,10 +3663,16 @@ win_line ( xfree(p_extra_free); p_extra_free = p; for (i = 0; i < tab_len; i++) { - utf_char2bytes(wp->w_p_lcs_chars.tab2, p); - p += mb_char2len(wp->w_p_lcs_chars.tab2); - n_extra += mb_char2len(wp->w_p_lcs_chars.tab2) - - (saved_nextra > 0 ? 1: 0); + int lcs = wp->w_p_lcs_chars.tab2; + + // if tab3 is given, need to change the char + // for tab + if (wp->w_p_lcs_chars.tab3 && i == tab_len - 1) { + lcs = wp->w_p_lcs_chars.tab3; + } + utf_char2bytes(lcs, p); + p += mb_char2len(lcs); + n_extra += mb_char2len(lcs) - (saved_nextra > 0 ? 1 : 0); } p_extra = p_extra_free; @@ -5724,12 +5733,11 @@ static void end_search_hl(void) * Init for calling prepare_search_hl(). */ static void init_search_hl(win_T *wp) + FUNC_ATTR_NONNULL_ALL { - matchitem_T *cur; - - /* Setup for match and 'hlsearch' highlighting. Disable any previous - * match */ - cur = wp->w_match_head; + // Setup for match and 'hlsearch' highlighting. Disable any previous + // match + matchitem_T *cur = wp->w_match_head; while (cur != NULL) { cur->hl.rm = cur->match; if (cur->hlg_id == 0) @@ -5739,7 +5747,7 @@ static void init_search_hl(win_T *wp) cur->hl.buf = wp->w_buffer; cur->hl.lnum = 0; cur->hl.first_lnum = 0; - /* Set the time limit to 'redrawtime'. */ + // Set the time limit to 'redrawtime'. cur->hl.tm = profile_setlimit(p_rdt); cur = cur->next; } @@ -5755,18 +5763,16 @@ static void init_search_hl(win_T *wp) * Advance to the match in window "wp" line "lnum" or past it. */ static void prepare_search_hl(win_T *wp, linenr_T lnum) + FUNC_ATTR_NONNULL_ALL { - matchitem_T *cur; /* points to the match list */ - match_T *shl; /* points to search_hl or a match */ - int shl_flag; /* flag to indicate whether search_hl - has been processed or not */ - int n; - - /* - * When using a multi-line pattern, start searching at the top - * of the window or just after a closed fold. - * Do this both for search_hl and the match list. - */ + matchitem_T *cur; // points to the match list + match_T *shl; // points to search_hl or a match + bool shl_flag; // flag to indicate whether search_hl + // has been processed or not + + // When using a multi-line pattern, start searching at the top + // of the window or just after a closed fold. + // Do this both for search_hl and the match list. cur = wp->w_match_head; shl_flag = false; while (cur != NULL || shl_flag == false) { @@ -5793,7 +5799,7 @@ static void prepare_search_hl(win_T *wp, linenr_T lnum) } bool pos_inprogress = true; // mark that a position match search is // in progress - n = 0; + int n = 0; while (shl->first_lnum < lnum && (shl->rm.regprog != NULL || (cur != NULL && pos_inprogress))) { next_search_hl(wp, shl, shl->first_lnum, (colnr_T)n, @@ -5831,6 +5837,7 @@ next_search_hl ( colnr_T mincol, /* minimal column for a match */ matchitem_T *cur /* to retrieve match positions if any */ ) + FUNC_ATTR_NONNULL_ARG(2) { linenr_T l; colnr_T matchcol; @@ -5838,11 +5845,10 @@ next_search_hl ( int save_called_emsg = called_emsg; if (shl->lnum != 0) { - /* Check for three situations: - * 1. If the "lnum" is below a previous match, start a new search. - * 2. If the previous match includes "mincol", use it. - * 3. Continue after the previous match. - */ + // Check for three situations: + // 1. If the "lnum" is below a previous match, start a new search. + // 2. If the previous match includes "mincol", use it. + // 3. Continue after the previous match. l = shl->lnum + shl->rm.endpos[0].lnum - shl->rm.startpos[0].lnum; if (lnum > l) shl->lnum = 0; @@ -5856,22 +5862,21 @@ next_search_hl ( */ called_emsg = FALSE; for (;; ) { - /* Stop searching after passing the time limit. */ + // Stop searching after passing the time limit. if (profile_passed_limit(shl->tm)) { shl->lnum = 0; /* no match found in time */ break; } - /* Three situations: - * 1. No useful previous match: search from start of line. - * 2. Not Vi compatible or empty match: continue at next character. - * Break the loop if this is beyond the end of the line. - * 3. Vi compatible searching: continue at end of previous match. - */ - if (shl->lnum == 0) + // Three situations: + // 1. No useful previous match: search from start of line. + // 2. Not Vi compatible or empty match: continue at next character. + // Break the loop if this is beyond the end of the line. + // 3. Vi compatible searching: continue at end of previous match. + if (shl->lnum == 0) { matchcol = 0; - else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL - || (shl->rm.endpos[0].lnum == 0 - && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) { + } else if (vim_strchr(p_cpo, CPO_SEARCH) == NULL + || (shl->rm.endpos[0].lnum == 0 + && shl->rm.endpos[0].col <= shl->rm.startpos[0].col)) { char_u *ml; matchcol = shl->rm.startpos[0].col; @@ -5888,8 +5893,8 @@ next_search_hl ( shl->lnum = lnum; if (shl->rm.regprog != NULL) { - /* Remember whether shl->rm is using a copy of the regprog in - * cur->match. */ + // Remember whether shl->rm is using a copy of the regprog in + // cur->match. bool regprog_is_copy = (shl != &search_hl && cur != NULL && shl == &cur->hl @@ -5918,7 +5923,7 @@ next_search_hl ( nmatched = next_search_hl_pos(shl, lnum, &(cur->pos), matchcol); } if (nmatched == 0) { - shl->lnum = 0; /* no match found */ + shl->lnum = 0; // no match found break; } if (shl->rm.startpos[0].lnum > 0 @@ -5926,7 +5931,7 @@ next_search_hl ( || nmatched > 1 || shl->rm.endpos[0].col > mincol) { shl->lnum += shl->rm.startpos[0].lnum; - break; /* useful match found */ + break; // useful match found } // Restore called_emsg for assert_fails(). @@ -5943,6 +5948,7 @@ next_search_hl_pos( posmatch_T *posmatch, // match positions colnr_T mincol // minimal column for a match ) + FUNC_ATTR_NONNULL_ALL { int i; int found = -1; @@ -6097,9 +6103,10 @@ void check_for_delay(int check_msg_scroll) && emsg_silent == 0) { ui_flush(); os_delay(1000L, true); - emsg_on_display = FALSE; - if (check_msg_scroll) - msg_scroll = FALSE; + emsg_on_display = false; + if (check_msg_scroll) { + msg_scroll = false; + } } } diff --git a/src/nvim/search.c b/src/nvim/search.c index 3ee9777805..23086c629b 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -1192,6 +1192,7 @@ int do_search( len = STRLEN(p) + off_len + 3; } + xfree(msgbuf); msgbuf = xmalloc(len); { memset(msgbuf, ' ', len); @@ -2227,6 +2228,8 @@ showmatch( pos_T *lpos, save_cursor; pos_T mpos; colnr_T vcol; + long *so = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; + long *siso = curwin->w_p_siso >= 0 ? &curwin->w_p_siso : &p_siso; long save_so; long save_siso; int save_state; @@ -2262,23 +2265,24 @@ showmatch( && vcol < curwin->w_leftcol + curwin->w_width_inner)) { mpos = *lpos; // save the pos, update_screen() may change it save_cursor = curwin->w_cursor; - save_so = p_so; - save_siso = p_siso; - /* Handle "$" in 'cpo': If the ')' is typed on top of the "$", - * stop displaying the "$". */ - if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) + save_so = *so; + save_siso = *siso; + // Handle "$" in 'cpo': If the ')' is typed on top of the "$", + // stop displaying the "$". + if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) { dollar_vcol = -1; - ++curwin->w_virtcol; /* do display ')' just before "$" */ - update_screen(VALID); /* show the new char first */ + } + curwin->w_virtcol++; // do display ')' just before "$" + update_screen(VALID); // show the new char first save_dollar_vcol = dollar_vcol; save_state = State; State = SHOWMATCH; - ui_cursor_shape(); /* may show different cursor shape */ - curwin->w_cursor = mpos; /* move to matching char */ - p_so = 0; /* don't use 'scrolloff' here */ - p_siso = 0; /* don't use 'sidescrolloff' here */ - showruler(FALSE); + ui_cursor_shape(); // may show different cursor shape + curwin->w_cursor = mpos; // move to matching char + *so = 0; // don't use 'scrolloff' here + *siso = 0; // don't use 'sidescrolloff' here + showruler(false); setcursor(); ui_flush(); /* Restore dollar_vcol(), because setcursor() may call curs_rows() @@ -2294,11 +2298,11 @@ showmatch( os_delay(p_mat * 100L, true); else if (!char_avail()) os_delay(p_mat * 100L, false); - curwin->w_cursor = save_cursor; /* restore cursor position */ - p_so = save_so; - p_siso = save_siso; + curwin->w_cursor = save_cursor; // restore cursor position + *so = save_so; + *siso = save_siso; State = save_state; - ui_cursor_shape(); /* may show different cursor shape */ + ui_cursor_shape(); // may show different cursor shape } } } diff --git a/src/nvim/sign.c b/src/nvim/sign.c index 23dd447744..ab5d04d39b 100644 --- a/src/nvim/sign.c +++ b/src/nvim/sign.c @@ -198,7 +198,7 @@ static void insert_sign( // column for signs. if (buf->b_signlist == NULL) { redraw_buf_later(buf, NOT_VALID); - changed_cline_bef_curs(); + changed_line_abv_curs(); } // first sign in signlist @@ -265,6 +265,81 @@ dict_T * sign_get_info(signlist_T *sign) return d; } +// Sort the signs placed on the same line as "sign" by priority. Invoked after +// changing the priority of an already placed sign. Assumes the signs in the +// buffer are sorted by line number and priority. +static void sign_sort_by_prio_on_line(buf_T *buf, signlist_T *sign) + FUNC_ATTR_NONNULL_ALL +{ + // If there is only one sign in the buffer or only one sign on the line or + // the sign is already sorted by priority, then return. + if ((sign->prev == NULL + || sign->prev->lnum != sign->lnum + || sign->prev->priority > sign->priority) + && (sign->next == NULL + || sign->next->lnum != sign->lnum + || sign->next->priority < sign->priority)) { + return; + } + + // One or more signs on the same line as 'sign' + // Find a sign after which 'sign' should be inserted + + // First search backward for a sign with higher priority on the same line + signlist_T *p = sign; + while (p->prev != NULL + && p->prev->lnum == sign->lnum + && p->prev->priority <= sign->priority) { + p = p->prev; + } + if (p == sign) { + // Sign not found. Search forward for a sign with priority just before + // 'sign'. + p = sign->next; + while (p->next != NULL + && p->next->lnum == sign->lnum + && p->next->priority > sign->priority) { + p = p->next; + } + } + + // Remove 'sign' from the list + if (buf->b_signlist == sign) { + buf->b_signlist = sign->next; + } + if (sign->prev != NULL) { + sign->prev->next = sign->next; + } + if (sign->next != NULL) { + sign->next->prev = sign->prev; + } + sign->prev = NULL; + sign->next = NULL; + + // Re-insert 'sign' at the right place + if (p->priority <= sign->priority) { + // 'sign' has a higher priority and should be inserted before 'p' + sign->prev = p->prev; + sign->next = p; + p->prev = sign; + if (sign->prev != NULL) { + sign->prev->next = sign; + } + if (buf->b_signlist == p) { + buf->b_signlist = sign; + } + } else { + // 'sign' has a lower priority and should be inserted after 'p' + sign->prev = p; + sign->next = p->next; + p->next = sign; + if (sign->next != NULL) { + sign->next->prev = sign; + } + } +} + + /// Add the sign into the signlist. Find the right spot to do it though. void buf_addsign( buf_T *buf, // buffer to store sign in @@ -284,6 +359,8 @@ void buf_addsign( && sign_in_group(sign, groupname)) { // Update an existing sign sign->typenr = typenr; + sign->priority = prio; + sign_sort_by_prio_on_line(buf, sign); return; } else if (lnum < sign->lnum) { insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr); @@ -418,11 +495,11 @@ linenr_T buf_delsign( } } - // When deleted the last sign needs to redraw the windows to remove the - // sign column. + // When deleting the last sign the cursor position may change, because the + // sign columns no longer shows. And the 'signcolumn' may be hidden. if (buf->b_signlist == NULL) { redraw_buf_later(buf, NOT_VALID); - changed_cline_bef_curs(); + changed_line_abv_curs(); } return lnum; @@ -495,7 +572,7 @@ void buf_delete_signs(buf_T *buf, char_u *group) // When deleting the last sign need to redraw the windows to remove the // sign column. Not when curwin is NULL (this means we're exiting). if (buf->b_signlist != NULL && curwin != NULL) { - changed_cline_bef_curs(); + changed_line_abv_curs(); } lastp = &buf->b_signlist; @@ -754,6 +831,14 @@ int sign_define_by_name( } else { sp_prev->sn_next = sp; } + } else { + // Signs may already exist, a redraw is needed in windows with a + // non-empty sign list. + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (wp->w_buffer->b_signlist != NULL) { + redraw_buf_later(wp->w_buffer, NOT_VALID); + } + } } // set values for a defined sign. @@ -1531,10 +1616,44 @@ static enum EXP_SUBCMD, // expand :sign sub-commands EXP_DEFINE, // expand :sign define {name} args EXP_PLACE, // expand :sign place {id} args + EXP_LIST, // expand :sign place args EXP_UNPLACE, // expand :sign unplace" - EXP_SIGN_NAMES // expand with name of placed signs + EXP_SIGN_NAMES, // expand with name of placed signs + EXP_SIGN_GROUPS, // expand with name of placed sign groups } expand_what; +// Return the n'th sign name (used for command line completion) +static char_u *get_nth_sign_name(int idx) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + // Complete with name of signs already defined + int current_idx = 0; + for (sign_T *sp = first_sign; sp != NULL; sp = sp->sn_next) { + if (current_idx++ == idx) { + return sp->sn_name; + } + } + return NULL; +} + +// Return the n'th sign group name (used for command line completion) +static char_u *get_nth_sign_group_name(int idx) +{ + // Complete with name of sign groups already defined + int current_idx = 0; + int todo = (int)sg_table.ht_used; + for (hashitem_T *hi = sg_table.ht_array; todo > 0; hi++) { + if (!HASHITEM_EMPTY(hi)) { + todo--; + if (current_idx++ == idx) { + signgroup_T *const group = HI2SG(hi); + return group->sg_name; + } + } + } + return NULL; +} + /// Function given to ExpandGeneric() to obtain the sign command /// expansion. char_u * get_sign_name(expand_T *xp, int idx) @@ -1552,20 +1671,18 @@ char_u * get_sign_name(expand_T *xp, int idx) "buffer=", NULL }; return (char_u *)place_arg[idx]; } + case EXP_LIST: { + char *list_arg[] = { "group=", "file=", "buffer=", NULL }; + return (char_u *)list_arg[idx]; + } case EXP_UNPLACE: { char *unplace_arg[] = { "group=", "file=", "buffer=", NULL }; return (char_u *)unplace_arg[idx]; } - case EXP_SIGN_NAMES: { - // Complete with name of signs already defined - int current_idx = 0; - for (sign_T *sp = first_sign; sp != NULL; sp = sp->sn_next) { - if (current_idx++ == idx) { - return sp->sn_name; - } - } - } - return NULL; + case EXP_SIGN_NAMES: + return get_nth_sign_name(idx); + case EXP_SIGN_GROUPS: + return get_nth_sign_group_name(idx); default: return NULL; } @@ -1574,7 +1691,6 @@ char_u * get_sign_name(expand_T *xp, int idx) /// Handle command line completion for :sign command. void set_context_in_sign_cmd(expand_T *xp, char_u *arg) { - char_u *p; char_u *end_subcmd; char_u *last; int cmd_idx; @@ -1598,26 +1714,6 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg) // | // begin_subcmd_args begin_subcmd_args = skipwhite(end_subcmd); - p = skiptowhite(begin_subcmd_args); - if (*p == NUL) { - // - // Expand first argument of subcmd when possible. - // For ":jump {id}" and ":unplace {id}", we could - // possibly expand the ids of all signs already placed. - // - xp->xp_pattern = begin_subcmd_args; - switch (cmd_idx) { - case SIGNCMD_LIST: - case SIGNCMD_UNDEFINE: - // :sign list <CTRL-D> - // :sign undefine <CTRL-D> - expand_what = EXP_SIGN_NAMES; - break; - default: - xp->xp_context = EXPAND_NOTHING; - } - return; - } // Expand last argument of subcmd. // @@ -1626,6 +1722,7 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg) // p // Loop until reaching last argument. + char_u *p = begin_subcmd_args; do { p = skipwhite(p); last = p; @@ -1645,7 +1742,20 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg) expand_what = EXP_DEFINE; break; case SIGNCMD_PLACE: - expand_what = EXP_PLACE; + // List placed signs + if (ascii_isdigit(*begin_subcmd_args)) { + // :sign place {id} {args}... + expand_what = EXP_PLACE; + } else { + // :sign place {args}... + expand_what = EXP_LIST; + } + break; + case SIGNCMD_LIST: + case SIGNCMD_UNDEFINE: + // :sign list <CTRL-D> + // :sign undefine <CTRL-D> + expand_what = EXP_SIGN_NAMES; break; case SIGNCMD_JUMP: case SIGNCMD_UNPLACE: @@ -1659,19 +1769,33 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg) xp->xp_pattern = p + 1; switch (cmd_idx) { case SIGNCMD_DEFINE: - if (STRNCMP(last, "texthl", p - last) == 0 - || STRNCMP(last, "linehl", p - last) == 0 - || STRNCMP(last, "numhl", p - last) == 0) { + if (STRNCMP(last, "texthl", 6) == 0 + || STRNCMP(last, "linehl", 6) == 0 + || STRNCMP(last, "numhl", 5) == 0) { xp->xp_context = EXPAND_HIGHLIGHT; - } else if (STRNCMP(last, "icon", p - last) == 0) { + } else if (STRNCMP(last, "icon", 4) == 0) { xp->xp_context = EXPAND_FILES; } else { xp->xp_context = EXPAND_NOTHING; } break; case SIGNCMD_PLACE: - if (STRNCMP(last, "name", p - last) == 0) { + if (STRNCMP(last, "name", 4) == 0) { expand_what = EXP_SIGN_NAMES; + } else if (STRNCMP(last, "group", 5) == 0) { + expand_what = EXP_SIGN_GROUPS; + } else if (STRNCMP(last, "file", 4) == 0) { + xp->xp_context = EXPAND_BUFFERS; + } else { + xp->xp_context = EXPAND_NOTHING; + } + break; + case SIGNCMD_UNPLACE: + case SIGNCMD_JUMP: + if (STRNCMP(last, "group", 5) == 0) { + expand_what = EXP_SIGN_GROUPS; + } else if (STRNCMP(last, "file", 4) == 0) { + xp->xp_context = EXPAND_BUFFERS; } else { xp->xp_context = EXPAND_NOTHING; } diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 6cb8d01f51..180073ade1 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -2827,9 +2827,6 @@ void spell_suggest(int count) smsg(_("Sorry, only %" PRId64 " suggestions"), (int64_t)sug.su_ga.ga_len); } else { - XFREE_CLEAR(repl_from); - XFREE_CLEAR(repl_to); - // When 'rightleft' is set the list is drawn right-left. cmdmsg_rl = curwin->w_p_rl; if (cmdmsg_rl) @@ -2909,6 +2906,9 @@ void spell_suggest(int count) if (selected > 0 && selected <= sug.su_ga.ga_len && u_save_cursor() == OK) { // Save the from and to text for :spellrepall. + XFREE_CLEAR(repl_from); + XFREE_CLEAR(repl_to); + stp = &SUG(sug.su_ga, selected - 1); if (sug.su_badlen > stp->st_orglen) { // Replacing less than "su_badlen", append the remainder to @@ -5761,19 +5761,22 @@ cleanup_suggestions ( int maxscore, int keep // nr of suggestions to keep ) + FUNC_ATTR_NONNULL_ALL { suggest_T *stp = &SUG(*gap, 0); - // Sort the list. - qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare); + if (gap->ga_len > 0) { + // Sort the list. + qsort(gap->ga_data, (size_t)gap->ga_len, sizeof(suggest_T), sug_compare); - // Truncate the list to the number of suggestions that will be displayed. - if (gap->ga_len > keep) { - for (int i = keep; i < gap->ga_len; ++i) { - xfree(stp[i].st_word); + // Truncate the list to the number of suggestions that will be displayed. + if (gap->ga_len > keep) { + for (int i = keep; i < gap->ga_len; i++) { + xfree(stp[i].st_word); + } + gap->ga_len = keep; + return stp[keep - 1].st_score; } - gap->ga_len = keep; - return stp[keep - 1].st_score; } return maxscore; } diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index ddb9188371..ef4dfb3caa 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -6400,7 +6400,7 @@ static int color_numbers_88[28] = { 0, 4, 2, 6, 75, 11, 78, 15, -1 }; // for xterm with 256 colors... static int color_numbers_256[28] = { 0, 4, 2, 6, - 1, 5, 130, 130, + 1, 5, 130, 3, 248, 248, 7, 7, 242, 242, 12, 81, 10, 121, diff --git a/src/nvim/tag.c b/src/nvim/tag.c index 57bb43c846..ff07a00952 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -2540,7 +2540,9 @@ parse_match( } p += 2; // skip ";\"" if (*p++ == TAB) { - while (ASCII_ISALPHA(*p)) { + // Accept ASCII alphabetic kind characters and any multi-byte + // character. + while (ASCII_ISALPHA(*p) || utfc_ptr2len(p) > 1) { if (STRNCMP(p, "kind:", 5) == 0) { tagp->tagkind = p + 5; } else if (STRNCMP(p, "user_data:", 10) == 0) { @@ -2559,19 +2561,22 @@ parse_match( } if (pt == NULL) break; - p = pt + 1; + p = pt; + MB_PTR_ADV(p); } } } if (tagp->tagkind != NULL) { for (p = tagp->tagkind; - *p && *p != '\t' && *p != '\r' && *p != '\n'; ++p) - ; + *p && *p != '\t' && *p != '\r' && *p != '\n'; + MB_PTR_ADV(p)) { + } tagp->tagkind_end = p; } if (tagp->user_data != NULL) { for (p = tagp->user_data; - *p && *p != '\t' && *p != '\r' && *p != '\n'; p++) { + *p && *p != '\t' && *p != '\r' && *p != '\n'; + MB_PTR_ADV(p)) { } tagp->user_data_end = p; } @@ -3181,7 +3186,8 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname) if (tp.command_end != NULL) { for (char_u *p = tp.command_end + 3; - *p != NUL && *p != '\n' && *p != '\r'; p++) { + *p != NUL && *p != '\n' && *p != '\r'; + MB_PTR_ADV(p)) { if (p == tp.tagkind || (p + 5 == tp.tagkind && STRNCMP(p, "kind:", 5) == 0)) { // skip "kind:<kind>" and "<kind>" diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index c5e756905a..a37cc60928 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -992,8 +992,9 @@ static void mouse_action(Terminal *term, int button, int row, int col, static bool send_mouse_event(Terminal *term, int c) { int row = mouse_row, col = mouse_col, grid = mouse_grid; + int offset; win_T *mouse_win = mouse_find_win(&grid, &row, &col); - if (mouse_win == NULL) { + if (mouse_win == NULL || (offset = win_col_off(mouse_win)) > col) { goto end; } @@ -1015,7 +1016,7 @@ static bool send_mouse_event(Terminal *term, int c) default: return false; } - mouse_action(term, button, row, col, drag, 0); + mouse_action(term, button, row, col - offset, drag, 0); size_t len = vterm_output_read(term->vt, term->textbuf, sizeof(term->textbuf)); terminal_send(term, term->textbuf, (size_t)len); diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index c36458930f..e52fd888bd 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -86,7 +86,7 @@ nongui: nolog $(FIXFF) $(SCRIPTS) newtests report @echo 'set $$_exitcode = -1\nrun\nif $$_exitcode != -1\n quit\nend' > .gdbinit report: - $(RUN_VIMTEST) $(NO_INITS) -u NONE -S summarize.vim messages + $(NVIM_PRG) -u NONE $(NO_INITS) -S summarize.vim messages @echo @echo 'Test results:' @cat test_result.log diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim index fc79f57d2e..c86fdf25ab 100644 --- a/src/nvim/testdir/test49.vim +++ b/src/nvim/testdir/test49.vim @@ -1,6 +1,6 @@ " Vim script language tests " Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com> -" Last Change: 2019 May 24 +" Last Change: 2019 Oct 08 "------------------------------------------------------------------------------- " Test environment {{{1 @@ -456,7 +456,7 @@ function! ExtraVim(...) " messing up the user's viminfo file. let redirect = a:0 ? \ " -c 'au VimLeave * redir END' -c 'redir\\! >" . a:1 . "'" : "" - exec "!echo '" . debug_quits . "q' | $NVIM_PRG -u NONE -N -es" . redirect . + exec "!echo '" . debug_quits . "q' | " .. v:progpath .. " -u NONE -N -es" . redirect . \ " -c 'debuggreedy|set viminfo+=nviminfo'" . \ " -c 'let ExtraVimBegin = " . extra_begin . "'" . \ " -c 'let ExtraVimResult = \"" . resultfile . "\"'" . breakpoints . diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index e3547aea5b..954e5d875f 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1072,6 +1072,40 @@ func Test_Cmd_Autocmds() enew! endfunc +func s:ReadFile() + setl noswapfile nomodified + let filename = resolve(expand("<afile>:p")) + execute 'read' fnameescape(filename) + 1d_ + exe 'file' fnameescape(filename) + setl buftype=acwrite +endfunc + +func s:WriteFile() + let filename = resolve(expand("<afile>:p")) + setl buftype= + noautocmd execute 'write' fnameescape(filename) + setl buftype=acwrite + setl nomodified +endfunc + +func Test_BufReadCmd() + autocmd BufReadCmd *.test call s:ReadFile() + autocmd BufWriteCmd *.test call s:WriteFile() + + call writefile(['one', 'two', 'three'], 'Xcmd.test') + edit Xcmd.test + call assert_match('Xcmd.test" line 1 of 3', execute('file')) + normal! Gofour + write + call assert_equal(['one', 'two', 'three', 'four'], readfile('Xcmd.test')) + + bwipe! + call delete('Xcmd.test') + au! BufReadCmd + au! BufWriteCmd +endfunc + func SetChangeMarks(start, end) exe a:start. 'mark [' exe a:end. 'mark ]' @@ -1786,3 +1820,46 @@ func Test_FileChangedShell_reload() bwipe! call delete('Xchanged') endfunc + +" Test for FileReadCmd autocmd +func Test_autocmd_FileReadCmd() + func ReadFileCmd() + call append(line('$'), "v:cmdarg = " .. v:cmdarg) + endfunc + augroup FileReadCmdTest + au! + au FileReadCmd Xtest call ReadFileCmd() + augroup END + + new + read ++bin Xtest + read ++nobin Xtest + read ++edit Xtest + read ++bad=keep Xtest + read ++bad=drop Xtest + read ++bad=- Xtest + read ++ff=unix Xtest + read ++ff=dos Xtest + read ++ff=mac Xtest + read ++enc=utf-8 Xtest + + call assert_equal(['', + \ 'v:cmdarg = ++bin', + \ 'v:cmdarg = ++nobin', + \ 'v:cmdarg = ++edit', + \ 'v:cmdarg = ++bad=keep', + \ 'v:cmdarg = ++bad=drop', + \ 'v:cmdarg = ++bad=-', + \ 'v:cmdarg = ++ff=unix', + \ 'v:cmdarg = ++ff=dos', + \ 'v:cmdarg = ++ff=mac', + \ 'v:cmdarg = ++enc=utf-8'], getline(1, '$')) + + close! + augroup FileReadCmdTest + au! + augroup END + delfunc ReadFileCmd +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim index 40d3cdbdae..6bb602717f 100644 --- a/src/nvim/testdir/test_compiler.vim +++ b/src/nvim/testdir/test_compiler.vim @@ -38,10 +38,11 @@ func Test_compiler() endfunc func Test_compiler_without_arg() - let a=split(execute('compiler')) - call assert_match('^.*runtime/compiler/ant.vim$', a[0]) - call assert_match('^.*runtime/compiler/bcc.vim$', a[1]) - call assert_match('^.*runtime/compiler/xmlwf.vim$', a[-1]) + let runtime = substitute($VIMRUNTIME, '\\', '/', 'g') + let a = split(execute('compiler')) + call assert_match(runtime .. '/compiler/ant.vim$', a[0]) + call assert_match(runtime .. '/compiler/bcc.vim$', a[1]) + call assert_match(runtime .. '/compiler/xmlwf.vim$', a[-1]) endfunc func Test_compiler_completion() diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim index 21e0271bda..fed642e34b 100644 --- a/src/nvim/testdir/test_diffmode.vim +++ b/src/nvim/testdir/test_diffmode.vim @@ -67,7 +67,7 @@ func Common_vert_split() set foldmethod=marker foldcolumn=4 call assert_equal(0, &diff) call assert_equal('marker', &foldmethod) - call assert_equal(4, &foldcolumn) + call assert_equal('4', &foldcolumn) call assert_equal(0, &scrollbind) call assert_equal(0, &cursorbind) call assert_equal(1, &wrap) @@ -76,7 +76,7 @@ func Common_vert_split() vert diffsplit Xtest2 call assert_equal(1, &diff) call assert_equal('diff', &foldmethod) - call assert_equal(2, &foldcolumn) + call assert_equal('2', &foldcolumn) call assert_equal(1, &scrollbind) call assert_equal(1, &cursorbind) call assert_equal(0, &wrap) @@ -142,7 +142,7 @@ func Common_vert_split() 1wincmd w call assert_equal(0, &diff) call assert_equal('marker', &foldmethod) - call assert_equal(4, &foldcolumn) + call assert_equal('4', &foldcolumn) call assert_equal(0, &scrollbind) call assert_equal(0, &cursorbind) call assert_equal(1, &wrap) @@ -150,7 +150,7 @@ func Common_vert_split() wincmd w call assert_equal(0, &diff) call assert_equal('marker', &foldmethod) - call assert_equal(4, &foldcolumn) + call assert_equal('4', &foldcolumn) call assert_equal(0, &scrollbind) call assert_equal(0, &cursorbind) call assert_equal(1, &wrap) @@ -158,7 +158,7 @@ func Common_vert_split() wincmd w call assert_equal(0, &diff) call assert_equal('marker', &foldmethod) - call assert_equal(4, &foldcolumn) + call assert_equal('4', &foldcolumn) call assert_equal(0, &scrollbind) call assert_equal(0, &cursorbind) call assert_equal(1, &wrap) diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim index 5da05e85b5..1792dcc00b 100644 --- a/src/nvim/testdir/test_digraph.vim +++ b/src/nvim/testdir/test_digraph.vim @@ -433,6 +433,18 @@ func Test_digraphs_output() call assert_equal('Z% Ж 1046', matchstr(out, '\C\<Z%\D*1046\>')) call assert_equal('u- Å« 363', matchstr(out, '\C\<u-\D*363\>')) call assert_equal('SH ^A 1', matchstr(out, '\C\<SH\D*1\>')) + call assert_notmatch('Latin supplement', out) + + let out_bang_without_custom = execute(':digraph!') + digraph lt 60 + let out_bang_with_custom = execute(':digraph!') + call assert_notmatch('lt', out_bang_without_custom) + call assert_match("^\n" + \ .. "NU ^@ 10 .*\n" + \ .. "Latin supplement\n" + \ .. "!I ¡ 161 .*\n" + \ .. ".*\n" + \ .. 'Custom\n.*\<lt < 60\>', out_bang_with_custom) bw! endfunc diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim index dd546dbf71..264d8b000f 100644 --- a/src/nvim/testdir/test_expr.vim +++ b/src/nvim/testdir/test_expr.vim @@ -475,6 +475,8 @@ func Test_funcref() let OneByRef = funcref('One') call assert_equal(2, OneByRef()) call assert_fails('echo funcref("{")', 'E475:') + let OneByRef = funcref("One", repeat(["foo"], 20)) + call assert_fails('let OneByRef = funcref("One", repeat(["foo"], 21))', 'E118:') endfunc func Test_empty_concatenate() diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 7290cceb0b..c3ddce7914 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -79,6 +79,7 @@ let s:filename_checks = { \ 'bib': ['file.bib'], \ 'bindzone': ['named.root'], \ 'blank': ['file.bl'], + \ 'bsdl': ['file.bsd', 'file.bsdl'], \ 'bst': ['file.bst'], \ 'bzr': ['bzr_log.any'], \ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c'], @@ -436,7 +437,7 @@ let s:filename_checks = { \ 'swiftgyb': ['file.swift.gyb'], \ 'sil': ['file.sil'], \ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf'], - \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file'], + \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file'], \ 'systemverilog': ['file.sv', 'file.svh'], \ 'tags': ['tags'], \ 'tak': ['file.tak'], @@ -480,7 +481,7 @@ let s:filename_checks = { \ 'verilog': ['file.v'], \ 'verilogams': ['file.va', 'file.vams'], \ 'vgrindefs': ['vgrindefs'], - \ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst', 'file.vhdl_123'], + \ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst', 'file.vhdl_123', 'file.vho'], \ 'vim': ['file.vim', 'file.vba', '.exrc', '_exrc'], \ 'viminfo': ['.viminfo', '_viminfo'], \ 'vmasm': ['file.mar'], @@ -600,6 +601,7 @@ let s:script_checks = { \ 'haskell': [['#!/path/haskell']], \ 'cpp': [['// Standard iostream objects -*- C++ -*-'], \ ['// -*- C++ -*-']], + \ 'yaml': [['%YAML 1.2']], \ } func Test_script_detection() diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index 7822507f86..bd5cb6ad19 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -186,6 +186,32 @@ func Test_strftime() call assert_fails('call strftime([])', 'E730:') call assert_fails('call strftime("%Y", [])', 'E745:') + + " Check that the time changes after we change the timezone + " Save previous timezone value, if any + if exists('$TZ') + let tz = $TZ + endif + + " Force EST and then UTC, save the current hour (24-hour clock) for each + let $TZ = 'EST' | let est = strftime('%H') + let $TZ = 'UTC' | let utc = strftime('%H') + + " Those hours should be two bytes long, and should not be the same; if they + " are, a tzset(3) call may have failed somewhere + call assert_equal(strlen(est), 2) + call assert_equal(strlen(utc), 2) + " TODO: this fails on MS-Windows + if has('unix') + call assert_notequal(est, utc) + endif + + " If we cached a timezone value, put it back, otherwise clear it + if exists('tz') + let $TZ = tz + else + unlet $TZ + endif endfunc func Test_resolve() @@ -640,6 +666,16 @@ func Test_getbufvar() call assert_equal('iso-8859-2', getbufvar(bufnr('%'), '&fenc')) close + " Get the b: dict. + let b:testvar = 'one' + new + let b:testvar = 'two' + let thebuf = bufnr() + wincmd w + call assert_equal('two', getbufvar(thebuf, 'testvar')) + call assert_equal('two', getbufvar(thebuf, '').testvar) + bwipe! + set fileformats& endfunc diff --git a/src/nvim/testdir/test_hardcopy.vim b/src/nvim/testdir/test_hardcopy.vim index ced13b107c..6125f9b993 100644 --- a/src/nvim/testdir/test_hardcopy.vim +++ b/src/nvim/testdir/test_hardcopy.vim @@ -1,39 +1,137 @@ " Test :hardcopy -func Test_printoptions_parsing() - " Only test that this doesn't throw an error. - set printoptions=left:5in,right:10pt,top:8mm,bottom:2pc - set printoptions=left:2in,top:30pt,right:16mm,bottom:3pc - set printoptions=header:3,syntax:y,number:7,wrap:n - set printoptions=duplex:short,collate:n,jobsplit:y,portrait:n - set printoptions=paper:10x14 - set printoptions=paper:A3 - set printoptions=paper:A4 - set printoptions=paper:A5 - set printoptions=paper:B4 - set printoptions=paper:B5 - set printoptions=paper:executive - set printoptions=paper:folio - set printoptions=paper:ledger - set printoptions=paper:legal - set printoptions=paper:letter - set printoptions=paper:quarto - set printoptions=paper:statement - set printoptions=paper:tabloid - set printoptions=formfeed:y - set printoptions= - set printoptions& +func Test_printoptions() + edit test_hardcopy.vim + syn on + + for opt in ['left:5in,right:10pt,top:8mm,bottom:2pc', + \ 'left:2in,top:30pt,right:16mm,bottom:3pc', + \ 'header:3,syntax:y,number:y,wrap:n', + \ 'header:3,syntax:n,number:y,wrap:y', + \ 'duplex:short,collate:n,jobsplit:y,portrait:n', + \ 'duplex:long,collate:y,jobsplit:n,portrait:y', + \ 'paper:10x14', + \ 'paper:A3', + \ 'paper:A4', + \ 'paper:A5', + \ 'paper:B4', + \ 'paper:B5', + \ 'paper:executive', + \ 'paper:folio', + \ 'paper:ledger', + \ 'paper:legal', + \ 'paper:letter', + \ 'paper:quarto', + \ 'paper:statement', + \ 'paper:tabloid', + \ 'formfeed:y', + \ ''] + exe 'set printoptions=' .. opt + if has('postscript') + hardcopy > Xhardcopy_printoptions + let lines = readfile('Xhardcopy_printoptions') + call assert_true(len(lines) > 20, opt) + call assert_true(lines[0] =~ 'PS-Adobe', opt) + call delete('Xhardcopy_printoptions') + endif + endfor call assert_fails('set printoptions=paper', 'E550:') call assert_fails('set printoptions=shredder:on', 'E551:') call assert_fails('set printoptions=left:no', 'E552:') + set printoptions& + bwipe endfunc -func Test_printmbfont_parsing() - " Only test that this doesn't throw an error. - set printmbfont=r:WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no - set printmbfont= +func Test_printmbfont() + " Print a small help page which contains tabs to cover code that expands tabs to spaces. + help help + syn on + + for opt in [':WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no', + \ ''] + exe 'set printmbfont=' .. opt + if has('postscript') + hardcopy > Xhardcopy_printmbfont + let lines = readfile('Xhardcopy_printmbfont') + call assert_true(len(lines) > 20, opt) + call assert_true(lines[0] =~ 'PS-Adobe', opt) + call delete('Xhardcopy_printmbfont') + endif + endfor set printmbfont& + bwipe +endfunc + +func Test_printexpr() + if !has('unix') + return + endif + + " Not a very useful printexpr value, but enough to test + " hardcopy with 'printexpr'. + function PrintFile(fname) + call writefile(['Test printexpr: ' .. v:cmdarg], + \ 'Xhardcopy_printexpr') + call delete(a:fname) + return 0 + endfunc + set printexpr=PrintFile(v:fname_in) + + help help + hardcopy dummy args + call assert_equal(['Test printexpr: dummy args'], + \ readfile('Xhardcopy_printexpr')) + call delete('Xhardcopy_printexpr') + + " Function return 1 to test print failure. + function PrintFails(fname) + call delete(a:fname) + return 1 + endfunc + set printexpr=PrintFails(v:fname_in) + call assert_fails('hardcopy', 'E365:') + + set printexpr& + bwipe +endfunc + +func Test_errors() + " FIXME: Windows fails differently than Unix. + if has('unix') + edit test_hardcopy.vim + call assert_fails('hardcopy >', 'E324:') + bwipe + endif +endfunc + +func Test_dark_background() + edit test_hardcopy.vim + syn on + + for bg in ['dark', 'light'] + exe 'set background=' .. bg + + if has('postscript') + hardcopy > Xhardcopy_dark_background + let lines = readfile('Xhardcopy_dark_background') + call assert_true(len(lines) > 20) + call assert_true(lines[0] =~ 'PS-Adobe') + call delete('Xhardcopy_dark_background') + endif + endfor + + set background& + bwipe +endfun + +func Test_empty_buffer() + " FIXME: Unclear why this fails on Windows. + if has('unix') + new + call assert_equal("\nNo text to be printed", execute('hardcopy')) + bwipe + endif endfunc func Test_printheader_parsing() @@ -46,22 +144,6 @@ func Test_printheader_parsing() set printheader& endfunc -" Test that :hardcopy produces a non-empty file. -" We don't check much of the contents. -func Test_with_syntax() - if has('postscript') - edit test_hardcopy.vim - set printoptions=syntax:y - syn on - hardcopy > Xhardcopy - let lines = readfile('Xhardcopy') - call assert_true(len(lines) > 20) - call assert_true(lines[0] =~ 'PS-Adobe') - call delete('Xhardcopy') - set printoptions& - endif -endfunc - func Test_fname_with_spaces() if !has('postscript') return @@ -86,4 +168,3 @@ func Test_illegal_byte() bwipe! call delete('Xpstest') endfunc - diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim index 57cfaa298e..dcc588120c 100644 --- a/src/nvim/testdir/test_listchars.vim +++ b/src/nvim/testdir/test_listchars.vim @@ -58,6 +58,26 @@ func Test_listchars() call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) endfor + " tab with 3rd character and linebreak set + set listchars-=tab:<=> + set listchars+=tab:<·> + set linebreak + let expected = [ + \ '<······>aa<····>$', + \ '..bb<··>--$', + \ '...cccc>-$', + \ 'dd........ee--<>$', + \ '-$' + \ ] + redraw! + for i in range(1, 5) + call cursor(i, 1) + call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) + endfor + set nolinebreak + set listchars-=tab:<·> + set listchars+=tab:<=> + set listchars-=trail:- let expected = [ \ '<======>aa<====>$', diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim index 0b941d51ec..5f73bd80ad 100644 --- a/src/nvim/testdir/test_maparg.vim +++ b/src/nvim/testdir/test_maparg.vim @@ -41,6 +41,11 @@ function Test_maparg() map abc y<S-char-114>y call assert_equal("yRy", maparg('abc')) + omap { w + let d = maparg('{', 'o', 0, 1) + call assert_equal(['{', 'w', 'o'], [d.lhs, d.rhs, d.mode]) + ounmap { + map abc <Nop> call assert_equal("<Nop>", maparg('abc')) unmap abc @@ -62,3 +67,5 @@ function Test_range_map() execute "normal a\uf040\<Esc>" call assert_equal("abcd", getline(1)) endfunction + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index f14f292a92..82562339f6 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -390,3 +390,77 @@ func Test_motionforce_omap() delfunc Select delfunc GetCommand endfunc + +" Test for mapping errors +func Test_map_error() + call assert_fails('unmap', 'E474:') + call assert_fails("exe 'map ' .. repeat('a', 51) .. ' :ls'", 'E474:') + call assert_fails('unmap abc', 'E31:') + call assert_fails('unabbr abc', 'E24:') + call assert_equal('', maparg('')) + call assert_fails('echo maparg("abc", [])', 'E730:') + + " unique map + map ,w /[#&!]<CR> + call assert_fails("map <unique> ,w /[#&!]<CR>", 'E227:') + " unique buffer-local map + call assert_fails("map <buffer> <unique> ,w /[.,;]<CR>", 'E225:') + unmap ,w + + " unique abbreviation + abbr SP special + call assert_fails("abbr <unique> SP special", 'E226:') + " unique buffer-local map + call assert_fails("abbr <buffer> <unique> SP special", 'E224:') + unabbr SP + + call assert_fails('mapclear abc', 'E474:') + call assert_fails('abclear abc', 'E474:') +endfunc + +" Test for <special> key mapping +func Test_map_special() + throw 'skipped: Nvim does not support cpoptions flag "<"' + new + let old_cpo = &cpo + set cpo+=< + imap <F12> Blue + call feedkeys("i\<F12>", "x") + call assert_equal("<F12>", getline(1)) + call feedkeys("ddi<F12>", "x") + call assert_equal("Blue", getline(1)) + iunmap <F12> + imap <special> <F12> Green + call feedkeys("ddi\<F12>", "x") + call assert_equal("Green", getline(1)) + call feedkeys("ddi<F12>", "x") + call assert_equal("<F12>", getline(1)) + iunmap <special> <F12> + let &cpo = old_cpo + %bwipe! +endfunc + +" Test for hasmapto() +func Test_hasmapto() + call assert_equal(0, hasmapto('/^\k\+ (')) + call assert_equal(0, hasmapto('/^\k\+ (', 'n')) + nmap ,f /^\k\+ (<CR> + call assert_equal(1, hasmapto('/^\k\+ (')) + call assert_equal(1, hasmapto('/^\k\+ (', 'n')) + call assert_equal(0, hasmapto('/^\k\+ (', 'v')) + + call assert_equal(0, hasmapto('/^\k\+ (', 'n', 1)) +endfunc + +" Test for command-line completion of maps +func Test_mapcomplete() + call assert_equal(['<buffer>', '<expr>', '<nowait>', '<script>', + \ '<silent>', '<special>', '<unique>'], + \ getcompletion('', 'mapping')) + call assert_equal([], getcompletion(',d', 'mapping')) + + call feedkeys(":abbr! \<C-A>\<C-B>\"\<CR>", 'tx') + call assert_match("abbr! \x01", @:) +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim index 265dee66ce..7fbf04311d 100644 --- a/src/nvim/testdir/test_messages.vim +++ b/src/nvim/testdir/test_messages.vim @@ -1,4 +1,4 @@ -" Tests for :messages +" Tests for :messages, :echomsg, :echoerr function Test_messages() let oldmore = &more @@ -6,6 +6,9 @@ function Test_messages() set nomore " Avoid the "message maintainer" line. let $LANG = '' + let $LC_ALL = '' + let $LC_MESSAGES = '' + let $LC_COLLATE = '' let arr = map(range(10), '"hello" . v:val') for s in arr @@ -65,6 +68,35 @@ func Test_message_completion() call assert_equal('"message clear', @:) endfunc +func Test_echomsg() + call assert_equal("\nhello", execute(':echomsg "hello"')) + call assert_equal("\n", execute(':echomsg ""')) + call assert_equal("\n12345", execute(':echomsg 12345')) + call assert_equal("\n[]", execute(':echomsg []')) + call assert_equal("\n[1, 2, 3]", execute(':echomsg [1, 2, 3]')) + call assert_equal("\n{}", execute(':echomsg {}')) + call assert_equal("\n{'a': 1, 'b': 2}", execute(':echomsg {"a": 1, "b": 2}')) + if has('float') + call assert_equal("\n1.23", execute(':echomsg 1.23')) + endif + call assert_match("function('<lambda>\\d*')", execute(':echomsg {-> 1234}')) +endfunc + +func Test_echoerr() + throw 'skipped: Nvim does not support test_ignore_error()' + call test_ignore_error('IgNoRe') + call assert_equal("\nIgNoRe hello", execute(':echoerr "IgNoRe hello"')) + call assert_equal("\n12345 IgNoRe", execute(':echoerr 12345 "IgNoRe"')) + call assert_equal("\n[1, 2, 'IgNoRe']", execute(':echoerr [1, 2, "IgNoRe"]')) + call assert_equal("\n{'IgNoRe': 2, 'a': 1}", execute(':echoerr {"a": 1, "IgNoRe": 2}')) + if has('float') + call assert_equal("\n1.23 IgNoRe", execute(':echoerr 1.23 "IgNoRe"')) + endif + call test_ignore_error('<lambda>') + call assert_match("function('<lambda>\\d*')", execute(':echoerr {-> 1234}')) + call test_ignore_error('RESET') +endfunc + func Test_echospace() set noruler noshowcmd laststatus=1 call assert_equal(&columns - 1, v:echospace) diff --git a/src/nvim/testdir/test_number.vim b/src/nvim/testdir/test_number.vim index 59debcea0d..3c9afc41d5 100644 --- a/src/nvim/testdir/test_number.vim +++ b/src/nvim/testdir/test_number.vim @@ -252,3 +252,14 @@ func Test_numberwidth_adjusted() call s:compare_lines(expect, lines) call s:close_windows() endfunc + +" This was causing a memcheck error +func Test_relativenumber_uninitialised() + new + set rnu + call setline(1, ["a", "b"]) + redraw + call feedkeys("j", 'xt') + redraw + bwipe! +endfunc diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 29d391c232..41f1710faf 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -511,3 +511,46 @@ func Test_shortmess_F2() bwipe bwipe endfunc + +func Test_local_scrolloff() + set so=5 + set siso=7 + split + call assert_equal(5, &so) + setlocal so=3 + call assert_equal(3, &so) + wincmd w + call assert_equal(5, &so) + wincmd w + setlocal so< + call assert_equal(5, &so) + setlocal so=0 + call assert_equal(0, &so) + setlocal so=-1 + call assert_equal(5, &so) + + call assert_equal(7, &siso) + setlocal siso=3 + call assert_equal(3, &siso) + wincmd w + call assert_equal(7, &siso) + wincmd w + setlocal siso< + call assert_equal(7, &siso) + setlocal siso=0 + call assert_equal(0, &siso) + setlocal siso=-1 + call assert_equal(7, &siso) + + close + set so& + set siso& +endfunc + +func Test_visualbell() + set belloff= + set visualbell + call assert_beeps('normal 0h') + set novisualbell + set belloff=all +endfunc diff --git a/src/nvim/testdir/test_plus_arg_edit.vim b/src/nvim/testdir/test_plus_arg_edit.vim index f6d31e7626..e91a6e467a 100644 --- a/src/nvim/testdir/test_plus_arg_edit.vim +++ b/src/nvim/testdir/test_plus_arg_edit.vim @@ -8,3 +8,31 @@ function Test_edit() call delete('Xfile1') call delete('Xfile2') endfunction + +func Test_edit_bad() + if !has('multi_byte') + finish + endif + + " Test loading a utf8 file with bad utf8 sequences. + call writefile(["[\xff][\xc0][\xe2\x89\xf0][\xc2\xc2]"], "Xfile") + new + + " Without ++bad=..., the default behavior is like ++bad=? + e! ++enc=utf8 Xfile + call assert_equal('[?][?][???][??]', getline(1)) + + e! ++enc=utf8 ++bad=_ Xfile + call assert_equal('[_][_][___][__]', getline(1)) + + e! ++enc=utf8 ++bad=drop Xfile + call assert_equal('[][][][]', getline(1)) + + e! ++enc=utf8 ++bad=keep Xfile + call assert_equal("[\xff][\xc0][\xe2\x89\xf0][\xc2\xc2]", getline(1)) + + call assert_fails('e! ++enc=utf8 ++bad=foo Xfile', 'E474:') + + bw! + call delete('Xfile') +endfunc diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim index f3eb88abf0..4b0097617e 100644 --- a/src/nvim/testdir/test_profile.vim +++ b/src/nvim/testdir/test_profile.vim @@ -16,6 +16,7 @@ func Test_profile_func() while l:count > 0 let l:count = l:count - 1 endwhile + sleep 1m endfunc func! Foo3() endfunc @@ -51,7 +52,7 @@ func Test_profile_func() " - Unlike Foo3(), Foo2() should not be deleted since there is a check " for v:profiling. " - Bar() is not reported since it does not match "profile func Foo*". - call assert_equal(30, len(lines)) + call assert_equal(31, len(lines)) call assert_equal('FUNCTION Foo1()', lines[0]) call assert_match('Defined:.*Xprofile_func.vim:3', lines[1]) @@ -71,17 +72,18 @@ func Test_profile_func() call assert_match('^\s*101\s\+.*\swhile l:count > 0$', lines[16]) call assert_match('^\s*100\s\+.*\s let l:count = l:count - 1$', lines[17]) call assert_match('^\s*101\s\+.*\sendwhile$', lines[18]) - call assert_equal('', lines[19]) - call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[20]) - call assert_equal('count total (s) self (s) function', lines[21]) - call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[22]) - call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[23]) - call assert_equal('', lines[24]) - call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[25]) - call assert_equal('count total (s) self (s) function', lines[26]) - call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[27]) - call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[28]) - call assert_equal('', lines[29]) + call assert_match('^\s*1\s\+.\+sleep 1m$', lines[19]) + call assert_equal('', lines[20]) + call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[21]) + call assert_equal('count total (s) self (s) function', lines[22]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[23]) + call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[24]) + call assert_equal('', lines[25]) + call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[26]) + call assert_equal('count total (s) self (s) function', lines[27]) + call assert_match('^\s*1\s\+\d\+\.\d\+\s\+Foo2()$', lines[28]) + call assert_match('^\s*2\s\+\d\+\.\d\+\s\+Foo1()$', lines[29]) + call assert_equal('', lines[30]) call delete('Xprofile_func.vim') call delete('Xprofile_func.log') diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index d7b387c2c9..35555ca9d3 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -1510,6 +1510,13 @@ func Test_setqflist_invalid_nr() call setqflist([], ' ', {'nr' : $XXX_DOES_NOT_EXIST}) endfunc +func Test_setqflist_user_sets_buftype() + call setqflist([{'text': 'foo'}, {'text': 'bar'}]) + set buftype=quickfix + call setqflist([], 'a') + enew +endfunc + func Test_quickfix_set_list_with_act() call XquickfixSetListWithAct('c') call XquickfixSetListWithAct('l') @@ -3311,6 +3318,14 @@ func Test_lvimgrep_crash() enew | only endfunc +func Test_lvimgrep_crash2() + au BufNewFile x sfind + call assert_fails('lvimgrep x x', 'E480:') + call assert_fails('lvimgrep x x x', 'E480:') + + au! BufNewFile +endfunc + " Test for the position of the quickfix and location list window func Test_qfwin_pos() " Open two windows diff --git a/src/nvim/testdir/test_quotestar.vim b/src/nvim/testdir/test_quotestar.vim index ce5a9ee827..77a5153a81 100644 --- a/src/nvim/testdir/test_quotestar.vim +++ b/src/nvim/testdir/test_quotestar.vim @@ -108,7 +108,8 @@ func Do_test_quotestar_for_x11() call remote_send(name, ":gui -f\<CR>") endif " Wait for the server in the GUI to be up and answering requests. - call WaitForAssert({-> assert_match("1", remote_expr(name, "has('gui_running')", "", 1))}) + " On some systems and with valgrind this can be very slow. + call WaitForAssert({-> assert_match("1", remote_expr(name, "has('gui_running')", "", 1))}, 10000) call remote_send(name, ":let @* = 'maybe'\<CR>") call WaitForAssert({-> assert_equal("maybe", remote_expr(name, "@*", "", 2))}) diff --git a/src/nvim/testdir/test_restricted.vim b/src/nvim/testdir/test_restricted.vim new file mode 100644 index 0000000000..a29f7c33d3 --- /dev/null +++ b/src/nvim/testdir/test_restricted.vim @@ -0,0 +1,103 @@ +" Test for "rvim" or "vim -Z" + +source shared.vim + +"if has('win32') && has('gui') +" " Win32 GUI shows a dialog instead of displaying the error in the last line. +" finish +"endif + +func Test_restricted() + call Run_restricted_test('!ls', 'E145:') +endfunc + +func Run_restricted_test(ex_cmd, error) + let cmd = GetVimCommand('Xrestricted') + if cmd == '' + return + endif + + " Use a VimEnter autocommand to avoid that the error message is displayed in + " a dialog with an OK button. + call writefile([ + \ "func Init()", + \ " silent! " . a:ex_cmd, + \ " call writefile([v:errmsg], 'Xrestrout')", + \ " qa!", + \ "endfunc", + \ "au VimEnter * call Init()", + \ ], 'Xrestricted') + call system(cmd . ' -Z') + call assert_match(a:error, join(readfile('Xrestrout'))) + + call delete('Xrestricted') + call delete('Xrestrout') +endfunc + +func Test_restricted_lua() + if !has('lua') + throw 'Skipped: Lua is not supported' + endif + call Run_restricted_test('lua print("Hello, Vim!")', 'E981:') + call Run_restricted_test('luado return "hello"', 'E981:') + call Run_restricted_test('luafile somefile', 'E981:') + call Run_restricted_test('call luaeval("expression")', 'E145:') +endfunc + +func Test_restricted_mzscheme() + if !has('mzscheme') + throw 'Skipped: MzScheme is not supported' + endif + call Run_restricted_test('mzscheme statement', 'E981:') + call Run_restricted_test('mzfile somefile', 'E981:') + call Run_restricted_test('call mzeval("expression")', 'E145:') +endfunc + +func Test_restricted_perl() + if !has('perl') + throw 'Skipped: Perl is not supported' + endif + " TODO: how to make Safe mode fail? + " call Run_restricted_test('perl system("ls")', 'E981:') + " call Run_restricted_test('perldo system("hello")', 'E981:') + " call Run_restricted_test('perlfile somefile', 'E981:') + " call Run_restricted_test('call perleval("system(\"ls\")")', 'E145:') +endfunc + +func Test_restricted_python() + if !has('python') + throw 'Skipped: Python is not supported' + endif + call Run_restricted_test('python print "hello"', 'E981:') + call Run_restricted_test('pydo return "hello"', 'E981:') + call Run_restricted_test('pyfile somefile', 'E981:') + call Run_restricted_test('call pyeval("expression")', 'E145:') +endfunc + +func Test_restricted_python3() + if !has('python3') + throw 'Skipped: Python3 is not supported' + endif + call Run_restricted_test('py3 print "hello"', 'E981:') + call Run_restricted_test('py3do return "hello"', 'E981:') + call Run_restricted_test('py3file somefile', 'E981:') + call Run_restricted_test('call py3eval("expression")', 'E145:') +endfunc + +func Test_restricted_ruby() + if !has('ruby') + throw 'Skipped: Ruby is not supported' + endif + call Run_restricted_test('ruby print "Hello"', 'E981:') + call Run_restricted_test('rubydo print "Hello"', 'E981:') + call Run_restricted_test('rubyfile somefile', 'E981:') +endfunc + +func Test_restricted_tcl() + if !has('tcl') + throw 'Skipped: Tcl is not supported' + endif + call Run_restricted_test('tcl puts "Hello"', 'E981:') + call Run_restricted_test('tcldo puts "Hello"', 'E981:') + call Run_restricted_test('tclfile somefile', 'E981:') +endfunc diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index 5d99027ca5..8036dea29f 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -698,3 +698,9 @@ func Test_search_display_pattern() set norl endif endfunc + +func Test_search_special() + " this was causing illegal memory access and an endless loop + set t_PE= + exe "norm /\x80PS" +endfunc diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim index ef4b227215..8b1927e4f0 100644 --- a/src/nvim/testdir/test_signs.vim +++ b/src/nvim/testdir/test_signs.vim @@ -4,6 +4,8 @@ if !has('signs') finish endif +source screendump.vim + func Test_sign() new call setline(1, ['a', 'b', 'c', 'd']) @@ -210,13 +212,16 @@ func Test_sign_completion() call assert_equal('"sign define Sign linehl=SpellBad SpellCap ' . \ 'SpellLocal SpellRare', @:) - call writefile(['foo'], 'XsignOne') - call writefile(['bar'], 'XsignTwo') + call feedkeys(":sign define Sign texthl=Spell\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign define Sign texthl=SpellBad SpellCap ' . + \ 'SpellLocal SpellRare', @:) + + call writefile(repeat(["Sun is shining"], 30), "XsignOne") + call writefile(repeat(["Sky is blue"], 30), "XsignTwo") call feedkeys(":sign define Sign icon=Xsig\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:) - call delete('XsignOne') - call delete('XsignTwo') + " Test for completion of arguments to ':sign undefine' call feedkeys(":sign undefine \<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"sign undefine Sign1 Sign2', @:) @@ -227,17 +232,70 @@ func Test_sign_completion() call feedkeys(":sign place 1 name=\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"sign place 1 name=Sign1 Sign2', @:) + edit XsignOne + sign place 1 name=Sign1 line=5 + sign place 1 name=Sign1 group=g1 line=10 + edit XsignTwo + sign place 1 name=Sign2 group=g2 line=15 + + " Test for completion of group= and file= arguments to ':sign place' + call feedkeys(":sign place 1 name=Sign1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign place 1 name=Sign1 file=XsignOne XsignTwo', @:) + call feedkeys(":sign place 1 name=Sign1 group=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign place 1 name=Sign1 group=g1 g2', @:) + + " Test for completion of arguments to 'sign place' without sign identifier + call feedkeys(":sign place \<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign place buffer= file= group=', @:) + call feedkeys(":sign place file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign place file=XsignOne XsignTwo', @:) + call feedkeys(":sign place group=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign place group=g1 g2', @:) + call feedkeys(":sign place group=g1 file=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign place group=g1 file=XsignOne XsignTwo', @:) + + " Test for completion of arguments to ':sign unplace' call feedkeys(":sign unplace 1 \<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"sign unplace 1 buffer= file= group=', @:) - + call feedkeys(":sign unplace 1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign unplace 1 file=XsignOne XsignTwo', @:) + call feedkeys(":sign unplace 1 group=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign unplace 1 group=g1 g2', @:) + call feedkeys(":sign unplace 1 group=g2 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign unplace 1 group=g2 file=XsignOne XsignTwo', @:) + + " Test for completion of arguments to ':sign list' call feedkeys(":sign list \<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"sign list Sign1 Sign2', @:) + " Test for completion of arguments to ':sign jump' call feedkeys(":sign jump 1 \<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"sign jump 1 buffer= file= group=', @:) + call feedkeys(":sign jump 1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign jump 1 file=XsignOne XsignTwo', @:) + call feedkeys(":sign jump 1 group=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign jump 1 group=g1 g2', @:) + + " Error cases + call feedkeys(":sign here\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal('"sign here', @:) + call feedkeys(":sign define Sign here=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"sign define Sign here=\<C-A>", @:) + call feedkeys(":sign place 1 here=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"sign place 1 here=\<C-A>", @:) + call feedkeys(":sign jump 1 here=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"sign jump 1 here=\<C-A>", @:) + call feedkeys(":sign here there\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"sign here there\<C-A>", @:) + call feedkeys(":sign here there=\<C-A>\<C-B>\"\<CR>", 'tx') + call assert_equal("\"sign here there=\<C-A>", @:) + sign unplace * group=* sign undefine Sign1 sign undefine Sign2 + enew + call delete('XsignOne') + call delete('XsignTwo') endfunc func Test_sign_invalid_commands() @@ -1127,6 +1185,319 @@ func Test_sign_priority() \ 'priority' : 10}], \ s[0].signs) + call sign_unplace('*') + + " Three signs on different lines with changing priorities + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 11, 'priority' : 50}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 12, 'priority' : 60}) + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 13, 'priority' : 70}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 12, 'priority' : 40}) + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 13, 'priority' : 30}) + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 11, 'priority' : 50}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 11, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 12, 'group' : '', + \ 'priority' : 40}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 13, 'group' : '', + \ 'priority' : 30}], + \ s[0].signs) + + call sign_unplace('*') + + " Two signs on the same line with changing priorities + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 30}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + " Change the priority of the last sign to highest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 40}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 40}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}], + \ s[0].signs) + " Change the priority of the first sign to lowest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 25}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 25}], + \ s[0].signs) + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 45}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 55}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 55}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 45}], + \ s[0].signs) + + call sign_unplace('*') + + " Three signs on the same line with changing priorities + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 40}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 30}) + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 40}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + + " Change the priority of the middle sign to the highest + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 50}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 40}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + + " Change the priority of the middle sign to the lowest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 15}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}], + \ s[0].signs) + + " Change the priority of the last sign to the highest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 55}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 55}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + + " Change the priority of the first sign to the lowest + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 15}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 50}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}], + \ s[0].signs) + + call sign_unplace('*') + + " Three signs on the same line with changing priorities along with other + " signs + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 2, 'priority' : 10}) + call sign_place(2, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 30}) + call sign_place(3, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + call sign_place(4, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 25}) + call sign_place(5, '', 'sign2', 'Xsign', + \ {'lnum' : 6, 'priority' : 80}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 25}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + " Change the priority of the first sign to lowest + call sign_place(2, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 15}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 25}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + " Change the priority of the last sign to highest + call sign_place(2, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 30}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 25}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + " Change the priority of the middle sign to lowest + call sign_place(4, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 15}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + " Change the priority of the middle sign to highest + call sign_place(3, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 35}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '', + \ 'priority' : 10}, + \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 35}, + \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 30}, + \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 15}, + \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '', + \ 'priority' : 80}], + \ s[0].signs) + + call sign_unplace('*') + + " Multiple signs with the same priority on the same line + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + call sign_place(2, '', 'sign2', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + " Place the last sign again with the same priority + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + " Place the first sign again with the same priority + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + " Place the middle sign again with the same priority + call sign_place(3, '', 'sign3', 'Xsign', + \ {'lnum' : 4, 'priority' : 20}) + let s = sign_getplaced('Xsign', {'group' : '*'}) + call assert_equal([ + \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}, + \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '', + \ 'priority' : 20}], + \ s[0].signs) + + call sign_unplace('*') + + " Place multiple signs with same id on a line with different priority + call sign_place(1, '', 'sign1', 'Xsign', + \ {'lnum' : 5, 'priority' : 20}) + call sign_place(1, '', 'sign2', 'Xsign', + \ {'lnum' : 5, 'priority' : 10}) + let s = sign_getplaced('Xsign', {'lnum' : 5}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign2', 'lnum' : 5, 'group' : '', + \ 'priority' : 10}], + \ s[0].signs) + call sign_place(1, '', 'sign2', 'Xsign', + \ {'lnum' : 5, 'priority' : 5}) + let s = sign_getplaced('Xsign', {'lnum' : 5}) + call assert_equal([ + \ {'id' : 1, 'name' : 'sign2', 'lnum' : 5, 'group' : '', + \ 'priority' : 5}], + \ s[0].signs) + " Error case call assert_fails("call sign_place(1, 'g1', 'sign1', 'Xsign', \ [])", 'E715:') @@ -1339,3 +1710,35 @@ func Test_sign_jump_func() sign undefine sign1 enew! | only! endfunc + +" Test for correct cursor position after the sign column appears or disappears. +func Test_sign_cursor_position() + if !CanRunVimInTerminal() + throw 'Skipped: cannot make screendumps' + endif + + let lines =<< trim END + call setline(1, [repeat('x', 75), 'mmmm', 'yyyy']) + call cursor(2,1) + sign define s1 texthl=Search text==> + redraw + sign place 10 line=2 name=s1 + END + call writefile(lines, 'XtestSigncolumn') + let buf = RunVimInTerminal('-S XtestSigncolumn', {'rows': 6}) + call VerifyScreenDump(buf, 'Test_sign_cursor_1', {}) + + " Change the sign text + call term_sendkeys(buf, ":sign define s1 text=-)\<CR>") + call VerifyScreenDump(buf, 'Test_sign_cursor_2', {}) + + " update cursor position calculation + call term_sendkeys(buf, "lh") + call term_sendkeys(buf, ":sign unplace 10\<CR>") + call VerifyScreenDump(buf, 'Test_sign_cursor_3', {}) + + + " clean up + call StopVimInTerminal(buf) + call delete('XtestSigncolumn') +endfunc diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index 94789d6ea3..e5eaa01e92 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -130,20 +130,21 @@ endfunc func Test_spellinfo() throw 'skipped: Nvim does not support enc=latin1' new + let runtime = substitute($VIMRUNTIME, '\\', '/', 'g') set enc=latin1 spell spelllang=en - call assert_match("^\nfile: .*/runtime/spell/en.latin1.spl\n$", execute('spellinfo')) + call assert_match("^\nfile: " .. runtime .. "/spell/en.latin1.spl\n$", execute('spellinfo')) set enc=cp1250 spell spelllang=en - call assert_match("^\nfile: .*/runtime/spell/en.ascii.spl\n$", execute('spellinfo')) + call assert_match("^\nfile: " .. runtime .. "/spell/en.ascii.spl\n$", execute('spellinfo')) set enc=utf-8 spell spelllang=en - call assert_match("^\nfile: .*/runtime/spell/en.utf-8.spl\n$", execute('spellinfo')) + call assert_match("^\nfile: " .. runtime .. "/spell/en.utf-8.spl\n$", execute('spellinfo')) set enc=latin1 spell spelllang=en_us,en_nz call assert_match("^\n" . - \ "file: .*/runtime/spell/en.latin1.spl\n" . - \ "file: .*/runtime/spell/en.latin1.spl\n$", execute('spellinfo')) + \ "file: " .. runtime .. "/spell/en.latin1.spl\n" . + \ "file: " .. runtime .. "/spell/en.latin1.spl\n$", execute('spellinfo')) set spell spelllang= call assert_fails('spellinfo', 'E756:') diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim index e94bd22cea..ff07d8eceb 100644 --- a/src/nvim/testdir/test_substitute.vim +++ b/src/nvim/testdir/test_substitute.vim @@ -613,6 +613,25 @@ func Test_sub_replace_10() call assert_equal('1aaa', substitute('123', '1\zs\|[23]', 'a', 'g')) endfunc +func SubReplacer(text, submatches) + return a:text .. a:submatches[0] .. a:text +endfunc +func SubReplacer20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, submatches) + return a:t3 .. a:submatches[0] .. a:t11 +endfunc + +func Test_substitute_partial() + call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacer', ['foo']), 'g')) + + " 19 arguments plus one is just OK + let Replacer = function('SubReplacer20', repeat(['foo'], 19)) + call assert_equal('1foo2foo3', substitute('123', '2', Replacer, 'g')) + + " 20 arguments plus one is too many + let Replacer = function('SubReplacer20', repeat(['foo'], 20)) + call assert_fails("call substitute('123', '2', Replacer, 'g')", 'E118') +endfunc + func Test_sub_cmd_9() new let input = ['1 aaa', '2 aaa', '3 aaa'] diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim index cb54ace695..d4ff42fd68 100644 --- a/src/nvim/testdir/test_taglist.vim +++ b/src/nvim/testdir/test_taglist.vim @@ -7,6 +7,7 @@ func Test_taglist() \ "BFoo\tXbar\t1", \ "BBar\tXbar\t2", \ "Kindly\tXbar\t3;\"\tv\tfile:", + \ "Lambda\tXbar\t3;\"\tλ\tfile:", \ "Command\tXbar\tcall cursor(3, 4)|;\"\td", \ ], 'Xtags') set tags=Xtags @@ -17,12 +18,16 @@ func Test_taglist() call assert_equal(['FFoo', 'BFoo'], map(taglist("Foo", "Xfoo"), {i, v -> v.name})) call assert_equal(['BFoo', 'FFoo'], map(taglist("Foo", "Xbar"), {i, v -> v.name})) - let kind = taglist("Kindly") - call assert_equal(1, len(kind)) - call assert_equal('v', kind[0]['kind']) - call assert_equal('3', kind[0]['cmd']) - call assert_equal(1, kind[0]['static']) - call assert_equal('Xbar', kind[0]['filename']) + let kindly = taglist("Kindly") + call assert_equal(1, len(kindly)) + call assert_equal('v', kindly[0]['kind']) + call assert_equal('3', kindly[0]['cmd']) + call assert_equal(1, kindly[0]['static']) + call assert_equal('Xbar', kindly[0]['filename']) + + let lambda = taglist("Lambda") + call assert_equal(1, len(lambda)) + call assert_equal('λ', lambda[0]['kind']) let cmd = taglist("Command") call assert_equal(1, len(cmd)) diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim index 3043103270..40376a877e 100644 --- a/src/nvim/testdir/test_timers.vim +++ b/src/nvim/testdir/test_timers.vim @@ -339,4 +339,8 @@ func Test_nocatch_garbage_collect() delfunc FeedChar endfunc +func Test_timer_invalid_callback() + call assert_fails('call timer_start(0, "0")', 'E921') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_user_func.vim b/src/nvim/testdir/test_user_func.vim index e7a3701386..67701ee3ca 100644 --- a/src/nvim/testdir/test_user_func.vim +++ b/src/nvim/testdir/test_user_func.vim @@ -94,3 +94,7 @@ func Test_user_func() unlet g:retval g:counter enew! endfunc + +func Test_failed_call_in_try() + try | call UnknownFunc() | catch | endtry +endfunc diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim index b1f33f56dd..1b4ce4c4af 100644 --- a/src/nvim/testdir/test_utf8.vim +++ b/src/nvim/testdir/test_utf8.vim @@ -60,3 +60,46 @@ func Test_getvcol() call assert_equal(2, virtcol("'[")) call assert_equal(2, virtcol("']")) endfunc + +func Test_list2str_str2list_utf8() + " One Unicode codepoint + let s = "\u3042\u3044" + let l = [0x3042, 0x3044] + call assert_equal(l, str2list(s, 1)) + call assert_equal(s, list2str(l, 1)) + if &enc ==# 'utf-8' + call assert_equal(str2list(s), str2list(s, 1)) + call assert_equal(list2str(l), list2str(l, 1)) + endif + + " With composing characters + let s = "\u304b\u3099\u3044" + let l = [0x304b, 0x3099, 0x3044] + call assert_equal(l, str2list(s, 1)) + call assert_equal(s, list2str(l, 1)) + if &enc ==# 'utf-8' + call assert_equal(str2list(s), str2list(s, 1)) + call assert_equal(list2str(l), list2str(l, 1)) + endif + + " Null list is the same as an empty list + call assert_equal('', list2str([])) + " call assert_equal('', list2str(test_null_list())) +endfunc + +func Test_list2str_str2list_latin1() + " When 'encoding' is not multi-byte can still get utf-8 string. + " But we need to create the utf-8 string while 'encoding' is utf-8. + let s = "\u3042\u3044" + let l = [0x3042, 0x3044] + + let save_encoding = &encoding + " set encoding=latin1 + + let lres = str2list(s, 1) + let sres = list2str(l, 1) + + let &encoding = save_encoding + call assert_equal(l, lres) + call assert_equal(s, sres) +endfunc diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim index 6066d61af4..56031662a3 100644 --- a/src/nvim/testdir/test_writefile.vim +++ b/src/nvim/testdir/test_writefile.vim @@ -1,4 +1,4 @@ -" Tests for the writefile() function. +" Tests for the writefile() function and some :write commands. func Test_writefile() let f = tempname() @@ -16,6 +16,11 @@ func Test_writefile() call delete(f) endfunc +func Test_writefile_ignore_regexp_error() + write Xt[z-a]est.txt + call delete('Xt[z-a]est.txt') +endfunc + func Test_writefile_fails_gently() call assert_fails('call writefile(["test"], "Xfile", [])', 'E730:') call assert_false(filereadable("Xfile")) diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 951cb50c3c..bbee7e4712 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -31,6 +31,10 @@ void tinput_init(TermInput *input, Loop *loop) input->paste = 0; input->in_fd = STDIN_FILENO; input->waiting_for_bg_response = 0; + // The main thread is waiting for the UI thread to call CONTINUE, so it can + // safely access global variables. + input->ttimeout = (bool)p_ttimeout; + input->ttimeoutlen = p_ttm; input->key_buffer = rbuffer_new(KEY_BUFFER_SIZE); uv_mutex_init(&input->key_buffer_mutex); uv_cond_init(&input->key_buffer_cond); @@ -285,21 +289,6 @@ static TermKeyResult tk_getkey(TermKey *tk, TermKeyKey *key, bool force) static void tinput_timer_cb(TimeWatcher *watcher, void *data); -static int get_key_code_timeout(void) -{ - Integer ms = -1; - // Check 'ttimeout' to determine if we should send ESC after 'ttimeoutlen'. - Error err = ERROR_INIT; - if (nvim_get_option(cstr_as_string("ttimeout"), &err).data.boolean) { - Object rv = nvim_get_option(cstr_as_string("ttimeoutlen"), &err); - if (!ERROR_SET(&err)) { - ms = rv.data.integer; - } - } - api_clear_error(&err); - return (int)ms; -} - static void tk_getkeys(TermInput *input, bool force) { TermKeyKey key; @@ -324,12 +313,11 @@ static void tk_getkeys(TermInput *input, bool force) // yet contain all the bytes required. `key` structure indicates what // termkey_getkey_force() would return. - int ms = get_key_code_timeout(); - - if (ms > 0) { + if (input->ttimeout && input->ttimeoutlen >= 0) { // Stop the current timer if already running time_watcher_stop(&input->timer_handle); - time_watcher_start(&input->timer_handle, tinput_timer_cb, (uint32_t)ms, 0); + time_watcher_start(&input->timer_handle, tinput_timer_cb, + (uint64_t)input->ttimeoutlen, 0); } else { tk_getkeys(input, true); } diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 77bd6fa132..b30546c815 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -12,7 +12,9 @@ typedef struct term_input { // Phases: -1=all 0=disabled 1=first-chunk 2=continue 3=last-chunk int8_t paste; bool waiting; + bool ttimeout; int8_t waiting_for_bg_response; + long ttimeoutlen; TermKey *tk; #if TERMKEY_VERSION_MAJOR > 0 || TERMKEY_VERSION_MINOR > 18 TermKey_Terminfo_Getstr_Hook *tk_ti_hook_fn; ///< libtermkey terminfo hook diff --git a/src/nvim/tui/terminfo.c b/src/nvim/tui/terminfo.c index 03173afe07..ff2a357752 100644 --- a/src/nvim/tui/terminfo.c +++ b/src/nvim/tui/terminfo.c @@ -31,7 +31,10 @@ bool terminfo_is_term_family(const char *term, const char *family) return tlen >= flen && 0 == memcmp(term, family, flen) // Per commentary in terminfo, minus is the only valid suffix separator. - && ('\0' == term[flen] || '-' == term[flen]); + // The screen terminfo may have a terminal name like screen.xterm. By making + // the dot(.) a valid separator, such terminal names will also be the + // terminal family of the screen. + && ('\0' == term[flen] || '-' == term[flen] || '.' == term[flen]); } bool terminfo_is_bsd_console(const char *term) @@ -187,7 +190,7 @@ void terminfo_info_msg(const unibi_term *const ut) msg_printf_attr(0, " %-25s %-10s = ", unibi_name_str(i), unibi_short_name_str(i)); // Most of these strings will contain escape sequences. - msg_outtrans_special((char_u *)s, false); + msg_outtrans_special((char_u *)s, false, 0); msg_putchar('\n'); } } @@ -214,7 +217,7 @@ void terminfo_info_msg(const unibi_term *const ut) msg_puts("Extended string capabilities:\n"); for (size_t i = 0; i < unibi_count_ext_str(ut); i++) { msg_printf_attr(0, " %-25s = ", unibi_get_ext_str_name(ut, i)); - msg_outtrans_special((char_u *)unibi_get_ext_str(ut, i), false); + msg_outtrans_special((char_u *)unibi_get_ext_str(ut, i), false, 0); msg_putchar('\n'); } } diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index e9276db484..228545a844 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -31,6 +31,7 @@ #include "nvim/event/signal.h" #include "nvim/os/input.h" #include "nvim/os/os.h" +#include "nvim/os/signal.h" #include "nvim/os/tty.h" #include "nvim/strings.h" #include "nvim/syntax.h" @@ -48,10 +49,15 @@ #define OUTBUF_SIZE 0xffff #define TOO_MANY_EVENTS 1000000 -#define STARTS_WITH(str, prefix) (strlen(str) >= (sizeof(prefix) - 1) \ - && 0 == memcmp((str), (prefix), sizeof(prefix) - 1)) -#define TMUX_WRAP(is_tmux, seq) ((is_tmux) \ - ? "\x1bPtmux;\x1b" seq "\x1b\\" : seq) +#define STARTS_WITH(str, prefix) \ + (strlen(str) >= (sizeof(prefix) - 1) && 0 == memcmp((str), (prefix), \ + sizeof(prefix) - 1)) +#define SCREEN_WRAP(is_screen, seq) ((is_screen) \ + ? DCS_STR seq STERM_STR : seq) +#define SCREEN_TMUX_WRAP(is_screen, is_tmux, seq) \ + ((is_screen) \ + ? DCS_STR seq STERM_STR : (is_tmux) \ + ? DCS_STR "tmux;\x1b" seq STERM_STR : seq) #define LINUXSET0C "\x1b[?0c" #define LINUXSET1C "\x1b[?1c" @@ -1099,6 +1105,7 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow, set_scroll_region(ui, top, bot, left, right); } cursor_goto(ui, top, left); + update_attrs(ui, 0); if (rows > 0) { if (rows == 1) { @@ -1238,7 +1245,9 @@ static void suspend_event(void **argv) tui_terminal_stop(ui); data->cont_received = false; stream_set_blocking(input_global_fd(), true); // normalize stream (#2598) + signal_stop(); kill(0, SIGTSTP); + signal_start(); while (!data->cont_received) { // poll the event loop until SIGCONT is received loop_poll_events(data->loop, -1); @@ -1291,6 +1300,12 @@ static void tui_option_set(UI *ui, String name, Object value) data->print_attr_id = -1; invalidate(ui, 0, data->grid.height, 0, data->grid.width); } + if (strequal(name.data, "ttimeout")) { + data->input.ttimeout = value.data.boolean; + } + if (strequal(name.data, "ttimeoutlen")) { + data->input.ttimeoutlen = (long)value.data.integer; + } } static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, @@ -1528,7 +1543,10 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, bool rxvt = terminfo_is_term_family(term, "rxvt"); bool teraterm = terminfo_is_term_family(term, "teraterm"); bool putty = terminfo_is_term_family(term, "putty"); - bool screen = terminfo_is_term_family(term, "screen"); + bool screen = terminfo_is_term_family(term, "screen") && !os_getenv("TMUX"); + bool screen_host_linuxvt = + terminfo_is_term_family(screen && term[6] == '.' + ? term + 7 : NULL, "linux"); bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX"); bool st = terminfo_is_term_family(term, "st"); bool gnome = terminfo_is_term_family(term, "gnome") @@ -1630,6 +1648,11 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, // per the screen manual; 2017-04 terminfo.src lacks these. unibi_set_if_empty(ut, unibi_to_status_line, "\x1b_"); unibi_set_if_empty(ut, unibi_from_status_line, "\x1b\\"); + // Fix an issue where smglr is inherited by TERM=screen.xterm. + if (unibi_get_str(ut, unibi_set_lr_margin)) { + ILOG("Disabling smglr with TERM=screen.xterm for screen."); + unibi_set_str(ut, unibi_set_lr_margin, NULL); + } } else if (tmux) { unibi_set_if_empty(ut, unibi_to_status_line, "\x1b_"); unibi_set_if_empty(ut, unibi_from_status_line, "\x1b\\"); @@ -1682,8 +1705,9 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, #define XTERM_SETAB_16 \ "\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m" - data->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg", - "\x1b]11;?\x07"); + data->unibi_ext.get_bg = + (int)unibi_add_ext_str(ut, "ext.get_bg", + SCREEN_TMUX_WRAP(screen, tmux, "\x1b]11;?\x07")); // Terminals with 256-colour SGR support despite what terminfo says. if (unibi_get_num(ut, unibi_max_colors) < 256) { @@ -1718,6 +1742,32 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss"); } + // GNU Screen does not have Ss/Se. When terminfo has Ss/Se, it is wrapped with + // DCS because it is inherited from the host terminal. + if (screen) { + size_t len; + size_t dcs_st_len = strlen(DCS_STR) + strlen(STERM_STR); + if (-1 != data->unibi_ext.set_cursor_style) { + const char *orig_ss = + unibi_get_ext_str(data->ut, (size_t)data->unibi_ext.reset_cursor_style); + len = STRLEN(orig_ss) + dcs_st_len + 1; + char *ss = xmalloc(len); + snprintf(ss, len, "%s%s%s", DCS_STR, orig_ss, STERM_STR); + unibi_set_ext_str(data->ut, (size_t)data->unibi_ext.set_cursor_style, ss); + xfree(ss); + } + if (-1 != data->unibi_ext.reset_cursor_style) { + const char *orig_se = + unibi_get_ext_str(data->ut, (size_t)data->unibi_ext.reset_cursor_style); + len = strlen(orig_se) + dcs_st_len + 1; + char *se = xmalloc(len); + snprintf(se, len, "%s%s%s", DCS_STR, orig_se, STERM_STR); + unibi_set_ext_str(data->ut, + (size_t)data->unibi_ext.reset_cursor_style, se); + xfree(se); + } + } + // Dickey ncurses terminfo includes Ss/Se capabilities since 2011-07-14. So // adding them to terminal types, that have such control sequences but lack // the correct terminfo entries, is a fixup, not an augmentation. @@ -1733,7 +1783,12 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, || (konsolev >= 180770) // #9364 || tmux // per tmux manual page // https://lists.gnu.org/archive/html/screen-devel/2013-03/msg00000.html - || screen + || (screen + && (!screen_host_linuxvt + || (screen_host_linuxvt + && (xterm_version || (vte_version > 0) || colorterm)))) + // Since GNU Screen does not support DECSCUSR, DECSCUSR is wrapped + // in DCS and output to the host terminal. || st // #7641 || rxvt // per command.C // per analysis of VT100Terminal.m @@ -1746,34 +1801,43 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, || (linuxvt && (xterm_version || (vte_version > 0) || colorterm)))) { data->unibi_ext.set_cursor_style = - (int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q"); + (int)unibi_add_ext_str(ut, "Ss", SCREEN_WRAP(screen, "\x1b[%p1%d q")); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", ""); } unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style, - "\x1b[ q"); - } else if (linuxvt) { + SCREEN_WRAP(screen, "\x1b[ q")); + } else if (linuxvt || screen_host_linuxvt) { // Linux uses an idiosyncratic escape code to set the cursor shape and // does not support DECSCUSR. // See http://linuxgazette.net/137/anonymous.html for more info - data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss", - "\x1b[?" - "%?" - // The parameter passed to Ss is the DECSCUSR parameter, so the - // terminal capability has to translate into the Linux idiosyncratic - // parameter. - // - // linuxvt only supports block and underline. It is also only - // possible to have a steady block (no steady underline) - "%p1%{2}%<" "%t%{8}" // blink block - "%e%p1%{2}%=" "%t%{112}" // steady block - "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block) - "%e%p1%{4}%=" "%t%{4}" // steady underline - "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline) - "%e%p1%{6}%=" "%t%{2}" // steady bar - "%e%{0}" // anything else - "%;" "%dc"); + // + // Since gnu Screen does not have Ss/Se, if the host terminal is a linux + // console that does not support xterm extensions, it will wraps the + // linux-specific sequence in DCS and outputs it. + data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str( + ut, "Ss", + SCREEN_WRAP(screen, + "\x1b[?" + "%?" + // The parameter passed to Ss is the DECSCUSR parameter, + // so the + // terminal capability has to translate into the Linux + // idiosyncratic parameter. + // + // linuxvt only supports block and underline. It is also + // only possible to have a steady block (no steady + // underline) + "%p1%{2}%<" "%t%{8}" // blink block + "%e%p1%{2}%=" "%t%{112}" // steady block + "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half + // block) + "%e%p1%{4}%=" "%t%{4}" // steady underline + "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline) + "%e%p1%{6}%=" "%t%{2}" // steady bar + "%e%{0}" // anything else + "%;" "%dc")); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", ""); @@ -1783,21 +1847,25 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, } else if (konsolev > 0 && konsolev < 180770) { // Konsole before version 18.07.70: set up a nonce profile. This has // side-effects on temporary font resizing. #6798 - data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss", - TMUX_WRAP(tmux, "\x1b]50;CursorShape=%?" - "%p1%{3}%<" "%t%{0}" // block - "%e%p1%{5}%<" "%t%{2}" // underline - "%e%{1}" // everything else is bar - "%;%d;BlinkingCursorEnabled=%?" - "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special, - "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag. - "%;%d\x07")); + data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str( + ut, "Ss", + SCREEN_TMUX_WRAP(screen, tmux, + "\x1b]50;CursorShape=%?" + "%p1%{3}%<" "%t%{0}" // block + "%e%p1%{5}%<" "%t%{2}" // underline + "%e%{1}" // everything else is bar + "%;%d;BlinkingCursorEnabled=%?" + "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude + // zero as special, + "%e%p1%{1}%&" // in all other c2ses we can treat bit + // #0 as a flag. + "%;%d\x07")); if (-1 == data->unibi_ext.reset_cursor_style) { data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se", ""); } unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style, - "\x1b]50;\x07"); + SCREEN_TMUX_WRAP(screen, tmux, "\x1b]50;\x07")); } } } @@ -1826,6 +1894,8 @@ static void augment_terminfo(TUIData *data, const char *term, bool alacritty = terminfo_is_term_family(term, "alacritty"); // None of the following work over SSH; see :help TERM . bool iterm_pretending_xterm = xterm && iterm_env; + bool screen_host_rxvt = + terminfo_is_term_family(screen && term[6] == '.' ? term + 7 : NULL, "rxvt"); const char *xterm_version = os_getenv("XTERM_VERSION"); bool true_xterm = xterm && !!xterm_version && !bsdvt; @@ -1895,8 +1965,8 @@ static void augment_terminfo(TUIData *data, const char *term, // all panes, which is not particularly desirable. A better approach // would use a tmux control sequence and an extra if(screen) test. data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str( - ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\")); - } else if ((xterm || rxvt || alacritty) + ut, NULL, SCREEN_TMUX_WRAP(screen, tmux, "\033]Pl%p1%06x\033\\")); + } else if ((xterm || rxvt || tmux || alacritty) && (vte_version == 0 || vte_version >= 3900)) { // Supported in urxvt, newer VTE. data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str( @@ -1915,21 +1985,27 @@ static void augment_terminfo(TUIData *data, const char *term, /// Terminals usually ignore unrecognized private modes, and there is no /// known ambiguity with these. So we just set them unconditionally. + /// If the DECSET is not supported by GNU Screen, it is wrapped with DCS and + /// sent to the host terminal. data->unibi_ext.enable_lr_margin = (int)unibi_add_ext_str( ut, "ext.enable_lr_margin", "\x1b[?69h"); data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str( ut, "ext.disable_lr_margin", "\x1b[?69l"); data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str( - ut, "ext.enable_bpaste", "\x1b[?2004h"); + ut, "ext.enable_bpaste", SCREEN_WRAP(screen, "\x1b[?2004h")); data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str( - ut, "ext.disable_bpaste", "\x1b[?2004l"); + ut, "ext.disable_bpaste", SCREEN_WRAP(screen, "\x1b[?2004l")); // For urxvt send BOTH xterm and old urxvt sequences. #8695 data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str( ut, "ext.enable_focus", - rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h"); + (rxvt || screen_host_rxvt) + ? SCREEN_WRAP(screen, "\x1b[?1004h\x1b]777;focus;on\x7") + : SCREEN_WRAP(screen, "\x1b[?1004h")); data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str( ut, "ext.disable_focus", - rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l"); + (rxvt || screen_host_rxvt) + ? SCREEN_WRAP(screen, "\x1b[?1004l\x1b]777;focus;off\x7") + : SCREEN_WRAP(screen, "\x1b[?1004l")); data->unibi_ext.enable_mouse = (int)unibi_add_ext_str( ut, "ext.enable_mouse", "\x1b[?1002h\x1b[?1006h"); data->unibi_ext.disable_mouse = (int)unibi_add_ext_str( @@ -1961,7 +2037,23 @@ static void flush_buf(UI *ui) uv_buf_t *bufp = &bufs[0]; TUIData *data = ui->data; - if (data->bufpos <= 0 && data->busy == data->is_invisible) { + // The content of the output for each condition is shown in the following + // table. Therefore, if data->bufpos == 0 and N/A or invis + norm, there is + // no need to output it. + // + // | is_invisible | !is_invisible + // ------+-----------------+--------------+--------------- + // busy | want_invisible | N/A | invis + // | !want_invisible | N/A | invis + // ------+-----------------+--------------+--------------- + // !busy | want_invisible | N/A | invis + // | !want_invisible | norm | invis + norm + // ------+-----------------+--------------+--------------- + // + if (data->bufpos <= 0 + && ((data->is_invisible && data->busy) + || (data->is_invisible && !data->busy && data->want_invisible) + || (!data->is_invisible && !data->busy && !data->want_invisible))) { return; } @@ -1988,8 +2080,8 @@ static void flush_buf(UI *ui) bufp->base = data->norm; bufp->len = UV_BUF_LEN(data->normlen); bufp++; + data->is_invisible = false; } - data->is_invisible = false; } uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle), diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 0f841760d6..3a5aa95ad3 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -424,7 +424,7 @@ int ui_current_col(void) void ui_flush(void) { cmdline_ui_flush(); - win_ui_flush_positions(); + win_ui_flush(); msg_ext_ui_flush(); msg_scroll_flush(); diff --git a/src/nvim/version.c b/src/nvim/version.c index c67fd9175f..15a9713c7c 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -129,13 +129,13 @@ static const int included_patches[] = { 1792, 1791, 1790, - // 1789, + 1789, 1788, 1787, 1786, 1785, 1784, - // 1783, + 1783, 1782, 1781, 1780, @@ -258,7 +258,7 @@ static const int included_patches[] = { 1663, 1662, 1661, - // 1660, + 1660, 1659, 1658, 1657, @@ -331,7 +331,7 @@ static const int included_patches[] = { 1590, // 1589, // 1588, - // 1587, + 1587, 1586, 1585, 1584, @@ -398,7 +398,7 @@ static const int included_patches[] = { 1523, 1522, 1521, - // 1520, + 1520, 1519, 1518, 1517, @@ -496,7 +496,7 @@ static const int included_patches[] = { 1425, 1424, 1423, - // 1422, + 1422, 1421, 1420, 1419, @@ -530,7 +530,7 @@ static const int included_patches[] = { 1391, 1390, 1389, - // 1388, + 1388, 1387, 1386, 1385, @@ -547,7 +547,7 @@ static const int included_patches[] = { 1374, 1373, 1372, - // 1371, + 1371, 1370, 1369, 1368, @@ -560,11 +560,11 @@ static const int included_patches[] = { 1361, 1360, 1359, - // 1358, + 1358, 1357, 1356, - // 1355, - // 1354, + 1355, + 1354, 1353, 1352, 1351, @@ -573,7 +573,7 @@ static const int included_patches[] = { 1348, 1347, 1346, - // 1345, + 1345, 1344, 1343, 1342, @@ -631,7 +631,7 @@ static const int included_patches[] = { 1290, 1289, 1288, - // 1287, + 1287, 1286, 1285, 1284, @@ -789,7 +789,7 @@ static const int included_patches[] = { 1132, 1131, 1130, - // 1129, + 1129, 1128, 1127, 1126, diff --git a/src/nvim/viml/parser/expressions.h b/src/nvim/viml/parser/expressions.h index 23e172da75..838a742271 100644 --- a/src/nvim/viml/parser/expressions.h +++ b/src/nvim/viml/parser/expressions.h @@ -326,7 +326,7 @@ struct expr_ast_node { } data; }; -enum { +enum ExprParserFlags { /// Allow multiple expressions in a row: e.g. for :echo /// /// Parser will still parse only one of them though. @@ -345,7 +345,7 @@ enum { // viml_expressions_parser.c, nvim_parse_expression() flags parsing // alongside with its documentation and flag sets in check_parsing() // function in expressions parser functional and unit tests. -} ExprParserFlags; +}; /// AST error definition typedef struct { diff --git a/src/nvim/window.c b/src/nvim/window.c index 8181883426..a89715ff79 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -618,7 +618,6 @@ void win_set_minimal_style(win_T *wp) wp->w_p_cuc = false; wp->w_p_spell = false; wp->w_p_list = false; - wp->w_p_fdc = 0; // Hide EOB region: use " " fillchar and cleared highlighting if (wp->w_p_fcs_chars.eob != ' ') { @@ -642,6 +641,12 @@ void win_set_minimal_style(win_T *wp) wp->w_p_scl = (char_u *)xstrdup("auto"); } + // foldcolumn: use 'auto' + if (wp->w_p_fdc[0] != '0') { + xfree(wp->w_p_fdc); + wp->w_p_fdc = (char_u *)xstrdup("0"); + } + // colorcolumn: cleared if (wp->w_p_cc != NULL && *wp->w_p_cc != NUL) { xfree(wp->w_p_cc); @@ -689,6 +694,21 @@ void win_check_anchored_floats(win_T *win) } } +/// Return the number of fold columns to display +int win_fdccol_count(win_T *wp) +{ + const char *fdc = (const char *)wp->w_p_fdc; + + // auto:<NUM> + if (strncmp(fdc, "auto:", 5) == 0) { + int needed_fdccols = getDeepestNesting(wp); + return MIN(fdc[5] - '0', needed_fdccols); + } else { + return fdc[0] - '0'; + } +} + + static void ui_ext_win_position(win_T *wp) { if (!wp->w_floating) { @@ -753,6 +773,21 @@ static void ui_ext_win_position(win_T *wp) } +void ui_ext_win_viewport(win_T *wp) +{ + if ((wp == curwin || ui_has(kUIMultigrid)) && wp->w_viewport_invalid) { + int botline = wp->w_botline; + if (botline == wp->w_buffer->b_ml.ml_line_count+1 + && wp->w_empty_rows == 0) { + // TODO(bfredl): The might be more cases to consider, like how does this + // interact with incomplete final line? Diff filler lines? + botline = wp->w_buffer->b_ml.ml_line_count; + } + ui_call_win_viewport(wp->w_grid.handle, wp->handle, wp->w_topline-1, + botline, wp->w_cursor.lnum-1, wp->w_cursor.col); + wp->w_viewport_invalid = false; + } +} static bool parse_float_anchor(String anchor, FloatAnchor *out) { @@ -4668,6 +4703,11 @@ static win_T *win_alloc(win_T *after, int hidden) new_wp->w_scbind_pos = 1; new_wp->w_floating = 0; new_wp->w_float_config = FLOAT_CONFIG_INIT; + new_wp->w_viewport_invalid = true; + + // use global option for global-local options + new_wp->w_p_so = -1; + new_wp->w_p_siso = -1; /* We won't calculate w_fraction until resizing the window */ new_wp->w_fraction = 0; @@ -5779,9 +5819,10 @@ void scroll_to_fraction(win_T *wp, int prev_height) } if (wp == curwin) { - if (p_so) + if (get_scrolloff_value()) { update_topline(); - curs_columns(FALSE); /* validate w_wrow */ + } + curs_columns(false); // validate w_wrow } if (prev_height > 0) { wp->w_prev_fraction_row = wp->w_wrow; @@ -6503,10 +6544,12 @@ void restore_buffer(bufref_T *save_curbuf) /// @param[in] id a desired ID 'id' can be specified /// (greater than or equal to 1). -1 must be specified if no /// particular ID is desired +/// @param[in] conceal_char pointer to conceal replacement char /// @return ID of added match, -1 on failure. int match_add(win_T *wp, const char *const grp, const char *const pat, int prio, int id, list_T *pos_list, const char *const conceal_char) + FUNC_ATTR_NONNULL_ARG(1, 2) { matchitem_T *cur; matchitem_T *prev; @@ -6543,7 +6586,7 @@ int match_add(win_T *wp, const char *const grp, const char *const pat, return -1; } - /* Find available match ID. */ + // Find available match ID. while (id == -1) { cur = wp->w_match_head; while (cur != NULL && cur->id != wp->w_next_match_id) @@ -6553,7 +6596,7 @@ int match_add(win_T *wp, const char *const grp, const char *const pat, wp->w_next_match_id++; } - /* Build new match. */ + // Build new match. m = xcalloc(1, sizeof(matchitem_T)); m->id = id; m->priority = prio; @@ -6661,9 +6704,9 @@ int match_add(win_T *wp, const char *const grp, const char *const pat, rtype = VALID; } } - - /* Insert new match. The match list is in ascending order with regard to - * the match priorities. */ + + // Insert new match. The match list is in ascending order with regard to + // the match priorities. cur = wp->w_match_head; prev = cur; while (cur != NULL && prio >= cur->priority) { @@ -6967,7 +7010,7 @@ void get_framelayout(const frame_T *fr, list_T *l, bool outer) } } -void win_ui_flush_positions(void) +void win_ui_flush(void) { FOR_ALL_TAB_WINDOWS(tp, wp) { if (wp->w_pos_changed && wp->w_grid.chars != NULL) { @@ -6978,6 +7021,9 @@ void win_ui_flush_positions(void) } wp->w_pos_changed = false; } + if (tp == curtab) { + ui_ext_win_viewport(wp); + } } } diff --git a/src/nvim/xdiff/xdiff.h b/src/nvim/xdiff/xdiff.h index bc26fb64fd..8ff4a05bfb 100644 --- a/src/nvim/xdiff/xdiff.h +++ b/src/nvim/xdiff/xdiff.h @@ -25,9 +25,9 @@ #ifdef __cplusplus extern "C" { -#endif /* #ifdef __cplusplus */ +#endif // #ifdef __cplusplus -/* xpparm_t.flags */ +// xpparm_t.flags #define XDF_NEED_MINIMAL (1 << 0) #define XDF_IGNORE_WHITESPACE (1 << 1) @@ -48,22 +48,22 @@ extern "C" { #define XDF_INDENT_HEURISTIC (1 << 23) -/* xdemitconf_t.flags */ +// xdemitconf_t.flags #define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_FUNCCONTEXT (1 << 2) -/* merge simplification levels */ +// merge simplification levels #define XDL_MERGE_MINIMAL 0 #define XDL_MERGE_EAGER 1 #define XDL_MERGE_ZEALOUS 2 #define XDL_MERGE_ZEALOUS_ALNUM 3 -/* merge favor modes */ +// merge favor modes #define XDL_MERGE_FAVOR_OURS 1 #define XDL_MERGE_FAVOR_THEIRS 2 #define XDL_MERGE_FAVOR_UNION 3 -/* merge output styles */ +// merge output styles #define XDL_MERGE_DIFF3 1 typedef struct s_mmfile { @@ -79,7 +79,7 @@ typedef struct s_mmbuffer { typedef struct s_xpparam { unsigned long flags; - /* See Documentation/diff-options.txt. */ + // See Documentation/diff-options.txt. char **anchors; size_t anchors_nr; } xpparam_t; @@ -126,9 +126,9 @@ typedef struct s_xmparam { int level; int favor; int style; - const char *ancestor; /* label for orig */ - const char *file1; /* label for mf1 */ - const char *file2; /* label for mf2 */ + const char *ancestor; // label for orig + const char *file1; // label for mf1 + const char *file2; // label for mf2 } xmparam_t; #define DEFAULT_CONFLICT_MARKER_SIZE 7 @@ -138,6 +138,6 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, mmfile_t *mf2, #ifdef __cplusplus } -#endif /* #ifdef __cplusplus */ +#endif // #ifdef __cplusplus -#endif /* #if !defined(XDIFF_H) */ +#endif // #if !defined(XDIFF_H) diff --git a/src/nvim/xdiff/xdiffi.c b/src/nvim/xdiff/xdiffi.c index 96d5277027..3806903986 100644 --- a/src/nvim/xdiff/xdiffi.c +++ b/src/nvim/xdiff/xdiffi.c @@ -418,24 +418,24 @@ static int xget_indent(xrecord_t *rec) ret += 1; else if (c == '\t') ret += 8 - ret % 8; - /* ignore other whitespace characters */ + // ignore other whitespace characters if (ret >= MAX_INDENT) return MAX_INDENT; } - /* The line contains only whitespace. */ + // The line contains only whitespace. return -1; } /* - * If more than this number of consecutive blank rows are found, just return this - * value. This avoids requiring O(N^2) work for pathological cases, and also - * ensures that the output of score_split fits in an int. + * If more than this number of consecutive blank rows are found, just return + * this value. This avoids requiring O(N^2) work for pathological cases, and + * also ensures that the output of score_split fits in an int. */ #define MAX_BLANKS 20 -/* Characteristics measured about a hypothetical split position. */ +// Characteristics measured about a hypothetical split position. struct split_measurement { /* * Is the split at the end of the file (aside from any blank lines)? @@ -472,10 +472,10 @@ struct split_measurement { }; struct split_score { - /* The effective indent of this split (smaller is preferred). */ + // The effective indent of this split (smaller is preferred). int effective_indent; - /* Penalty for this split (smaller is preferred). */ + // Penalty for this split (smaller is preferred). int penalty; }; @@ -534,16 +534,16 @@ static void measure_split(const xdfile_t *xdf, long split, * integer math. */ -/* Penalty if there are no non-blank lines before the split */ +// Penalty if there are no non-blank lines before the split #define START_OF_FILE_PENALTY 1 -/* Penalty if there are no non-blank lines after the split */ +// Penalty if there are no non-blank lines after the split #define END_OF_FILE_PENALTY 21 -/* Multiplier for the number of blank lines around the split */ +// Multiplier for the number of blank lines around the split #define TOTAL_BLANK_WEIGHT (-30) -/* Multiplier for the number of blank lines after the split */ +// Multiplier for the number of blank lines after the split #define POST_BLANK_WEIGHT 6 /* @@ -610,7 +610,7 @@ static void score_add_split(const struct split_measurement *m, struct split_scor post_blank = (m->indent == -1) ? 1 + m->post_blank : 0; total_blank = m->pre_blank + post_blank; - /* Penalties based on nearby blank lines: */ + // Penalties based on nearby blank lines: s->penalty += TOTAL_BLANK_WEIGHT * total_blank; s->penalty += POST_BLANK_WEIGHT * post_blank; @@ -621,13 +621,13 @@ static void score_add_split(const struct split_measurement *m, struct split_scor any_blanks = (total_blank != 0); - /* Note that the effective indent is -1 at the end of the file: */ + // Note that the effective indent is -1 at the end of the file: s->effective_indent += indent; if (indent == -1) { - /* No additional adjustments needed. */ + // No additional adjustments needed. } else if (m->pre_indent == -1) { - /* No additional adjustments needed. */ + // No additional adjustments needed. } else if (indent > m->pre_indent) { /* * The line is indented more than its predecessor. @@ -669,7 +669,7 @@ static void score_add_split(const struct split_measurement *m, struct split_scor static int score_cmp(struct split_score *s1, struct split_score *s2) { - /* -1 if s1.effective_indent < s2->effective_indent, etc. */ + // -1 if s1.effective_indent < s2->effective_indent, etc. int cmp_indents = ((s1->effective_indent > s2->effective_indent) - (s1->effective_indent < s2->effective_indent)); @@ -809,7 +809,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { group_init(xdfo, &go); while (1) { - /* If the group is empty in the to-be-compacted file, skip it: */ + // If the group is empty in the to-be-compacted file, skip it: if (g.end == g.start) goto next; @@ -828,7 +828,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { */ end_matching_other = -1; - /* Shift the group backward as much as possible: */ + // Shift the group backward as much as possible: while (!group_slide_up(xdf, &g, flags)) if (group_previous(xdfo, &go)) xdl_bug("group sync broken sliding up"); @@ -842,7 +842,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { if (go.end > go.start) end_matching_other = g.end; - /* Now shift the group forward as far as possible: */ + // Now shift the group forward as far as possible: while (1) { if (group_slide_down(xdf, &g, flags)) break; @@ -863,7 +863,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { */ if (g.end == earliest_end) { - /* no shifting was possible */ + // no shifting was possible } else if (end_matching_other != -1) { /* * Move the possibly merged group of changes back to line @@ -921,7 +921,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { } next: - /* Move past the just-processed group: */ + // Move past the just-processed group: if (group_next(xdf, &g)) break; if (group_next(xdfo, &go)) diff --git a/src/nvim/xdiff/xdiffi.h b/src/nvim/xdiff/xdiffi.h index 8f1c7c8b04..467a1e85cd 100644 --- a/src/nvim/xdiff/xdiffi.h +++ b/src/nvim/xdiff/xdiffi.h @@ -61,4 +61,4 @@ int xdl_do_patience_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, int xdl_do_histogram_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdfenv_t *env); -#endif /* #if !defined(XDIFFI_H) */ +#endif // #if !defined(XDIFFI_H) diff --git a/src/nvim/xdiff/xemit.c b/src/nvim/xdiff/xemit.c index d8a6f1ed38..f1a45139cc 100644 --- a/src/nvim/xdiff/xemit.c +++ b/src/nvim/xdiff/xemit.c @@ -54,9 +54,9 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) xdchange_t *xch, *xchp, *lxch; long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen; long max_ignorable = xecfg->ctxlen; - unsigned long ignored = 0; /* number of ignored blank lines */ + unsigned long ignored = 0; // number of ignored blank lines - /* remove ignorable changes that are too far before other changes */ + // remove ignorable changes that are too far before other changes for (xchp = *xscr; xchp && xchp->ignore; xchp = xchp->next) { xch = xchp->next; @@ -99,9 +99,9 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) static long def_ff(const char *rec, long len, char *buf, long sz, void *priv UNUSED) { if (len > 0 && - (isalpha((unsigned char)*rec) || /* identifier? */ - *rec == '_' || /* also identifier? */ - *rec == '$')) { /* identifiers from VMS and other esoterico */ + (isalpha((unsigned char)*rec) || // identifier? + *rec == '_' || // also identifier? + *rec == '$')) { // identifiers from VMS and other esoterico if (len > sz) len = sz; while (0 < len && isspace((unsigned char)rec[len - 1])) @@ -197,7 +197,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, if (xecfg->flags & XDL_EMIT_FUNCCONTEXT) { long fs1, i1 = xch->i1; - /* Appended chunk? */ + // Appended chunk? if (i1 >= xe->xdf1.nrec) { long i2 = xch->i2; diff --git a/src/nvim/xdiff/xemit.h b/src/nvim/xdiff/xemit.h index 1b9887e670..3ce7e3dd50 100644 --- a/src/nvim/xdiff/xemit.h +++ b/src/nvim/xdiff/xemit.h @@ -33,4 +33,4 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, -#endif /* #if !defined(XEMIT_H) */ +#endif // #if !defined(XEMIT_H) diff --git a/src/nvim/xdiff/xhistogram.c b/src/nvim/xdiff/xhistogram.c index 3fb8974dd4..28cf8258e5 100644 --- a/src/nvim/xdiff/xhistogram.c +++ b/src/nvim/xdiff/xhistogram.c @@ -55,8 +55,8 @@ struct histindex { struct record { unsigned int ptr, cnt; struct record *next; - } **records, /* an occurrence */ - **line_map; /* map of line to record chain */ + } **records, // an occurrence + **line_map; // map of line to record chain chastore_t rcha; unsigned int *next_ptrs; unsigned int table_bits, @@ -128,7 +128,7 @@ static int scanA(struct histindex *index, int line1, int count1) */ NEXT_PTR(index, ptr) = rec->ptr; rec->ptr = ptr; - /* cap rec->cnt at MAX_CNT */ + // cap rec->cnt at MAX_CNT rec->cnt = XDL_MIN(MAX_CNT, rec->cnt + 1); LINE_MAP(index, ptr) = rec; goto continue_scan; @@ -154,7 +154,7 @@ static int scanA(struct histindex *index, int line1, int count1) LINE_MAP(index, ptr) = rec; continue_scan: - ; /* no op */ + ; // no op } return 0; @@ -266,7 +266,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env, index.records = NULL; index.line_map = NULL; - /* in case of early xdl_cha_free() */ + // in case of early xdl_cha_free() index.rcha.head = NULL; index.table_bits = xdl_hashbits(count1); @@ -288,7 +288,7 @@ static int find_lcs(xpparam_t const *xpp, xdfenv_t *env, goto cleanup; memset(index.next_ptrs, 0, sz); - /* lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() */ + // lines / 4 + 1 comes from xprepare.c:xdl_prepare_ctx() if (xdl_cha_init(&index.rcha, sizeof(struct record), count1 / 4 + 1) < 0) goto cleanup; diff --git a/src/nvim/xdiff/xinclude.h b/src/nvim/xdiff/xinclude.h index 46b8608314..5a359d1431 100644 --- a/src/nvim/xdiff/xinclude.h +++ b/src/nvim/xdiff/xinclude.h @@ -20,13 +20,13 @@ * */ -/* defines HAVE_ATTRIBUTE_UNUSED */ +// defines HAVE_ATTRIBUTE_UNUSED #ifdef HAVE_CONFIG_H # include "../auto/config.h" #endif -/* Mark unused function arguments with UNUSED, so that gcc -Wunused-parameter - * can be used to check for mistakes. */ +// Mark unused function arguments with UNUSED, so that gcc -Wunused-parameter +// can be used to check for mistakes. #ifdef HAVE_ATTRIBUTE_UNUSED # define UNUSED __attribute__((unused)) #else @@ -58,4 +58,4 @@ #include "xemit.h" -#endif /* #if !defined(XINCLUDE_H) */ +#endif // #if !defined(XINCLUDE_H) diff --git a/src/nvim/xdiff/xmacros.h b/src/nvim/xdiff/xmacros.h index 2809a28ca9..1167ebbb05 100644 --- a/src/nvim/xdiff/xmacros.h +++ b/src/nvim/xdiff/xmacros.h @@ -51,4 +51,4 @@ do { \ } while (0) -#endif /* #if !defined(XMACROS_H) */ +#endif // #if !defined(XMACROS_H) diff --git a/src/nvim/xdiff/xpatience.c b/src/nvim/xdiff/xpatience.c index 2c65aac386..f6c84c67d8 100644 --- a/src/nvim/xdiff/xpatience.c +++ b/src/nvim/xdiff/xpatience.c @@ -69,7 +69,7 @@ struct hashmap { */ unsigned anchor : 1; } *entries, *first, *last; - /* were common records found? */ + // were common records found? unsigned long has_matches; mmfile_t *file1, *file2; xdfenv_t *env; @@ -86,7 +86,7 @@ static int is_anchor(xpparam_t const *xpp, const char *line) return 0; } -/* The argument "pass" is 1 for the first file, 2 for the second. */ +// The argument "pass" is 1 for the first file, 2 for the second. static void insert_record(xpparam_t const *xpp, int line, struct hashmap *map, int pass) { @@ -155,7 +155,7 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2, result->xpp = xpp; result->env = env; - /* We know exactly how large we want the hash map */ + // We know exactly how large we want the hash map result->alloc = count1 * 2; result->entries = (struct entry *) xdl_malloc(result->alloc * sizeof(struct entry)); @@ -163,11 +163,11 @@ static int fill_hashmap(mmfile_t *file1, mmfile_t *file2, return -1; memset(result->entries, 0, result->alloc * sizeof(struct entry)); - /* First, fill with entries from the first file */ + // First, fill with entries from the first file while (count1--) insert_record(xpp, line1++, result, 1); - /* Then search for matches in the second file */ + // Then search for matches in the second file while (count2--) insert_record(xpp, line2++, result, 2); @@ -185,13 +185,13 @@ static int binary_search(struct entry **sequence, int longest, while (left + 1 < right) { int middle = left + (right - left) / 2; - /* by construction, no two entries can be equal */ + // by construction, no two entries can be equal if (sequence[middle]->line2 > entry->line2) right = middle; else left = middle; } - /* return the index in "sequence", _not_ the sequence length */ + // return the index in "sequence", _not_ the sequence length return left; } @@ -216,7 +216,7 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) */ int anchor_i = -1; - /* Added to silence Coverity. */ + // Added to silence Coverity. if (sequence == NULL) return map->first; @@ -237,13 +237,13 @@ static struct entry *find_longest_common_sequence(struct hashmap *map) } } - /* No common unique lines were found */ + // No common unique lines were found if (!longest) { xdl_free(sequence); return NULL; } - /* Iterate starting at the last element, adjusting the "next" members */ + // Iterate starting at the last element, adjusting the "next" members entry = sequence[longest - 1]; entry->next = NULL; while (entry->previous) { @@ -273,7 +273,7 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first, int next1, next2; for (;;) { - /* Try to grow the line ranges of common lines */ + // Try to grow the line ranges of common lines if (first) { next1 = first->line1; next2 = first->line2; @@ -292,7 +292,7 @@ static int walk_common_sequence(struct hashmap *map, struct entry *first, line2++; } - /* Recurse */ + // Recurse if (next1 > line1 || next2 > line2) { struct hashmap submap; @@ -343,7 +343,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2, struct entry *first; int result = 0; - /* trivial case: one side is empty */ + // trivial case: one side is empty if (!count1) { while(count2--) env->xdf2.rchg[line2++ - 1] = 1; @@ -359,7 +359,7 @@ static int patience_diff(mmfile_t *file1, mmfile_t *file2, line1, count1, line2, count2)) return -1; - /* are there any matching lines at all? */ + // are there any matching lines at all? if (!map.has_matches) { while(count1--) env->xdf1.rchg[line1++ - 1] = 1; @@ -387,7 +387,7 @@ int xdl_do_patience_diff(mmfile_t *file1, mmfile_t *file2, if (xdl_prepare_env(file1, file2, xpp, env) < 0) return -1; - /* environment is cleaned up in xdl_diff() */ + // environment is cleaned up in xdl_diff() return patience_diff(file1, file2, xpp, env, 1, env->xdf1.nrec, 1, env->xdf2.nrec); } diff --git a/src/nvim/xdiff/xprepare.h b/src/nvim/xdiff/xprepare.h index 947d9fc1bb..b67b3b25ab 100644 --- a/src/nvim/xdiff/xprepare.h +++ b/src/nvim/xdiff/xprepare.h @@ -31,4 +31,4 @@ void xdl_free_env(xdfenv_t *xe); -#endif /* #if !defined(XPREPARE_H) */ +#endif // #if !defined(XPREPARE_H) diff --git a/src/nvim/xdiff/xtypes.h b/src/nvim/xdiff/xtypes.h index 8442bd436e..026999c1bf 100644 --- a/src/nvim/xdiff/xtypes.h +++ b/src/nvim/xdiff/xtypes.h @@ -64,4 +64,4 @@ typedef struct s_xdfenv { -#endif /* #if !defined(XTYPES_H) */ +#endif // #if !defined(XTYPES_H) diff --git a/src/nvim/xdiff/xutils.c b/src/nvim/xdiff/xutils.c index 25a090fb73..e8c7d2f884 100644 --- a/src/nvim/xdiff/xutils.c +++ b/src/nvim/xdiff/xutils.c @@ -168,7 +168,7 @@ static int ends_with_optional_cr(const char *l, long s, long i) s--; if (s == i) return 1; - /* do not ignore CR at the end of an incomplete line */ + // do not ignore CR at the end of an incomplete line if (complete && s == i + 1 && l[i] == '\r') return 1; return 0; @@ -208,7 +208,7 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) { while (i1 < s1 && i2 < s2) { if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) { - /* Skip matching spaces and try again */ + // Skip matching spaces and try again while (i1 < s1 && XDL_ISSPACE(l1[i1])) i1++; while (i2 < s2 && XDL_ISSPACE(l2[i2])) @@ -224,7 +224,7 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) i2++; } } else if (flags & XDF_IGNORE_CR_AT_EOL) { - /* Find the first difference and see how the line ends */ + // Find the first difference and see how the line ends while (i1 < s1 && i2 < s2 && l1[i1] == l2[i2]) { i1++; i2++; @@ -261,7 +261,7 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data, for (; ptr < top && *ptr != '\n'; ptr++) { if (cr_at_eol_only) { - /* do not ignore CR at the end of an incomplete line */ + // do not ignore CR at the end of an incomplete line if (*ptr == '\r' && (ptr + 1 < top && ptr[1] == '\n')) continue; @@ -274,7 +274,7 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data, ptr++; at_eol = (top <= ptr + 1 || ptr[1] == '\n'); if (flags & XDF_IGNORE_WHITESPACE) - ; /* already handled */ + ; // already handled else if (flags & XDF_IGNORE_WHITESPACE_CHANGE && !at_eol) { ha += (ha << 5); diff --git a/src/nvim/xdiff/xutils.h b/src/nvim/xdiff/xutils.h index fba7bae03c..0bebd93022 100644 --- a/src/nvim/xdiff/xutils.h +++ b/src/nvim/xdiff/xutils.h @@ -44,4 +44,4 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp, -#endif /* #if !defined(XUTILS_H) */ +#endif // #if !defined(XUTILS_H) diff --git a/src/tree_sitter/api.h b/src/tree_sitter/api.h index 40187e3db0..9d832e6ec4 100644 --- a/src/tree_sitter/api.h +++ b/src/tree_sitter/api.h @@ -174,8 +174,19 @@ const TSLanguage *ts_parser_language(const TSParser *self); * The second and third parameters specify the location and length of an array * of ranges. The parser does *not* take ownership of these ranges; it copies * the data, so it doesn't matter how these ranges are allocated. + * + * If `length` is zero, then the entire document will be parsed. Otherwise, + * the given ranges must be ordered from earliest to latest in the document, + * and they must not overlap. That is, the following must hold for all + * `i` < `length - 1`: + * + * ranges[i].end_byte <= ranges[i + 1].start_byte + * + * If this requirement is not satisfied, the operation will fail, the ranges + * will not be assigned, and this function will return `false`. On success, + * this function returns `true` */ -void ts_parser_set_included_ranges( +bool ts_parser_set_included_ranges( TSParser *self, const TSRange *ranges, uint32_t length @@ -325,14 +336,6 @@ TSLogger ts_parser_logger(const TSParser *self); */ void ts_parser_print_dot_graphs(TSParser *self, int file); -/** - * Set whether or not the parser should halt immediately upon detecting an - * error. This will generally result in a syntax tree with an error at the - * root, and one or more partial syntax trees within the error. This behavior - * may not be supported long-term. - */ -void ts_parser_halt_on_error(TSParser *self, bool halt); - /******************/ /* Section - Tree */ /******************/ @@ -732,13 +735,23 @@ const char *ts_query_string_value_for_id( ); /** - * Disable a certain capture within a query. This prevents the capture - * from being returned in matches, and also avoids any resource usage - * associated with recording the capture. + * Disable a certain capture within a query. + * + * This prevents the capture from being returned in matches, and also avoids + * any resource usage associated with recording the capture. Currently, there + * is no way to undo this. */ void ts_query_disable_capture(TSQuery *, const char *, uint32_t); /** + * Disable a certain pattern within a query. + * + * This prevents the pattern from matching and removes most of the overhead + * associated with the pattern. Currently, there is no way to undo this. + */ +void ts_query_disable_pattern(TSQuery *, uint32_t); + +/** * Create a new cursor for executing a given query. * * The cursor stores the state that is needed to iteratively search diff --git a/src/tree_sitter/array.h b/src/tree_sitter/array.h index bc77e687bf..26cb8448f1 100644 --- a/src/tree_sitter/array.h +++ b/src/tree_sitter/array.h @@ -126,12 +126,28 @@ static inline void array__splice(VoidArray *self, size_t element_size, array__reserve(self, element_size, new_size); char *contents = (char *)self->contents; - if (self->size > old_end) - memmove(contents + new_end * element_size, contents + old_end * element_size, - (self->size - old_end) * element_size); - if (new_count > 0) - memcpy((contents + index * element_size), elements, - new_count * element_size); + if (self->size > old_end) { + memmove( + contents + new_end * element_size, + contents + old_end * element_size, + (self->size - old_end) * element_size + ); + } + if (new_count > 0) { + if (elements) { + memcpy( + (contents + index * element_size), + elements, + new_count * element_size + ); + } else { + memset( + (contents + index * element_size), + 0, + new_count * element_size + ); + } + } self->size += new_count - old_count; } diff --git a/src/tree_sitter/atomic.h b/src/tree_sitter/atomic.h index 301ee36700..7bd0e850a9 100644 --- a/src/tree_sitter/atomic.h +++ b/src/tree_sitter/atomic.h @@ -12,11 +12,11 @@ static inline size_t atomic_load(const volatile size_t *p) { } static inline uint32_t atomic_inc(volatile uint32_t *p) { - return InterlockedIncrement(p); + return InterlockedIncrement((long volatile *)p); } static inline uint32_t atomic_dec(volatile uint32_t *p) { - return InterlockedDecrement(p); + return InterlockedDecrement((long volatile *)p); } #else diff --git a/src/tree_sitter/bits.h b/src/tree_sitter/bits.h index 3bec455dd1..ce7a715567 100644 --- a/src/tree_sitter/bits.h +++ b/src/tree_sitter/bits.h @@ -7,7 +7,7 @@ static inline uint32_t bitmask_for_index(uint16_t id) { return (1u << (31 - id)); } -#ifdef _WIN32 +#if defined _WIN32 && !defined __GNUC__ #include <intrin.h> diff --git a/src/tree_sitter/language.c b/src/tree_sitter/language.c index e240ef2a53..a396b4b0b6 100644 --- a/src/tree_sitter/language.c +++ b/src/tree_sitter/language.c @@ -72,8 +72,10 @@ const char *ts_language_symbol_name( return "ERROR"; } else if (symbol == ts_builtin_sym_error_repeat) { return "_ERROR"; - } else { + } else if (symbol < ts_language_symbol_count(self)) { return self->symbol_names[symbol]; + } else { + return NULL; } } @@ -119,7 +121,7 @@ const char *ts_language_field_name_for_id( TSFieldId id ) { uint32_t count = ts_language_field_count(self); - if (count) { + if (count && id <= count) { return self->field_names[id]; } else { return NULL; diff --git a/src/tree_sitter/language.h b/src/tree_sitter/language.h index d7e17c3d70..f908b4593a 100644 --- a/src/tree_sitter/language.h +++ b/src/tree_sitter/language.h @@ -29,10 +29,12 @@ static inline bool ts_language_is_symbol_external(const TSLanguage *self, TSSymb return 0 < symbol && symbol < self->external_token_count + 1; } -static inline const TSParseAction *ts_language_actions(const TSLanguage *self, - TSStateId state, - TSSymbol symbol, - uint32_t *count) { +static inline const TSParseAction *ts_language_actions( + const TSLanguage *self, + TSStateId state, + TSSymbol symbol, + uint32_t *count +) { TableEntry entry; ts_language_table_entry(self, state, symbol, &entry); *count = entry.action_count; @@ -90,8 +92,8 @@ static inline TSStateId ts_language_next_state(const TSLanguage *self, const TSParseAction *actions = ts_language_actions(self, state, symbol, &count); if (count > 0) { TSParseAction action = actions[count - 1]; - if (action.type == TSParseActionTypeShift || action.type == TSParseActionTypeRecover) { - return action.params.state; + if (action.type == TSParseActionTypeShift) { + return action.params.extra ? state : action.params.state; } } return 0; diff --git a/src/tree_sitter/lexer.c b/src/tree_sitter/lexer.c index e2ca851973..3f8a4c0ae8 100644 --- a/src/tree_sitter/lexer.c +++ b/src/tree_sitter/lexer.c @@ -355,7 +355,7 @@ void ts_lexer_mark_end(Lexer *self) { ts_lexer__mark_end(&self->data); } -void ts_lexer_set_included_ranges( +bool ts_lexer_set_included_ranges( Lexer *self, const TSRange *ranges, uint32_t count @@ -363,6 +363,16 @@ void ts_lexer_set_included_ranges( if (count == 0 || !ranges) { ranges = &DEFAULT_RANGE; count = 1; + } else { + uint32_t previous_byte = 0; + for (unsigned i = 0; i < count; i++) { + const TSRange *range = &ranges[i]; + if ( + range->start_byte < previous_byte || + range->end_byte < range->start_byte + ) return false; + previous_byte = range->end_byte; + } } size_t size = count * sizeof(TSRange); @@ -370,6 +380,7 @@ void ts_lexer_set_included_ranges( memcpy(self->included_ranges, ranges, size); self->included_range_count = count; ts_lexer_goto(self, self->current_position); + return true; } TSRange *ts_lexer_included_ranges(const Lexer *self, uint32_t *count) { diff --git a/src/tree_sitter/lexer.h b/src/tree_sitter/lexer.h index 8cd9c26706..5e39294529 100644 --- a/src/tree_sitter/lexer.h +++ b/src/tree_sitter/lexer.h @@ -38,7 +38,7 @@ void ts_lexer_start(Lexer *); void ts_lexer_finish(Lexer *, uint32_t *); void ts_lexer_advance_to_end(Lexer *); void ts_lexer_mark_end(Lexer *); -void ts_lexer_set_included_ranges(Lexer *self, const TSRange *ranges, uint32_t count); +bool ts_lexer_set_included_ranges(Lexer *self, const TSRange *ranges, uint32_t count); TSRange *ts_lexer_included_ranges(const Lexer *self, uint32_t *count); #ifdef __cplusplus diff --git a/src/tree_sitter/node.c b/src/tree_sitter/node.c index b03e2fc979..576f3ef38e 100644 --- a/src/tree_sitter/node.c +++ b/src/tree_sitter/node.c @@ -150,7 +150,9 @@ static inline TSNode ts_node__child( while (ts_node_child_iterator_next(&iterator, &child)) { if (ts_node__is_relevant(child, include_anonymous)) { if (index == child_index) { - ts_tree_set_cached_parent(self.tree, &child, &self); + if (ts_node__is_relevant(self, true)) { + ts_tree_set_cached_parent(self.tree, &child, &self); + } return child; } index++; diff --git a/src/tree_sitter/parser.c b/src/tree_sitter/parser.c index f381afccab..d4b227308b 100644 --- a/src/tree_sitter/parser.c +++ b/src/tree_sitter/parser.c @@ -71,7 +71,6 @@ struct TSParser { unsigned accept_count; unsigned operation_count; const volatile size_t *cancellation_flag; - bool halt_on_error; Subtree old_tree; TSRangeArray included_range_differences; unsigned included_range_difference_index; @@ -325,6 +324,12 @@ static bool ts_parser__can_reuse_first_leaf( TSStateId leaf_state = ts_subtree_leaf_parse_state(tree); TSLexMode leaf_lex_mode = self->language->lex_modes[leaf_state]; + // At the end of a non-terminal extra node, the lexer normally returns + // NULL, which indicates that the parser should look for a reduce action + // at symbol `0`. Avoid reusing tokens in this situation to ensure that + // the same thing happens when incrementally reparsing. + if (current_lex_mode.lex_state == (uint16_t)(-1)) return false; + // If the token was created in a state with the same set of lookaheads, it is reusable. if ( table_entry->action_count > 0 && @@ -594,6 +599,10 @@ static Subtree ts_parser__reuse_node( uint32_t byte_offset = reusable_node_byte_offset(&self->reusable_node); uint32_t end_byte_offset = byte_offset + ts_subtree_total_bytes(result); + // Do not reuse an EOF node if the included ranges array has changes + // later on in the file. + if (ts_subtree_is_eof(result)) end_byte_offset = UINT32_MAX; + if (byte_offset > position) { LOG("before_reusable_node symbol:%s", TREE_NAME(result)); break; @@ -1014,7 +1023,9 @@ static void ts_parser__handle_error( TSStateId state_after_missing_symbol = ts_language_next_state( self->language, state, missing_symbol ); - if (state_after_missing_symbol == 0) continue; + if (state_after_missing_symbol == 0 || state_after_missing_symbol == state) { + continue; + } if (ts_language_has_reduce_action( self->language, @@ -1067,46 +1078,6 @@ static void ts_parser__handle_error( LOG_STACK(); } -static void ts_parser__halt_parse(TSParser *self) { - LOG("halting_parse"); - LOG_STACK(); - - ts_lexer_advance_to_end(&self->lexer); - Length remaining_length = length_sub( - self->lexer.current_position, - ts_stack_position(self->stack, 0) - ); - - Subtree filler_node = ts_subtree_new_error( - &self->tree_pool, - 0, - length_zero(), - remaining_length, - remaining_length.bytes, - 0, - self->language - ); - ts_subtree_to_mut_unsafe(filler_node).ptr->visible = false; - ts_stack_push(self->stack, 0, filler_node, false, 0); - - SubtreeArray children = array_new(); - Subtree root_error = ts_subtree_new_error_node(&self->tree_pool, &children, false, self->language); - ts_stack_push(self->stack, 0, root_error, false, 0); - - Subtree eof = ts_subtree_new_leaf( - &self->tree_pool, - ts_builtin_sym_end, - length_zero(), - length_zero(), - 0, - 0, - false, - false, - self->language - ); - ts_parser__accept(self, 0, eof); -} - static bool ts_parser__recover_to_state( TSParser *self, StackVersion version, @@ -1644,8 +1615,8 @@ static unsigned ts_parser__condense_stack(TSParser *self) { static bool ts_parser_has_outstanding_parse(TSParser *self) { return ( - self->lexer.current_position.bytes > 0 || - ts_stack_state(self->stack, 0) != 1 + ts_stack_state(self->stack, 0) != 1 || + ts_stack_node_count_since_error(self->stack, 0) != 0 ); } @@ -1661,7 +1632,6 @@ TSParser *ts_parser_new(void) { self->finished_tree = NULL_SUBTREE; self->reusable_node = reusable_node_new(); self->dot_graph_file = NULL; - self->halt_on_error = false; self->cancellation_flag = NULL; self->timeout_duration = 0; self->end_clock = clock_null(); @@ -1741,10 +1711,6 @@ void ts_parser_print_dot_graphs(TSParser *self, int fd) { } } -void ts_parser_halt_on_error(TSParser *self, bool should_halt_on_error) { - self->halt_on_error = should_halt_on_error; -} - const size_t *ts_parser_cancellation_flag(const TSParser *self) { return (const size_t *)self->cancellation_flag; } @@ -1761,8 +1727,12 @@ void ts_parser_set_timeout_micros(TSParser *self, uint64_t timeout_micros) { self->timeout_duration = duration_from_micros(timeout_micros); } -void ts_parser_set_included_ranges(TSParser *self, const TSRange *ranges, uint32_t count) { - ts_lexer_set_included_ranges(&self->lexer, ranges, count); +bool ts_parser_set_included_ranges( + TSParser *self, + const TSRange *ranges, + uint32_t count +) { + return ts_lexer_set_included_ranges(&self->lexer, ranges, count); } const TSRange *ts_parser_included_ranges(const TSParser *self, uint32_t *count) { @@ -1858,9 +1828,6 @@ TSTree *ts_parser_parse( unsigned min_error_cost = ts_parser__condense_stack(self); if (self->finished_tree.ptr && ts_subtree_error_cost(self->finished_tree) < min_error_cost) { break; - } else if (self->halt_on_error && min_error_cost > 0) { - ts_parser__halt_parse(self); - break; } while (self->included_range_difference_index < self->included_range_differences.size) { diff --git a/src/tree_sitter/query.c b/src/tree_sitter/query.c index 2563325248..92a8006179 100644 --- a/src/tree_sitter/query.c +++ b/src/tree_sitter/query.c @@ -19,6 +19,8 @@ typedef struct { uint8_t next_size; } Stream; +#define MAX_STEP_CAPTURE_COUNT 4 + /* * QueryStep - A step in the process of matching a query. Each node within * a query S-expression maps to one of these steps. An entire pattern is @@ -33,13 +35,21 @@ typedef struct { * captured in this pattern. * - `depth` - The depth where this node occurs in the pattern. The root node * of the pattern has depth zero. + * - `repeat_step_index` - If this step is part of a repetition, the index of + * the beginning of the repetition. A `NONE` value means this step is not + * part of a repetition. */ typedef struct { TSSymbol symbol; TSFieldId field; - uint16_t capture_id; - uint16_t depth: 15; + uint16_t capture_ids[MAX_STEP_CAPTURE_COUNT]; + uint16_t repeat_step_index; + uint16_t depth: 11; bool contains_captures: 1; + bool is_pattern_start: 1; + bool is_immediate: 1; + bool is_last: 1; + bool is_repeated: 1; } QueryStep; /* @@ -62,10 +72,12 @@ typedef struct { } SymbolTable; /* - * PatternEntry - The set of steps needed to match a particular pattern, - * represented as a slice of a shared array. These entries are stored in a - * 'pattern map' - a sorted array that makes it possible to efficiently lookup - * patterns based on the symbol for their first step. + * PatternEntry - Information about the starting point for matching a + * particular pattern, consisting of the index of the pattern within the query, + * and the index of the patter's first step in the shared `steps` array. These + * entries are stored in a 'pattern map' - a sorted array that makes it + * possible to efficiently lookup patterns based on the symbol for their first + * step. */ typedef struct { uint16_t step_index; @@ -79,23 +91,27 @@ typedef struct { * represented as one of these states. */ typedef struct { + uint32_t id; uint16_t start_depth; uint16_t pattern_index; uint16_t step_index; - uint16_t capture_count; - uint16_t capture_list_id; uint16_t consumed_capture_count; - uint32_t id; + uint16_t repeat_match_count; + uint16_t step_index_on_failure; + uint8_t capture_list_id; + bool seeking_non_match; } QueryState; +typedef Array(TSQueryCapture) CaptureList; + /* * CaptureListPool - A collection of *lists* of captures. Each QueryState - * needs to maintain its own list of captures. They are all represented as - * slices of one shared array. The CaptureListPool keeps track of which - * parts of the shared array are currently in use by a QueryState. + * needs to maintain its own list of captures. To avoid repeated allocations, + * the reuses a fixed set of capture lists, and keeps track of which ones + * are currently in use. */ typedef struct { - Array(TSQueryCapture) list; + CaptureList list[32]; uint32_t usage_map; } CaptureListPool; @@ -113,7 +129,6 @@ struct TSQuery { Array(Slice) predicates_by_pattern; Array(uint32_t) start_bytes_by_pattern; const TSLanguage *language; - uint16_t max_capture_count; uint16_t wildcard_root_pattern_count; TSSymbol *symbol_map; }; @@ -140,6 +155,7 @@ static const TSQueryError PARENT_DONE = -1; static const uint8_t PATTERN_DONE_MARKER = UINT8_MAX; static const uint16_t NONE = UINT16_MAX; static const TSSymbol WILDCARD_SYMBOL = 0; +static const TSSymbol NAMED_WILDCARD_SYMBOL = UINT16_MAX - 1; static const uint16_t MAX_STATE_COUNT = 32; // #define LOG(...) fprintf(stderr, __VA_ARGS__) @@ -226,24 +242,25 @@ static void stream_scan_identifier(Stream *stream) { static CaptureListPool capture_list_pool_new(void) { return (CaptureListPool) { - .list = array_new(), .usage_map = UINT32_MAX, }; } -static void capture_list_pool_reset(CaptureListPool *self, uint16_t list_size) { +static void capture_list_pool_reset(CaptureListPool *self) { self->usage_map = UINT32_MAX; - uint32_t total_size = MAX_STATE_COUNT * list_size; - array_reserve(&self->list, total_size); - self->list.size = total_size; + for (unsigned i = 0; i < 32; i++) { + array_clear(&self->list[i]); + } } static void capture_list_pool_delete(CaptureListPool *self) { - array_delete(&self->list); + for (unsigned i = 0; i < 32; i++) { + array_delete(&self->list[i]); + } } -static TSQueryCapture *capture_list_pool_get(CaptureListPool *self, uint16_t id) { - return &self->list.contents[id * (self->list.size / MAX_STATE_COUNT)]; +static CaptureList *capture_list_pool_get(CaptureListPool *self, uint16_t id) { + return &self->list[id]; } static bool capture_list_pool_is_empty(const CaptureListPool *self) { @@ -262,6 +279,7 @@ static uint16_t capture_list_pool_acquire(CaptureListPool *self) { } static void capture_list_pool_release(CaptureListPool *self, uint16_t id) { + array_clear(&self->list[id]); self->usage_map |= bitmask_for_index(id); } @@ -324,6 +342,114 @@ static uint16_t symbol_table_insert_name( return self->slices.size - 1; } +static uint16_t symbol_table_insert_name_with_escapes( + SymbolTable *self, + const char *escaped_name, + uint32_t escaped_length +) { + Slice slice = { + .offset = self->characters.size, + .length = 0, + }; + array_grow_by(&self->characters, escaped_length + 1); + + // Copy the contents of the literal into the characters buffer, processing escape + // sequences like \n and \". This needs to be done before checking if the literal + // is already present, in order to do the string comparison. + bool is_escaped = false; + for (unsigned i = 0; i < escaped_length; i++) { + const char *src = &escaped_name[i]; + char *dest = &self->characters.contents[slice.offset + slice.length]; + if (is_escaped) { + switch (*src) { + case 'n': + *dest = '\n'; + break; + case 'r': + *dest = '\r'; + break; + case 't': + *dest = '\t'; + break; + case '0': + *dest = '\0'; + break; + default: + *dest = *src; + break; + } + is_escaped = false; + slice.length++; + } else { + if (*src == '\\') { + is_escaped = true; + } else { + *dest = *src; + slice.length++; + } + } + } + + // If the string is already present, remove the redundant content from the characters + // buffer and return the existing id. + int id = symbol_table_id_for_name(self, &self->characters.contents[slice.offset], slice.length); + if (id >= 0) { + self->characters.size -= (escaped_length + 1); + return id; + } + + self->characters.contents[slice.offset + slice.length] = 0; + array_push(&self->slices, slice); + return self->slices.size - 1; +} + +/************ + * QueryStep + ************/ + +static QueryStep query_step__new( + TSSymbol symbol, + uint16_t depth, + bool is_immediate +) { + return (QueryStep) { + .symbol = symbol, + .depth = depth, + .field = 0, + .capture_ids = {NONE, NONE, NONE, NONE}, + .contains_captures = false, + .is_repeated = false, + .is_last = false, + .is_pattern_start = false, + .is_immediate = is_immediate, + .repeat_step_index = NONE, + }; +} + +static void query_step__add_capture(QueryStep *self, uint16_t capture_id) { + for (unsigned i = 0; i < MAX_STEP_CAPTURE_COUNT; i++) { + if (self->capture_ids[i] == NONE) { + self->capture_ids[i] = capture_id; + break; + } + } +} + +static void query_step__remove_capture(QueryStep *self, uint16_t capture_id) { + for (unsigned i = 0; i < MAX_STEP_CAPTURE_COUNT; i++) { + if (self->capture_ids[i] == capture_id) { + self->capture_ids[i] = NONE; + while (i + 1 < MAX_STEP_CAPTURE_COUNT) { + if (self->capture_ids[i + 1] == NONE) break; + self->capture_ids[i] = self->capture_ids[i + 1]; + self->capture_ids[i + 1] = NONE; + i++; + } + break; + } + } +} + /********* * Query *********/ @@ -333,7 +459,7 @@ static uint16_t symbol_table_insert_name( // to quickly find the starting steps of all of the patterns whose root matches // that node. Each entry has two fields: a `pattern_index`, which identifies one // of the patterns in the query, and a `step_index`, which indicates the start -// offset of that pattern's steps pattern within the `steps` array. +// offset of that pattern's steps within the `steps` array. // // The entries are sorted by the patterns' root symbols, and lookups use a // binary search. This ensures that the cost of this initial lookup step @@ -399,14 +525,14 @@ static void ts_query__finalize_steps(TSQuery *self) { for (unsigned i = 0; i < self->steps.size; i++) { QueryStep *step = &self->steps.contents[i]; uint32_t depth = step->depth; - if (step->capture_id != NONE) { + if (step->capture_ids[0] != NONE) { step->contains_captures = true; } else { step->contains_captures = false; for (unsigned j = i + 1; j < self->steps.size; j++) { QueryStep *s = &self->steps.contents[j]; if (s->depth == PATTERN_DONE_MARKER || s->depth <= depth) break; - if (s->capture_id != NONE) step->contains_captures = true; + if (s->capture_ids[0] != NONE) step->contains_captures = true; } } } @@ -473,9 +599,22 @@ static TSQueryError ts_query__parse_predicate( stream_advance(stream); // Parse the string content + bool is_escaped = false; const char *string_content = stream->input; - while (stream->next != '"') { - if (stream->next == '\n' || !stream_advance(stream)) { + for (;;) { + if (is_escaped) { + is_escaped = false; + } else { + if (stream->next == '\\') { + is_escaped = true; + } else if (stream->next == '"') { + break; + } else if (stream->next == '\n') { + stream_reset(stream, string_content - 1); + return TSQueryErrorSyntax; + } + } + if (!stream_advance(stream)) { stream_reset(stream, string_content - 1); return TSQueryErrorSyntax; } @@ -483,7 +622,7 @@ static TSQueryError ts_query__parse_predicate( uint32_t length = stream->input - string_content; // Add a step for the node - uint16_t id = symbol_table_insert_name( + uint16_t id = symbol_table_insert_name_with_escapes( &self->predicate_values, string_content, length @@ -533,7 +672,8 @@ static TSQueryError ts_query__parse_pattern( TSQuery *self, Stream *stream, uint32_t depth, - uint32_t *capture_count + uint32_t *capture_count, + bool is_immediate ) { uint16_t starting_step_index = self->steps.size; @@ -552,7 +692,7 @@ static TSQueryError ts_query__parse_pattern( // Parse a nested list, which represents a pattern followed by // zero-or-more predicates. if (stream->next == '(' && depth == 0) { - TSQueryError e = ts_query__parse_pattern(self, stream, 0, capture_count); + TSQueryError e = ts_query__parse_pattern(self, stream, 0, capture_count, is_immediate); if (e) return e; // Parse the predicates. @@ -573,7 +713,7 @@ static TSQueryError ts_query__parse_pattern( // Parse the wildcard symbol if (stream->next == '*') { - symbol = WILDCARD_SYMBOL; + symbol = depth > 0 ? NAMED_WILDCARD_SYMBOL : WILDCARD_SYMBOL; stream_advance(stream); } @@ -597,24 +737,37 @@ static TSQueryError ts_query__parse_pattern( } // Add a step for the node. - array_push(&self->steps, ((QueryStep) { - .depth = depth, - .symbol = symbol, - .field = 0, - .capture_id = NONE, - .contains_captures = false, - })); + array_push(&self->steps, query_step__new(symbol, depth, is_immediate)); // Parse the child patterns stream_skip_whitespace(stream); + bool child_is_immediate = false; + uint16_t child_start_step_index = self->steps.size; for (;;) { - TSQueryError e = ts_query__parse_pattern(self, stream, depth + 1, capture_count); + if (stream->next == '.') { + child_is_immediate = true; + stream_advance(stream); + stream_skip_whitespace(stream); + } + + TSQueryError e = ts_query__parse_pattern( + self, + stream, + depth + 1, + capture_count, + child_is_immediate + ); if (e == PARENT_DONE) { + if (child_is_immediate) { + self->steps.contents[child_start_step_index].is_last = true; + } stream_advance(stream); break; } else if (e) { return e; } + + child_is_immediate = false; } } @@ -643,13 +796,7 @@ static TSQueryError ts_query__parse_pattern( stream_reset(stream, string_content); return TSQueryErrorNodeType; } - array_push(&self->steps, ((QueryStep) { - .depth = depth, - .symbol = symbol, - .field = 0, - .capture_id = NONE, - .contains_captures = false, - })); + array_push(&self->steps, query_step__new(symbol, depth, is_immediate)); if (stream->next != '"') return TSQueryErrorSyntax; stream_advance(stream); @@ -672,7 +819,13 @@ static TSQueryError ts_query__parse_pattern( // Parse the pattern uint32_t step_index = self->steps.size; - TSQueryError e = ts_query__parse_pattern(self, stream, depth, capture_count); + TSQueryError e = ts_query__parse_pattern( + self, + stream, + depth, + capture_count, + is_immediate + ); if (e == PARENT_DONE) return TSQueryErrorSyntax; if (e) return e; @@ -695,12 +848,7 @@ static TSQueryError ts_query__parse_pattern( stream_skip_whitespace(stream); // Add a step that matches any kind of node - array_push(&self->steps, ((QueryStep) { - .depth = depth, - .symbol = WILDCARD_SYMBOL, - .field = 0, - .contains_captures = false, - })); + array_push(&self->steps, query_step__new(WILDCARD_SYMBOL, depth, is_immediate)); } else { @@ -709,26 +857,43 @@ static TSQueryError ts_query__parse_pattern( stream_skip_whitespace(stream); - // Parse an '@'-prefixed capture pattern - if (stream->next == '@') { - stream_advance(stream); + // Parse suffixes modifiers for this pattern + for (;;) { + QueryStep *step = &self->steps.contents[starting_step_index]; - // Parse the capture name - if (!stream_is_ident_start(stream)) return TSQueryErrorSyntax; - const char *capture_name = stream->input; - stream_scan_identifier(stream); - uint32_t length = stream->input - capture_name; + if (stream->next == '+') { + stream_advance(stream); + step->is_repeated = true; + array_back(&self->steps)->repeat_step_index = starting_step_index; + stream_skip_whitespace(stream); + } - // Add the capture id to the first step of the pattern - uint16_t capture_id = symbol_table_insert_name( - &self->captures, - capture_name, - length - ); - self->steps.contents[starting_step_index].capture_id = capture_id; - (*capture_count)++; + // Parse an '@'-prefixed capture pattern + else if (stream->next == '@') { + stream_advance(stream); - stream_skip_whitespace(stream); + // Parse the capture name + if (!stream_is_ident_start(stream)) return TSQueryErrorSyntax; + const char *capture_name = stream->input; + stream_scan_identifier(stream); + uint32_t length = stream->input - capture_name; + + // Add the capture id to the first step of the pattern + uint16_t capture_id = symbol_table_insert_name( + &self->captures, + capture_name, + length + ); + query_step__add_capture(step, capture_id); + (*capture_count)++; + + stream_skip_whitespace(stream); + } + + // No more suffix modifiers + else { + break; + } } return 0; @@ -778,24 +943,22 @@ TSQuery *ts_query_new( .predicates_by_pattern = array_new(), .symbol_map = symbol_map, .wildcard_root_pattern_count = 0, - .max_capture_count = 0, .language = language, }; // Parse all of the S-expressions in the given string. Stream stream = stream_new(source, source_len); stream_skip_whitespace(&stream); - uint32_t start_step_index; while (stream.input < stream.end) { - start_step_index = self->steps.size; + uint32_t start_step_index = self->steps.size; uint32_t capture_count = 0; array_push(&self->start_bytes_by_pattern, stream.input - source); array_push(&self->predicates_by_pattern, ((Slice) { .offset = self->predicate_steps.size, .length = 0, })); - *error_type = ts_query__parse_pattern(self, &stream, 0, &capture_count); - array_push(&self->steps, ((QueryStep) { .depth = PATTERN_DONE_MARKER })); + *error_type = ts_query__parse_pattern(self, &stream, 0, &capture_count, false); + array_push(&self->steps, query_step__new(0, PATTERN_DONE_MARKER, false)); // If any pattern could not be parsed, then report the error information // and terminate. @@ -805,7 +968,19 @@ TSQuery *ts_query_new( return NULL; } + // If a pattern has a wildcard at its root, optimize the matching process + // by skipping matching the wildcard. + if ( + self->steps.contents[start_step_index].symbol == WILDCARD_SYMBOL + ) { + QueryStep *second_step = &self->steps.contents[start_step_index + 1]; + if (second_step->symbol != WILDCARD_SYMBOL && second_step->depth != PATTERN_DONE_MARKER) { + start_step_index += 1; + } + } + // Maintain a map that can look up patterns for a given root symbol. + self->steps.contents[start_step_index].is_pattern_start = true; ts_query__pattern_map_insert( self, self->steps.contents[start_step_index].symbol, @@ -814,13 +989,6 @@ TSQuery *ts_query_new( if (self->steps.contents[start_step_index].symbol == WILDCARD_SYMBOL) { self->wildcard_root_pattern_count++; } - - // Keep track of the maximum number of captures in pattern, because - // that numer determines how much space is needed to store each capture - // list. - if (capture_count > self->max_capture_count) { - self->max_capture_count = capture_count; - } } ts_query__finalize_steps(self); @@ -891,16 +1059,31 @@ void ts_query_disable_capture( const char *name, uint32_t length ) { + // Remove capture information for any pattern step that previously + // captured with the given name. int id = symbol_table_id_for_name(&self->captures, name, length); if (id != -1) { for (unsigned i = 0; i < self->steps.size; i++) { QueryStep *step = &self->steps.contents[i]; - if (step->capture_id == id) { - step->capture_id = NONE; - } + query_step__remove_capture(step, id); + } + ts_query__finalize_steps(self); + } +} + +void ts_query_disable_pattern( + TSQuery *self, + uint32_t pattern_index +) { + // Remove the given pattern from the pattern map. Its steps will still + // be in the `steps` array, but they will never be read. + for (unsigned i = 0; i < self->pattern_map.size; i++) { + PatternEntry *pattern = &self->pattern_map.contents[i]; + if (pattern->pattern_index == pattern_index) { + array_erase(&self->pattern_map, i); + i--; } } - ts_query__finalize_steps(self); } /*************** @@ -940,7 +1123,7 @@ void ts_query_cursor_exec( array_clear(&self->states); array_clear(&self->finished_states); ts_tree_cursor_reset(&self->cursor, node); - capture_list_pool_reset(&self->capture_list_pool, query->max_capture_count); + capture_list_pool_reset(&self->capture_list_pool); self->next_state_id = 0; self->depth = 0; self->ascending = false; @@ -984,12 +1167,12 @@ static bool ts_query_cursor__first_in_progress_capture( bool result = false; for (unsigned i = 0; i < self->states.size; i++) { const QueryState *state = &self->states.contents[i]; - if (state->capture_count > 0) { - const TSQueryCapture *captures = capture_list_pool_get( - &self->capture_list_pool, - state->capture_list_id - ); - uint32_t capture_byte = ts_node_start_byte(captures[0].node); + const CaptureList *captures = capture_list_pool_get( + &self->capture_list_pool, + state->capture_list_id + ); + if (captures->size > 0) { + uint32_t capture_byte = ts_node_start_byte(captures->contents[0].node); if ( !result || capture_byte < *byte_offset || @@ -1010,8 +1193,21 @@ static bool ts_query_cursor__first_in_progress_capture( static bool ts_query__cursor_add_state( TSQueryCursor *self, - const PatternEntry *slice + const PatternEntry *pattern ) { + QueryStep *step = &self->query->steps.contents[pattern->step_index]; + + // If this pattern begins with a repetition, then avoid creating + // new states after already matching the repetition one or more times. + // The query should only one match for the repetition - the one that + // started the earliest. + if (step->is_repeated) { + for (unsigned i = 0; i < self->states.size; i++) { + QueryState *state = &self->states.contents[i]; + if (state->step_index == pattern->step_index) return true; + } + } + uint32_t list_id = capture_list_pool_acquire(&self->capture_list_pool); // If there are no capture lists left in the pool, then terminate whichever @@ -1037,14 +1233,20 @@ static bool ts_query__cursor_add_state( } } - LOG(" start state. pattern:%u\n", slice->pattern_index); + LOG( + " start state. pattern:%u, step:%u\n", + pattern->pattern_index, + pattern->step_index + ); array_push(&self->states, ((QueryState) { .capture_list_id = list_id, - .step_index = slice->step_index, - .pattern_index = slice->pattern_index, - .start_depth = self->depth, - .capture_count = 0, + .step_index = pattern->step_index, + .pattern_index = pattern->pattern_index, + .start_depth = self->depth - step->depth, .consumed_capture_count = 0, + .repeat_match_count = 0, + .step_index_on_failure = NONE, + .seeking_non_match = false, })); return true; } @@ -1058,15 +1260,15 @@ static QueryState *ts_query__cursor_copy_state( array_push(&self->states, *state); QueryState *new_state = array_back(&self->states); new_state->capture_list_id = new_list_id; - TSQueryCapture *old_captures = capture_list_pool_get( + CaptureList *old_captures = capture_list_pool_get( &self->capture_list_pool, state->capture_list_id ); - TSQueryCapture *new_captures = capture_list_pool_get( + CaptureList *new_captures = capture_list_pool_get( &self->capture_list_pool, new_list_id ); - memcpy(new_captures, old_captures, state->capture_count * sizeof(TSQueryCapture)); + array_push_all(new_captures, old_captures); return new_state; } @@ -1113,15 +1315,16 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) { return self->finished_states.size > 0; } } else { - bool can_have_later_siblings; + bool has_later_siblings; bool can_have_later_siblings_with_this_field; TSFieldId field_id = ts_tree_cursor_current_status( &self->cursor, - &can_have_later_siblings, + &has_later_siblings, &can_have_later_siblings_with_this_field ); TSNode node = ts_tree_cursor_current_node(&self->cursor); TSSymbol symbol = ts_node_symbol(node); + bool is_named = ts_node_is_named(node); if (symbol != ts_builtin_sym_error && self->query->symbol_map) { symbol = self->query->symbol_map[symbol]; } @@ -1145,43 +1348,46 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) { ) return false; LOG( - "enter node. type:%s, field:%s, row:%u state_count:%u, finished_state_count:%u, can_have_later_siblings:%d, can_have_later_siblings_with_this_field:%d\n", + "enter node. " + "type:%s, field:%s, row:%u state_count:%u, " + "finished_state_count:%u, has_later_siblings:%d, " + "can_have_later_siblings_with_this_field:%d\n", ts_node_type(node), ts_language_field_name_for_id(self->query->language, field_id), ts_node_start_point(node).row, self->states.size, self->finished_states.size, - can_have_later_siblings, + has_later_siblings, can_have_later_siblings_with_this_field ); // Add new states for any patterns whose root node is a wildcard. for (unsigned i = 0; i < self->query->wildcard_root_pattern_count; i++) { - PatternEntry *slice = &self->query->pattern_map.contents[i]; - QueryStep *step = &self->query->steps.contents[slice->step_index]; + PatternEntry *pattern = &self->query->pattern_map.contents[i]; + QueryStep *step = &self->query->steps.contents[pattern->step_index]; // If this node matches the first step of the pattern, then add a new // state at the start of this pattern. if (step->field && field_id != step->field) continue; - if (!ts_query__cursor_add_state(self, slice)) break; + if (!ts_query__cursor_add_state(self, pattern)) break; } // Add new states for any patterns whose root node matches this node. unsigned i; if (ts_query__pattern_map_search(self->query, symbol, &i)) { - PatternEntry *slice = &self->query->pattern_map.contents[i]; - QueryStep *step = &self->query->steps.contents[slice->step_index]; + PatternEntry *pattern = &self->query->pattern_map.contents[i]; + QueryStep *step = &self->query->steps.contents[pattern->step_index]; do { // If this node matches the first step of the pattern, then add a new // state at the start of this pattern. if (step->field && field_id != step->field) continue; - if (!ts_query__cursor_add_state(self, slice)) break; + if (!ts_query__cursor_add_state(self, pattern)) break; // Advance to the next pattern whose root node matches this node. i++; if (i == self->query->pattern_map.size) break; - slice = &self->query->pattern_map.contents[i]; - step = &self->query->steps.contents[slice->step_index]; + pattern = &self->query->pattern_map.contents[i]; + step = &self->query->steps.contents[pattern->step_index]; } while (step->symbol == symbol); } @@ -1191,14 +1397,23 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) { QueryStep *step = &self->query->steps.contents[state->step_index]; // Check that the node matches all of the criteria for the next - // step of the pattern.if ( + // step of the pattern. if ((uint32_t)state->start_depth + (uint32_t)step->depth != self->depth) continue; // Determine if this node matches this step of the pattern, and also // if this node can have later siblings that match this step of the // pattern. - bool node_does_match = !step->symbol || step->symbol == symbol; - bool later_sibling_can_match = can_have_later_siblings; + bool node_does_match = + step->symbol == symbol || + step->symbol == WILDCARD_SYMBOL || + (step->symbol == NAMED_WILDCARD_SYMBOL && is_named); + bool later_sibling_can_match = has_later_siblings; + if (step->is_immediate && is_named) { + later_sibling_can_match = false; + } + if (step->is_last && has_later_siblings) { + node_does_match = false; + } if (step->field) { if (step->field == field_id) { if (!can_have_later_siblings_with_this_field) { @@ -1210,6 +1425,24 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) { } if (!node_does_match) { + // If this QueryState has processed a repeating sequence, and that repeating + // sequence has ended, move on to the *next* step of this state's pattern. + if ( + state->step_index_on_failure != NONE && + (!later_sibling_can_match || step->is_repeated) + ) { + LOG( + " finish repetition state. pattern:%u, step:%u\n", + state->pattern_index, + state->step_index + ); + state->step_index = state->step_index_on_failure; + state->step_index_on_failure = NONE; + state->repeat_match_count = 0; + i--; + continue; + } + if (!later_sibling_can_match) { LOG( " discard state. pattern:%u, step:%u\n", @@ -1224,9 +1457,17 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) { i--; n--; } + + state->seeking_non_match = false; continue; } + // The `seeking_non_match` flag indicates that a previous QueryState + // has already begun processing this repeating sequence, so that *this* + // QueryState should not begin matching until a separate repeating sequence + // is found. + if (state->seeking_non_match) continue; + // Some patterns can match their root node in multiple ways, // capturing different children. If this pattern step could match // later children within the same parent, then this query state @@ -1236,11 +1477,20 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) { // siblings. QueryState *next_state = state; if ( - step->depth > 0 && + !step->is_pattern_start && step->contains_captures && - later_sibling_can_match + later_sibling_can_match && + state->repeat_match_count == 0 ) { QueryState *copy = ts_query__cursor_copy_state(self, state); + + // The QueryState that matched this node has begun matching a repeating + // sequence. The QueryState that *skipped* this node should not start + // matching later elements of the same repeating sequence. + if (step->is_repeated) { + state->seeking_non_match = true; + } + if (copy) { LOG( " split state. pattern:%u, step:%u\n", @@ -1249,53 +1499,71 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) { ); next_state = copy; } else { - LOG(" canot split state.\n"); + LOG(" cannot split state.\n"); } } - LOG( - " advance state. pattern:%u, step:%u\n", - next_state->pattern_index, - next_state->step_index - ); - // If the current node is captured in this pattern, add it to the // capture list. - if (step->capture_id != NONE) { - LOG( - " capture node. pattern:%u, capture_id:%u\n", - next_state->pattern_index, - step->capture_id - ); - TSQueryCapture *capture_list = capture_list_pool_get( + for (unsigned j = 0; j < MAX_STEP_CAPTURE_COUNT; j++) { + uint16_t capture_id = step->capture_ids[j]; + if (step->capture_ids[j] == NONE) break; + CaptureList *capture_list = capture_list_pool_get( &self->capture_list_pool, next_state->capture_list_id ); - capture_list[next_state->capture_count++] = (TSQueryCapture) { + array_push(capture_list, ((TSQueryCapture) { node, - step->capture_id - }; + capture_id + })); + LOG( + " capture node. pattern:%u, capture_id:%u, capture_count:%u\n", + next_state->pattern_index, + capture_id, + capture_list->size + ); } - // If the pattern is now done, then remove it from the list of - // in-progress states, and add it to the list of finished states. - next_state->step_index++; - QueryStep *next_step = step + 1; - if (next_step->depth == PATTERN_DONE_MARKER) { - LOG(" finish pattern %u\n", next_state->pattern_index); + // If this is the end of a repetition, then jump back to the beginning + // of that repetition. + if (step->repeat_step_index != NONE) { + next_state->step_index_on_failure = next_state->step_index + 1; + next_state->step_index = step->repeat_step_index; + next_state->repeat_match_count++; + LOG( + " continue repeat. pattern:%u, match_count:%u\n", + next_state->pattern_index, + next_state->repeat_match_count + ); + } else { + next_state->step_index++; + LOG( + " advance state. pattern:%u, step:%u\n", + next_state->pattern_index, + next_state->step_index + ); - next_state->id = self->next_state_id++; - array_push(&self->finished_states, *next_state); - if (next_state == state) { - array_erase(&self->states, i); - i--; - n--; - } else { - self->states.size--; + QueryStep *next_step = step + 1; + + // If the pattern is now done, then remove it from the list of + // in-progress states, and add it to the list of finished states. + if (next_step->depth == PATTERN_DONE_MARKER) { + LOG(" finish pattern %u\n", next_state->pattern_index); + + next_state->id = self->next_state_id++; + array_push(&self->finished_states, *next_state); + if (next_state == state) { + array_erase(&self->states, i); + i--; + n--; + } else { + self->states.size--; + } } } } + // Continue descending if possible. if (ts_tree_cursor_goto_first_child(&self->cursor)) { self->depth++; @@ -1321,11 +1589,12 @@ bool ts_query_cursor_next_match( QueryState *state = &self->finished_states.contents[0]; match->id = state->id; match->pattern_index = state->pattern_index; - match->capture_count = state->capture_count; - match->captures = capture_list_pool_get( + CaptureList *captures = capture_list_pool_get( &self->capture_list_pool, state->capture_list_id ); + match->captures = captures->contents; + match->capture_count = captures->size; capture_list_pool_release(&self->capture_list_pool, state->capture_list_id); array_erase(&self->finished_states, 0); return true; @@ -1378,13 +1647,13 @@ bool ts_query_cursor_next_capture( uint32_t first_finished_pattern_index = first_unfinished_pattern_index; for (unsigned i = 0; i < self->finished_states.size; i++) { const QueryState *state = &self->finished_states.contents[i]; - if (state->capture_count > state->consumed_capture_count) { - const TSQueryCapture *captures = capture_list_pool_get( - &self->capture_list_pool, - state->capture_list_id - ); + CaptureList *captures = capture_list_pool_get( + &self->capture_list_pool, + state->capture_list_id + ); + if (captures->size > state->consumed_capture_count) { uint32_t capture_byte = ts_node_start_byte( - captures[state->consumed_capture_count].node + captures->contents[state->consumed_capture_count].node ); if ( capture_byte < first_finished_capture_byte || @@ -1416,11 +1685,12 @@ bool ts_query_cursor_next_capture( ]; match->id = state->id; match->pattern_index = state->pattern_index; - match->capture_count = state->capture_count; - match->captures = capture_list_pool_get( + CaptureList *captures = capture_list_pool_get( &self->capture_list_pool, state->capture_list_id ); + match->captures = captures->contents; + match->capture_count = captures->size; *capture_index = state->consumed_capture_count; state->consumed_capture_count++; return true; diff --git a/src/tree_sitter/stack.c b/src/tree_sitter/stack.c index 3e842c99c3..ade1577566 100644 --- a/src/tree_sitter/stack.c +++ b/src/tree_sitter/stack.c @@ -11,7 +11,7 @@ #define MAX_NODE_POOL_SIZE 50 #define MAX_ITERATOR_COUNT 64 -#ifdef _WIN32 +#if defined _WIN32 && !defined __GNUC__ #define inline __forceinline #else #define inline static inline __attribute__((always_inline)) diff --git a/src/tree_sitter/subtree.c b/src/tree_sitter/subtree.c index 30144fa175..b98f172339 100644 --- a/src/tree_sitter/subtree.c +++ b/src/tree_sitter/subtree.c @@ -322,12 +322,9 @@ void ts_subtree_balance(Subtree self, SubtreePool *pool, const TSLanguage *langu if (tree.ptr->repeat_depth > 0) { Subtree child1 = tree.ptr->children[0]; Subtree child2 = tree.ptr->children[tree.ptr->child_count - 1]; - if ( - ts_subtree_child_count(child1) > 0 && - ts_subtree_child_count(child2) > 0 && - child1.ptr->repeat_depth > child2.ptr->repeat_depth - ) { - unsigned n = child1.ptr->repeat_depth - child2.ptr->repeat_depth; + long repeat_delta = (long)ts_subtree_repeat_depth(child1) - (long)ts_subtree_repeat_depth(child2); + if (repeat_delta > 0) { + unsigned n = repeat_delta; for (unsigned i = n / 2; i > 0; i /= 2) { ts_subtree__compress(tree, i, language, &pool->tree_stack); n -= i; @@ -344,10 +341,6 @@ void ts_subtree_balance(Subtree self, SubtreePool *pool, const TSLanguage *langu } } -static inline uint32_t ts_subtree_repeat_depth(Subtree self) { - return ts_subtree_child_count(self) ? self.ptr->repeat_depth : 0; -} - void ts_subtree_set_children( MutableSubtree self, Subtree *children, uint32_t child_count, const TSLanguage *language ) { diff --git a/src/tree_sitter/subtree.h b/src/tree_sitter/subtree.h index 79ccd92390..18c48dcbd0 100644 --- a/src/tree_sitter/subtree.h +++ b/src/tree_sitter/subtree.h @@ -206,6 +206,10 @@ static inline uint32_t ts_subtree_child_count(Subtree self) { return self.data.is_inline ? 0 : self.ptr->child_count; } +static inline uint32_t ts_subtree_repeat_depth(Subtree self) { + return self.data.is_inline ? 0 : self.ptr->repeat_depth; +} + static inline uint32_t ts_subtree_node_count(Subtree self) { return (self.data.is_inline || self.ptr->child_count == 0) ? 1 : self.ptr->node_count; } diff --git a/src/tree_sitter/utf16.c b/src/tree_sitter/utf16.c deleted file mode 100644 index 3956c01cb9..0000000000 --- a/src/tree_sitter/utf16.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "./utf16.h" - -utf8proc_ssize_t utf16_iterate( - const utf8proc_uint8_t *string, - utf8proc_ssize_t length, - utf8proc_int32_t *code_point -) { - if (length < 2) { - *code_point = -1; - return 0; - } - - uint16_t *units = (uint16_t *)string; - uint16_t unit = units[0]; - - if (unit < 0xd800 || unit >= 0xe000) { - *code_point = unit; - return 2; - } - - if (unit < 0xdc00) { - if (length >= 4) { - uint16_t next_unit = units[1]; - if (next_unit >= 0xdc00 && next_unit < 0xe000) { - *code_point = 0x10000 + ((unit - 0xd800) << 10) + (next_unit - 0xdc00); - return 4; - } - } - } - - *code_point = -1; - return 2; -} diff --git a/src/tree_sitter/utf16.h b/src/tree_sitter/utf16.h deleted file mode 100644 index 32fd05e6db..0000000000 --- a/src/tree_sitter/utf16.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef TREE_SITTER_UTF16_H_ -#define TREE_SITTER_UTF16_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> -#include <stdlib.h> -#include "utf8proc.h" - -// Analogous to utf8proc's utf8proc_iterate function. Reads one code point from -// the given UTF16 string and stores it in the location pointed to by `code_point`. -// Returns the number of bytes in `string` that were read. -utf8proc_ssize_t utf16_iterate(const utf8proc_uint8_t *, utf8proc_ssize_t, utf8proc_int32_t *); - -#ifdef __cplusplus -} -#endif - -#endif // TREE_SITTER_UTF16_H_ |