diff options
author | Justin M. Keyes <justinkz@gmail.com> | 2019-05-26 20:59:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-26 20:59:28 +0200 |
commit | 1ca84897a0d65b0afbb2141f12a2061dabeb6b09 (patch) | |
tree | 01e8232cc8d79cf7dc03d66459d4d0bcaa4b077c /src/nvim/eval.c | |
parent | 0bbaef8a99af8733cc64ff29858e17c19ed30b3c (diff) | |
parent | 80f40f0203f5af167f8c77bf6b9f22a4d1abd6da (diff) | |
download | rneovim-1ca84897a0d65b0afbb2141f12a2061dabeb6b09.tar.gz rneovim-1ca84897a0d65b0afbb2141f12a2061dabeb6b09.tar.bz2 rneovim-1ca84897a0d65b0afbb2141f12a2061dabeb6b09.zip |
Merge #10059 from jerdna-regeiz/vim-8.1.0614
vim-patch:8.1.0614,8.1.0632,8.1.0644,8.1.0658,8.1.0660,8.1.0669,8.1.0673,8.1.0679,8.1.0697,8.1.0701,8.1.0702,8.1.0709,8.1.0717,8.1.0750,8.1.0767,8.1.0772,8.1.0039
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r-- | src/nvim/eval.c | 476 |
1 files changed, 454 insertions, 22 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 9f56b42fba..1d15e04218 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -68,6 +68,7 @@ #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/sha256.h" +#include "nvim/sign.h" #include "nvim/spell.h" #include "nvim/state.h" #include "nvim/strings.h" @@ -1113,6 +1114,19 @@ static void restore_vimvar(int idx, typval_T *save_tv) } } +/// If there is a window for "curbuf", make it the current window. +static void find_win_for_curbuf(void) +{ + wininfo_T *wip; + + for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next) { + if (wip->wi_win != NULL) { + curwin = wip->wi_win; + break; + } + } +} + /* * Evaluate an expression to a list with suggestions. * For the "expr:" part of 'spellsuggest'. @@ -1125,7 +1139,7 @@ list_T *eval_spell_expr(char_u *badword, char_u *expr) list_T *list = NULL; char_u *p = skipwhite(expr); - /* Set "v:val" to the bad word. */ + // Set "v:val" to the bad word. prepare_vimvar(VV_VAL, &save_val); vimvars[VV_VAL].vv_type = VAR_STRING; vimvars[VV_VAL].vv_str = badword; @@ -7183,7 +7197,7 @@ static buf_T *tv_get_buf(typval_T *tv, int curtab_only) if (name[0] == '$' && name[1] == NUL) return lastbuf; - /* Ignore 'magic' and 'cpoptions' here to make scripts portable */ + // Ignore 'magic' and 'cpoptions' here to make scripts portable save_magic = p_magic; p_magic = TRUE; save_cpo = p_cpo; @@ -7195,13 +7209,29 @@ static buf_T *tv_get_buf(typval_T *tv, int curtab_only) p_magic = save_magic; p_cpo = save_cpo; - /* If not found, try expanding the name, like done for bufexists(). */ - if (buf == NULL) + // If not found, try expanding the name, like done for bufexists(). + if (buf == NULL) { buf = find_buffer(tv); + } return buf; } +/// Get the buffer from "arg" and give an error and return NULL if it is not +/// valid. +static buf_T * get_buf_arg(typval_T *arg) +{ + buf_T *buf; + + emsg_off++; + buf = tv_get_buf(arg, false); + emsg_off--; + if (buf == NULL) { + EMSG2(_("E158: Invalid buffer name: %s"), tv_get_string(arg)); + } + return buf; +} + /* * "bufname(expr)" function */ @@ -7999,6 +8029,85 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, FunPtr fptr) callback_free(&callback); } +/// "deletebufline()" function +static void f_deletebufline(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + buf_T *buf; + linenr_T first, last; + linenr_T lnum; + long count; + int is_curbuf; + buf_T *curbuf_save = NULL; + win_T *curwin_save = NULL; + + buf = tv_get_buf(&argvars[0], false); + if (buf == NULL) { + rettv->vval.v_number = 1; // FAIL + return; + } + is_curbuf = buf == curbuf; + + first = tv_get_lnum_buf(&argvars[1], buf); + if (argvars[2].v_type != VAR_UNKNOWN) { + last = tv_get_lnum_buf(&argvars[2], buf); + } else { + last = first; + } + + if (buf->b_ml.ml_mfp == NULL || first < 1 + || first > buf->b_ml.ml_line_count || last < first) { + rettv->vval.v_number = 1; // FAIL + return; + } + + if (!is_curbuf) { + curbuf_save = curbuf; + curwin_save = curwin; + curbuf = buf; + find_win_for_curbuf(); + } + if (last > curbuf->b_ml.ml_line_count) { + last = curbuf->b_ml.ml_line_count; + } + count = last - first + 1; + + // When coming here from Insert mode, sync undo, so that this can be + // undone separately from what was previously inserted. + if (u_sync_once == 2) { + u_sync_once = 1; // notify that u_sync() was called + u_sync(true); + } + + if (u_save(first - 1, last + 1) == FAIL) { + rettv->vval.v_number = 1; // FAIL + return; + } + + for (lnum = first; lnum <= last; lnum++) { + ml_delete(first, true); + } + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == buf) { + if (wp->w_cursor.lnum > last) { + wp->w_cursor.lnum -= count; + } else if (wp->w_cursor.lnum> first) { + wp->w_cursor.lnum = first; + } + if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count) { + wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count; + } + } + } + check_cursor_col(); + deleted_lines_mark(first, count); + + if (!is_curbuf) { + curbuf = curbuf_save; + curwin = curwin_save; + } +} + /* * "did_filetype()" function */ @@ -9286,24 +9395,6 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr) } } -/// Returns information about signs placed in a buffer as list of dicts. -static list_T *get_buffer_signs(buf_T *buf) - FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ - list_T *const l = tv_list_alloc(kListLenMayKnow); - for (signlist_T *sign = buf->b_signlist; sign; sign = sign->next) { - dict_T *const d = tv_dict_alloc(); - - tv_dict_add_nr(d, S_LEN("id"), sign->id); - tv_dict_add_nr(d, S_LEN("lnum"), sign->lnum); - tv_dict_add_str(d, S_LEN("name"), - (const char *)sign_typenr2name(sign->typenr)); - - tv_list_append_dict(l, d); - } - return l; -} - /// Returns buffer options, variables and other attributes in a dictionary. static dict_T *get_buffer_info(buf_T *buf) { @@ -15438,6 +15529,347 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = get_sw_value(curbuf); } +/// "sign_define()" function +static void f_sign_define(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + const char *name; + dict_T *dict; + char *icon = NULL; + char *linehl = NULL; + char *text = NULL; + char *texthl = NULL; + char *numhl = NULL; + + rettv->vval.v_number = -1; + + name = tv_get_string_chk(&argvars[0]); + if (name == NULL) { + return; + } + + if (argvars[1].v_type != VAR_UNKNOWN) { + if (argvars[1].v_type != VAR_DICT) { + EMSG(_(e_dictreq)); + return; + } + + // sign attributes + dict = argvars[1].vval.v_dict; + if (tv_dict_find(dict, "icon", -1) != NULL) { + icon = tv_dict_get_string(dict, "icon", true); + } + if (tv_dict_find(dict, "linehl", -1) != NULL) { + linehl = tv_dict_get_string(dict, "linehl", true); + } + if (tv_dict_find(dict, "text", -1) != NULL) { + text = tv_dict_get_string(dict, "text", true); + } + if (tv_dict_find(dict, "texthl", -1) != NULL) { + texthl = tv_dict_get_string(dict, "texthl", true); + } + if (tv_dict_find(dict, "numhl", -1) != NULL) { + numhl = tv_dict_get_string(dict, "numhl", true); + } + } + + if (sign_define_by_name((char_u *)name, (char_u *)icon, (char_u *)linehl, + (char_u *)text, (char_u *)texthl, (char_u *)numhl) + == OK) { + rettv->vval.v_number = 0; + } + + xfree(icon); + xfree(linehl); + xfree(text); + xfree(texthl); +} + +/// "sign_getdefined()" function +static void f_sign_getdefined(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + const char *name = NULL; + + tv_list_alloc_ret(rettv, 0); + + if (argvars[0].v_type != VAR_UNKNOWN) { + name = tv_get_string(&argvars[0]); + } + + sign_getlist((const char_u *)name, rettv->vval.v_list); +} + +/// "sign_getplaced()" function +static void f_sign_getplaced(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + buf_T *buf = NULL; + dict_T *dict; + dictitem_T *di; + linenr_T lnum = 0; + int sign_id = 0; + const char *group = NULL; + bool notanum = false; + + tv_list_alloc_ret(rettv, 0); + + if (argvars[0].v_type != VAR_UNKNOWN) { + // get signs placed in the specified buffer + buf = get_buf_arg(&argvars[0]); + if (buf == NULL) { + return; + } + + if (argvars[1].v_type != VAR_UNKNOWN) { + if (argvars[1].v_type != VAR_DICT + || ((dict = argvars[1].vval.v_dict) == NULL)) { + EMSG(_(e_dictreq)); + return; + } + if ((di = tv_dict_find(dict, "lnum", -1)) != NULL) { + // get signs placed at this line + lnum = (linenr_T)tv_get_number_chk(&di->di_tv, ¬anum); + if (notanum) { + return; + } + lnum = tv_get_lnum(&di->di_tv); + } + if ((di = tv_dict_find(dict, "id", -1)) != NULL) { + // get sign placed with this identifier + sign_id = (int)tv_get_number_chk(&di->di_tv, ¬anum); + if (notanum) { + return; + } + } + if ((di = tv_dict_find(dict, "group", -1)) != NULL) { + group = tv_get_string_chk(&di->di_tv); + if (group == NULL) { + return; + } + if (*group == '\0') { // empty string means global group + group = NULL; + } + } + } + } + + sign_get_placed(buf, lnum, sign_id, (const char_u *)group, + rettv->vval.v_list); +} + +/// "sign_jump()" function +static void f_sign_jump(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + int sign_id; + char *sign_group = NULL; + buf_T *buf; + bool notanum = false; + + rettv->vval.v_number = -1; + + // Sign identifer + sign_id = (int)tv_get_number_chk(&argvars[0], ¬anum); + if (notanum) { + return; + } + if (sign_id <= 0) { + EMSG(_(e_invarg)); + return; + } + + // Sign group + const char * sign_group_chk = tv_get_string_chk(&argvars[1]); + if (sign_group_chk == NULL) { + return; + } + if (sign_group_chk[0] == '\0') { + sign_group = NULL; // global sign group + } else { + sign_group = xstrdup(sign_group_chk); + if (sign_group == NULL) { + return; + } + } + + // Buffer to place the sign + buf = get_buf_arg(&argvars[2]); + if (buf == NULL) { + goto cleanup; + } + + rettv->vval.v_number = sign_jump(sign_id, (char_u *)sign_group, buf); + +cleanup: + xfree(sign_group); +} + +/// "sign_place()" function +static void f_sign_place(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + int sign_id; + char_u *group = NULL; + const char *sign_name; + buf_T *buf; + dict_T *dict; + dictitem_T *di; + linenr_T lnum = 0; + int prio = SIGN_DEF_PRIO; + bool notanum = false; + + rettv->vval.v_number = -1; + + // Sign identifer + sign_id = (int)tv_get_number_chk(&argvars[0], ¬anum); + if (notanum) { + return; + } + if (sign_id < 0) { + EMSG(_(e_invarg)); + return; + } + + // Sign group + const char *group_chk = tv_get_string_chk(&argvars[1]); + if (group_chk == NULL) { + return; + } + if (group_chk[0] == '\0') { + group = NULL; // global sign group + } else { + group = vim_strsave((const char_u *)group_chk); + if (group == NULL) { + return; + } + } + + // Sign name + sign_name = tv_get_string_chk(&argvars[2]); + if (sign_name == NULL) { + goto cleanup; + } + + // Buffer to place the sign + buf = get_buf_arg(&argvars[3]); + if (buf == NULL) { + goto cleanup; + } + + if (argvars[4].v_type != VAR_UNKNOWN) { + if (argvars[4].v_type != VAR_DICT + || ((dict = argvars[4].vval.v_dict) == NULL)) { + EMSG(_(e_dictreq)); + goto cleanup; + } + + // Line number where the sign is to be placed + if ((di = tv_dict_find(dict, "lnum", -1)) != NULL) { + lnum = (linenr_T)tv_get_number_chk(&di->di_tv, ¬anum); + if (notanum) { + goto cleanup; + } + lnum = tv_get_lnum(&di->di_tv); + } + if ((di = tv_dict_find(dict, "priority", -1)) != NULL) { + // Sign priority + prio = (int)tv_get_number_chk(&di->di_tv, ¬anum); + if (notanum) { + goto cleanup; + } + } + } + + if (sign_place(&sign_id, group, (const char_u *)sign_name, buf, lnum, prio) + == OK) { + rettv->vval.v_number = sign_id; + } + +cleanup: + xfree(group); +} + +/// "sign_undefine()" function +static void f_sign_undefine(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + const char *name; + + rettv->vval.v_number = -1; + + if (argvars[0].v_type == VAR_UNKNOWN) { + // Free all the signs + free_signs(); + rettv->vval.v_number = 0; + } else { + // Free only the specified sign + name = tv_get_string_chk(&argvars[0]); + if (name == NULL) { + return; + } + + if (sign_undefine_by_name((const char_u *)name) == OK) { + rettv->vval.v_number = 0; + } + } +} + +/// "sign_unplace()" function +static void f_sign_unplace(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + dict_T *dict; + dictitem_T *di; + int sign_id = 0; + buf_T *buf = NULL; + char_u *group = NULL; + + rettv->vval.v_number = -1; + + if (argvars[0].v_type != VAR_STRING) { + EMSG(_(e_invarg)); + return; + } + + const char *group_chk = tv_get_string(&argvars[0]); + if (group_chk[0] == '\0') { + group = NULL; // global sign group + } else { + group = vim_strsave((const char_u *)group_chk); + if (group == NULL) { + return; + } + } + + if (argvars[1].v_type != VAR_UNKNOWN) { + if (argvars[1].v_type != VAR_DICT) { + EMSG(_(e_dictreq)); + goto cleanup; + } + dict = argvars[1].vval.v_dict; + + if ((di = tv_dict_find(dict, "buffer", -1)) != NULL) { + buf = get_buf_arg(&di->di_tv); + if (buf == NULL) { + goto cleanup; + } + } + if (tv_dict_find(dict, "id", -1) != NULL) { + sign_id = tv_dict_get_number(dict, "id"); + } + } + + if (buf == NULL) { + // Delete the sign in all the buffers + FOR_ALL_BUFFERS(cbuf) { + if (sign_unplace(sign_id, group, cbuf, 0) == OK) { + rettv->vval.v_number = 0; + } + } + } else { + if (sign_unplace(sign_id, group, buf, 0) == OK) { + rettv->vval.v_number = 0; + } + } + +cleanup: + xfree(group); +} + /* * "simplify()" function */ |