Patch 9.0.1308
Problem:    The code for setting options is too complicated.
Solution:   Refactor the code for setting options. (Yegappan Lakshmanan,
            closes #11989)
Files:      src/option.c


*** ../vim-9.0.1307/src/option.c        2023-02-13 16:10:00.375551633 +0000
--- src/option.c        2023-02-14 13:06:30.795414084 +0000
***************
*** 186,216 ****
      long_u    n;
  
      opt_idx = findoption((char_u *)"maxmemtot");
!     if (opt_idx >= 0)
!     {
  #if !defined(HAVE_AVAIL_MEM) && !defined(HAVE_TOTAL_MEM)
!       if (options[opt_idx].def_val[VI_DEFAULT] == (char_u *)0L)
  #endif
!       {
  #if defined(HAVE_AVAIL_MEM)
!           // Use amount of memory available at this moment.
!           n = (mch_avail_mem(FALSE) >> 1);
  #elif defined(HAVE_TOTAL_MEM)
!           // Use amount of memory available to Vim.
!           n = (mch_total_mem(FALSE) >> 1);
  #else
!           n = (0x7fffffff >> 11);
  #endif
!           options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
!           opt_idx = findoption((char_u *)"maxmem");
!           if (opt_idx >= 0)
!           {
  #if !defined(HAVE_AVAIL_MEM) && !defined(HAVE_TOTAL_MEM)
!               if ((long)(long_i)options[opt_idx].def_val[VI_DEFAULT] > (long)n
!                 || (long)(long_i)options[opt_idx].def_val[VI_DEFAULT] == 0L)
  #endif
!                   options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
!           }
        }
      }
  }
--- 186,216 ----
      long_u    n;
  
      opt_idx = findoption((char_u *)"maxmemtot");
!     if (opt_idx < 0)
!       return;
! 
  #if !defined(HAVE_AVAIL_MEM) && !defined(HAVE_TOTAL_MEM)
!     if (options[opt_idx].def_val[VI_DEFAULT] == (char_u *)0L)
  #endif
!     {
  #if defined(HAVE_AVAIL_MEM)
!       // Use amount of memory available at this moment.
!       n = (mch_avail_mem(FALSE) >> 1);
  #elif defined(HAVE_TOTAL_MEM)
!       // Use amount of memory available to Vim.
!       n = (mch_total_mem(FALSE) >> 1);
  #else
!       n = (0x7fffffff >> 11);
  #endif
!       options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
!       opt_idx = findoption((char_u *)"maxmem");
!       if (opt_idx >= 0)
!       {
  #if !defined(HAVE_AVAIL_MEM) && !defined(HAVE_TOTAL_MEM)
!           if ((long)(long_i)options[opt_idx].def_val[VI_DEFAULT] > (long)n
!                   || (long)(long_i)options[opt_idx].def_val[VI_DEFAULT] == 0L)
  #endif
!               options[opt_idx].def_val[VI_DEFAULT] = (char_u *)n;
        }
      }
  }
***************
*** 316,327 ****
      char_u    *p;
  
      p = get_isolated_shell_name();
!     if (p != NULL)
!     {
!       if (fnamecmp(p, "nologin") == 0 || fnamecmp(p, "false") == 0)
!           restricted = TRUE;
!       vim_free(p);
!     }
  }
  #endif
  
--- 316,326 ----
      char_u    *p;
  
      p = get_isolated_shell_name();
!     if (p == NULL)
!       return;
!     if (fnamecmp(p, "nologin") == 0 || fnamecmp(p, "false") == 0)
!       restricted = TRUE;
!     vim_free(p);
  }
  #endif
  
***************
*** 342,352 ****
        p_rtp = (char_u *)CLEAN_RUNTIMEPATH;
      }
      opt_idx = findoption((char_u *)"packpath");
!     if (opt_idx >= 0)
!     {
!       options[opt_idx].def_val[VI_DEFAULT] = (char_u *)CLEAN_RUNTIMEPATH;
!       p_pp = (char_u *)CLEAN_RUNTIMEPATH;
!     }
  }
  #endif
  
--- 341,350 ----
        p_rtp = (char_u *)CLEAN_RUNTIMEPATH;
      }
      opt_idx = findoption((char_u *)"packpath");
!     if (opt_idx < 0)
!       return;
!     options[opt_idx].def_val[VI_DEFAULT] = (char_u *)CLEAN_RUNTIMEPATH;
!     p_pp = (char_u *)CLEAN_RUNTIMEPATH;
  }
  #endif
  
***************
*** 532,538 ****
        vim_free(p_enc);
        p_enc = save_enc;
      }
- 
  }
  
  /*
--- 530,535 ----
***************
*** 1493,1748 ****
  }
  
  /*
!  * Part of do_set() for string options.
!  * Returns FAIL on failure, do not process further options.
   */
!     static int
! do_set_string(
!       int         opt_idx,
!       int         opt_flags,
!       char_u      **argp,
!       int         nextchar,
!       set_op_T    op_arg,
!       int         flags,
!       int         cp_val,
!       char_u      *varp_arg,
!       char        *errbuf,
!       int         *value_checked,
!       char        **errmsg)
  {
-     char_u    *arg = *argp;
-     set_op_T    op = op_arg;
-     char_u    *varp = varp_arg;
-     char_u    *save_arg = NULL;
-     char_u    *s = NULL;
-     char_u    *oldval = NULL; // previous value if *varp
      char_u    *newval;
!     char_u    *origval = NULL;
!     char_u    *origval_l = NULL;
!     char_u    *origval_g = NULL;
! #if defined(FEAT_EVAL)
!     char_u    *saved_origval = NULL;
!     char_u    *saved_origval_l = NULL;
!     char_u    *saved_origval_g = NULL;
!     char_u    *saved_newval = NULL;
  #endif
!     unsigned  newlen;
!     int               comma;
!     char_u    whichwrap[80];
  
!     // When using ":set opt=val" for a global option
!     // with a local value the local value will be
!     // reset, use the global value here.
!     if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
!           && ((int)options[opt_idx].indir & PV_BOTH))
!       varp = options[opt_idx].var;
  
!     // The old value is kept until we are sure that the new value is valid.
!     oldval = *(char_u **)varp;
  
!     if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
      {
!       origval_l = *(char_u **)get_varp_scope(
!                          &(options[opt_idx]), OPT_LOCAL);
!       origval_g = *(char_u **)get_varp_scope(
!                         &(options[opt_idx]), OPT_GLOBAL);
  
!       // A global-local string option might have an empty option as value to
!       // indicate that the global value should be used.
!       if (((int)options[opt_idx].indir & PV_BOTH)
!                                                 && origval_l == empty_option)
!           origval_l = origval_g;
      }
  
!     // When setting the local value of a global option, the old value may be
!     // the global value.
!     if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL))
!       origval = *(char_u **)get_varp(&options[opt_idx]);
      else
!       origval = oldval;
  
!     if (nextchar == '&')      // set to default val
      {
!       newval = options[opt_idx].def_val[((flags & P_VI_DEF) || cp_val)
!                                                  ? VI_DEFAULT : VIM_DEFAULT];
!       if ((char_u **)varp == &p_bg)
        {
!           // guess the value of 'background'
! #ifdef FEAT_GUI
!           if (gui.in_use)
!               newval = gui_bg_default();
            else
! #endif
!               newval = term_bg_default();
        }
!       else if ((char_u **)varp == &p_fencs && enc_utf8)
!           newval = fencs_utf8_default;
  
!       // expand environment variables and ~ since the default value was
!       // already expanded, only required when an environment variable was set
!       // later
!       if (newval == NULL)
!           newval = empty_option;
        else
        {
!           s = option_expand(opt_idx, newval);
!           if (s == NULL)
!               s = newval;
!           newval = vim_strsave(s);
        }
      }
      else if (nextchar == '<') // set to global val
-     {
        newval = vim_strsave(*(char_u **)get_varp_scope(
                                             &(options[opt_idx]), OPT_GLOBAL));
-     }
      else
      {
        ++arg;  // jump to after the '=' or ':'
  
!       /*
!        * Set 'keywordprg' to ":help" if an empty
!        * value was passed to :set by the user.
!        */
        if (varp == (char_u *)&p_kp && (*arg == NUL || *arg == ' '))
        {
            save_arg = arg;
            arg = (char_u *)":help";
        }
!       /*
!        * Convert 'backspace' number to string, for
!        * adding, prepending and removing string.
!        */
        else if (varp == (char_u *)&p_bs && VIM_ISDIGIT(**(char_u **)varp))
!       {
!           int i = getdigits((char_u **)varp);
! 
!           switch (i)
!           {
!               case 0:
!                   *(char_u **)varp = empty_option;
!                   break;
!               case 1:
!                   *(char_u **)varp = vim_strsave((char_u *)"indent,eol");
!                   break;
!               case 2:
!                   *(char_u **)varp = vim_strsave(
!                                                (char_u *)"indent,eol,start");
!                   break;
!               case 3:
!                   *(char_u **)varp = vim_strsave(
!                                               (char_u *)"indent,eol,nostop");
!                   break;
!           }
!           vim_free(oldval);
!           if (origval == oldval)
!               origval = *(char_u **)varp;
!           if (origval_l == oldval)
!               origval_l = *(char_u **)varp;
!           if (origval_g == oldval)
!               origval_g = *(char_u **)varp;
!           oldval = *(char_u **)varp;
!       }
!       /*
!        * Convert 'whichwrap' number to string, for backwards compatibility
!        * with Vim 3.0.
!        */
        else if (varp == (char_u *)&p_ww && VIM_ISDIGIT(*arg))
        {
!           *whichwrap = NUL;
!           int i = getdigits(&arg);
!           if (i & 1)
!               STRCAT(whichwrap, "b,");
!           if (i & 2)
!               STRCAT(whichwrap, "s,");
!           if (i & 4)
!               STRCAT(whichwrap, "h,l,");
!           if (i & 8)
!               STRCAT(whichwrap, "<,>,");
!           if (i & 16)
!               STRCAT(whichwrap, "[,],");
!           if (*whichwrap != NUL)      // remove trailing ,
!               whichwrap[STRLEN(whichwrap) - 1] = NUL;
            save_arg = arg;
!           arg = (char_u *)whichwrap;
        }
!       /*
!        * Remove '>' before 'dir' and 'bdir', for backwards compatibility with
!        * version 3.0
!        */
        else if (*arg == '>' && (varp == (char_u *)&p_dir
!                                                || varp == (char_u *)&p_bdir))
            ++arg;
  
!       /*
!        * Copy the new string into allocated memory.
!        * Can't use set_string_option_direct(), because we need to remove the
!        * backslashes.
!        */
!       // get a bit too much
!       newlen = (unsigned)STRLEN(arg) + 1;
!       if (op != OP_NONE)
!           newlen += (unsigned)STRLEN(origval) + 1;
!       newval = alloc(newlen);
!       if (newval == NULL)  // out of mem, don't change
!           return FAIL;
!       s = newval;
! 
!       /*
!        * Copy the string, skip over escaped chars.
!        * For MS-DOS and WIN32 backslashes before normal file name characters
!        * are not removed, and keep backslash at start, for "\\machine\path",
!        * but do remove it for "\\\\machine\\path".
!        * The reverse is found in ExpandOldSetting().
!        */
!       while (*arg != NUL && !VIM_ISWHITE(*arg))
!       {
!           int i;
! 
!           if (*arg == '\\' && arg[1] != NUL
! #ifdef BACKSLASH_IN_FILENAME
!                   && !((flags & P_EXPAND)
!                           && vim_isfilec(arg[1])
!                           && !VIM_ISWHITE(arg[1])
!                           && (arg[1] != '\\'
!                                          || (s == newval && arg[2] != '\\')))
! #endif
!                                               )
!               ++arg;  // remove backslash
!           if (has_mbyte && (i = (*mb_ptr2len)(arg)) > 1)
!           {
!               // copy multibyte char
!               mch_memmove(s, arg, (size_t)i);
!               arg += i;
!               s += i;
!           }
!           else
!               *s++ = *arg++;
!       }
!       *s = NUL;
  
!       /*
!        * Expand environment variables and ~.
!        * Don't do it when adding without inserting a comma.
!        */
        if (op == OP_NONE || (flags & P_COMMA))
        {
!           s = option_expand(opt_idx, newval);
!           if (s != NULL)
!           {
!               vim_free(newval);
!               newlen = (unsigned)STRLEN(s) + 1;
!               if (op != OP_NONE)
!                   newlen += (unsigned)STRLEN(origval) + 1;
!               newval = alloc(newlen);
!               if (newval == NULL)
!                   return FAIL;
!               STRCPY(newval, s);
!           }
        }
  
!       // locate newval[] in origval[] when removing it
!       // and when adding to avoid duplicates
        int len = 0;
        if (op == OP_REMOVING || (flags & P_NODUP))
        {
--- 1490,1880 ----
  }
  
  /*
!  * Get the Vim/Vi default value for a string option.
   */
!     static char_u *
! stropt_get_default_val(
!     int               opt_idx,
!     char_u    *varp,
!     int               flags,
!     int               cp_val)
  {
      char_u    *newval;
! 
!     newval = options[opt_idx].def_val[((flags & P_VI_DEF) || cp_val)
!       ? VI_DEFAULT : VIM_DEFAULT];
!     if ((char_u **)varp == &p_bg)
!     {
!       // guess the value of 'background'
! #ifdef FEAT_GUI
!       if (gui.in_use)
!           newval = gui_bg_default();
!       else
  #endif
!           newval = term_bg_default();
!     }
!     else if ((char_u **)varp == &p_fencs && enc_utf8)
!       newval = fencs_utf8_default;
  
!     // expand environment variables and ~ since the default value was
!     // already expanded, only required when an environment variable was set
!     // later
!     if (newval == NULL)
!       newval = empty_option;
!     else
!     {
!       char_u *s = option_expand(opt_idx, newval);
!       if (s == NULL)
!           s = newval;
!       newval = vim_strsave(s);
!     }
  
!     return newval;
! }
  
! /*
!  * Convert the 'backspace' option number value to a string: for adding,
!  * prepending and removing string.
!  */
!     static void
! opt_backspace_nr2str(
!     char_u    *varp,
!     char_u    **origval_p,
!     char_u    **origval_l_p,
!     char_u    **origval_g_p,
!     char_u    **oldval_p)
! {
!     int               i = getdigits((char_u **)varp);
! 
!     switch (i)
!     {
!       case 0:
!           *(char_u **)varp = empty_option;
!           break;
!       case 1:
!           *(char_u **)varp = vim_strsave((char_u *)"indent,eol");
!           break;
!       case 2:
!           *(char_u **)varp = vim_strsave((char_u *)"indent,eol,start");
!           break;
!       case 3:
!           *(char_u **)varp = vim_strsave((char_u *)"indent,eol,nostop");
!           break;
!     }
!     vim_free(*oldval_p);
!     if (*origval_p == *oldval_p)
!       *origval_p = *(char_u **)varp;
!     if (*origval_l_p == *oldval_p)
!       *origval_l_p = *(char_u **)varp;
!     if (*origval_g_p == *oldval_p)
!       *origval_g_p = *(char_u **)varp;
!     *oldval_p = *(char_u **)varp;
! }
! 
! /*
!  * Convert the 'whichwrap' option number value to a string, for backwards
!  * compatibility with Vim 3.0.
!  * Note: 'argp' is a pointer to a char_u pointer and is updated.
!  */
!     static char_u *
! opt_whichwrap_nr2str(char_u **argp, char_u *whichwrap)
! {
!     *whichwrap = NUL;
!     int i = getdigits(argp);
!     if (i & 1)
!       STRCAT(whichwrap, "b,");
!     if (i & 2)
!       STRCAT(whichwrap, "s,");
!     if (i & 4)
!       STRCAT(whichwrap, "h,l,");
!     if (i & 8)
!       STRCAT(whichwrap, "<,>,");
!     if (i & 16)
!       STRCAT(whichwrap, "[,],");
!     if (*whichwrap != NUL)    // remove trailing ,
!       whichwrap[STRLEN(whichwrap) - 1] = NUL;
! 
!     return whichwrap;
! }
! 
! /*
!  * Copy the new string value into allocated memory for the option.
!  * Can't use set_string_option_direct(), because we need to remove the
!  * backslashes.
!  */
!     static char_u *
! stropt_copy_value(
!     char_u    *origval,
!     char_u    **argp,
!     set_op_T  op,
!     int               flags UNUSED)
! {
!     char_u    *arg = *argp;
!     unsigned  newlen;
!     char_u    *newval;
!     char_u    *s = NULL;
! 
!     // get a bit too much
!     newlen = (unsigned)STRLEN(arg) + 1;
!     if (op != OP_NONE)
!       newlen += (unsigned)STRLEN(origval) + 1;
!     newval = alloc(newlen);
!     if (newval == NULL)  // out of mem, don't change
!       return NULL;
!     s = newval;
! 
!     // Copy the string, skip over escaped chars.
!     // For MS-DOS and WIN32 backslashes before normal file name characters
!     // are not removed, and keep backslash at start, for "\\machine\path",
!     // but do remove it for "\\\\machine\\path".
!     // The reverse is found in ExpandOldSetting().
!     while (*arg != NUL && !VIM_ISWHITE(*arg))
      {
!       int i;
  
!       if (*arg == '\\' && arg[1] != NUL
! #ifdef BACKSLASH_IN_FILENAME
!               && !((flags & P_EXPAND)
!                   && vim_isfilec(arg[1])
!                   && !VIM_ISWHITE(arg[1])
!                   && (arg[1] != '\\'
!                       || (s == newval && arg[2] != '\\')))
! #endif
!          )
!           ++arg;      // remove backslash
!       if (has_mbyte && (i = (*mb_ptr2len)(arg)) > 1)
!       {
!           // copy multibyte char
!           mch_memmove(s, arg, (size_t)i);
!           arg += i;
!           s += i;
!       }
!       else
!           *s++ = *arg++;
      }
+     *s = NUL;
  
!     *argp = arg;
!     return newval;
! }
! 
! /*
!  * Expand environment variables and ~ in string option value 'newval'.
!  */
!     static char_u *
! stropt_expand_envvar(
!     int               opt_idx,
!     char_u    *origval,
!     char_u    *newval,
!     set_op_T  op)
! {
!     char_u *s = option_expand(opt_idx, newval);
!     if (s == NULL)
!       return newval;
! 
!     vim_free(newval);
!     unsigned newlen = (unsigned)STRLEN(s) + 1;
!     if (op != OP_NONE)
!       newlen += (unsigned)STRLEN(origval) + 1;
! 
!     newval = alloc(newlen);
!     if (newval == NULL)
!       return NULL;
! 
!     STRCPY(newval, s);
! 
!     return newval;
! }
! 
! /*
!  * Concatenate the original and new values of a string option, adding a "," if
!  * needed.
!  */
!     static void
! stropt_concat_with_comma(
!     char_u    *origval,
!     char_u    *newval,
!     set_op_T  op,
!     int               flags)
! {
!     int               len = 0;
! 
!     int comma = ((flags & P_COMMA) && *origval != NUL && *newval != NUL);
!     if (op == OP_ADDING)
!     {
!       len = (int)STRLEN(origval);
!       // strip a trailing comma, would get 2
!       if (comma && len > 1
!               && (flags & P_ONECOMMA) == P_ONECOMMA
!               && origval[len - 1] == ','
!               && origval[len - 2] != '\\')
!           len--;
!       mch_memmove(newval + len + comma, newval, STRLEN(newval) + 1);
!       mch_memmove(newval, origval, (size_t)len);
!     }
      else
!     {
!       len = (int)STRLEN(newval);
!       STRMOVE(newval + len + comma, origval);
!     }
!     if (comma)
!       newval[len] = ',';
! }
  
! /*
!  * Remove a value from a string option.  Copy string option value in "origval"
!  * to "newval" and then remove the string "strval" of length "len".
!  */
!     static void
! stropt_remove_val(
!     char_u    *origval,
!     char_u    *newval,
!     int               flags,
!     char_u    *strval,
!     int               len)
! {
!     // Remove newval[] from origval[]. (Note: "len" has been set above
!     // and is used here).
!     STRCPY(newval, origval);
!     if (*strval)
      {
!       // may need to remove a comma
!       if (flags & P_COMMA)
        {
!           if (strval == origval)
!           {
!               // include comma after string
!               if (strval[len] == ',')
!                   ++len;
!           }
            else
!           {
!               // include comma before string
!               --strval;
!               ++len;
!           }
        }
!       STRMOVE(newval + (strval - origval), strval + len);
!     }
! }
  
! /*
!  * Remove flags that appear twice in the string option value 'newval'.
!  */
!     static void
! stropt_remove_dupflags(char_u *newval, int flags)
! {
!     char_u    *s = newval;
! 
!     // Remove flags that appear twice.
!     while (*s)
!     {
!       // if options have P_FLAGLIST and P_ONECOMMA such as 'whichwrap'
!       if (flags & P_ONECOMMA)
!       {
!           if (*s != ',' && *(s + 1) == ',' && vim_strchr(s + 2, *s) != NULL)
!           {
!               // Remove the duplicated value and the next comma.
!               STRMOVE(s, s + 2);
!               continue;
!           }
!       }
        else
        {
!           if ((!(flags & P_COMMA) || *s != ',')
!                   && vim_strchr(s + 1, *s) != NULL)
!           {
!               STRMOVE(s, s + 1);
!               continue;
!           }
        }
+       ++s;
      }
+ }
+ 
+ /*
+  * Get the string value specified for a ":set" command.  The following set
+  * options are supported:
+  *    set {opt}&
+  *    set {opt}<
+  *    set {opt}={val}
+  *    set {opt}:{val}
+  */
+     static char_u *
+ stropt_get_newval(
+     int               nextchar,
+     int               opt_idx,
+     char_u    **argp,
+     char_u    *varp,
+     char_u    **origval_arg,
+     char_u    **origval_l_arg,
+     char_u    **origval_g_arg,
+     char_u    **oldval_arg,
+     set_op_T    *op_arg,
+     int               flags,
+     int               cp_val)
+ {
+     char_u    *arg = *argp;
+     char_u    *origval = *origval_arg;
+     char_u    *origval_l = *origval_l_arg;
+     char_u    *origval_g = *origval_g_arg;
+     char_u    *oldval = *oldval_arg;
+     set_op_T    op = *op_arg;
+     char_u    *save_arg = NULL;
+     char_u    *newval;
+     char_u    *s = NULL;
+     char_u    whichwrap[80];
+ 
+     if (nextchar == '&')      // set to default val
+       newval = stropt_get_default_val(opt_idx, varp, flags, cp_val);
      else if (nextchar == '<') // set to global val
        newval = vim_strsave(*(char_u **)get_varp_scope(
                                             &(options[opt_idx]), OPT_GLOBAL));
      else
      {
        ++arg;  // jump to after the '=' or ':'
  
!       // Set 'keywordprg' to ":help" if an empty
!       // value was passed to :set by the user.
        if (varp == (char_u *)&p_kp && (*arg == NUL || *arg == ' '))
        {
            save_arg = arg;
            arg = (char_u *)":help";
        }
!       // Convert 'backspace' number to string
        else if (varp == (char_u *)&p_bs && VIM_ISDIGIT(**(char_u **)varp))
!           opt_backspace_nr2str(varp, &origval, &origval_l, &origval_g,
!                                                               &oldval);
        else if (varp == (char_u *)&p_ww && VIM_ISDIGIT(*arg))
        {
!           // Convert 'whichwrap' number to string, for backwards
!           // compatibility with Vim 3.0.
!           char_u *t = opt_whichwrap_nr2str(&arg, whichwrap);
            save_arg = arg;
!           arg = t;
        }
!       // Remove '>' before 'dir' and 'bdir', for backwards compatibility with
!       // version 3.0
        else if (*arg == '>' && (varp == (char_u *)&p_dir
!                   || varp == (char_u *)&p_bdir))
            ++arg;
  
!       // Copy the new string into allocated memory.
!       newval = stropt_copy_value(origval, &arg, op, flags);
!       if (newval == NULL)
!           goto done;
  
!       // Expand environment variables and ~.
!       // Don't do it when adding without inserting a comma.
        if (op == OP_NONE || (flags & P_COMMA))
        {
!           newval = stropt_expand_envvar(opt_idx, origval, newval, op);
!           if (newval == NULL)
!               goto done;
        }
  
!       // locate newval[] in origval[] when removing it and when adding to
!       // avoid duplicates
        int len = 0;
        if (op == OP_REMOVING || (flags & P_NODUP))
        {
***************
*** 1763,1855 ****
  
        // concatenate the two strings; add a ',' if needed
        if (op == OP_ADDING || op == OP_PREPENDING)
!       {
!           comma = ((flags & P_COMMA) && *origval != NUL && *newval != NUL);
!           if (op == OP_ADDING)
!           {
!               len = (int)STRLEN(origval);
!               // strip a trailing comma, would get 2
!               if (comma && len > 1
!                         && (flags & P_ONECOMMA) == P_ONECOMMA
!                         && origval[len - 1] == ','
!                         && origval[len - 2] != '\\')
!                   len--;
!               mch_memmove(newval + len + comma, newval, STRLEN(newval) + 1);
!               mch_memmove(newval, origval, (size_t)len);
!           }
!           else
!           {
!               len = (int)STRLEN(newval);
!               STRMOVE(newval + len + comma, origval);
!           }
!           if (comma)
!               newval[len] = ',';
!       }
! 
!       // Remove newval[] from origval[]. (Note: "len" has been set above and
!       // is used here).
!       if (op == OP_REMOVING)
!       {
!           STRCPY(newval, origval);
!           if (*s)
!           {
!               // may need to remove a comma
!               if (flags & P_COMMA)
!               {
!                   if (s == origval)
!                   {
!                       // include comma after string
!                       if (s[len] == ',')
!                           ++len;
!                   }
!                   else
!                   {
!                       // include comma before string
!                       --s;
!                       ++len;
!                   }
!               }
!               STRMOVE(newval + (s - origval), s + len);
!           }
!       }
  
        if (flags & P_FLAGLIST)
-       {
            // Remove flags that appear twice.
!           for (s = newval; *s;)
!           {
!               // if options have P_FLAGLIST and P_ONECOMMA such as
!               // 'whichwrap'
!               if (flags & P_ONECOMMA)
!               {
!                   if (*s != ',' && *(s + 1) == ','
!                                             && vim_strchr(s + 2, *s) != NULL)
!                   {
!                       // Remove the duplicated value and the next comma.
!                       STRMOVE(s, s + 2);
!                       continue;
!                   }
!               }
!               else
!               {
!                   if ((!(flags & P_COMMA) || *s != ',')
!                                             && vim_strchr(s + 1, *s) != NULL)
!                   {
!                       STRMOVE(s, s + 1);
!                       continue;
!                   }
!               }
!               ++s;
!           }
!       }
  
!       if (save_arg != NULL)
!           arg = save_arg;  // arg was temporarily changed, restore it
      }
  
!     /*
!      * Set the new value.
!      */
      *(char_u **)(varp) = newval;
  
  #if defined(FEAT_EVAL)
--- 1895,1994 ----
  
        // concatenate the two strings; add a ',' if needed
        if (op == OP_ADDING || op == OP_PREPENDING)
!           stropt_concat_with_comma(origval, newval, op, flags);
!       else if (op == OP_REMOVING)
!           // Remove newval[] from origval[]. (Note: "len" has been set above
!           // and is used here).
!           stropt_remove_val(origval, newval, flags, s, len);
  
        if (flags & P_FLAGLIST)
            // Remove flags that appear twice.
!           stropt_remove_dupflags(newval, flags);
!     }
! 
! done:
!     if (save_arg != NULL)
!       arg = save_arg;  // arg was temporarily changed, restore it
!     *argp = arg;
!     *origval_arg = origval;
!     *origval_l_arg = origval_l;
!     *origval_g_arg = origval_g;
!     *oldval_arg = oldval;
!     *op_arg = op;
  
!     return newval;
! }
! 
! /*
!  * Part of do_set() for string options.
!  * Returns FAIL on failure, do not process further options.
!  */
!     static int
! do_set_option_string(
!       int         opt_idx,
!       int         opt_flags,
!       char_u      **argp,
!       int         nextchar,
!       set_op_T    op_arg,
!       int         flags,
!       int         cp_val,
!       char_u      *varp_arg,
!       char        *errbuf,
!       int         *value_checked,
!       char        **errmsg)
! {
!     char_u    *arg = *argp;
!     set_op_T    op = op_arg;
!     char_u    *varp = varp_arg;
!     char_u    *oldval = NULL; // previous value if *varp
!     char_u    *newval;
!     char_u    *origval = NULL;
!     char_u    *origval_l = NULL;
!     char_u    *origval_g = NULL;
! #if defined(FEAT_EVAL)
!     char_u    *saved_origval = NULL;
!     char_u    *saved_origval_l = NULL;
!     char_u    *saved_origval_g = NULL;
!     char_u    *saved_newval = NULL;
! #endif
! 
!     // When using ":set opt=val" for a global option
!     // with a local value the local value will be
!     // reset, use the global value here.
!     if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0
!           && ((int)options[opt_idx].indir & PV_BOTH))
!       varp = options[opt_idx].var;
! 
!     // The old value is kept until we are sure that the new value is valid.
!     oldval = *(char_u **)varp;
! 
!     if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
!     {
!       origval_l = *(char_u **)get_varp_scope(
!                          &(options[opt_idx]), OPT_LOCAL);
!       origval_g = *(char_u **)get_varp_scope(
!                         &(options[opt_idx]), OPT_GLOBAL);
! 
!       // A global-local string option might have an empty option as value to
!       // indicate that the global value should be used.
!       if (((int)options[opt_idx].indir & PV_BOTH)
!                                                 && origval_l == empty_option)
!           origval_l = origval_g;
      }
  
!     // When setting the local value of a global option, the old value may be
!     // the global value.
!     if (((int)options[opt_idx].indir & PV_BOTH) && (opt_flags & OPT_LOCAL))
!       origval = *(char_u **)get_varp(&options[opt_idx]);
!     else
!       origval = oldval;
! 
!     // Get the new value for the option
!     newval = stropt_get_newval(nextchar, opt_idx, &arg, varp, &origval,
!                               &origval_l, &origval_g, &oldval, &op, flags,
!                               cp_val);
! 
!     // Set the new value.
      *(char_u **)(varp) = newval;
  
  #if defined(FEAT_EVAL)
***************
*** 2147,2155 ****
        else if (opt_idx >= 0)
        {
            // string option
!           if (do_set_string(opt_idx, opt_flags, &arg, nextchar, op, flags,
!                                   cp_val, varp, errbuf, &value_checked,
!                                   &errmsg) == FAIL)
            {
                if (errmsg != NULL)
                    goto skip;
--- 2286,2294 ----
        else if (opt_idx >= 0)
        {
            // string option
!           if (do_set_option_string(opt_idx, opt_flags, &arg, nextchar, op,
!                                       flags, cp_val, varp, errbuf,
!                                       &value_checked, &errmsg) == FAIL)
            {
                if (errmsg != NULL)
                    goto skip;
***************
*** 3033,3067 ****
      static void
  did_set_undofile(int opt_flags)
  {
!     // Only take action when the option was set. When reset we do not
!     // delete the undo file, the option may be set again without making
!     // any changes in between.
!     if (curbuf->b_p_udf || p_udf)
!     {
!       char_u  hash[UNDO_HASH_SIZE];
!       buf_T   *save_curbuf = curbuf;
! 
!       FOR_ALL_BUFFERS(curbuf)
!       {
!           // When 'undofile' is set globally: for every buffer, otherwise
!           // only for the current buffer: Try to read in the undofile,
!           // if one exists, the buffer wasn't changed and the buffer was
!           // loaded
!           if ((curbuf == save_curbuf
!                       || (opt_flags & OPT_GLOBAL) || opt_flags == 0)
!                   && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
!           {
  #ifdef FEAT_CRYPT
!               if (crypt_get_method_nr(curbuf) == CRYPT_M_SOD)
!                   continue;
  #endif
!               u_compute_hash(hash);
!               u_read_undo(NULL, hash, curbuf->b_fname);
!           }
        }
-       curbuf = save_curbuf;
      }
! 
  }
  #endif
  
--- 3172,3205 ----
      static void
  did_set_undofile(int opt_flags)
  {
!     // Only take action when the option was set.
!     if (!curbuf->b_p_udf && !p_udf)
!       return;
! 
!     // When reset we do not delete the undo file, the option may be set again
!     // without making any changes in between.
!     char_u    hash[UNDO_HASH_SIZE];
!     buf_T     *save_curbuf = curbuf;
! 
!     FOR_ALL_BUFFERS(curbuf)
!     {
!       // When 'undofile' is set globally: for every buffer, otherwise
!       // only for the current buffer: Try to read in the undofile,
!       // if one exists, the buffer wasn't changed and the buffer was
!       // loaded
!       if ((curbuf == save_curbuf
!                   || (opt_flags & OPT_GLOBAL) || opt_flags == 0)
!               && !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
!       {
  #ifdef FEAT_CRYPT
!           if (crypt_get_method_nr(curbuf) == CRYPT_M_SOD)
!               continue;
  #endif
!           u_compute_hash(hash);
!           u_read_undo(NULL, hash, curbuf->b_fname);
        }
      }
!     curbuf = save_curbuf;
  }
  #endif
  
***************
*** 3254,3264 ****
  {
      // when 'scrollbind' is set: snapshot the current position to avoid a jump
      // at the end of normal_cmd()
!     if (curwin->w_p_scb)
!     {
!       do_check_scrollbind(FALSE);
!       curwin->w_scbind_pos = curwin->w_topline;
!     }
  }
  
  #ifdef FEAT_QUICKFIX
--- 3392,3401 ----
  {
      // when 'scrollbind' is set: snapshot the current position to avoid a jump
      // at the end of normal_cmd()
!     if (!curwin->w_p_scb)
!       return;
!     do_check_scrollbind(FALSE);
!     curwin->w_scbind_pos = curwin->w_topline;
  }
  
  #ifdef FEAT_QUICKFIX
***************
*** 3292,3302 ****
      static void
  did_set_smoothscroll(void)
  {
!     if (!curwin->w_p_sms)
!     {
!       curwin->w_skipcol = 0;
!       changed_line_abv_curs();
!     }
  }
  
  /*
--- 3429,3438 ----
      static void
  did_set_smoothscroll(void)
  {
!     if (curwin->w_p_sms)
!       return;
!     curwin->w_skipcol = 0;
!     changed_line_abv_curs();
  }
  
  /*
***************
*** 3425,3438 ****
      static void
  did_set_ballooneval(long old_value)
  {
!     if (!balloonEvalForTerm)
!     {
!       if (p_beval && !old_value)
!           gui_mch_enable_beval_area(balloonEval);
!       else if (!p_beval && old_value)
!           gui_mch_disable_beval_area(balloonEval);
!     }
! 
  }
  #endif
  
--- 3561,3572 ----
      static void
  did_set_ballooneval(long old_value)
  {
!     if (balloonEvalForTerm)
!       return;
!     if (p_beval && !old_value)
!       gui_mch_enable_beval_area(balloonEval);
!     else if (!p_beval && old_value)
!       gui_mch_disable_beval_area(balloonEval);
  }
  #endif
  
*** ../vim-9.0.1307/src/version.c       2023-02-13 16:10:00.375551633 +0000
--- src/version.c       2023-02-14 13:03:52.859183536 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1308,
  /**/

-- 
Would you care for a drink?   I mean, if it were, like,
disabled and you had to look after it?

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230214130754.775571C0932%40moolenaar.net.

Raspunde prin e-mail lui