diff options
Diffstat (limited to 'src/nvim')
48 files changed, 843 insertions, 486 deletions
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 271fd5b485..055abb797f 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -16,6 +16,7 @@ #define BOOLEAN_OBJ(b) ((Object) { \ .type = kObjectTypeBoolean, \ .data.boolean = b }) +#define BOOL(b) BOOLEAN_OBJ(b) #define INTEGER_OBJ(i) ((Object) { \ .type = kObjectTypeInteger, \ @@ -29,6 +30,8 @@ .type = kObjectTypeString, \ .data.string = s }) +#define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s)) + #define BUFFER_OBJ(s) ((Object) { \ .type = kObjectTypeBuffer, \ .data.integer = s }) @@ -59,6 +62,8 @@ #define PUT(dict, k, v) \ kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v })) +#define PUT_BOOL(dict, name, condition) PUT(dict, name, BOOLEAN_OBJ(condition)); + #define ADD(array, item) \ kv_push(array, item) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 77002697fe..8ac820abd9 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -970,6 +970,47 @@ Object nvim_get_option(String name, Error *err) return get_option_from(NULL, SREQ_GLOBAL, name, err); } +/// Gets the option information for all options. +/// +/// The dictionary has the full option names as keys and option metadata +/// dictionaries as detailed at |nvim_get_option_info|. +/// +/// @return dictionary of all options +Dictionary nvim_get_all_options_info(Error *err) + FUNC_API_SINCE(7) +{ + return get_all_vimoptions(); +} + +/// Gets the option information for one option +/// +/// Resulting dictionary has keys: +/// - name: Name of the option (like 'filetype') +/// - shortname: Shortened name of the option (like 'ft') +/// - type: type of option ("string", "integer" or "boolean") +/// - default: The default value for the option +/// - was_set: Whether the option was set. +/// +/// - last_set_sid: Last set script id (if any) +/// - last_set_linenr: line number where option was set +/// - last_set_chan: Channel where option was set (0 for local) +/// +/// - scope: one of "global", "win", or "buf" +/// - global_local: whether win or buf option has a global value +/// +/// - commalist: List of comma separated values +/// - flaglist: List of single char flags +/// +/// +/// @param name Option name +/// @param[out] err Error details, if any +/// @return Option Information +Dictionary nvim_get_option_info(String name, Error *err) + FUNC_API_SINCE(7) +{ + return get_vimoption(name, err); +} + /// Sets an option value. /// /// @param channel_id diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index ffa44c33cd..839d61cd2e 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -1637,12 +1637,23 @@ void do_autochdir(void) void no_write_message(void) { - EMSG(_("E37: No write since last change (add ! to override)")); + if (curbuf->terminal + && channel_job_running((uint64_t)curbuf->b_p_channel)) { + EMSG(_("E948: Job still running (add ! to end the job)")); + } else { + EMSG(_("E37: No write since last change (add ! to override)")); + } } -void no_write_message_nobang(void) +void no_write_message_nobang(const buf_T *const buf) + FUNC_ATTR_NONNULL_ALL { - EMSG(_("E37: No write since last change")); + if (buf->terminal + && channel_job_running((uint64_t)buf->b_p_channel)) { + EMSG(_("E948: Job still running")); + } else { + EMSG(_("E37: No write since last change")); + } } // diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 5d44c3274e..7fefa8520a 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -196,8 +196,8 @@ static int ctrl_x_mode = CTRL_X_NORMAL; static int compl_matches = 0; static char_u *compl_pattern = NULL; -static int compl_direction = FORWARD; -static int compl_shows_dir = FORWARD; +static Direction compl_direction = FORWARD; +static Direction compl_shows_dir = FORWARD; static int compl_pending = 0; // > 1 for postponed CTRL-N static pos_T compl_startpos; static colnr_T compl_col = 0; /* column where the text starts @@ -2156,7 +2156,7 @@ static bool ins_compl_accept_char(int c) /// /// @param[in] cont_s_ipos next ^X<> will set initial_pos int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname, - int dir, bool cont_s_ipos) + Direction dir, bool cont_s_ipos) FUNC_ATTR_NONNULL_ARG(1) { char_u *str = str_arg; @@ -2308,7 +2308,7 @@ static int ins_compl_add(char_u *const str, int len, FUNC_ATTR_NONNULL_ARG(1) { compl_T *match; - int dir = (cdir == kDirectionNotSet ? compl_direction : cdir); + const Direction dir = (cdir == kDirectionNotSet ? compl_direction : cdir); int flags = flags_arg; os_breakcheck(); @@ -2511,7 +2511,7 @@ static void ins_compl_add_matches(int num_matches, char_u **matches, int icase) FUNC_ATTR_NONNULL_ALL { int add_r = OK; - int dir = compl_direction; + Direction dir = compl_direction; for (int i = 0; i < num_matches && add_r != FAIL; i++) { if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir, @@ -2864,7 +2864,7 @@ ins_compl_dictionaries ( char_u **files; int count; int save_p_scs; - int dir = compl_direction; + Direction dir = compl_direction; if (*dict == NUL) { /* When 'dictionary' is empty and spell checking is enabled use @@ -2945,7 +2945,10 @@ theend: xfree(buf); } -static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir) +static void ins_compl_files(int count, char_u **files, int thesaurus, + int flags, regmatch_T *regmatch, char_u *buf, + Direction *dir) + FUNC_ATTR_NONNULL_ARG(2, 7) { char_u *ptr; int i; @@ -3137,6 +3140,56 @@ bool ins_compl_active(void) return compl_started; } +static void ins_compl_update_sequence_numbers(void) +{ + int number = 0; + compl_T *match; + + if (compl_direction == FORWARD) { + // search backwards for the first valid (!= -1) number. + // This should normally succeed already at the first loop + // cycle, so it's fast! + for (match = compl_curr_match->cp_prev; + match != NULL && match != compl_first_match; + match = match->cp_prev) { + if (match->cp_number != -1) { + number = match->cp_number; + break; + } + } + if (match != NULL) { + // go up and assign all numbers which are not assigned yet + for (match = match->cp_next; + match != NULL && match->cp_number == -1; + match = match->cp_next) { + match->cp_number = ++number; + } + } + } else { // BACKWARD + assert(compl_direction == BACKWARD); + // search forwards (upwards) for the first valid (!= -1) + // number. This should normally succeed already at the + // first loop cycle, so it's fast! + for (match = compl_curr_match->cp_next; + match != NULL && match != compl_first_match; + match = match->cp_next) { + if (match->cp_number != -1) { + number = match->cp_number; + break; + } + } + if (match != NULL) { + // go down and assign all numbers which are not + // assigned yet + for (match = match->cp_prev; + match && match->cp_number == -1; + match = match->cp_prev) { + match->cp_number = ++number; + } + } + } +} + // Get complete information void get_complete_info(list_T *what_list, dict_T *retdict) { @@ -3214,6 +3267,9 @@ void get_complete_info(list_T *what_list, dict_T *retdict) } if (ret == OK && (what_flag & CI_WHAT_SELECTED)) { + if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) { + ins_compl_update_sequence_numbers(); + } ret = tv_dict_add_nr(retdict, S_LEN("selected"), (compl_curr_match != NULL) ? compl_curr_match->cp_number - 1 : -1); @@ -3865,7 +3921,7 @@ theend: */ static void ins_compl_add_list(list_T *const list) { - int dir = compl_direction; + Direction dir = compl_direction; // Go through the List with matches and add each of them. TV_LIST_ITER(list, li, { @@ -5242,52 +5298,11 @@ static int ins_complete(int c, bool enable_pum) } else if (compl_curr_match->cp_next == compl_curr_match->cp_prev) { edit_submode_extra = (char_u *)_("The only match"); edit_submode_highl = HLF_COUNT; + compl_curr_match->cp_number = 1; } else { // Update completion sequence number when needed. if (compl_curr_match->cp_number == -1) { - int number = 0; - compl_T *match; - - if (compl_direction == FORWARD) { - /* search backwards for the first valid (!= -1) number. - * This should normally succeed already at the first loop - * cycle, so it's fast! */ - for (match = compl_curr_match->cp_prev; match != NULL - && match != compl_first_match; - match = match->cp_prev) - if (match->cp_number != -1) { - number = match->cp_number; - break; - } - if (match != NULL) - /* go up and assign all numbers which are not assigned - * yet */ - for (match = match->cp_next; - match != NULL && match->cp_number == -1; - match = match->cp_next) - match->cp_number = ++number; - } else { // BACKWARD - // search forwards (upwards) for the first valid (!= -1) - // number. This should normally succeed already at the - // first loop cycle, so it's fast! - for (match = compl_curr_match->cp_next; - match != NULL && match != compl_first_match; - match = match->cp_next) { - if (match->cp_number != -1) { - number = match->cp_number; - break; - } - } - if (match != NULL) { - // go down and assign all numbers which are not - // assigned yet - for (match = match->cp_prev; - match && match->cp_number == -1; - match = match->cp_prev) { - match->cp_number = ++number; - } - } - } + ins_compl_update_sequence_numbers(); } /* The match should always have a sequence number now, this is diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 054b788940..fa037b59d7 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -64,6 +64,7 @@ static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary"); static char *e_illvar = N_("E461: Illegal variable name: %s"); static char *e_cannot_mod = N_("E995: Cannot modify existing variable"); static char *e_invalwindow = N_("E957: Invalid window number"); +static char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s"); // TODO(ZyX-I): move to eval/executor static char *e_letwrong = N_("E734: Wrong variable type for %s="); @@ -2638,22 +2639,18 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx) xp->xp_pattern = arg; } -/* - * ":unlet[!] var1 ... " command. - */ +/// ":unlet[!] var1 ... " command. void ex_unlet(exarg_T *eap) { - ex_unletlock(eap, eap->arg, 0); + ex_unletlock(eap, eap->arg, 0, do_unlet_var); } // TODO(ZyX-I): move to eval/ex_cmds -/* - * ":lockvar" and ":unlockvar" commands - */ +/// ":lockvar" and ":unlockvar" commands void ex_lockvar(exarg_T *eap) { - char_u *arg = eap->arg; + char_u *arg = eap->arg; int deep = 2; if (eap->forceit) { @@ -2663,30 +2660,41 @@ void ex_lockvar(exarg_T *eap) arg = skipwhite(arg); } - ex_unletlock(eap, arg, deep); + ex_unletlock(eap, arg, deep, do_lock_var); } // TODO(ZyX-I): move to eval/ex_cmds -/* - * ":unlet", ":lockvar" and ":unlockvar" are quite similar. - */ -static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep) +/// Common parsing logic for :unlet, :lockvar and :unlockvar. +/// +/// Invokes `callback` afterwards if successful and `eap->skip == false`. +/// +/// @param[in] eap Ex command arguments for the command. +/// @param[in] argstart Start of the string argument for the command. +/// @param[in] deep Levels to (un)lock for :(un)lockvar, -1 to (un)lock +/// everything. +/// @param[in] callback Appropriate handler for the command. +static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep, + ex_unletlock_callback callback) + FUNC_ATTR_NONNULL_ALL { - char_u *arg = argstart; + char_u *arg = argstart; char_u *name_end; bool error = false; lval_T lv; do { if (*arg == '$') { - const char *name = (char *)++arg; - + lv.ll_name = (const char *)arg; + lv.ll_tv = NULL; + arg++; if (get_env_len((const char_u **)&arg) == 0) { - EMSG2(_(e_invarg2), name - 1); + EMSG2(_(e_invarg2), arg - 1); return; } - os_unsetenv(name); + if (!error && !eap->skip && callback(&lv, arg, eap, deep) == FAIL) { + error = true; + } name_end = arg; } else { // Parse the name and find the end. @@ -2707,17 +2715,8 @@ static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep) break; } - if (!error && !eap->skip) { - if (eap->cmdidx == CMD_unlet) { - if (do_unlet_var(&lv, name_end, eap->forceit) == FAIL) { - error = true; - } - } else { - if (do_lock_var(&lv, name_end, deep, - eap->cmdidx == CMD_lockvar) == FAIL) { - error = true; - } - } + if (!error && !eap->skip && callback(&lv, name_end, eap, deep) == FAIL) { + error = true; } if (!eap->skip) { @@ -2732,8 +2731,19 @@ static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep) // TODO(ZyX-I): move to eval/ex_cmds -static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit) +/// Unlet a variable indicated by `lp`. +/// +/// @param[in] lp The lvalue. +/// @param[in] name_end End of the string argument for the command. +/// @param[in] eap Ex command arguments for :unlet. +/// @param[in] deep Unused. +/// +/// @return OK on success, or FAIL on failure. +static int do_unlet_var(lval_T *lp, char_u *name_end, exarg_T *eap, + int deep FUNC_ATTR_UNUSED) + FUNC_ATTR_NONNULL_ALL { + int forceit = eap->forceit; int ret = OK; int cc; @@ -2741,8 +2751,10 @@ static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit) cc = *name_end; *name_end = NUL; - // Normal name or expanded name. - if (do_unlet(lp->ll_name, lp->ll_name_len, forceit) == FAIL) { + // Environment variable, normal name or expanded name. + if (*lp->ll_name == '$') { + os_unsetenv(lp->ll_name + 1); + } else if (do_unlet(lp->ll_name, lp->ll_name_len, forceit) == FAIL) { ret = FAIL; } *name_end = cc; @@ -2816,7 +2828,7 @@ static int do_unlet_var(lval_T *const lp, char_u *const name_end, int forceit) /// /// @param[in] name Variable name to unlet. /// @param[in] name_len Variable name length. -/// @param[in] fonceit If true, do not complain if variable doesn’t exist. +/// @param[in] forceit If true, do not complain if variable doesn’t exist. /// /// @return OK if it existed, FAIL otherwise. int do_unlet(const char *const name, const size_t name_len, const bool forceit) @@ -2883,14 +2895,21 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit) // TODO(ZyX-I): move to eval/ex_cmds -/* - * Lock or unlock variable indicated by "lp". - * "deep" is the levels to go (-1 for unlimited); - * "lock" is TRUE for ":lockvar", FALSE for ":unlockvar". - */ -static int do_lock_var(lval_T *lp, char_u *const name_end, const int deep, - const bool lock) +/// Lock or unlock variable indicated by `lp`. +/// +/// Locks if `eap->cmdidx == CMD_lockvar`, unlocks otherwise. +/// +/// @param[in] lp The lvalue. +/// @param[in] name_end Unused. +/// @param[in] eap Ex command arguments for :(un)lockvar. +/// @param[in] deep Levels to (un)lock, -1 to (un)lock everything. +/// +/// @return OK on success, or FAIL on failure. +static int do_lock_var(lval_T *lp, char_u *name_end FUNC_ATTR_UNUSED, + exarg_T *eap, int deep) + FUNC_ATTR_NONNULL_ARG(1, 3) { + bool lock = eap->cmdidx == CMD_lockvar; int ret = OK; if (deep == 0) { // Nothing to do. @@ -2898,25 +2917,31 @@ static int do_lock_var(lval_T *lp, char_u *const name_end, const int deep, } if (lp->ll_tv == NULL) { - // Normal name or expanded name. - dictitem_T *const di = find_var( - (const char *)lp->ll_name, lp->ll_name_len, NULL, - true); - if (di == NULL) { + if (*lp->ll_name == '$') { + EMSG2(_(e_lock_unlock), lp->ll_name); ret = FAIL; - } else if ((di->di_flags & DI_FLAGS_FIX) - && di->di_tv.v_type != VAR_DICT - && di->di_tv.v_type != VAR_LIST) { - // For historical reasons this error is not given for Lists and - // Dictionaries. E.g. b: dictionary may be locked/unlocked. - emsgf(_("E940: Cannot lock or unlock variable %s"), lp->ll_name); } else { - if (lock) { - di->di_flags |= DI_FLAGS_LOCK; + // Normal name or expanded name. + dictitem_T *const di = find_var( + (const char *)lp->ll_name, lp->ll_name_len, NULL, + true); + if (di == NULL) { + ret = FAIL; + } else if ((di->di_flags & DI_FLAGS_FIX) + && di->di_tv.v_type != VAR_DICT + && di->di_tv.v_type != VAR_LIST) { + // For historical reasons this error is not given for Lists and + // Dictionaries. E.g. b: dictionary may be locked/unlocked. + EMSG2(_(e_lock_unlock), lp->ll_name); + ret = FAIL; } else { - di->di_flags &= ~DI_FLAGS_LOCK; + if (lock) { + di->di_flags |= DI_FLAGS_LOCK; + } else { + di->di_flags &= ~DI_FLAGS_LOCK; + } + tv_item_lock(&di->di_tv, deep, lock); } - tv_item_lock(&di->di_tv, deep, lock); } } else if (lp->ll_range) { listitem_T *li = lp->ll_li; diff --git a/src/nvim/eval.h b/src/nvim/eval.h index 0b4cbb3b4d..06b7f9e21d 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -233,6 +233,8 @@ typedef enum { kDictListItems, ///< List dictionary contents: [keys, values]. } DictListType; +typedef int (*ex_unletlock_callback)(lval_T *, char_u *, exarg_T *, int); + // Used for checking if local variables or arguments used in a lambda. extern bool *eval_lavars_used; diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b08ee3794d..4df935469a 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7044,7 +7044,8 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, FunPtr fptr) xfree(buf); } # else - rettv->vval.v_string = (char_u *)xstrdup(p); + char *v = os_realpath(fname, NULL); + rettv->vval.v_string = (char_u *)(v == NULL ? xstrdup(fname) : v); # endif #endif diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index d2ccbe3e6d..b0a51eaefd 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -1965,7 +1965,12 @@ void do_wqall(exarg_T *eap) } FOR_ALL_BUFFERS(buf) { - if (!bufIsChanged(buf) || bt_dontwrite(buf)) { + if (exiting + && buf->terminal + && channel_job_running((uint64_t)buf->b_p_channel)) { + no_write_message_nobang(buf); + error++; + } else if (!bufIsChanged(buf) || bt_dontwrite(buf)) { continue; } /* diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 6b03117ff3..3b9c44c3cd 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1297,7 +1297,7 @@ bool check_changed(buf_T *buf, int flags) if (flags & CCGD_EXCMD) { no_write_message(); } else { - no_write_message_nobang(); + no_write_message_nobang(curbuf); } return true; } @@ -1503,8 +1503,10 @@ bool check_changed_any(bool hidden, bool unload) msg_col = 0; msg_didout = false; } - if (EMSG2(_("E162: No write since last change for buffer \"%s\""), - buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) { + if ((buf->terminal && channel_job_running((uint64_t)buf->b_p_channel)) + ? EMSG2(_("E947: Job still running in buffer \"%s\""), buf->b_fname) + : EMSG2(_("E162: No write since last change for buffer \"%s\""), + buf_spname(buf) != NULL ? buf_spname(buf) : buf->b_fname)) { save = no_wait_return; no_wait_return = false; wait_return(false); diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 0100be15bc..ed408c28e5 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -1024,7 +1024,7 @@ static int command_line_execute(VimState *state, int key) } // free expanded names when finished walking through matches - if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm + if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A && s->c != Ctrl_L) { if (compl_match_array) { @@ -1328,7 +1328,8 @@ static int command_line_execute(VimState *state, int key) // - hitting <ESC> twice means: abandon command line. // - wildcard expansion is only done when the 'wildchar' key is really // typed, not when it comes from a macro - if ((s->c == p_wc && !s->gotesc && KeyTyped) || s->c == p_wcm) { + if ((s->c == p_wc && !s->gotesc && KeyTyped) || s->c == p_wcm + || s->c == Ctrl_Z) { int options = WILD_NO_BEEP; if (wim_flags[s->wim_index] & WIM_BUFLASTUSED) { options |= WILD_BUFLASTUSED; diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 0a3c30134b..344a2387d6 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -927,7 +927,7 @@ void nlua_typval_eval(const String str, typval_T *const arg, memcpy(lcmd + sizeof(EVALHEADER) - 1, str.data, str.size); lcmd[lcmd_len - 1] = ')'; #undef EVALHEADER - typval_exec_lua(lcmd, lcmd_len, "luaeval()", arg, 1, true, ret_tv); + nlua_typval_exec(lcmd, lcmd_len, "luaeval()", arg, 1, true, ret_tv); if (lcmd != (char *)IObuff) { xfree(lcmd); @@ -954,16 +954,16 @@ void nlua_typval_call(const char *str, size_t len, typval_T *const args, #undef CALLHEADER #undef CALLSUFFIX - typval_exec_lua(lcmd, lcmd_len, "v:lua", args, argcount, false, ret_tv); + nlua_typval_exec(lcmd, lcmd_len, "v:lua", args, argcount, false, ret_tv); if (lcmd != (char *)IObuff) { xfree(lcmd); } } -static void typval_exec_lua(const char *lcmd, size_t lcmd_len, const char *name, - typval_T *const args, int argcount, bool special, - typval_T *ret_tv) +static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, + const char *name, typval_T *const args, + int argcount, bool special, typval_T *ret_tv) { if (check_secure()) { if (ret_tv) { @@ -1140,7 +1140,7 @@ void ex_lua(exarg_T *const eap) xfree(code); return; } - typval_exec_lua(code, len, ":lua", NULL, 0, false, NULL); + nlua_typval_exec(code, len, ":lua", NULL, 0, false, NULL); xfree(code); } @@ -1231,17 +1231,30 @@ void ex_luado(exarg_T *const eap) void ex_luafile(exarg_T *const eap) FUNC_ATTR_NONNULL_ALL { + nlua_exec_file((const char *)eap->arg); +} + +/// execute lua code from a file. +/// +/// @param path path of the file +/// +/// @return true if everything ok, false if there was an error (echoed) +bool nlua_exec_file(const char *path) + FUNC_ATTR_NONNULL_ALL +{ lua_State *const lstate = nlua_enter(); - if (luaL_loadfile(lstate, (const char *)eap->arg)) { + if (luaL_loadfile(lstate, path)) { nlua_error(lstate, _("E5112: Error while creating lua chunk: %.*s")); - return; + return false; } if (lua_pcall(lstate, 0, 0, 0)) { nlua_error(lstate, _("E5113: Error while calling lua chunk: %.*s")); - return; + return false; } + + return true; } static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL diff --git a/src/nvim/main.c b/src/nvim/main.c index 63249416b1..79c165419e 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1069,9 +1069,14 @@ static void command_line_scan(mparm_T *parmp) } else { a = argv[0]; } - size_t s_size = STRLEN(a) + 4; + + size_t s_size = STRLEN(a) + 9; char *s = xmalloc(s_size); - snprintf(s, s_size, "so %s", a); + if (path_with_extension(a, "lua")) { + snprintf(s, s_size, "luafile %s", a); + } else { + snprintf(s, s_size, "so %s", a); + } parmp->cmds_tofree[parmp->n_commands] = true; parmp->commands[parmp->n_commands++] = s; } else { @@ -1770,6 +1775,23 @@ static bool do_user_initialization(void) do_exrc = p_exrc; return do_exrc; } + + char_u *init_lua_path = (char_u *)stdpaths_user_conf_subpath("init.lua"); + if (os_path_exists(init_lua_path) + && nlua_exec_file((const char *)init_lua_path)) { + os_setenv("MYVIMRC", (const char *)init_lua_path, 1); + char_u *vimrc_path = (char_u *)stdpaths_user_conf_subpath("init.vim"); + + if (os_path_exists(vimrc_path)) { + EMSG3(_("Conflicting configs: \"%s\" \"%s\""), init_lua_path, vimrc_path); + } + + xfree(vimrc_path); + xfree(init_lua_path); + return false; + } + xfree(init_lua_path); + char_u *user_vimrc = (char_u *)stdpaths_user_conf_subpath("init.vim"); if (do_source(user_vimrc, true, DOSO_VIMRC) != FAIL) { do_exrc = p_exrc; @@ -1829,8 +1851,12 @@ static void source_startup_scripts(const mparm_T *const parmp) || strequal(parmp->use_vimrc, "NORC")) { // Do nothing. } else { - if (do_source((char_u *)parmp->use_vimrc, false, DOSO_NONE) != OK) { - EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc); + if (path_with_extension(parmp->use_vimrc, "lua")) { + nlua_exec_file(parmp->use_vimrc); + } else { + if (do_source((char_u *)parmp->use_vimrc, false, DOSO_NONE) != OK) { + EMSG2(_("E282: Cannot read from \"%s\""), parmp->use_vimrc); + } } } } else if (!silent_mode) { diff --git a/src/nvim/message.c b/src/nvim/message.c index f76a408481..ad38e6d060 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1711,8 +1711,11 @@ void msg_prt_line(char_u *s, int list) } else if ((l = utfc_ptr2len(s)) > 1) { col += utf_ptr2cells(s); char buf[MB_MAXBYTES + 1]; - if (curwin->w_p_lcs_chars.nbsp != NUL && list - && (utf_ptr2char(s) == 160 || utf_ptr2char(s) == 0x202f)) { + if (l >= MB_MAXBYTES) { + xstrlcpy(buf, "¿", sizeof(buf)); + } else if (curwin->w_p_lcs_chars.nbsp != NUL && list + && (utf_ptr2char(s) == 160 + || utf_ptr2char(s) == 0x202f)) { utf_char2bytes(curwin->w_p_lcs_chars.nbsp, (char_u *)buf); buf[utfc_ptr2len((char_u *)buf)] = NUL; } else { diff --git a/src/nvim/option.c b/src/nvim/option.c index 0034117ddc..acca6fe681 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -352,9 +352,6 @@ void set_init_1(bool clean_arg) langmap_init(); - // Be nocompatible - p_cp = false; - /* * Find default value for 'shell' option. * Don't use it if it is empty. @@ -683,7 +680,7 @@ set_options_default( { for (int i = 0; options[i].fullname; i++) { if (!(options[i].flags & P_NODEFAULT)) { - set_option_default(i, opt_flags, p_cp); + set_option_default(i, opt_flags, false); } } @@ -763,7 +760,7 @@ void set_init_2(bool headless) // which results in the actual value computed from the window height. idx = findoption("scroll"); if (idx >= 0 && !(options[idx].flags & P_WAS_SET)) { - set_option_default(idx, OPT_LOCAL, p_cp); + set_option_default(idx, OPT_LOCAL, false); } comp_col(); @@ -1113,7 +1110,7 @@ int do_set( if (vim_strchr((char_u *)"?=:!&<", nextchar) != NULL) { arg += len; - cp_val = p_cp; + cp_val = false; if (nextchar == '&' && arg[1] == 'v' && arg[2] == 'i') { if (arg[3] == 'm') { // "opt&vim": set to Vim default cp_val = false; @@ -3617,10 +3614,14 @@ static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) { int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; int indir = (int)options[opt_idx].indir; - const LastSet last_set = { .script_ctx = - { script_ctx.sc_sid, script_ctx.sc_seq, - script_ctx.sc_lnum + sourcing_lnum }, - current_channel_id }; + const LastSet last_set = { + .script_ctx = { + script_ctx.sc_sid, + script_ctx.sc_seq, + script_ctx.sc_lnum + sourcing_lnum + }, + current_channel_id + }; // Remember where the option was set. For local options need to do that // in the buffer or window structure. @@ -4950,7 +4951,7 @@ static int optval_default(vimoption_T *p, char_u *varp) if (varp == NULL) { return true; // hidden option is always at default } - dvi = ((p->flags & P_VI_DEF) || p_cp) ? VI_DEFAULT : VIM_DEFAULT; + dvi = (p->flags & P_VI_DEF) ? VI_DEFAULT : VIM_DEFAULT; if (p->flags & P_NUM) { return *(long *)varp == (long)(intptr_t)p->def_val[dvi]; } @@ -7174,3 +7175,75 @@ long get_sidescrolloff_value(void) { return curwin->w_p_siso < 0 ? p_siso : curwin->w_p_siso; } + +Dictionary get_vimoption(String name, Error *err) +{ + int opt_idx = findoption_len((const char *)name.data, name.size); + if (opt_idx < 0) { + api_set_error(err, kErrorTypeValidation, "no such option: '%s'", name.data); + return (Dictionary)ARRAY_DICT_INIT; + } + return vimoption2dict(&options[opt_idx]); +} + +Dictionary get_all_vimoptions(void) +{ + Dictionary retval = ARRAY_DICT_INIT; + for (size_t i = 0; i < PARAM_COUNT; i++) { + Dictionary opt_dict = vimoption2dict(&options[i]); + PUT(retval, options[i].fullname, DICTIONARY_OBJ(opt_dict)); + } + return retval; +} + +static Dictionary vimoption2dict(vimoption_T *opt) +{ + Dictionary dict = ARRAY_DICT_INIT; + + PUT(dict, "name", CSTR_TO_OBJ(opt->fullname)); + PUT(dict, "shortname", CSTR_TO_OBJ(opt->shortname)); + + const char *scope; + if (opt->indir & PV_BUF) { + scope = "buf"; + } else if (opt->indir & PV_WIN) { + scope = "win"; + } else { + scope = "global"; + } + + PUT(dict, "scope", CSTR_TO_OBJ(scope)); + + // welcome to the jungle + PUT(dict, "global_local", BOOL(opt->indir & PV_BOTH)); + PUT(dict, "commalist", BOOL(opt->flags & P_COMMA)); + PUT(dict, "flaglist", BOOL(opt->flags & P_FLAGLIST)); + + PUT(dict, "was_set", BOOL(opt->flags & P_WAS_SET)); + + PUT(dict, "last_set_sid", INTEGER_OBJ(opt->last_set.script_ctx.sc_sid)); + PUT(dict, "last_set_linenr", INTEGER_OBJ(opt->last_set.script_ctx.sc_lnum)); + PUT(dict, "last_set_chan", INTEGER_OBJ((int64_t)opt->last_set.channel_id)); + + const char *type; + Object def; + // TODO(bfredl): do you even nocp? + char_u *def_val = opt->def_val[(opt->flags & P_VI_DEF) + ? VI_DEFAULT : VIM_DEFAULT]; + if (opt->flags & P_STRING) { + type = "string"; + def = CSTR_TO_OBJ(def_val ? (char *)def_val : ""); + } else if (opt->flags & P_NUM) { + type = "number"; + def = INTEGER_OBJ((Integer)(intptr_t)def_val); + } else if (opt->flags & P_BOOL) { + type = "boolean"; + def = BOOL((intptr_t)def_val); + } else { + type = ""; def = NIL; + } + PUT(dict, "type", CSTR_TO_OBJ(type)); + PUT(dict, "default", def); + + return dict; +} diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index af0ea7f4a2..ec2160d365 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -372,7 +372,6 @@ EXTERN long p_cwh; // 'cmdwinheight' EXTERN long p_ch; // 'cmdheight' EXTERN long p_columns; // 'columns' EXTERN int p_confirm; // 'confirm' -EXTERN int p_cp; // 'compatible' EXTERN char_u *p_cot; // 'completeopt' # ifdef BACKSLASH_IN_FILENAME EXTERN char_u *p_csl; // 'completeslash' diff --git a/src/nvim/path.c b/src/nvim/path.c index f52fbbd5c8..2de7e00ddb 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -1704,6 +1704,13 @@ int path_with_url(const char *fname) return path_is_url(p); } +bool path_with_extension(const char *path, const char *extension) +{ + const char *last_dot = strrchr(path, '.'); + if (!last_dot) { return false; } + return strcmp(last_dot + 1, extension) == 0; +} + /* * Return TRUE if "name" is a full (absolute) path name or URL. */ diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 3d7d587ed2..7fdc998e20 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -6155,7 +6155,7 @@ static int qf_setprop_items_from_lines( qf_free_items(&qi->qf_lists[qf_idx]); } if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat, - false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { + false, (linenr_T)0, (linenr_T)0, NULL, NULL) >= 0) { retval = OK; } @@ -6256,9 +6256,12 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action, retval = qf_setprop_curidx(qi, qfl, di); } - if (retval == OK) { + if (newlist || retval == OK) { qf_list_changed(qfl); } + if (newlist) { + qf_update_buffer(qi, NULL); + } return retval; } diff --git a/src/nvim/search.c b/src/nvim/search.c index 90e1e25de2..787a464070 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -89,7 +89,7 @@ static struct spat spats[2] = static int last_idx = 0; /* index in spats[] for RE_LAST */ static char_u lastc[2] = { NUL, NUL }; // last character searched for -static int lastcdir = FORWARD; // last direction of character search +static Direction lastcdir = FORWARD; // last direction of character search static int last_t_cmd = true; // last search t_cmd static char_u lastc_bytes[MB_MAXBYTES + 1]; static int lastc_bytelen = 1; // >1 for multi-byte char @@ -437,7 +437,7 @@ void set_last_csearch(int c, char_u *s, int len) memset(lastc_bytes, 0, sizeof(lastc_bytes)); } -void set_csearch_direction(int cdir) +void set_csearch_direction(Direction cdir) { lastcdir = cdir; } @@ -1430,7 +1430,7 @@ end_do_search: * ADDING is set. If p_ic is set then the pattern must be in lowercase. * Return OK for success, or FAIL if no line found. */ -int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat) +int search_for_exact_line(buf_T *buf, pos_T *pos, Direction dir, char_u *pat) { linenr_T start = 0; char_u *ptr; @@ -1496,10 +1496,11 @@ int search_for_exact_line(buf_T *buf, pos_T *pos, int dir, char_u *pat) * Return FAIL or OK. */ int searchc(cmdarg_T *cap, int t_cmd) + FUNC_ATTR_NONNULL_ALL { - int c = cap->nchar; /* char to search for */ - int dir = cap->arg; /* TRUE for searching forward */ - long count = cap->count1; /* repeat count */ + int c = cap->nchar; // char to search for + Direction dir = cap->arg; // TRUE for searching forward + long count = cap->count1; // repeat count int col; char_u *p; int len; @@ -4462,7 +4463,7 @@ static void search_stat(int dirc, pos_T *pos, void find_pattern_in_path( char_u *ptr, // pointer to search pattern - int dir, // direction of expansion + Direction dir, // direction of expansion size_t len, // length of search pattern bool whole, // match whole words only bool skip_comments, // don't match inside comments diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 797fe41320..5714f5e425 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -79,7 +79,6 @@ /* for offsetof() */ #include <stddef.h> -#include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/spell.h" #include "nvim/buffer.h" @@ -6653,7 +6652,7 @@ void spell_dump_compl ( char_u *pat, // leading part of the word int ic, // ignore case - int *dir, // direction for adding matches + Direction *dir, // direction for adding matches int dumpflags_arg // DUMPFLAG_* ) { @@ -6820,7 +6819,9 @@ spell_dump_compl ( // Dumps one word: apply case modifications and append a line to the buffer. // When "lnum" is zero add insert mode completion. -static void dump_word(slang_T *slang, char_u *word, char_u *pat, int *dir, int dumpflags, int wordflags, linenr_T lnum) +static void dump_word(slang_T *slang, char_u *word, char_u *pat, + Direction *dir, int dumpflags, int wordflags, + linenr_T lnum) { bool keepcap = false; char_u *p; @@ -6906,7 +6907,7 @@ dump_prefixes ( slang_T *slang, char_u *word, // case-folded word char_u *pat, - int *dir, + Direction *dir, int dumpflags, int flags, // flags with prefix ID linenr_T startlnum diff --git a/src/nvim/spell.h b/src/nvim/spell.h index ad66df4c5d..e93c82b91d 100644 --- a/src/nvim/spell.h +++ b/src/nvim/spell.h @@ -6,6 +6,7 @@ #include "nvim/spell_defs.h" #include "nvim/ex_cmds_defs.h" #include "nvim/globals.h" +#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "spell.h.generated.h" diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim index c86fdf25ab..5468f7c4aa 100644 --- a/src/nvim/testdir/test49.vim +++ b/src/nvim/testdir/test49.vim @@ -318,7 +318,7 @@ let ExtraVimCount = 0 let ExtraVimBase = expand("<sfile>") let ExtraVimTestEnv = "" " -function! ExtraVim(...) +function ExtraVim(...) " Count how often this function is called. let g:ExtraVimCount = g:ExtraVimCount + 1 @@ -500,7 +500,7 @@ endfunction " an ExtraVim script as passed by ExtraVim() in ExtraVimBegin. " " EXTRA_VIM_START - do not change or remove this line. -function! ExtraVimThrowpoint() +function ExtraVimThrowpoint() if !exists("g:ExtraVimBegin") Xout "ExtraVimThrowpoint() used outside ExtraVim() script." return v:throwpoint @@ -530,7 +530,7 @@ endfunction " as a script file, use ExecAsScript below. " " EXTRA_VIM_START - do not change or remove this line. -function! MakeScript(funcname, ...) +function MakeScript(funcname, ...) let script = tempname() execute "redir! >" . script execute "function" a:funcname @@ -568,7 +568,7 @@ endfunction " location specified in the function. " " EXTRA_VIM_START - do not change or remove this line. -function! ExecAsScript(funcname) +function ExecAsScript(funcname) " Make a script from the function passed as argument. let script = MakeScript(a:funcname) @@ -3694,7 +3694,7 @@ endif if ExtraVim(msgfile) try Xpath 4194304 " X: 4194304 - let x = novar " error E121/E15; exception: E121 + let x = novar " error E121; exception: E121 catch /E15:/ " should not catch Xpath 8388608 " X: 0 endtry @@ -3702,7 +3702,7 @@ if ExtraVim(msgfile) endif Xpath 33554432 " X: 33554432 -if !MESSAGES('E121', "Undefined variable", 'E15', "Invalid expression") +if !MESSAGES('E121', "Undefined variable") Xpath 67108864 " X: 0 endif @@ -8548,7 +8548,7 @@ endfunction " Remove the autocommands for the events specified as arguments in all used " autogroups. -function! Delete_autocommands(...) +function Delete_autocommands(...) let augfile = tempname() while 1 try diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index 7647475427..4f056abdc0 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -1,7 +1,6 @@ " A series of tests that can run in one Vim invocation. " This makes testing go faster, since Vim doesn't need to restart. -source test_assign.vim source test_backup.vim source test_behave.vim source test_cd.vim diff --git a/src/nvim/testdir/test_assign.vim b/src/nvim/testdir/test_assign.vim deleted file mode 100644 index 50415ad6fd..0000000000 --- a/src/nvim/testdir/test_assign.vim +++ /dev/null @@ -1,47 +0,0 @@ -" Test for assignment - -func Test_no_type_checking() - let v = 1 - let v = [1,2,3] - let v = {'a': 1, 'b': 2} - let v = 3.4 - let v = 'hello' -endfunc - -func Test_let_termcap() - " Nvim does not support `:set termcap`. - return - " Terminal code - let old_t_te = &t_te - let &t_te = "\<Esc>[yes;" - call assert_match('t_te.*^[[yes;', execute("set termcap")) - let &t_te = old_t_te - - if exists("+t_k1") - " Key code - let old_t_k1 = &t_k1 - let &t_k1 = "that" - call assert_match('t_k1.*that', execute("set termcap")) - let &t_k1 = old_t_k1 - endif - - call assert_fails('let x = &t_xx', 'E15') - let &t_xx = "yes" - call assert_equal("yes", &t_xx) - let &t_xx = "" - call assert_fails('let x = &t_xx', 'E15') -endfunc - -func Test_let_option_error() - let _w = &tw - let &tw = 80 - call assert_fails('let &tw .= 1', 'E734') - call assert_equal(80, &tw) - let &tw = _w - - let _w = &fillchars - let &fillchars = "vert:|" - call assert_fails('let &fillchars += "diff:-"', 'E734') - call assert_equal("vert:|", &fillchars) - let &fillchars = _w -endfunc diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 1fa7eeaea0..641e98ab30 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -1359,7 +1359,7 @@ func Test_ChangedP() endfunc let g:setline_handled = v:false -func! SetLineOne() +func SetLineOne() if !g:setline_handled call setline(1, "(x)") let g:setline_handled = v:true diff --git a/src/nvim/testdir/test_charsearch.vim b/src/nvim/testdir/test_charsearch.vim index 8b313b5a35..17a49e02be 100644 --- a/src/nvim/testdir/test_charsearch.vim +++ b/src/nvim/testdir/test_charsearch.vim @@ -1,5 +1,5 @@ -function! Test_charsearch() +func Test_charsearch() enew! call append(0, ['Xabcdefghijkemnopqretuvwxyz', \ 'Yabcdefghijkemnopqretuvwxyz', @@ -29,10 +29,10 @@ function! Test_charsearch() normal! ;;p call assert_equal('ZabcdeZfghijkZZemnokqretkZvwxyz', getline(3)) enew! -endfunction +endfunc " Test for t,f,F,T movement commands and 'cpo-;' setting -function! Test_search_cmds() +func Test_search_cmds() enew! call append(0, ["aaa two three four", " zzz", "yyy ", \ "bbb yee yoo four", "ccc two three four", @@ -59,4 +59,4 @@ function! Test_search_cmds() call assert_equal('ccc', getline(5)) call assert_equal('ddd yee y', getline(6)) enew! -endfunction +endfunc diff --git a/src/nvim/testdir/test_charsearch_utf8.vim b/src/nvim/testdir/test_charsearch_utf8.vim index eac5d46ad8..09341a90b0 100644 --- a/src/nvim/testdir/test_charsearch_utf8.vim +++ b/src/nvim/testdir/test_charsearch_utf8.vim @@ -14,6 +14,6 @@ function! Test_search_cmds() normal! , call assert_equal([0, 1, 28, 0], getpos('.')) bw! -endfunction +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim index abad6983dc..e1393e875b 100644 --- a/src/nvim/testdir/test_edit.vim +++ b/src/nvim/testdir/test_edit.vim @@ -11,7 +11,7 @@ source view_util.vim " Needs to come first until the bug in getchar() is " fixed: https://groups.google.com/d/msg/vim_dev/fXL9yme4H4c/bOR-U6_bAQAJ -func! Test_edit_00b() +func Test_edit_00b() new call setline(1, ['abc ']) inoreabbr <buffer> h here some more @@ -23,7 +23,7 @@ func! Test_edit_00b() bw! endfunc -func! Test_edit_01() +func Test_edit_01() " set for Travis CI? " set nocp noesckeys new @@ -61,7 +61,7 @@ func! Test_edit_01() bw! endfunc -func! Test_edit_02() +func Test_edit_02() " Change cursor position in InsertCharPre command new call setline(1, 'abc') @@ -101,7 +101,7 @@ func! Test_edit_02() bw! endfunc -func! Test_edit_03() +func Test_edit_03() " Change cursor after <c-o> command to end of line new call setline(1, 'abc') @@ -120,7 +120,7 @@ func! Test_edit_03() bw! endfunc -func! Test_edit_04() +func Test_edit_04() " test for :stopinsert new call setline(1, 'abc') @@ -132,7 +132,7 @@ func! Test_edit_04() bw! endfunc -func! Test_edit_05() +func Test_edit_05() " test for folds being opened new call setline(1, ['abcX', 'abcX', 'zzzZ']) @@ -154,7 +154,7 @@ func! Test_edit_05() bw! endfunc -func! Test_edit_06() +func Test_edit_06() " Test in diff mode if !has("diff") || !executable("diff") return @@ -176,7 +176,7 @@ func! Test_edit_06() bw! endfunc -func! Test_edit_07() +func Test_edit_07() " 1) Test with completion <c-l> when popupmenu is visible new call setline(1, 'J') @@ -228,7 +228,7 @@ func! Test_edit_08() unlet g:bufnr endfunc -func! Test_edit_09() +func Test_edit_09() " test i_CTRL-\ combinations new call setline(1, ['abc', 'def', 'ghi']) @@ -258,7 +258,7 @@ func! Test_edit_09() bw! endfunc -func! Test_edit_10() +func Test_edit_10() " Test for starting selectmode new set selectmode=key keymodel=startsel @@ -270,7 +270,7 @@ func! Test_edit_10() bw! endfunc -func! Test_edit_11() +func Test_edit_11() " Test that indenting kicks in new set cindent @@ -314,7 +314,7 @@ func! Test_edit_11() bw! endfunc -func! Test_edit_11_indentexpr() +func Test_edit_11_indentexpr() " Test that indenting kicks in new " Use indentexpr instead of cindenting @@ -341,7 +341,7 @@ func! Test_edit_11_indentexpr() bw! endfunc -func! Test_edit_12() +func Test_edit_12() " Test changing indent in replace mode new call setline(1, ["\tabc", "\tdef"]) @@ -393,7 +393,7 @@ func! Test_edit_12() bw! endfunc -func! Test_edit_13() +func Test_edit_13() " Test smartindenting if exists("+smartindent") new @@ -481,7 +481,7 @@ func! Test_edit_CTRL_() endfunc " needs to come first, to have the @. register empty -func! Test_edit_00a_CTRL_A() +func Test_edit_00a_CTRL_A() " Test pressing CTRL-A new call setline(1, repeat([''], 5)) @@ -501,7 +501,7 @@ func! Test_edit_00a_CTRL_A() bw! endfunc -func! Test_edit_CTRL_EY() +func Test_edit_CTRL_EY() " Ctrl-E/ Ctrl-Y in insert mode completion to scroll 10new call setline(1, range(1, 100)) @@ -517,7 +517,7 @@ func! Test_edit_CTRL_EY() bw! endfunc -func! Test_edit_CTRL_G() +func Test_edit_CTRL_G() new call setline(1, ['foobar', 'foobar', 'foobar']) call cursor(2, 4) @@ -535,7 +535,7 @@ func! Test_edit_CTRL_G() bw! endfunc -func! Test_edit_CTRL_I() +func Test_edit_CTRL_I() " Tab in completion mode let path=expand("%:p:h") new @@ -559,7 +559,7 @@ func! Test_edit_CTRL_I() bw! endfunc -func! Test_edit_CTRL_K() +func Test_edit_CTRL_K() " Test pressing CTRL-K (basically only dictionary completion and digraphs " the rest is already covered call writefile(['A', 'AA', 'AAA', 'AAAA'], 'Xdictionary.txt') @@ -632,7 +632,7 @@ func! Test_edit_CTRL_K() bw! endfunc -func! Test_edit_CTRL_L() +func Test_edit_CTRL_L() " Test Ctrl-X Ctrl-L (line completion) new set complete=. @@ -688,7 +688,7 @@ func! Test_edit_CTRL_L() bw! endfunc -func! Test_edit_CTRL_N() +func Test_edit_CTRL_N() " Check keyword completion new set complete=. @@ -709,7 +709,7 @@ func! Test_edit_CTRL_N() bw! endfunc -func! Test_edit_CTRL_O() +func Test_edit_CTRL_O() " Check for CTRL-O in insert mode new inoreabbr <buffer> h here some more @@ -749,7 +749,7 @@ func! Test_edit_CTRL_R() bw! endfunc -func! Test_edit_CTRL_S() +func Test_edit_CTRL_S() " Test pressing CTRL-S (basically only spellfile completion) " the rest is already covered new @@ -793,7 +793,7 @@ func! Test_edit_CTRL_S() bw! endfunc -func! Test_edit_CTRL_T() +func Test_edit_CTRL_T() " Check for CTRL-T and CTRL-X CTRL-T in insert mode " 1) increase indent new @@ -870,7 +870,7 @@ func! Test_edit_CTRL_T() bw! endfunc -func! Test_edit_CTRL_U() +func Test_edit_CTRL_U() " Test 'completefunc' new " -1, -2 and -3 are special return values @@ -929,7 +929,7 @@ func! Test_edit_CTRL_U() bw! endfunc -func! Test_edit_CTRL_Z() +func Test_edit_CTRL_Z() " Ctrl-Z when insertmode is not set inserts it literally new call setline(1, 'abc') @@ -939,7 +939,7 @@ func! Test_edit_CTRL_Z() " TODO: How to Test Ctrl-Z in insert mode, e.g. suspend? endfunc -func! Test_edit_DROP() +func Test_edit_DROP() if !has("dnd") return endif @@ -955,7 +955,7 @@ func! Test_edit_DROP() bw! endfunc -func! Test_edit_CTRL_V() +func Test_edit_CTRL_V() if has("ebcdic") return endif @@ -983,7 +983,7 @@ func! Test_edit_CTRL_V() bw! endfunc -func! Test_edit_F1() +func Test_edit_F1() " Pressing <f1> new call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix') @@ -993,7 +993,7 @@ func! Test_edit_F1() bw endfunc -func! Test_edit_F21() +func Test_edit_F21() " Pressing <f21> " sends a netbeans command if has("netbeans_intg") @@ -1004,7 +1004,7 @@ func! Test_edit_F21() endif endfunc -func! Test_edit_HOME_END() +func Test_edit_HOME_END() " Test Home/End Keys new set foldopen+=hor @@ -1019,7 +1019,7 @@ func! Test_edit_HOME_END() bw! endfunc -func! Test_edit_INS() +func Test_edit_INS() " Test for Pressing <Insert> new call setline(1, ['abc', 'def']) @@ -1033,7 +1033,7 @@ func! Test_edit_INS() bw! endfunc -func! Test_edit_LEFT_RIGHT() +func Test_edit_LEFT_RIGHT() " Left, Shift-Left, Right, Shift-Right new call setline(1, ['abc def ghi', 'ABC DEF GHI', 'ZZZ YYY XXX']) @@ -1080,7 +1080,7 @@ func! Test_edit_LEFT_RIGHT() bw! endfunc -func! Test_edit_MOUSE() +func Test_edit_MOUSE() " This is a simple test, since we not really using the mouse here if !has("mouse") return @@ -1135,7 +1135,7 @@ func! Test_edit_MOUSE() bw! endfunc -func! Test_edit_PAGEUP_PAGEDOWN() +func Test_edit_PAGEUP_PAGEDOWN() 10new call setline(1, repeat(['abc def ghi'], 30)) call cursor(1, 1) @@ -1234,7 +1234,7 @@ func! Test_edit_PAGEUP_PAGEDOWN() bw! endfunc -func! Test_edit_forbidden() +func Test_edit_forbidden() new " 1) edit in the sandbox is not allowed call setline(1, 'a') @@ -1294,7 +1294,7 @@ func! Test_edit_forbidden() bw! endfunc -func! Test_edit_rightleft() +func Test_edit_rightleft() " Cursor in rightleft mode moves differently if !exists("+rightleft") return diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index 52b5884c8b..f3c3e085f6 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -471,7 +471,6 @@ let s:filename_checks = { \ 'tssgm': ['file.tssgm'], \ 'tssop': ['file.tssop'], \ 'twig': ['file.twig'], - \ 'typescript': ['file.ts'], \ 'typescriptreact': ['file.tsx'], \ 'uc': ['file.uc'], \ 'udevconf': ['/etc/udev/udev.conf'], @@ -668,5 +667,22 @@ func Test_hook_file() filetype off endfunc +func Test_ts_file() + filetype on + + call writefile(['<?xml version="1.0" encoding="utf-8"?>'], 'Xfile.ts') + split Xfile.ts + call assert_equal('xml', &filetype) + bwipe! + + call writefile(['// looks like Typescript'], 'Xfile.ts') + split Xfile.ts + call assert_equal('typescript', &filetype) + bwipe! + + call delete('Xfile.hook') + filetype off +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_fnameescape.vim b/src/nvim/testdir/test_fnameescape.vim index cdff0dfbd9..5382b89aa6 100644 --- a/src/nvim/testdir/test_fnameescape.vim +++ b/src/nvim/testdir/test_fnameescape.vim @@ -1,6 +1,6 @@ " Test if fnameescape is correct for special chars like ! -function! Test_fnameescape() +func Test_fnameescape() let fname = 'Xspa ce' let status = v:false try @@ -18,4 +18,4 @@ function! Test_fnameescape() endtry call assert_true(status, "ExclamationMark") call delete(fname) -endfunction +endfunc diff --git a/src/nvim/testdir/test_getcwd.vim b/src/nvim/testdir/test_getcwd.vim index 5d97295e9a..ca098781e4 100644 --- a/src/nvim/testdir/test_getcwd.vim +++ b/src/nvim/testdir/test_getcwd.vim @@ -1,112 +1,112 @@ -function! GetCwdInfo(win, tab) - let tab_changed = 0 - let mod = ":t" - if a:tab > 0 && a:tab != tabpagenr() - let tab_changed = 1 - exec "tabnext " . a:tab - endif - let bufname = fnamemodify(bufname(winbufnr(a:win)), mod) - if tab_changed - tabprevious - endif - if a:win == 0 && a:tab == 0 - let dirname = fnamemodify(getcwd(), mod) - let lflag = haslocaldir() - elseif a:tab == 0 - let dirname = fnamemodify(getcwd(a:win), mod) - let lflag = haslocaldir(a:win) - else - let dirname = fnamemodify(getcwd(a:win, a:tab), mod) - let lflag = haslocaldir(a:win, a:tab) - endif - return bufname . ' ' . dirname . ' ' . lflag -endfunction +func GetCwdInfo(win, tab) + let tab_changed = 0 + let mod = ":t" + if a:tab > 0 && a:tab != tabpagenr() + let tab_changed = 1 + exec "tabnext " . a:tab + endif + let bufname = fnamemodify(bufname(winbufnr(a:win)), mod) + if tab_changed + tabprevious + endif + if a:win == 0 && a:tab == 0 + let dirname = fnamemodify(getcwd(), mod) + let lflag = haslocaldir() + elseif a:tab == 0 + let dirname = fnamemodify(getcwd(a:win), mod) + let lflag = haslocaldir(a:win) + else + let dirname = fnamemodify(getcwd(a:win, a:tab), mod) + let lflag = haslocaldir(a:win, a:tab) + endif + return bufname . ' ' . dirname . ' ' . lflag +endfunc " Do all test in a separate window to avoid E211 when we recursively " delete the Xtopdir directory during cleanup function SetUp() - set visualbell - set nocp viminfo+=nviminfo + set visualbell + set nocp viminfo+=nviminfo - " On windows a swapfile in Xtopdir prevents it from being cleaned up. - set noswapfile + " On windows a swapfile in Xtopdir prevents it from being cleaned up. + set noswapfile - " On windows a stale "Xtopdir" directory may exist, remove it so that - " we start from a clean state. - call delete("Xtopdir", "rf") - new - call mkdir('Xtopdir') - cd Xtopdir - let g:topdir = getcwd() - call mkdir('Xdir1') - call mkdir('Xdir2') - call mkdir('Xdir3') + " On windows a stale "Xtopdir" directory may exist, remove it so that + " we start from a clean state. + call delete("Xtopdir", "rf") + new + call mkdir('Xtopdir') + cd Xtopdir + let g:topdir = getcwd() + call mkdir('Xdir1') + call mkdir('Xdir2') + call mkdir('Xdir3') endfunction let g:cwd=getcwd() function TearDown() - q - exec "cd " . g:cwd - call delete("Xtopdir", "rf") + q + exec "cd " . g:cwd + call delete("Xtopdir", "rf") endfunction function Test_GetCwd() - new a - new b - new c - 3wincmd w - lcd Xdir1 - call assert_equal("a Xdir1 1", GetCwdInfo(0, 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - call assert_equal("b Xtopdir 0", GetCwdInfo(0, 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - lcd Xdir3 - call assert_equal("c Xdir3 1", GetCwdInfo(0, 0)) - call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), 0)) - call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), 0)) - call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), tabpagenr())) - call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), tabpagenr())) - call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), tabpagenr())) - call assert_equal(g:topdir, getcwd(-1)) + new a + new b + new c + 3wincmd w + lcd Xdir1 + call assert_equal("a Xdir1 1", GetCwdInfo(0, 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + call assert_equal("b Xtopdir 0", GetCwdInfo(0, 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + lcd Xdir3 + call assert_equal("c Xdir3 1", GetCwdInfo(0, 0)) + call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), 0)) + call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), 0)) + call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + call assert_equal("a Xdir1 1", GetCwdInfo(bufwinnr("a"), tabpagenr())) + call assert_equal("b Xtopdir 0", GetCwdInfo(bufwinnr("b"), tabpagenr())) + call assert_equal("c Xdir3 1", GetCwdInfo(bufwinnr("c"), tabpagenr())) + call assert_equal(g:topdir, getcwd(-1)) - tabnew x - new y - new z - 3wincmd w - call assert_equal("x Xtopdir 0", GetCwdInfo(0, 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - lcd Xdir2 - call assert_equal("y Xdir2 1", GetCwdInfo(0, 0)) - call assert_equal(g:topdir, getcwd(-1)) - wincmd W - lcd Xdir3 - call assert_equal("z Xdir3 1", GetCwdInfo(0, 0)) - call assert_equal("x Xtopdir 0", GetCwdInfo(bufwinnr("x"), 0)) - call assert_equal("y Xdir2 1", GetCwdInfo(bufwinnr("y"), 0)) - call assert_equal("z Xdir3 1", GetCwdInfo(bufwinnr("z"), 0)) - call assert_equal(g:topdir, getcwd(-1)) - let tp_nr = tabpagenr() - tabrewind - call assert_equal("x Xtopdir 0", GetCwdInfo(3, tp_nr)) - call assert_equal("y Xdir2 1", GetCwdInfo(2, tp_nr)) - call assert_equal("z Xdir3 1", GetCwdInfo(1, tp_nr)) - call assert_equal(g:topdir, getcwd(-1)) + tabnew x + new y + new z + 3wincmd w + call assert_equal("x Xtopdir 0", GetCwdInfo(0, 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + lcd Xdir2 + call assert_equal("y Xdir2 1", GetCwdInfo(0, 0)) + call assert_equal(g:topdir, getcwd(-1)) + wincmd W + lcd Xdir3 + call assert_equal("z Xdir3 1", GetCwdInfo(0, 0)) + call assert_equal("x Xtopdir 0", GetCwdInfo(bufwinnr("x"), 0)) + call assert_equal("y Xdir2 1", GetCwdInfo(bufwinnr("y"), 0)) + call assert_equal("z Xdir3 1", GetCwdInfo(bufwinnr("z"), 0)) + call assert_equal(g:topdir, getcwd(-1)) + let tp_nr = tabpagenr() + tabrewind + call assert_equal("x Xtopdir 0", GetCwdInfo(3, tp_nr)) + call assert_equal("y Xdir2 1", GetCwdInfo(2, tp_nr)) + call assert_equal("z Xdir3 1", GetCwdInfo(1, tp_nr)) + call assert_equal(g:topdir, getcwd(-1)) endfunc function Test_GetCwd_lcd_shellslash() - new - let root = fnamemodify('/', ':p') - exe 'lcd '.root - let cwd = getcwd() - if !exists('+shellslash') || &shellslash - call assert_equal(cwd[-1:], '/') - else - call assert_equal(cwd[-1:], '\') - endif + new + let root = fnamemodify('/', ':p') + exe 'lcd '.root + let cwd = getcwd() + if !exists('+shellslash') || &shellslash + call assert_equal(cwd[-1:], '/') + else + call assert_equal(cwd[-1:], '\') + endif endfunc diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim index a80a73161f..8f6834c2ab 100644 --- a/src/nvim/testdir/test_highlight.vim +++ b/src/nvim/testdir/test_highlight.vim @@ -39,15 +39,15 @@ func Test_highlight() call assert_fails("hi Crash term='asdf", "E475:") endfunc -function! HighlightArgs(name) +func HighlightArgs(name) return 'hi ' . substitute(split(execute('hi ' . a:name), '\n')[0], '\<xxx\>', '', '') -endfunction +endfunc -function! IsColorable() +func IsColorable() return has('gui_running') || str2nr(&t_Co) >= 8 -endfunction +endfunc -function! HiCursorLine() +func HiCursorLine() let hiCursorLine = HighlightArgs('CursorLine') if has('gui_running') let guibg = matchstr(hiCursorLine, 'guibg=\w\+') @@ -58,9 +58,9 @@ function! HiCursorLine() let hi_bg = 'hi CursorLine cterm=NONE ctermbg=Gray' endif return [hiCursorLine, hi_ul, hi_bg] -endfunction +endfunc -function! Check_lcs_eol_attrs(attrs, row, col) +func Check_lcs_eol_attrs(attrs, row, col) let save_lcs = &lcs set list @@ -68,7 +68,7 @@ function! Check_lcs_eol_attrs(attrs, row, col) set nolist let &lcs = save_lcs -endfunction +endfunc func Test_highlight_eol_with_cursorline() let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine() diff --git a/src/nvim/testdir/test_hlsearch.vim b/src/nvim/testdir/test_hlsearch.vim index 97f6ae7b51..cf2791113a 100644 --- a/src/nvim/testdir/test_hlsearch.vim +++ b/src/nvim/testdir/test_hlsearch.vim @@ -1,6 +1,6 @@ " Test for v:hlsearch -function! Test_hlsearch() +func Test_hlsearch() new call setline(1, repeat(['aaa'], 10)) set hlsearch nolazyredraw @@ -30,7 +30,7 @@ function! Test_hlsearch() call garbagecollect(1) call getchar(1) enew! -endfunction +endfunc func Test_hlsearch_hangs() if !has('reltime') || !has('float') diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim index 57a0a7aaf4..6fe1d29434 100644 --- a/src/nvim/testdir/test_ins_complete.vim +++ b/src/nvim/testdir/test_ins_complete.vim @@ -312,6 +312,24 @@ func Test_completefunc_args() delfunc CompleteFunc endfunc +func CompleteTest(findstart, query) + if a:findstart + return col('.') + endif + return ['matched'] +endfunc + +func Test_completefunc_info() + new + set completeopt=menuone + set completefunc=CompleteTest + call feedkeys("i\<C-X>\<C-U>\<C-R>\<C-R>=string(complete_info())\<CR>\<ESC>", "tx") + call assert_equal("matched{'pum_visible': 1, 'mode': 'function', 'selected': 0, 'items': [{'word': 'matched', 'menu': '', 'user_data': '', 'info': '', 'kind': '', 'abbr': ''}]}", getline(1)) + bwipe! + set completeopt& + set completefunc& +endfunc + " Check that when using feedkeys() typeahead does not interrupt searching for " completions. func Test_compl_feedkeys() diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim index 0b9331ee38..a5cbd8f6a6 100644 --- a/src/nvim/testdir/test_let.vim +++ b/src/nvim/testdir/test_let.vim @@ -150,6 +150,59 @@ func Test_let_utf8_environment() call assert_equal('ĀĒĪŌŪあいうえお', $a) endfunc +func Test_let_no_type_checking() + let v = 1 + let v = [1,2,3] + let v = {'a': 1, 'b': 2} + let v = 3.4 + let v = 'hello' +endfunc + +func Test_let_termcap() + throw 'skipped: Nvim does not support termcap option' + " Terminal code + let old_t_te = &t_te + let &t_te = "\<Esc>[yes;" + call assert_match('t_te.*^[[yes;', execute("set termcap")) + let &t_te = old_t_te + + if exists("+t_k1") + " Key code + let old_t_k1 = &t_k1 + let &t_k1 = "that" + call assert_match('t_k1.*that', execute("set termcap")) + let &t_k1 = old_t_k1 + endif + + call assert_fails('let x = &t_xx', 'E113') + let &t_xx = "yes" + call assert_equal("yes", &t_xx) + let &t_xx = "" + call assert_fails('let x = &t_xx', 'E113') +endfunc + +func Test_let_option_error() + let _w = &tw + let &tw = 80 + call assert_fails('let &tw .= 1', 'E734') + call assert_equal(80, &tw) + let &tw = _w + + let _w = &fillchars + let &fillchars = "vert:|" + call assert_fails('let &fillchars += "diff:-"', 'E734') + call assert_equal("vert:|", &fillchars) + let &fillchars = _w +endfunc + +func Test_let_errors() + let s = 'abcd' + call assert_fails('let s[1] = 5', 'E689:') + + let l = [1, 2, 3] + call assert_fails('let l[:] = 5', 'E709:') +endfunc + func Test_let_heredoc_fails() call assert_fails('let v =<< marker', 'E991:') diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim index cdc5e4cc7c..d619ac0eb5 100644 --- a/src/nvim/testdir/test_listlbr.vim +++ b/src/nvim/testdir/test_listlbr.vim @@ -16,9 +16,9 @@ function s:screen_lines(lnum, width) abort return ScreenLines(a:lnum, a:width) endfunction -function! s:compare_lines(expect, actual) +func s:compare_lines(expect, actual) call assert_equal(join(a:expect, "\n"), join(a:actual, "\n")) -endfunction +endfunc function s:test_windows(...) call NewWindow(10, 20) diff --git a/src/nvim/testdir/test_listlbr_utf8.vim b/src/nvim/testdir/test_listlbr_utf8.vim index b648a3361b..c38e0c5f3c 100644 --- a/src/nvim/testdir/test_listlbr_utf8.vim +++ b/src/nvim/testdir/test_listlbr_utf8.vim @@ -9,15 +9,15 @@ endif source view_util.vim -function s:screen_lines(lnum, width) abort +func s:screen_lines(lnum, width) abort return ScreenLines(a:lnum, a:width) -endfunction +endfunc -function! s:compare_lines(expect, actual) +func s:compare_lines(expect, actual) call assert_equal(a:expect, a:actual) -endfunction +endfunc -function s:screen_attr(lnum, chars, ...) abort +func s:screen_attr(lnum, chars, ...) abort let line = getline(a:lnum) let attr = [] let prefix = get(a:000, 0, 0) @@ -26,18 +26,18 @@ function s:screen_attr(lnum, chars, ...) abort let attr += [screenattr(a:lnum, scol + prefix)] endfor return attr -endfunction +endfunc -function s:test_windows(...) +func s:test_windows(...) call NewWindow(10, 20) setl ts=4 sw=4 sts=4 linebreak sbr=+ wrap exe get(a:000, 0, '') -endfunction +endfunc -function s:close_windows(...) +func s:close_windows(...) call CloseWindow() exe get(a:000, 0, '') -endfunction +endfunc func Test_linebreak_with_fancy_listchars() call s:test_windows("setl list listchars=nbsp:\u2423,tab:\u2595\u2014,trail:\u02d1,eol:\ub6") diff --git a/src/nvim/testdir/test_matchadd_conceal.vim b/src/nvim/testdir/test_matchadd_conceal.vim index 393e183ddb..f9e40a9b43 100644 --- a/src/nvim/testdir/test_matchadd_conceal.vim +++ b/src/nvim/testdir/test_matchadd_conceal.vim @@ -27,9 +27,9 @@ function! Test_simple_matchadd() call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) quit! -endfunction +endfunc -function! Test_simple_matchadd_and_conceal() +func Test_simple_matchadd_and_conceal() new setlocal concealcursor=n conceallevel=1 @@ -49,9 +49,9 @@ function! Test_simple_matchadd_and_conceal() call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) quit! -endfunction +endfunc -function! Test_matchadd_and_conceallevel_3() +func Test_matchadd_and_conceallevel_3() new setlocal conceallevel=3 @@ -90,9 +90,9 @@ function! Test_matchadd_and_conceallevel_3() syntax off quit! -endfunction +endfunc -function! Test_default_conceal_char() +func Test_default_conceal_char() new setlocal concealcursor=n conceallevel=1 @@ -126,9 +126,9 @@ function! Test_default_conceal_char() let &listchars = listchars_save quit! -endfunction +endfunc -function! Test_syn_and_match_conceal() +func Test_syn_and_match_conceal() new setlocal concealcursor=n conceallevel=1 @@ -162,9 +162,9 @@ function! Test_syn_and_match_conceal() syntax off quit! -endfunction +endfunc -function! Test_clearmatches() +func Test_clearmatches() new setlocal concealcursor=n conceallevel=1 @@ -201,9 +201,9 @@ function! Test_clearmatches() call assert_equal({'group': 'Conceal', 'pattern': '\%2l ', 'priority': 10, 'id': a[0].id, 'conceal': 'Z'}, a[0]) quit! -endfunction +endfunc -function! Test_using_matchaddpos() +func Test_using_matchaddpos() new setlocal concealcursor=n conceallevel=1 " set filetype and :syntax on to change screenattr() @@ -232,9 +232,9 @@ function! Test_using_matchaddpos() syntax off quit! -endfunction +endfunc -function! Test_matchadd_repeat_conceal_with_syntax_off() +func Test_matchadd_repeat_conceal_with_syntax_off() new " To test targets in the same line string is replaced with conceal char @@ -251,9 +251,9 @@ function! Test_matchadd_repeat_conceal_with_syntax_off() call assert_equal('t_tt', Screenline(2)) quit! -endfunction +endfunc -function! Test_matchadd_and_syn_conceal() +func Test_matchadd_and_syn_conceal() new let cnt='Inductive bool : Type := | true : bool | false : bool.' let expect = 'Inductive - : Type := | true : - | false : -.' diff --git a/src/nvim/testdir/test_matchadd_conceal_utf8.vim b/src/nvim/testdir/test_matchadd_conceal_utf8.vim index 160d0598a1..34c8c49dd5 100644 --- a/src/nvim/testdir/test_matchadd_conceal_utf8.vim +++ b/src/nvim/testdir/test_matchadd_conceal_utf8.vim @@ -36,4 +36,4 @@ function! Test_match_using_multibyte_conceal_char() call assert_equal(screenattr(lnum, 1), screenattr(lnum, 16)) quit! -endfunction +endfunc diff --git a/src/nvim/testdir/test_number.vim b/src/nvim/testdir/test_number.vim index 3c9afc41d5..81326bce14 100644 --- a/src/nvim/testdir/test_number.vim +++ b/src/nvim/testdir/test_number.vim @@ -2,23 +2,23 @@ source view_util.vim -func! s:screen_lines(start, end) abort +func s:screen_lines(start, end) abort return ScreenLines([a:start, a:end], 8) endfunc -func! s:compare_lines(expect, actual) +func s:compare_lines(expect, actual) call assert_equal(a:expect, a:actual) endfunc -func! s:test_windows(h, w) abort +func s:test_windows(h, w) abort call NewWindow(a:h, a:w) endfunc -func! s:close_windows() abort +func s:close_windows() abort call CloseWindow() endfunc -func! s:validate_cursor() abort +func s:validate_cursor() abort " update skipcol. " wincol(): " f_wincol diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim index 10e16f4198..15c1836c9a 100644 --- a/src/nvim/testdir/test_options.vim +++ b/src/nvim/testdir/test_options.vim @@ -1,6 +1,6 @@ " Test for options -function! Test_whichwrap() +func Test_whichwrap() set whichwrap=b,s call assert_equal('b,s', &whichwrap) diff --git a/src/nvim/testdir/test_partial.vim b/src/nvim/testdir/test_partial.vim index 590e18e024..52aac05ea1 100644 --- a/src/nvim/testdir/test_partial.vim +++ b/src/nvim/testdir/test_partial.vim @@ -113,9 +113,9 @@ func Test_function_in_dict() call OuterCall() endfunc -function! s:cache_clear() dict +func s:cache_clear() dict return self.name -endfunction +endfunc func Test_script_function_in_dict() let s:obj = {'name': 'foo'} @@ -135,10 +135,10 @@ func Test_script_function_in_dict() call assert_equal('bar', B()) endfunc -function! s:cache_arg(arg) dict +func s:cache_arg(arg) dict let s:result = self.name . '/' . a:arg return s:result -endfunction +endfunc func Test_script_function_in_dict_arg() let s:obj = {'name': 'foo'} diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 5c84e45a79..e06c4f59da 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -4485,4 +4485,62 @@ func Test_quickfix_window_fails_to_open() call delete('XquickfixFails') endfunc +" Test for updating the quickfix buffer whenever the assocaited quickfix list +" is changed. +func Xqfbuf_update(cchar) + call s:setup_commands(a:cchar) + + Xexpr "F1:1:line1" + Xopen + call assert_equal(['F1|1| line1'], getline(1, '$')) + call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) + + " Test setqflist() using the 'lines' key in 'what' + " add a new entry + call g:Xsetlist([], 'a', {'lines' : ['F2:2: line2']}) + call assert_equal(['F1|1| line1', 'F2|2| line2'], getline(1, '$')) + call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick) + " replace all the entries with a single entry + call g:Xsetlist([], 'r', {'lines' : ['F3:3: line3']}) + call assert_equal(['F3|3| line3'], getline(1, '$')) + call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick) + " remove all the entries + call g:Xsetlist([], 'r', {'lines' : []}) + call assert_equal([''], getline(1, '$')) + call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick) + " add a new list + call g:Xsetlist([], ' ', {'lines' : ['F4:4: line4']}) + call assert_equal(['F4|4| line4'], getline(1, '$')) + call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) + + " Test setqflist() using the 'items' key in 'what' + " add a new entry + call g:Xsetlist([], 'a', {'items' : [{'filename' : 'F5', 'lnum' : 5, 'text' : 'line5'}]}) + call assert_equal(['F4|4| line4', 'F5|5| line5'], getline(1, '$')) + call assert_equal(2, g:Xgetlist({'changedtick' : 0}).changedtick) + " replace all the entries with a single entry + call g:Xsetlist([], 'r', {'items' : [{'filename' : 'F6', 'lnum' : 6, 'text' : 'line6'}]}) + call assert_equal(['F6|6| line6'], getline(1, '$')) + call assert_equal(3, g:Xgetlist({'changedtick' : 0}).changedtick) + " remove all the entries + call g:Xsetlist([], 'r', {'items' : []}) + call assert_equal([''], getline(1, '$')) + call assert_equal(4, g:Xgetlist({'changedtick' : 0}).changedtick) + " add a new list + call g:Xsetlist([], ' ', {'items' : [{'filename' : 'F7', 'lnum' : 7, 'text' : 'line7'}]}) + call assert_equal(['F7|7| line7'], getline(1, '$')) + call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) + + call g:Xsetlist([], ' ', {}) + call assert_equal([''], getline(1, '$')) + call assert_equal(1, g:Xgetlist({'changedtick' : 0}).changedtick) + + Xclose +endfunc + +func Test_qfbuf_update() + call Xqfbuf_update('c') + call Xqfbuf_update('l') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_smartindent.vim b/src/nvim/testdir/test_smartindent.vim index 9e93a55eb0..e89ad19d34 100644 --- a/src/nvim/testdir/test_smartindent.vim +++ b/src/nvim/testdir/test_smartindent.vim @@ -1,24 +1,24 @@ " Tests for smartindent " Tests for not doing smart indenting when it isn't set. -function! Test_nosmartindent() +func Test_nosmartindent() new call append(0, [" some test text", - \ " test text", - \ "test text", - \ " test text"]) + \ " test text", + \ "test text", + \ " test text"]) set nocindent nosmartindent autoindent exe "normal! gg/some\<CR>" exe "normal! 2cc#test\<Esc>" call assert_equal(" #test", getline(1)) enew! | close -endfunction +endfunc -function MyIndent() -endfunction +func MyIndent() +endfunc " When 'indentexpr' is set, setting 'si' has no effect. -function Test_smartindent_has_no_effect() +func Test_smartindent_has_no_effect() new exe "normal! i\<Tab>one\<Esc>" set noautoindent @@ -36,6 +36,6 @@ function Test_smartindent_has_no_effect() set smartindent& set indentexpr& bwipe! -endfunction +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim index ff07d8eceb..2a27f7a3a1 100644 --- a/src/nvim/testdir/test_substitute.vim +++ b/src/nvim/testdir/test_substitute.vim @@ -1,6 +1,6 @@ " Tests for multi-line regexps with ":s". -function! Test_multiline_subst() +func Test_multiline_subst() enew! call append(0, ["1 aa", \ "bb", @@ -38,9 +38,9 @@ function! Test_multiline_subst() call assert_equal('7x7f', getline(12)) call assert_equal('xxxxx', getline(13)) enew! -endfunction +endfunc -function! Test_substitute_variants() +func Test_substitute_variants() " Validate that all the 2-/3-letter variants which embed the flags into the " command name actually work. enew! @@ -248,9 +248,9 @@ func Test_sub_cmd_4() " List entry format: [input, cmd, output] let tests = [ ['aAa', "s/A/\\=substitute(submatch(0), '.', '\\', '')/", - \ ['a\a']], + \ ['a\a']], \ ['bBb', "s/B/\\=substitute(submatch(0), '.', '\\', '')/", - \ ['b\b']], + \ ['b\b']], \ ['cCc', "s/C/\\=substitute(submatch(0), '.', '\<C-V>\<C-M>', '')/", \ ["c\<C-V>", 'c']], \ ['dDd', "s/D/\\=substitute(submatch(0), '.', '\\\<C-V>\<C-M>', '')/", diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim index f70cc1f70a..9b800d0fa9 100644 --- a/src/nvim/testdir/test_textobjects.vim +++ b/src/nvim/testdir/test_textobjects.vim @@ -301,7 +301,7 @@ func Test_sentence_with_quotes() %delete _ endfunc -func! Test_sentence_with_cursor_on_delimiter() +func Test_sentence_with_cursor_on_delimiter() enew! call setline(1, "A '([sentence.])' A sentence.") diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim index 1b4ce4c4af..e8161f8fcb 100644 --- a/src/nvim/testdir/test_utf8.vim +++ b/src/nvim/testdir/test_utf8.vim @@ -22,17 +22,17 @@ func Test_strchars() endfunc " Test for customlist completion -function! CustomComplete1(lead, line, pos) +func CustomComplete1(lead, line, pos) return ['あ', 'い'] -endfunction +endfunc -function! CustomComplete2(lead, line, pos) +func CustomComplete2(lead, line, pos) return ['あたし', 'あたま', 'あたりめ'] -endfunction +endfunc -function! CustomComplete3(lead, line, pos) +func CustomComplete3(lead, line, pos) return ['Nこ', 'Nん', 'Nぶ'] -endfunction +endfunc func Test_customlist_completion() command -nargs=1 -complete=customlist,CustomComplete1 Test1 echo @@ -103,3 +103,14 @@ func Test_list2str_str2list_latin1() call assert_equal(l, lres) call assert_equal(s, sres) endfunc + +func Test_print_overlong() + " Text with more composing characters than MB_MAXBYTES. + new + call setline(1, 'axxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') + s/x/\=nr2char(1629)/g + print + bwipe! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_utf8_comparisons.vim b/src/nvim/testdir/test_utf8_comparisons.vim index 1fc670aafd..fdf9d80802 100644 --- a/src/nvim/testdir/test_utf8_comparisons.vim +++ b/src/nvim/testdir/test_utf8_comparisons.vim @@ -29,26 +29,26 @@ function! Chk(a, b, result) call Ch(a:a, '<?', a:b, 1) call Ch(a:a, '>?', a:b, 0) endif -endfunction +endfunc -function! Check(a, b, result) +func Check(a, b, result) call Chk(a:a, a:b, a:result) call Chk(a:b, a:a, -a:result) -endfunction +endfunc -function! LT(a, b) +func LT(a, b) call Check(a:a, a:b, -1) -endfunction +endfunc -function! GT(a, b) +func GT(a, b) call Check(a:a, a:b, 1) -endfunction +endfunc -function! EQ(a, b) +func EQ(a, b) call Check(a:a, a:b, 0) -endfunction +endfunc -function Test_comparisons() +func Test_comparisons() call EQ('', '') call LT('', 'a') call EQ('abc', 'abc') @@ -81,11 +81,11 @@ function Test_comparisons() for n in range(0xC0, 0xFF) call LT(printf('xYz\xc2\x%.2XUvW', n), printf('XyZ\xc2\x%.2XuVw', n)) endfor -endfunction +endfunc " test that g~ap changes one paragraph only. -function Test_gap() +func Test_gap() new call feedkeys("iabcd\n\ndefggg0g~ap", "tx") call assert_equal(["ABCD", "", "defg"], getline(1,3)) -endfunction +endfunc diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index 118a5dab2b..4edf8308e7 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -5,11 +5,11 @@ " Test environment {{{1 "------------------------------------------------------------------------------- -com! XpathINIT let g:Xpath = '' +com! XpathINIT let g:Xpath = '' com! -nargs=1 -bar Xpath let g:Xpath = g:Xpath . <args> " Append a message to the "messages" file -func! Xout(text) +func Xout(text) split messages $put =a:text wq @@ -50,7 +50,7 @@ function! MakeScript(funcname, ...) write bwipeout return script -endfunction +endfunc " ExecAsScript - Source a temporary script made from a function. {{{2 " @@ -301,9 +301,9 @@ XpathINIT " let calls = "" com! -nargs=1 CALL - \ if !exists("calls") && !exists("outer") | - \ let g:calls = g:calls . <args> | - \ endif + \ if !exists("calls") && !exists("outer") | + \ let g:calls = g:calls . <args> | + \ endif let i = 0 while i < 3 @@ -357,7 +357,7 @@ endif if exists("*F1") call F1("F1") if exists("*G1") - call G1("G1") + call G1("G1") endif endif @@ -367,13 +367,13 @@ endif if exists("*F2") call F2(2, "F2") if exists("*G21") - call G21("G21") + call G21("G21") endif if exists("*G22") - call G22("G22") + call G22("G22") endif if exists("*G23") - call G23("G23") + call G23("G23") endif endif @@ -383,13 +383,13 @@ endif if exists("*F3") call F3(3, "F3") if exists("*G31") - call G31("G31") + call G31("G31") endif if exists("*G32") - call G32("G32") + call G32("G32") endif if exists("*G33") - call G33("G33") + call G33("G33") endif endif @@ -640,7 +640,7 @@ function! MSG(enr, emsg) endif endif return match -endfunction +endfunc if 1 || strlen("\"") | Xpath 'a' Xpath 'b' @@ -1099,70 +1099,70 @@ endfunction func Test_script_lines() " :append try - call DefineFunction('T_Append', [ - \ 'append', - \ 'py <<EOS', - \ '.', - \ ]) + call DefineFunction('T_Append', [ + \ 'append', + \ 'py <<EOS', + \ '.', + \ ]) catch - call assert_report("Can't define function") + call assert_report("Can't define function") endtry try - call DefineFunction('T_Append', [ - \ 'append', - \ 'abc', - \ ]) - call assert_report("Shouldn't be able to define function") + call DefineFunction('T_Append', [ + \ 'append', + \ 'abc', + \ ]) + call assert_report("Shouldn't be able to define function") catch - call assert_exception('Vim(function):E126: Missing :endfunction') + call assert_exception('Vim(function):E126: Missing :endfunction') endtry " :change try - call DefineFunction('T_Change', [ - \ 'change', - \ 'py <<EOS', - \ '.', - \ ]) + call DefineFunction('T_Change', [ + \ 'change', + \ 'py <<EOS', + \ '.', + \ ]) catch - call assert_report("Can't define function") + call assert_report("Can't define function") endtry try - call DefineFunction('T_Change', [ - \ 'change', - \ 'abc', - \ ]) - call assert_report("Shouldn't be able to define function") + call DefineFunction('T_Change', [ + \ 'change', + \ 'abc', + \ ]) + call assert_report("Shouldn't be able to define function") catch - call assert_exception('Vim(function):E126: Missing :endfunction') + call assert_exception('Vim(function):E126: Missing :endfunction') endtry " :insert try - call DefineFunction('T_Insert', [ - \ 'insert', - \ 'py <<EOS', - \ '.', - \ ]) + call DefineFunction('T_Insert', [ + \ 'insert', + \ 'py <<EOS', + \ '.', + \ ]) catch - call assert_report("Can't define function") + call assert_report("Can't define function") endtry try - call DefineFunction('T_Insert', [ - \ 'insert', - \ 'abc', - \ ]) - call assert_report("Shouldn't be able to define function") + call DefineFunction('T_Insert', [ + \ 'insert', + \ 'abc', + \ ]) + call assert_report("Shouldn't be able to define function") catch - call assert_exception('Vim(function):E126: Missing :endfunction') + call assert_exception('Vim(function):E126: Missing :endfunction') endtry endfunc "------------------------------------------------------------------------------- " Test 96: line continuation {{{1 " -" Undefined behavior was detected by ubsan with line continuation -" after an empty line. +" Undefined behavior was detected by ubsan with line continuation +" after an empty line. "------------------------------------------------------------------------------- func Test_script_emty_line_continuation() @@ -1393,6 +1393,20 @@ func Test_compound_assignment_operators() let @/ = '' endfunc +func Test_unlet_env() + let $TESTVAR = 'yes' + call assert_equal('yes', $TESTVAR) + call assert_fails('lockvar $TESTVAR', 'E940') + call assert_fails('unlockvar $TESTVAR', 'E940') + call assert_equal('yes', $TESTVAR) + if 0 + unlet $TESTVAR + endif + call assert_equal('yes', $TESTVAR) + unlet $TESTVAR + call assert_equal('', $TESTVAR) +endfunc + func Test_funccall_garbage_collect() func Func(x, ...) call add(a:x, a:000) |