changeset 31922:440256d03990 v9.0.1293

patch 9.0.1293: the set_num_option() is too long Commit: https://github.com/vim/vim/commit/0caaf1e46511f7a92e036f05e6aa9d5992540117 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Thu Feb 9 12:23:17 2023 +0000 patch 9.0.1293: the set_num_option() is too long Problem: The set_num_option() is too long. Solution: Move code to separate functions. (Yegappan Lakshmanan, closes #11954)
author Bram Moolenaar <Bram@vim.org>
date Thu, 09 Feb 2023 13:30:04 +0100
parents f23a4fc4520e
children 29fab93b9d07
files src/option.c src/version.c
diffstat 2 files changed, 600 insertions(+), 375 deletions(-) [+]
line wrap: on
line diff
--- a/src/option.c
+++ b/src/option.c
@@ -540,7 +540,7 @@ static char_u *fencs_utf8_default = (cha
  * utf-8.
  */
     void
-set_fencs_unicode()
+set_fencs_unicode(void)
 {
     set_string_option_direct((char_u *)"fencs", -1, fencs_utf8_default,
 								  OPT_FREE, 0);
@@ -3479,410 +3479,556 @@ set_bool_option(
 }
 
 /*
- * Set the value of a number option, and take care of side effects.
- * Returns NULL for success, or an error message for an error.
+ * Process the new 'winheight' or the 'helpheight' option value.
  */
     static char *
-set_num_option(
-    int		opt_idx,		// index in options[] table
-    char_u	*varp,			// pointer to the option variable
-    long	value,			// new value
-    char	*errbuf,		// buffer for error messages
-    size_t	errbuflen,		// length of "errbuf"
-    int		opt_flags)		// OPT_LOCAL, OPT_GLOBAL,
-					// OPT_MODELINE, etc.
-{
-    char	*errmsg = NULL;
-    long	old_value = *(long *)varp;
-#if defined(FEAT_EVAL)
-    long	old_global_value = 0;	// only used when setting a local and
-					// global option
-#endif
-    long	old_Rows = Rows;	// remember old Rows
-    long	old_Columns = Columns;	// remember old Columns
-    long	*pp = (long *)varp;
-
-    // Disallow changing some options from secure mode.
-    if ((secure
-#ifdef HAVE_SANDBOX
-		|| sandbox != 0
-#endif
-		) && (options[opt_idx].flags & P_SECURE))
-	return e_not_allowed_here;
-
-#if defined(FEAT_EVAL)
-    // Save the global value before changing anything. This is needed as for
-    // a global-only option setting the "local value" in fact sets the global
-    // value (since there is only one value).
-    if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
-	old_global_value = *(long *)get_varp_scope(&(options[opt_idx]),
-								   OPT_GLOBAL);
-#endif
-
-    *pp = value;
-#ifdef FEAT_EVAL
-    // Remember where the option was set.
-    set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
-#endif
-#ifdef FEAT_GUI
-    need_mouse_correct = TRUE;
-#endif
-
-    if (curbuf->b_p_sw < 0)
+did_set_winheight_helpheight(long *pp, char *errmsg)
+{
+    if (p_wh < 1)
+    {
+	errmsg = e_argument_must_be_positive;
+	p_wh = 1;
+    }
+    if (p_wmh > p_wh)
+    {
+	errmsg = e_winheight_cannot_be_smaller_than_winminheight;
+	p_wh = p_wmh;
+    }
+    if (p_hh < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+	p_hh = 0;
+    }
+
+    // Change window height NOW
+    if (!ONE_WINDOW)
+    {
+	if (pp == &p_wh && curwin->w_height < p_wh)
+	    win_setheight((int)p_wh);
+	if (pp == &p_hh && curbuf->b_help && curwin->w_height < p_hh)
+	    win_setheight((int)p_hh);
+    }
+
+    return errmsg;
+}
+
+/*
+ * Process the new 'winminheight' option value.
+ */
+    static char *
+did_set_winminheight(char *errmsg)
+{
+    if (p_wmh < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+	p_wmh = 0;
+    }
+    if (p_wmh > p_wh)
+    {
+	errmsg = e_winheight_cannot_be_smaller_than_winminheight;
+	p_wmh = p_wh;
+    }
+    win_setminheight();
+
+    return errmsg;
+}
+
+/*
+ * Process the new 'winwidth' option value.
+ */
+    static char *
+did_set_winwidth(char *errmsg)
+{
+    if (p_wiw < 1)
     {
 	errmsg = e_argument_must_be_positive;
-#ifdef FEAT_VARTABS
-	// Use the first 'vartabstop' value, or 'tabstop' if vts isn't in use.
-	curbuf->b_p_sw = tabstop_count(curbuf->b_p_vts_array) > 0
-		       ? tabstop_first(curbuf->b_p_vts_array)
-		       : curbuf->b_p_ts;
-#else
-	curbuf->b_p_sw = curbuf->b_p_ts;
-#endif
-    }
-
-    /*
-     * Number options that need some action when changed
-     */
-    if (pp == &p_wh || pp == &p_hh)
-    {
-	// 'winheight' and 'helpheight'
-	if (p_wh < 1)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    p_wh = 1;
-	}
-	if (p_wmh > p_wh)
-	{
-	    errmsg = e_winheight_cannot_be_smaller_than_winminheight;
-	    p_wh = p_wmh;
-	}
-	if (p_hh < 0)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    p_hh = 0;
-	}
-
-	// Change window height NOW
-	if (!ONE_WINDOW)
-	{
-	    if (pp == &p_wh && curwin->w_height < p_wh)
-		win_setheight((int)p_wh);
-	    if (pp == &p_hh && curbuf->b_help && curwin->w_height < p_hh)
-		win_setheight((int)p_hh);
-	}
-    }
-    else if (pp == &p_wmh)
-    {
-	// 'winminheight'
-	if (p_wmh < 0)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    p_wmh = 0;
-	}
-	if (p_wmh > p_wh)
-	{
-	    errmsg = e_winheight_cannot_be_smaller_than_winminheight;
-	    p_wmh = p_wh;
-	}
-	win_setminheight();
-    }
-    else if (pp == &p_wiw)
-    {
-	// 'winwidth'
-	if (p_wiw < 1)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    p_wiw = 1;
-	}
-	if (p_wmw > p_wiw)
-	{
-	    errmsg = e_winwidth_cannot_be_smaller_than_winminwidth;
-	    p_wiw = p_wmw;
-	}
-
-	// Change window width NOW
-	if (!ONE_WINDOW && curwin->w_width < p_wiw)
-	    win_setwidth((int)p_wiw);
-    }
-    else if (pp == &p_wmw)
-    {
-	// 'winminwidth'
-	if (p_wmw < 0)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    p_wmw = 0;
-	}
-	if (p_wmw > p_wiw)
-	{
-	    errmsg = e_winwidth_cannot_be_smaller_than_winminwidth;
-	    p_wmw = p_wiw;
-	}
-	win_setminwidth();
-    }
-
-    // (re)set last window status line
-    else if (pp == &p_ls)
-    {
-	last_status(FALSE);
-    }
-
-    // (re)set tab page line
-    else if (pp == &p_stal)
-    {
-	shell_new_rows();	// recompute window positions and heights
-    }
+	p_wiw = 1;
+    }
+    if (p_wmw > p_wiw)
+    {
+	errmsg = e_winwidth_cannot_be_smaller_than_winminwidth;
+	p_wiw = p_wmw;
+    }
+
+    // Change window width NOW
+    if (!ONE_WINDOW && curwin->w_width < p_wiw)
+	win_setwidth((int)p_wiw);
+
+    return errmsg;
+}
+
+/*
+ * Process the new 'winminwidth' option value.
+ */
+    static char *
+did_set_winminwidth(char *errmsg)
+{
+    if (p_wmw < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+	p_wmw = 0;
+    }
+    if (p_wmw > p_wiw)
+    {
+	errmsg = e_winwidth_cannot_be_smaller_than_winminwidth;
+	p_wmw = p_wiw;
+    }
+    win_setminwidth();
+
+    return errmsg;
+}
+
+/*
+ * Process the new 'laststatus' option value.
+ */
+    static void
+did_set_laststatus(void)
+{
+    last_status(FALSE);	// (re)set last window status line
+}
+
+/*
+ * Process the new 'showtabline' option value.
+ */
+    static void
+did_set_showtabline(void)
+{
+    shell_new_rows();	// recompute window positions and heights
+}
 
 #ifdef FEAT_GUI
-    else if (pp == &p_linespace)
-    {
-	// Recompute gui.char_height and resize the Vim window to keep the
-	// same number of lines.
-	if (gui.in_use && gui_mch_adjust_charheight() == OK)
-	    gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
-    }
+/*
+ * Process the new 'linespace' option value.
+ */
+    static void
+did_set_linespace(void)
+{
+    // Recompute gui.char_height and resize the Vim window to keep the
+    // same number of lines.
+    if (gui.in_use && gui_mch_adjust_charheight() == OK)
+	gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
+}
 #endif
 
 #ifdef FEAT_FOLDING
-    // 'foldlevel'
-    else if (pp == &curwin->w_p_fdl)
-    {
-	if (curwin->w_p_fdl < 0)
-	    curwin->w_p_fdl = 0;
-	newFoldLevel();
-    }
-
-    // 'foldminlines'
-    else if (pp == &curwin->w_p_fml)
-    {
+/*
+ * Process the new 'foldlevel' option value.
+ */
+    static void
+did_set_foldlevel(void)
+{
+    if (curwin->w_p_fdl < 0)
+	curwin->w_p_fdl = 0;
+    newFoldLevel();
+}
+
+/*
+ * Process the new 'foldminlines' option value.
+ */
+    static void
+did_set_foldminlines(void)
+{
+    foldUpdateAll(curwin);
+}
+
+/*
+ * Process the new 'foldnestmax' option value.
+ */
+    static void
+did_set_foldnestmax(void)
+{
+    if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin))
 	foldUpdateAll(curwin);
-    }
-
-    // 'foldnestmax'
-    else if (pp == &curwin->w_p_fdn)
-    {
-	if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin))
-	    foldUpdateAll(curwin);
-    }
-
-    // 'foldcolumn'
-    else if (pp == &curwin->w_p_fdc)
-    {
-	if (curwin->w_p_fdc < 0)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    curwin->w_p_fdc = 0;
-	}
-	else if (curwin->w_p_fdc > 12)
-	{
-	    errmsg = e_invalid_argument;
-	    curwin->w_p_fdc = 12;
-	}
-    }
-#endif // FEAT_FOLDING
-
-    // 'shiftwidth' or 'tabstop'
-    else if (pp == &curbuf->b_p_sw || pp == &curbuf->b_p_ts)
-    {
+}
+
+/*
+ * Process the new 'foldcolumn' option value.
+ */
+    static char *
+did_set_foldcolumn(char *errmsg)
+{
+    if (curwin->w_p_fdc < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+	curwin->w_p_fdc = 0;
+    }
+    else if (curwin->w_p_fdc > 12)
+    {
+	errmsg = e_invalid_argument;
+	curwin->w_p_fdc = 12;
+    }
+
+    return errmsg;
+}
+#endif
+
+/*
+ * Process the new 'shiftwidth' or the 'tabstop' option value.
+ */
+    static void
+did_set_shiftwidth_tabstop(long *pp)
+{
 #ifdef FEAT_FOLDING
-	if (foldmethodIsIndent(curwin))
-	    foldUpdateAll(curwin);
-#endif
-	// When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
-	// parse 'cinoptions'.
-	if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0)
-	    parse_cino(curbuf);
-    }
-
-    // 'maxcombine'
-    else if (pp == &p_mco)
-    {
-	if (p_mco > MAX_MCO)
-	    p_mco = MAX_MCO;
-	else if (p_mco < 0)
-	    p_mco = 0;
-	screenclear();	    // will re-allocate the screen
-    }
-
-    else if (pp == &curbuf->b_p_iminsert)
-    {
-	if (curbuf->b_p_iminsert < 0 || curbuf->b_p_iminsert > B_IMODE_LAST)
-	{
-	    errmsg = e_invalid_argument;
-	    curbuf->b_p_iminsert = B_IMODE_NONE;
-	}
-	p_iminsert = curbuf->b_p_iminsert;
-	if (termcap_active)	// don't do this in the alternate screen
-	    showmode();
+    if (foldmethodIsIndent(curwin))
+	foldUpdateAll(curwin);
+#endif
+    // When 'shiftwidth' changes, or it's zero and 'tabstop' changes:
+    // parse 'cinoptions'.
+    if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0)
+	parse_cino(curbuf);
+}
+
+/*
+ * Process the new 'maxcombine' option value.
+ */
+    static void
+did_set_maxcombine(void)
+{
+    if (p_mco > MAX_MCO)
+	p_mco = MAX_MCO;
+    else if (p_mco < 0)
+	p_mco = 0;
+    screenclear();	    // will re-allocate the screen
+}
+
+/*
+ * Process the new 'iminsert' option value.
+ */
+    static char *
+did_set_iminsert(char *errmsg)
+{
+    if (curbuf->b_p_iminsert < 0 || curbuf->b_p_iminsert > B_IMODE_LAST)
+    {
+	errmsg = e_invalid_argument;
+	curbuf->b_p_iminsert = B_IMODE_NONE;
+    }
+    p_iminsert = curbuf->b_p_iminsert;
+    if (termcap_active)	// don't do this in the alternate screen
+	showmode();
 #if defined(FEAT_KEYMAP)
-	// Show/unshow value of 'keymap' in status lines.
-	status_redraw_curbuf();
-#endif
-    }
+    // Show/unshow value of 'keymap' in status lines.
+    status_redraw_curbuf();
+#endif
+
+    return errmsg;
+}
 
 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
-    // 'imstyle'
-    else if (pp == &p_imst)
-    {
-	if (p_imst != IM_ON_THE_SPOT && p_imst != IM_OVER_THE_SPOT)
-	    errmsg = e_invalid_argument;
-    }
-#endif
-
-    else if (pp == &p_window)
-    {
-	if (p_window < 1)
-	    p_window = 1;
-	else if (p_window >= Rows)
-	    p_window = Rows - 1;
-    }
-
-    else if (pp == &curbuf->b_p_imsearch)
-    {
-	if (curbuf->b_p_imsearch < -1 || curbuf->b_p_imsearch > B_IMODE_LAST)
-	{
-	    errmsg = e_invalid_argument;
-	    curbuf->b_p_imsearch = B_IMODE_NONE;
-	}
-	p_imsearch = curbuf->b_p_imsearch;
-    }
-
+/*
+ * Process the new 'imstyle' option value.
+ */
+    static char *
+did_set_imstyle(char *errmsg)
+{
+    if (p_imst != IM_ON_THE_SPOT && p_imst != IM_OVER_THE_SPOT)
+	errmsg = e_invalid_argument;
+
+    return errmsg;
+}
+#endif
+
+/*
+ * Process the new 'window' option value.
+ */
+    static void
+did_set_window(void)
+{
+    if (p_window < 1)
+	p_window = 1;
+    else if (p_window >= Rows)
+	p_window = Rows - 1;
+}
+
+/*
+ * Process the new 'imsearch' option value.
+ */
+    static char *
+did_set_imsearch(char *errmsg)
+{
+    if (curbuf->b_p_imsearch < -1 || curbuf->b_p_imsearch > B_IMODE_LAST)
+    {
+	errmsg = e_invalid_argument;
+	curbuf->b_p_imsearch = B_IMODE_NONE;
+    }
+    p_imsearch = curbuf->b_p_imsearch;
+
+    return errmsg;
+}
+
+/*
+ * Process the new 'titlelen' option value.
+ */
+    static char *
+did_set_titlelen(long old_value, char *errmsg)
+{
     // if 'titlelen' has changed, redraw the title
-    else if (pp == &p_titlelen)
-    {
-	if (p_titlelen < 0)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    p_titlelen = 85;
-	}
-	if (starting != NO_SCREEN && old_value != p_titlelen)
-	    need_maketitle = TRUE;
-    }
-
+    if (p_titlelen < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+	p_titlelen = 85;
+    }
+    if (starting != NO_SCREEN && old_value != p_titlelen)
+	need_maketitle = TRUE;
+
+    return errmsg;
+}
+
+/*
+ * Process the new 'cmdheight' option value.
+ */
+    static char *
+did_set_cmdheight(long old_value, char *errmsg)
+{
     // if p_ch changed value, change the command line height
-    else if (pp == &p_ch)
-    {
-	if (p_ch < 1)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    p_ch = 1;
-	}
-	if (p_ch > Rows - min_rows() + 1)
-	    p_ch = Rows - min_rows() + 1;
-
-	// Only compute the new window layout when startup has been
-	// completed. Otherwise the frame sizes may be wrong.
-	if ((p_ch != old_value
-		      || tabline_height() + topframe->fr_height != Rows - p_ch)
-		&& full_screen
+    if (p_ch < 1)
+    {
+	errmsg = e_argument_must_be_positive;
+	p_ch = 1;
+    }
+    if (p_ch > Rows - min_rows() + 1)
+	p_ch = Rows - min_rows() + 1;
+
+    // Only compute the new window layout when startup has been
+    // completed. Otherwise the frame sizes may be wrong.
+    if ((p_ch != old_value
+		|| tabline_height() + topframe->fr_height != Rows - p_ch)
+	    && full_screen
 #ifdef FEAT_GUI
-		&& !gui.starting
-#endif
-		       )
-	    command_height();
-    }
-
+	    && !gui.starting
+#endif
+       )
+	command_height();
+
+    return errmsg;
+}
+
+/*
+ * Process the new 'updatecount' option value.
+ */
+    static char *
+did_set_updatecount(long old_value, char *errmsg)
+{
     // when 'updatecount' changes from zero to non-zero, open swap files
-    else if (pp == &p_uc)
-    {
-	if (p_uc < 0)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    p_uc = 100;
-	}
-	if (p_uc && !old_value)
-	    ml_open_files();
-    }
+    if (p_uc < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+	p_uc = 100;
+    }
+    if (p_uc && !old_value)
+	ml_open_files();
+
+    return errmsg;
+}
+
 #ifdef FEAT_CONCEAL
-    else if (pp == &curwin->w_p_cole)
-    {
-	if (curwin->w_p_cole < 0)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    curwin->w_p_cole = 0;
-	}
-	else if (curwin->w_p_cole > 3)
-	{
-	    errmsg = e_invalid_argument;
-	    curwin->w_p_cole = 3;
-	}
-    }
-#endif
-#ifdef MZSCHEME_GUI_THREADS
-    else if (pp == &p_mzq)
-	mzvim_reset_timer();
+/*
+ * Process the new 'conceallevel' option value.
+ */
+    static char *
+did_set_conceallevel(char *errmsg)
+{
+    if (curwin->w_p_cole < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+	curwin->w_p_cole = 0;
+    }
+    else if (curwin->w_p_cole > 3)
+    {
+	errmsg = e_invalid_argument;
+	curwin->w_p_cole = 3;
+    }
+
+    return errmsg;
+}
 #endif
 
 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
-    // 'pyxversion'
-    else if (pp == &p_pyx)
-    {
-	if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3)
-	    errmsg = e_invalid_argument;
-    }
-#endif
-
+/*
+ * Process the new 'pyxversion' option value.
+ */
+    static char *
+did_set_pyxversion(char *errmsg)
+{
+    if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3)
+	errmsg = e_invalid_argument;
+
+    return errmsg;
+}
+#endif
+
+/*
+ * Process the new global 'undolevels' option value.
+ */
+    static void
+did_set_global_undolevels(long value, long old_value)
+{
     // sync undo before 'undolevels' changes
-    else if (pp == &p_ul)
-    {
-	// use the old value, otherwise u_sync() may not work properly
-	p_ul = old_value;
-	u_sync(TRUE);
-	p_ul = value;
-    }
-    else if (pp == &curbuf->b_p_ul)
-    {
-	// use the old value, otherwise u_sync() may not work properly
-	curbuf->b_p_ul = old_value;
-	u_sync(TRUE);
-	curbuf->b_p_ul = value;
-    }
+
+    // use the old value, otherwise u_sync() may not work properly
+    p_ul = old_value;
+    u_sync(TRUE);
+    p_ul = value;
+}
+
+/*
+ * Process the new buffer local 'undolevels' option value.
+ */
+    static void
+did_set_buflocal_undolevels(long value, long old_value)
+{
+    // use the old value, otherwise u_sync() may not work properly
+    curbuf->b_p_ul = old_value;
+    u_sync(TRUE);
+    curbuf->b_p_ul = value;
+}
 
 #ifdef FEAT_LINEBREAK
+/*
+ * Process the new 'numberwidth' option value.
+ */
+    static char *
+did_set_numberwidth(char *errmsg)
+{
     // 'numberwidth' must be positive
-    else if (pp == &curwin->w_p_nuw)
-    {
-	if (curwin->w_p_nuw < 1)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    curwin->w_p_nuw = 1;
-	}
-	if (curwin->w_p_nuw > 20)
-	{
-	    errmsg = e_invalid_argument;
-	    curwin->w_p_nuw = 20;
-	}
-	curwin->w_nrwidth_line_count = 0; // trigger a redraw
-    }
-#endif
-
-    else if (pp == &curbuf->b_p_tw)
-    {
-	if (curbuf->b_p_tw < 0)
-	{
-	    errmsg = e_argument_must_be_positive;
-	    curbuf->b_p_tw = 0;
-	}
+    if (curwin->w_p_nuw < 1)
+    {
+	errmsg = e_argument_must_be_positive;
+	curwin->w_p_nuw = 1;
+    }
+    if (curwin->w_p_nuw > 20)
+    {
+	errmsg = e_invalid_argument;
+	curwin->w_p_nuw = 20;
+    }
+    curwin->w_nrwidth_line_count = 0; // trigger a redraw
+
+    return errmsg;
+}
+#endif
+
+/*
+ * Process the new 'textwidth' option value.
+ */
+    static char *
+did_set_textwidth(char *errmsg)
+{
+    if (curbuf->b_p_tw < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+	curbuf->b_p_tw = 0;
+    }
 #ifdef FEAT_SYN_HL
-	{
-	    win_T	*wp;
-	    tabpage_T	*tp;
-
-	    FOR_ALL_TAB_WINDOWS(tp, wp)
-		check_colorcolumn(wp);
-	}
-#endif
-    }
-
-    /*
-     * Check the bounds for numeric options here
-     */
+    {
+	win_T	*wp;
+	tabpage_T	*tp;
+
+	FOR_ALL_TAB_WINDOWS(tp, wp)
+	    check_colorcolumn(wp);
+    }
+#endif
+
+    return errmsg;
+}
+
+/*
+ * When some number options are changed, need to take some action.
+ */
+    static char *
+did_set_num_option(long *pp, long value, long old_value, char *errmsg)
+{
+    if (pp == &p_wh				// 'winheight'
+	    || pp == &p_hh)			// 'helpheight'
+	errmsg = did_set_winheight_helpheight(pp, errmsg);
+    else if (pp == &p_wmh)			// 'winminheight'
+	errmsg = did_set_winminheight(errmsg);
+    else if (pp == &p_wiw)			// 'winwidth'
+	errmsg = did_set_winwidth(errmsg);
+    else if (pp == &p_wmw)			// 'winminwidth'
+	errmsg = did_set_winminwidth(errmsg);
+    else if (pp == &p_ls)
+	did_set_laststatus();			// 'laststatus'
+    else if (pp == &p_stal)
+	did_set_showtabline();			// 'showtabline'
+#ifdef FEAT_GUI
+    else if (pp == &p_linespace)		// 'linespace'
+	did_set_linespace();
+#endif
+#ifdef FEAT_FOLDING
+    else if (pp == &curwin->w_p_fdl)		// 'foldlevel'
+	did_set_foldlevel();
+    else if (pp == &curwin->w_p_fml)		// 'foldminlines'
+	did_set_foldminlines();
+    else if (pp == &curwin->w_p_fdn)		// 'foldnestmax'
+	did_set_foldnestmax();
+    else if (pp == &curwin->w_p_fdc)		// 'foldcolumn'
+	errmsg = did_set_foldcolumn(errmsg);
+#endif // FEAT_FOLDING
+    else if (  pp == &curbuf->b_p_sw		// 'shiftwidth'
+	    || pp == &curbuf->b_p_ts)		// 'tabstop'
+	did_set_shiftwidth_tabstop(pp);
+    else if (pp == &p_mco)			// 'maxcombine'
+	did_set_maxcombine();
+    else if (pp == &curbuf->b_p_iminsert)	// 'iminsert'
+	errmsg = did_set_iminsert(errmsg);
+#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+    else if (pp == &p_imst)			// 'imstyle'
+	errmsg = did_set_imstyle(errmsg);
+#endif
+    else if (pp == &p_window)			// 'window'
+	did_set_window();
+    else if (pp == &curbuf->b_p_imsearch)	// 'imsearch'
+	errmsg = did_set_imsearch(errmsg);
+    else if (pp == &p_titlelen)			// 'titlelen'
+	errmsg = did_set_titlelen(old_value, errmsg);
+    else if (pp == &p_ch)			// 'cmdheight'
+	errmsg = did_set_cmdheight(old_value, errmsg);
+    else if (pp == &p_uc)			// 'updatecount'
+	errmsg = did_set_updatecount(old_value, errmsg);
+#ifdef FEAT_CONCEAL
+    else if (pp == &curwin->w_p_cole)		// 'conceallevel'
+	errmsg = did_set_conceallevel(errmsg);
+#endif
+#ifdef MZSCHEME_GUI_THREADS
+    else if (pp == &p_mzq)			// 'mzquantum'
+	mzvim_reset_timer();
+#endif
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+    else if (pp == &p_pyx)			// 'pyxversion'
+	errmsg = did_set_pyxversion(errmsg);
+#endif
+    else if (pp == &p_ul)			// global 'undolevels'
+	did_set_global_undolevels(value, old_value);
+    else if (pp == &curbuf->b_p_ul)		// buffer local 'undolevels'
+	did_set_buflocal_undolevels(value, old_value);
+#ifdef FEAT_LINEBREAK
+    else if (pp == &curwin->w_p_nuw)		// 'numberwidth'
+	errmsg = did_set_numberwidth(errmsg);
+#endif
+    else if (pp == &curbuf->b_p_tw)		// 'textwidth'
+	errmsg = did_set_textwidth(errmsg);
+
+    return errmsg;
+}
+
+/*
+ * Check the bounds of numeric options.
+ */
+    static char *
+check_num_option_bounds(
+    long	*pp,
+    long	old_value,
+    long	old_Rows,
+    long	old_Columns,
+    char	*errbuf,
+    size_t	errbuflen,
+    char	*errmsg)
+{
     if (Rows < min_rows() && full_screen)
     {
 	if (errbuf != NULL)
 	{
 	    vim_snprintf(errbuf, errbuflen,
-			       _(e_need_at_least_nr_lines), min_rows());
+		    _(e_need_at_least_nr_lines), min_rows());
 	    errmsg = errbuf;
 	}
 	Rows = min_rows();
@@ -3892,7 +4038,7 @@ set_num_option(
 	if (errbuf != NULL)
 	{
 	    vim_snprintf(errbuf, errbuflen,
-			    _(e_need_at_least_nr_columns), MIN_COLUMNS);
+		    _(e_need_at_least_nr_columns), MIN_COLUMNS);
 	    errmsg = errbuf;
 	}
 	Columns = MIN_COLUMNS;
@@ -3912,7 +4058,7 @@ set_num_option(
 #ifdef FEAT_GUI
 		&& !gui.starting
 #endif
-	    )
+		)
 	    set_shellsize((int)Columns, (int)Rows, TRUE);
 	else
 	{
@@ -4015,6 +4161,83 @@ set_num_option(
 	p_ss = 0;
     }
 
+    return errmsg;
+}
+
+/*
+ * Set the value of a number option, and take care of side effects.
+ * Returns NULL for success, or an error message for an error.
+ */
+    static char *
+set_num_option(
+    int		opt_idx,		// index in options[] table
+    char_u	*varp,			// pointer to the option variable
+    long	value,			// new value
+    char	*errbuf,		// buffer for error messages
+    size_t	errbuflen,		// length of "errbuf"
+    int		opt_flags)		// OPT_LOCAL, OPT_GLOBAL,
+					// OPT_MODELINE, etc.
+{
+    char	*errmsg = NULL;
+    long	old_value = *(long *)varp;
+#if defined(FEAT_EVAL)
+    long	old_global_value = 0;	// only used when setting a local and
+					// global option
+#endif
+    long	old_Rows = Rows;	// remember old Rows
+    long	old_Columns = Columns;	// remember old Columns
+    long	*pp = (long *)varp;
+
+    // Disallow changing some options from secure mode.
+    if ((secure
+#ifdef HAVE_SANDBOX
+		|| sandbox != 0
+#endif
+		) && (options[opt_idx].flags & P_SECURE))
+	return e_not_allowed_here;
+
+#if defined(FEAT_EVAL)
+    // Save the global value before changing anything. This is needed as for
+    // a global-only option setting the "local value" in fact sets the global
+    // value (since there is only one value).
+    if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
+	old_global_value = *(long *)get_varp_scope(&(options[opt_idx]),
+								   OPT_GLOBAL);
+#endif
+
+    *pp = value;
+#ifdef FEAT_EVAL
+    // Remember where the option was set.
+    set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+#endif
+#ifdef FEAT_GUI
+    need_mouse_correct = TRUE;
+#endif
+
+    if (curbuf->b_p_sw < 0)
+    {
+	errmsg = e_argument_must_be_positive;
+#ifdef FEAT_VARTABS
+	// Use the first 'vartabstop' value, or 'tabstop' if vts isn't in use.
+	curbuf->b_p_sw = tabstop_count(curbuf->b_p_vts_array) > 0
+		       ? tabstop_first(curbuf->b_p_vts_array)
+		       : curbuf->b_p_ts;
+#else
+	curbuf->b_p_sw = curbuf->b_p_ts;
+#endif
+    }
+
+    /*
+     * Number options that need some action when changed
+     */
+    errmsg = did_set_num_option(pp, value, old_value, errmsg);
+
+    /*
+     * Check the bounds for numeric options here
+     */
+    errmsg = check_num_option_bounds(pp, old_value, old_Rows, old_Columns,
+						errbuf, errbuflen, errmsg);
+
     // May set global value for local option.
     if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
 	*(long *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL) = *pp;
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1293,
+/**/
     1292,
 /**/
     1291,