diff options
-rw-r--r-- | man/nvim.1 | 95 | ||||
-rw-r--r-- | runtime/doc/starting.txt | 11 | ||||
-rw-r--r-- | runtime/doc/vim_diff.txt | 4 | ||||
-rw-r--r-- | src/nvim/event/rstream.c | 2 | ||||
-rw-r--r-- | src/nvim/globals.h | 235 | ||||
-rw-r--r-- | src/nvim/main.c | 639 | ||||
-rw-r--r-- | src/nvim/message.c | 5 | ||||
-rw-r--r-- | src/nvim/os/input.c | 20 | ||||
-rw-r--r-- | test/functional/core/startup_spec.lua | 94 | ||||
-rw-r--r-- | test/functional/helpers.lua | 8 |
10 files changed, 549 insertions, 564 deletions
diff --git a/man/nvim.1 b/man/nvim.1 index 12f342247e..75c037946a 100644 --- a/man/nvim.1 +++ b/man/nvim.1 @@ -1,4 +1,4 @@ -.Dd January 28, 2016 +.Dd December 17, 2017 .Dt NVIM 1 .Os .Sh NAME @@ -25,7 +25,7 @@ To enter commands in type a colon .Pq Sq \&: which is also used in this manual to denote commands. -For more information, consult the online help system with the +For more information, consult the online help with the .Ic :help command. .Bl -tag -width Fl @@ -73,24 +73,18 @@ See Interpret all further arguments as files. Can be used to edit files starting with a hyphen .Pq Sq - . -.It Fl -literal -Interpret filenames literally, that is, do not expand wildcards. -Has no effect on Unix-like systems, where the shell expands wildcards. .It Fl e -Ex mode. +Ex mode. Reads stdin as Ex commands. See .Ic :help Ex-mode . .It Fl E -Improved Ex mode. +Ex mode, improved. Reads stdin as text. See .Ic :help gQ . -.It Fl s -Silent mode. -Only takes effect if -.Fl e -or -.Fl E -is specified before it. +.It Fl es +Silent (batch) mode. Reads stdin as Ex commands. +.It Fl Es +Silent (batch) mode. Reads stdin as text. .It Fl d Diff mode. Show the difference between two to four files, similar to @@ -99,12 +93,12 @@ See .Ic :help diff . .It Fl R Read-only mode. -Sets the option 'readonly'. +Sets the 'readonly' option. Implies .Fl n . Buffers can still be edited, but cannot be written to disk if already associated with a file. -To overwrite a file, add an exclamation mark to the needed Ex command, such as +To overwrite a file, add an exclamation mark to the relevant Ex command, such as .Ic :w! . See .Ic :help 'readonly' . @@ -112,37 +106,31 @@ See Restricted mode. Disable commands that make use of an external shell. .It Fl m -Disable file modifications. -Unsets the option 'write'. +Resets the 'write' option, to disable file modifications. Writing to a file is disabled, but buffers can still be modified. .It Fl M -Disable file and buffer modifications. -Unsets the options 'write' and 'modifiable'. -Note that these options can be set to re-enable making modifications. +Resets the 'write' and 'modifiable' options, to disable file and buffer +modifications. .It Fl b Binary mode. See .Ic :help edit-binary . .It Fl l Lisp mode. -Sets the options 'lisp' and 'showmatch'. +Sets the 'lisp' and 'showmatch' options. .It Fl A Arabic mode. -Sets the option 'arabic'. -.It Fl F -Farsi mode. -Sets the options 'fkmap' and 'rightleft'. +Sets the 'arabic' option. .It Fl H Hebrew mode. -Sets the options 'hkmap' and 'rightleft'. +Sets the 'hkmap' and 'rightleft' options. .It Fl V Ns Oo Ar N Oc Ns Op Ar file Verbose mode. Print messages about which files are being sourced and for reading and writing a ShaDa file. .Ar N -is the value for the 'verbose' option; defaults to -.Cm 10 -if omitted. +is the 'verbose' level; defaults to +.Cm 10. If .Ar file is specified, append messages to @@ -153,9 +141,9 @@ Debugging mode. Started when executing the first command from a script. .It Fl n Disable the use of swap files. -Sets the option 'updatecount' to +Sets the 'updatecount' option to .Cm 0 . -Can be useful for editing file(s) on a slow medium. +Can be useful for editing files on a slow medium. .It Fl r Op Ar file Recovery mode. If @@ -176,13 +164,13 @@ Alias for .It Fl u Ar vimrc Use .Ar vimrc -instead of the default of +instead of the default .Pa ~/.config/nvim/init.vim . If .Ar vimrc is .Cm NORC , -do not load any initialization files (excluding plugins), +do not load any initialization files (except plugins), and do not attempt to parse environment variables. If .Ar vimrc @@ -194,7 +182,7 @@ See .It Fl i Ar shada Use .Ar shada -instead of the default of +instead of the default .Pa ~/.local/share/nvim/shada/main.shada . If .Ar shada @@ -233,7 +221,6 @@ For the first file, position the cursor on line If .Ar linenum is omitted, position the cursor on the last line of the file. -Note that .Cm +5 and .Cm -c 5 @@ -246,8 +233,7 @@ For the first file, position the cursor on the first occurrence of .Ar pattern . If .Ar pattern -is omitted, the most recently used search pattern is used (if there is one). -Note that +is omitted, the most recent search pattern is used (if any). .Cm +/foo and .Cm -c /foo @@ -268,10 +254,9 @@ Up to 10 instances of or .Cm + can be used. -Note that -.Qq Cm +set si +.Qq Cm +foo and -.Cm -c \(dqset si\(dq +.Cm -c \(dqfoo\(dq are equivalent. .It Fl -cmd Ar command Like @@ -292,9 +277,9 @@ cannot start with a hyphen .Pq Sq - . If .Ar session -is omitted, then -.Pa Session.vim , -if found, is used. +is omitted then +.Pa Session.vim +is used, if found. See .Ic :help session-file . .It Fl s Ar scriptin @@ -339,24 +324,24 @@ Print version information and exit. .Sh ENVIRONMENT .Bl -tag -width Fl .It Ev VIM -Used to locate various user files, such as init.vim. +Used to locate user files, such as init.vim. +System-dependent, see :help $VIM. .It Ev VIMRUNTIME -Used to locate runtime files, such as online documentation and -syntax highlighting definitions. +Used to locate runtime files (documentation, syntax highlighting, etc.). .It Ev XDG_CONFIG_HOME Path to the user-local configuration directory, see .Sx FILES . Defaults to -.Pa ~/.config -if not set. +.Pa ~/.config . +See :help xdg. .It Ev XDG_DATA_HOME Like .Ev XDG_CONFIG_HOME , but used to store data not generally edited by the user, namely swap, backup, and ShaDa files. Defaults to -.Pa ~/.local/share -if not set. +.Pa ~/.local/share . +See :help xdg. .It Ev VIMINIT Ex commands to be executed at startup. For example, the command to quit is @@ -370,9 +355,11 @@ to See .Ic :help VIMINIT . .It Ev SHELL -Used to set the 'shell' option, which determines the shell used by the -.Ic :terminal -command. +Used to initialize the 'shell' option, which decides the default shell used by +features like +.Ic :terminal , +.Ic :! , and +.Ic system() . .El .Sh FILES .Bl -tag -width "~/.config/nvim/init.vim" diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index db3eb757c0..5ff9e0b5dc 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -22,8 +22,7 @@ More generally, Vim is started with: Option arguments and file name arguments can be mixed, and any number of them can be given. However, watch out for options that take an argument. -Exactly one out of the following five items may be used to choose how to -start editing: +The following items may be used to choose how to start editing: *-file* *---* filename One or more file names. The first one will be the current @@ -34,7 +33,6 @@ filename One or more file names. The first one will be the current nvim -- -filename < All arguments after the "--" will be interpreted as file names, no other options or "+command" argument can follow. - For behavior of quotes on MS-Windows, see |win32-quotes|. *--* - This argument can mean two things, depending on whether Ex @@ -104,13 +102,6 @@ argument. (Only available when compiled with the |+startuptime| feature). - *--literal* ---literal Take file names literally, don't expand wildcards. Not needed - for Unix, because Vim always takes file names literally (the - shell expands wildcards). - Applies to all the names, also the ones that come before this - argument. - *-+* +[num] The cursor will be positioned on line "num" for the first file being edited. If "num" is missing, the cursor will be diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 04d78da45a..ceae8eba8c 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -440,6 +440,10 @@ Other compile-time features: Emacs tags support X11 integration (see |x11-selection|) +Startup: + --literal (file args are always literal; to expand wildcards on Windows, use + |:n| e.g. `nvim +"n *"`) + Nvim does not have a built-in GUI and hence the following aliases have been removed: gvim, gex, gview, rgvim, rgview diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c index 2fbe7f6773..6812b342bf 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -115,7 +115,7 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) if (cnt == UV_ENOBUFS || cnt == 0) { return; } else if (cnt == UV_EOF && uvstream->type == UV_TTY) { - // The TTY driver might signal TTY without closing the stream + // The TTY driver might signal EOF without closing the stream invoke_read_cb(stream, 0, true); } else { DLOG("Closing Stream (%p): %s (%s)", stream, diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 2860817f79..51bc3f1289 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -290,13 +290,11 @@ 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 */ -/* - * Lines left before a "more" message. Ex mode needs to be able to reset this - * after you type something. - */ -EXTERN int lines_left INIT(= -1); /* lines left for listing */ -EXTERN int msg_no_more INIT(= FALSE); /* don't use more prompt, truncate - messages */ +/// Lines left before a "more" message. Ex mode needs to be able to reset this +/// after you type something. +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 */ @@ -307,88 +305,71 @@ EXTERN int debug_did_msg INIT(= false); // did "debug mode" message EXTERN int debug_tick INIT(= 0); // breakpoint change count EXTERN int debug_backtrace_level INIT(= 0); // breakpoint backtrace level -/* Values for "do_profiling". */ -#define PROF_NONE 0 /* profiling not started */ -#define PROF_YES 1 /* profiling busy */ -#define PROF_PAUSED 2 /* profiling paused */ -EXTERN int do_profiling INIT(= PROF_NONE); /* PROF_ values */ +// Values for "do_profiling". +#define PROF_NONE 0 ///< profiling not started +#define PROF_YES 1 ///< profiling busy +#define PROF_PAUSED 2 ///< profiling paused +EXTERN int do_profiling INIT(= PROF_NONE); ///< PROF_ values -/* - * The exception currently being thrown. Used to pass an exception to - * a different cstack. Also used for discarding an exception before it is - * caught or made pending. - */ +/// Exception currently being thrown. Used to pass an exception to a different +/// cstack. Also used for discarding an exception before it is caught or made +/// pending. EXTERN except_T *current_exception; -/* - * need_rethrow: set to TRUE when a throw that cannot be handled in do_cmdline() - * must be propagated to the cstack of the previously called do_cmdline(). - */ -EXTERN int need_rethrow INIT(= FALSE); +/// Set when a throw that cannot be handled in do_cmdline() must be propagated +/// to the cstack of the previously called do_cmdline(). +EXTERN int need_rethrow INIT(= false); -/* - * check_cstack: set to TRUE when a ":finish" or ":return" that cannot be - * handled in do_cmdline() must be propagated to the cstack of the previously - * called do_cmdline(). - */ -EXTERN int check_cstack INIT(= FALSE); +/// Set when a ":finish" or ":return" that cannot be handled in do_cmdline() +/// must be propagated to the cstack of the previously called do_cmdline(). +EXTERN int check_cstack INIT(= false); -/* - * Number of nested try conditionals (across function calls and ":source" - * commands). - */ +/// Number of nested try conditionals (across function calls and ":source" +/// commands). EXTERN int trylevel INIT(= 0); -/* - * 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 - * 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 - * zero again and there was no error or interrupt or throw. - */ -EXTERN int force_abort INIT(= FALSE); - -/* - * "msg_list" points to a variable in the stack of do_cmdline() which keeps - * the list of arguments of several emsg() calls, one of which is to be - * converted to an error exception immediately after the failing command - * returns. The message to be used for the exception value is pointed to by - * the "throw_msg" field of the first element in the list. It is usually the - * same as the "msg" field of that element, but can be identical to the "msg" - * field of a later list element, when the "emsg_severe" flag was set when the - * emsg() call was made. - */ +/// 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 +/// 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 +/// zero again and there was no error or interrupt or throw. +EXTERN int force_abort INIT(= false); + +/// "msg_list" points to a variable in the stack of do_cmdline() which keeps +/// the list of arguments of several emsg() calls, one of which is to be +/// converted to an error exception immediately after the failing command +/// returns. The message to be used for the exception value is pointed to by +/// the "throw_msg" field of the first element in the list. It is usually the +/// same as the "msg" field of that element, but can be identical to the "msg" +/// field of a later list element, when the "emsg_severe" flag was set when the +/// emsg() call was made. EXTERN struct msglist **msg_list INIT(= NULL); -/* - * suppress_errthrow: When TRUE, don't convert an error to an exception. Used - * when displaying the 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); +/// When set, don't convert an error to an exception. Used when displaying the +/// 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); -/* - * 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 - * stack of all caught and pending exceptions is embedded in the various - * cstacks; the pending exceptions, however, are not on the caught stack. - */ +/// 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 +/// stack of all caught and pending exceptions is embedded in the various +/// cstacks; the pending exceptions, however, are not on the caught stack. EXTERN except_T *caught_stack INIT(= NULL); -/* - * Garbage collection can only take place when we are sure there are no Lists - * or Dictionaries being used internally. This is flagged with - * "may_garbage_collect" when we are at the toplevel. - * "want_garbage_collect" is set by the garbagecollect() function, which means - * we do garbage collection before waiting for a char at the toplevel. - * "garbage_collect_at_exit" indicates garbagecollect(1) was called. - */ -EXTERN int may_garbage_collect INIT(= FALSE); -EXTERN int want_garbage_collect INIT(= FALSE); -EXTERN int garbage_collect_at_exit INIT(= FALSE); +/// +/// Garbage collection can only take place when we are sure there are no Lists +/// or Dictionaries being used internally. This is flagged with +/// "may_garbage_collect" when we are at the toplevel. +/// "want_garbage_collect" is set by the garbagecollect() function, which means +/// we do garbage collection before waiting for a char at the toplevel. +/// "garbage_collect_at_exit" indicates garbagecollect(1) was called. +/// +EXTERN int may_garbage_collect INIT(= false); +EXTERN int want_garbage_collect INIT(= false); +EXTERN int garbage_collect_at_exit INIT(= false); // Special values for current_SID. #define SID_MODELINE -1 // when using a modeline @@ -574,57 +555,46 @@ EXTERN int stdout_isatty INIT(= true); // volatile because it is used in a signal handler. EXTERN volatile int full_screen INIT(= false); -EXTERN int restricted INIT(= FALSE); -// TRUE when started in restricted mode (-Z) -EXTERN int secure INIT(= FALSE); -/* non-zero when only "safe" commands are - * allowed, e.g. when sourcing .exrc or .vimrc - * in current directory */ +// When started in restricted mode (-Z). +EXTERN int restricted INIT(= false); + +/// Non-zero when only "safe" commands are allowed, e.g. when sourcing .exrc or +/// .vimrc in current directory. +EXTERN int secure INIT(= false); +/// Non-zero when changing text and jumping to another window/buffer is not +/// allowed. EXTERN int textlock INIT(= 0); -/* non-zero when changing text and jumping to - * another window or buffer is not allowed */ +/// Non-zero when the current buffer can't be changed. Used for FileChangedRO. EXTERN int curbuf_lock INIT(= 0); -/* non-zero when the current buffer can't be - * changed. Used for FileChangedRO. */ + +/// Non-zero when no buffer name can be changed, no buffer can be deleted and +/// current directory can't be changed. Used for SwapExists et al. EXTERN int allbuf_lock INIT(= 0); -/* non-zero when no buffer name can be - * changed, no buffer can be deleted and - * current directory can't be changed. - * Used for SwapExists et al. */ + +/// Non-zero when evaluating an expression in a "sandbox". Several things are +/// not allowed then. EXTERN int sandbox INIT(= 0); -/* Non-zero when evaluating an expression in a - * "sandbox". Several things are not allowed - * then. */ - -EXTERN int silent_mode INIT(= FALSE); -/* set to TRUE when "-s" commandline argument - * used for ex */ - -// Set to true when sourcing of startup scripts (init.vim) is done. -// Used for options that cannot be changed after startup scripts. -EXTERN bool did_source_startup_scripts INIT(= false); - -EXTERN pos_T VIsual; /* start position of active Visual selection */ -EXTERN int VIsual_active INIT(= FALSE); -/* whether Visual mode is active */ -EXTERN int VIsual_select INIT(= FALSE); -/* whether Select mode is active */ -EXTERN int VIsual_reselect; -/* whether to restart the selection after a - * Select mode mapping or menu */ -EXTERN int VIsual_mode INIT(= 'v'); -/* type of Visual mode */ +/// Batch-mode: "-es" or "-Es" commandline argument was given. +EXTERN int silent_mode INIT(= false); -EXTERN int redo_VIsual_busy INIT(= FALSE); -/* TRUE when redoing Visual */ +/// Start position of active Visual selection. +EXTERN pos_T VIsual; +/// Whether Visual mode is active. +EXTERN int VIsual_active INIT(= false); +/// Whether Select mode is active. +EXTERN int VIsual_select INIT(= false); +/// Whether to restart the selection after a Select-mode mapping or menu. +EXTERN int VIsual_reselect; +/// Type of Visual mode. +EXTERN int VIsual_mode INIT(= 'v'); +/// 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. - */ +/// 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; /* @@ -732,25 +702,23 @@ EXTERN int (*iconvctl)(iconv_t cd, int request, void *argument); EXTERN int* (*iconv_errno)(void); # endif -/* - * "State" is the main state of Vim. - * There are other variables that modify the state: - * "Visual_mode" When State is NORMAL or INSERT. - * "finish_op" When State is NORMAL, after typing the operator and before - * typing the motion command. - */ -EXTERN int State INIT(= NORMAL); /* This is the current state of the - * command interpreter. */ +/// "State" is the main state of Vim. +/// There are other variables that modify the state: +/// Visual_mode: When State is NORMAL or INSERT. +/// finish_op : When State is NORMAL, after typing the operator and +/// before typing the motion command. +EXTERN int State INIT(= NORMAL); // This is the current state of the + // command interpreter. EXTERN bool finish_op INIT(= false); // true while an operator is pending EXTERN long opcount INIT(= 0); // count for pending operator // Ex Mode (Q) state -EXTERN int exmode_active INIT(= 0); // zero, EXMODE_NORMAL or EXMODE_VIM -EXTERN int ex_no_reprint INIT(= false); // no need to print after z or p +EXTERN int exmode_active INIT(= 0); // Zero, EXMODE_NORMAL or EXMODE_VIM. +EXTERN int ex_no_reprint INIT(=false); // No need to print after z or p. -EXTERN int Recording INIT(= FALSE); /* TRUE when recording into a reg. */ -EXTERN int Exec_reg INIT(= FALSE); /* TRUE when executing a register */ +EXTERN int Recording INIT(= false); // TRUE when recording into a reg. +EXTERN int Exec_reg INIT(= false); // TRUE when executing a register. EXTERN int no_mapping INIT(= false); // currently no mapping allowed EXTERN int no_zero_mapping INIT(= 0); // mapping zero not allowed @@ -1164,10 +1132,9 @@ EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */ EXTERN int ignored; EXTERN char *ignoredp; -// If a msgpack-rpc channel should be started over stdin/stdout +// Start a msgpack-rpc channel over stdin/stdout. EXTERN bool embedded_mode INIT(= false); -// Dont try to start an user interface -// or read/write to stdio (unless embedding) +// Do not start a UI nor read/write to stdio (unless embedding). EXTERN bool headless_mode INIT(= false); /// Used to track the status of external functions. diff --git a/src/nvim/main.c b/src/nvim/main.c index 8b0d3bb2cc..e1a01fdba6 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -97,7 +97,6 @@ typedef struct { char_u *tagname; // tag from -t argument char_u *use_ef; // 'errorfile' from -q argument - int want_full_screen; bool input_isatty; // stdin is a terminal bool output_isatty; // stdout is a terminal bool err_isatty; // stderr is a terminal @@ -106,9 +105,6 @@ typedef struct { int window_count; // number of windows to use int window_layout; // 0, WIN_HOR, WIN_VER or WIN_TABS -#if !defined(UNIX) - int literal; // don't expand file names -#endif int diff_mode; // start with 'diff' set char *listen_addr; // --listen {address} @@ -159,6 +155,7 @@ void event_init(void) bool event_teardown(void) { if (!main_loop.events) { + input_stop(); return true; } @@ -271,25 +268,17 @@ int main(int argc, char **argv) /* Don't redraw until much later. */ ++RedrawingDisabled; - /* - * When listing swap file names, don't do cursor positioning et. al. - */ - if (recoverymode && fname == NULL) - params.want_full_screen = FALSE; - setbuf(stdout, NULL); - full_screen = true; - check_tty(¶ms); + full_screen = !silent_mode; - /* - * Set the default values for the options that use Rows and Columns. - */ + // Set the default values for the options that use Rows and Columns. win_init_size(); // Set the 'diff' option now, so that it can be checked for in a vimrc // file. There is no buffer yet though. - if (params.diff_mode) - diff_win_options(firstwin, FALSE); + if (params.diff_mode) { + diff_win_options(firstwin, false); + } assert(p_ch >= 0 && Rows >= p_ch && Rows - p_ch <= INT_MAX); cmdline_row = (int)(Rows - p_ch); @@ -298,26 +287,31 @@ int main(int argc, char **argv) set_init_2(headless_mode); TIME_MSG("inits 2"); - msg_scroll = TRUE; - no_wait_return = TRUE; + msg_scroll = true; + no_wait_return = true; - init_highlight(TRUE, FALSE); /* set the default highlight groups */ + init_highlight(true, false); // Default highlight groups. TIME_MSG("init highlight"); - /* Set the break level after the terminal is initialized. */ + // Set the break level after the terminal is initialized. debug_break_level = params.use_debug_break_level; - bool reading_input = !headless_mode - && (params.input_isatty || params.output_isatty - || params.err_isatty); - - if (reading_input) { + // + // Read user-input if any TTY is connected. + // Read ex-commands if invoked with "-es". + // + bool reading_tty = !headless_mode + && (params.input_isatty || params.output_isatty + || params.err_isatty); + bool reading_excmds = !params.input_isatty && silent_mode + && exmode_active == EXMODE_NORMAL; + if (reading_tty || reading_excmds) { // One of the startup commands (arguments, sourced scripts or plugins) may // prompt the user, so start reading from a tty now. - int fd = fileno(stdin); - if (!params.input_isatty || params.edit_type == EDIT_STDIN) { - // Use stderr or stdout since stdin is not a tty and/or could be used to - // read the "-" file (eg: cat file | nvim -) + int fd = STDIN_FILENO; + if (!silent_mode + && (!params.input_isatty || params.edit_type == EDIT_STDIN)) { + // Use stderr or stdout since stdin is being used to read commands. fd = params.err_isatty ? fileno(stderr) : fileno(stdout); } input_start(fd); @@ -341,18 +335,18 @@ int main(int argc, char **argv) // Reset 'loadplugins' for "-u NONE" before "--cmd" arguments. // Allows for setting 'loadplugins' there. - if (params.use_vimrc != NULL && strcmp(params.use_vimrc, "NONE") == 0) { + if (params.use_vimrc != NULL && strequal(params.use_vimrc, "NONE")) { p_lpl = false; } - /* Execute --cmd arguments. */ + // Execute --cmd arguments. exe_pre_commands(¶ms); - /* Source startup scripts. */ + // Source startup scripts. source_startup_scripts(¶ms); // If using the runtime (-u is not NONE), enable syntax & filetype plugins. - if (params.use_vimrc == NULL || strcmp(params.use_vimrc, "NONE") != 0) { + if (params.use_vimrc == NULL || !strequal(params.use_vimrc, "NONE")) { // Does ":filetype plugin indent on". filetype_maybe_enable(); // Sources syntax/syntax.vim, which calls `:filetype on`. @@ -378,17 +372,21 @@ int main(int argc, char **argv) mch_exit(0); } - // Set a few option defaults after reading vimrc files: - // 'title' and 'icon', Unix: 'shellpipe' and 'shellredir'. + // Set a few option defaults after reading vimrc files: 'title', 'icon', + // 'shellpipe', 'shellredir'. set_init_3(); TIME_MSG("inits 3"); - /* - * "-n" argument: Disable swap file by setting 'updatecount' to 0. - * Note that this overrides anything from a vimrc file. - */ - if (params.no_swap_file) + // "-n" argument: Disable swap file by setting 'updatecount' to 0. + // Note that this overrides anything from a vimrc file. + if (params.no_swap_file) { p_uc = 0; + } + + // XXX: Minimize 'updatetime' for -es/-Es. #7679 + if (silent_mode) { + p_ut = 1; + } if (curwin->w_p_rl && p_altkeymap) { p_hkmap = FALSE; /* Reset the Hebrew keymap mode */ @@ -421,48 +419,47 @@ int main(int argc, char **argv) * Clear screen now, so file message will not be cleared. */ starting = NO_BUFFERS; - no_wait_return = FALSE; - if (!exmode_active) - msg_scroll = FALSE; + no_wait_return = false; + if (!exmode_active) { + msg_scroll = false; + } - /* - * If "-" argument given: Read file from stdin. - * Do this before starting Raw mode, because it may change things that the - * writing end of the pipe doesn't like, e.g., in case stdin and stderr - * are the same terminal: "cat | vim -". - * Using autocommands here may cause trouble... - */ - if (params.edit_type == EDIT_STDIN && !recoverymode) + // Read file (text, not commands) from stdin if: + // - stdin is not a tty + // - and -e/-es was not given + // + // Do this before starting Raw mode, because it may change things that the + // writing end of the pipe doesn't like, e.g., in case stdin and stderr + // are the same terminal: "cat | vim -". + // Using autocommands here may cause trouble... + if (params.edit_type == EDIT_STDIN && !recoverymode) { read_stdin(); + } - - if (reading_input && (need_wait_return || msg_didany)) { - // Since at this point there's no UI instance running yet, error messages - // would have been printed to stdout. Before starting (which can result in - // a alternate screen buffer being shown) we need confirmation that the - // user has seen the messages and that is done with a call to wait_return. + if (reading_tty && (need_wait_return || msg_didany)) { + // Because there's no UI yet, error messages would have been printed to + // stdout. Before starting we need confirmation that the user has seen the + // messages and that is done with a call to wait_return. TIME_MSG("waiting for return"); - wait_return(TRUE); + wait_return(true); } - if (!headless_mode) { - // Stop reading from input stream, the UI layer will take over now. - input_stop(); + if (!headless_mode && !silent_mode) { + input_stop(); // Stop reading input, let the UI take over. ui_builtin_start(); } setmouse(); // may start using the mouse ui_reset_scroll_region(); // In case Rows changed - // Don't clear the screen when starting in Ex mode, unless using the GUI. - if (exmode_active) - must_redraw = CLEAR; - else { - screenclear(); /* clear screen */ + if (exmode_active) { + must_redraw = CLEAR; // Don't clear the screen when starting in Ex mode. + } else { + screenclear(); // clear screen TIME_MSG("clearing screen"); } - no_wait_return = TRUE; + no_wait_return = true; /* * Create the requested number of windows and edit buffers in them. @@ -691,9 +688,7 @@ static int get_number_arg(const char *p, int *idx, int def) } #if defined(HAVE_LOCALE_H) -/* - * Setup to use the current locale (for ctype() and many other things). - */ +/// Setup to use the current locale (for ctype() and many other things). static void init_locale(void) { setlocale(LC_ALL, ""); @@ -724,61 +719,73 @@ static void init_locale(void) } #endif +/// Decides whether text (as opposed to commands) will be read from stdin. +/// @see EDIT_STDIN +static bool edit_stdin(bool explicit, mparm_T *parmp) +{ + bool implicit = !headless_mode + && !embedded_mode + && exmode_active != EXMODE_NORMAL // -E/-Es but not -e/-es. + && !parmp->input_isatty + && scriptin[0] == NULL; // `-s -` was not given. + return explicit || implicit; +} /// Scan the command line arguments. static void command_line_scan(mparm_T *parmp) { int argc = parmp->argc; - char **argv = parmp->argv; - int argv_idx; /* index in argv[n][] */ - int had_minmin = FALSE; /* found "--" argument */ - int want_argument; /* option argument with argument */ + char **argv = parmp->argv; + int argv_idx; // index in argv[n][] + bool had_stdin_file = false; // found explicit "-" argument + bool had_minmin = false; // found "--" argument + int want_argument; // option argument with argument int c; - char_u *p = NULL; + char_u *p = NULL; long n; - --argc; - ++argv; - argv_idx = 1; /* active option letter is argv[0][argv_idx] */ + argc--; + argv++; + argv_idx = 1; // active option letter is argv[0][argv_idx] while (argc > 0) { - /* - * "+" or "+{number}" or "+/{pat}" or "+{command}" argument. - */ + // "+" or "+{number}" or "+/{pat}" or "+{command}" argument. if (argv[0][0] == '+' && !had_minmin) { - if (parmp->n_commands >= MAX_ARG_CMDS) + if (parmp->n_commands >= MAX_ARG_CMDS) { mainerr(err_extra_cmd, NULL); - argv_idx = -1; /* skip to next argument */ - if (argv[0][1] == NUL) + } + argv_idx = -1; // skip to next argument + if (argv[0][1] == NUL) { parmp->commands[parmp->n_commands++] = "$"; - else + } else { parmp->commands[parmp->n_commands++] = &(argv[0][1]); - } - /* - * Optional argument. - */ - else if (argv[0][0] == '-' && !had_minmin) { - want_argument = FALSE; + } + + // Optional argument. + } else if (argv[0][0] == '-' && !had_minmin) { + want_argument = false; c = argv[0][argv_idx++]; switch (c) { - case NUL: /* "vim -" read from stdin */ + case NUL: { // "nvim -" read from stdin if (exmode_active) { - // "ex -" silent mode - silent_mode = TRUE; + // "nvim -e -" silent mode + silent_mode = true; } else { - if (parmp->edit_type != EDIT_NONE) { + if (parmp->edit_type != EDIT_NONE + && parmp->edit_type != EDIT_FILE + && parmp->edit_type != EDIT_STDIN) { mainerr(err_too_many_args, argv[0]); } + had_stdin_file = true; parmp->edit_type = EDIT_STDIN; } - argv_idx = -1; /* skip to next argument */ + argv_idx = -1; // skip to next argument break; - - case '-': /* "--" don't take any more option arguments */ - /* "--help" give help message */ - /* "--version" give version message */ - /* "--literal" take files literally */ - /* "--noplugin[s]" skip plugins */ - /* "--cmd <cmd>" execute cmd before vimrc */ + } + case '-': { // "--" don't take any more option arguments + // "--help" give help message + // "--version" give version message + // "--noplugin[s]" skip plugins + // "--cmd <cmd>" execute cmd before vimrc if (STRICMP(argv[0] + argv_idx, "help") == 0) { usage(); mch_exit(0); @@ -821,26 +828,25 @@ static void command_line_scan(mparm_T *parmp) want_argument = true; argv_idx += 6; } else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) { -#if !defined(UNIX) - parmp->literal = TRUE; -#endif - } else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0) - p_lpl = FALSE; - else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0) { - want_argument = TRUE; + // Do nothing: file args are always literal. #7679 + } else if (STRNICMP(argv[0] + argv_idx, "noplugin", 8) == 0) { + p_lpl = false; + } else if (STRNICMP(argv[0] + argv_idx, "cmd", 3) == 0) { + want_argument = true; argv_idx += 3; } else if (STRNICMP(argv[0] + argv_idx, "startuptime", 11) == 0) { - want_argument = TRUE; + want_argument = true; argv_idx += 11; } else { if (argv[0][argv_idx]) mainerr(err_opt_unknown, argv[0]); - had_minmin = TRUE; + had_minmin = true; + } + if (!want_argument) { + argv_idx = -1; // skip to next argument } - if (!want_argument) - argv_idx = -1; /* skip to next argument */ break; - + } case 'A': { // "-A" start in Arabic mode. set_option_value("arabic", 1L, NULL, 0); break; @@ -854,168 +860,176 @@ static void command_line_scan(mparm_T *parmp) break; } - case 'e': /* "-e" Ex mode */ + case 'D': { // "-D" Debugging + parmp->use_debug_break_level = 9999; + break; + } + case 'd': { // "-d" 'diff' + parmp->diff_mode = true; + break; + } + case 'e': { // "-e" Ex mode exmode_active = EXMODE_NORMAL; break; - - case 'E': /* "-E" Improved Ex mode */ + } + case 'E': { // "-E" Improved Ex mode exmode_active = EXMODE_VIM; break; - - case 'f': /* "-f" GUI: run in foreground. */ + } + case 'f': { // "-f" GUI: run in foreground. break; - + } case 'F': { // "-F" start in Farsi mode: rl + fkmap set. p_fkmap = true; set_option_value("rl", 1L, NULL, 0); break; } - - case 'h': /* "-h" give help message */ + case 'h': { // "-h" give help message usage(); mch_exit(0); - + } case 'H': { // "-H" start in Hebrew mode: rl + hkmap set. p_hkmap = true; set_option_value("rl", 1L, NULL, 0); break; } - case 'l': { // "-l" lisp mode, 'lisp' and 'showmatch' on. set_option_value("lisp", 1L, NULL, 0); p_sm = true; break; } - - case 'M': /* "-M" no changes or writing of files */ + case 'M': { // "-M" no changes or writing of files reset_modifiable(); - /* FALLTHROUGH */ - - case 'm': /* "-m" no writing of files */ - p_write = FALSE; + // FALLTHROUGH + } + case 'm': { // "-m" no writing of files + p_write = false; break; + } - case 'N': // "-N" Nocompatible - case 'X': // "-X" Do not connect to X server + case 'N': // "-N" Nocompatible + case 'X': // "-X" Do not connect to X server // No-op break; - case 'n': /* "-n" no swap file */ - parmp->no_swap_file = TRUE; + case 'n': { // "-n" no swap file + parmp->no_swap_file = true; break; - - case 'p': // "-p[N]" open N tab pages + } + case 'p': { // "-p[N]" open N tab pages // default is 0: open window for each file parmp->window_count = get_number_arg(argv[0], &argv_idx, 0); parmp->window_layout = WIN_TABS; break; - - case 'o': /* "-o[N]" open N horizontal split windows */ - /* default is 0: open window for each file */ + } + case 'o': { // "-o[N]" open N horizontal split windows + // default is 0: open window for each file parmp->window_count = get_number_arg(argv[0], &argv_idx, 0); parmp->window_layout = WIN_HOR; break; - - case 'O': /* "-O[N]" open N vertical split windows */ - /* default is 0: open window for each file */ + } + case 'O': { // "-O[N]" open N vertical split windows + // default is 0: open window for each file parmp->window_count = get_number_arg(argv[0], &argv_idx, 0); parmp->window_layout = WIN_VER; break; - - case 'q': /* "-q" QuickFix mode */ - if (parmp->edit_type != EDIT_NONE) + } + case 'q': { // "-q" QuickFix mode + if (parmp->edit_type != EDIT_NONE) { mainerr(err_too_many_args, argv[0]); + } parmp->edit_type = EDIT_QF; - if (argv[0][argv_idx]) { /* "-q{errorfile}" */ + if (argv[0][argv_idx]) { // "-q{errorfile}" parmp->use_ef = (char_u *)argv[0] + argv_idx; argv_idx = -1; - } else if (argc > 1) /* "-q {errorfile}" */ - want_argument = TRUE; + } else if (argc > 1) { // "-q {errorfile}" + want_argument = true; + } break; - - case 'R': /* "-R" readonly mode */ - readonlymode = TRUE; - curbuf->b_p_ro = TRUE; - p_uc = 10000; /* don't update very often */ + } + case 'R': { // "-R" readonly mode + readonlymode = true; + curbuf->b_p_ro = true; + p_uc = 10000; // don't update very often break; - - case 'r': /* "-r" recovery mode */ - case 'L': /* "-L" recovery mode */ + } + case 'r': // "-r" recovery mode + case 'L': { // "-L" recovery mode recoverymode = 1; break; - - case 's': - if (exmode_active) { // "-es" silent (batch) mode + } + case 's': { + if (exmode_active) { // "-es" silent (batch) Ex-mode silent_mode = true; } else { // "-s {scriptin}" read from script file want_argument = true; } break; - - case 't': /* "-t {tag}" or "-t{tag}" jump to tag */ - if (parmp->edit_type != EDIT_NONE) + } + case 't': { // "-t {tag}" or "-t{tag}" jump to tag + if (parmp->edit_type != EDIT_NONE) { mainerr(err_too_many_args, argv[0]); + } parmp->edit_type = EDIT_TAG; - if (argv[0][argv_idx]) { /* "-t{tag}" */ + if (argv[0][argv_idx]) { // "-t{tag}" parmp->tagname = (char_u *)argv[0] + argv_idx; argv_idx = -1; - } else /* "-t {tag}" */ - want_argument = TRUE; - break; - - case 'D': /* "-D" Debugging */ - parmp->use_debug_break_level = 9999; - break; - case 'd': /* "-d" 'diff' */ - parmp->diff_mode = TRUE; + } else { // "-t {tag}" + want_argument = true; + } break; - case 'v': + } + case 'v': { version(); mch_exit(0); - case 'V': /* "-V{N}" Verbose level */ - /* default is 10: a little bit verbose */ + } + case 'V': { // "-V{N}" Verbose level + // default is 10: a little bit verbose p_verbose = get_number_arg(argv[0], &argv_idx, 10); if (argv[0][argv_idx] != NUL) { set_option_value("verbosefile", 0L, argv[0] + argv_idx, 0); argv_idx = (int)STRLEN(argv[0]); } break; - - case 'w': /* "-w{number}" set window height */ - /* "-w {scriptout}" write to script */ + } + case 'w': { // "-w{number}" set window height + // "-w {scriptout}" write to script if (ascii_isdigit(((char_u *)argv[0])[argv_idx])) { n = get_number_arg(argv[0], &argv_idx, 10); set_option_value("window", n, NULL, 0); break; } - want_argument = TRUE; + want_argument = true; break; - - case 'Z': /* "-Z" restricted mode */ - restricted = TRUE; + } + case 'Z': { // "-Z" restricted mode + restricted = true; break; + } - case 'c': /* "-c{command}" or "-c {command}" execute - command */ + case 'c': { // "-c{command}" or "-c {command}" exec command if (argv[0][argv_idx] != NUL) { - if (parmp->n_commands >= MAX_ARG_CMDS) + if (parmp->n_commands >= MAX_ARG_CMDS) { mainerr(err_extra_cmd, NULL); - parmp->commands[parmp->n_commands++] = argv[0] - + argv_idx; + } + parmp->commands[parmp->n_commands++] = argv[0] + argv_idx; argv_idx = -1; break; } - /*FALLTHROUGH*/ - case 'S': /* "-S {file}" execute Vim script */ - case 'i': /* "-i {shada}" use for ShaDa file */ - case 'u': /* "-u {vimrc}" vim inits file */ - case 'U': /* "-U {gvimrc}" gvim inits file */ - case 'W': /* "-W {scriptout}" overwrite */ - want_argument = TRUE; + // FALLTHROUGH + } + case 'S': // "-S {file}" execute Vim script + case 'i': // "-i {shada}" use for ShaDa file + case 'u': // "-u {vimrc}" vim inits file + case 'U': // "-U {gvimrc}" gvim inits file + case 'W': { // "-W {scriptout}" overwrite + want_argument = true; break; + } - default: + default: { mainerr(err_opt_unknown, argv[0]); + } } // Handle option arguments with argument. @@ -1025,43 +1039,45 @@ static void command_line_scan(mparm_T *parmp) mainerr(err_opt_garbage, argv[0]); } - --argc; - if (argc < 1 && c != 'S') /* -S has an optional argument */ + argc--; + if (argc < 1 && c != 'S') { // -S has an optional argument mainerr(err_arg_missing, argv[0]); - ++argv; + } + argv++; argv_idx = -1; switch (c) { - case 'c': /* "-c {command}" execute command */ - case 'S': /* "-S {file}" execute Vim script */ - if (parmp->n_commands >= MAX_ARG_CMDS) + case 'c': // "-c {command}" execute command + case 'S': { // "-S {file}" execute Vim script + if (parmp->n_commands >= MAX_ARG_CMDS) { mainerr(err_extra_cmd, NULL); + } if (c == 'S') { - char *a; + char *a; - if (argc < 1) - /* "-S" without argument: use default session file - * name. */ + if (argc < 1) { + // "-S" without argument: use default session file name. a = SESSION_FILE; - else if (argv[0][0] == '-') { - /* "-S" followed by another option: use default - * session file name. */ + } else if (argv[0][0] == '-') { + // "-S" followed by another option: use default session file. a = SESSION_FILE; ++argc; --argv; } else { a = argv[0]; } - char *s = xmalloc(STRLEN(a) + 4); - sprintf(s, "so %s", a); - parmp->cmds_tofree[parmp->n_commands] = TRUE; + size_t s_size = STRLEN(a) + 4; + char *s = xmalloc(s_size); + snprintf(s, s_size, "so %s", a); + parmp->cmds_tofree[parmp->n_commands] = true; parmp->commands[parmp->n_commands++] = s; } else { parmp->commands[parmp->n_commands++] = argv[0]; } break; + } - case '-': + case '-': { if (strequal(argv[-1], "--cmd")) { // "--cmd {command}" execute command if (parmp->n_pre_commands >= MAX_ARG_CMDS) { @@ -1074,16 +1090,19 @@ static void command_line_scan(mparm_T *parmp) } // "--startuptime <file>" already handled break; + } - case 'q': /* "-q {errorfile}" QuickFix mode */ + case 'q': { // "-q {errorfile}" QuickFix mode parmp->use_ef = (char_u *)argv[0]; break; + } - case 'i': /* "-i {shada}" use for shada */ + case 'i': { // "-i {shada}" use for shada used_shada_file = argv[0]; break; + } - case 's': /* "-s {scriptin}" read from script file */ + case 's': { // "-s {scriptin}" read from script file if (scriptin[0] != NULL) { scripterror: vim_snprintf((char *)IObuff, IOSIZE, @@ -1093,11 +1112,10 @@ scripterror: mch_exit(2); } int error; - if (STRCMP(argv[0], "-") == 0) { + if (strequal(argv[0], "-")) { const int stdin_dup_fd = os_dup(STDIN_FILENO); #ifdef WIN32 - // On Windows, replace the original stdin with the - // console input handle. + // Replace the original stdin with the console input handle. close(STDIN_FILENO); const HANDLE conin_handle = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, @@ -1120,20 +1138,22 @@ scripterror: } save_typebuf(); break; + } - case 't': /* "-t {tag}" */ + case 't': { // "-t {tag}" parmp->tagname = (char_u *)argv[0]; break; - - case 'u': /* "-u {vimrc}" vim inits file */ + } + case 'u': { // "-u {vimrc}" vim inits file parmp->use_vimrc = argv[0]; break; - - case 'U': /* "-U {gvimrc}" gvim inits file */ + } + case 'U': { // "-U {gvimrc}" gvim inits file break; + } - case 'w': /* "-w {nr}" 'window' value */ - /* "-w {scriptout}" append to script file */ + case 'w': { // "-w {nr}" 'window' value + // "-w {scriptout}" append to script file if (ascii_isdigit(*((char_u *)argv[0]))) { argv_idx = 0; n = get_number_arg(argv[0], &argv_idx, 10); @@ -1141,10 +1161,12 @@ scripterror: argv_idx = -1; break; } - /*FALLTHROUGH*/ - case 'W': /* "-W {scriptout}" overwrite script file */ - if (scriptout != NULL) + // FALLTHROUGH + } + case 'W': { // "-W {scriptout}" overwrite script file + if (scriptout != NULL) { goto scripterror; + } if ((scriptout = mch_fopen(argv[0], c == 'w' ? APPENDBIN : WRITEBIN)) == NULL) { mch_errmsg(_("Cannot open for script output: \"")); @@ -1153,30 +1175,28 @@ scripterror: mch_exit(2); } break; - + } } } - } - /* - * File name argument. - */ - else { - argv_idx = -1; /* skip to next argument */ - - /* Check for only one type of editing. */ - if (parmp->edit_type != EDIT_NONE && parmp->edit_type != EDIT_FILE) + } else { // File name argument. + argv_idx = -1; // skip to next argument + + // Check for only one type of editing. + if (parmp->edit_type != EDIT_NONE + && parmp->edit_type != EDIT_FILE + && parmp->edit_type != EDIT_STDIN) { mainerr(err_too_many_args, argv[0]); + } parmp->edit_type = EDIT_FILE; - /* Add the file to the global argument list. */ + // Add the file to the global argument list. ga_grow(&global_alist.al_ga, 1); p = vim_strsave((char_u *)argv[0]); if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0 && !os_isdir(alist_name(&GARGLIST[0]))) { - char_u *r; - - r = (char_u *)concat_fnames((char *)p, (char *)path_tail(alist_name(&GARGLIST[0])), TRUE); + char_u *r = (char_u *)concat_fnames((char *)p, + (char *)path_tail(alist_name(&GARGLIST[0])), true); xfree(p); p = r; } @@ -1186,30 +1206,22 @@ scripterror: path_fix_case(p); #endif - alist_add(&global_alist, p, -#if !defined(UNIX) - parmp->literal ? 2 : 0 /* add buffer nr after exp. */ -#else - 2 /* add buffer number now and use curbuf */ -#endif - ); - + int alist_fnum_flag = edit_stdin(had_stdin_file, parmp) + ? 1 // add buffer nr after exp. + : 2; // add buffer number now and use curbuf + alist_add(&global_alist, p, alist_fnum_flag); } - /* - * If there are no more letters after the current "-", go to next - * argument. argv_idx is set to -1 when the current argument is to be - * skipped. - */ + // If there are no more letters after the current "-", go to next argument. + // argv_idx is set to -1 when the current argument is to be skipped. if (argv_idx <= 0 || argv[0][argv_idx] == NUL) { - --argc; - ++argv; + argc--; + argv++; argv_idx = 1; } } - /* If there is a "+123" or "-c" command, set v:swapcommand to the first - * one. */ + // If there is a "+123" or "-c" command, set v:swapcommand to the first one. if (parmp->n_commands > 0) { const size_t swcmd_len = STRLEN(parmp->commands[0]) + 3; char *const swcmd = xmalloc(swcmd_len); @@ -1217,6 +1229,12 @@ scripterror: set_vim_var_string(VV_SWAPCOMMAND, swcmd, -1); xfree(swcmd); } + + // Handle "foo | nvim". EDIT_FILE may be overwritten now. #6299 + if (edit_stdin(had_stdin_file, parmp)) { + parmp->edit_type = EDIT_STDIN; + } + TIME_MSG("parsing arguments"); } @@ -1229,7 +1247,6 @@ static void init_params(mparm_T *paramp, int argc, char **argv) memset(paramp, 0, sizeof(*paramp)); paramp->argc = argc; paramp->argv = argv; - paramp->want_full_screen = true; paramp->use_debug_break_level = -1; paramp->window_count = -1; paramp->listen_addr = NULL; @@ -1252,10 +1269,10 @@ static void init_startuptime(mparm_T *paramp) static void check_and_set_isatty(mparm_T *paramp) { stdin_isatty - = paramp->input_isatty = os_isatty(fileno(stdin)); + = paramp->input_isatty = os_isatty(STDIN_FILENO); stdout_isatty - = paramp->output_isatty = os_isatty(fileno(stdout)); - paramp->err_isatty = os_isatty(fileno(stderr)); + = paramp->output_isatty = os_isatty(STDOUT_FILENO); + paramp->err_isatty = os_isatty(STDERR_FILENO); #ifndef WIN32 int tty_fd = paramp->input_isatty ? STDIN_FILENO @@ -1291,26 +1308,6 @@ static void init_path(const char *exename) /// Get filename from command line, if any. static char_u *get_fname(mparm_T *parmp, char_u *cwd) { -#if !defined(UNIX) - /* - * Expand wildcards in file names. - */ - if (!parmp->literal) { - cwd = xmalloc(MAXPATHL); - if (cwd != NULL) { - os_dirname(cwd, MAXPATHL); - } - // Temporarily add '(' and ')' to 'isfname'. These are valid - // filename characters but are excluded from 'isfname' to make - // "gf" work on a file name in parenthesis (e.g.: see vim.h). - do_cmdline_cmd(":set isf+=(,)"); - alist_expand(NULL, 0); - do_cmdline_cmd(":set isf&"); - if (cwd != NULL) { - os_chdir((char *)cwd); - } - } -#endif return alist_name(&GARGLIST[0]); } @@ -1402,55 +1399,17 @@ static void handle_tag(char_u *tagname) } } -// Print a warning if stdout is not a terminal. -// When starting in Ex mode and commands come from a file, set Silent mode. -static void check_tty(mparm_T *parmp) -{ - if (headless_mode) { - return; - } - - // is active input a terminal? - if (exmode_active) { - if (!parmp->input_isatty) { - silent_mode = true; - } - } else if (parmp->want_full_screen && (!parmp->err_isatty - && (!parmp->output_isatty || !parmp->input_isatty))) { - - if (!parmp->output_isatty) { - mch_errmsg(_("Vim: Warning: Output is not to a terminal\n")); - } - - if (!parmp->input_isatty) { - mch_errmsg(_("Vim: Warning: Input is not from a terminal\n")); - } - - ui_flush(); - - if (scriptin[0] == NULL) { - os_delay(2000L, true); - } - - TIME_MSG("Warning delay"); - } -} - -/* - * Read text from stdin. - */ +/// Read text from stdin. static void read_stdin(void) { - int i; - - /* When getting the ATTENTION prompt here, use a dialog */ + // When getting the ATTENTION prompt here, use a dialog. swap_exists_action = SEA_DIALOG; - no_wait_return = TRUE; - i = msg_didany; - set_buflisted(TRUE); - (void)open_buffer(TRUE, NULL, 0); /* create memfile and read file */ - no_wait_return = FALSE; - msg_didany = i; + no_wait_return = true; + int save_msg_didany = msg_didany; + set_buflisted(true); + (void)open_buffer(true, NULL, 0); // create memfile and read file + no_wait_return = false; + msg_didany = save_msg_didany; TIME_MSG("reading stdin"); check_swap_exists_action(); } @@ -1791,14 +1750,15 @@ static bool do_user_initialization(void) static void source_startup_scripts(const mparm_T *const parmp) FUNC_ATTR_NONNULL_ALL { - // If -u argument given, use only the initializations from that file and - // nothing else. + // If -u given, use only the initializations from that file and nothing else. if (parmp->use_vimrc != NULL) { - if (strcmp(parmp->use_vimrc, "NONE") == 0 - || strcmp(parmp->use_vimrc, "NORC") == 0) { + if (strequal(parmp->use_vimrc, "NONE") + || strequal(parmp->use_vimrc, "NORC")) { + // Do nothing. } else { - if (do_source((char_u *)parmp->use_vimrc, FALSE, DOSO_NONE) != OK) + if (do_source((char_u *)parmp->use_vimrc, false, DOSO_NONE) != OK) { EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc); + } } } else if (!silent_mode) { #ifdef SYS_VIMRC_FILE @@ -1837,7 +1797,6 @@ static void source_startup_scripts(const mparm_T *const parmp) } secure = 0; } - did_source_startup_scripts = true; TIME_MSG("sourcing vimrc file(s)"); } @@ -1927,7 +1886,6 @@ static void usage(void) mch_msg(_("Usage:\n")); mch_msg(_(" nvim [options] [file ...] Edit file(s)\n")); - mch_msg(_(" nvim [options] - Read text from stdin\n")); mch_msg(_(" nvim [options] -t <tag> Edit file where tag is defined\n")); mch_msg(_(" nvim [options] -q [errorfile] Edit file with first error\n")); mch_msg(_("\nOptions:\n")); @@ -1961,10 +1919,7 @@ static void usage(void) mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n")); mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n")); mch_msg(_(" --headless Don't start a user interface\n")); - mch_msg(_(" --listen <address> Start RPC server at this address\n")); -#if !defined(UNIX) - mch_msg(_(" --literal Don't expand wildcards\n")); -#endif + mch_msg(_(" --listen <address> Serve RPC API from this address\n")); mch_msg(_(" --noplugin Don't load plugins\n")); mch_msg(_(" --startuptime <file> Write startup timing messages to <file>\n")); mch_msg(_("\nSee \":help startup-options\" for all options.\n")); diff --git a/src/nvim/message.c b/src/nvim/message.c index 188e3544e6..7935bcbc2f 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2076,8 +2076,9 @@ static void t_puts(int *t_col, const char_u *t_s, const char_u *s, int attr) } } -// Returns TRUE when messages should be printed to stdout/stderr, which -// happens when no UIs are attached and nvim is not being embedded +// Returns TRUE when messages should be printed to stdout/stderr: +// - "batch mode" ("silent mode", -es/-Es) +// - no UI and not embedded int msg_use_printf(void) { return !embedded_mode && !ui_active(); diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 405500767d..599487c345 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -34,7 +34,7 @@ typedef enum { kInputEof } InbufPollResult; -static Stream read_stream = {.closed = true}; +static Stream read_stream = { .closed = true }; // Input before UI starts. static RBuffer *input_buffer = NULL; static bool input_eof = false; static int global_fd = -1; @@ -50,7 +50,7 @@ void input_init(void) input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN); } -/// Gets the file from which input was gathered at startup. +/// Global TTY (or pipe for "-es") input stream, before UI starts. int input_global_fd(void) { return global_fd; @@ -64,7 +64,7 @@ void input_start(int fd) global_fd = fd; rstream_init_fd(&main_loop, &read_stream, fd, READ_BUFFER_SIZE); - rstream_start(&read_stream, read_cb, NULL); + rstream_start(&read_stream, input_read_cb, NULL); } void input_stop(void) @@ -108,6 +108,11 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt) } } else { if ((result = inbuf_poll((int)p_ut)) == kInputNone) { + if (read_stream.closed && silent_mode) { + // Drained eventloop & initial input; exit silent/batch-mode (-es/-Es). + read_error_exit(); + } + if (trigger_cursorhold() && !typebuf_changed(tb_change_cnt)) { create_cursorhold_event(); } else { @@ -376,11 +381,11 @@ static InbufPollResult inbuf_poll(int ms) return input_eof ? kInputEof : kInputNone; } -static void read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, - bool at_eof) +static void input_read_cb(Stream *stream, RBuffer *buf, size_t c, void *data, + bool at_eof) { if (at_eof) { - input_eof = true; + input_done(); } assert(rbuffer_space(input_buffer) >= rbuffer_size(buf)); @@ -438,8 +443,9 @@ static bool input_ready(void) // Exit because of an input read error. static void read_error_exit(void) { - if (silent_mode) /* Normal way to exit for "ex -s" */ + if (silent_mode) { // Normal way to exit for "nvim -es". getout(0); + } STRCPY(IObuff, _("Vim: Error reading input, exiting...\n")); preserve_exit(); } diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua index ae7f949e52..f1f96ba626 100644 --- a/test/functional/core/startup_spec.lua +++ b/test/functional/core/startup_spec.lua @@ -4,16 +4,19 @@ local Screen = require('test.functional.ui.screen') local clear = helpers.clear local command = helpers.command local eq = helpers.eq +local feed = helpers.feed local funcs = helpers.funcs local nvim_prog = helpers.nvim_prog local nvim_set = helpers.nvim_set local read_file = helpers.read_file local retry = helpers.retry +local sleep = helpers.sleep local iswin = helpers.iswin describe('startup', function() before_each(function() clear() + os.remove('Xtest_startup_ttyout') end) after_each(function() os.remove('Xtest_startup_ttyout') @@ -46,8 +49,8 @@ describe('startup', function() end -- Running in :terminal command([[exe printf("terminal %s -u NONE -i NONE --cmd \"]] - ..nvim_set..[[\" ]] - ..[[-c \"echo has('ttyin') has('ttyout')\""]] + ..nvim_set..[[\"]] + ..[[ -c \"echo has('ttyin') has('ttyout')\""]] ..[[, shellescape(v:progpath))]]) screen:expect([[ ^ | @@ -56,41 +59,104 @@ describe('startup', function() ]]) end) it('output to pipe: has("ttyin")==1 has("ttyout")==0', function() - local screen = Screen.new(25, 5) - screen:attach() if iswin() then command([[set shellcmdflag=/s\ /c shellxquote=\"]]) end -- Running in :terminal command([[exe printf("terminal %s -u NONE -i NONE --cmd \"]] - ..nvim_set..[[\" ]] - ..[[-c \"call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')\"]] - ..[[-c q | cat -v"]] -- Output to a pipe. + ..nvim_set..[[\"]] + ..[[ -c \"call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')\"]] + ..[[ -c q | cat -v"]] -- Output to a pipe. ..[[, shellescape(v:progpath))]]) retry(nil, 3000, function() - screen:sleep(1) + sleep(1) eq('1\n0\n', -- stdin is a TTY, stdout is a pipe read_file('Xtest_startup_ttyout')) end) end) it('input from pipe: has("ttyin")==0 has("ttyout")==1', function() - local screen = Screen.new(25, 5) - screen:attach() if iswin() then command([[set shellcmdflag=/s\ /c shellxquote=\"]]) end -- Running in :terminal command([[exe printf("terminal echo foo | ]] -- Input from a pipe. ..[[%s -u NONE -i NONE --cmd \"]] - ..nvim_set..[[\" ]] - ..[[-c \"call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')\"]] - ..[[-c q -- -"]] + ..nvim_set..[[\"]] + ..[[ -c \"call writefile([has('ttyin'), has('ttyout')], 'Xtest_startup_ttyout')\"]] + ..[[ -c q -- -"]] ..[[, shellescape(v:progpath))]]) retry(nil, 3000, function() - screen:sleep(1) + sleep(1) eq('0\n1\n', -- stdin is a pipe, stdout is a TTY read_file('Xtest_startup_ttyout')) end) end) + it('input from pipe (implicit) #7679', function() + local screen = Screen.new(25, 3) + screen:attach() + if iswin() then + command([[set shellcmdflag=/s\ /c shellxquote=\"]]) + end + -- Running in :terminal + command([[exe printf("terminal echo foo | ]] -- Input from a pipe. + ..[[%s -u NONE -i NONE --cmd \"]] + ..nvim_set..[[\"]] + ..[[ -c \"echo has('ttyin') has('ttyout')\""]] + ..[[, shellescape(v:progpath))]]) + screen:expect([[ + ^foo | + 0 1 | + | + ]]) + end) + it('input from pipe + file args #7679', function() + eq('ohyeah\r\n0 0 bufs=3', + funcs.system({nvim_prog, '-n', '-u', 'NONE', '-i', 'NONE', '--headless', + '+.print', + "+echo has('ttyin') has('ttyout') 'bufs='.bufnr('$')", + '+qall!', + '-', + 'test/functional/fixtures/tty-test.c', + 'test/functional/fixtures/shell-test.c', + }, + { 'ohyeah', '' })) + end) + + it('-e/-E interactive #7679', function() + clear('-E') + local screen = Screen.new(25, 3) + screen:attach() + feed("put ='from -E'<CR>") + screen:expect([[ + | + from -E | + :^ | + ]]) + end) + + it('stdin with -es/-Es #7679', function() + local input = { 'append', 'line1', 'line2', '.', '%print', '' } + local inputstr = table.concat(input, '\n') + + -- + -- -Es: read stdin as text + -- + eq('partylikeits1999\n', + funcs.system({nvim_prog, '-n', '-u', 'NONE', '-i', 'NONE', '-Es', '+.print', 'test/functional/fixtures/tty-test.c' }, + { 'partylikeits1999', '' })) + eq(inputstr, + funcs.system({nvim_prog, '-i', 'NONE', '-Es', '+%print', '-' }, + input)) + + -- + -- -es: read stdin as ex-commands + -- + eq(' encoding=utf-8\n', + funcs.system({nvim_prog, '-n', '-u', 'NONE', '-i', 'NONE', '-es', 'test/functional/fixtures/tty-test.c' }, + { 'set encoding', '' })) + eq('line1\nline2\n', + funcs.system({nvim_prog, '-i', 'NONE', '-es', '-' }, + input)) + end) end) diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index 9895281773..a6d2764187 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -316,6 +316,14 @@ local function retry(max, max_ms, fn) end end +-- Starts a new global Nvim session. +-- Parameters are interpreted as startup args, OR a map with these keys: +-- args: Merged with the default `nvim_argv` set. +-- env : Defines the environment of the new session. +-- +-- Example: +-- clear('-e') +-- clear({args={'-e'}, env={TERM=term}}) local function clear(...) local args = {unpack(nvim_argv)} local new_args |