2017-04-19 18:11:50 +02:00
|
|
|
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
|
|
|
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
|
|
|
2014-01-31 14:39:15 +01:00
|
|
|
#define EXTERN
|
2015-01-24 01:42:21 +01:00
|
|
|
#include <assert.h>
|
2015-01-24 01:42:21 +01:00
|
|
|
#include <stdint.h>
|
2014-03-25 00:30:14 +01:00
|
|
|
#include <string.h>
|
2014-04-16 08:21:19 +02:00
|
|
|
#include <stdbool.h>
|
2014-03-25 00:30:14 +01:00
|
|
|
|
2014-09-12 02:56:52 +02:00
|
|
|
#include <msgpack.h>
|
|
|
|
|
2014-06-17 17:22:05 +02:00
|
|
|
#include "nvim/ascii.h"
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/vim.h"
|
|
|
|
#include "nvim/main.h"
|
|
|
|
#include "nvim/buffer.h"
|
|
|
|
#include "nvim/charset.h"
|
|
|
|
#include "nvim/diff.h"
|
|
|
|
#include "nvim/eval.h"
|
|
|
|
#include "nvim/ex_cmds.h"
|
|
|
|
#include "nvim/ex_cmds2.h"
|
|
|
|
#include "nvim/ex_docmd.h"
|
|
|
|
#include "nvim/fileio.h"
|
|
|
|
#include "nvim/fold.h"
|
|
|
|
#include "nvim/getchar.h"
|
|
|
|
#include "nvim/hashtab.h"
|
2018-04-08 09:49:20 +02:00
|
|
|
#include "nvim/highlight.h"
|
2014-11-01 18:34:42 +01:00
|
|
|
#include "nvim/iconv.h"
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/if_cscope.h"
|
2014-06-17 20:43:22 +02:00
|
|
|
#ifdef HAVE_LOCALE_H
|
|
|
|
# include <locale.h>
|
|
|
|
#endif
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/mark.h"
|
|
|
|
#include "nvim/mbyte.h"
|
|
|
|
#include "nvim/memline.h"
|
|
|
|
#include "nvim/message.h"
|
|
|
|
#include "nvim/misc1.h"
|
|
|
|
#include "nvim/garray.h"
|
|
|
|
#include "nvim/log.h"
|
|
|
|
#include "nvim/memory.h"
|
|
|
|
#include "nvim/move.h"
|
2014-12-02 02:04:15 +01:00
|
|
|
#include "nvim/mouse.h"
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/normal.h"
|
|
|
|
#include "nvim/ops.h"
|
|
|
|
#include "nvim/option.h"
|
|
|
|
#include "nvim/os_unix.h"
|
viminfo: First version of ShaDa file dumping
What works:
1. ShaDa file dumping: header, registers, jump list, history, search patterns,
substitute strings, variables.
2. ShaDa file reading: registers, global marks, variables.
Most was not tested.
TODO:
1. Merging.
2. Reading history, local marks, jump and buffer lists.
3. Documentation update.
4. Converting some data from &encoding.
5. Safer variant of dumping viminfo (dump to temporary file then rename).
6. Removing old viminfo code (currently masked with `#if 0` in a ShaDa file for
reference).
2015-04-25 17:47:31 +02:00
|
|
|
#include "nvim/os/os_defs.h"
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/path.h"
|
2014-07-17 12:01:45 +02:00
|
|
|
#include "nvim/profile.h"
|
2017-04-26 15:28:10 +02:00
|
|
|
#include "nvim/popupmnu.h"
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/quickfix.h"
|
|
|
|
#include "nvim/screen.h"
|
2019-05-24 22:10:19 +02:00
|
|
|
#include "nvim/sign.h"
|
main: Start modeling Nvim as pushdown automaton
From a very high level point of view, Vim/Nvim can be described as state
machines following these instructions in a loop:
- Read user input
- Peform some action. The action is determined by the current state and can
switch states.
- Possibly display some feedback to the user.
This is not immediately visible because these instructions spread across dozens
of nested loops and function calls, making it very hard to modify the state
machine(to support more event types, for example).
So far, the approach Nvim has taken to allow more events is this:
- At the very core function that blocks for input, poll for arbitrary events.
- If the event received from the OS is user input, just return it normally to
the callers.
- If the event is not direct result of user input(possibly a vimscript function
call coming from a msgpack-rpc socket or a job control callback), return a
special key code(`K_EVENT`) that is handled by callers where it is safer to
perform arbitrary actions.
One problem with this approach is that the `K_EVENT` signal is being sent across
multiple states that may be unaware of it. This was partially fixed with the
`input_enable_events`/`input_disable_events` functions, which were added as a
mechanism that the upper layers can use to tell the core input functions that it
is ready to accept `K_EVENT`.
Another problem is that the mapping engine is implemented in getchar.c
which is called from every state, but the mapping engine is not aware of
`K_EVENT` so events can break mappings.
While it is theoretically possible to modify getchar.c to make it aware of
`K_EVENT`, this commit fixes the problem with a different approach: Model Nvim
as a pushdown automaton(https://en.wikipedia.org/wiki/Pushdown_automaton). This
design has many advantages which include:
- Decoupling the event loop from the states reponsible for handling events.
- Better control of state transition with less dependency on global variable
hacks(eg: 'restart_edit' global variable).
- Easier removal of global variables and function splitting. That is because
many variables are for state-specific information, and probably ended up being
global to simplify communication between functions, which we fix by storing
state-specific information in specialized structures.
The final goal is to let Nvim have a single top-level event loop represented by
the following pseudo-code:
```
while not quitting
let event = read_event
current_state(event)
update_screen()
```
This closely mirrors the state machine description above and makes it easier to
understand, extend and debug the program.
Note that while the pseudo code suggests an explicit stack of states that
doesn't rely on return addresses(as suggested by the principles of
automata-based programming:
https://en.wikipedia.org/wiki/Automata-based_programming), for now we'll use the
call stack as a structure to manage state transitioning as it would be very
difficult to refactor Nvim to use an explicit stack of states, and the benefits
would be small.
While this change may seem like an endless amount of work, it is possible to
do it incrementally as was shown in the previous commits. The general procedure
is:
1- Find a blocking `vgetc()`(or derivatives) call. This call represents an
implicit state of the program.
2- Split the code before and after the `vgetc()` call into functions that match
the signature of `state_check_callback` and `state_execute_callback.
Only `state_execute_callback` is required.
3- Create a `VimState` "subclass" and a initializer function that sets the
function pointers and performs any other required initialization steps. If
the state has no local variables, just use `VimState` without subclassing.
4- Instead of calling the original function containing the `vgetc()`,
initialize a stack-allocated `VimState` subclass, then call `state_enter` to
begin processing events in the state.
5- The check/execute callbacks can return 1 to continue normally, 0 to break the
loop or -1 to skip to the next iteration. These callbacks contain code that
execute before and after the old `vgetc()` call.
The functions created in step 2 may contain other `vgetc()` calls. These
represent implicit sub-states of the current state, but it is fine to remove
them later in smaller steps since we didn't break compatibility with existing
code.
2015-10-05 19:17:15 +02:00
|
|
|
#include "nvim/state.h"
|
2014-05-12 12:12:27 +02:00
|
|
|
#include "nvim/strings.h"
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/syntax.h"
|
|
|
|
#include "nvim/ui.h"
|
|
|
|
#include "nvim/version.h"
|
|
|
|
#include "nvim/window.h"
|
viminfo: First version of ShaDa file dumping
What works:
1. ShaDa file dumping: header, registers, jump list, history, search patterns,
substitute strings, variables.
2. ShaDa file reading: registers, global marks, variables.
Most was not tested.
TODO:
1. Merging.
2. Reading history, local marks, jump and buffer lists.
3. Documentation update.
4. Converting some data from &encoding.
5. Safer variant of dumping viminfo (dump to temporary file then rename).
6. Removing old viminfo code (currently masked with `#if 0` in a ShaDa file for
reference).
2015-04-25 17:47:31 +02:00
|
|
|
#include "nvim/shada.h"
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/os/input.h"
|
|
|
|
#include "nvim/os/os.h"
|
2014-09-19 09:49:37 +02:00
|
|
|
#include "nvim/os/time.h"
|
2017-07-04 16:20:00 +02:00
|
|
|
#include "nvim/os/fileio.h"
|
2015-07-17 04:10:04 +02:00
|
|
|
#include "nvim/event/loop.h"
|
2014-05-12 11:59:22 +02:00
|
|
|
#include "nvim/os/signal.h"
|
2015-07-17 05:32:07 +02:00
|
|
|
#include "nvim/event/process.h"
|
2014-10-20 12:35:10 +02:00
|
|
|
#include "nvim/msgpack_rpc/helpers.h"
|
2015-07-17 04:10:04 +02:00
|
|
|
#include "nvim/msgpack_rpc/server.h"
|
|
|
|
#include "nvim/msgpack_rpc/channel.h"
|
2018-09-20 19:19:38 +02:00
|
|
|
#include "nvim/api/ui.h"
|
2014-09-12 02:56:52 +02:00
|
|
|
#include "nvim/api/private/defs.h"
|
|
|
|
#include "nvim/api/private/helpers.h"
|
2014-09-19 09:49:37 +02:00
|
|
|
#include "nvim/api/private/handle.h"
|
2016-06-16 13:35:04 +02:00
|
|
|
#include "nvim/api/private/dispatch.h"
|
2017-07-10 01:58:54 +02:00
|
|
|
#ifndef WIN32
|
|
|
|
# include "nvim/os/pty_process_unix.h"
|
|
|
|
#endif
|
2017-06-23 09:56:35 +02:00
|
|
|
#include "nvim/api/vim.h"
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-04-11 01:28:33 +02:00
|
|
|
// Maximum number of commands from + or -c arguments.
|
2014-01-31 14:39:15 +01:00
|
|
|
#define MAX_ARG_CMDS 10
|
|
|
|
|
2018-04-11 01:28:33 +02:00
|
|
|
// values for "window_layout"
|
|
|
|
#define WIN_HOR 1 // "-o" horizontally split windows
|
|
|
|
#define WIN_VER 2 // "-O" vertically split windows
|
|
|
|
#define WIN_TABS 3 // "-p" windows on tab pages
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-04-11 01:28:33 +02:00
|
|
|
// Struct for various parameters passed between main() and other functions.
|
2014-01-31 14:39:15 +01:00
|
|
|
typedef struct {
|
|
|
|
int argc;
|
|
|
|
char **argv;
|
|
|
|
|
2015-05-13 21:29:49 +02:00
|
|
|
char *use_vimrc; // vimrc from -u argument
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-04-11 01:28:33 +02:00
|
|
|
int n_commands; // no. of commands from + or -c
|
2015-05-13 21:29:49 +02:00
|
|
|
char *commands[MAX_ARG_CMDS]; // commands from + or -c arg
|
2018-04-11 01:28:33 +02:00
|
|
|
char_u cmds_tofree[MAX_ARG_CMDS]; // commands that need free()
|
|
|
|
int n_pre_commands; // no. of commands from --cmd
|
2015-05-13 21:29:49 +02:00
|
|
|
char *pre_commands[MAX_ARG_CMDS]; // commands from --cmd argument
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-04-11 01:28:33 +02:00
|
|
|
int edit_type; // type of editing to do
|
|
|
|
char_u *tagname; // tag from -t argument
|
|
|
|
char_u *use_ef; // 'errorfile' from -q argument
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-02-13 16:06:01 +01:00
|
|
|
bool input_isatty; // stdin is a terminal
|
|
|
|
bool output_isatty; // stdout is a terminal
|
|
|
|
bool err_isatty; // stderr is a terminal
|
2017-08-06 02:44:15 +02:00
|
|
|
int no_swap_file; // "-n" argument used
|
2014-01-31 14:39:15 +01:00
|
|
|
int use_debug_break_level;
|
2018-04-11 01:28:33 +02:00
|
|
|
int window_count; // number of windows to use
|
|
|
|
int window_layout; // 0, WIN_HOR, WIN_VER or WIN_TABS
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-04-11 01:28:33 +02:00
|
|
|
int diff_mode; // start with 'diff' set
|
2018-04-08 17:20:25 +02:00
|
|
|
|
|
|
|
char *listen_addr; // --listen {address}
|
2014-01-31 14:39:15 +01:00
|
|
|
} mparm_T;
|
|
|
|
|
2019-04-10 03:27:25 +02:00
|
|
|
// Values for edit_type.
|
|
|
|
#define EDIT_NONE 0 // no edit type yet
|
|
|
|
#define EDIT_FILE 1 // file name argument[s] given, use argument list
|
|
|
|
#define EDIT_STDIN 2 // read file from stdin
|
|
|
|
#define EDIT_TAG 3 // tag name argument given, use tagname
|
|
|
|
#define EDIT_QF 4 // start in quickfix mode
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-05-10 15:24:13 +02:00
|
|
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
|
|
|
# include "main.c.generated.h"
|
|
|
|
#endif
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2016-05-30 19:55:29 +02:00
|
|
|
Loop main_loop;
|
|
|
|
|
2017-05-17 03:23:34 +02:00
|
|
|
static char *argv0 = NULL;
|
2015-05-30 07:06:19 +02:00
|
|
|
|
2015-01-24 01:42:21 +01:00
|
|
|
// Error messages
|
2015-05-30 07:06:19 +02:00
|
|
|
static const char *err_arg_missing = N_("Argument missing after");
|
|
|
|
static const char *err_opt_garbage = N_("Garbage after option argument");
|
|
|
|
static const char *err_opt_unknown = N_("Unknown option argument");
|
|
|
|
static const char *err_too_many_args = N_("Too many edit arguments");
|
|
|
|
static const char *err_extra_cmd =
|
|
|
|
N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments");
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-01-24 01:42:21 +01:00
|
|
|
|
2015-07-17 04:10:04 +02:00
|
|
|
void event_init(void)
|
|
|
|
{
|
2019-06-12 14:22:42 +02:00
|
|
|
log_init();
|
2016-05-30 19:55:29 +02:00
|
|
|
loop_init(&main_loop, NULL);
|
2015-07-17 04:10:04 +02:00
|
|
|
// early msgpack-rpc initialization
|
|
|
|
msgpack_rpc_init_method_table();
|
|
|
|
msgpack_rpc_helpers_init();
|
|
|
|
input_init();
|
|
|
|
signal_init();
|
|
|
|
// finish mspgack-rpc initialization
|
|
|
|
channel_init();
|
2017-06-23 09:56:35 +02:00
|
|
|
remote_ui_init();
|
|
|
|
api_vim_init();
|
2015-07-17 04:10:04 +02:00
|
|
|
terminal_init();
|
2018-02-03 20:11:31 +01:00
|
|
|
ui_init();
|
2015-07-17 04:10:04 +02:00
|
|
|
}
|
|
|
|
|
2017-05-30 01:25:25 +02:00
|
|
|
/// @returns false if main_loop could not be closed gracefully
|
|
|
|
bool event_teardown(void)
|
2015-07-17 04:10:04 +02:00
|
|
|
{
|
2016-05-30 19:55:29 +02:00
|
|
|
if (!main_loop.events) {
|
2018-05-27 03:41:02 +02:00
|
|
|
input_stop();
|
2017-05-30 01:25:25 +02:00
|
|
|
return true;
|
2015-07-17 04:10:04 +02:00
|
|
|
}
|
|
|
|
|
2016-09-29 17:09:37 +02:00
|
|
|
multiqueue_process_events(main_loop.events);
|
2018-09-16 11:22:32 +02:00
|
|
|
loop_poll_events(&main_loop, 0); // Drain thread_events, fast_events.
|
2015-07-17 04:10:04 +02:00
|
|
|
input_stop();
|
|
|
|
channel_teardown();
|
2016-05-30 19:55:29 +02:00
|
|
|
process_teardown(&main_loop);
|
2016-05-28 11:16:03 +02:00
|
|
|
timer_teardown();
|
2015-07-17 04:10:04 +02:00
|
|
|
server_teardown();
|
|
|
|
signal_teardown();
|
|
|
|
terminal_teardown();
|
|
|
|
|
2017-05-30 01:25:25 +02:00
|
|
|
return loop_close(&main_loop, true);
|
2015-07-17 04:10:04 +02:00
|
|
|
}
|
|
|
|
|
2014-09-19 09:49:37 +02:00
|
|
|
/// Performs early initialization.
|
|
|
|
///
|
|
|
|
/// Needed for unit tests. Must be called after `time_init()`.
|
|
|
|
void early_init(void)
|
|
|
|
{
|
2019-02-24 20:09:14 +01:00
|
|
|
env_init();
|
2015-05-20 13:06:43 +02:00
|
|
|
fs_init();
|
2014-09-19 09:49:37 +02:00
|
|
|
handle_init();
|
|
|
|
eval_init(); // init global variables
|
2017-05-17 03:23:34 +02:00
|
|
|
init_path(argv0 ? argv0 : "nvim");
|
|
|
|
init_normal_cmds(); // Init the table of Normal mode commands.
|
2018-04-08 09:51:22 +02:00
|
|
|
highlight_init();
|
2014-09-19 09:49:37 +02:00
|
|
|
|
2015-05-30 07:06:19 +02:00
|
|
|
#if defined(HAVE_LOCALE_H)
|
2014-09-19 09:49:37 +02:00
|
|
|
// Setup to use the current locale (for ctype() and many other things).
|
|
|
|
// NOTE: Translated messages with encodings other than latin1 will not
|
|
|
|
// work until set_init_1() has been called!
|
|
|
|
init_locale();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Allocate the first window and buffer.
|
|
|
|
// Can't do anything without it, exit when it fails.
|
|
|
|
if (!win_alloc_first()) {
|
|
|
|
mch_exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
init_yank(); // init yank buffers
|
|
|
|
|
|
|
|
alist_init(&global_alist); // Init the argument list to empty.
|
|
|
|
global_alist.id = 0;
|
|
|
|
|
|
|
|
// Set the default values for the options.
|
|
|
|
// NOTE: Non-latin1 translated messages are working only after this,
|
|
|
|
// because this is where "has_mbyte" will be set, which is used by
|
|
|
|
// msg_outtrans_len_attr().
|
|
|
|
// First find out the home directory, needed to expand "~" in options.
|
|
|
|
init_homedir(); // find real value of $HOME
|
|
|
|
set_init_1();
|
|
|
|
TIME_MSG("inits 1");
|
|
|
|
|
|
|
|
set_lang_var(); // set v:lang and v:ctype
|
2019-06-12 14:22:42 +02:00
|
|
|
|
|
|
|
init_signs();
|
2014-09-19 09:49:37 +02:00
|
|
|
}
|
|
|
|
|
2014-12-01 03:22:46 +01:00
|
|
|
#ifdef MAKE_LIB
|
2019-01-30 02:26:12 +01:00
|
|
|
int nvim_main(int argc, char **argv); // silence -Wmissing-prototypes
|
2014-12-01 03:22:46 +01:00
|
|
|
int nvim_main(int argc, char **argv)
|
2017-08-23 01:17:59 +02:00
|
|
|
#elif defined(WIN32)
|
|
|
|
int wmain(int argc, wchar_t **argv_w) // multibyte args on Windows. #7060
|
2014-12-01 03:22:46 +01:00
|
|
|
#else
|
2014-05-17 22:34:16 +02:00
|
|
|
int main(int argc, char **argv)
|
2014-12-01 03:22:46 +01:00
|
|
|
#endif
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
2017-08-23 01:30:25 +02:00
|
|
|
#if defined(WIN32) && !defined(MAKE_LIB)
|
2018-01-17 12:44:04 +01:00
|
|
|
char **argv = xmalloc((size_t)argc * sizeof(char *));
|
2017-08-23 01:17:59 +02:00
|
|
|
for (int i = 0; i < argc; i++) {
|
|
|
|
char *buf = NULL;
|
|
|
|
utf16_to_utf8(argv_w[i], &buf);
|
|
|
|
assert(buf);
|
2017-08-23 00:55:00 +02:00
|
|
|
argv[i] = buf;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-05-17 03:23:34 +02:00
|
|
|
argv0 = argv[0];
|
2015-05-30 07:06:19 +02:00
|
|
|
|
2016-02-03 19:47:55 +01:00
|
|
|
char_u *fname = NULL; // file name from command line
|
|
|
|
mparm_T params; // various parameters passed between
|
|
|
|
// main() and other functions.
|
2017-12-27 19:30:23 +01:00
|
|
|
char_u *cwd = NULL; // current working dir on startup
|
2014-09-19 09:49:37 +02:00
|
|
|
time_init();
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-04-08 17:20:25 +02:00
|
|
|
// Many variables are in `params` so that we can pass them around easily.
|
|
|
|
// `argc` and `argv` are also copied, so that they can be changed.
|
2014-02-22 04:55:12 +01:00
|
|
|
init_params(¶ms, argc, argv);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-22 04:55:12 +01:00
|
|
|
init_startuptime(¶ms);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2019-06-12 14:22:42 +02:00
|
|
|
event_init();
|
|
|
|
|
2014-09-19 09:49:37 +02:00
|
|
|
early_init();
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-02-13 16:06:01 +01:00
|
|
|
// Check if we have an interactive window.
|
2014-02-22 04:55:12 +01:00
|
|
|
check_and_set_isatty(¶ms);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-04-08 17:20:25 +02:00
|
|
|
// Process the command line arguments. File names are put in the global
|
|
|
|
// argument list "global_alist".
|
2014-01-31 14:39:15 +01:00
|
|
|
command_line_scan(¶ms);
|
2018-10-02 04:58:47 +02:00
|
|
|
|
|
|
|
if (embedded_mode) {
|
|
|
|
const char *err;
|
|
|
|
if (!channel_from_stdio(true, CALLBACK_READER_INIT, &err)) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-08 17:20:25 +02:00
|
|
|
server_init(params.listen_addr);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2016-02-09 20:55:40 +01:00
|
|
|
if (GARGCOUNT > 0) {
|
|
|
|
fname = get_fname(¶ms, cwd);
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
|
|
|
TIME_MSG("expanding arguments");
|
|
|
|
|
|
|
|
if (params.diff_mode && params.window_count == -1)
|
|
|
|
params.window_count = 0; /* open up to 3 windows */
|
|
|
|
|
|
|
|
/* Don't redraw until much later. */
|
|
|
|
++RedrawingDisabled;
|
|
|
|
|
2015-02-17 03:47:56 +01:00
|
|
|
setbuf(stdout, NULL);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-26 17:18:52 +02:00
|
|
|
full_screen = !silent_mode;
|
2017-12-03 02:44:22 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
// Set the default values for the options that use Rows and Columns.
|
2014-01-31 14:39:15 +01:00
|
|
|
win_init_size();
|
2015-10-17 16:25:53 +02:00
|
|
|
// Set the 'diff' option now, so that it can be checked for in a vimrc
|
|
|
|
// file. There is no buffer yet though.
|
2018-05-24 11:51:35 +02:00
|
|
|
if (params.diff_mode) {
|
|
|
|
diff_win_options(firstwin, false);
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-01-24 01:42:21 +01:00
|
|
|
assert(p_ch >= 0 && Rows >= p_ch && Rows - p_ch <= INT_MAX);
|
|
|
|
cmdline_row = (int)(Rows - p_ch);
|
2014-01-31 14:39:15 +01:00
|
|
|
msg_row = cmdline_row;
|
2019-02-07 13:05:25 +01:00
|
|
|
screenalloc(); // allocate screen buffers
|
2017-06-05 08:29:10 +02:00
|
|
|
set_init_2(headless_mode);
|
2014-01-31 14:39:15 +01:00
|
|
|
TIME_MSG("inits 2");
|
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
msg_scroll = true;
|
|
|
|
no_wait_return = true;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
init_highlight(true, false); // Default highlight groups.
|
2014-01-31 14:39:15 +01:00
|
|
|
TIME_MSG("init highlight");
|
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
// Set the break level after the terminal is initialized.
|
2014-01-31 14:39:15 +01:00
|
|
|
debug_break_level = params.use_debug_break_level;
|
|
|
|
|
2018-05-29 07:22:15 +02:00
|
|
|
// Read ex-commands if invoked with "-es".
|
2019-06-04 09:14:45 +02:00
|
|
|
if (!params.input_isatty && silent_mode && exmode_active == EXMODE_NORMAL) {
|
|
|
|
input_start(STDIN_FILENO);
|
2015-03-18 16:46:04 +01:00
|
|
|
}
|
|
|
|
|
2015-03-08 12:58:31 +01:00
|
|
|
// open terminals when opening files that start with term://
|
2016-02-28 04:29:38 +01:00
|
|
|
#define PROTO "term://"
|
2016-10-09 16:00:12 +02:00
|
|
|
do_cmdline_cmd("augroup nvim_terminal");
|
|
|
|
do_cmdline_cmd("autocmd!");
|
2016-02-28 04:29:38 +01:00
|
|
|
do_cmdline_cmd("autocmd BufReadCmd " PROTO "* nested "
|
2016-10-09 16:00:12 +02:00
|
|
|
":if !exists('b:term_title')|call termopen( "
|
2015-05-13 21:29:49 +02:00
|
|
|
// Capture the command string
|
|
|
|
"matchstr(expand(\"<amatch>\"), "
|
2016-02-28 04:29:38 +01:00
|
|
|
"'\\c\\m" PROTO "\\%(.\\{-}//\\%(\\d\\+:\\)\\?\\)\\?\\zs.*'), "
|
2015-05-13 21:29:49 +02:00
|
|
|
// capture the working directory
|
|
|
|
"{'cwd': get(matchlist(expand(\"<amatch>\"), "
|
2016-10-09 16:00:12 +02:00
|
|
|
"'\\c\\m" PROTO "\\(.\\{-}\\)//'), 1, '')})"
|
|
|
|
"|endif");
|
|
|
|
do_cmdline_cmd("augroup END");
|
2016-02-28 04:29:38 +01:00
|
|
|
#undef PROTO
|
2015-03-08 12:58:31 +01:00
|
|
|
|
2017-03-21 17:07:00 +01:00
|
|
|
// Reset 'loadplugins' for "-u NONE" before "--cmd" arguments.
|
|
|
|
// Allows for setting 'loadplugins' there.
|
2018-05-29 07:22:15 +02:00
|
|
|
if (params.use_vimrc != NULL && strequal(params.use_vimrc, "NONE")) {
|
2017-03-21 17:07:00 +01:00
|
|
|
p_lpl = false;
|
|
|
|
}
|
|
|
|
|
2019-06-30 00:09:45 +02:00
|
|
|
// Wait for UIs to set up Nvim or show early messages
|
|
|
|
// and prompts (--cmd, swapfile dialog, …).
|
2019-04-10 14:02:21 +02:00
|
|
|
bool use_remote_ui = (embedded_mode && !headless_mode);
|
|
|
|
bool use_builtin_ui = (!headless_mode && !embedded_mode && !silent_mode);
|
|
|
|
if (use_remote_ui || use_builtin_ui) {
|
2019-06-04 09:14:45 +02:00
|
|
|
TIME_MSG("waiting for UI to make request");
|
2019-04-12 20:39:47 +02:00
|
|
|
if (use_remote_ui) {
|
2019-04-10 14:02:21 +02:00
|
|
|
remote_ui_wait_for_attach();
|
|
|
|
} else {
|
|
|
|
ui_builtin_start();
|
|
|
|
}
|
2019-06-04 09:14:45 +02:00
|
|
|
TIME_MSG("done waiting for UI");
|
2018-07-18 13:31:23 +02:00
|
|
|
|
2018-09-20 19:19:38 +02:00
|
|
|
// prepare screen now, so external UIs can display messages
|
|
|
|
starting = NO_BUFFERS;
|
|
|
|
screenclear();
|
2019-06-04 09:14:45 +02:00
|
|
|
TIME_MSG("initialized screen early for UI");
|
2018-07-18 13:31:23 +02:00
|
|
|
}
|
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
// Execute --cmd arguments.
|
2014-02-01 15:17:43 +01:00
|
|
|
exe_pre_commands(¶ms);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
// Source startup scripts.
|
2014-02-01 15:17:43 +01:00
|
|
|
source_startup_scripts(¶ms);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2016-02-12 18:02:42 +01:00
|
|
|
// If using the runtime (-u is not NONE), enable syntax & filetype plugins.
|
2018-05-24 11:51:35 +02:00
|
|
|
if (params.use_vimrc == NULL || !strequal(params.use_vimrc, "NONE")) {
|
2016-02-14 21:14:38 +01:00
|
|
|
// Does ":filetype plugin indent on".
|
|
|
|
filetype_maybe_enable();
|
|
|
|
// Sources syntax/syntax.vim, which calls `:filetype on`.
|
|
|
|
syn_maybe_on();
|
2015-05-16 09:10:38 +02:00
|
|
|
}
|
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* Read all the plugin files.
|
|
|
|
* Only when compiled with +eval, since most plugins need it.
|
|
|
|
*/
|
2014-02-22 04:55:12 +01:00
|
|
|
load_plugins();
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-10-17 16:25:53 +02:00
|
|
|
// Decide about window layout for diff mode after reading vimrc.
|
2014-02-22 04:55:12 +01:00
|
|
|
set_window_layout(¶ms);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* Recovery mode without a file name: List swap files.
|
|
|
|
* This uses the 'dir' option, therefore it must be after the
|
|
|
|
* initializations.
|
|
|
|
*/
|
|
|
|
if (recoverymode && fname == NULL) {
|
|
|
|
recover_names(NULL, TRUE, 0, NULL);
|
|
|
|
mch_exit(0);
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-27 03:41:02 +02:00
|
|
|
// Set a few option defaults after reading vimrc files: 'title', 'icon',
|
|
|
|
// 'shellpipe', 'shellredir'.
|
2014-02-01 15:17:43 +01:00
|
|
|
set_init_3();
|
|
|
|
TIME_MSG("inits 3");
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-27 03:41:02 +02:00
|
|
|
// "-n" argument: Disable swap file by setting 'updatecount' to 0.
|
|
|
|
// Note that this overrides anything from a vimrc file.
|
|
|
|
if (params.no_swap_file) {
|
2014-02-01 15:17:43 +01:00
|
|
|
p_uc = 0;
|
2018-05-27 03:41:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXX: Minimize 'updatetime' for -es/-Es. #7679
|
|
|
|
if (silent_mode) {
|
|
|
|
p_ut = 1;
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2019-02-17 10:54:00 +01:00
|
|
|
//
|
|
|
|
// Read in registers, history etc, from the ShaDa file.
|
|
|
|
// This is where v:oldfiles gets filled.
|
|
|
|
//
|
2015-07-06 01:16:05 +02:00
|
|
|
if (*p_shada != NUL) {
|
2015-07-25 18:42:04 +02:00
|
|
|
shada_read_everything(NULL, false, true);
|
viminfo: First version of ShaDa file dumping
What works:
1. ShaDa file dumping: header, registers, jump list, history, search patterns,
substitute strings, variables.
2. ShaDa file reading: registers, global marks, variables.
Most was not tested.
TODO:
1. Merging.
2. Reading history, local marks, jump and buffer lists.
3. Documentation update.
4. Converting some data from &encoding.
5. Safer variant of dumping viminfo (dump to temporary file then rename).
6. Removing old viminfo code (currently masked with `#if 0` in a ShaDa file for
reference).
2015-04-25 17:47:31 +02:00
|
|
|
TIME_MSG("reading ShaDa");
|
2014-02-01 15:17:43 +01:00
|
|
|
}
|
2016-07-26 22:16:23 +02:00
|
|
|
// It's better to make v:oldfiles an empty list than NULL.
|
|
|
|
if (get_vim_var_list(VV_OLDFILES) == NULL) {
|
2018-01-02 22:00:16 +01:00
|
|
|
set_vim_var_list(VV_OLDFILES, tv_list_alloc(0));
|
2016-07-26 22:16:23 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* "-q errorfile": Load the error file now.
|
|
|
|
* If the error file can't be read, exit before doing anything else.
|
|
|
|
*/
|
2014-02-22 04:55:12 +01:00
|
|
|
handle_quickfix(¶ms);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* Start putting things on the screen.
|
|
|
|
* Scroll screen down before drawing over it
|
|
|
|
* Clear screen now, so file message will not be cleared.
|
|
|
|
*/
|
|
|
|
starting = NO_BUFFERS;
|
2017-12-03 04:44:46 +01:00
|
|
|
no_wait_return = false;
|
|
|
|
if (!exmode_active) {
|
|
|
|
msg_scroll = false;
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
// Read file (text, not commands) from stdin if:
|
|
|
|
// - stdin is not a tty
|
|
|
|
// - and -e/-es was not given
|
2017-12-03 04:44:46 +01:00
|
|
|
//
|
|
|
|
// 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) {
|
2014-02-01 15:17:43 +01:00
|
|
|
read_stdin();
|
2017-12-03 04:44:46 +01:00
|
|
|
}
|
2015-03-17 18:49:09 +01:00
|
|
|
|
2014-12-06 15:27:36 +01:00
|
|
|
setmouse(); // may start using the mouse
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2019-06-30 00:09:45 +02:00
|
|
|
if (exmode_active || use_remote_ui || use_builtin_ui) {
|
2019-06-04 09:14:45 +02:00
|
|
|
// Don't clear the screen when starting in Ex mode, or when a UI might have
|
|
|
|
// displayed messages.
|
2019-04-14 14:06:53 +02:00
|
|
|
redraw_later(VALID);
|
2018-05-27 03:41:02 +02:00
|
|
|
} else {
|
2018-05-24 11:51:35 +02:00
|
|
|
screenclear(); // clear screen
|
2014-02-01 15:17:43 +01:00
|
|
|
TIME_MSG("clearing screen");
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
no_wait_return = true;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* Create the requested number of windows and edit buffers in them.
|
|
|
|
* Also does recovery if "recoverymode" set.
|
|
|
|
*/
|
|
|
|
create_windows(¶ms);
|
|
|
|
TIME_MSG("opening buffers");
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/* clear v:swapcommand */
|
|
|
|
set_vim_var_string(VV_SWAPCOMMAND, NULL, -1);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/* Ex starts at last line of the file */
|
|
|
|
if (exmode_active)
|
|
|
|
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
|
|
|
|
TIME_MSG("BufEnter autocommands");
|
|
|
|
setpcmark();
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* When started with "-q errorfile" jump to first error now.
|
|
|
|
*/
|
|
|
|
if (params.edit_type == EDIT_QF) {
|
|
|
|
qf_jump(NULL, 0, 0, FALSE);
|
|
|
|
TIME_MSG("jump to first error");
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2016-02-03 19:47:55 +01:00
|
|
|
// If opened more than one window, start editing files in the other
|
|
|
|
// windows.
|
|
|
|
edit_buffers(¶ms, cwd);
|
|
|
|
xfree(cwd);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
if (params.diff_mode) {
|
2015-01-20 01:37:13 +01:00
|
|
|
/* set options in each window for "nvim -d". */
|
2014-09-20 06:28:50 +02:00
|
|
|
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
2014-02-01 15:17:43 +01:00
|
|
|
diff_win_options(wp, TRUE);
|
2014-08-21 02:39:05 +02:00
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* Shorten any of the filenames, but only when absolute.
|
|
|
|
*/
|
|
|
|
shorten_fnames(FALSE);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* Need to jump to the tag before executing the '-c command'.
|
|
|
|
* Makes "vim -c '/return' -t main" work.
|
|
|
|
*/
|
2014-02-22 04:55:12 +01:00
|
|
|
handle_tag(params.tagname);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/* Execute any "+", "-c" and "-S" arguments. */
|
|
|
|
if (params.n_commands > 0)
|
|
|
|
exe_commands(¶ms);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2019-03-30 12:40:41 +01:00
|
|
|
starting = 0;
|
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
RedrawingDisabled = 0;
|
|
|
|
redraw_all_later(NOT_VALID);
|
2019-03-29 13:09:54 +01:00
|
|
|
no_wait_return = false;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2016-07-01 11:34:43 +02:00
|
|
|
// 'autochdir' has been postponed.
|
|
|
|
do_autochdir();
|
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/* start in insert mode */
|
|
|
|
if (p_im)
|
|
|
|
need_start_insertmode = TRUE;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2016-11-14 16:19:06 +01:00
|
|
|
set_vim_var_nr(VV_VIM_DID_ENTER, 1L);
|
2016-11-14 17:35:19 +01:00
|
|
|
apply_autocmds(EVENT_VIMENTER, NULL, NULL, false, curbuf);
|
2014-02-01 15:17:43 +01:00
|
|
|
TIME_MSG("VimEnter autocommands");
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2017-03-18 19:33:25 +01:00
|
|
|
// Adjust default register name for "unnamed" in 'clipboard'. Can only be
|
|
|
|
// done after the clipboard is available and all initial commands that may
|
|
|
|
// modify the 'clipboard' setting have run; i.e. just before entering the
|
|
|
|
// main loop.
|
|
|
|
set_reg_var(get_default_register_name());
|
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/* When a startup script or session file setup for diff'ing and
|
|
|
|
* scrollbind, sync the scrollbind now. */
|
|
|
|
if (curwin->w_p_diff && curwin->w_p_scb) {
|
|
|
|
update_topline();
|
|
|
|
check_scrollbind((linenr_T)0, 0L);
|
|
|
|
TIME_MSG("diff scrollbinding");
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/* If ":startinsert" command used, stuff a dummy command to be able to
|
|
|
|
* call normal_cmd(), which will then start Insert mode. */
|
|
|
|
if (restart_edit != 0)
|
|
|
|
stuffcharReadbuff(K_NOP);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-07-16 18:01:54 +02:00
|
|
|
// WORKAROUND(mhi): #3023
|
|
|
|
if (cb_flags & CB_UNNAMEDMASK) {
|
|
|
|
(void)eval_has_provider("clipboard");
|
|
|
|
}
|
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
TIME_MSG("before starting main loop");
|
2016-09-30 02:33:50 +02:00
|
|
|
ILOG("starting main loop");
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2014-02-01 15:17:43 +01:00
|
|
|
/*
|
|
|
|
* Call the main command loop. This never returns.
|
|
|
|
*/
|
2015-10-04 14:36:34 +02:00
|
|
|
normal_enter(false, false);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-01-17 12:44:04 +01:00
|
|
|
#if defined(WIN32) && !defined(MAKE_LIB)
|
|
|
|
xfree(argv);
|
|
|
|
#endif
|
2014-02-01 15:17:43 +01:00
|
|
|
return 0;
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
|
2018-02-07 02:32:50 +01:00
|
|
|
/// Exit properly
|
2014-02-23 21:34:45 +01:00
|
|
|
void getout(int exitval)
|
2018-02-07 02:32:50 +01:00
|
|
|
FUNC_ATTR_NORETURN
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
2019-06-17 01:52:56 +02:00
|
|
|
exiting = true;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
|
|
|
/* When running in Ex mode an error causes us to exit with a non-zero exit
|
|
|
|
* code. POSIX requires this, although it's not 100% clear from the
|
|
|
|
* standard. */
|
|
|
|
if (exmode_active)
|
|
|
|
exitval += ex_exitval;
|
|
|
|
|
2016-11-22 14:53:07 +01:00
|
|
|
set_vim_var_nr(VV_EXITING, exitval);
|
|
|
|
|
2014-01-31 14:39:15 +01:00
|
|
|
/* Position the cursor on the last screen line, below all the text */
|
2015-02-17 03:47:56 +01:00
|
|
|
ui_cursor_goto((int)Rows - 1, 0);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
|
|
|
/* Optionally print hashtable efficiency. */
|
|
|
|
hash_debug_results();
|
|
|
|
|
|
|
|
if (get_vim_var_nr(VV_DYING) <= 1) {
|
2019-06-17 01:52:56 +02:00
|
|
|
const tabpage_T *next_tp;
|
|
|
|
|
|
|
|
// Trigger BufWinLeave for all windows, but only once per buffer.
|
|
|
|
for (const tabpage_T *tp = first_tabpage; tp != NULL; tp = next_tp) {
|
2014-01-31 14:39:15 +01:00
|
|
|
next_tp = tp->tp_next;
|
2014-08-23 19:03:14 +02:00
|
|
|
FOR_ALL_WINDOWS_IN_TAB(wp, tp) {
|
|
|
|
if (wp->w_buffer == NULL) {
|
2014-01-31 14:39:15 +01:00
|
|
|
/* Autocmd must have close the buffer already, skip. */
|
|
|
|
continue;
|
2014-08-23 19:03:14 +02:00
|
|
|
}
|
|
|
|
|
2014-08-11 05:56:58 +02:00
|
|
|
buf_T *buf = wp->w_buffer;
|
2018-06-21 23:44:31 +02:00
|
|
|
if (buf_get_changedtick(buf) != -1) {
|
2018-08-25 03:16:34 +02:00
|
|
|
bufref_T bufref;
|
|
|
|
|
|
|
|
set_bufref(&bufref, buf);
|
2014-01-31 14:39:15 +01:00
|
|
|
apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname,
|
2017-02-22 23:38:54 +01:00
|
|
|
buf->b_fname, false, buf);
|
2018-08-25 03:16:34 +02:00
|
|
|
if (bufref_valid(&bufref)) {
|
|
|
|
buf_set_changedtick(buf, -1); // note that we did it already
|
|
|
|
}
|
2017-02-15 00:00:45 +01:00
|
|
|
// start all over, autocommands may mess up the lists
|
2014-01-31 14:39:15 +01:00
|
|
|
next_tp = first_tabpage;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Trigger BufUnload for buffers that are loaded */
|
2014-08-03 03:19:33 +02:00
|
|
|
FOR_ALL_BUFFERS(buf) {
|
2014-01-31 14:39:15 +01:00
|
|
|
if (buf->b_ml.ml_mfp != NULL) {
|
2017-01-09 14:35:04 +01:00
|
|
|
bufref_T bufref;
|
|
|
|
set_bufref(&bufref, buf);
|
|
|
|
apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname, false, buf);
|
|
|
|
if (!bufref_valid(&bufref)) {
|
|
|
|
// Autocmd deleted the buffer.
|
2014-01-31 14:39:15 +01:00
|
|
|
break;
|
2017-01-09 14:35:04 +01:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
2014-08-03 03:19:33 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
apply_autocmds(EVENT_VIMLEAVEPRE, NULL, NULL, FALSE, curbuf);
|
|
|
|
}
|
|
|
|
|
2015-07-06 01:16:05 +02:00
|
|
|
if (p_shada && *p_shada != NUL) {
|
|
|
|
// Write out the registers, history, marks etc, to the ShaDa file
|
viminfo: First version of ShaDa file dumping
What works:
1. ShaDa file dumping: header, registers, jump list, history, search patterns,
substitute strings, variables.
2. ShaDa file reading: registers, global marks, variables.
Most was not tested.
TODO:
1. Merging.
2. Reading history, local marks, jump and buffer lists.
3. Documentation update.
4. Converting some data from &encoding.
5. Safer variant of dumping viminfo (dump to temporary file then rename).
6. Removing old viminfo code (currently masked with `#if 0` in a ShaDa file for
reference).
2015-04-25 17:47:31 +02:00
|
|
|
shada_write_file(NULL, false);
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
|
|
|
if (get_vim_var_nr(VV_DYING) <= 1)
|
|
|
|
apply_autocmds(EVENT_VIMLEAVE, NULL, NULL, FALSE, curbuf);
|
|
|
|
|
|
|
|
profile_dump();
|
|
|
|
|
|
|
|
if (did_emsg
|
2014-02-01 15:17:43 +01:00
|
|
|
) {
|
2014-01-31 14:39:15 +01:00
|
|
|
/* give the user a chance to read the (error) message */
|
|
|
|
no_wait_return = FALSE;
|
|
|
|
wait_return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Position the cursor again, the autocommands may have moved it */
|
2015-02-17 03:47:56 +01:00
|
|
|
ui_cursor_goto((int)Rows - 1, 0);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2017-10-05 09:49:17 +02:00
|
|
|
// Apply 'titleold'.
|
|
|
|
if (p_title && *p_titleold != NUL) {
|
|
|
|
ui_call_set_title(cstr_as_string((char *)p_titleold));
|
|
|
|
}
|
|
|
|
|
2014-01-31 14:39:15 +01:00
|
|
|
#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
|
|
|
|
iconv_end();
|
|
|
|
#endif
|
|
|
|
cs_end();
|
2017-01-06 01:13:23 +01:00
|
|
|
if (garbage_collect_at_exit) {
|
|
|
|
garbage_collect(false);
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
|
|
|
mch_exit(exitval);
|
|
|
|
}
|
|
|
|
|
2015-01-24 01:42:21 +01:00
|
|
|
/// Gets the integer value of a numeric command line argument if given,
|
|
|
|
/// such as '-o10'.
|
|
|
|
///
|
|
|
|
/// @param[in] p pointer to argument
|
|
|
|
/// @param[in, out] idx pointer to index in argument, is incremented
|
|
|
|
/// @param[in] def default value
|
|
|
|
///
|
|
|
|
/// @return def unmodified if:
|
|
|
|
/// - argument isn't given
|
|
|
|
/// - argument is non-numeric
|
|
|
|
///
|
|
|
|
/// @return argument's numeric value otherwise
|
|
|
|
static int get_number_arg(const char *p, int *idx, int def)
|
2017-05-20 03:08:41 +02:00
|
|
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
2017-05-20 03:08:41 +02:00
|
|
|
if (ascii_isdigit(p[*idx])) { // -V522
|
2015-01-24 01:42:21 +01:00
|
|
|
def = atoi(&(p[*idx]));
|
2015-04-23 00:47:53 +02:00
|
|
|
while (ascii_isdigit(p[*idx])) {
|
2014-01-31 14:39:15 +01:00
|
|
|
*idx = *idx + 1;
|
2015-01-24 01:42:21 +01:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2015-05-30 07:06:19 +02:00
|
|
|
#if defined(HAVE_LOCALE_H)
|
2017-12-03 04:44:46 +01:00
|
|
|
/// Setup to use the current locale (for ctype() and many other things).
|
2014-03-16 08:20:00 +01:00
|
|
|
static void init_locale(void)
|
|
|
|
{
|
2014-01-31 14:39:15 +01:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
|
2014-04-12 08:28:46 +02:00
|
|
|
# ifdef LC_NUMERIC
|
2014-01-31 14:39:15 +01:00
|
|
|
/* Make sure strtod() uses a decimal point, not a comma. */
|
|
|
|
setlocale(LC_NUMERIC, "C");
|
|
|
|
# endif
|
|
|
|
|
2016-02-17 15:16:25 +01:00
|
|
|
# ifdef LOCALE_INSTALL_DIR // gnu/linux standard: $prefix/share/locale
|
|
|
|
bindtextdomain(PROJECT_NAME, LOCALE_INSTALL_DIR);
|
|
|
|
# else // old vim style: $runtime/lang
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
|
|
|
char_u *p;
|
|
|
|
|
2016-07-10 23:05:06 +02:00
|
|
|
// expand_env() doesn't work yet, because g_chartab[] is not
|
|
|
|
// initialized yet, call vim_getenv() directly
|
2015-04-13 00:31:00 +02:00
|
|
|
p = (char_u *)vim_getenv("VIMRUNTIME");
|
2014-05-01 20:00:13 +02:00
|
|
|
if (p != NULL && *p != NUL) {
|
2014-01-31 14:39:15 +01:00
|
|
|
vim_snprintf((char *)NameBuff, MAXPATHL, "%s/lang", p);
|
2016-02-17 15:16:25 +01:00
|
|
|
bindtextdomain(PROJECT_NAME, (char *)NameBuff);
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
2015-04-13 00:31:00 +02:00
|
|
|
xfree(p);
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
2016-02-17 15:16:25 +01:00
|
|
|
# endif
|
|
|
|
textdomain(PROJECT_NAME);
|
2014-02-22 04:55:12 +01:00
|
|
|
TIME_MSG("locale set");
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-05-23 10:54:09 +02:00
|
|
|
/// Decides whether text (as opposed to commands) will be read from stdin.
|
|
|
|
/// @see EDIT_STDIN
|
2018-05-28 07:09:55 +02:00
|
|
|
static bool edit_stdin(bool explicit, mparm_T *parmp)
|
2018-05-23 10:54:09 +02:00
|
|
|
{
|
2018-05-28 07:09:55 +02:00
|
|
|
bool implicit = !headless_mode
|
2018-05-23 10:54:09 +02:00
|
|
|
&& !embedded_mode
|
2018-05-23 02:28:31 +02:00
|
|
|
&& exmode_active != EXMODE_NORMAL // -E/-Es but not -e/-es.
|
2018-05-23 10:54:09 +02:00
|
|
|
&& !parmp->input_isatty
|
|
|
|
&& scriptin[0] == NULL; // `-s -` was not given.
|
2018-05-28 07:09:55 +02:00
|
|
|
return explicit || implicit;
|
2018-05-23 10:54:09 +02:00
|
|
|
}
|
|
|
|
|
2018-04-16 22:38:02 +02:00
|
|
|
/// Scan the command line arguments.
|
2014-02-23 21:34:45 +01:00
|
|
|
static void command_line_scan(mparm_T *parmp)
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
|
|
|
int argc = parmp->argc;
|
2018-05-24 11:51:35 +02:00
|
|
|
char **argv = parmp->argv;
|
|
|
|
int argv_idx; // index in argv[n][]
|
2018-05-28 07:09:55 +02:00
|
|
|
bool had_stdin_file = false; // found explicit "-" argument
|
|
|
|
bool had_minmin = false; // found "--" argument
|
2018-05-24 11:51:35 +02:00
|
|
|
int want_argument; // option argument with argument
|
2014-01-31 14:39:15 +01:00
|
|
|
int c;
|
|
|
|
long n;
|
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
argv_idx = 1; // active option letter is argv[0][argv_idx]
|
2014-01-31 14:39:15 +01:00
|
|
|
while (argc > 0) {
|
2018-05-24 11:51:35 +02:00
|
|
|
// "+" or "+{number}" or "+/{pat}" or "+{command}" argument.
|
2014-01-31 14:39:15 +01:00
|
|
|
if (argv[0][0] == '+' && !had_minmin) {
|
2018-05-24 11:51:35 +02:00
|
|
|
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_extra_cmd, NULL);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
argv_idx = -1; // skip to next argument
|
|
|
|
if (argv[0][1] == NUL) {
|
2015-05-13 21:29:49 +02:00
|
|
|
parmp->commands[parmp->n_commands++] = "$";
|
2018-05-24 11:51:35 +02:00
|
|
|
} else {
|
2015-05-13 21:29:49 +02:00
|
|
|
parmp->commands[parmp->n_commands++] = &(argv[0][1]);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Optional argument.
|
|
|
|
} else if (argv[0][0] == '-' && !had_minmin) {
|
|
|
|
want_argument = false;
|
2014-01-31 14:39:15 +01:00
|
|
|
c = argv[0][argv_idx++];
|
|
|
|
switch (c) {
|
2018-05-24 11:51:35 +02:00
|
|
|
case NUL: { // "nvim -" read from stdin
|
2015-02-13 16:06:01 +01:00
|
|
|
if (exmode_active) {
|
2018-05-24 11:51:35 +02:00
|
|
|
// "nvim -e -" silent mode
|
|
|
|
silent_mode = true;
|
2019-04-10 03:27:25 +02:00
|
|
|
parmp->no_swap_file = true;
|
2015-02-13 16:06:01 +01:00
|
|
|
} else {
|
2018-05-28 07:09:55 +02:00
|
|
|
if (parmp->edit_type != EDIT_NONE
|
|
|
|
&& parmp->edit_type != EDIT_FILE
|
|
|
|
&& parmp->edit_type != EDIT_STDIN) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_too_many_args, argv[0]);
|
2015-02-13 16:06:01 +01:00
|
|
|
}
|
2018-05-28 07:09:55 +02:00
|
|
|
had_stdin_file = true;
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->edit_type = EDIT_STDIN;
|
|
|
|
}
|
2018-05-24 11:51:35 +02:00
|
|
|
argv_idx = -1; // skip to next argument
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
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
|
2015-05-11 23:30:18 +02:00
|
|
|
if (STRICMP(argv[0] + argv_idx, "help") == 0) {
|
2014-02-01 15:17:43 +01:00
|
|
|
usage();
|
2015-05-11 23:30:18 +02:00
|
|
|
mch_exit(0);
|
|
|
|
} else if (STRICMP(argv[0] + argv_idx, "version") == 0) {
|
|
|
|
version();
|
2014-02-01 15:17:43 +01:00
|
|
|
mch_exit(0);
|
2014-09-09 19:11:05 +02:00
|
|
|
} else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {
|
2017-07-04 16:20:00 +02:00
|
|
|
FileDescriptor fp;
|
2018-04-14 21:17:51 +02:00
|
|
|
const int fof_ret = file_open_fd(&fp, STDOUT_FILENO,
|
2017-12-03 14:49:30 +01:00
|
|
|
kFileWriteOnly);
|
2017-07-04 16:20:00 +02:00
|
|
|
msgpack_packer *p = msgpack_packer_new(&fp, msgpack_file_write);
|
|
|
|
|
|
|
|
if (fof_ret != 0) {
|
|
|
|
emsgf(_("E5421: Failed to open stdin: %s"), os_strerror(fof_ret));
|
|
|
|
}
|
2014-09-12 02:56:52 +02:00
|
|
|
|
2017-07-04 15:47:07 +02:00
|
|
|
if (p == NULL) {
|
2018-09-23 15:44:13 +02:00
|
|
|
EMSG(_(e_outofmem));
|
2014-05-29 16:42:08 +02:00
|
|
|
}
|
2014-09-12 02:56:52 +02:00
|
|
|
|
2017-07-04 15:47:07 +02:00
|
|
|
Object md = DICTIONARY_OBJ(api_metadata());
|
|
|
|
msgpack_rpc_from_object(md, p);
|
|
|
|
|
2016-04-10 15:50:59 +02:00
|
|
|
msgpack_packer_free(p);
|
2017-07-04 18:48:26 +02:00
|
|
|
const int ff_ret = file_flush(&fp);
|
|
|
|
if (ff_ret < 0) {
|
|
|
|
msgpack_file_write_error(ff_ret);
|
|
|
|
}
|
2014-05-29 16:42:08 +02:00
|
|
|
mch_exit(0);
|
2015-02-13 16:06:05 +01:00
|
|
|
} else if (STRICMP(argv[0] + argv_idx, "headless") == 0) {
|
2017-06-05 08:29:10 +02:00
|
|
|
headless_mode = true;
|
2014-09-09 19:11:05 +02:00
|
|
|
} else if (STRICMP(argv[0] + argv_idx, "embed") == 0) {
|
2014-08-12 20:04:28 +02:00
|
|
|
embedded_mode = true;
|
2018-04-08 17:20:25 +02:00
|
|
|
} else if (STRNICMP(argv[0] + argv_idx, "listen", 6) == 0) {
|
|
|
|
want_argument = true;
|
|
|
|
argv_idx += 6;
|
2014-03-16 08:20:00 +01:00
|
|
|
} else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) {
|
2018-05-29 07:22:15 +02:00
|
|
|
// Do nothing: file args are always literal. #7679
|
2018-05-24 11:51:35 +02:00
|
|
|
} 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;
|
2014-02-01 15:17:43 +01:00
|
|
|
argv_idx += 3;
|
2014-03-16 08:20:00 +01:00
|
|
|
} else if (STRNICMP(argv[0] + argv_idx, "startuptime", 11) == 0) {
|
2018-05-24 11:51:35 +02:00
|
|
|
want_argument = true;
|
2014-02-01 15:17:43 +01:00
|
|
|
argv_idx += 11;
|
2019-04-15 21:15:36 +02:00
|
|
|
} else if (STRNICMP(argv[0] + argv_idx, "clean", 5) == 0) {
|
|
|
|
parmp->use_vimrc = "NONE";
|
|
|
|
set_option_value("shadafile", 0L, "NONE", 0);
|
2014-03-16 08:20:00 +01:00
|
|
|
} else {
|
2014-02-01 15:17:43 +01:00
|
|
|
if (argv[0][argv_idx])
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_opt_unknown, argv[0]);
|
2018-05-24 11:51:35 +02:00
|
|
|
had_minmin = true;
|
|
|
|
}
|
|
|
|
if (!want_argument) {
|
|
|
|
argv_idx = -1; // skip to next argument
|
2014-02-01 15:17:43 +01:00
|
|
|
}
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2016-08-20 21:24:34 +02:00
|
|
|
case 'A': { // "-A" start in Arabic mode.
|
|
|
|
set_option_value("arabic", 1L, NULL, 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2016-08-20 21:24:34 +02:00
|
|
|
}
|
|
|
|
case 'b': { // "-b" binary mode.
|
|
|
|
// Needs to be effective before expanding file names, because
|
|
|
|
// for Win32 this makes us edit a shortcut file itself,
|
|
|
|
// instead of the file it links to.
|
2014-02-01 15:17:43 +01:00
|
|
|
set_options_bin(curbuf->b_p_bin, 1, 0);
|
2016-08-20 21:24:34 +02:00
|
|
|
curbuf->b_p_bin = 1; // Binary file I/O.
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2016-08-20 21:24:34 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
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
|
2014-02-01 15:17:43 +01:00
|
|
|
exmode_active = EXMODE_NORMAL;
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2018-06-04 02:06:32 +02:00
|
|
|
case 'E': { // "-E" Ex mode
|
2014-02-01 15:17:43 +01:00
|
|
|
exmode_active = EXMODE_VIM;
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'f': { // "-f" GUI: run in foreground.
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2018-08-27 17:24:33 +02:00
|
|
|
case '?': // "-?" give help message (for MS-Windows)
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'h': { // "-h" give help message
|
2014-02-01 15:17:43 +01:00
|
|
|
usage();
|
2015-05-11 23:30:18 +02:00
|
|
|
mch_exit(0);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2016-08-20 21:24:34 +02:00
|
|
|
case 'H': { // "-H" start in Hebrew mode: rl + hkmap set.
|
|
|
|
p_hkmap = true;
|
|
|
|
set_option_value("rl", 1L, NULL, 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2016-08-20 21:24:34 +02:00
|
|
|
}
|
|
|
|
case 'l': { // "-l" lisp mode, 'lisp' and 'showmatch' on.
|
|
|
|
set_option_value("lisp", 1L, NULL, 0);
|
|
|
|
p_sm = true;
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2016-08-20 21:24:34 +02:00
|
|
|
}
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'M': { // "-M" no changes or writing of files
|
2014-02-01 15:17:43 +01:00
|
|
|
reset_modifiable();
|
2018-09-21 05:57:06 +02:00
|
|
|
FALLTHROUGH;
|
|
|
|
}
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'm': { // "-m" no writing of files
|
|
|
|
p_write = false;
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'N': // "-N" Nocompatible
|
|
|
|
case 'X': // "-X" Do not connect to X server
|
2018-04-16 22:38:02 +02:00
|
|
|
// No-op
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'n': { // "-n" no swap file
|
|
|
|
parmp->no_swap_file = true;
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'p': { // "-p[N]" open N tab pages
|
2018-04-08 14:04:58 +02:00
|
|
|
// default is 0: open window for each file
|
2015-01-24 01:42:21 +01:00
|
|
|
parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->window_layout = WIN_TABS;
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'o': { // "-o[N]" open N horizontal split windows
|
|
|
|
// default is 0: open window for each file
|
2015-01-24 01:42:21 +01:00
|
|
|
parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->window_layout = WIN_HOR;
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'O': { // "-O[N]" open N vertical split windows
|
|
|
|
// default is 0: open window for each file
|
2015-01-24 01:42:21 +01:00
|
|
|
parmp->window_count = get_number_arg(argv[0], &argv_idx, 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->window_layout = WIN_VER;
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'q': { // "-q" QuickFix mode
|
|
|
|
if (parmp->edit_type != EDIT_NONE) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_too_many_args, argv[0]);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->edit_type = EDIT_QF;
|
2018-05-24 11:51:35 +02:00
|
|
|
if (argv[0][argv_idx]) { // "-q{errorfile}"
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->use_ef = (char_u *)argv[0] + argv_idx;
|
|
|
|
argv_idx = -1;
|
2018-05-24 11:51:35 +02:00
|
|
|
} else if (argc > 1) { // "-q {errorfile}"
|
|
|
|
want_argument = true;
|
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'R': { // "-R" readonly mode
|
|
|
|
readonlymode = true;
|
|
|
|
curbuf->b_p_ro = true;
|
|
|
|
p_uc = 10000; // don't update very often
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'r': // "-r" recovery mode
|
|
|
|
case 'L': { // "-L" recovery mode
|
2014-02-01 15:17:43 +01:00
|
|
|
recoverymode = 1;
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 's': {
|
|
|
|
if (exmode_active) { // "-es" silent (batch) Ex-mode
|
2017-08-06 02:44:15 +02:00
|
|
|
silent_mode = true;
|
2019-04-10 03:27:25 +02:00
|
|
|
parmp->no_swap_file = true;
|
2017-08-06 02:44:15 +02:00
|
|
|
} else { // "-s {scriptin}" read from script file
|
|
|
|
want_argument = true;
|
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 't': { // "-t {tag}" or "-t{tag}" jump to tag
|
|
|
|
if (parmp->edit_type != EDIT_NONE) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_too_many_args, argv[0]);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->edit_type = EDIT_TAG;
|
2018-05-24 11:51:35 +02:00
|
|
|
if (argv[0][argv_idx]) { // "-t{tag}"
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->tagname = (char_u *)argv[0] + argv_idx;
|
|
|
|
argv_idx = -1;
|
2018-05-24 11:51:35 +02:00
|
|
|
} else { // "-t {tag}"
|
|
|
|
want_argument = true;
|
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'v': {
|
2015-05-11 23:30:18 +02:00
|
|
|
version();
|
|
|
|
mch_exit(0);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'V': { // "-V{N}" Verbose level
|
|
|
|
// default is 10: a little bit verbose
|
2015-01-24 01:42:21 +01:00
|
|
|
p_verbose = get_number_arg(argv[0], &argv_idx, 10);
|
2014-05-01 20:00:13 +02:00
|
|
|
if (argv[0][argv_idx] != NUL) {
|
2016-08-20 21:24:34 +02:00
|
|
|
set_option_value("verbosefile", 0L, argv[0] + argv_idx, 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
argv_idx = (int)STRLEN(argv[0]);
|
|
|
|
}
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'w': { // "-w{number}" set window height
|
|
|
|
// "-w {scriptout}" write to script
|
2015-04-23 00:47:53 +02:00
|
|
|
if (ascii_isdigit(((char_u *)argv[0])[argv_idx])) {
|
2015-01-24 01:42:21 +01:00
|
|
|
n = get_number_arg(argv[0], &argv_idx, 10);
|
2016-08-20 21:24:34 +02:00
|
|
|
set_option_value("window", n, NULL, 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
|
|
|
}
|
2018-05-24 11:51:35 +02:00
|
|
|
want_argument = true;
|
2014-01-31 14:39:15 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'Z': { // "-Z" restricted mode
|
|
|
|
restricted = true;
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'c': { // "-c{command}" or "-c {command}" exec command
|
2014-05-01 20:00:13 +02:00
|
|
|
if (argv[0][argv_idx] != NUL) {
|
2018-05-24 11:51:35 +02:00
|
|
|
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_extra_cmd, NULL);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
parmp->commands[parmp->n_commands++] = argv[0] + argv_idx;
|
2014-02-01 15:17:43 +01:00
|
|
|
argv_idx = -1;
|
|
|
|
break;
|
|
|
|
}
|
2018-09-20 12:32:15 +02:00
|
|
|
FALLTHROUGH;
|
|
|
|
}
|
2018-05-24 11:51:35 +02:00
|
|
|
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;
|
2014-01-31 14:39:15 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
default: {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_opt_unknown, argv[0]);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
|
2018-04-08 17:20:25 +02:00
|
|
|
// Handle option arguments with argument.
|
2014-01-31 14:39:15 +01:00
|
|
|
if (want_argument) {
|
2018-04-08 17:20:25 +02:00
|
|
|
// Check for garbage immediately after the option letter.
|
|
|
|
if (argv[0][argv_idx] != NUL) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_opt_garbage, argv[0]);
|
2018-04-08 17:20:25 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
argc--;
|
|
|
|
if (argc < 1 && c != 'S') { // -S has an optional argument
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_arg_missing, argv[0]);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
argv++;
|
2014-01-31 14:39:15 +01:00
|
|
|
argv_idx = -1;
|
|
|
|
|
|
|
|
switch (c) {
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'c': // "-c {command}" execute command
|
|
|
|
case 'S': { // "-S {file}" execute Vim script
|
|
|
|
if (parmp->n_commands >= MAX_ARG_CMDS) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_extra_cmd, NULL);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
if (c == 'S') {
|
2018-05-24 11:51:35 +02:00
|
|
|
char *a;
|
2014-02-01 15:17:43 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
if (argc < 1) {
|
|
|
|
// "-S" without argument: use default session file name.
|
2014-02-01 15:17:43 +01:00
|
|
|
a = SESSION_FILE;
|
2018-05-24 11:51:35 +02:00
|
|
|
} else if (argv[0][0] == '-') {
|
|
|
|
// "-S" followed by another option: use default session file.
|
2014-02-01 15:17:43 +01:00
|
|
|
a = SESSION_FILE;
|
|
|
|
++argc;
|
|
|
|
--argv;
|
2015-05-13 21:29:50 +02:00
|
|
|
} else {
|
2014-02-01 15:17:43 +01:00
|
|
|
a = argv[0];
|
2015-05-13 21:29:50 +02:00
|
|
|
}
|
2018-05-24 11:51:35 +02:00
|
|
|
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;
|
2015-05-13 21:29:50 +02:00
|
|
|
parmp->commands[parmp->n_commands++] = s;
|
2015-05-13 21:29:49 +02:00
|
|
|
} else {
|
|
|
|
parmp->commands[parmp->n_commands++] = argv[0];
|
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case '-': {
|
2018-04-08 17:20:25 +02:00
|
|
|
if (strequal(argv[-1], "--cmd")) {
|
|
|
|
// "--cmd {command}" execute command
|
|
|
|
if (parmp->n_pre_commands >= MAX_ARG_CMDS) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_extra_cmd, NULL);
|
2018-04-08 17:20:25 +02:00
|
|
|
}
|
2015-05-13 21:29:49 +02:00
|
|
|
parmp->pre_commands[parmp->n_pre_commands++] = argv[0];
|
2018-04-08 17:20:25 +02:00
|
|
|
} else if (strequal(argv[-1], "--listen")) {
|
|
|
|
// "--listen {address}"
|
|
|
|
parmp->listen_addr = argv[0];
|
2014-02-01 15:17:43 +01:00
|
|
|
}
|
2018-04-08 17:20:25 +02:00
|
|
|
// "--startuptime <file>" already handled
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'q': { // "-q {errorfile}" QuickFix mode
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->use_ef = (char_u *)argv[0];
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'i': { // "-i {shada}" use for shada
|
2019-04-15 21:15:36 +02:00
|
|
|
set_option_value("shadafile", 0L, argv[0], 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case 's': { // "-s {scriptin}" read from script file
|
2014-02-01 15:17:43 +01:00
|
|
|
if (scriptin[0] != NULL) {
|
2014-01-31 14:39:15 +01:00
|
|
|
scripterror:
|
2017-03-19 17:28:16 +01:00
|
|
|
vim_snprintf((char *)IObuff, IOSIZE,
|
|
|
|
_("Attempt to open script file again: \"%s %s\"\n"),
|
|
|
|
argv[-1], argv[0]);
|
|
|
|
mch_errmsg((const char *)IObuff);
|
2014-02-01 15:17:43 +01:00
|
|
|
mch_exit(2);
|
|
|
|
}
|
2017-03-19 14:55:37 +01:00
|
|
|
int error;
|
2017-12-03 03:38:58 +01:00
|
|
|
if (strequal(argv[0], "-")) {
|
2018-04-14 21:17:51 +02:00
|
|
|
const int stdin_dup_fd = os_dup(STDIN_FILENO);
|
2018-04-14 21:21:36 +02:00
|
|
|
#ifdef WIN32
|
2018-05-24 11:51:35 +02:00
|
|
|
// Replace the original stdin with the console input handle.
|
2018-04-14 21:21:36 +02:00
|
|
|
close(STDIN_FILENO);
|
|
|
|
const HANDLE conin_handle =
|
|
|
|
CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
|
|
|
|
FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL,
|
|
|
|
OPEN_EXISTING, 0, (HANDLE)NULL);
|
|
|
|
const int conin_fd = _open_osfhandle(conin_handle, _O_RDONLY);
|
|
|
|
assert(conin_fd == STDIN_FILENO);
|
|
|
|
#endif
|
2017-03-19 14:55:37 +01:00
|
|
|
FileDescriptor *const stdin_dup = file_open_fd_new(
|
2017-12-03 14:49:30 +01:00
|
|
|
&error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking);
|
2017-03-19 14:55:37 +01:00
|
|
|
assert(stdin_dup != NULL);
|
2017-03-19 14:09:48 +01:00
|
|
|
scriptin[0] = stdin_dup;
|
2017-03-19 14:55:37 +01:00
|
|
|
} else if ((scriptin[0] = file_open_new(
|
2017-03-19 15:29:48 +01:00
|
|
|
&error, argv[0], kFileReadOnly|kFileNonBlocking, 0)) == NULL) {
|
2017-03-19 17:28:16 +01:00
|
|
|
vim_snprintf((char *)IObuff, IOSIZE,
|
|
|
|
_("Cannot open for reading: \"%s\": %s\n"),
|
|
|
|
argv[0], os_strerror(error));
|
|
|
|
mch_errmsg((const char *)IObuff);
|
2014-02-01 15:17:43 +01:00
|
|
|
mch_exit(2);
|
|
|
|
}
|
2014-05-10 06:11:34 +02:00
|
|
|
save_typebuf();
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case 't': { // "-t {tag}"
|
2014-02-01 15:17:43 +01:00
|
|
|
parmp->tagname = (char_u *)argv[0];
|
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'u': { // "-u {vimrc}" vim inits file
|
2015-05-13 21:29:49 +02:00
|
|
|
parmp->use_vimrc = argv[0];
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
|
|
|
case 'U': { // "-U {gvimrc}" gvim inits file
|
2014-02-01 15:17:43 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'w': { // "-w {nr}" 'window' value
|
|
|
|
// "-w {scriptout}" append to script file
|
2015-04-23 00:47:53 +02:00
|
|
|
if (ascii_isdigit(*((char_u *)argv[0]))) {
|
2014-02-01 15:17:43 +01:00
|
|
|
argv_idx = 0;
|
2015-01-24 01:42:21 +01:00
|
|
|
n = get_number_arg(argv[0], &argv_idx, 10);
|
2016-08-20 21:24:34 +02:00
|
|
|
set_option_value("window", n, NULL, 0);
|
2014-02-01 15:17:43 +01:00
|
|
|
argv_idx = -1;
|
|
|
|
break;
|
|
|
|
}
|
2018-09-20 12:32:15 +02:00
|
|
|
FALLTHROUGH;
|
|
|
|
}
|
2018-05-24 11:51:35 +02:00
|
|
|
case 'W': { // "-W {scriptout}" overwrite script file
|
|
|
|
if (scriptout != NULL) {
|
2014-02-01 15:17:43 +01:00
|
|
|
goto scripterror;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-02-01 15:17:43 +01:00
|
|
|
if ((scriptout = mch_fopen(argv[0],
|
|
|
|
c == 'w' ? APPENDBIN : WRITEBIN)) == NULL) {
|
|
|
|
mch_errmsg(_("Cannot open for script output: \""));
|
|
|
|
mch_errmsg(argv[0]);
|
|
|
|
mch_errmsg("\"\n");
|
|
|
|
mch_exit(2);
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
break;
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
}
|
2017-12-03 04:44:46 +01:00
|
|
|
} else { // File name argument.
|
|
|
|
argv_idx = -1; // skip to next argument
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2017-12-03 04:44:46 +01:00
|
|
|
// Check for only one type of editing.
|
2018-05-28 07:09:55 +02:00
|
|
|
if (parmp->edit_type != EDIT_NONE
|
|
|
|
&& parmp->edit_type != EDIT_FILE
|
|
|
|
&& parmp->edit_type != EDIT_STDIN) {
|
2015-05-30 07:06:19 +02:00
|
|
|
mainerr(err_too_many_args, argv[0]);
|
2017-12-03 04:44:46 +01:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
parmp->edit_type = EDIT_FILE;
|
|
|
|
|
2017-12-03 04:44:46 +01:00
|
|
|
// Add the file to the global argument list.
|
2014-04-08 03:28:33 +02:00
|
|
|
ga_grow(&global_alist.al_ga, 1);
|
2016-03-09 15:52:07 +01:00
|
|
|
char_u *p = vim_strsave((char_u *)argv[0]);
|
2014-05-09 02:34:46 +02:00
|
|
|
|
2014-03-27 12:38:33 +01:00
|
|
|
if (parmp->diff_mode && os_isdir(p) && GARGCOUNT > 0
|
|
|
|
&& !os_isdir(alist_name(&GARGLIST[0]))) {
|
2017-12-03 04:44:46 +01:00
|
|
|
char_u *r = (char_u *)concat_fnames((char *)p,
|
|
|
|
(char *)path_tail(alist_name(&GARGLIST[0])), true);
|
2015-04-12 16:37:22 +02:00
|
|
|
xfree(p);
|
2014-04-19 07:12:47 +02:00
|
|
|
p = r;
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_FNAME_CASE
|
2014-09-21 04:39:31 +02:00
|
|
|
// Make the case of the file name match the actual file.
|
|
|
|
path_fix_case(p);
|
2014-01-31 14:39:15 +01:00
|
|
|
#endif
|
|
|
|
|
2018-05-28 07:09:55 +02:00
|
|
|
int alist_fnum_flag = edit_stdin(had_stdin_file, parmp)
|
2018-05-23 10:54:09 +02:00
|
|
|
? 1 // add buffer nr after exp.
|
|
|
|
: 2; // add buffer number now and use curbuf
|
|
|
|
alist_add(&global_alist, p, alist_fnum_flag);
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
|
2017-12-03 04:44:46 +01:00
|
|
|
// 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.
|
2014-05-01 20:00:13 +02:00
|
|
|
if (argv_idx <= 0 || argv[0][argv_idx] == NUL) {
|
2017-12-03 04:44:46 +01:00
|
|
|
argc--;
|
|
|
|
argv++;
|
2014-01-31 14:39:15 +01:00
|
|
|
argv_idx = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-03 04:44:46 +01:00
|
|
|
// If there is a "+123" or "-c" command, set v:swapcommand to the first one.
|
2014-01-31 14:39:15 +01:00
|
|
|
if (parmp->n_commands > 0) {
|
2016-03-20 19:31:49 +01:00
|
|
|
const size_t swcmd_len = STRLEN(parmp->commands[0]) + 3;
|
|
|
|
char *const swcmd = xmalloc(swcmd_len);
|
|
|
|
snprintf(swcmd, swcmd_len, ":%s\r", parmp->commands[0]);
|
|
|
|
set_vim_var_string(VV_SWAPCOMMAND, swcmd, -1);
|
|
|
|
xfree(swcmd);
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
2017-12-03 03:38:58 +01:00
|
|
|
|
2018-05-28 07:09:55 +02:00
|
|
|
// Handle "foo | nvim". EDIT_FILE may be overwritten now. #6299
|
|
|
|
if (edit_stdin(had_stdin_file, parmp)) {
|
2018-05-23 10:54:09 +02:00
|
|
|
parmp->edit_type = EDIT_STDIN;
|
2017-12-03 03:38:58 +01:00
|
|
|
}
|
|
|
|
|
2014-02-22 04:55:12 +01:00
|
|
|
TIME_MSG("parsing arguments");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Many variables are in "params" so that we can pass them to invoked
|
|
|
|
* functions without a lot of arguments. "argc" and "argv" are also
|
|
|
|
* copied, so that they can be changed. */
|
2014-02-23 21:34:45 +01:00
|
|
|
static void init_params(mparm_T *paramp, int argc, char **argv)
|
2014-02-22 04:55:12 +01:00
|
|
|
{
|
2014-03-25 00:30:14 +01:00
|
|
|
memset(paramp, 0, sizeof(*paramp));
|
2014-02-22 04:55:12 +01:00
|
|
|
paramp->argc = argc;
|
|
|
|
paramp->argv = argv;
|
|
|
|
paramp->use_debug_break_level = -1;
|
|
|
|
paramp->window_count = -1;
|
2018-04-08 17:20:25 +02:00
|
|
|
paramp->listen_addr = NULL;
|
2014-02-22 04:55:12 +01:00
|
|
|
}
|
|
|
|
|
2018-04-08 17:20:25 +02:00
|
|
|
/// Initialize global startuptime file if "--startuptime" passed as an argument.
|
2014-02-23 21:34:45 +01:00
|
|
|
static void init_startuptime(mparm_T *paramp)
|
2014-02-22 04:55:12 +01:00
|
|
|
{
|
2014-07-18 11:02:27 +02:00
|
|
|
for (int i = 1; i < paramp->argc; i++) {
|
2014-02-22 04:55:12 +01:00
|
|
|
if (STRICMP(paramp->argv[i], "--startuptime") == 0 && i + 1 < paramp->argc) {
|
|
|
|
time_fd = mch_fopen(paramp->argv[i + 1], "a");
|
2014-07-18 17:49:27 +02:00
|
|
|
time_start("--- NVIM STARTING ---");
|
2014-02-22 04:55:12 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-07-18 11:02:27 +02:00
|
|
|
|
2014-02-22 04:55:12 +01:00
|
|
|
starttime = time(NULL);
|
|
|
|
}
|
|
|
|
|
2014-02-23 21:34:45 +01:00
|
|
|
static void check_and_set_isatty(mparm_T *paramp)
|
2014-02-22 04:55:12 +01:00
|
|
|
{
|
2017-10-23 01:50:26 +02:00
|
|
|
stdin_isatty
|
2018-05-29 07:22:15 +02:00
|
|
|
= paramp->input_isatty = os_isatty(STDIN_FILENO);
|
2017-10-23 01:50:26 +02:00
|
|
|
stdout_isatty
|
2018-05-29 07:22:15 +02:00
|
|
|
= paramp->output_isatty = os_isatty(STDOUT_FILENO);
|
|
|
|
paramp->err_isatty = os_isatty(STDERR_FILENO);
|
2018-01-17 12:42:23 +01:00
|
|
|
#ifndef WIN32
|
2017-07-10 01:58:54 +02:00
|
|
|
int tty_fd = paramp->input_isatty
|
2018-03-01 02:14:27 +01:00
|
|
|
? STDIN_FILENO
|
2017-07-10 01:58:54 +02:00
|
|
|
: (paramp->output_isatty
|
2018-03-01 02:14:27 +01:00
|
|
|
? STDOUT_FILENO
|
|
|
|
: (paramp->err_isatty ? STDERR_FILENO : -1));
|
2017-07-10 01:58:54 +02:00
|
|
|
pty_process_save_termios(tty_fd);
|
|
|
|
#endif
|
2014-02-22 04:55:12 +01:00
|
|
|
TIME_MSG("window checked");
|
|
|
|
}
|
2017-02-02 13:16:15 +01:00
|
|
|
|
|
|
|
// Sets v:progname and v:progpath. Also modifies $PATH on Windows.
|
2017-05-17 03:23:34 +02:00
|
|
|
static void init_path(const char *exename)
|
|
|
|
FUNC_ATTR_NONNULL_ALL
|
2017-02-02 13:16:15 +01:00
|
|
|
{
|
|
|
|
char exepath[MAXPATHL] = { 0 };
|
|
|
|
size_t exepathlen = MAXPATHL;
|
|
|
|
// Make v:progpath absolute.
|
|
|
|
if (os_exepath(exepath, &exepathlen) != 0) {
|
2017-05-13 18:17:21 +02:00
|
|
|
// Fall back to argv[0]. Missing procfs? #6734
|
|
|
|
path_guess_exepath(exename, exepath, sizeof(exepath));
|
2017-02-02 13:16:15 +01:00
|
|
|
}
|
|
|
|
set_vim_var_string(VV_PROGPATH, exepath, -1);
|
|
|
|
set_vim_var_string(VV_PROGNAME, (char *)path_tail((char_u *)exename), -1);
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
// Append the process start directory to $PATH, so that ":!foo" finds tools
|
|
|
|
// shipped with Windows package. This also mimics SearchPath().
|
|
|
|
os_setenv_append_path(exepath);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get filename from command line, if any.
|
2016-02-09 20:55:40 +01:00
|
|
|
static char_u *get_fname(mparm_T *parmp, char_u *cwd)
|
2014-02-22 04:55:12 +01:00
|
|
|
{
|
|
|
|
return alist_name(&GARGLIST[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decide about window layout for diff mode after reading vimrc.
|
|
|
|
*/
|
2014-02-23 21:34:45 +01:00
|
|
|
static void set_window_layout(mparm_T *paramp)
|
2014-02-22 04:55:12 +01:00
|
|
|
{
|
|
|
|
if (paramp->diff_mode && paramp->window_layout == 0) {
|
|
|
|
if (diffopt_horizontal())
|
|
|
|
paramp->window_layout = WIN_HOR; /* use horizontal split */
|
|
|
|
else
|
|
|
|
paramp->window_layout = WIN_VER; /* use vertical split */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read all the plugin files.
|
|
|
|
* Only when compiled with +eval, since most plugins need it.
|
|
|
|
*/
|
2014-02-23 21:34:45 +01:00
|
|
|
static void load_plugins(void)
|
2014-02-22 04:55:12 +01:00
|
|
|
{
|
|
|
|
if (p_lpl) {
|
2017-08-21 18:54:22 +02:00
|
|
|
char_u *rtp_copy = NULL;
|
|
|
|
|
2017-08-21 18:47:58 +02:00
|
|
|
// First add all package directories to 'runtimepath', so that their
|
|
|
|
// autoload directories can be found. Only if not done already with a
|
|
|
|
// :packloadall command.
|
2017-08-21 18:54:22 +02:00
|
|
|
// Make a copy of 'runtimepath', so that source_runtime does not use the
|
|
|
|
// pack directories.
|
2017-08-21 18:47:58 +02:00
|
|
|
if (!did_source_packages) {
|
2017-08-21 18:54:22 +02:00
|
|
|
rtp_copy = vim_strsave(p_rtp);
|
2017-08-21 18:47:58 +02:00
|
|
|
add_pack_start_dirs();
|
|
|
|
}
|
|
|
|
|
2017-08-21 18:54:22 +02:00
|
|
|
source_in_path(rtp_copy == NULL ? p_rtp : rtp_copy,
|
|
|
|
(char_u *)"plugin/**/*.vim", // NOLINT
|
|
|
|
DIP_ALL | DIP_NOAFTER);
|
2014-02-22 04:55:12 +01:00
|
|
|
TIME_MSG("loading plugins");
|
2017-08-21 18:54:22 +02:00
|
|
|
xfree(rtp_copy);
|
2016-04-26 05:07:51 +02:00
|
|
|
|
2017-08-21 18:47:58 +02:00
|
|
|
// Only source "start" packages if not done already with a :packloadall
|
|
|
|
// command.
|
|
|
|
if (!did_source_packages) {
|
|
|
|
load_start_packages();
|
|
|
|
}
|
2016-04-26 05:07:51 +02:00
|
|
|
TIME_MSG("loading packages");
|
2017-03-21 17:07:00 +01:00
|
|
|
|
|
|
|
source_runtime((char_u *)"plugin/**/*.vim", DIP_ALL | DIP_AFTER);
|
|
|
|
TIME_MSG("loading after plugins");
|
2014-02-22 04:55:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "-q errorfile": Load the error file now.
|
|
|
|
* If the error file can't be read, exit before doing anything else.
|
|
|
|
*/
|
2014-02-23 21:34:45 +01:00
|
|
|
static void handle_quickfix(mparm_T *paramp)
|
2014-02-22 04:55:12 +01:00
|
|
|
{
|
|
|
|
if (paramp->edit_type == EDIT_QF) {
|
|
|
|
if (paramp->use_ef != NULL)
|
|
|
|
set_string_option_direct((char_u *)"ef", -1,
|
|
|
|
paramp->use_ef, OPT_FREE, SID_CARG);
|
|
|
|
vim_snprintf((char *)IObuff, IOSIZE, "cfile %s", p_ef);
|
2017-12-17 03:50:20 +01:00
|
|
|
if (qf_init(NULL, p_ef, p_efm, true, IObuff, p_menc) < 0) {
|
2018-07-06 14:39:50 +02:00
|
|
|
msg_putchar('\n');
|
2014-02-22 04:55:12 +01:00
|
|
|
mch_exit(3);
|
|
|
|
}
|
|
|
|
TIME_MSG("reading errorfile");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Need to jump to the tag before executing the '-c command'.
|
|
|
|
* Makes "vim -c '/return' -t main" work.
|
|
|
|
*/
|
2014-02-23 21:34:45 +01:00
|
|
|
static void handle_tag(char_u *tagname)
|
2014-02-22 04:55:12 +01:00
|
|
|
{
|
|
|
|
if (tagname != NULL) {
|
|
|
|
swap_exists_did_quit = FALSE;
|
|
|
|
|
|
|
|
vim_snprintf((char *)IObuff, IOSIZE, "ta %s", tagname);
|
2015-05-13 21:29:49 +02:00
|
|
|
do_cmdline_cmd((char *)IObuff);
|
2014-02-22 04:55:12 +01:00
|
|
|
TIME_MSG("jumping to tag");
|
|
|
|
|
|
|
|
/* If the user doesn't want to edit the file then we quit here. */
|
|
|
|
if (swap_exists_did_quit)
|
|
|
|
getout(1);
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
|
2017-12-03 02:44:22 +01:00
|
|
|
/// Read text from stdin.
|
2014-03-16 08:20:00 +01:00
|
|
|
static void read_stdin(void)
|
|
|
|
{
|
2017-12-03 04:44:46 +01:00
|
|
|
// When getting the ATTENTION prompt here, use a dialog.
|
2014-01-31 14:39:15 +01:00
|
|
|
swap_exists_action = SEA_DIALOG;
|
2017-12-03 04:44:46 +01:00
|
|
|
no_wait_return = true;
|
|
|
|
int save_msg_didany = msg_didany;
|
|
|
|
set_buflisted(true);
|
|
|
|
(void)open_buffer(true, NULL, 0); // create memfile and read file
|
2018-06-17 23:05:28 +02:00
|
|
|
if (BUFEMPTY() && curbuf->b_next != NULL) {
|
|
|
|
// stdin was empty, go to buffer 2 (e.g. "echo file1 | xargs nvim"). #8561
|
2018-06-18 18:48:28 +02:00
|
|
|
do_cmdline_cmd("silent! bnext");
|
|
|
|
// Delete the empty stdin buffer.
|
|
|
|
do_cmdline_cmd("bwipeout 1");
|
2018-06-17 23:05:28 +02:00
|
|
|
}
|
2017-12-03 04:44:46 +01:00
|
|
|
no_wait_return = false;
|
|
|
|
msg_didany = save_msg_didany;
|
2014-01-31 14:39:15 +01:00
|
|
|
TIME_MSG("reading stdin");
|
|
|
|
check_swap_exists_action();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the requested number of windows and edit buffers in them.
|
|
|
|
* Also does recovery if "recoverymode" set.
|
|
|
|
*/
|
2014-02-23 21:34:45 +01:00
|
|
|
static void create_windows(mparm_T *parmp)
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
|
|
|
int dorewind;
|
|
|
|
int done = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the number of windows that was requested.
|
|
|
|
*/
|
|
|
|
if (parmp->window_count == -1) /* was not set */
|
|
|
|
parmp->window_count = 1;
|
|
|
|
if (parmp->window_count == 0)
|
|
|
|
parmp->window_count = GARGCOUNT;
|
|
|
|
if (parmp->window_count > 1) {
|
2015-10-17 16:25:53 +02:00
|
|
|
// Don't change the windows if there was a command in vimrc that
|
|
|
|
// already split some windows
|
2014-01-31 14:39:15 +01:00
|
|
|
if (parmp->window_layout == 0)
|
|
|
|
parmp->window_layout = WIN_HOR;
|
|
|
|
if (parmp->window_layout == WIN_TABS) {
|
|
|
|
parmp->window_count = make_tabpages(parmp->window_count);
|
|
|
|
TIME_MSG("making tab pages");
|
2014-03-16 08:20:00 +01:00
|
|
|
} else if (firstwin->w_next == NULL) {
|
2014-01-31 14:39:15 +01:00
|
|
|
parmp->window_count = make_windows(parmp->window_count,
|
|
|
|
parmp->window_layout == WIN_VER);
|
|
|
|
TIME_MSG("making windows");
|
|
|
|
} else
|
|
|
|
parmp->window_count = win_count();
|
|
|
|
} else
|
|
|
|
parmp->window_count = 1;
|
|
|
|
|
|
|
|
if (recoverymode) { /* do recover */
|
|
|
|
msg_scroll = TRUE; /* scroll message up */
|
|
|
|
ml_recover();
|
|
|
|
if (curbuf->b_ml.ml_mfp == NULL) /* failed */
|
|
|
|
getout(1);
|
|
|
|
do_modelines(0); /* do modelines */
|
2014-03-16 08:20:00 +01:00
|
|
|
} else {
|
2015-10-17 16:25:53 +02:00
|
|
|
// Open a buffer for windows that don't have one yet.
|
|
|
|
// Commands in the vimrc might have loaded a file or split the window.
|
|
|
|
// Watch out for autocommands that delete a window.
|
|
|
|
//
|
|
|
|
// Don't execute Win/Buf Enter/Leave autocommands here
|
2014-01-31 14:39:15 +01:00
|
|
|
++autocmd_no_enter;
|
|
|
|
++autocmd_no_leave;
|
|
|
|
dorewind = TRUE;
|
|
|
|
while (done++ < 1000) {
|
|
|
|
if (dorewind) {
|
|
|
|
if (parmp->window_layout == WIN_TABS)
|
|
|
|
goto_tabpage(1);
|
|
|
|
else
|
|
|
|
curwin = firstwin;
|
2014-03-16 08:20:00 +01:00
|
|
|
} else if (parmp->window_layout == WIN_TABS) {
|
2014-01-31 14:39:15 +01:00
|
|
|
if (curtab->tp_next == NULL)
|
|
|
|
break;
|
|
|
|
goto_tabpage(0);
|
2014-03-16 08:20:00 +01:00
|
|
|
} else {
|
2014-01-31 14:39:15 +01:00
|
|
|
if (curwin->w_next == NULL)
|
|
|
|
break;
|
|
|
|
curwin = curwin->w_next;
|
|
|
|
}
|
|
|
|
dorewind = FALSE;
|
|
|
|
curbuf = curwin->w_buffer;
|
|
|
|
if (curbuf->b_ml.ml_mfp == NULL) {
|
2019-04-29 17:41:17 +02:00
|
|
|
// Set 'foldlevel' to 'foldlevelstart' if it's not negative..
|
|
|
|
if (p_fdls >= 0) {
|
2014-01-31 14:39:15 +01:00
|
|
|
curwin->w_p_fdl = p_fdls;
|
2019-04-29 17:41:17 +02:00
|
|
|
}
|
|
|
|
// When getting the ATTENTION prompt here, use a dialog.
|
2014-01-31 14:39:15 +01:00
|
|
|
swap_exists_action = SEA_DIALOG;
|
|
|
|
set_buflisted(TRUE);
|
|
|
|
|
|
|
|
/* create memfile, read file */
|
|
|
|
(void)open_buffer(FALSE, NULL, 0);
|
|
|
|
|
|
|
|
if (swap_exists_action == SEA_QUIT) {
|
|
|
|
if (got_int || only_one_window()) {
|
|
|
|
/* abort selected or quit and only one window */
|
|
|
|
did_emsg = FALSE; /* avoid hit-enter prompt */
|
|
|
|
getout(1);
|
|
|
|
}
|
|
|
|
/* We can't close the window, it would disturb what
|
|
|
|
* happens next. Clear the file name and set the arg
|
|
|
|
* index to -1 to delete it later. */
|
|
|
|
setfname(curbuf, NULL, NULL, FALSE);
|
|
|
|
curwin->w_arg_idx = -1;
|
|
|
|
swap_exists_action = SEA_NONE;
|
|
|
|
} else
|
|
|
|
handle_swap_exists(NULL);
|
|
|
|
dorewind = TRUE; /* start again */
|
|
|
|
}
|
2014-11-27 18:10:42 +01:00
|
|
|
os_breakcheck();
|
2014-01-31 14:39:15 +01:00
|
|
|
if (got_int) {
|
|
|
|
(void)vgetc(); /* only break the file loading, not the rest */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (parmp->window_layout == WIN_TABS)
|
|
|
|
goto_tabpage(1);
|
|
|
|
else
|
|
|
|
curwin = firstwin;
|
|
|
|
curbuf = curwin->w_buffer;
|
|
|
|
--autocmd_no_enter;
|
|
|
|
--autocmd_no_leave;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-03 19:47:55 +01:00
|
|
|
/// If opened more than one window, start editing files in the other
|
|
|
|
/// windows. make_windows() has already opened the windows.
|
|
|
|
static void edit_buffers(mparm_T *parmp, char_u *cwd)
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
|
|
|
int arg_idx; /* index in argument list */
|
|
|
|
int i;
|
2018-09-07 02:18:12 +02:00
|
|
|
bool advance = true;
|
2014-01-31 14:39:15 +01:00
|
|
|
win_T *win;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't execute Win/Buf Enter/Leave autocommands here
|
|
|
|
*/
|
|
|
|
++autocmd_no_enter;
|
|
|
|
++autocmd_no_leave;
|
|
|
|
|
|
|
|
/* When w_arg_idx is -1 remove the window (see create_windows()). */
|
|
|
|
if (curwin->w_arg_idx == -1) {
|
2018-09-07 02:12:15 +02:00
|
|
|
win_close(curwin, true);
|
2018-09-07 02:18:12 +02:00
|
|
|
advance = false;
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
arg_idx = 1;
|
|
|
|
for (i = 1; i < parmp->window_count; ++i) {
|
2016-02-03 19:47:55 +01:00
|
|
|
if (cwd != NULL) {
|
|
|
|
os_chdir((char *)cwd);
|
|
|
|
}
|
|
|
|
// When w_arg_idx is -1 remove the window (see create_windows()).
|
2014-01-31 14:39:15 +01:00
|
|
|
if (curwin->w_arg_idx == -1) {
|
2018-09-06 05:04:54 +02:00
|
|
|
arg_idx++;
|
2018-09-07 02:12:15 +02:00
|
|
|
win_close(curwin, true);
|
2018-09-07 02:18:12 +02:00
|
|
|
advance = false;
|
2014-01-31 14:39:15 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (advance) {
|
|
|
|
if (parmp->window_layout == WIN_TABS) {
|
|
|
|
if (curtab->tp_next == NULL) /* just checking */
|
|
|
|
break;
|
|
|
|
goto_tabpage(0);
|
2014-03-16 08:20:00 +01:00
|
|
|
} else {
|
2014-01-31 14:39:15 +01:00
|
|
|
if (curwin->w_next == NULL) /* just checking */
|
|
|
|
break;
|
2014-04-30 11:06:52 +02:00
|
|
|
win_enter(curwin->w_next, false);
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
}
|
2018-09-07 02:18:12 +02:00
|
|
|
advance = true;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-10-17 16:25:53 +02:00
|
|
|
// Only open the file if there is no file in this window yet (that can
|
|
|
|
// happen when vimrc contains ":sall").
|
2014-01-31 14:39:15 +01:00
|
|
|
if (curbuf == firstwin->w_buffer || curbuf->b_ffname == NULL) {
|
|
|
|
curwin->w_arg_idx = arg_idx;
|
|
|
|
/* Edit file from arg list, if there is one. When "Quit" selected
|
|
|
|
* at the ATTENTION prompt close the window. */
|
|
|
|
swap_exists_did_quit = FALSE;
|
|
|
|
(void)do_ecmd(0, arg_idx < GARGCOUNT
|
|
|
|
? alist_name(&GARGLIST[arg_idx]) : NULL,
|
|
|
|
NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin);
|
|
|
|
if (swap_exists_did_quit) {
|
|
|
|
/* abort or quit selected */
|
|
|
|
if (got_int || only_one_window()) {
|
|
|
|
/* abort selected and only one window */
|
|
|
|
did_emsg = FALSE; /* avoid hit-enter prompt */
|
|
|
|
getout(1);
|
|
|
|
}
|
2018-09-07 02:12:15 +02:00
|
|
|
win_close(curwin, true);
|
2018-09-07 02:18:12 +02:00
|
|
|
advance = false;
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
2018-09-30 04:11:50 +02:00
|
|
|
if (arg_idx == GARGCOUNT - 1) {
|
2018-09-29 22:53:55 +02:00
|
|
|
arg_had_last = true;
|
2018-09-30 04:11:50 +02:00
|
|
|
}
|
|
|
|
arg_idx++;
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
2014-11-27 18:10:42 +01:00
|
|
|
os_breakcheck();
|
2014-01-31 14:39:15 +01:00
|
|
|
if (got_int) {
|
|
|
|
(void)vgetc(); /* only break the file loading, not the rest */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (parmp->window_layout == WIN_TABS)
|
|
|
|
goto_tabpage(1);
|
|
|
|
--autocmd_no_enter;
|
|
|
|
|
|
|
|
/* make the first window the current window */
|
|
|
|
win = firstwin;
|
|
|
|
/* Avoid making a preview window the current window. */
|
|
|
|
while (win->w_p_pvw) {
|
|
|
|
win = win->w_next;
|
|
|
|
if (win == NULL) {
|
|
|
|
win = firstwin;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-04-30 11:06:52 +02:00
|
|
|
win_enter(win, false);
|
2014-01-31 14:39:15 +01:00
|
|
|
|
|
|
|
--autocmd_no_leave;
|
|
|
|
TIME_MSG("editing files in windows");
|
|
|
|
if (parmp->window_count > 1 && parmp->window_layout != WIN_TABS)
|
2015-08-30 22:27:47 +02:00
|
|
|
win_equal(curwin, false, 'b'); /* adjust heights */
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Execute the commands from --cmd arguments "cmds[cnt]".
|
|
|
|
*/
|
2014-02-23 21:34:45 +01:00
|
|
|
static void exe_pre_commands(mparm_T *parmp)
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
2015-05-13 21:29:49 +02:00
|
|
|
char **cmds = parmp->pre_commands;
|
2014-01-31 14:39:15 +01:00
|
|
|
int cnt = parmp->n_pre_commands;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (cnt > 0) {
|
|
|
|
curwin->w_cursor.lnum = 0; /* just in case.. */
|
|
|
|
sourcing_name = (char_u *)_("pre-vimrc command line");
|
|
|
|
current_SID = SID_CMDARG;
|
|
|
|
for (i = 0; i < cnt; ++i)
|
|
|
|
do_cmdline_cmd(cmds[i]);
|
|
|
|
sourcing_name = NULL;
|
|
|
|
current_SID = 0;
|
|
|
|
TIME_MSG("--cmd commands");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Execute "+", "-c" and "-S" arguments.
|
|
|
|
*/
|
2014-02-23 21:34:45 +01:00
|
|
|
static void exe_commands(mparm_T *parmp)
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We start commands on line 0, make "vim +/pat file" match a
|
|
|
|
* pattern on line 1. But don't move the cursor when an autocommand
|
|
|
|
* with g`" was used.
|
|
|
|
*/
|
|
|
|
msg_scroll = TRUE;
|
|
|
|
if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1)
|
|
|
|
curwin->w_cursor.lnum = 0;
|
|
|
|
sourcing_name = (char_u *)"command line";
|
|
|
|
current_SID = SID_CARG;
|
|
|
|
for (i = 0; i < parmp->n_commands; ++i) {
|
|
|
|
do_cmdline_cmd(parmp->commands[i]);
|
|
|
|
if (parmp->cmds_tofree[i])
|
2015-04-12 16:37:22 +02:00
|
|
|
xfree(parmp->commands[i]);
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
sourcing_name = NULL;
|
|
|
|
current_SID = 0;
|
|
|
|
if (curwin->w_cursor.lnum == 0)
|
|
|
|
curwin->w_cursor.lnum = 1;
|
|
|
|
|
|
|
|
if (!exmode_active)
|
|
|
|
msg_scroll = FALSE;
|
|
|
|
|
|
|
|
/* When started with "-q errorfile" jump to first error again. */
|
|
|
|
if (parmp->edit_type == EDIT_QF)
|
|
|
|
qf_jump(NULL, 0, 0, FALSE);
|
|
|
|
TIME_MSG("executing command arguments");
|
|
|
|
}
|
|
|
|
|
2018-12-16 05:40:41 +01:00
|
|
|
/// Source system-wide vimrc if built with one defined
|
|
|
|
///
|
|
|
|
/// Does one of the following things, stops after whichever succeeds:
|
|
|
|
///
|
|
|
|
/// 1. Source system vimrc file from $XDG_CONFIG_DIRS/nvim/sysinit.vim
|
|
|
|
/// 2. Source system vimrc file from $VIM
|
|
|
|
static void do_system_initialization(void)
|
|
|
|
{
|
|
|
|
char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs);
|
|
|
|
if (config_dirs != NULL) {
|
|
|
|
const void *iter = NULL;
|
|
|
|
const char path_tail[] = {
|
|
|
|
'n', 'v', 'i', 'm', PATHSEP,
|
|
|
|
's', 'y', 's', 'i', 'n', 'i', 't', '.', 'v', 'i', 'm', NUL
|
|
|
|
};
|
|
|
|
do {
|
|
|
|
const char *dir;
|
|
|
|
size_t dir_len;
|
|
|
|
iter = vim_env_iter(':', config_dirs, iter, &dir, &dir_len);
|
|
|
|
if (dir == NULL || dir_len == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
char *vimrc = xmalloc(dir_len + sizeof(path_tail) + 1);
|
|
|
|
memcpy(vimrc, dir, dir_len);
|
|
|
|
vimrc[dir_len] = PATHSEP;
|
|
|
|
memcpy(vimrc + dir_len + 1, path_tail, sizeof(path_tail));
|
|
|
|
if (do_source((char_u *)vimrc, false, DOSO_NONE) != FAIL) {
|
|
|
|
xfree(vimrc);
|
|
|
|
xfree(config_dirs);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
xfree(vimrc);
|
|
|
|
} while (iter != NULL);
|
|
|
|
xfree(config_dirs);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SYS_VIMRC_FILE
|
|
|
|
// Get system wide defaults, if the file name is defined.
|
|
|
|
(void)do_source((char_u *)SYS_VIMRC_FILE, false, DOSO_NONE);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-10-23 16:43:35 +02:00
|
|
|
/// Source vimrc or do other user initialization
|
|
|
|
///
|
|
|
|
/// Does one of the following things, stops after whichever succeeds:
|
|
|
|
///
|
|
|
|
/// 1. Execution of VIMINIT environment variable.
|
|
|
|
/// 2. Sourcing user vimrc file ($XDG_CONFIG_HOME/nvim/init.vim).
|
|
|
|
/// 3. Sourcing other vimrc files ($XDG_CONFIG_DIRS[1]/nvim/init.vim, …).
|
|
|
|
/// 4. Execution of EXINIT environment variable.
|
|
|
|
///
|
|
|
|
/// @return True if it is needed to attempt to source exrc file according to
|
|
|
|
/// 'exrc' option definition.
|
|
|
|
static bool do_user_initialization(void)
|
|
|
|
FUNC_ATTR_WARN_UNUSED_RESULT
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
2015-10-23 16:43:35 +02:00
|
|
|
bool do_exrc = p_exrc;
|
2019-02-24 20:09:14 +01:00
|
|
|
if (execute_env("VIMINIT") == OK) {
|
2015-10-29 02:28:07 +01:00
|
|
|
do_exrc = p_exrc;
|
2015-10-23 16:43:35 +02:00
|
|
|
return do_exrc;
|
|
|
|
}
|
|
|
|
char_u *user_vimrc = (char_u *)stdpaths_user_conf_subpath("init.vim");
|
|
|
|
if (do_source(user_vimrc, true, DOSO_VIMRC) != FAIL) {
|
2015-10-29 02:28:07 +01:00
|
|
|
do_exrc = p_exrc;
|
2015-10-23 16:43:35 +02:00
|
|
|
if (do_exrc) {
|
|
|
|
do_exrc = (path_full_compare((char_u *)VIMRC_FILE, user_vimrc, false)
|
|
|
|
!= kEqualFiles);
|
|
|
|
}
|
|
|
|
xfree(user_vimrc);
|
|
|
|
return do_exrc;
|
|
|
|
}
|
|
|
|
xfree(user_vimrc);
|
|
|
|
char *const config_dirs = stdpaths_get_xdg_var(kXDGConfigDirs);
|
|
|
|
if (config_dirs != NULL) {
|
|
|
|
const void *iter = NULL;
|
|
|
|
do {
|
|
|
|
const char *dir;
|
|
|
|
size_t dir_len;
|
2017-05-15 03:54:52 +02:00
|
|
|
iter = vim_env_iter(':', config_dirs, iter, &dir, &dir_len);
|
2015-10-23 16:43:35 +02:00
|
|
|
if (dir == NULL || dir_len == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const char path_tail[] = { 'n', 'v', 'i', 'm', PATHSEP,
|
|
|
|
'i', 'n', 'i', 't', '.', 'v', 'i', 'm', NUL };
|
|
|
|
char *vimrc = xmalloc(dir_len + sizeof(path_tail) + 1);
|
|
|
|
memmove(vimrc, dir, dir_len);
|
|
|
|
vimrc[dir_len] = PATHSEP;
|
|
|
|
memmove(vimrc + dir_len + 1, path_tail, sizeof(path_tail));
|
|
|
|
if (do_source((char_u *) vimrc, true, DOSO_VIMRC) != FAIL) {
|
2015-10-29 02:28:07 +01:00
|
|
|
do_exrc = p_exrc;
|
2015-10-23 16:43:35 +02:00
|
|
|
if (do_exrc) {
|
|
|
|
do_exrc = (path_full_compare((char_u *)VIMRC_FILE, (char_u *)vimrc,
|
|
|
|
false) != kEqualFiles);
|
|
|
|
}
|
|
|
|
xfree(vimrc);
|
|
|
|
xfree(config_dirs);
|
|
|
|
return do_exrc;
|
|
|
|
}
|
|
|
|
xfree(vimrc);
|
|
|
|
} while (iter != NULL);
|
|
|
|
xfree(config_dirs);
|
|
|
|
}
|
2019-02-24 20:09:14 +01:00
|
|
|
if (execute_env("EXINIT") == OK) {
|
2015-10-29 02:28:07 +01:00
|
|
|
do_exrc = p_exrc;
|
2015-10-23 16:43:35 +02:00
|
|
|
return do_exrc;
|
|
|
|
}
|
|
|
|
return do_exrc;
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-10-23 16:43:35 +02:00
|
|
|
/// Source startup scripts
|
|
|
|
static void source_startup_scripts(const mparm_T *const parmp)
|
|
|
|
FUNC_ATTR_NONNULL_ALL
|
|
|
|
{
|
2018-05-24 11:51:35 +02:00
|
|
|
// If -u given, use only the initializations from that file and nothing else.
|
2014-01-31 14:39:15 +01:00
|
|
|
if (parmp->use_vimrc != NULL) {
|
2018-05-24 11:51:35 +02:00
|
|
|
if (strequal(parmp->use_vimrc, "NONE")
|
|
|
|
|| strequal(parmp->use_vimrc, "NORC")) {
|
|
|
|
// Do nothing.
|
2014-03-16 08:20:00 +01:00
|
|
|
} else {
|
2018-05-27 03:41:02 +02:00
|
|
|
if (do_source((char_u *)parmp->use_vimrc, false, DOSO_NONE) != OK) {
|
2014-01-31 14:39:15 +01:00
|
|
|
EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc);
|
2018-05-24 11:51:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
2014-03-16 08:20:00 +01:00
|
|
|
} else if (!silent_mode) {
|
2018-12-16 05:40:41 +01:00
|
|
|
do_system_initialization();
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-10-23 16:43:35 +02:00
|
|
|
if (do_user_initialization()) {
|
|
|
|
// Read initialization commands from ".vimrc" or ".exrc" in current
|
|
|
|
// directory. This is only done if the 'exrc' option is set.
|
|
|
|
// Because of security reasons we disallow shell and write commands
|
|
|
|
// now, except for unix if the file is owned by the user or 'secure'
|
|
|
|
// option has been reset in environment of global "exrc" or "vimrc".
|
|
|
|
// Only do this if VIMRC_FILE is not the same as vimrc file sourced in
|
|
|
|
// do_user_initialization.
|
2014-04-23 07:49:52 +02:00
|
|
|
#if defined(UNIX)
|
2015-10-17 16:25:53 +02:00
|
|
|
// If vimrc file is not owned by user, set 'secure' mode.
|
2014-01-31 14:39:15 +01:00
|
|
|
if (!file_owned(VIMRC_FILE))
|
|
|
|
#endif
|
2014-02-01 15:17:43 +01:00
|
|
|
secure = p_secure;
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-10-23 16:43:35 +02:00
|
|
|
if (do_source((char_u *)VIMRC_FILE, true, DOSO_VIMRC) == FAIL) {
|
2014-04-23 07:49:52 +02:00
|
|
|
#if defined(UNIX)
|
2015-10-23 16:43:35 +02:00
|
|
|
// if ".exrc" is not owned by user set 'secure' mode
|
|
|
|
if (!file_owned(EXRC_FILE)) {
|
2014-01-31 14:39:15 +01:00
|
|
|
secure = p_secure;
|
2015-10-23 16:43:35 +02:00
|
|
|
} else {
|
2014-01-31 14:39:15 +01:00
|
|
|
secure = 0;
|
2015-10-23 16:43:35 +02:00
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
#endif
|
2015-10-23 16:43:35 +02:00
|
|
|
(void)do_source((char_u *)EXRC_FILE, false, DOSO_NONE);
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
}
|
2015-10-23 16:43:35 +02:00
|
|
|
if (secure == 2) {
|
|
|
|
need_wait_return = true;
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
secure = 0;
|
|
|
|
}
|
|
|
|
TIME_MSG("sourcing vimrc file(s)");
|
|
|
|
}
|
|
|
|
|
2015-05-13 21:29:49 +02:00
|
|
|
/// Get an environment variable, and execute it as Ex commands.
|
|
|
|
///
|
|
|
|
/// @param env environment variable to execute
|
|
|
|
///
|
|
|
|
/// @return FAIL if the environment variable was not executed,
|
|
|
|
/// OK otherwise.
|
2019-02-24 20:09:14 +01:00
|
|
|
static int execute_env(char *env)
|
2018-05-18 09:07:42 +02:00
|
|
|
FUNC_ATTR_NONNULL_ALL
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
2015-05-03 15:25:53 +02:00
|
|
|
const char *initstr = os_getenv(env);
|
|
|
|
if (initstr != NULL) {
|
2015-05-13 21:29:49 +02:00
|
|
|
char_u *save_sourcing_name = sourcing_name;
|
|
|
|
linenr_T save_sourcing_lnum = sourcing_lnum;
|
|
|
|
sourcing_name = (char_u *)env;
|
2014-01-31 14:39:15 +01:00
|
|
|
sourcing_lnum = 0;
|
2015-05-13 21:29:49 +02:00
|
|
|
scid_T save_sid = current_SID;
|
2014-01-31 14:39:15 +01:00
|
|
|
current_SID = SID_ENV;
|
2015-05-03 15:25:53 +02:00
|
|
|
do_cmdline_cmd((char *)initstr);
|
2014-01-31 14:39:15 +01:00
|
|
|
sourcing_name = save_sourcing_name;
|
|
|
|
sourcing_lnum = save_sourcing_lnum;
|
2016-12-10 13:40:29 +01:00
|
|
|
current_SID = save_sid;
|
2014-01-31 14:39:15 +01:00
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
return FAIL;
|
|
|
|
}
|
|
|
|
|
2015-01-24 01:42:21 +01:00
|
|
|
#ifdef UNIX
|
|
|
|
/// Checks if user owns file.
|
|
|
|
/// Use both uv_fs_stat() and uv_fs_lstat() through os_fileinfo() and
|
|
|
|
/// os_fileinfo_link() respectively for extra security.
|
|
|
|
static bool file_owned(const char *fname)
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
2017-08-13 18:46:09 +02:00
|
|
|
assert(fname != NULL);
|
2014-01-31 14:39:15 +01:00
|
|
|
uid_t uid = getuid();
|
2014-04-26 18:23:49 +02:00
|
|
|
FileInfo file_info;
|
2014-08-27 19:14:44 +02:00
|
|
|
bool file_owned = os_fileinfo(fname, &file_info)
|
2014-04-26 18:23:49 +02:00
|
|
|
&& file_info.stat.st_uid == uid;
|
2014-08-27 19:14:44 +02:00
|
|
|
bool link_owned = os_fileinfo_link(fname, &file_info)
|
2014-04-26 18:23:49 +02:00
|
|
|
&& file_info.stat.st_uid == uid;
|
|
|
|
return file_owned && link_owned;
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-01-24 01:42:21 +01:00
|
|
|
/// Prints the following then exits:
|
2015-05-30 07:06:19 +02:00
|
|
|
/// - An error message `errstr`
|
|
|
|
/// - A string `str` if not null
|
2015-01-24 01:42:21 +01:00
|
|
|
///
|
2015-05-30 07:06:19 +02:00
|
|
|
/// @param errstr string containing an error message
|
|
|
|
/// @param str string to append to the primary error message, or NULL
|
|
|
|
static void mainerr(const char *errstr, const char *str)
|
2014-01-31 14:39:15 +01:00
|
|
|
{
|
2017-05-17 03:23:34 +02:00
|
|
|
char *prgname = (char *)path_tail((char_u *)argv0);
|
|
|
|
|
2015-01-24 01:42:21 +01:00
|
|
|
signal_stop(); // kill us with CTRL-C here, if you like
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2017-05-17 03:23:34 +02:00
|
|
|
mch_errmsg(prgname);
|
2015-05-30 07:06:19 +02:00
|
|
|
mch_errmsg(": ");
|
2015-05-30 07:06:19 +02:00
|
|
|
mch_errmsg(_(errstr));
|
2014-01-31 14:39:15 +01:00
|
|
|
if (str != NULL) {
|
|
|
|
mch_errmsg(": \"");
|
2015-01-24 01:42:21 +01:00
|
|
|
mch_errmsg(str);
|
2014-01-31 14:39:15 +01:00
|
|
|
mch_errmsg("\"");
|
|
|
|
}
|
2015-05-30 07:06:19 +02:00
|
|
|
mch_errmsg(_("\nMore info with \""));
|
2017-05-17 03:23:34 +02:00
|
|
|
mch_errmsg(prgname);
|
2015-05-30 07:06:19 +02:00
|
|
|
mch_errmsg(" -h\"\n");
|
2014-01-31 14:39:15 +01:00
|
|
|
|
|
|
|
mch_exit(1);
|
|
|
|
}
|
|
|
|
|
2015-05-11 23:30:18 +02:00
|
|
|
/// Prints version information for "nvim -v" or "nvim --version".
|
|
|
|
static void version(void)
|
|
|
|
{
|
|
|
|
info_message = TRUE; // use mch_msg(), not mch_errmsg()
|
|
|
|
list_version();
|
|
|
|
msg_putchar('\n');
|
|
|
|
msg_didout = FALSE;
|
|
|
|
}
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-05-11 23:30:18 +02:00
|
|
|
/// Prints help message for "nvim -h" or "nvim --help".
|
2014-03-16 08:20:00 +01:00
|
|
|
static void usage(void)
|
|
|
|
{
|
2015-01-27 06:24:18 +01:00
|
|
|
signal_stop(); // kill us with CTRL-C here, if you like
|
2014-01-31 14:39:15 +01:00
|
|
|
|
2015-01-27 06:24:18 +01:00
|
|
|
mch_msg(_("Usage:\n"));
|
2017-08-05 23:53:48 +02:00
|
|
|
mch_msg(_(" nvim [options] [file ...] Edit file(s)\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"));
|
2015-01-27 06:24:18 +01:00
|
|
|
mch_msg(_(" -- Only file names after this\n"));
|
2017-08-05 23:53:48 +02:00
|
|
|
mch_msg(_(" + Start at end of file\n"));
|
|
|
|
mch_msg(_(" --cmd <cmd> Execute <cmd> before any config\n"));
|
|
|
|
mch_msg(_(" +<cmd>, -c <cmd> Execute <cmd> after config and first file\n"));
|
|
|
|
mch_msg("\n");
|
|
|
|
mch_msg(_(" -b Binary mode\n"));
|
2015-01-20 01:37:13 +01:00
|
|
|
mch_msg(_(" -d Diff mode\n"));
|
2018-06-04 02:06:32 +02:00
|
|
|
mch_msg(_(" -e, -E Ex mode\n"));
|
|
|
|
mch_msg(_(" -es, -Es Silent (batch) mode\n"));
|
2017-08-05 23:53:48 +02:00
|
|
|
mch_msg(_(" -h, --help Print this help message\n"));
|
|
|
|
mch_msg(_(" -i <shada> Use this shada file\n"));
|
2015-01-27 06:24:18 +01:00
|
|
|
mch_msg(_(" -m Modifications (writing files) not allowed\n"));
|
|
|
|
mch_msg(_(" -M Modifications in text not allowed\n"));
|
|
|
|
mch_msg(_(" -n No swap file, use memory only\n"));
|
2017-08-05 23:53:48 +02:00
|
|
|
mch_msg(_(" -o[N] Open N windows (default: one per file)\n"));
|
|
|
|
mch_msg(_(" -O[N] Open N vertical windows (default: one per file)\n"));
|
|
|
|
mch_msg(_(" -p[N] Open N tab pages (default: one per file)\n"));
|
|
|
|
mch_msg(_(" -r, -L List swap files\n"));
|
|
|
|
mch_msg(_(" -r <file> Recover edit state for this file\n"));
|
|
|
|
mch_msg(_(" -R Read-only mode\n"));
|
2015-05-11 23:30:19 +02:00
|
|
|
mch_msg(_(" -S <session> Source <session> after loading the first file\n"));
|
|
|
|
mch_msg(_(" -s <scriptin> Read Normal mode commands from <scriptin>\n"));
|
2017-08-05 23:53:48 +02:00
|
|
|
mch_msg(_(" -u <config> Use this config file\n"));
|
|
|
|
mch_msg(_(" -v, --version Print version information\n"));
|
|
|
|
mch_msg(_(" -V[N][file] Verbose [level][file]\n"));
|
|
|
|
mch_msg(_(" -Z Restricted mode\n"));
|
|
|
|
mch_msg("\n");
|
|
|
|
mch_msg(_(" --api-info Write msgpack-encoded API metadata to stdout\n"));
|
2015-01-27 06:24:18 +01:00
|
|
|
mch_msg(_(" --embed Use stdin/stdout as a msgpack-rpc channel\n"));
|
2015-02-13 16:06:05 +01:00
|
|
|
mch_msg(_(" --headless Don't start a user interface\n"));
|
2017-12-03 03:38:58 +01:00
|
|
|
mch_msg(_(" --listen <address> Serve RPC API from this address\n"));
|
2017-08-05 23:53:48 +02:00
|
|
|
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"));
|
2014-01-31 14:39:15 +01:00
|
|
|
}
|
|
|
|
|
2015-01-27 06:24:18 +01:00
|
|
|
|
2014-01-31 14:39:15 +01:00
|
|
|
/*
|
|
|
|
* Check the result of the ATTENTION dialog:
|
|
|
|
* When "Quit" selected, exit Vim.
|
|
|
|
* When "Recover" selected, recover the file.
|
|
|
|
*/
|
2014-03-16 08:20:00 +01:00
|
|
|
static void check_swap_exists_action(void)
|
|
|
|
{
|
2014-01-31 14:39:15 +01:00
|
|
|
if (swap_exists_action == SEA_QUIT)
|
|
|
|
getout(1);
|
|
|
|
handle_swap_exists(NULL);
|
|
|
|
}
|