mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	Merge pull request #4593 from ZyX-I/length-functions
Make some function accept strings with length in place of just strings
This commit is contained in:
		| @@ -116,8 +116,14 @@ String vim_replace_termcodes(String str, Boolean from_part, Boolean do_lt, | ||||
|   } | ||||
|  | ||||
|   char *ptr = NULL; | ||||
|   replace_termcodes((char_u *)str.data, (char_u **)&ptr, | ||||
|                                             from_part, do_lt, special); | ||||
|   // Set 'cpoptions' the way we want it. | ||||
|   //    FLAG_CPO_BSLASH  set - backslashes are *not* treated specially | ||||
|   //    FLAG_CPO_KEYCODE set - keycodes are *not* reverse-engineered | ||||
|   //    FLAG_CPO_SPECI unset - <Key> sequences *are* interpreted | ||||
|   //  The third from end parameter of replace_termcodes() is true so that the | ||||
|   //  <lt> sequence is recognised - needed for a real backslash. | ||||
|   replace_termcodes((char_u *)str.data, str.size, (char_u **)&ptr, | ||||
|                     from_part, do_lt, special, CPO_TO_CPO_FLAGS); | ||||
|   return cstr_as_string(ptr); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1794,10 +1794,11 @@ bool vim_isblankline(char_u *lbuf) | ||||
| /// @param nptr Returns the signed result. | ||||
| /// @param unptr Returns the unsigned result. | ||||
| /// @param maxlen Max length of string to check. | ||||
| void vim_str2nr(char_u *start, int *prep, int *len, int what, | ||||
|                 long *nptr, unsigned long *unptr, int maxlen) | ||||
| void vim_str2nr(const char_u *const start, int *const prep, int *const len, | ||||
|                 const int what, long *const nptr, unsigned long *const unptr, | ||||
|                 const int maxlen) | ||||
| { | ||||
|   char_u *ptr = start; | ||||
|   const char_u *ptr = start; | ||||
|   int pre = 0;  // default is decimal | ||||
|   bool negative = false; | ||||
|   unsigned long un = 0; | ||||
|   | ||||
| @@ -4740,13 +4740,14 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate) | ||||
|         ++name; | ||||
|         break; | ||||
|  | ||||
|       /* Special key, e.g.: "\<C-W>" */ | ||||
|       case '<': extra = trans_special(&p, name, TRUE); | ||||
|       // Special key, e.g.: "\<C-W>" | ||||
|       case '<': | ||||
|         extra = trans_special((const char_u **) &p, STRLEN(p), name, true); | ||||
|         if (extra != 0) { | ||||
|           name += extra; | ||||
|           break; | ||||
|         } | ||||
|       /* FALLTHROUGH */ | ||||
|         // FALLTHROUGH | ||||
|  | ||||
|       default:  MB_COPY_CHAR(p, name); | ||||
|         break; | ||||
| @@ -10866,21 +10867,22 @@ static void f_hasmapto(typval_T *argvars, typval_T *rettv) | ||||
|  */ | ||||
| static void f_histadd(typval_T *argvars, typval_T *rettv) | ||||
| { | ||||
|   int histype; | ||||
|   HistoryType histype; | ||||
|   char_u      *str; | ||||
|   char_u buf[NUMBUFLEN]; | ||||
|  | ||||
|   rettv->vval.v_number = FALSE; | ||||
|   if (check_restricted() || check_secure()) | ||||
|   rettv->vval.v_number = false; | ||||
|   if (check_restricted() || check_secure()) { | ||||
|     return; | ||||
|   str = get_tv_string_chk(&argvars[0]);         /* NULL on type error */ | ||||
|   histype = str != NULL ? get_histtype(str) : -1; | ||||
|   if (histype >= 0) { | ||||
|   } | ||||
|   str = get_tv_string_chk(&argvars[0]);  // NULL on type error | ||||
|   histype = str != NULL ? get_histtype(str, STRLEN(str), false) : HIST_INVALID; | ||||
|   if (histype != HIST_INVALID) { | ||||
|     str = get_tv_string_buf(&argvars[1], buf); | ||||
|     if (*str != NUL) { | ||||
|       init_history(); | ||||
|       add_to_history(histype, str, FALSE, NUL); | ||||
|       rettv->vval.v_number = TRUE; | ||||
|       add_to_history(histype, str, false, NUL); | ||||
|       rettv->vval.v_number = true; | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| @@ -10895,20 +10897,21 @@ static void f_histdel(typval_T *argvars, typval_T *rettv) | ||||
|   char_u buf[NUMBUFLEN]; | ||||
|   char_u      *str; | ||||
|  | ||||
|   str = get_tv_string_chk(&argvars[0]);         /* NULL on type error */ | ||||
|   if (str == NULL) | ||||
|   str = get_tv_string_chk(&argvars[0]);  // NULL on type error | ||||
|   if (str == NULL) { | ||||
|     n = 0; | ||||
|   else if (argvars[1].v_type == VAR_UNKNOWN) | ||||
|     /* only one argument: clear entire history */ | ||||
|     n = clr_history(get_histtype(str)); | ||||
|   else if (argvars[1].v_type == VAR_NUMBER) | ||||
|     /* index given: remove that entry */ | ||||
|     n = del_history_idx(get_histtype(str), | ||||
|         (int)get_tv_number(&argvars[1])); | ||||
|   else | ||||
|     /* string given: remove all matching entries */ | ||||
|     n = del_history_entry(get_histtype(str), | ||||
|         get_tv_string_buf(&argvars[1], buf)); | ||||
|   } else if (argvars[1].v_type == VAR_UNKNOWN) { | ||||
|     // only one argument: clear entire history | ||||
|     n = clr_history(get_histtype(str, STRLEN(str), false)); | ||||
|   } else if (argvars[1].v_type == VAR_NUMBER) { | ||||
|     // index given: remove that entry | ||||
|     n = del_history_idx(get_histtype(str, STRLEN(str), false), | ||||
|                         (int) get_tv_number(&argvars[1])); | ||||
|   } else { | ||||
|     // string given: remove all matching entries | ||||
|     n = del_history_entry(get_histtype(str, STRLEN(str), false), | ||||
|                           get_tv_string_buf(&argvars[1], buf)); | ||||
|   } | ||||
|   rettv->vval.v_number = n; | ||||
| } | ||||
|  | ||||
| @@ -10917,20 +10920,21 @@ static void f_histdel(typval_T *argvars, typval_T *rettv) | ||||
|  */ | ||||
| static void f_histget(typval_T *argvars, typval_T *rettv) | ||||
| { | ||||
|   int type; | ||||
|   HistoryType type; | ||||
|   int idx; | ||||
|   char_u      *str; | ||||
|  | ||||
|   str = get_tv_string_chk(&argvars[0]);         /* NULL on type error */ | ||||
|   if (str == NULL) | ||||
|   str = get_tv_string_chk(&argvars[0]);  // NULL on type error | ||||
|   if (str == NULL) { | ||||
|     rettv->vval.v_string = NULL; | ||||
|   else { | ||||
|     type = get_histtype(str); | ||||
|     if (argvars[1].v_type == VAR_UNKNOWN) | ||||
|   } else { | ||||
|     type = get_histtype(str, STRLEN(str), false); | ||||
|     if (argvars[1].v_type == VAR_UNKNOWN) { | ||||
|       idx = get_history_idx(type); | ||||
|     else | ||||
|     } else { | ||||
|       idx = (int)get_tv_number_chk(&argvars[1], NULL); | ||||
|     /* -1 on type error */ | ||||
|     } | ||||
|     // -1 on type error | ||||
|     rettv->vval.v_string = vim_strsave(get_history_entry(type, idx)); | ||||
|   } | ||||
|   rettv->v_type = VAR_STRING; | ||||
| @@ -10945,11 +10949,13 @@ static void f_histnr(typval_T *argvars, typval_T *rettv) | ||||
|  | ||||
|   char_u      *history = get_tv_string_chk(&argvars[0]); | ||||
|  | ||||
|   i = history == NULL ? HIST_CMD - 1 : get_histtype(history); | ||||
|   if (i >= HIST_CMD && i < HIST_COUNT) | ||||
|   i = history == NULL ? HIST_CMD - 1 : get_histtype(history, STRLEN(history), | ||||
|                                                     false); | ||||
|   if (i != HIST_INVALID) { | ||||
|     i = get_history_idx(i); | ||||
|   else | ||||
|   } else { | ||||
|     i = -1; | ||||
|   } | ||||
|   rettv->vval.v_number = i; | ||||
| } | ||||
|  | ||||
| @@ -12086,8 +12092,9 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) | ||||
|  | ||||
|   mode = get_map_mode(&which, 0); | ||||
|  | ||||
|   keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE); | ||||
|   rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); | ||||
|   keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, false, | ||||
|                            CPO_TO_CPO_FLAGS); | ||||
|   rhs = check_map(keys, mode, exact, false, abbr, &mp, &buffer_local); | ||||
|   xfree(keys_buf); | ||||
|  | ||||
|   if (!get_dict) { | ||||
|   | ||||
| @@ -4556,7 +4556,8 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep, | ||||
|   char_u      *rep_buf = NULL; | ||||
|   garray_T    *gap; | ||||
|  | ||||
|   replace_termcodes(rep, &rep_buf, FALSE, FALSE, FALSE); | ||||
|   replace_termcodes(rep, STRLEN(rep), &rep_buf, false, false, false, | ||||
|                     CPO_TO_CPO_FLAGS); | ||||
|   if (rep_buf == NULL) { | ||||
|     /* Can't replace termcodes - try using the string as is */ | ||||
|     rep_buf = vim_strsave(rep); | ||||
|   | ||||
| @@ -4272,20 +4272,33 @@ void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options) | ||||
| *  Command line history stuff	 * | ||||
| *********************************/ | ||||
|  | ||||
| /* | ||||
|  * Translate a history character to the associated type number. | ||||
|  */ | ||||
| static int hist_char2type(int c) | ||||
| /// Translate a history character to the associated type number | ||||
| static HistoryType hist_char2type(const int c) | ||||
|   FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT | ||||
| { | ||||
|   if (c == ':') | ||||
|     return HIST_CMD; | ||||
|   if (c == '=') | ||||
|     return HIST_EXPR; | ||||
|   if (c == '@') | ||||
|     return HIST_INPUT; | ||||
|   if (c == '>') | ||||
|     return HIST_DEBUG; | ||||
|   return HIST_SEARCH;       /* must be '?' or '/' */ | ||||
|   switch (c) { | ||||
|     case ':': { | ||||
|       return HIST_CMD; | ||||
|     } | ||||
|     case '=': { | ||||
|       return HIST_EXPR; | ||||
|     } | ||||
|     case '@': { | ||||
|       return HIST_INPUT; | ||||
|     } | ||||
|     case '>': { | ||||
|       return HIST_DEBUG; | ||||
|     } | ||||
|     case '/': | ||||
|     case '?': { | ||||
|       return HIST_SEARCH; | ||||
|     } | ||||
|     default: { | ||||
|       assert(false); | ||||
|     } | ||||
|   } | ||||
|   // Silence -Wreturn-type | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -4454,28 +4467,38 @@ in_history ( | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Convert history name (from table above) to its HIST_ equivalent. | ||||
|  * When "name" is empty, return "cmd" history. | ||||
|  * Returns -1 for unknown history name. | ||||
|  */ | ||||
| int get_histtype(char_u *name) | ||||
| /// Convert history name to its HIST_ equivalent | ||||
| /// | ||||
| /// Names are taken from the table above. When `name` is empty returns currently | ||||
| /// active history or HIST_DEFAULT, depending on `return_default` argument. | ||||
| /// | ||||
| /// @param[in]  name            Converted name. | ||||
| /// @param[in]  len             Name length. | ||||
| /// @param[in]  return_default  Determines whether HIST_DEFAULT should be | ||||
| ///                             returned or value based on `ccline.cmdfirstc`. | ||||
| /// | ||||
| /// @return Any value from HistoryType enum, including HIST_INVALID. May not | ||||
| ///         return HIST_DEFAULT unless return_default is true. | ||||
| HistoryType get_histtype(const char_u *const name, const size_t len, | ||||
|                          const bool return_default) | ||||
|   FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT | ||||
| { | ||||
|   int i; | ||||
|   int len = (int)STRLEN(name); | ||||
|   // No argument: use current history. | ||||
|   if (len == 0) { | ||||
|     return return_default ? HIST_DEFAULT :hist_char2type(ccline.cmdfirstc); | ||||
|   } | ||||
|  | ||||
|   /* No argument: use current history. */ | ||||
|   if (len == 0) | ||||
|     return hist_char2type(ccline.cmdfirstc); | ||||
|  | ||||
|   for (i = 0; history_names[i] != NULL; ++i) | ||||
|     if (STRNICMP(name, history_names[i], len) == 0) | ||||
|   for (HistoryType i = 0; history_names[i] != NULL; i++) { | ||||
|     if (STRNICMP(name, history_names[i], len) == 0) { | ||||
|       return i; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && name[1] == NUL) | ||||
|   if (vim_strchr((char_u *)":=@>?/", name[0]) != NULL && len == 1) { | ||||
|     return hist_char2type(name[0]); | ||||
|   } | ||||
|  | ||||
|   return -1; | ||||
|   return HIST_INVALID; | ||||
| } | ||||
|  | ||||
| static int last_maptick = -1;           /* last seen maptick */ | ||||
| @@ -4847,23 +4870,20 @@ void ex_history(exarg_T *eap) | ||||
|     while (ASCII_ISALPHA(*end) | ||||
|            || vim_strchr((char_u *)":=@>/?", *end) != NULL) | ||||
|       end++; | ||||
|     i = *end; | ||||
|     *end = NUL; | ||||
|     histype1 = get_histtype(arg); | ||||
|     if (histype1 == -1) { | ||||
|       if (STRNICMP(arg, "all", STRLEN(arg)) == 0) { | ||||
|     histype1 = get_histtype(arg, end - arg, false); | ||||
|     if (histype1 == HIST_INVALID) { | ||||
|       if (STRNICMP(arg, "all", end - arg) == 0) { | ||||
|         histype1 = 0; | ||||
|         histype2 = HIST_COUNT-1; | ||||
|       } else { | ||||
|         *end = i; | ||||
|         EMSG(_(e_trailing)); | ||||
|         return; | ||||
|       } | ||||
|     } else | ||||
|       histype2 = histype1; | ||||
|     *end = i; | ||||
|   } else | ||||
|   } else { | ||||
|     end = arg; | ||||
|   } | ||||
|   if (!get_list_range(&end, &hisidx1, &hisidx2) || *end != NUL) { | ||||
|     EMSG(_(e_trailing)); | ||||
|     return; | ||||
|   | ||||
| @@ -27,11 +27,13 @@ | ||||
|  | ||||
| /// Present history tables | ||||
| typedef enum { | ||||
|   HIST_CMD,     ///< Colon commands. | ||||
|   HIST_SEARCH,  ///< Search commands. | ||||
|   HIST_EXPR,    ///< Expressions (e.g. from entering = register). | ||||
|   HIST_INPUT,   ///< input() lines. | ||||
|   HIST_DEBUG,   ///< Debug commands. | ||||
|   HIST_DEFAULT = -2,  ///< Default (current) history. | ||||
|   HIST_INVALID = -1,  ///< Unknown history. | ||||
|   HIST_CMD = 0,       ///< Colon commands. | ||||
|   HIST_SEARCH,        ///< Search commands. | ||||
|   HIST_EXPR,          ///< Expressions (e.g. from entering = register). | ||||
|   HIST_INPUT,         ///< input() lines. | ||||
|   HIST_DEBUG,         ///< Debug commands. | ||||
| } HistoryType; | ||||
|  | ||||
| /// Number of history tables | ||||
|   | ||||
| @@ -2688,22 +2688,24 @@ do_map ( | ||||
|     goto theend; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * If mapping has been given as ^V<C_UP> say, then replace the term codes | ||||
|    * with the appropriate two bytes. If it is a shifted special key, unshift | ||||
|    * it too, giving another two bytes. | ||||
|    * replace_termcodes() may move the result to allocated memory, which | ||||
|    * needs to be freed later (*keys_buf and *arg_buf). | ||||
|    * replace_termcodes() also removes CTRL-Vs and sometimes backslashes. | ||||
|    */ | ||||
|   if (haskey) | ||||
|     keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, special); | ||||
|   // If mapping has been given as ^V<C_UP> say, then replace the term codes | ||||
|   // with the appropriate two bytes. If it is a shifted special key, unshift | ||||
|   // it too, giving another two bytes. | ||||
|   // replace_termcodes() may move the result to allocated memory, which | ||||
|   // needs to be freed later (*keys_buf and *arg_buf). | ||||
|   // replace_termcodes() also removes CTRL-Vs and sometimes backslashes. | ||||
|   if (haskey) { | ||||
|     keys = replace_termcodes(keys, STRLEN(keys), &keys_buf, true, true, special, | ||||
|                              CPO_TO_CPO_FLAGS); | ||||
|   } | ||||
|   orig_rhs = rhs; | ||||
|   if (hasarg) { | ||||
|     if (STRICMP(rhs, "<nop>") == 0)         /* "<Nop>" means nothing */ | ||||
|     if (STRICMP(rhs, "<nop>") == 0) {  // "<Nop>" means nothing | ||||
|       rhs = (char_u *)""; | ||||
|     else | ||||
|       rhs = replace_termcodes(rhs, &arg_buf, FALSE, TRUE, special); | ||||
|     } else { | ||||
|       rhs = replace_termcodes(rhs, STRLEN(rhs), &arg_buf, false, true, special, | ||||
|                               CPO_TO_CPO_FLAGS); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* | ||||
| @@ -3270,7 +3272,8 @@ int map_to_exists(char_u *str, char_u *modechars, int abbr) | ||||
|   char_u      *buf; | ||||
|   int retval; | ||||
|  | ||||
|   rhs = replace_termcodes(str, &buf, FALSE, TRUE, FALSE); | ||||
|   rhs = replace_termcodes(str, STRLEN(str), &buf, false, true, false, | ||||
|                           CPO_TO_CPO_FLAGS); | ||||
|  | ||||
|   if (vim_strchr(modechars, 'n') != NULL) | ||||
|     mode |= NORMAL; | ||||
| @@ -3465,7 +3468,7 @@ int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file) | ||||
|         mp = maphash[hash]; | ||||
|       for (; mp; mp = mp->m_next) { | ||||
|         if (mp->m_mode & expand_mapmodes) { | ||||
|           p = translate_mapping(mp->m_keys, TRUE); | ||||
|           p = translate_mapping(mp->m_keys, true, CPO_TO_CPO_FLAGS); | ||||
|           if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) { | ||||
|             if (round == 1) | ||||
|               ++count; | ||||
| @@ -4190,14 +4193,15 @@ void add_map(char_u *map, int mode) | ||||
| // Returns NULL when there is a problem. | ||||
| static char_u * translate_mapping ( | ||||
|     char_u *str, | ||||
|     int expmap  // TRUE when expanding mappings on command-line | ||||
|     int expmap,   // True when expanding mappings on command-line | ||||
|     int cpo_flags  // Value of various flags present in &cpo | ||||
| ) | ||||
| { | ||||
|   garray_T ga; | ||||
|   ga_init(&ga, 1, 40); | ||||
|  | ||||
|   int cpo_bslash = (vim_strchr(p_cpo, CPO_BSLASH) != NULL); | ||||
|   int cpo_special = (vim_strchr(p_cpo, CPO_SPECI) != NULL); | ||||
|   bool cpo_bslash = !(cpo_flags&FLAG_CPO_BSLASH); | ||||
|   bool cpo_special = !(cpo_flags&FLAG_CPO_SPECI); | ||||
|  | ||||
|   for (; *str; ++str) { | ||||
|     int c = *str; | ||||
|   | ||||
| @@ -482,26 +482,28 @@ char_u *get_special_key_name(int c, int modifiers) | ||||
|   return string; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Try translating a <> name at (*srcp)[] to dst[]. | ||||
|  * Return the number of characters added to dst[], zero for no match. | ||||
|  * If there is a match, srcp is advanced to after the <> name. | ||||
|  * dst[] must be big enough to hold the result (up to six characters)! | ||||
|  */ | ||||
| unsigned int  | ||||
| trans_special ( | ||||
|     char_u **srcp, | ||||
|     char_u *dst, | ||||
|     int keycode             /* prefer key code, e.g. K_DEL instead of DEL */ | ||||
| ) | ||||
| /// Try translating a <> name | ||||
| /// | ||||
| /// @param[in,out]  srcp  Source from which <> are translated. Is advanced to | ||||
| ///                       after the <> name if there is a match. | ||||
| /// @param[in]  src_len  Length of the srcp. | ||||
| /// @param[out]  dst  Location where translation result will be kept. Must have | ||||
| ///                   at least six bytes. | ||||
| /// @param[in]  keycode  Prefer key code, e.g. K_DEL in place of DEL. | ||||
| /// | ||||
| /// @return Number of characters added to dst, zero for no match. | ||||
| unsigned int trans_special(const char_u **srcp, const size_t src_len, | ||||
|                            char_u *const dst, const bool keycode) | ||||
|   FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT | ||||
| { | ||||
|   int modifiers = 0; | ||||
|   int key; | ||||
|   unsigned int dlen = 0; | ||||
|  | ||||
|   key = find_special_key(srcp, &modifiers, keycode, FALSE); | ||||
|   if (key == 0) | ||||
|   key = find_special_key(srcp, src_len, &modifiers, keycode, false); | ||||
|   if (key == 0) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   /* Put the appropriate modifier in a string */ | ||||
|   if (modifiers != 0) { | ||||
| @@ -514,69 +516,78 @@ trans_special ( | ||||
|     dst[dlen++] = K_SPECIAL; | ||||
|     dst[dlen++] = (char_u)KEY2TERMCAP0(key); | ||||
|     dst[dlen++] = KEY2TERMCAP1(key); | ||||
|   } else if (has_mbyte && !keycode) | ||||
|   } else if (has_mbyte && !keycode) { | ||||
|     dlen += (unsigned int)(*mb_char2bytes)(key, dst + dlen); | ||||
|   else if (keycode) { | ||||
|   } else if (keycode) { | ||||
|     char_u *after = add_char2buf(key, dst + dlen); | ||||
|     assert(after >= dst && (uintmax_t)(after - dst) <= UINT_MAX); | ||||
|     dlen = (unsigned int)(after - dst); | ||||
|   } | ||||
|   else | ||||
|   } else { | ||||
|     dst[dlen++] = (char_u)key; | ||||
|   } | ||||
|  | ||||
|   return dlen; | ||||
| } | ||||
|  | ||||
| // Try translating a <> name at (*srcp)[], return the key and modifiers. | ||||
| // srcp is advanced to after the <> name. | ||||
| // returns 0 if there is no match. | ||||
| int find_special_key( | ||||
|     char_u **srcp, | ||||
|     int *modp, | ||||
|     int keycode,                // prefer key code, e.g. K_DEL instead of DEL | ||||
|     int keep_x_key              // don't translate xHome to Home key | ||||
| ) | ||||
| /// Try translating a <> name | ||||
| /// | ||||
| /// @param[in,out]  srcp  Translated <> name. Is advanced to after the <> name. | ||||
| /// @param[in]  src_len  srcp length. | ||||
| /// @param[out]  modp  Location where information about modifiers is saved. | ||||
| /// @param[in]  keycode  Prefer key code, e.g. K_DEL in place of DEL. | ||||
| /// @param[in]  keep_x_key  Don’t translate xHome to Home key. | ||||
| /// | ||||
| /// @return Key and modifiers or 0 if there is no match. | ||||
| int find_special_key(const char_u **srcp, const size_t src_len, int *const modp, | ||||
|                      const bool keycode, const bool keep_x_key) | ||||
|   FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL | ||||
| { | ||||
|   char_u      *last_dash; | ||||
|   char_u      *end_of_name; | ||||
|   char_u      *src; | ||||
|   char_u      *bp; | ||||
|   const char_u *last_dash; | ||||
|   const char_u *end_of_name; | ||||
|   const char_u *src; | ||||
|   const char_u *bp; | ||||
|   const char_u *const end = *srcp + src_len - 1; | ||||
|   int modifiers; | ||||
|   int bit; | ||||
|   int key; | ||||
|   unsigned long n; | ||||
|   int l; | ||||
|  | ||||
|   src = *srcp; | ||||
|   if (src[0] != '<') | ||||
|   if (src_len == 0) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   src = *srcp; | ||||
|   if (src[0] != '<') { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   // Find end of modifier list | ||||
|   last_dash = src; | ||||
|   for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) { | ||||
|   for (bp = src + 1; bp <= end && (*bp == '-' || vim_isIDc(*bp)); bp++) { | ||||
|     if (*bp == '-') { | ||||
|       last_dash = bp; | ||||
|       if (bp[1] != NUL) { | ||||
|       if (bp + 1 <= end) { | ||||
|         if (has_mbyte) { | ||||
|           l = mb_ptr2len(bp + 1); | ||||
|           l = mb_ptr2len_len(bp + 1, (int) (end - bp) + 1); | ||||
|         } else { | ||||
|           l = 1; | ||||
|         } | ||||
|         if (bp[l + 1] == '>') { | ||||
|           bp += l;              // anything accepted, like <C-?> | ||||
|         if (end - bp > l && bp[l + 1] == '>') { | ||||
|           bp += l;  // anything accepted, like <C-?> | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) { | ||||
|       bp += 3;          // skip t_xx, xx may be '-' or '>' | ||||
|     } else if (STRNICMP(bp, "char-", 5) == 0) { | ||||
|     if (end - bp > 3 && bp[0] == 't' && bp[1] == '_') { | ||||
|       bp += 3;  // skip t_xx, xx may be '-' or '>' | ||||
|     } else if (end - bp > 4 && STRNICMP(bp, "char-", 5) == 0) { | ||||
|       vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0); | ||||
|       bp += l + 5; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (*bp == '>') {     /* found matching '>' */ | ||||
|   if (bp <= end && *bp == '>') {  // found matching '>' | ||||
|     end_of_name = bp + 1; | ||||
|  | ||||
|     /* Which modifiers are given? */ | ||||
| @@ -696,7 +707,7 @@ int find_special_key_in_table(int c) | ||||
|  * termcap name. | ||||
|  * Return the key code, or 0 if not found. | ||||
|  */ | ||||
| int get_special_key_code(char_u *name) | ||||
| int get_special_key_code(const char_u *name) | ||||
| { | ||||
|   char_u  *table_name; | ||||
|   int i, j; | ||||
| @@ -730,50 +741,58 @@ int get_mouse_button(int code, bool *is_click, bool *is_drag) | ||||
|   return 0;         /* Shouldn't get here */ | ||||
| } | ||||
|  | ||||
| // Replace any terminal code strings in from[] with the equivalent internal | ||||
| // vim representation.	This is used for the "from" and "to" part of a | ||||
| // mapping, and the "to" part of a menu command. | ||||
| // Any strings like "<C-UP>" are also replaced, unless 'cpoptions' contains | ||||
| // '<'. | ||||
| // K_SPECIAL by itself is replaced by K_SPECIAL KS_SPECIAL KE_FILLER. | ||||
| // | ||||
| // The replacement is done in result[] and finally copied into allocated | ||||
| // memory. If this all works well *bufp is set to the allocated memory and a | ||||
| // pointer to it is returned. If something fails *bufp is set to NULL and from | ||||
| // is returned. | ||||
| // | ||||
| // CTRL-V characters are removed.  When "from_part" is TRUE, a trailing CTRL-V | ||||
| // is included, otherwise it is removed (for ":map xx ^V", maps xx to | ||||
| // nothing).  When 'cpoptions' does not contain 'B', a backslash can be used | ||||
| // instead of a CTRL-V. | ||||
| char_u * replace_termcodes ( | ||||
|     char_u *from, | ||||
|     char_u **bufp, | ||||
|     int from_part, | ||||
|     int do_lt,                     // also translate <lt> | ||||
|     int special                    // always accept <key> notation | ||||
| ) | ||||
| /// Replace any terminal code strings with the equivalent internal | ||||
| /// representation | ||||
| /// | ||||
| /// This is used for the "from" and "to" part of a mapping, and the "to" part of | ||||
| /// a menu command. Any strings like "<C-UP>" are also replaced, unless | ||||
| /// 'cpoptions' contains '<'. K_SPECIAL by itself is replaced by K_SPECIAL | ||||
| /// KS_SPECIAL KE_FILLER. | ||||
| /// | ||||
| /// @param[in]  from  What characters to replace. | ||||
| /// @param[in]  from_len  Length of the "from" argument. | ||||
| /// @param[out]  bufp  Location where results were saved in case of success | ||||
| ///                    (allocated). Will be set to NULL in case of failure. | ||||
| /// @param[in]  do_lt  If true, also translate <lt>. | ||||
| /// @param[in]  from_part  If true, trailing <C-v> is included, otherwise it is | ||||
| ///                        removed (to make ":map xx ^V" map xx to nothing). | ||||
| ///                        When cpo_flags contains #FLAG_CPO_BSLASH, a backslash | ||||
| ///                        can be used in place of <C-v>. All other <C-v> | ||||
| ///                        characters are removed. | ||||
| /// @param[in]  special  If true, always accept <key> notation. | ||||
| /// @param[in]  cpo_flags  Relevant flags derived from p_cpo, see | ||||
| ///                        #CPO_TO_CPO_FLAGS. | ||||
| /// | ||||
| /// @return Pointer to an allocated memory in case of success, "from" in case of | ||||
| ///         failure. In case of success returned pointer is also saved to | ||||
| ///         "bufp". | ||||
| char_u *replace_termcodes(const char_u *from, const size_t from_len, | ||||
|                           char_u **bufp, const bool from_part, const bool do_lt, | ||||
|                           const bool special, int cpo_flags) | ||||
|   FUNC_ATTR_NONNULL_ALL | ||||
| { | ||||
|   ssize_t i; | ||||
|   size_t slen; | ||||
|   char_u key; | ||||
|   size_t dlen = 0; | ||||
|   char_u      *src; | ||||
|   const char_u *src; | ||||
|   const char_u *const end = from + from_len - 1; | ||||
|   int do_backslash;             // backslash is a special character | ||||
|   int do_special;               // recognize <> key codes | ||||
|   char_u      *result;          // buffer for resulting string | ||||
|  | ||||
|   do_backslash = (vim_strchr(p_cpo, CPO_BSLASH) == NULL); | ||||
|   do_special = (vim_strchr(p_cpo, CPO_SPECI) == NULL) || special; | ||||
|   do_backslash = !(cpo_flags&FLAG_CPO_BSLASH); | ||||
|   do_special = !(cpo_flags&FLAG_CPO_SPECI) || special; | ||||
|  | ||||
|   // Allocate space for the translation.  Worst case a single character is | ||||
|   // replaced by 6 bytes (shifted special key), plus a NUL at the end. | ||||
|   result = xmalloc(STRLEN(from) * 6 + 1); | ||||
|   result = xmalloc(from_len * 6 + 1); | ||||
|  | ||||
|   src = from; | ||||
|  | ||||
|   // Check for #n at start only: function key n | ||||
|   if (from_part && src[0] == '#' && ascii_isdigit(src[1])) {  // function key | ||||
|   if (from_part && from_len > 1 && src[0] == '#' | ||||
|       && ascii_isdigit(src[1])) {  // function key | ||||
|     result[dlen++] = K_SPECIAL; | ||||
|     result[dlen++] = 'k'; | ||||
|     if (src[1] == '0') { | ||||
| @@ -785,13 +804,14 @@ char_u * replace_termcodes ( | ||||
|   } | ||||
|  | ||||
|   // Copy each byte from *from to result[dlen] | ||||
|   while (*src != NUL) { | ||||
|   while (src <= end) { | ||||
|     // If 'cpoptions' does not contain '<', check for special key codes, | ||||
|     // like "<C-S-LeftMouse>" | ||||
|     if (do_special && (do_lt || STRNCMP(src, "<lt>", 4) != 0)) { | ||||
|     if (do_special && (do_lt || ((end - src) >= 3 | ||||
|                                  && STRNCMP(src, "<lt>", 4) != 0))) { | ||||
|       // Replace <SID> by K_SNR <script-nr> _. | ||||
|       // (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14) | ||||
|       if (STRNICMP(src, "<SID>", 5) == 0) { | ||||
|       if (end - src >= 4 && STRNICMP(src, "<SID>", 5) == 0) { | ||||
|         if (current_SID <= 0) { | ||||
|           EMSG(_(e_usingsid)); | ||||
|         } else { | ||||
| @@ -806,7 +826,7 @@ char_u * replace_termcodes ( | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       slen = trans_special(&src, result + dlen, TRUE); | ||||
|       slen = trans_special(&src, (size_t) (end - src) + 1, result + dlen, true); | ||||
|       if (slen) { | ||||
|         dlen += slen; | ||||
|         continue; | ||||
| @@ -819,10 +839,10 @@ char_u * replace_termcodes ( | ||||
|       // Replace <Leader> by the value of "mapleader". | ||||
|       // Replace <LocalLeader> by the value of "maplocalleader". | ||||
|       // If "mapleader" or "maplocalleader" isn't set use a backslash. | ||||
|       if (STRNICMP(src, "<Leader>", 8) == 0) { | ||||
|       if (end - src >= 7 && STRNICMP(src, "<Leader>", 8) == 0) { | ||||
|         len = 8; | ||||
|         p = get_var_value((char_u *)"g:mapleader"); | ||||
|       } else if (STRNICMP(src, "<LocalLeader>", 13) == 0)   { | ||||
|       } else if (end - src >= 12 && STRNICMP(src, "<LocalLeader>", 13) == 0) { | ||||
|         len = 13; | ||||
|         p = get_var_value((char_u *)"g:maplocalleader"); | ||||
|       } else { | ||||
| @@ -851,8 +871,8 @@ char_u * replace_termcodes ( | ||||
|     // If 'cpoptions' does not contain 'B', also accept a backslash. | ||||
|     key = *src; | ||||
|     if (key == Ctrl_V || (do_backslash && key == '\\')) { | ||||
|       ++src;  // skip CTRL-V or backslash | ||||
|       if (*src == NUL) { | ||||
|       src++;  // skip CTRL-V or backslash | ||||
|       if (src > end) { | ||||
|         if (from_part) { | ||||
|           result[dlen++] = key; | ||||
|         } | ||||
| @@ -861,7 +881,7 @@ char_u * replace_termcodes ( | ||||
|     } | ||||
|  | ||||
|     // skip multibyte char correctly | ||||
|     for (i = (*mb_ptr2len)(src); i > 0; --i) { | ||||
|     for (i = (*mb_ptr2len_len)(src, (int) (end - src) + 1); i > 0; i--) { | ||||
|       // If the character is K_SPECIAL, replace it with K_SPECIAL | ||||
|       // KS_SPECIAL KE_FILLER. | ||||
|       // If compiled with the GUI replace CSI with K_CSI. | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| #ifndef NVIM_KEYMAP_H | ||||
| #define NVIM_KEYMAP_H | ||||
|  | ||||
| #include "nvim/strings.h" | ||||
|  | ||||
| /* | ||||
|  * Keycode definitions for special keys. | ||||
|  * | ||||
| @@ -461,6 +463,14 @@ enum key_extra { | ||||
| // This is a total of 6 tokens, and is currently the longest one possible. | ||||
| #define MAX_KEY_CODE_LEN    6 | ||||
|  | ||||
| #define FLAG_CPO_BSLASH    0x01 | ||||
| #define FLAG_CPO_SPECI     0x02 | ||||
| #define CPO_TO_CPO_FLAGS   (((vim_strchr(p_cpo, CPO_BSLASH) == NULL) \ | ||||
|                              ? 0 \ | ||||
|                              : FLAG_CPO_BSLASH)| \ | ||||
|                             (vim_strchr(p_cpo, CPO_SPECI) == NULL \ | ||||
|                              ? 0 \ | ||||
|                              : FLAG_CPO_SPECI)) | ||||
|  | ||||
| #ifdef INCLUDE_GENERATED_DECLARATIONS | ||||
| # include "keymap.h.generated.h" | ||||
|   | ||||
| @@ -215,10 +215,12 @@ ex_menu ( | ||||
|     if (STRICMP(map_to, "<nop>") == 0) {        /* "<Nop>" means nothing */ | ||||
|       map_to = (char_u *)""; | ||||
|       map_buf = NULL; | ||||
|     } else if (modes & MENU_TIP_MODE) | ||||
|       map_buf = NULL;           /* Menu tips are plain text. */ | ||||
|     else | ||||
|       map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special); | ||||
|     } else if (modes & MENU_TIP_MODE) { | ||||
|       map_buf = NULL;  // Menu tips are plain text. | ||||
|     } else { | ||||
|       map_to = replace_termcodes(map_to, STRLEN(map_to), &map_buf, false, true, | ||||
|                                  special, CPO_TO_CPO_FLAGS); | ||||
|     } | ||||
|     menuarg.modes = modes; | ||||
|     menuarg.noremap[0] = noremap; | ||||
|     menuarg.silent[0] = silent; | ||||
|   | ||||
| @@ -1177,28 +1177,27 @@ do_set ( | ||||
|           errmsg = e_invarg; | ||||
|           goto skip; | ||||
|         } | ||||
|         arg[len] = NUL;                             /* put NUL after name */ | ||||
|         if (arg[1] == 't' && arg[2] == '_')         /* could be term code */ | ||||
|           opt_idx = findoption(arg + 1); | ||||
|         arg[len++] = '>';                           /* restore '>' */ | ||||
|         if (opt_idx == -1) | ||||
|         if (arg[1] == 't' && arg[2] == '_') {  // could be term code | ||||
|           opt_idx = findoption_len(arg + 1, (size_t) (len - 1)); | ||||
|         } | ||||
|         len++; | ||||
|         if (opt_idx == -1) { | ||||
|           key = find_key_option(arg + 1); | ||||
|         } | ||||
|       } else { | ||||
|         len = 0; | ||||
|         /* | ||||
|          * The two characters after "t_" may not be alphanumeric. | ||||
|          */ | ||||
|         if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) | ||||
|         // The two characters after "t_" may not be alphanumeric. | ||||
|         if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) { | ||||
|           len = 4; | ||||
|         else | ||||
|           while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') | ||||
|             ++len; | ||||
|         nextchar = arg[len]; | ||||
|         arg[len] = NUL;                             /* put NUL after name */ | ||||
|         opt_idx = findoption(arg); | ||||
|         arg[len] = nextchar;                        /* restore nextchar */ | ||||
|         if (opt_idx == -1) | ||||
|         } else { | ||||
|           while (ASCII_ISALNUM(arg[len]) || arg[len] == '_') { | ||||
|             len++; | ||||
|           } | ||||
|         } | ||||
|         opt_idx = findoption_len(arg, (size_t) len); | ||||
|         if (opt_idx == -1) { | ||||
|           key = find_key_option(arg); | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       /* remember character after option name */ | ||||
| @@ -2965,7 +2964,8 @@ did_set_string_option ( | ||||
|   /* 'pastetoggle': translate key codes like in a mapping */ | ||||
|   else if (varp == &p_pt) { | ||||
|     if (*p_pt) { | ||||
|       (void)replace_termcodes(p_pt, &p, TRUE, TRUE, FALSE); | ||||
|       (void)replace_termcodes(p_pt, STRLEN(p_pt), &p, true, true, false, | ||||
|                               CPO_TO_CPO_FLAGS); | ||||
|       if (p != NULL) { | ||||
|         if (new_value_alloced) | ||||
|           free_string_option(p_pt); | ||||
| @@ -4303,14 +4303,16 @@ static void check_redraw(uint32_t flags) | ||||
|     redraw_all_later(NOT_VALID); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Find index for option 'arg'. | ||||
|  * Return -1 if not found. | ||||
|  */ | ||||
| static int findoption(char_u *arg) | ||||
| /// Find index for named option | ||||
| /// | ||||
| /// @param[in]  arg  Option to find index for. | ||||
| /// @param[in]  len  Length of the option. | ||||
| /// | ||||
| /// @return Index of the option or -1 if option was not found. | ||||
| int findoption_len(const char_u *const arg, const size_t len) | ||||
| { | ||||
|   char            *s, *p; | ||||
|   static short quick_tab[27] = {0, 0};          /* quick access table */ | ||||
|   char *s, *p; | ||||
|   static int quick_tab[27] = { 0, 0 };  // quick access table | ||||
|   int is_term_opt; | ||||
|  | ||||
|   /* | ||||
| @@ -4334,25 +4336,31 @@ static int findoption(char_u *arg) | ||||
|   /* | ||||
|    * Check for name starting with an illegal character. | ||||
|    */ | ||||
|   if (arg[0] < 'a' || arg[0] > 'z') | ||||
|   if (len == 0 || arg[0] < 'a' || arg[0] > 'z') { | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   int opt_idx; | ||||
|   is_term_opt = (arg[0] == 't' && arg[1] == '_'); | ||||
|   if (is_term_opt) | ||||
|   is_term_opt = (len > 2 && arg[0] == 't' && arg[1] == '_'); | ||||
|   if (is_term_opt) { | ||||
|     opt_idx = quick_tab[26]; | ||||
|   else | ||||
|   } else { | ||||
|     opt_idx = quick_tab[CharOrdLow(arg[0])]; | ||||
|   } | ||||
|   // Match full name | ||||
|   for (; (s = options[opt_idx].fullname) != NULL; opt_idx++) { | ||||
|     if (STRCMP(arg, s) == 0)                        /* match full name */ | ||||
|     if (STRNCMP(arg, s, len) == 0 && s[len] == NUL) { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   if (s == NULL && !is_term_opt) { | ||||
|     opt_idx = quick_tab[CharOrdLow(arg[0])]; | ||||
|     // Match short name | ||||
|     for (; options[opt_idx].fullname != NULL; opt_idx++) { | ||||
|       s = options[opt_idx].shortname; | ||||
|       if (s != NULL && STRCMP(arg, s) == 0)         /* match short name */ | ||||
|       if (s != NULL && STRNCMP(arg, s, len) == 0 && s[len] == NUL) { | ||||
|         break; | ||||
|       } | ||||
|       s = NULL; | ||||
|     } | ||||
|   } | ||||
| @@ -4419,6 +4427,15 @@ bool set_tty_option(char *name, char *value) | ||||
|     || !strcmp(name, "ttytype"); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Find index for option 'arg'. | ||||
|  * Return -1 if not found. | ||||
|  */ | ||||
| static int findoption(char_u *arg) | ||||
| { | ||||
|   return findoption_len(arg, STRLEN(arg)); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Get the value for an option. | ||||
|  * | ||||
| @@ -4675,27 +4692,32 @@ char_u *get_highlight_default(void) | ||||
| /* | ||||
|  * Translate a string like "t_xx", "<t_xx>" or "<S-Tab>" to a key number. | ||||
|  */ | ||||
| static int find_key_option(char_u *arg) | ||||
| int find_key_option_len(const char_u *arg, size_t len) | ||||
| { | ||||
|   int key; | ||||
|   int modifiers; | ||||
|  | ||||
|   /* | ||||
|    * Don't use get_special_key_code() for t_xx, we don't want it to call | ||||
|    * add_termcap_entry(). | ||||
|    */ | ||||
|   if (arg[0] == 't' && arg[1] == '_' && arg[2] && arg[3]) | ||||
|   // Don't use get_special_key_code() for t_xx, we don't want it to call | ||||
|   // add_termcap_entry(). | ||||
|   if (len >= 4 && arg[0] == 't' && arg[1] == '_') { | ||||
|     key = TERMCAP2KEY(arg[2], arg[3]); | ||||
|   else { | ||||
|     --arg;                          /* put arg at the '<' */ | ||||
|   } else { | ||||
|     arg--;  // put arg at the '<' | ||||
|     modifiers = 0; | ||||
|     key = find_special_key(&arg, &modifiers, TRUE, TRUE); | ||||
|     if (modifiers)                  /* can't handle modifiers here */ | ||||
|     key = find_special_key(&arg, len + 1, &modifiers, true, true); | ||||
|     if (modifiers) {  // can't handle modifiers here | ||||
|       key = 0; | ||||
|     } | ||||
|   } | ||||
|   return key; | ||||
| } | ||||
|  | ||||
| static int find_key_option(const char_u *arg) | ||||
| { | ||||
|   return find_key_option_len(arg, STRLEN(arg)); | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * if 'all' == 0: show changed options | ||||
|  * if 'all' == 1: show all normal options | ||||
|   | ||||
| @@ -175,8 +175,9 @@ size_t input_enqueue(String keys) | ||||
|   char *ptr = keys.data, *end = ptr + keys.size; | ||||
|  | ||||
|   while (rbuffer_space(input_buffer) >= 6 && ptr < end) { | ||||
|     uint8_t buf[6] = {0}; | ||||
|     unsigned int new_size = trans_special((uint8_t **)&ptr, buf, true); | ||||
|     uint8_t buf[6] = { 0 }; | ||||
|     unsigned int new_size = trans_special((const uint8_t **)&ptr, keys.size, | ||||
|                                           buf, true); | ||||
|  | ||||
|     if (new_size) { | ||||
|       new_size = handle_mouse_event(&ptr, buf, new_size); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Justin M. Keyes
					Justin M. Keyes