diff options
Diffstat (limited to 'src/nvim/eval/funcs.c')
| -rw-r--r-- | src/nvim/eval/funcs.c | 480 | 
1 files changed, 240 insertions, 240 deletions
| diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index deeda28571..caaf675db2 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -391,28 +391,16 @@ static void f_argv(typval_T *argvars, typval_T *rettv, FunPtr fptr)    }  } +// "assert_beeps(cmd [, error])" function  static void f_assert_beeps(typval_T *argvars, typval_T *rettv, FunPtr fptr)  { -  const char *const cmd = tv_get_string_chk(&argvars[0]); -  garray_T ga; -  int ret = 0; - -  called_vim_beep = false; -  suppress_errthrow = true; -  emsg_silent = false; -  do_cmdline_cmd(cmd); -  if (!called_vim_beep) { -    prepare_assert_error(&ga); -    ga_concat(&ga, (const char_u *)"command did not beep: "); -    ga_concat(&ga, (const char_u *)cmd); -    assert_error(&ga); -    ga_clear(&ga); -    ret = 1; -  } +  rettv->vval.v_number = assert_beeps(argvars, false); +} -  suppress_errthrow = false; -  emsg_on_display = false; -  rettv->vval.v_number = ret; +// "assert_nobeep(cmd [, error])" function +static void f_assert_nobeep(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ +  rettv->vval.v_number = assert_beeps(argvars, true);  }  // "assert_equal(expected, actual[, msg])" function @@ -614,12 +602,7 @@ static void f_bufname(typval_T *argvars, typval_T *rettv, FunPtr fptr)    if (argvars[0].v_type == VAR_UNKNOWN) {      buf = curbuf;    } else { -    if (!tv_check_str_or_nr(&argvars[0])) { -      return; -    } -    emsg_off++; -    buf = tv_get_buf(&argvars[0], false); -    emsg_off--; +    buf = tv_get_buf_from_arg(&argvars[0]);    }    if (buf != NULL && buf->b_fname != NULL) {      rettv->vval.v_string = (char_u *)xstrdup((char *)buf->b_fname); @@ -639,6 +622,9 @@ static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)    if (argvars[0].v_type == VAR_UNKNOWN) {      buf = curbuf;    } else { +    // Don't use tv_get_buf_from_arg(); we continue if the buffer wasn't found +    // and the second argument isn't zero, but we want to return early if the +    // first argument isn't a string or number so only one error is shown.      if (!tv_check_str_or_nr(&argvars[0])) {        return;      } @@ -665,18 +651,12 @@ static void f_bufnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)  static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)  { -  if (!tv_check_str_or_nr(&argvars[0])) { +  const buf_T *const buf = tv_get_buf_from_arg(&argvars[0]); +  if (buf == NULL) {  // no need to search if invalid arg or buffer not found      rettv->vval.v_number = -1;      return;    } -  emsg_off++; -  buf_T *buf = tv_get_buf(&argvars[0], true); -  if (buf == NULL) {  // no need to search if buffer was not found -    rettv->vval.v_number = -1; -    goto end; -  } -    int winnr = 0;    int winid;    bool found_buf = false; @@ -689,8 +669,6 @@ static void buf_win_common(typval_T *argvars, typval_T *rettv, bool get_nr)      }    }    rettv->vval.v_number = (found_buf ? (get_nr ? winnr : winid) : -1); -end: -  emsg_off--;  }  /// "bufwinid(nr)" function @@ -743,6 +721,18 @@ buf_T *tv_get_buf(typval_T *tv, int curtab_only)    return buf;  } +/// Like tv_get_buf() but give an error message if the type is wrong. +buf_T *tv_get_buf_from_arg(typval_T *const tv) FUNC_ATTR_NONNULL_ALL +{ +  if (!tv_check_str_or_nr(tv)) { +    return NULL; +  } +  emsg_off++; +  buf_T *const buf = tv_get_buf(tv, false); +  emsg_off--; +  return buf; +} +  /// Get the buffer from "arg" and give an error and return NULL if it is not  /// valid.  buf_T * get_buf_arg(typval_T *arg) @@ -822,6 +812,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)      return;    } +  bool owned = false;    char_u      *func;    partial_T   *partial = NULL;    dict_T      *selfdict = NULL; @@ -832,6 +823,7 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)      func = partial_name(partial);    } else if (nlua_is_table_from_lua(&argvars[0])) {      func = nlua_register_table_as_callable(&argvars[0]); +    owned = true;    } else {      func = (char_u *)tv_get_string(&argvars[0]);    } @@ -849,6 +841,9 @@ static void f_call(typval_T *argvars, typval_T *rettv, FunPtr fptr)    }    func_call(func, &argvars[1], partial, selfdict, rettv); +  if (owned) { +    func_unref(func); +  }  }  /* @@ -923,7 +918,7 @@ static void f_chansend(typval_T *argvars, typval_T *rettv, FunPtr fptr)    }    uint64_t id = argvars[0].vval.v_number;    const char *error = NULL; -  rettv->vval.v_number = channel_send(id, input, input_len, &error); +  rettv->vval.v_number = channel_send(id, input, input_len, true, &error);    if (error) {      EMSG(error);    } @@ -1105,7 +1100,7 @@ static void f_complete(typval_T *argvars, typval_T *rettv, FunPtr fptr)   */  static void f_complete_add(typval_T *argvars, typval_T *rettv, FunPtr fptr)  { -  rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0); +  rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0, false);  }  /* @@ -1855,15 +1850,30 @@ static void f_environ(typval_T *argvars, typval_T *rettv, FunPtr fptr)      ptrdiff_t len = end - str;      assert(len > 0);      const char * value = str + len + 1; -    if (tv_dict_find(rettv->vval.v_dict, str, len) != NULL) { + +    char c = env[i][len]; +    env[i][len] = NUL; + +#ifdef WIN32 +    // Upper-case all the keys for Windows so we can detect duplicates +    char *const key = strcase_save(str, true); +#else +    char *const key = xstrdup(str); +#endif + +    env[i][len] = c; + +    if (tv_dict_find(rettv->vval.v_dict, key, len) != NULL) {        // Since we're traversing from the end of the env block to the front, any        // duplicate names encountered should be ignored.  This preserves the        // semantics of env vars defined later in the env block taking precedence. +      xfree(key);        continue;      }      tv_dict_add_str(rettv->vval.v_dict, -                    str, len, +                    key, len,                      value); +    xfree(key);    }    os_free_fullenv(env);  } @@ -1958,8 +1968,8 @@ static char_u *get_list_line(int c, void *cookie, int indent, bool do_concat)    return (char_u *)(s == NULL ? NULL : xstrdup(s));  } -// "execute(command)" function -static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +static void execute_common(typval_T *argvars, typval_T *rettv, FunPtr fptr, +                           int arg_off)  {    const int save_msg_silent = msg_silent;    const int save_emsg_silent = emsg_silent; @@ -1973,9 +1983,9 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)      return;    } -  if (argvars[1].v_type != VAR_UNKNOWN) { +  if (argvars[arg_off + 1].v_type != VAR_UNKNOWN) {      char buf[NUMBUFLEN]; -    const char *const s = tv_get_string_buf_chk(&argvars[1], buf); +    const char *const s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);      if (s == NULL) {        return; @@ -2002,10 +2012,10 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)      msg_col = 0;  // prevent leading spaces    } -  if (argvars[0].v_type != VAR_LIST) { -    do_cmdline_cmd(tv_get_string(&argvars[0])); -  } else if (argvars[0].vval.v_list != NULL) { -    list_T *const list = argvars[0].vval.v_list; +  if (argvars[arg_off].v_type != VAR_LIST) { +    do_cmdline_cmd(tv_get_string(&argvars[arg_off])); +  } else if (argvars[arg_off].vval.v_list != NULL) { +    list_T *const list = argvars[arg_off].vval.v_list;      tv_list_ref(list);      GetListLineCookie cookie = {        .l = list, @@ -2037,6 +2047,39 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)    capture_ga = save_capture_ga;  } +// "execute(command)" function +static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ +  execute_common(argvars, rettv, fptr, 0); +} + +// "win_execute(win_id, command)" function +static void f_win_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ +  tabpage_T *tp; +  win_T *wp = win_id2wp_tp(argvars, &tp); +  win_T *save_curwin; +  tabpage_T *save_curtab; +  // Return an empty string if something fails. +  rettv->v_type = VAR_STRING; +  rettv->vval.v_string = NULL; + +  if (wp != NULL && tp != NULL) { +    pos_T curpos = wp->w_cursor; +    if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true) == +        OK) { +      check_cursor(); +      execute_common(argvars, rettv, fptr, 1); +    } +    restore_win_noblock(save_curwin, save_curtab, true); + +    // Update the status line if the cursor moved. +    if (win_valid(wp) && !equalpos(curpos, wp->w_cursor)) { +        wp->w_redr_status = true; +    } +  } +} +  /// "exepath()" function  static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)  { @@ -2058,7 +2101,6 @@ static void f_exepath(typval_T *argvars, typval_T *rettv, FunPtr fptr)  static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)  {    int n = false; -  int len = 0;    const char *p = tv_get_string(&argvars[0]);    if (*p == '$') {  // Environment variable. @@ -2089,29 +2131,7 @@ static void f_exists(typval_T *argvars, typval_T *rettv, FunPtr fptr)        n = au_exists(p + 1);      }    } else {  // Internal variable. -    typval_T tv; - -    // get_name_len() takes care of expanding curly braces -    const char *name = p; -    char *tofree; -    len = get_name_len((const char **)&p, &tofree, true, false); -    if (len > 0) { -      if (tofree != NULL) { -        name = tofree; -      } -      n = (get_var_tv(name, len, &tv, NULL, false, true) == OK); -      if (n) { -        // Handle d.key, l[idx], f(expr). -        n = (handle_subscript(&p, &tv, true, false) == OK); -        if (n) { -          tv_clear(&tv); -        } -      } -    } -    if (*p != NUL) -      n = FALSE; - -    xfree(tofree); +    n = var_exists(p);    }    rettv->vval.v_number = n; @@ -2765,10 +2785,9 @@ static void f_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)          }        } else if (strcmp(what, "args") == 0) {          rettv->v_type = VAR_LIST; -        if (tv_list_alloc_ret(rettv, pt->pt_argc) != NULL) { -          for (int i = 0; i < pt->pt_argc; i++) { -            tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]); -          } +        tv_list_alloc_ret(rettv, pt->pt_argc); +        for (int i = 0; i < pt->pt_argc; i++) { +          tv_list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);          }        } else {          EMSG2(_(e_invarg2), what); @@ -2829,13 +2848,9 @@ static void f_getbufinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr)      }    } else if (argvars[0].v_type != VAR_UNKNOWN) {      // Information about one buffer.  Argument specifies the buffer -    if (tv_check_num(&argvars[0])) {  // issue errmsg if type error -      emsg_off++; -      argbuf = tv_get_buf(&argvars[0], false); -      emsg_off--; -      if (argbuf == NULL) { -        return; -      } +    argbuf = tv_get_buf_from_arg(&argvars[0]); +    if (argbuf == NULL) { +      return;      }    } @@ -2905,13 +2920,7 @@ static void get_buffer_lines(buf_T *buf,   */  static void f_getbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)  { -  buf_T *buf = NULL; - -  if (tv_check_str_or_nr(&argvars[0])) { -    emsg_off++; -    buf = tv_get_buf(&argvars[0], false); -    emsg_off--; -  } +  buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);    const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);    const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN @@ -3054,7 +3063,10 @@ static void f_getchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)        n = safe_vgetc();      } -    if (n == K_IGNORE || n == K_VER_SCROLLBAR || n == K_HOR_SCROLLBAR) { +    if (n == K_IGNORE +        || n == K_MOUSEMOVE +        || n == K_VER_SCROLLBAR +        || n == K_HOR_SCROLLBAR) {        continue;      }      break; @@ -5099,7 +5111,21 @@ static dict_T *create_environment(const dictitem_T *job_env,    }    if (job_env) { +#ifdef WIN32 +    TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, { +      // Always use upper-case keys for Windows so we detect duplicate keys +      char *const key = strcase_save((const char *)var->di_key, true); +      size_t len = strlen(key); +      dictitem_T *dv = tv_dict_find(env, key, len); +      if (dv) { +        tv_dict_item_remove(env, dv); +      } +      tv_dict_add_str(env, key, len, tv_get_string(&var->di_tv)); +      xfree(key); +    }); +#else      tv_dict_extend(env, job_env->di_tv.vval.v_dict, "force"); +#endif    }    if (pty) { @@ -5542,18 +5568,36 @@ static void f_libcallnr(typval_T *argvars, typval_T *rettv, FunPtr fptr)    libcall_common(argvars, rettv, VAR_NUMBER);  } -/* - * "line(string)" function - */ +// "line(string, [winid])" function  static void f_line(typval_T *argvars, typval_T *rettv, FunPtr fptr)  {    linenr_T lnum = 0; -  pos_T       *fp; +  pos_T *fp = NULL;    int fnum; -  fp = var2fpos(&argvars[0], TRUE, &fnum); -  if (fp != NULL) +  if (argvars[1].v_type != VAR_UNKNOWN) { +    tabpage_T *tp; +    win_T *save_curwin; +    tabpage_T *save_curtab; + +    // use window specified in the second argument +    win_T *wp = win_id2wp_tp(&argvars[1], &tp); +    if (wp != NULL && tp != NULL) { +      if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, true) +          == OK) { +        check_cursor(); +        fp = var2fpos(&argvars[0], true, &fnum); +      } +      restore_win_noblock(save_curwin, save_curtab, true); +    } +  } else { +    // use current window +    fp = var2fpos(&argvars[0], true, &fnum); +  } + +  if (fp != NULL) {      lnum = fp->lnum; +  }    rettv->vval.v_number = lnum;  } @@ -6529,6 +6573,26 @@ static void f_prompt_setinterrupt(typval_T *argvars,      buf->b_prompt_interrupt= interrupt_callback;  } +/// "prompt_getprompt({buffer})" function +void f_prompt_getprompt(typval_T *argvars, typval_T *rettv, FunPtr fptr) +  FUNC_ATTR_NONNULL_ALL +{ +  // return an empty string by default, e.g. it's not a prompt buffer +  rettv->v_type = VAR_STRING; +  rettv->vval.v_string = NULL; + +  buf_T *const buf = tv_get_buf_from_arg(&argvars[0]); +  if (buf == NULL) { +    return; +  } + +  if (!bt_prompt(buf)) { +    return; +  } + +  rettv->vval.v_string = vim_strsave(buf_prompt_text(buf)); +} +  // "prompt_setprompt({buffer}, {text})" function  static void f_prompt_setprompt(typval_T *argvars,                                 typval_T *rettv, FunPtr fptr) @@ -8868,56 +8932,30 @@ static void f_shiftwidth(typval_T *argvars, typval_T *rettv, FunPtr fptr)  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; +  if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_UNKNOWN) { +    // Define multiple signs +    tv_list_alloc_ret(rettv, kListLenMayKnow); -  name = tv_get_string_chk(&argvars[0]); -  if (name == NULL) { +    sign_define_multiple(argvars[0].vval.v_list, rettv->vval.v_list);      return;    } -  if (argvars[1].v_type != VAR_UNKNOWN) { -    if (argvars[1].v_type != VAR_DICT) { -      EMSG(_(e_dictreq)); -      return; -    } +  // Define a single sign +  rettv->vval.v_number = -1; -    // 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); -    } +  name = tv_get_string_chk(&argvars[0]); +  if (name == NULL) { +    return;    } -  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; +  if (argvars[1].v_type != VAR_UNKNOWN && argvars[1].v_type != VAR_DICT) { +    EMSG(_(e_dictreq)); +    return;    } -  xfree(icon); -  xfree(linehl); -  xfree(text); -  xfree(texthl); -  xfree(numhl); +  rettv->vval.v_number = sign_define_from_dict( +      name, argvars[1].v_type == VAR_DICT ? argvars[1].vval.v_dict : NULL);  }  /// "sign_getdefined()" function @@ -9038,83 +9076,44 @@ cleanup:  /// "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; +  dict_T *dict = NULL;    rettv->vval.v_number = -1; -  // Sign identifier -  sign_id = (int)tv_get_number_chk(&argvars[0], ¬anum); -  if (notanum) { -    return; -  } -  if (sign_id < 0) { -    EMSG(_(e_invarg)); +  if (argvars[4].v_type != VAR_UNKNOWN +      && (argvars[4].v_type != VAR_DICT +          || ((dict = argvars[4].vval.v_dict) == NULL))) { +    EMSG(_(e_dictreq));      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); -  } +  rettv->vval.v_number = sign_place_from_dict( +      &argvars[0], &argvars[1], &argvars[2], &argvars[3], dict); +} -  // Sign name -  sign_name = tv_get_string_chk(&argvars[2]); -  if (sign_name == NULL) { -    goto cleanup; -  } +/// "sign_placelist()" function.  Place multiple signs. +static void f_sign_placelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ +  int sign_id; -  // Buffer to place the sign -  buf = get_buf_arg(&argvars[3]); -  if (buf == NULL) { -    goto cleanup; +  tv_list_alloc_ret(rettv, kListLenMayKnow); + +  if (argvars[0].v_type != VAR_LIST) { +    EMSG(_(e_listreq)); +    return;    } -  if (argvars[4].v_type != VAR_UNKNOWN) { -    if (argvars[4].v_type != VAR_DICT -        || ((dict = argvars[4].vval.v_dict) == NULL)) { +  // Process the List of sign attributes +  TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, { +    sign_id = -1; +    if (TV_LIST_ITEM_TV(li)->v_type == VAR_DICT) { +      sign_id = sign_place_from_dict( +          NULL, NULL, NULL, NULL, TV_LIST_ITEM_TV(li)->vval.v_dict); +    } else {        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; -      } -      (void)lnum; -      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); +    tv_list_append_number(rettv->vval.v_list, sign_id); +  });  }  /// "sign_undefine()" function @@ -9122,6 +9121,14 @@ static void f_sign_undefine(typval_T *argvars, typval_T *rettv, FunPtr fptr)  {    const char *name; +  if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_UNKNOWN) { +    // Undefine multiple signs +    tv_list_alloc_ret(rettv, kListLenMayKnow); + +    sign_undefine_multiple(argvars[0].vval.v_list, rettv->vval.v_list); +    return; +  } +    rettv->vval.v_number = -1;    if (argvars[0].v_type == VAR_UNKNOWN) { @@ -9144,11 +9151,7 @@ static void f_sign_undefine(typval_T *argvars, typval_T *rettv, FunPtr fptr)  /// "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; +  dict_T *dict = NULL;    rettv->vval.v_number = -1; @@ -9157,46 +9160,38 @@ static void f_sign_unplace(typval_T *argvars, typval_T *rettv, FunPtr fptr)      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 (argvars[1].v_type != VAR_UNKNOWN) {      if (argvars[1].v_type != VAR_DICT) {        EMSG(_(e_dictreq)); -      goto cleanup; +      return;      }      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; -    } +  rettv->vval.v_number = sign_unplace_from_dict(&argvars[0], dict); +} + +/// "sign_unplacelist()" function +static void f_sign_unplacelist(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ +  int retval; + +  tv_list_alloc_ret(rettv, kListLenMayKnow); + +  if (argvars[0].v_type != VAR_LIST) { +    EMSG(_(e_listreq)); +    return;    } -cleanup: -  xfree(group); +  TV_LIST_ITER_CONST(argvars[0].vval.v_list, li, { +    retval = -1; +    if (TV_LIST_ITEM_TV(li)->v_type == VAR_DICT) { +      retval = sign_unplace_from_dict(NULL, TV_LIST_ITEM_TV(li)->vval.v_dict); +    } else { +      EMSG(_(e_dictreq)); +    } +    tv_list_append_number(rettv->vval.v_list, retval); +  });  }  /* @@ -9265,6 +9260,7 @@ static void f_sockconnect(typval_T *argvars, typval_T *rettv, FunPtr fptr)  /// struct storing information about current sort  typedef struct {    int item_compare_ic; +  bool item_compare_lc;    bool item_compare_numeric;    bool item_compare_numbers;    bool item_compare_float; @@ -9339,10 +9335,10 @@ static int item_compare(const void *s1, const void *s2, bool keep_zero)      p2 = "";    }    if (!sortinfo->item_compare_numeric) { -    if (sortinfo->item_compare_ic) { -      res = STRICMP(p1, p2); +    if (sortinfo->item_compare_lc) { +      res = strcoll(p1, p2);      } else { -      res = STRCMP(p1, p2); +      res = sortinfo->item_compare_ic ? STRICMP(p1, p2): STRCMP(p1, p2);      }    } else {      double n1, n2; @@ -9477,6 +9473,7 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)      }      info.item_compare_ic = false; +    info.item_compare_lc = false;      info.item_compare_numeric = false;      info.item_compare_numbers = false;      info.item_compare_float = false; @@ -9521,6 +9518,9 @@ static void do_sort_uniq(typval_T *argvars, typval_T *rettv, bool sort)            } else if (strcmp(info.item_compare_func, "i") == 0) {              info.item_compare_func = NULL;              info.item_compare_ic = true; +          } else if (strcmp(info.item_compare_func, "l") == 0) { +            info.item_compare_func = NULL; +            info.item_compare_lc = true;            }          }        } | 
