changeset 31996:ca6bc7c04163 v9.0.1330

patch 9.0.1330: handling new value of an option has a long "else if" chain Commit: https://github.com/vim/vim/commit/af93691b53f38784efce0b93fe7644c44a7e382e Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Mon Feb 20 12:16:39 2023 +0000 patch 9.0.1330: handling new value of an option has a long "else if" chain Problem: Handling new value of an option has a long "else if" chain. Solution: Use a function pointer. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/12015)
author Bram Moolenaar <Bram@vim.org>
date Mon, 20 Feb 2023 13:30:05 +0100
parents 95971aa5e525
children c7a3b0bfa44b
files src/buffer.c src/clipboard.c src/evalfunc.c src/ex_cmds.c src/ex_docmd.c src/ex_getln.c src/gui_xim.c src/hardcopy.c src/if_mzsch.c src/insexpand.c src/map.c src/ops.c src/option.c src/option.h src/optiondefs.h src/optionstr.c src/proto/clipboard.pro src/proto/ex_getln.pro src/proto/gui_xim.pro src/proto/hardcopy.pro src/proto/if_mzsch.pro src/proto/insexpand.pro src/proto/map.pro src/proto/ops.pro src/proto/option.pro src/proto/optionstr.pro src/proto/quickfix.pro src/proto/spell.pro src/proto/tag.pro src/quickfix.c src/spell.c src/spellfile.c src/spellsuggest.c src/structs.h src/tag.c src/version.c src/vim.h
diffstat 37 files changed, 1577 insertions(+), 1569 deletions(-) [+]
line wrap: on
line diff
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1971,7 +1971,7 @@ enter_buffer(buf_T *buf)
     // May need to set the spell language.  Can only do this after the buffer
     // has been properly setup.
     if (!curbuf->b_help && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
-	(void)did_set_spelllang(curwin);
+	(void)parse_spelllang(curwin);
 #endif
 #ifdef FEAT_VIMINFO
     curbuf->b_last_used = vim_time();
--- a/src/clipboard.c
+++ b/src/clipboard.c
@@ -1253,7 +1253,7 @@ clip_gen_owner_exists(Clipboard_T *cbd U
  * Return an error message or NULL for success.
  */
     char *
-check_clipboard_option(void)
+did_set_clipboard(optset_T *args UNUSED)
 {
     int		new_unnamed = 0;
     int		new_autoselect_star = FALSE;
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -9940,7 +9940,7 @@ f_spellbadword(typval_T *argvars UNUSED,
 
     if (!curwin->w_p_spell)
     {
-	did_set_spelllang(curwin);
+	parse_spelllang(curwin);
 	curwin->w_p_spell = TRUE;
     }
 
@@ -10030,7 +10030,7 @@ f_spellsuggest(typval_T *argvars UNUSED,
 
     if (!curwin->w_p_spell)
     {
-	did_set_spelllang(curwin);
+	parse_spelllang(curwin);
 	curwin->w_p_spell = TRUE;
     }
 
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -3142,7 +3142,7 @@ do_ecmd(
     // If the window options were changed may need to set the spell language.
     // Can only do this after the buffer has been properly setup.
     if (did_get_winopts && curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
-	(void)did_set_spelllang(curwin);
+	(void)parse_spelllang(curwin);
 #endif
 
     if (command == NULL)
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -1570,7 +1570,7 @@ getline_cookie(
 #endif
 }
 
-#if defined(FEAT_EVAL) || defined(PROT)
+#if defined(FEAT_EVAL) || defined(PROTO)
 /*
  * Get the next line source line without advancing.
  */
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -4366,7 +4366,7 @@ get_list_range(char_u **str, int *num1, 
  * Returns NULL if value is OK, error message otherwise.
  */
     char *
-check_cedit(void)
+did_set_cedit(optset_T *args UNUSED)
 {
     int n;
 
--- a/src/gui_xim.c
+++ b/src/gui_xim.c
@@ -13,6 +13,18 @@
 
 #include "vim.h"
 
+#if !defined(GTK_CHECK_VERSION)
+# define GTK_CHECK_VERSION(a, b, c) 0
+#endif
+#if !defined(FEAT_GUI_GTK) && defined(PROTO)
+typedef int GtkWidget;
+typedef int GtkIMContext;
+typedef int gchar;
+typedef int gpointer;
+typedef int PangoAttrIterator;
+typedef int GdkEventKey;
+#endif
+
 #if defined(FEAT_GUI_GTK) && defined(FEAT_XIM)
 # if GTK_CHECK_VERSION(3,0,0)
 #  include <gdk/gdkkeysyms-compat.h>
@@ -74,7 +86,7 @@ static callback_T imaf_cb;	    // 'imact
 static callback_T imsf_cb;	    // 'imstatusfunc' callback function
 
     char *
-set_imactivatefunc_option(void)
+did_set_imactivatefunc(optset_T *args UNUSED)
 {
     if (option_set_callback_func(p_imaf, &imaf_cb) == FAIL)
 	return e_invalid_argument;
@@ -83,7 +95,7 @@ set_imactivatefunc_option(void)
 }
 
     char *
-set_imstatusfunc_option(void)
+did_set_imstatusfunc(optset_T *args UNUSED)
 {
     if (option_set_callback_func(p_imsf, &imsf_cb) == FAIL)
 	return e_invalid_argument;
--- a/src/hardcopy.c
+++ b/src/hardcopy.c
@@ -144,7 +144,7 @@ static colnr_T hardcopy_line(prt_setting
  * Returns an error message or NULL;
  */
     char *
-parse_printoptions(void)
+parse_printoptions(optset_T *args UNUSED)
 {
     return parse_list_options(p_popt, printer_opts, OPT_PRINT_NUM_OPTIONS);
 }
@@ -155,7 +155,7 @@ parse_printoptions(void)
  * Returns an error message or NULL;
  */
     char *
-parse_printmbfont(void)
+parse_printmbfont(optset_T *args UNUSED)
 {
     return parse_list_options(p_pmfn, mbfont_opts, OPT_MBFONT_NUM_OPTIONS);
 }
--- a/src/if_mzsch.c
+++ b/src/if_mzsch.c
@@ -886,13 +886,15 @@ remove_timer(void)
     timer_id = 0;
 }
 
-    void
-mzvim_reset_timer(void)
+    char *
+did_set_mzquantum(void)
 {
+    // reset timer
     if (timer_id != 0)
 	remove_timer();
     if (mz_threads_allow && p_mzq > 0 && gui.in_use)
 	setup_timer();
+    return NULL;
 }
 
 #endif // MZSCHEME_GUI_THREADS
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -2546,7 +2546,7 @@ copy_global_to_buflocal_cb(callback_T *g
  * lambda expression.
  */
     char *
-set_completefunc_option(void)
+did_set_completefunc(optset_T *args UNUSED)
 {
     if (option_set_callback_func(curbuf->b_p_cfu, &cfu_cb) == FAIL)
 	return e_invalid_argument;
@@ -2575,7 +2575,7 @@ set_buflocal_cfu_callback(buf_T *buf UNU
  * lambda expression.
  */
     char *
-set_omnifunc_option(void)
+did_set_omnifunc(optset_T *args UNUSED)
 {
     if (option_set_callback_func(curbuf->b_p_ofu, &ofu_cb) == FAIL)
 	return e_invalid_argument;
@@ -2603,7 +2603,7 @@ set_buflocal_ofu_callback(buf_T *buf UNU
  * lambda expression.
  */
     char *
-set_thesaurusfunc_option(void)
+did_set_thesaurusfunc(optset_T *args UNUSED)
 {
     int	retval;
 
--- a/src/map.c
+++ b/src/map.c
@@ -3034,8 +3034,8 @@ langmap_init(void)
  * Called when langmap option is set; the language map can be
  * changed at any time!
  */
-    void
-langmap_set(void)
+    char *
+did_set_langmap(optset_T *args UNUSED)
 {
     char_u  *p;
     char_u  *p2;
@@ -3088,9 +3088,11 @@ langmap_set(void)
 	    }
 	    if (to == NUL)
 	    {
+		// TODO: Need to use errbuf argument for this error message
+		// and return it.
 		semsg(_(e_langmap_matching_character_missing_for_str),
 							     transchar(from));
-		return;
+		return NULL;
 	    }
 
 	    if (from >= 256)
@@ -3110,8 +3112,10 @@ langmap_set(void)
 		    {
 			if (p[0] != ',')
 			{
+			    // TODO: Need to use errbuf argument for this error
+			    // message and return it.
 			    semsg(_(e_langmap_extra_characters_after_semicolon_str), p);
-			    return;
+			    return NULL;
 			}
 			++p;
 		    }
@@ -3120,6 +3124,8 @@ langmap_set(void)
 	    }
 	}
     }
+
+    return NULL;
 }
 #endif
 
--- a/src/ops.c
+++ b/src/ops.c
@@ -3406,7 +3406,7 @@ static callback_T opfunc_cb;
  * Returns OK or FAIL.
  */
     char *
-set_operatorfunc_option(void)
+did_set_operatorfunc(optset_T *args UNUSED)
 {
     if (option_set_callback_func(p_opfunc, &opfunc_cb) == FAIL)
 	return e_invalid_argument;
--- a/src/option.c
+++ b/src/option.c
@@ -952,13 +952,13 @@ set_init_2(void)
 #endif
 
 #ifdef CURSOR_SHAPE
-    parse_shape_opt(SHAPE_CURSOR); // set cursor shapes from 'guicursor'
+    parse_shape_opt(SHAPE_CURSOR);	// set cursor shapes from 'guicursor'
 #endif
 #ifdef FEAT_MOUSESHAPE
-    parse_shape_opt(SHAPE_MOUSE);  // set mouse shapes from 'mouseshape'
+    parse_shape_opt(SHAPE_MOUSE);	// set mouse shapes from 'mouseshape'
 #endif
 #ifdef FEAT_PRINTER
-    (void)parse_printoptions();	    // parse 'printoptions' default value
+    (void)parse_printoptions(NULL);	// parse 'printoptions' default value
 #endif
 }
 
@@ -2032,7 +2032,7 @@ do_set_option_string(
 	// options. Note: when setting 'syntax' or 'filetype' autocommands may
 	// be triggered that can cause havoc.
 	*errmsg = did_set_string_option(
-			opt_idx, (char_u **)varp, oldval, errbuf,
+			opt_idx, (char_u **)varp, oldval, newval, errbuf,
 			opt_flags, value_checked);
 
 	secure = secure_saved;
@@ -2844,10 +2844,10 @@ didset_options(void)
     (void)did_set_spell_option(TRUE);
 #endif
     // set cedit_key
-    (void)check_cedit();
+    (void)did_set_cedit(NULL);
 #ifdef FEAT_LINEBREAK
     // initialize the table for 'breakat'.
-    fill_breakat_flags();
+    did_set_breakat(NULL);
 #endif
     after_copy_winopt(curwin);
 }
@@ -2872,7 +2872,7 @@ didset_options2(void)
 
 #ifdef FEAT_CLIPBOARD
     // Parse default for 'clipboard'
-    (void)check_clipboard_option();
+    (void)did_set_clipboard(NULL);
 #endif
 #ifdef FEAT_VARTABS
     vim_free(curbuf->b_p_vsts_array);
@@ -3140,44 +3140,47 @@ apply_optionset_autocmd(
 /*
  * Process the updated 'compatible' option value.
  */
-    static void
-did_set_compatible(void)
+    char *
+did_set_compatible(optset_T *args UNUSED)
 {
     compatible_set();
-}
-
-#ifdef FEAT_LANGMAP
+    return NULL;
+}
+
+#if defined(FEAT_LANGMAP) || defined(PROTO)
 /*
  * Process the updated 'langremap' option value.
  */
-    static void
-did_set_langremap(void)
+    char *
+did_set_langremap(optset_T *args UNUSED)
 {
     // 'langremap' -> !'langnoremap'
     p_lnr = !p_lrm;
+    return NULL;
 }
 
 /*
  * Process the updated 'langnoremap' option value.
  */
-    static void
-did_set_langnoremap(void)
+    char *
+did_set_langnoremap(optset_T *args UNUSED)
 {
     // 'langnoremap' -> !'langremap'
     p_lrm = !p_lnr;
-}
-#endif
-
-#ifdef FEAT_PERSISTENT_UNDO
+    return NULL;
+}
+#endif
+
+#if defined(FEAT_PERSISTENT_UNDO) || defined(PROTO)
 /*
  * Process the updated 'undofile' option value.
  */
-    static void
-did_set_undofile(int opt_flags)
+    char *
+did_set_undofile(optset_T *args)
 {
     // Only take action when the option was set.
     if (!curbuf->b_p_udf && !p_udf)
-	return;
+	return NULL;
 
     // When reset we do not delete the undo file, the option may be set again
     // without making any changes in between.
@@ -3191,7 +3194,8 @@ did_set_undofile(int opt_flags)
 	// if one exists, the buffer wasn't changed and the buffer was
 	// loaded
 	if ((curbuf == save_curbuf
-		    || (opt_flags & OPT_GLOBAL) || opt_flags == 0)
+		    || (args->os_flags & OPT_GLOBAL)
+		    || args->os_flags == 0)
 		&& !curbufIsChanged() && curbuf->b_ml.ml_mfp != NULL)
 	{
 #ifdef FEAT_CRYPT
@@ -3203,17 +3207,19 @@ did_set_undofile(int opt_flags)
 	}
     }
     curbuf = save_curbuf;
+
+    return NULL;
 }
 #endif
 
 /*
  * Process the updated 'readonly' option value.
  */
-    static void
-did_set_readonly(int opt_flags)
+    char *
+did_set_readonly(optset_T *args)
 {
     // when 'readonly' is reset globally, also reset readonlymode
-    if (!curbuf->b_p_ro && (opt_flags & OPT_LOCAL) == 0)
+    if (!curbuf->b_p_ro && (args->os_flags & OPT_LOCAL) == 0)
 	readonlymode = FALSE;
 
     // when 'readonly' is set may give W10 again
@@ -3221,25 +3227,28 @@ did_set_readonly(int opt_flags)
 	curbuf->b_did_warn = FALSE;
 
     redraw_titles();
-}
-
-#ifdef FEAT_GUI
+
+    return NULL;
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
 /*
  * Process the updated 'mousehide' option value.
  */
-    static void
-did_set_mousehide(void)
+    char *
+did_set_mousehide(optset_T *args UNUSED)
 {
     if (!p_mh)
 	gui_mch_mousehide(FALSE);
+    return NULL;
 }
 #endif
 
 /*
  * Process the updated 'modifiable' option value.
  */
-    static char *
-did_set_modifiable(int *doskip UNUSED)
+    char *
+did_set_modifiable(optset_T *args UNUSED)
 {
     // when 'modifiable' is changed, redraw the window title
 
@@ -3249,7 +3258,7 @@ did_set_modifiable(int *doskip UNUSED)
 		    && curbuf->b_term != NULL && !term_is_finished(curbuf))))
     {
 	curbuf->b_p_ma = FALSE;
-	*doskip = TRUE;
+	args->os_doskip = TRUE;
 	return e_cannot_make_terminal_with_running_job_modifiable;
     }
 # endif
@@ -3262,41 +3271,45 @@ did_set_modifiable(int *doskip UNUSED)
  * Process the updated 'endoffile' or 'endofline' or 'fixendofline' or 'bomb'
  * option value.
  */
-    static void
-did_set_eof_eol_fixeol_bomb(void)
+    char *
+did_set_eof_eol_fixeol_bomb(optset_T *args UNUSED)
 {
     // redraw the window title and tab page text
     redraw_titles();
+    return NULL;
 }
 
 /*
  * Process the updated 'binary' option value.
  */
-    static void
-did_set_binary(int opt_flags, long old_value)
+    char *
+did_set_binary(optset_T *args)
 {
     // when 'bin' is set also set some other options
-    set_options_bin(old_value, curbuf->b_p_bin, opt_flags);
+    set_options_bin(args->os_oldval.boolean, curbuf->b_p_bin, args->os_flags);
     redraw_titles();
+
+    return NULL;
 }
 
 /*
  * Process the updated 'buflisted' option value.
  */
-    static void
-did_set_buflisted(long old_value)
+    char *
+did_set_buflisted(optset_T *args)
 {
     // when 'buflisted' changes, trigger autocommands
-    if (old_value != curbuf->b_p_bl)
+    if (args->os_oldval.boolean != curbuf->b_p_bl)
 	apply_autocmds(curbuf->b_p_bl ? EVENT_BUFADD : EVENT_BUFDELETE,
 						NULL, NULL, TRUE, curbuf);
+    return NULL;
 }
 
 /*
  * Process the updated 'swapfile' option value.
  */
-    static void
-did_set_swapfile(void)
+    char *
+did_set_swapfile(optset_T *args UNUSED)
 {
     // when 'swf' is set, create swapfile, when reset remove swapfile
     if (curbuf->b_p_swf && p_uc)
@@ -3305,13 +3318,14 @@ did_set_swapfile(void)
 	// no need to reset curbuf->b_may_swap, ml_open_file() will check
 	// buf->b_p_swf
 	mf_close_file(curbuf, TRUE);	// remove the swap file
+    return NULL;
 }
 
 /*
  * Process the updated 'terse' option value.
  */
-    static void
-did_set_terse(void)
+    char *
+did_set_terse(optset_T *args UNUSED)
 {
     char_u	*p;
 
@@ -3328,23 +3342,25 @@ did_set_terse(void)
     // remove 's' from p_shm
     else if (!p_terse && p != NULL)
 	STRMOVE(p, p + 1);
+    return NULL;
 }
 
 /*
  * Process the updated 'paste' option value.
  */
-    static void
-did_set_paste(void)
+    char *
+did_set_paste(optset_T *args UNUSED)
 {
     // when 'paste' is set or reset also change other options
     paste_option_changed();
+    return NULL;
 }
 
 /*
  * Process the updated 'insertmode' option value.
  */
-    static void
-did_set_insertmode(long old_value)
+    char *
+did_set_insertmode(optset_T *args)
 {
     // when 'insertmode' is set from an autocommand need to do work here
     if (p_im)
@@ -3354,7 +3370,7 @@ did_set_insertmode(long old_value)
 	stop_insert_mode = FALSE;
     }
     // only reset if it was set previously
-    else if (old_value)
+    else if (args->os_oldval.boolean)
     {
 	need_start_insertmode = FALSE;
 	stop_insert_mode = TRUE;
@@ -3362,51 +3378,57 @@ did_set_insertmode(long old_value)
 	    clear_cmdline = TRUE;	// remove "(insert)"
 	restart_edit = 0;
     }
+
+    return NULL;
 }
 
 /*
  * Process the updated 'ignorecase' option value.
  */
-    static void
-did_set_ignorecase(void)
+    char *
+did_set_ignorecase(optset_T *args UNUSED)
 {
     // when 'ignorecase' is set or reset and 'hlsearch' is set, redraw
     if (p_hls)
 	redraw_all_later(UPD_SOME_VALID);
-}
-
-#ifdef FEAT_SEARCH_EXTRA
+    return NULL;
+}
+
+#if defined(FEAT_SEARCH_EXTRA) || defined(PROTO)
 /*
  * Process the updated 'hlsearch' option value.
  */
-    static void
-did_set_hlsearch(void)
+    char *
+did_set_hlsearch(optset_T *args UNUSED)
 {
     // when 'hlsearch' is set or reset: reset no_hlsearch
     set_no_hlsearch(FALSE);
+    return NULL;
 }
 #endif
 
 /*
  * Process the updated 'scrollbind' option value.
  */
-    static void
-did_set_scrollbind(void)
+    char *
+did_set_scrollbind(optset_T *args UNUSED)
 {
     // when 'scrollbind' is set: snapshot the current position to avoid a jump
     // at the end of normal_cmd()
     if (!curwin->w_p_scb)
-	return;
+	return NULL;
+
     do_check_scrollbind(FALSE);
     curwin->w_scbind_pos = curwin->w_topline;
+    return NULL;
 }
 
 #ifdef FEAT_QUICKFIX
 /*
  * Process the updated 'previewwindow' option value.
  */
-    static char *
-did_set_previewwindow(int *doskip)
+    char *
+did_set_previewwindow(optset_T *args)
 {
     if (!curwin->w_p_pvw)
 	return NULL;
@@ -3418,7 +3440,7 @@ did_set_previewwindow(int *doskip)
 	if (win->w_p_pvw && win != curwin)
 	{
 	    curwin->w_p_pvw = FALSE;
-	    *doskip = TRUE;
+	    args->os_doskip = TRUE;
 	    return e_preview_window_already_exists;
 	}
 
@@ -3429,75 +3451,84 @@ did_set_previewwindow(int *doskip)
 /*
  * Process the updated 'smoothscroll' option value.
  */
-    static void
-did_set_smoothscroll(void)
+    char *
+did_set_smoothscroll(optset_T *args UNUSED)
 {
     if (curwin->w_p_sms)
-	return;
+	return NULL;
+
     curwin->w_skipcol = 0;
     changed_line_abv_curs();
+    return NULL;
 }
 
 /*
  * Process the updated 'textmode' option value.
  */
-    static void
-did_set_textmode(int opt_flags)
+    char *
+did_set_textmode(optset_T *args)
 {
     // when 'textmode' is set or reset also change 'fileformat'
-    set_fileformat(curbuf->b_p_tx ? EOL_DOS : EOL_UNIX, opt_flags);
+    set_fileformat(curbuf->b_p_tx ? EOL_DOS : EOL_UNIX, args->os_flags);
+
+    return NULL;
 }
 
 /*
  * Process the updated 'textauto' option value.
  */
-    static void
-did_set_textauto(int opt_flags)
+    char *
+did_set_textauto(optset_T *args)
 {
     // when 'textauto' is set or reset also change 'fileformats'
     set_string_option_direct((char_u *)"ffs", -1,
 				p_ta ? (char_u *)DFLT_FFS_VIM : (char_u *)"",
-				OPT_FREE | opt_flags, 0);
+				OPT_FREE | args->os_flags, 0);
+
+    return NULL;
 }
 
 /*
  * Process the updated 'lisp' option value.
  */
-    static void
-did_set_lisp(void)
+    char *
+did_set_lisp(optset_T *args UNUSED)
 {
     // When 'lisp' option changes include/exclude '-' in keyword characters.
     (void)buf_init_chartab(curbuf, FALSE);	    // ignore errors
+    return NULL;
 }
 
 /*
  * Process the updated 'title' or the 'icon' option value.
  */
-    static void
-did_set_title_icon(void)
+    char *
+did_set_title_icon(optset_T *args UNUSED)
 {
     // when 'title' changed, may need to change the title; same for 'icon'
     did_set_title();
+    return NULL;
 }
 
 /*
  * Process the updated 'modified' option value.
  */
-    static void
-did_set_modified(long value)
-{
-    if (!value)
+    char *
+did_set_modified(optset_T *args)
+{
+    if (!args->os_newval.boolean)
 	save_file_ff(curbuf);	// Buffer is unchanged
     redraw_titles();
-    modified_was_set = value;
-}
-
-#ifdef BACKSLASH_IN_FILENAME
+    modified_was_set = args->os_newval.boolean;
+    return NULL;
+}
+
+#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
 /*
  * Process the updated 'shellslash' option value.
  */
-    static void
-did_set_shellslash(void)
+    char *
+did_set_shellslash(optset_T *args UNUSED)
 {
     if (p_ssl)
     {
@@ -3518,90 +3549,101 @@ did_set_shellslash(void)
 # ifdef FEAT_EVAL
     scriptnames_slash_adjust();
 # endif
+    return NULL;
 }
 #endif
 
 /*
  * Process the updated 'wrap' option value.
  */
-    static void
-did_set_wrap(void)
+    char *
+did_set_wrap(optset_T *args UNUSED)
 {
     // If 'wrap' is set, set w_leftcol to zero.
     if (curwin->w_p_wrap)
 	curwin->w_leftcol = 0;
+    return NULL;
 }
 
 /*
  * Process the updated 'equalalways' option value.
  */
-    static void
-did_set_equalalways(long old_value)
-{
-    if (p_ea && !old_value)
+    char *
+did_set_equalalways(optset_T *args)
+{
+    if (p_ea && !args->os_oldval.boolean)
 	win_equal(curwin, FALSE, 0);
+
+    return NULL;
 }
 
 /*
  * Process the updated 'weirdinvert' option value.
  */
-    static void
-did_set_weirdinvert(long old_value)
+    char *
+did_set_weirdinvert(optset_T *args)
 {
     // When 'weirdinvert' changed, set/reset 't_xs'.
     // Then set 'weirdinvert' according to value of 't_xs'.
-    if (p_wiv && !old_value)
+    if (p_wiv && !args->os_oldval.boolean)
 	T_XS = (char_u *)"y";
-    else if (!p_wiv && old_value)
+    else if (!p_wiv && args->os_oldval.boolean)
 	T_XS = empty_option;
     p_wiv = (*T_XS != NUL);
-}
-
-#ifdef FEAT_BEVAL_GUI
+
+    return NULL;
+}
+
+#if defined(FEAT_BEVAL_GUI) || defined(PROTO)
 /*
  * Process the updated 'ballooneval' option value.
  */
-    static void
-did_set_ballooneval(long old_value)
+    char *
+did_set_ballooneval(optset_T *args)
 {
     if (balloonEvalForTerm)
-	return;
-    if (p_beval && !old_value)
+	return NULL;
+
+    if (p_beval && !args->os_oldval.boolean)
 	gui_mch_enable_beval_area(balloonEval);
-    else if (!p_beval && old_value)
+    else if (!p_beval && args->os_oldval.boolean)
 	gui_mch_disable_beval_area(balloonEval);
-}
-#endif
-
-#ifdef FEAT_BEVAL_TERM
+
+    return NULL;
+}
+#endif
+
+#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
 /*
  * Process the updated 'balloonevalterm' option value.
  */
-    static void
-did_set_balloonevalterm(void)
+    char *
+did_set_balloonevalterm(optset_T *args UNUSED)
 {
     mch_bevalterm_changed();
-}
-#endif
-
-#ifdef FEAT_AUTOCHDIR
+    return NULL;
+}
+#endif
+
+#if defined(FEAT_AUTOCHDIR) || defined(PROTO)
 /*
  * Process the updated 'autochdir' option value.
  */
-    static void
-did_set_autochdir(void)
+    char *
+did_set_autochdir(optset_T *args UNUSED)
 {
     // Change directories when the 'acd' option is set now.
     DO_AUTOCHDIR;
-}
-#endif
-
-#ifdef FEAT_DIFF
+    return NULL;
+}
+#endif
+
+#if defined(FEAT_DIFF) || defined(PROTO)
 /*
  * Process the updated 'diff' option value.
  */
-    static void
-did_set_diff(void)
+    char *
+did_set_diff(optset_T *args UNUSED)
 {
     // May add or remove the buffer from the list of diff buffers.
     diff_buf_adjust(curwin);
@@ -3609,15 +3651,16 @@ did_set_diff(void)
     if (foldmethodIsDiff(curwin))
 	foldUpdateAll(curwin);
 # endif
-}
-#endif
-
-#ifdef HAVE_INPUT_METHOD
+    return NULL;
+}
+#endif
+
+#if defined(HAVE_INPUT_METHOD) || defined(PROTO)
 /*
  * Process the updated 'imdisable' option value.
  */
-    static void
-did_set_imdisable(void)
+    char *
+did_set_imdisable(optset_T *args UNUSED)
 {
     // Only de-activate it here, it will be enabled when changing mode.
     if (p_imdisable)
@@ -3626,29 +3669,30 @@ did_set_imdisable(void)
 	// When the option is set from an autocommand, it may need to take
 	// effect right away.
 	im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
-}
-#endif
-
-#ifdef FEAT_SPELL
+    return NULL;
+}
+#endif
+
+#if defined(FEAT_SPELL) || defined(PROTO)
 /*
  * Process the updated 'spell' option value.
  */
-    static char *
-did_set_spell(void)
+    char *
+did_set_spell(optset_T *args UNUSED)
 {
     if (curwin->w_p_spell)
-	return did_set_spelllang(curwin);
+	return parse_spelllang(curwin);
 
     return NULL;
 }
 #endif
 
-#ifdef FEAT_ARABIC
+#if defined(FEAT_ARABIC) || defined(PROTO)
 /*
  * Process the updated 'arabic' option value.
  */
-    static char *
-did_set_arabic(void)
+    char *
+did_set_arabic(optset_T *args UNUSED)
 {
     char *errmsg = NULL;
 
@@ -3728,13 +3772,13 @@ did_set_arabic(void)
 }
 #endif
 
-#if defined(FEAT_SIGNS) && defined(FEAT_GUI)
 /*
  * Process the updated 'number' or 'relativenumber' option value.
  */
-    static void
-did_set_number_relativenumber(char_u *varp)
-{
+    char *
+did_set_number_relativenumber(optset_T *args UNUSED)
+{
+#if (defined(FEAT_SIGNS) && defined(FEAT_GUI)) || defined(PROTO)
     if (gui.in_use
 	    && (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) == 'u')
 	    && curbuf->b_signlist != NULL)
@@ -3745,15 +3789,16 @@ did_set_number_relativenumber(char_u *va
 	// number column.  If the 'number' option is set and only the
 	// 'relativenumber' option is toggled, then don't refresh the screen
 	// (optimization).
-	if (!(curwin->w_p_nu && ((int *)varp == &curwin->w_p_rnu)))
+	if (!(curwin->w_p_nu && ((int *)args->os_varp == &curwin->w_p_rnu)))
 	    redraw_all_later(UPD_CLEAR);
     }
-}
-#endif
+#endif
+    return NULL;
+}
 
 #ifdef FEAT_TERMGUICOLORS
-    static char *
-did_set_termguicolors(int *doskip UNUSED)
+    char *
+did_set_termguicolors(optset_T *args UNUSED)
 {
 # ifdef FEAT_VTP
     // Do not turn on 'tgc' when 24-bit colors are not supported.
@@ -3764,7 +3809,7 @@ did_set_termguicolors(int *doskip UNUSED
 	    !has_vtp_working())
     {
 	p_tgc = 0;
-	*doskip = TRUE;
+	args->os_doskip = TRUE;
 	return e_24_bit_colors_are_not_supported_on_this_environment;
     }
     if (is_term_win32())
@@ -3794,133 +3839,6 @@ did_set_termguicolors(int *doskip UNUSED
 #endif
 
 /*
- * When some boolean options are changed, need to take some action.
- */
-    static char *
-did_set_bool_option(
-    char_u	*varp,
-    int		opt_flags,
-    long	value,
-    long	old_value,
-    int		*doskip)
-{
-    char *errmsg = NULL;
-
-    if ((int *)varp == &p_cp)			// 'compatible'
-	did_set_compatible();
-#ifdef FEAT_LANGMAP
-    else if ((int *)varp == &p_lrm)		// 'langremap'
-	did_set_langremap();
-    else if ((int *)varp == &p_lnr)		// 'langnoremap'
-	did_set_langnoremap();
-#endif
-#ifdef FEAT_PERSISTENT_UNDO
-    else if ((int *)varp == &curbuf->b_p_udf	// buffer local 'undofile'
-	    || (int *)varp == &p_udf)		// 'undofile'
-	did_set_undofile(opt_flags);
-#endif
-    else if ((int *)varp == &curbuf->b_p_ro)	// 'readonly'
-	did_set_readonly(opt_flags);
-#ifdef FEAT_GUI
-    else if ((int *)varp == &p_mh)		// 'mousehide'
-	did_set_mousehide();
-#endif
-    else if ((int *)varp == &curbuf->b_p_ma)
-	errmsg = did_set_modifiable(doskip);	// 'modifiable'
-    else if ((int *)varp == &curbuf->b_p_eof	// 'endoffile'
-	    || (int *)varp == &curbuf->b_p_eol	// 'endofline'
-	    || (int *)varp == &curbuf->b_p_fixeol	// 'fixendofline'
-	    || (int *)varp == &curbuf->b_p_bomb)	// 'bomb'
-	did_set_eof_eol_fixeol_bomb();
-    else if ((int *)varp == &curbuf->b_p_bin)	// 'binary'
-	did_set_binary(opt_flags, old_value);
-    else if ((int *)varp == &curbuf->b_p_bl)	// 'buflisted'
-	did_set_buflisted(old_value);
-    else if ((int *)varp == &curbuf->b_p_swf)	// 'swapfile'
-	did_set_swapfile();
-    else if ((int *)varp == &p_terse)		// 'terse'
-	did_set_terse();
-    else if ((int *)varp == &p_paste)		// 'paste'
-	did_set_paste();
-    else if ((int *)varp == &p_im)		// 'insertmode'
-	did_set_insertmode(old_value);
-    else if ((int *)varp == &p_ic)		// 'ignorecase'
-	did_set_ignorecase();
-#ifdef FEAT_SEARCH_EXTRA
-    else if ((int *)varp == &p_hls)		// 'hlsearch'
-	did_set_hlsearch();
-#endif
-    else if ((int *)varp == &curwin->w_p_scb)	// 'scrollbind'
-	did_set_scrollbind();
-#ifdef FEAT_QUICKFIX
-    else if ((int *)varp == &curwin->w_p_pvw)	// 'previewwindow'
-	errmsg = did_set_previewwindow(doskip);
-#endif
-    else if ((int *)varp == &curwin->w_p_sms)	// 'smoothscroll'
-	did_set_smoothscroll();
-    else if ((int *)varp == &curbuf->b_p_tx)	// 'textmode'
-	did_set_textmode(opt_flags);
-    else if ((int *)varp == &p_ta)		// 'textauto'
-	did_set_textauto(opt_flags);
-    else if (varp == (char_u *)&(curbuf->b_p_lisp))	// 'lisp'
-	did_set_lisp();
-    else if (  (int *)varp == &p_title		// 'title'
-	    || (int *)varp == &p_icon)		// 'icon'
-	did_set_title_icon();
-    else if ((int *)varp == &curbuf->b_changed)	// 'modified'
-	did_set_modified(value);
-#ifdef BACKSLASH_IN_FILENAME
-    else if ((int *)varp == &p_ssl)		// 'shellslash'
-	did_set_shellslash();
-#endif
-    else if ((int *)varp == &curwin->w_p_wrap)	// 'wrap'
-	did_set_wrap();
-    else if ((int *)varp == &p_ea)		// 'equalalways'
-	did_set_equalalways(old_value);
-    else if ((int *)varp == &p_wiv)		// weirdinvert'
-	did_set_weirdinvert(old_value);
-#ifdef FEAT_BEVAL_GUI
-    else if ((int *)varp == &p_beval)		// 'ballooneval'
-	did_set_ballooneval(old_value);
-#endif
-#ifdef FEAT_BEVAL_TERM
-    else if ((int *)varp == &p_bevalterm)	// 'balloonevalterm'
-	did_set_balloonevalterm();
-#endif
-#ifdef FEAT_AUTOCHDIR
-    else if ((int *)varp == &p_acd)		// 'autochdir'
-	did_set_autochdir();
-#endif
-#ifdef FEAT_DIFF
-    else if ((int *)varp == &curwin->w_p_diff)	// 'diff'
-	did_set_diff();
-#endif
-#ifdef HAVE_INPUT_METHOD
-    else if ((int *)varp == &p_imdisable)	// 'imdisable'
-	did_set_imdisable();
-#endif
-#ifdef FEAT_SPELL
-    else if ((int *)varp == &curwin->w_p_spell)	// 'spell'
-	errmsg = did_set_spell();
-#endif
-#ifdef FEAT_ARABIC
-    else if ((int *)varp == &curwin->w_p_arab)	// 'arabic'
-	errmsg = did_set_arabic();
-#endif
-#if defined(FEAT_SIGNS) && defined(FEAT_GUI)
-    else if (  (int *)varp == &curwin->w_p_nu	// 'number'
-	    || (int *)varp == &curwin->w_p_rnu)	// 'relativenumber'
-	did_set_number_relativenumber(varp);
-#endif
-#ifdef FEAT_TERMGUICOLORS
-    else if ((int *)varp == &p_tgc)		// 'termguicolors'
-	errmsg = did_set_termguicolors(doskip);
-#endif
-
-    return errmsg;
-}
-
-/*
  * Set the value of a boolean option, and take care of side effects.
  * Returns NULL for success, or an error message for an error.
  */
@@ -3971,10 +3889,19 @@ set_bool_option(
     /*
      * Handle side effects of changing a bool option.
      */
-    int doskip = FALSE;
-    errmsg = did_set_bool_option(varp, opt_flags, value, old_value, &doskip);
-    if (doskip)
-	return errmsg;
+    if (options[opt_idx].opt_did_set_cb != NULL)
+    {
+	optset_T args;
+
+	args.os_varp = varp;
+	args.os_flags = opt_flags;
+	args.os_oldval.boolean = old_value;
+	args.os_newval.boolean = value;
+	args.os_doskip = FALSE;
+	errmsg = options[opt_idx].opt_did_set_cb(&args);
+	if (args.os_doskip)
+	    return errmsg;
+    }
 
     // after handling side effects, call autocommand
 
@@ -4001,9 +3928,12 @@ set_bool_option(
 /*
  * Process the new 'winheight' or the 'helpheight' option value.
  */
-    static char *
-did_set_winheight_helpheight(long *pp, char *errmsg)
-{
+    char *
+did_set_winheight_helpheight(optset_T *args)
+{
+    long	*pp = (long *)args->os_varp;
+    char	*errmsg = NULL;
+
     if (p_wh < 1)
     {
 	errmsg = e_argument_must_be_positive;
@@ -4035,9 +3965,11 @@ did_set_winheight_helpheight(long *pp, c
 /*
  * Process the new 'winminheight' option value.
  */
-    static char *
-did_set_winminheight(char *errmsg)
-{
+    char *
+did_set_winminheight(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (p_wmh < 0)
     {
 	errmsg = e_argument_must_be_positive;
@@ -4056,9 +3988,11 @@ did_set_winminheight(char *errmsg)
 /*
  * Process the new 'winwidth' option value.
  */
-    static char *
-did_set_winwidth(char *errmsg)
-{
+    char *
+did_set_winwidth(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (p_wiw < 1)
     {
 	errmsg = e_argument_must_be_positive;
@@ -4080,9 +4014,11 @@ did_set_winwidth(char *errmsg)
 /*
  * Process the new 'winminwidth' option value.
  */
-    static char *
-did_set_winminwidth(char *errmsg)
-{
+    char *
+did_set_winminwidth(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (p_wmw < 0)
     {
 	errmsg = e_argument_must_be_positive;
@@ -4101,72 +4037,80 @@ did_set_winminwidth(char *errmsg)
 /*
  * Process the new 'laststatus' option value.
  */
-    static void
-did_set_laststatus(void)
+    char *
+did_set_laststatus(optset_T *args UNUSED)
 {
     last_status(FALSE);	// (re)set last window status line
+    return NULL;
 }
 
 /*
  * Process the new 'showtabline' option value.
  */
-    static void
-did_set_showtabline(void)
+    char *
+did_set_showtabline(optset_T *args UNUSED)
 {
     shell_new_rows();	// recompute window positions and heights
-}
-
-#ifdef FEAT_GUI
+    return NULL;
+}
+
+#if defined(FEAT_GUI) || defined(PROTO)
 /*
  * Process the new 'linespace' option value.
  */
-    static void
-did_set_linespace(void)
+    char *
+did_set_linespace(optset_T *args UNUSED)
 {
     // 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
+    return NULL;
+}
+#endif
+
+#if defined(FEAT_FOLDING) || defined(PROTO)
 /*
  * Process the new 'foldlevel' option value.
  */
-    static void
-did_set_foldlevel(void)
+    char *
+did_set_foldlevel(optset_T *args UNUSED)
 {
     if (curwin->w_p_fdl < 0)
 	curwin->w_p_fdl = 0;
     newFoldLevel();
+    return NULL;
 }
 
 /*
  * Process the new 'foldminlines' option value.
  */
-    static void
-did_set_foldminlines(void)
+    char *
+did_set_foldminlines(optset_T *args UNUSED)
 {
     foldUpdateAll(curwin);
+    return NULL;
 }
 
 /*
  * Process the new 'foldnestmax' option value.
  */
-    static void
-did_set_foldnestmax(void)
+    char *
+did_set_foldnestmax(optset_T *args UNUSED)
 {
     if (foldmethodIsSyntax(curwin) || foldmethodIsIndent(curwin))
 	foldUpdateAll(curwin);
+    return NULL;
 }
 
 /*
  * Process the new 'foldcolumn' option value.
  */
-    static char *
-did_set_foldcolumn(char *errmsg)
-{
+    char *
+did_set_foldcolumn(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (curwin->w_p_fdc < 0)
     {
 	errmsg = e_argument_must_be_positive;
@@ -4185,9 +4129,25 @@ did_set_foldcolumn(char *errmsg)
 /*
  * Process the new 'shiftwidth' or the 'tabstop' option value.
  */
-    static void
-did_set_shiftwidth_tabstop(long *pp)
-{
+    char *
+did_set_shiftwidth_tabstop(optset_T *args)
+{
+    long	*pp = (long *)args->os_varp;
+    char	*errmsg = NULL;
+
+    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
+    }
+
 #ifdef FEAT_FOLDING
     if (foldmethodIsIndent(curwin))
 	foldUpdateAll(curwin);
@@ -4196,27 +4156,32 @@ did_set_shiftwidth_tabstop(long *pp)
     // parse 'cinoptions'.
     if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0)
 	parse_cino(curbuf);
+
+    return errmsg;
 }
 
 /*
  * Process the new 'maxcombine' option value.
  */
-    static void
-did_set_maxcombine(void)
+    char *
+did_set_maxcombine(optset_T *args UNUSED)
 {
     if (p_mco > MAX_MCO)
 	p_mco = MAX_MCO;
     else if (p_mco < 0)
 	p_mco = 0;
     screenclear();	    // will re-allocate the screen
+    return NULL;
 }
 
 /*
  * Process the new 'iminsert' option value.
  */
-    static char *
-did_set_iminsert(char *errmsg)
-{
+    char *
+did_set_iminsert(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (curbuf->b_p_iminsert < 0 || curbuf->b_p_iminsert > B_IMODE_LAST)
     {
 	errmsg = e_invalid_argument;
@@ -4233,13 +4198,15 @@ did_set_iminsert(char *errmsg)
     return errmsg;
 }
 
-#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+#if (defined(FEAT_XIM) && defined(FEAT_GUI_GTK)) || defined(PROTO)
 /*
  * Process the new 'imstyle' option value.
  */
-    static char *
-did_set_imstyle(char *errmsg)
-{
+    char *
+did_set_imstyle(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (p_imst != IM_ON_THE_SPOT && p_imst != IM_OVER_THE_SPOT)
 	errmsg = e_invalid_argument;
 
@@ -4250,21 +4217,24 @@ did_set_imstyle(char *errmsg)
 /*
  * Process the new 'window' option value.
  */
-    static void
-did_set_window(void)
+    char *
+did_set_window(optset_T *args UNUSED)
 {
     if (p_window < 1)
 	p_window = 1;
     else if (p_window >= Rows)
 	p_window = Rows - 1;
+    return NULL;
 }
 
 /*
  * Process the new 'imsearch' option value.
  */
-    static char *
-did_set_imsearch(char *errmsg)
-{
+    char *
+did_set_imsearch(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (curbuf->b_p_imsearch < -1 || curbuf->b_p_imsearch > B_IMODE_LAST)
     {
 	errmsg = e_invalid_argument;
@@ -4278,9 +4248,12 @@ did_set_imsearch(char *errmsg)
 /*
  * Process the new 'titlelen' option value.
  */
-    static char *
-did_set_titlelen(long old_value, char *errmsg)
-{
+    char *
+did_set_titlelen(optset_T *args)
+{
+    long old_value = args->os_oldval.number;
+    char *errmsg = NULL;
+
     // if 'titlelen' has changed, redraw the title
     if (p_titlelen < 0)
     {
@@ -4296,9 +4269,12 @@ did_set_titlelen(long old_value, char *e
 /*
  * Process the new 'cmdheight' option value.
  */
-    static char *
-did_set_cmdheight(long old_value, char *errmsg)
-{
+    char *
+did_set_cmdheight(optset_T *args)
+{
+    long old_value = args->os_oldval.number;
+    char *errmsg = NULL;
+
     // if p_ch changed value, change the command line height
     if (p_ch < 1)
     {
@@ -4325,9 +4301,12 @@ did_set_cmdheight(long old_value, char *
 /*
  * Process the new 'updatecount' option value.
  */
-    static char *
-did_set_updatecount(long old_value, char *errmsg)
-{
+    char *
+did_set_updatecount(optset_T *args)
+{
+    long old_value = args->os_oldval.number;
+    char *errmsg = NULL;
+
     // when 'updatecount' changes from zero to non-zero, open swap files
     if (p_uc < 0)
     {
@@ -4340,13 +4319,15 @@ did_set_updatecount(long old_value, char
     return errmsg;
 }
 
-#ifdef FEAT_CONCEAL
+#if defined(FEAT_CONCEAL) || defined(PROTO)
 /*
  * Process the new 'conceallevel' option value.
  */
-    static char *
-did_set_conceallevel(char *errmsg)
-{
+    char *
+did_set_conceallevel(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (curwin->w_p_cole < 0)
     {
 	errmsg = e_argument_must_be_positive;
@@ -4362,13 +4343,15 @@ did_set_conceallevel(char *errmsg)
 }
 #endif
 
-#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
+#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) || defined(PROTO)
 /*
  * Process the new 'pyxversion' option value.
  */
-    static char *
-did_set_pyxversion(char *errmsg)
-{
+    char *
+did_set_pyxversion(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (p_pyx != 0 && p_pyx != 2 && p_pyx != 3)
 	errmsg = e_invalid_argument;
 
@@ -4402,13 +4385,15 @@ did_set_buflocal_undolevels(long value, 
     curbuf->b_p_ul = value;
 }
 
-#ifdef FEAT_LINEBREAK
+#if defined(FEAT_LINEBREAK) || defined(PROTO)
 /*
  * Process the new 'numberwidth' option value.
  */
-    static char *
-did_set_numberwidth(char *errmsg)
-{
+    char *
+did_set_numberwidth(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     // 'numberwidth' must be positive
     if (curwin->w_p_nuw < 1)
     {
@@ -4429,9 +4414,11 @@ did_set_numberwidth(char *errmsg)
 /*
  * Process the new 'textwidth' option value.
  */
-    static char *
-did_set_textwidth(char *errmsg)
-{
+    char *
+did_set_textwidth(optset_T *args UNUSED)
+{
+    char *errmsg = NULL;
+
     if (curbuf->b_p_tw < 0)
     {
 	errmsg = e_argument_must_be_positive;
@@ -4451,83 +4438,21 @@ did_set_textwidth(char *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;
+ * Process the new 'undolevels' option value.
+ */
+    char *
+did_set_undolevels(optset_T *args)
+{
+    long *pp = (long *)args->os_varp;
+
+    if (pp == &p_ul)			// global 'undolevels'
+	did_set_global_undolevels(args->os_newval.number,
+						       args->os_oldval.number);
+    else if (pp == &curbuf->b_p_ul)	// buffer local 'undolevels'
+	did_set_buflocal_undolevels(args->os_newval.number,
+						       args->os_oldval.number);
+
+    return NULL;
 }
 
 /*
@@ -4734,27 +4659,20 @@ set_num_option(
     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
-     */
+    // Invoke the option specific callback function to validate and apply the
+    // new value.
+    if (options[opt_idx].opt_did_set_cb != NULL)
+    {
+	optset_T args;
+
+	args.os_varp = varp;
+	args.os_flags = opt_flags;
+	args.os_oldval.number = old_value;
+	args.os_newval.number = value;
+	errmsg = options[opt_idx].opt_did_set_cb(&args);
+    }
+
+    // Check the bounds for numeric options here
     errmsg = check_num_option_bounds(pp, old_value, old_Rows, old_Columns,
 						errbuf, errbuflen, errmsg);
 
@@ -6530,6 +6448,15 @@ get_option_fullname(int opt_idx)
 #endif
 
 /*
+ * Return the did_set callback function for the option at 'opt_idx'
+ */
+    opt_did_set_cb_T
+get_option_did_set_cb(int opt_idx)
+{
+    return options[opt_idx].opt_did_set_cb;
+}
+
+/*
  * Get the value of 'equalprg', either the buffer-local one or the global one.
  */
     char_u *
@@ -8062,10 +7989,10 @@ compatible_set(void)
 #if defined(FEAT_LINEBREAK) || defined(PROTO)
 
 /*
- * fill_breakat_flags() -- called when 'breakat' changes value.
- */
-    void
-fill_breakat_flags(void)
+ * Called when the 'breakat' option changes value.
+ */
+    char *
+did_set_breakat(optset_T *args UNUSED)
 {
     char_u	*p;
     int		i;
@@ -8076,6 +8003,8 @@ fill_breakat_flags(void)
     if (p_breakat != NULL)
 	for (p = p_breakat; *p; p++)
 	    breakat_flags[*p] = TRUE;
+
+    return NULL;
 }
 #endif
 
--- a/src/option.h
+++ b/src/option.h
@@ -14,7 +14,7 @@
 #define _OPTION_H_
 
 //
-// Flags
+// Option Flags
 //
 #define P_BOOL		0x01	// the option is boolean
 #define P_NUM		0x02	// the option is numeric
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -263,12 +263,15 @@ struct vimoption
 {
     char	*fullname;	// full option name
     char	*shortname;	// permissible abbreviation
-    long_u	flags;		// see below
+    long_u	flags;		// see in option.h
     char_u	*var;		// global option: pointer to variable;
 				// window-local option: VAR_WIN;
 				// buffer-local option: global value
     idopt_T	indir;		// global option: PV_NONE;
 				// local option: indirect option index
+    // callback function to invoke after an option is modified to validate and
+    // apply the new value.
+    opt_did_set_cb_T	opt_did_set_cb;
     char_u	*def_val[2];	// default values for variable (vi and vim)
 #ifdef FEAT_EVAL
     sctx_T	script_ctx;	// script context where the option was last set
@@ -321,6 +324,7 @@ static struct vimoption options[] =
 #else
 			    (char_u *)NULL, PV_NONE,
 #endif
+			    NULL,
 			    {
 #if defined(MSWIN) && !defined(FEAT_GUI_MSWIN)
 			    (char_u *)128L,
@@ -329,72 +333,72 @@ static struct vimoption options[] =
 #endif
 					    (char_u *)0L} SCTX_INIT},
     {"antialias",   "anti", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)FALSE}
 			    SCTX_INIT},
     {"arabic",	    "arab", P_BOOL|P_VI_DEF|P_VIM|P_CURSWANT,
 #ifdef FEAT_ARABIC
-			    (char_u *)VAR_WIN, PV_ARAB,
+			    (char_u *)VAR_WIN, PV_ARAB, did_set_arabic,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"arabicshape", "arshape", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
 #ifdef FEAT_ARABIC
-			    (char_u *)&p_arshape, PV_NONE,
+			    (char_u *)&p_arshape, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"allowrevins", "ari",  P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_RIGHTLEFT
-			    (char_u *)&p_ari, PV_NONE,
+			    (char_u *)&p_ari, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"altkeymap",   "akm",  P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"ambiwidth",  "ambw",  P_STRING|P_VI_DEF|P_RCLR,
-			    (char_u *)&p_ambw, PV_NONE,
+			    (char_u *)&p_ambw, PV_NONE, did_set_ambiwidth,
 			    {(char_u *)"single", (char_u *)0L}
 			    SCTX_INIT},
     {"autochdir",  "acd",   P_BOOL|P_VI_DEF,
 #ifdef FEAT_AUTOCHDIR
-			    (char_u *)&p_acd, PV_NONE,
+			    (char_u *)&p_acd, PV_NONE, did_set_autochdir,
 			    {(char_u *)FALSE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"autoshelldir",  "asd",   P_BOOL|P_VI_DEF,
 #ifdef FEAT_AUTOSHELLDIR
-			    (char_u *)&p_asd, PV_NONE,
+			    (char_u *)&p_asd, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"autoindent",  "ai",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_ai, PV_AI,
+			    (char_u *)&p_ai, PV_AI, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"autoprint",   "ap",   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"autoread",    "ar",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_ar, PV_AR,
+			    (char_u *)&p_ar, PV_AR, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"autowrite",   "aw",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_aw, PV_NONE,
+			    (char_u *)&p_aw, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"autowriteall","awa",  P_BOOL|P_VI_DEF,
-			    (char_u *)&p_awa, PV_NONE,
+			    (char_u *)&p_awa, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"background",  "bg",   P_STRING|P_VI_DEF|P_RCLR,
-			    (char_u *)&p_bg, PV_NONE,
+			    (char_u *)&p_bg, PV_NONE, did_set_background,
 			    {
 #if (defined(MSWIN)) && !defined(FEAT_GUI)
 			    (char_u *)"dark",
@@ -403,13 +407,13 @@ static struct vimoption options[] =
 #endif
 					    (char_u *)0L} SCTX_INIT},
     {"backspace",   "bs",   P_STRING|P_VI_DEF|P_VIM|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_bs, PV_NONE,
+			    (char_u *)&p_bs, PV_NONE, did_set_backspace,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"backup",	    "bk",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_bk, PV_NONE,
+			    (char_u *)&p_bk, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"backupcopy",  "bkc",  P_STRING|P_VIM|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_bkc, PV_BKC,
+			    (char_u *)&p_bkc, PV_BKC, did_set_backupcopy,
 #ifdef UNIX
 			    {(char_u *)"yes", (char_u *)"auto"}
 #else
@@ -418,10 +422,11 @@ static struct vimoption options[] =
 			    SCTX_INIT},
     {"backupdir",   "bdir", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA
 							    |P_NODUP|P_SECURE,
-			    (char_u *)&p_bdir, PV_NONE,
+			    (char_u *)&p_bdir, PV_NONE, NULL,
 			    {(char_u *)DFLT_BDIR, (char_u *)0L} SCTX_INIT},
     {"backupext",   "bex",  P_STRING|P_VI_DEF|P_NFNAME,
 			    (char_u *)&p_bex, PV_NONE,
+			    did_set_backupext_or_patchmode,
 			    {
 #ifdef VMS
 			    (char_u *)"_",
@@ -430,75 +435,77 @@ static struct vimoption options[] =
 #endif
 					    (char_u *)0L} SCTX_INIT},
     {"backupskip",  "bsk",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_bsk, PV_NONE,
+			    (char_u *)&p_bsk, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"balloondelay","bdlay",P_NUM|P_VI_DEF,
 #ifdef FEAT_BEVAL
-			    (char_u *)&p_bdlay, PV_NONE,
+			    (char_u *)&p_bdlay, PV_NONE, NULL,
 			    {(char_u *)600L, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"ballooneval", "beval",P_BOOL|P_VI_DEF|P_NO_MKRC,
 #ifdef FEAT_BEVAL_GUI
-			    (char_u *)&p_beval, PV_NONE,
+			    (char_u *)&p_beval, PV_NONE, did_set_ballooneval,
 			    {(char_u *)FALSE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"balloonevalterm", "bevalterm",P_BOOL|P_VI_DEF|P_NO_MKRC,
 #ifdef FEAT_BEVAL_TERM
 			    (char_u *)&p_bevalterm, PV_NONE,
+			    did_set_balloonevalterm,
 			    {(char_u *)FALSE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"balloonexpr", "bexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE,
 #if defined(FEAT_BEVAL) && defined(FEAT_EVAL)
-			    (char_u *)&p_bexpr, PV_BEXPR,
+			    (char_u *)&p_bexpr, PV_BEXPR, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"beautify",    "bf",   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"belloff",      "bo",  P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
-			    (char_u *)&p_bo, PV_NONE,
+			    (char_u *)&p_bo, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"binary",	    "bin",  P_BOOL|P_VI_DEF|P_RSTAT,
-			    (char_u *)&p_bin, PV_BIN,
+			    (char_u *)&p_bin, PV_BIN, did_set_binary,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"bioskey",	    "biosk",P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"bomb",	    NULL,   P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
 			    (char_u *)&p_bomb, PV_BOMB,
+			    did_set_eof_eol_fixeol_bomb,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"breakat",	    "brk",  P_STRING|P_VI_DEF|P_RALL|P_FLAGLIST,
 #ifdef FEAT_LINEBREAK
-			    (char_u *)&p_breakat, PV_NONE,
+			    (char_u *)&p_breakat, PV_NONE, did_set_breakat,
 			    {(char_u *)" \t!@*-+;:,./?", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"breakindent",   "bri",  P_BOOL|P_VI_DEF|P_VIM|P_RWIN,
 #ifdef FEAT_LINEBREAK
-			    (char_u *)VAR_WIN, PV_BRI,
+			    (char_u *)VAR_WIN, PV_BRI, NULL,
 			    {(char_u *)FALSE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
@@ -506,79 +513,80 @@ static struct vimoption options[] =
 						  |P_ONECOMMA|P_NODUP,
 #ifdef FEAT_LINEBREAK
 			    (char_u *)VAR_WIN, PV_BRIOPT,
+			    did_set_breakindentopt,
 			    {(char_u *)"", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)NULL}
 #endif
 			    SCTX_INIT},
     {"browsedir",   "bsdir",P_STRING|P_VI_DEF,
 #ifdef FEAT_BROWSE
-			    (char_u *)&p_bsdir, PV_NONE,
+			    (char_u *)&p_bsdir, PV_NONE, did_set_browsedir,
 			    {(char_u *)"last", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"bufhidden",   "bh",   P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB,
-			    (char_u *)&p_bh, PV_BH,
+			    (char_u *)&p_bh, PV_BH, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"buflisted",   "bl",   P_BOOL|P_VI_DEF|P_NOGLOB,
-			    (char_u *)&p_bl, PV_BL,
+			    (char_u *)&p_bl, PV_BL, did_set_buflisted,
 			    {(char_u *)1L, (char_u *)0L}
 			    SCTX_INIT},
     {"buftype",	    "bt",   P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB,
-			    (char_u *)&p_bt, PV_BT,
+			    (char_u *)&p_bt, PV_BT, did_set_buftype,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"casemap",	    "cmp",   P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_cmp, PV_NONE,
+			    (char_u *)&p_cmp, PV_NONE, NULL,
 			    {(char_u *)"internal,keepascii", (char_u *)0L}
 			    SCTX_INIT},
     {"cdhome",	    "cdh",  P_BOOL|P_VI_DEF|P_VIM|P_SECURE,
-			    (char_u *)&p_cdh, PV_NONE,
+			    (char_u *)&p_cdh, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L}
 			    SCTX_INIT},
     {"cdpath",	    "cd",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE|P_COMMA|P_NODUP,
-			    (char_u *)&p_cdpath, PV_NONE,
+			    (char_u *)&p_cdpath, PV_NONE, NULL,
 			    {(char_u *)",,", (char_u *)0L}
 			    SCTX_INIT},
     {"cedit",	    NULL,   P_STRING,
-			    (char_u *)&p_cedit, PV_NONE,
+			    (char_u *)&p_cedit, PV_NONE, did_set_cedit,
 			    {(char_u *)"", (char_u *)CTRL_F_STR}
 			    SCTX_INIT},
     {"charconvert",  "ccv", P_STRING|P_VI_DEF|P_SECURE,
 #if defined(FEAT_EVAL)
-			    (char_u *)&p_ccv, PV_NONE,
+			    (char_u *)&p_ccv, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"cindent",	    "cin",  P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_cin, PV_CIN,
+			    (char_u *)&p_cin, PV_CIN, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"cinkeys",	    "cink", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_cink, PV_CINK,
+			    (char_u *)&p_cink, PV_CINK, NULL,
 			    {INDENTKEYS_DEFAULT, (char_u *)0L} SCTX_INIT},
     {"cinoptions",  "cino", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_cino, PV_CINO,
+			    (char_u *)&p_cino, PV_CINO, did_set_cinoptions,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"cinscopedecls", "cinsd", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_cinsd, PV_CINSD,
+			    (char_u *)&p_cinsd, PV_CINSD, NULL,
 			    {(char_u *)"public,protected,private", (char_u *)0L}
 			    SCTX_INIT},
     {"cinwords",    "cinw", P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_cinw, PV_CINW,
+			    (char_u *)&p_cinw, PV_CINW, NULL,
 			    {(char_u *)"if,else,while,do,for,switch",
 				(char_u *)0L}
 			    SCTX_INIT},
     {"clipboard",   "cb",   P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_CLIPBOARD
-			    (char_u *)&p_cb, PV_NONE,
+			    (char_u *)&p_cb, PV_NONE, did_set_clipboard,
 # ifdef FEAT_XCLIPBOARD
 			    {(char_u *)"autoselect,exclude:cons\\|linux",
 							       (char_u *)0L}
@@ -586,339 +594,342 @@ static struct vimoption options[] =
 			    {(char_u *)"", (char_u *)0L}
 # endif
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"cmdheight",   "ch",   P_NUM|P_VI_DEF|P_RALL,
-			    (char_u *)&p_ch, PV_NONE,
+			    (char_u *)&p_ch, PV_NONE, did_set_cmdheight,
 			    {(char_u *)1L, (char_u *)0L} SCTX_INIT},
     {"cmdwinheight", "cwh", P_NUM|P_VI_DEF,
-			    (char_u *)&p_cwh, PV_NONE,
+			    (char_u *)&p_cwh, PV_NONE, NULL,
 			    {(char_u *)7L, (char_u *)0L} SCTX_INIT},
     {"colorcolumn", "cc",   P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP|P_RWIN,
 #ifdef FEAT_SYN_HL
-			    (char_u *)VAR_WIN, PV_CC,
+			    (char_u *)VAR_WIN, PV_CC, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"columns",	    "co",   P_NUM|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RCLR,
-			    (char_u *)&Columns, PV_NONE,
+			    (char_u *)&Columns, PV_NONE, NULL,
 			    {(char_u *)80L, (char_u *)0L} SCTX_INIT},
     {"comments",    "com",  P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA
 							  |P_NODUP|P_CURSWANT,
-			    (char_u *)&p_com, PV_COM,
+			    (char_u *)&p_com, PV_COM, NULL,
 			    {(char_u *)"s1:/*,mb:*,ex:*/,://,b:#,:%,:XCOMM,n:>,fb:-",
 				(char_u *)0L}
 			    SCTX_INIT},
     {"commentstring", "cms", P_STRING|P_ALLOCED|P_VI_DEF|P_CURSWANT,
 #ifdef FEAT_FOLDING
-			    (char_u *)&p_cms, PV_CMS,
+			    (char_u *)&p_cms, PV_CMS, did_set_commentstring,
 			    {(char_u *)"/*%s*/", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
 			    // P_PRI_MKRC isn't needed here, optval_default()
 			    // always returns TRUE for 'compatible'
     {"compatible",  "cp",   P_BOOL|P_RALL,
-			    (char_u *)&p_cp, PV_NONE,
+			    (char_u *)&p_cp, PV_NONE, did_set_compatible,
 			    {(char_u *)TRUE, (char_u *)FALSE} SCTX_INIT},
     {"complete",    "cpt",  P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_cpt, PV_CPT,
+			    (char_u *)&p_cpt, PV_CPT, NULL,
 			    {(char_u *)".,w,b,u,t,i", (char_u *)0L}
 			    SCTX_INIT},
     {"concealcursor","cocu", P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF,
 #ifdef FEAT_CONCEAL
-			    (char_u *)VAR_WIN, PV_COCU,
+			    (char_u *)VAR_WIN, PV_COCU, NULL,
 			    {(char_u *)"", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"conceallevel","cole", P_NUM|P_RWIN|P_VI_DEF,
 #ifdef FEAT_CONCEAL
-			    (char_u *)VAR_WIN, PV_COLE,
+			    (char_u *)VAR_WIN, PV_COLE, did_set_conceallevel,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)0L, (char_u *)0L}
 			    SCTX_INIT},
     {"completefunc", "cfu", P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC,
 #ifdef FEAT_COMPL_FUNC
-			    (char_u *)&p_cfu, PV_CFU,
+			    (char_u *)&p_cfu, PV_CFU, did_set_completefunc,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"completeopt",   "cot",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_cot, PV_NONE,
+			    (char_u *)&p_cot, PV_NONE, did_set_completeopt,
 			    {(char_u *)"menu,preview", (char_u *)0L}
 			    SCTX_INIT},
     {"completepopup", "cpp", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
 #if defined(FEAT_PROP_POPUP) && defined(FEAT_QUICKFIX)
-			    (char_u *)&p_cpp, PV_NONE,
+			    (char_u *)&p_cpp, PV_NONE, did_set_completepopup,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"completeslash",   "csl",  P_STRING|P_VI_DEF|P_VIM,
 #if defined(BACKSLASH_IN_FILENAME)
-			    (char_u *)&p_csl, PV_CSL,
+			    (char_u *)&p_csl, PV_CSL, did_set_completeslash,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"confirm",     "cf",   P_BOOL|P_VI_DEF,
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-			    (char_u *)&p_confirm, PV_NONE,
+			    (char_u *)&p_confirm, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"conskey",	    "consk",P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"copyindent",  "ci",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_ci, PV_CI,
+			    (char_u *)&p_ci, PV_CI, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"cpoptions",   "cpo",  P_STRING|P_VIM|P_RALL|P_FLAGLIST,
-			    (char_u *)&p_cpo, PV_NONE,
+			    (char_u *)&p_cpo, PV_NONE, NULL,
 			    {(char_u *)CPO_VI, (char_u *)CPO_VIM}
 			    SCTX_INIT},
     {"cryptmethod", "cm",   P_STRING|P_ALLOCED|P_VI_DEF,
 #ifdef FEAT_CRYPT
-			    (char_u *)&p_cm, PV_CM,
+			    (char_u *)&p_cm, PV_CM, did_set_cryptmethod,
 			    {(char_u *)"blowfish2", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"cscopepathcomp", "cspc", P_NUM|P_VI_DEF|P_VIM,
 #ifdef FEAT_CSCOPE
-			    (char_u *)&p_cspc, PV_NONE,
+			    (char_u *)&p_cspc, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"cscopeprg",   "csprg", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #ifdef FEAT_CSCOPE
-			    (char_u *)&p_csprg, PV_NONE,
+			    (char_u *)&p_csprg, PV_NONE, NULL,
 			    {(char_u *)"cscope", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"cscopequickfix", "csqf", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #if defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)
 			    (char_u *)&p_csqf, PV_NONE,
+			    did_set_cscopequickfix,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"cscoperelative", "csre", P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_CSCOPE
-			    (char_u *)&p_csre, PV_NONE,
+			    (char_u *)&p_csre, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"cscopetag",   "cst",  P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_CSCOPE
-			    (char_u *)&p_cst, PV_NONE,
+			    (char_u *)&p_cst, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"cscopetagorder", "csto", P_NUM|P_VI_DEF|P_VIM,
 #ifdef FEAT_CSCOPE
-			    (char_u *)&p_csto, PV_NONE,
+			    (char_u *)&p_csto, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"cscopeverbose", "csverb", P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_CSCOPE
-			    (char_u *)&p_csverbose, PV_NONE,
+			    (char_u *)&p_csverbose, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"cursorbind",  "crb",  P_BOOL|P_VI_DEF,
-			    (char_u *)VAR_WIN, PV_CRBIND,
+			    (char_u *)VAR_WIN, PV_CRBIND, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"cursorcolumn", "cuc", P_BOOL|P_VI_DEF|P_RWINONLY,
 #ifdef FEAT_SYN_HL
-			    (char_u *)VAR_WIN, PV_CUC,
+			    (char_u *)VAR_WIN, PV_CUC, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"cursorline",   "cul", P_BOOL|P_VI_DEF|P_RWINONLY,
 #ifdef FEAT_SYN_HL
-			    (char_u *)VAR_WIN, PV_CUL,
+			    (char_u *)VAR_WIN, PV_CUL, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"cursorlineopt", "culopt", P_STRING|P_VI_DEF|P_RWIN|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_SYN_HL
-			    (char_u *)VAR_WIN, PV_CULOPT,
+			    (char_u *)VAR_WIN, PV_CULOPT, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"both", (char_u *)0L} SCTX_INIT},
     {"debug",	    NULL,   P_STRING|P_VI_DEF,
-			    (char_u *)&p_debug, PV_NONE,
+			    (char_u *)&p_debug, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"define",	    "def",  P_STRING|P_ALLOCED|P_VI_DEF|P_CURSWANT,
 #ifdef FEAT_FIND_ID
-			    (char_u *)&p_def, PV_DEF,
+			    (char_u *)&p_def, PV_DEF, NULL,
 			    {(char_u *)"^\\s*#\\s*define", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"delcombine", "deco",  P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_deco, PV_NONE,
+			    (char_u *)&p_deco, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"dictionary",  "dict", P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP|P_NDNAME,
-			    (char_u *)&p_dict, PV_DICT,
+			    (char_u *)&p_dict, PV_DICT, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"diff",	    NULL,   P_BOOL|P_VI_DEF|P_RWIN|P_NOGLOB,
 #ifdef FEAT_DIFF
-			    (char_u *)VAR_WIN, PV_DIFF,
+			    (char_u *)VAR_WIN, PV_DIFF, did_set_diff,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"diffexpr",    "dex",  P_STRING|P_VI_DEF|P_SECURE|P_CURSWANT,
 #if defined(FEAT_DIFF) && defined(FEAT_EVAL)
-			    (char_u *)&p_dex, PV_NONE,
+			    (char_u *)&p_dex, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"diffopt",	    "dip",  P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN|P_ONECOMMA
 								     |P_NODUP,
 #ifdef FEAT_DIFF
-			    (char_u *)&p_dip, PV_NONE,
+			    (char_u *)&p_dip, PV_NONE, did_set_diffopt,
 			    {(char_u *)"internal,filler,closeoff",
 								(char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)NULL}
 #endif
 			    SCTX_INIT},
     {"digraph",	    "dg",   P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_DIGRAPHS
-			    (char_u *)&p_dg, PV_NONE,
+			    (char_u *)&p_dg, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"directory",   "dir",  P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA
 							    |P_NODUP|P_SECURE,
-			    (char_u *)&p_dir, PV_NONE,
+			    (char_u *)&p_dir, PV_NONE, NULL,
 			    {(char_u *)DFLT_DIR, (char_u *)0L} SCTX_INIT},
     {"display",	    "dy",   P_STRING|P_VI_DEF|P_ONECOMMA|P_RALL|P_NODUP,
-			    (char_u *)&p_dy, PV_NONE,
+			    (char_u *)&p_dy, PV_NONE, did_set_display,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"eadirection", "ead",  P_STRING|P_VI_DEF,
-			    (char_u *)&p_ead, PV_NONE,
+			    (char_u *)&p_ead, PV_NONE, NULL,
 			    {(char_u *)"both", (char_u *)0L}
 			    SCTX_INIT},
     {"edcompatible","ed",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_ed, PV_NONE,
+			    (char_u *)&p_ed, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"emoji",      "emo",   P_BOOL|P_VI_DEF|P_RCLR,
-			    (char_u *)&p_emoji, PV_NONE,
+			    (char_u *)&p_emoji, PV_NONE, did_set_ambiwidth,
 			    {(char_u *)TRUE, (char_u *)0L}
 			    SCTX_INIT},
     {"encoding",    "enc",  P_STRING|P_VI_DEF|P_RCLR|P_NO_ML,
-			    (char_u *)&p_enc, PV_NONE,
+			    (char_u *)&p_enc, PV_NONE, NULL,
 			    {(char_u *)ENC_DFLT, (char_u *)0L}
 			    SCTX_INIT},
     {"endoffile",   "eof",  P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
 			    (char_u *)&p_eof, PV_EOF,
+			    did_set_eof_eol_fixeol_bomb,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"endofline",   "eol",  P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
 			    (char_u *)&p_eol, PV_EOL,
+			    did_set_eof_eol_fixeol_bomb,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"equalalways", "ea",   P_BOOL|P_VI_DEF|P_RALL,
-			    (char_u *)&p_ea, PV_NONE,
+			    (char_u *)&p_ea, PV_NONE, did_set_equalalways,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"equalprg",    "ep",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_ep, PV_EP,
+			    (char_u *)&p_ep, PV_EP, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"errorbells",  "eb",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_eb, PV_NONE,
+			    (char_u *)&p_eb, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"errorfile",   "ef",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #ifdef FEAT_QUICKFIX
-			    (char_u *)&p_ef, PV_NONE,
+			    (char_u *)&p_ef, PV_NONE, NULL,
 			    {(char_u *)DFLT_ERRORFILE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"errorformat", "efm",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_QUICKFIX
-			    (char_u *)&p_efm, PV_EFM,
+			    (char_u *)&p_efm, PV_EFM, NULL,
 			    {(char_u *)DFLT_EFM, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"esckeys",	    "ek",   P_BOOL|P_VIM,
-			    (char_u *)&p_ek, PV_NONE,
+			    (char_u *)&p_ek, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
     {"eventignore", "ei",   P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_ei, PV_NONE,
+			    (char_u *)&p_ei, PV_NONE, did_set_eventignore,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"expandtab",   "et",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_et, PV_ET,
+			    (char_u *)&p_et, PV_ET, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"exrc",	    "ex",   P_BOOL|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_exrc, PV_NONE,
+			    (char_u *)&p_exrc, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"fileencoding","fenc", P_STRING|P_ALLOCED|P_VI_DEF|P_RSTAT|P_RBUF
 								   |P_NO_MKRC,
-			    (char_u *)&p_fenc, PV_FENC,
+			    (char_u *)&p_fenc, PV_FENC, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"fileencodings","fencs", P_STRING|P_VI_DEF|P_ONECOMMA,
-			    (char_u *)&p_fencs, PV_NONE,
+			    (char_u *)&p_fencs, PV_NONE, NULL,
 			    {(char_u *)"ucs-bom", (char_u *)0L}
 			    SCTX_INIT},
     {"fileformat",  "ff",   P_STRING|P_ALLOCED|P_VI_DEF|P_RSTAT|P_NO_MKRC
 								  |P_CURSWANT,
-			    (char_u *)&p_ff, PV_FF,
+			    (char_u *)&p_ff, PV_FF, did_set_fileformat,
 			    {(char_u *)DFLT_FF, (char_u *)0L} SCTX_INIT},
     {"fileformats", "ffs",  P_STRING|P_VIM|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_ffs, PV_NONE,
+			    (char_u *)&p_ffs, PV_NONE, did_set_fileformats,
 			    {(char_u *)DFLT_FFS_VI, (char_u *)DFLT_FFS_VIM}
 			    SCTX_INIT},
     {"fileignorecase", "fic", P_BOOL|P_VI_DEF,
-			    (char_u *)&p_fic, PV_NONE,
+			    (char_u *)&p_fic, PV_NONE, NULL,
 			    {
 #ifdef CASE_INSENSITIVE_FILENAME
 				    (char_u *)TRUE,
@@ -927,189 +938,190 @@ static struct vimoption options[] =
 #endif
 					(char_u *)0L} SCTX_INIT},
     {"filetype",    "ft",   P_STRING|P_EXPAND|P_ALLOCED|P_VI_DEF|P_NOGLOB|P_NFNAME,
-			    (char_u *)&p_ft, PV_FT,
+			    (char_u *)&p_ft, PV_FT, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"fillchars",   "fcs",  P_STRING|P_VI_DEF|P_RALL|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_fcs, PV_FCS,
+			    (char_u *)&p_fcs, PV_FCS, NULL,
 			    {(char_u *)"vert:|,fold:-,eob:~,lastline:@",
 								  (char_u *)0L}
 			    SCTX_INIT},
     {"fixendofline",  "fixeol", P_BOOL|P_VI_DEF|P_RSTAT,
 			    (char_u *)&p_fixeol, PV_FIXEOL,
+			    did_set_eof_eol_fixeol_bomb,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"fkmap",	    "fk",   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"flash",	    "fl",   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"foldclose",   "fcl",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP|P_RWIN,
 #ifdef FEAT_FOLDING
-			    (char_u *)&p_fcl, PV_NONE,
+			    (char_u *)&p_fcl, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldcolumn",  "fdc",  P_NUM|P_VI_DEF|P_RWIN,
 #ifdef FEAT_FOLDING
-			    (char_u *)VAR_WIN, PV_FDC,
+			    (char_u *)VAR_WIN, PV_FDC, did_set_foldcolumn,
 			    {(char_u *)FALSE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldenable",  "fen",  P_BOOL|P_VI_DEF|P_RWIN,
 #ifdef FEAT_FOLDING
-			    (char_u *)VAR_WIN, PV_FEN,
+			    (char_u *)VAR_WIN, PV_FEN, NULL,
 			    {(char_u *)TRUE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldexpr",    "fde",  P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN|P_MLE,
 #if defined(FEAT_FOLDING) && defined(FEAT_EVAL)
-			    (char_u *)VAR_WIN, PV_FDE,
+			    (char_u *)VAR_WIN, PV_FDE, NULL,
 			    {(char_u *)"0", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldignore",  "fdi",  P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
 #ifdef FEAT_FOLDING
-			    (char_u *)VAR_WIN, PV_FDI,
+			    (char_u *)VAR_WIN, PV_FDI, did_set_foldignore,
 			    {(char_u *)"#", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldlevel",   "fdl",  P_NUM|P_VI_DEF|P_RWIN,
 #ifdef FEAT_FOLDING
-			    (char_u *)VAR_WIN, PV_FDL,
+			    (char_u *)VAR_WIN, PV_FDL, did_set_foldlevel,
 			    {(char_u *)0L, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldlevelstart","fdls", P_NUM|P_VI_DEF|P_CURSWANT,
 #ifdef FEAT_FOLDING
-			    (char_u *)&p_fdls, PV_NONE,
+			    (char_u *)&p_fdls, PV_NONE, NULL,
 			    {(char_u *)-1L, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldmarker",  "fmr",  P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|
 						    P_RWIN|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_FOLDING
-			    (char_u *)VAR_WIN, PV_FMR,
+			    (char_u *)VAR_WIN, PV_FMR, did_set_foldmarker,
 			    {(char_u *)"{{{,}}}", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldmethod",  "fdm",  P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN,
 #ifdef FEAT_FOLDING
-			    (char_u *)VAR_WIN, PV_FDM,
+			    (char_u *)VAR_WIN, PV_FDM, did_set_foldmethod,
 			    {(char_u *)"manual", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldminlines","fml",  P_NUM|P_VI_DEF|P_RWIN,
 #ifdef FEAT_FOLDING
-			    (char_u *)VAR_WIN, PV_FML,
+			    (char_u *)VAR_WIN, PV_FML, did_set_foldminlines,
 			    {(char_u *)1L, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldnestmax", "fdn",  P_NUM|P_VI_DEF|P_RWIN,
 #ifdef FEAT_FOLDING
-			    (char_u *)VAR_WIN, PV_FDN,
+			    (char_u *)VAR_WIN, PV_FDN, did_set_foldnestmax,
 			    {(char_u *)20L, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldopen",    "fdo",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP|P_CURSWANT,
 #ifdef FEAT_FOLDING
-			    (char_u *)&p_fdo, PV_NONE,
+			    (char_u *)&p_fdo, PV_NONE, NULL,
 		 {(char_u *)"block,hor,mark,percent,quickfix,search,tag,undo",
 						 (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"foldtext",    "fdt",  P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN|P_MLE,
 #if defined(FEAT_FOLDING) && defined(FEAT_EVAL)
-			    (char_u *)VAR_WIN, PV_FDT,
+			    (char_u *)VAR_WIN, PV_FDT, NULL,
 			    {(char_u *)"foldtext()", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"formatexpr", "fex",   P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE,
 #ifdef FEAT_EVAL
-			    (char_u *)&p_fex, PV_FEX,
+			    (char_u *)&p_fex, PV_FEX, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"formatoptions","fo",  P_STRING|P_ALLOCED|P_VIM|P_FLAGLIST,
-			    (char_u *)&p_fo, PV_FO,
+			    (char_u *)&p_fo, PV_FO, NULL,
 			    {(char_u *)DFLT_FO_VI, (char_u *)DFLT_FO_VIM}
 			    SCTX_INIT},
     {"formatlistpat","flp", P_STRING|P_ALLOCED|P_VI_DEF,
-			    (char_u *)&p_flp, PV_FLP,
+			    (char_u *)&p_flp, PV_FLP, NULL,
 			    {(char_u *)"^\\s*\\d\\+[\\]:.)}\\t ]\\s*",
 						 (char_u *)0L} SCTX_INIT},
     {"formatprg",   "fp",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_fp, PV_FP,
+			    (char_u *)&p_fp, PV_FP, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"fsync",       "fs",   P_BOOL|P_SECURE|P_VI_DEF,
 #ifdef HAVE_FSYNC
-			    (char_u *)&p_fs, PV_NONE,
+			    (char_u *)&p_fs, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"gdefault",    "gd",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_gd, PV_NONE,
+			    (char_u *)&p_gd, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"graphic",	    "gr",   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"grepformat",  "gfm",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_QUICKFIX
-			    (char_u *)&p_gefm, PV_NONE,
+			    (char_u *)&p_gefm, PV_NONE, NULL,
 			    {(char_u *)DFLT_GREPFORMAT, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"grepprg",	    "gp",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #ifdef FEAT_QUICKFIX
-			    (char_u *)&p_gp, PV_GP,
+			    (char_u *)&p_gp, PV_GP, NULL,
 			    {
 # if defined(MSWIN)
 			    // may be changed to "grep -n" in os_win32.c
@@ -1125,13 +1137,13 @@ static struct vimoption options[] =
 # endif
 			    (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"guicursor",    "gcr", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef CURSOR_SHAPE
-			    (char_u *)&p_guicursor, PV_NONE,
+			    (char_u *)&p_guicursor, PV_NONE, NULL,
 			    {
 # ifdef FEAT_GUI
 				(char_u *)"n-v-c:block-Cursor/lCursor,ve:ver35-Cursor,o:hor50-Cursor,i-ci:ver25-Cursor/lCursor,r-cr:hor20-Cursor/lCursor,sm:block-Cursor-blinkwait175-blinkoff150-blinkon175",
@@ -1140,34 +1152,36 @@ static struct vimoption options[] =
 # endif
 				    (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"guifont",	    "gfn",  P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_GUI
-			    (char_u *)&p_guifont, PV_NONE,
+			    (char_u *)&p_guifont, PV_NONE, did_set_guifont,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"guifontset",  "gfs",  P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA,
 #if defined(FEAT_GUI) && defined(FEAT_XFONTSET)
 			    (char_u *)&p_guifontset, PV_NONE,
+			    did_set_guifontset,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"guifontwide", "gfw",  P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP,
 #if defined(FEAT_GUI)
 			    (char_u *)&p_guifontwide, PV_NONE,
+			    did_set_guifontwide,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
@@ -1176,9 +1190,10 @@ static struct vimoption options[] =
     {"guiligatures", "gli", P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP,
 #if defined(FEAT_GUI_GTK)
 			    (char_u *)&p_guiligatures, PV_NONE,
+			    did_set_guiligatures,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
@@ -1186,200 +1201,215 @@ static struct vimoption options[] =
 
     {"guiheadroom", "ghr",  P_NUM|P_VI_DEF,
 #if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)
-			    (char_u *)&p_ghr, PV_NONE,
+			    (char_u *)&p_ghr, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)50L, (char_u *)0L} SCTX_INIT},
     {"guioptions",  "go",   P_STRING|P_VI_DEF|P_RALL|P_FLAGLIST,
 #if defined(FEAT_GUI)
-			    (char_u *)&p_go, PV_NONE,
+			    (char_u *)&p_go, PV_NONE, did_set_guioptions,
 # if defined(UNIX)
 			    {(char_u *)"aegimrLtT", (char_u *)0L}
 # else
 			    {(char_u *)"egmrLtT", (char_u *)0L}
 # endif
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"guipty",	    NULL,   P_BOOL|P_VI_DEF,
 #if defined(FEAT_GUI)
-			    (char_u *)&p_guipty, PV_NONE,
+			    (char_u *)&p_guipty, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"guitablabel",  "gtl", P_STRING|P_VI_DEF|P_RWIN|P_MLE,
 #if defined(FEAT_GUI_TABLINE)
-			    (char_u *)&p_gtl, PV_NONE,
+			    (char_u *)&p_gtl, PV_NONE, did_set_guitablabel,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"guitabtooltip",  "gtt", P_STRING|P_VI_DEF|P_RWIN,
 #if defined(FEAT_GUI_TABLINE)
-			    (char_u *)&p_gtt, PV_NONE,
+			    (char_u *)&p_gtt, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"hardtabs",    "ht",   P_NUM|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"helpfile",    "hf",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_hf, PV_NONE,
+			    (char_u *)&p_hf, PV_NONE, did_set_helpfile,
 			    {(char_u *)DFLT_HELPFILE, (char_u *)0L}
 			    SCTX_INIT},
     {"helpheight",  "hh",   P_NUM|P_VI_DEF,
 			    (char_u *)&p_hh, PV_NONE,
+			    did_set_winheight_helpheight,
 			    {(char_u *)20L, (char_u *)0L} SCTX_INIT},
     {"helplang",    "hlg",  P_STRING|P_VI_DEF|P_ONECOMMA,
 #ifdef FEAT_MULTI_LANG
-			    (char_u *)&p_hlg, PV_NONE,
+			    (char_u *)&p_hlg, PV_NONE, did_set_helplang,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"hidden",	    "hid",  P_BOOL|P_VI_DEF,
-			    (char_u *)&p_hid, PV_NONE,
+			    (char_u *)&p_hid, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"highlight",   "hl",   P_STRING|P_VI_DEF|P_RCLR|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_hl, PV_NONE,
+			    (char_u *)&p_hl, PV_NONE, did_set_highlight,
 			    {(char_u *)HIGHLIGHT_INIT, (char_u *)0L}
 			    SCTX_INIT},
     {"history",	    "hi",   P_NUM|P_VIM,
-			    (char_u *)&p_hi, PV_NONE,
+			    (char_u *)&p_hi, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)50L} SCTX_INIT},
     {"hkmap",	    "hk",   P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_RIGHTLEFT
-			    (char_u *)&p_hkmap, PV_NONE,
+			    (char_u *)&p_hkmap, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"hkmapp",	    "hkp",  P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_RIGHTLEFT
-			    (char_u *)&p_hkmapp, PV_NONE,
+			    (char_u *)&p_hkmapp, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"hlsearch",    "hls",  P_BOOL|P_VI_DEF|P_VIM|P_RALL,
-			    (char_u *)&p_hls, PV_NONE,
+#if defined(FEAT_SEARCH_EXTRA)
+			    (char_u *)&p_hls, PV_NONE, did_set_hlsearch,
+#else
+			    (char_u *)NULL, PV_NONE, NULL,
+#endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"icon",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_icon, PV_NONE,
+			    (char_u *)&p_icon, PV_NONE, did_set_title_icon,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"iconstring",  NULL,   P_STRING|P_VI_DEF|P_MLE,
 			    (char_u *)&p_iconstring, PV_NONE,
+			    did_set_iconstring,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"ignorecase",  "ic",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_ic, PV_NONE,
+			    (char_u *)&p_ic, PV_NONE, did_set_ignorecase,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"imactivatefunc","imaf",P_STRING|P_VI_DEF|P_SECURE|P_FUNC,
-#if defined(FEAT_EVAL)
+#if defined(FEAT_EVAL) && \
+	(defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
 			    (char_u *)&p_imaf, PV_NONE,
+			    did_set_imactivatefunc,
 			    {(char_u *)"", (char_u *)NULL}
 # else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 # endif
 			    SCTX_INIT},
     {"imactivatekey","imak",P_STRING|P_VI_DEF,
 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
 			    (char_u *)&p_imak, PV_NONE,
+			    did_set_imactivatekey,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"imcmdline",   "imc",  P_BOOL|P_VI_DEF,
-			    (char_u *)&p_imcmdline, PV_NONE,
+			    (char_u *)&p_imcmdline, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"imdisable",   "imd",  P_BOOL|P_VI_DEF,
+#if defined(HAVE_INPUT_METHOD)
 			    (char_u *)&p_imdisable, PV_NONE,
+			    did_set_imdisable,
+#else
+			    (char_u *)NULL, PV_NONE, NULL,
+#endif
 			    {(char_u *)FALSE, (char_u *)0L}
 			    SCTX_INIT},
     {"iminsert",    "imi",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_iminsert, PV_IMI,
+			    (char_u *)&p_iminsert, PV_IMI, did_set_iminsert,
 			    {(char_u *)B_IMODE_NONE, (char_u *)0L}
 			    SCTX_INIT},
     {"imsearch",    "ims",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_imsearch, PV_IMS,
+			    (char_u *)&p_imsearch, PV_IMS, did_set_imsearch,
 			    {(char_u *)B_IMODE_USE_INSERT, (char_u *)0L}
 			    SCTX_INIT},
     {"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE|P_FUNC,
-#if defined(FEAT_EVAL)
-			    (char_u *)&p_imsf, PV_NONE,
+#if defined(FEAT_EVAL) && \
+	(defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
+			    (char_u *)&p_imsf, PV_NONE, did_set_imstatusfunc,
 			    {(char_u *)"", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"imstyle",	    "imst", P_NUM|P_VI_DEF|P_SECURE,
 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
-			    (char_u *)&p_imst, PV_NONE,
+			    (char_u *)&p_imst, PV_NONE, did_set_imstyle,
 			    {(char_u *)IM_OVER_THE_SPOT, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"include",	    "inc",  P_STRING|P_ALLOCED|P_VI_DEF,
 #ifdef FEAT_FIND_ID
-			    (char_u *)&p_inc, PV_INC,
+			    (char_u *)&p_inc, PV_INC, NULL,
 			    {(char_u *)"^\\s*#\\s*include", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"includeexpr", "inex", P_STRING|P_ALLOCED|P_VI_DEF|P_MLE,
 #if defined(FEAT_FIND_ID) && defined(FEAT_EVAL)
-			    (char_u *)&p_inex, PV_INEX,
+			    (char_u *)&p_inex, PV_INEX, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"incsearch",   "is",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_is, PV_NONE,
+			    (char_u *)&p_is, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"indentexpr", "inde",  P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE,
 #if defined(FEAT_EVAL)
-			    (char_u *)&p_inde, PV_INDE,
+			    (char_u *)&p_inde, PV_INDE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"indentkeys", "indk",  P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #if defined(FEAT_EVAL)
-			    (char_u *)&p_indk, PV_INDK,
+			    (char_u *)&p_indk, PV_INDK, NULL,
 			    {INDENTKEYS_DEFAULT, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"infercase",   "inf",  P_BOOL|P_VI_DEF,
-			    (char_u *)&p_inf, PV_INF,
+			    (char_u *)&p_inf, PV_INF, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"insertmode",  "im",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_im, PV_NONE,
+			    (char_u *)&p_im, PV_NONE, did_set_insertmode,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"isfname",	    "isf",  P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
-			    (char_u *)&p_isf, PV_NONE,
+			    (char_u *)&p_isf, PV_NONE, NULL,
 			    {
 #ifdef BACKSLASH_IN_FILENAME
 				// Excluded are: & and ^ are special in cmd.exe
@@ -1396,7 +1426,7 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"isident",	    "isi",  P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
-			    (char_u *)&p_isi, PV_NONE,
+			    (char_u *)&p_isi, PV_NONE, NULL,
 			    {
 #if defined(MSWIN)
 			    (char_u *)"@,48-57,_,128-167,224-235",
@@ -1405,7 +1435,7 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"iskeyword",   "isk",  P_STRING|P_ALLOCED|P_VIM|P_COMMA|P_NODUP,
-			    (char_u *)&p_isk, PV_ISK,
+			    (char_u *)&p_isk, PV_ISK, NULL,
 			    {
 				(char_u *)"@,48-57,_",
 #if defined(MSWIN)
@@ -1415,7 +1445,7 @@ static struct vimoption options[] =
 #endif
 			    } SCTX_INIT},
     {"isprint",	    "isp",  P_STRING|P_VI_DEF|P_RALL|P_COMMA|P_NODUP,
-			    (char_u *)&p_isp, PV_NONE,
+			    (char_u *)&p_isp, PV_NONE, NULL,
 			    {
 #if defined(MSWIN) || defined(VMS)
 			    (char_u *)"@,~-255",
@@ -1424,35 +1454,35 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"joinspaces",  "js",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_js, PV_NONE,
+			    (char_u *)&p_js, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"key",	    NULL,   P_STRING|P_ALLOCED|P_VI_DEF|P_NO_MKRC,
 #ifdef FEAT_CRYPT
-			    (char_u *)&p_key, PV_KEY,
+			    (char_u *)&p_key, PV_KEY, did_set_cryptkey,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"keymap",	    "kmp",  P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF|P_RSTAT|P_NFNAME|P_PRI_MKRC,
 #ifdef FEAT_KEYMAP
-			    (char_u *)&p_keymap, PV_KMAP,
+			    (char_u *)&p_keymap, PV_KMAP, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"keymodel",    "km",   P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_km, PV_NONE,
+			    (char_u *)&p_km, PV_NONE, did_set_keymodel,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"keyprotocol", "kpc",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_kpc, PV_NONE,
+			    (char_u *)&p_kpc, PV_NONE, did_set_keyprotocol,
 			    {(char_u *)"kitty:kitty,foot:kitty,wezterm:kitty,xterm:mok2", (char_u *)0L}
 			    SCTX_INIT},
     {"keywordprg",  "kp",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_kp, PV_KP,
+			    (char_u *)&p_kp, PV_KP, NULL,
 			    {
 #if defined(MSWIN)
 			    (char_u *)":help",
@@ -1466,49 +1496,49 @@ static struct vimoption options[] =
 				(char_u *)0L} SCTX_INIT},
     {"langmap",     "lmap", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP|P_SECURE,
 #ifdef FEAT_LANGMAP
-			    (char_u *)&p_langmap, PV_NONE,
+			    (char_u *)&p_langmap, PV_NONE, did_set_langmap,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"langmenu",    "lm",   P_STRING|P_VI_DEF|P_NFNAME,
 #if defined(FEAT_MENU) && defined(FEAT_MULTI_LANG)
-			    (char_u *)&p_lm, PV_NONE,
+			    (char_u *)&p_lm, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"langnoremap",  "lnr",   P_BOOL|P_VI_DEF,
 #ifdef FEAT_LANGMAP
-			    (char_u *)&p_lnr, PV_NONE,
+			    (char_u *)&p_lnr, PV_NONE, did_set_langnoremap,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"langremap",  "lrm",   P_BOOL|P_VI_DEF,
 #ifdef FEAT_LANGMAP
-			    (char_u *)&p_lrm, PV_NONE,
+			    (char_u *)&p_lrm, PV_NONE, did_set_langremap,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"laststatus",  "ls",   P_NUM|P_VI_DEF|P_RALL,
-			    (char_u *)&p_ls, PV_NONE,
+			    (char_u *)&p_ls, PV_NONE, did_set_laststatus,
 			    {(char_u *)1L, (char_u *)0L} SCTX_INIT},
     {"lazyredraw",  "lz",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_lz, PV_NONE,
+			    (char_u *)&p_lz, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"linebreak",   "lbr",  P_BOOL|P_VI_DEF|P_RWIN,
 #ifdef FEAT_LINEBREAK
-			    (char_u *)VAR_WIN, PV_LBR,
+			    (char_u *)VAR_WIN, PV_LBR, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"lines",	    NULL,   P_NUM|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RCLR,
-			    (char_u *)&Rows, PV_NONE,
+			    (char_u *)&Rows, PV_NONE, NULL,
 			    {
 #if defined(MSWIN)
 			    (char_u *)25L,
@@ -1519,8 +1549,9 @@ static struct vimoption options[] =
     {"linespace",   "lsp",  P_NUM|P_VI_DEF|P_RCLR,
 #ifdef FEAT_GUI
 			    (char_u *)&p_linespace, PV_NONE,
+			    did_set_linespace,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 #ifdef FEAT_GUI_MSWIN
 			    {(char_u *)1L, (char_u *)0L}
@@ -1529,135 +1560,135 @@ static struct vimoption options[] =
 #endif
 			    SCTX_INIT},
     {"lisp",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_lisp, PV_LISP,
+			    (char_u *)&p_lisp, PV_LISP, did_set_lisp,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"lispoptions", "lop",  P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_lop, PV_LOP,
+			    (char_u *)&p_lop, PV_LOP, did_set_lispoptions,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"lispwords",   "lw",   P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_lispwords, PV_LW,
+			    (char_u *)&p_lispwords, PV_LW, NULL,
 			    {(char_u *)LISPWORD_VALUE, (char_u *)0L} SCTX_INIT},
     {"list",	    NULL,   P_BOOL|P_VI_DEF|P_RWIN,
-			    (char_u *)VAR_WIN, PV_LIST,
+			    (char_u *)VAR_WIN, PV_LIST, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"listchars",   "lcs",  P_STRING|P_VI_DEF|P_RALL|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_lcs, PV_LCS,
+			    (char_u *)&p_lcs, PV_LCS, NULL,
 			    {(char_u *)"eol:$", (char_u *)0L} SCTX_INIT},
     {"loadplugins", "lpl",  P_BOOL|P_VI_DEF,
-			    (char_u *)&p_lpl, PV_NONE,
+			    (char_u *)&p_lpl, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"luadll",      NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(DYNAMIC_LUA)
-			    (char_u *)&p_luadll, PV_NONE,
+			    (char_u *)&p_luadll, PV_NONE, NULL,
 			    {(char_u *)DYNAMIC_LUA_DLL, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"macatsui",    NULL,   P_BOOL|P_VI_DEF|P_RCLR,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"magic",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_magic, PV_NONE,
+			    (char_u *)&p_magic, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"makeef",	    "mef",  P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #ifdef FEAT_QUICKFIX
-			    (char_u *)&p_mef, PV_NONE,
+			    (char_u *)&p_mef, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"makeencoding","menc", P_STRING|P_VI_DEF,
-			    (char_u *)&p_menc, PV_MENC,
+			    (char_u *)&p_menc, PV_MENC, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"makeprg",	    "mp",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #ifdef FEAT_QUICKFIX
-			    (char_u *)&p_mp, PV_MP,
+			    (char_u *)&p_mp, PV_MP, NULL,
 # ifdef VMS
 			    {(char_u *)"MMS", (char_u *)0L}
 # else
 			    {(char_u *)"make", (char_u *)0L}
 # endif
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"matchpairs",  "mps",  P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_mps, PV_MPS,
+			    (char_u *)&p_mps, PV_MPS, did_set_matchpairs,
 			    {(char_u *)"(:),{:},[:]", (char_u *)0L}
 			    SCTX_INIT},
     {"matchtime",   "mat",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_mat, PV_NONE,
+			    (char_u *)&p_mat, PV_NONE, NULL,
 			    {(char_u *)5L, (char_u *)0L} SCTX_INIT},
     {"maxcombine",  "mco",  P_NUM|P_VI_DEF|P_CURSWANT,
-			    (char_u *)&p_mco, PV_NONE,
+			    (char_u *)&p_mco, PV_NONE, did_set_maxcombine,
 			    {(char_u *)2, (char_u *)0L} SCTX_INIT},
     {"maxfuncdepth", "mfd", P_NUM|P_VI_DEF,
 #ifdef FEAT_EVAL
-			    (char_u *)&p_mfd, PV_NONE,
+			    (char_u *)&p_mfd, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)100L, (char_u *)0L} SCTX_INIT},
     {"maxmapdepth", "mmd",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_mmd, PV_NONE,
+			    (char_u *)&p_mmd, PV_NONE, NULL,
 			    {(char_u *)1000L, (char_u *)0L} SCTX_INIT},
     {"maxmem",	    "mm",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_mm, PV_NONE,
+			    (char_u *)&p_mm, PV_NONE, NULL,
 			    {(char_u *)DFLT_MAXMEM, (char_u *)0L}
 			    SCTX_INIT},
     {"maxmempattern","mmp", P_NUM|P_VI_DEF,
-			    (char_u *)&p_mmp, PV_NONE,
+			    (char_u *)&p_mmp, PV_NONE, NULL,
 			    {(char_u *)1000L, (char_u *)0L} SCTX_INIT},
     {"maxmemtot",   "mmt",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_mmt, PV_NONE,
+			    (char_u *)&p_mmt, PV_NONE, NULL,
 			    {(char_u *)DFLT_MAXMEMTOT, (char_u *)0L}
 			    SCTX_INIT},
     {"menuitems",   "mis",  P_NUM|P_VI_DEF,
 #ifdef FEAT_MENU
-			    (char_u *)&p_mis, PV_NONE,
+			    (char_u *)&p_mis, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)25L, (char_u *)0L} SCTX_INIT},
     {"mesg",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"mkspellmem",  "msm",  P_STRING|P_VI_DEF|P_EXPAND|P_SECURE,
 #ifdef FEAT_SPELL
-			    (char_u *)&p_msm, PV_NONE,
+			    (char_u *)&p_msm, PV_NONE, did_set_mkspellmem,
 			    {(char_u *)"460000,2000,500", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"modeline",    "ml",   P_BOOL|P_VIM,
-			    (char_u *)&p_ml, PV_ML,
+			    (char_u *)&p_ml, PV_ML, NULL,
 			    {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
     {"modelineexpr", "mle",  P_BOOL|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_mle, PV_NONE,
+			    (char_u *)&p_mle, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"modelines",   "mls",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_mls, PV_NONE,
+			    (char_u *)&p_mls, PV_NONE, NULL,
 			    {(char_u *)5L, (char_u *)0L} SCTX_INIT},
     {"modifiable",  "ma",   P_BOOL|P_VI_DEF|P_NOGLOB,
-			    (char_u *)&p_ma, PV_MA,
+			    (char_u *)&p_ma, PV_MA, did_set_modifiable,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"modified",    "mod",  P_BOOL|P_NO_MKRC|P_VI_DEF|P_RSTAT,
-			    (char_u *)&p_mod, PV_MOD,
+			    (char_u *)&p_mod, PV_MOD, did_set_modified,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"more",	    NULL,   P_BOOL|P_VIM,
-			    (char_u *)&p_more, PV_NONE,
+			    (char_u *)&p_more, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
     {"mouse",	    NULL,   P_STRING|P_VI_DEF|P_FLAGLIST,
-			    (char_u *)&p_mouse, PV_NONE,
+			    (char_u *)&p_mouse, PV_NONE, NULL,
 			    {
 #if defined(MSWIN)
 				(char_u *)"a",
@@ -1667,20 +1698,20 @@ static struct vimoption options[] =
 				(char_u *)0L} SCTX_INIT},
     {"mousefocus",   "mousef", P_BOOL|P_VI_DEF,
 #ifdef FEAT_GUI
-			    (char_u *)&p_mousef, PV_NONE,
+			    (char_u *)&p_mousef, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"mousehide",   "mh",   P_BOOL|P_VI_DEF,
 #ifdef FEAT_GUI
-			    (char_u *)&p_mh, PV_NONE,
+			    (char_u *)&p_mh, PV_NONE, did_set_mousehide,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"mousemodel",  "mousem", P_STRING|P_VI_DEF,
-			    (char_u *)&p_mousem, PV_NONE,
+			    (char_u *)&p_mousem, PV_NONE, did_set_mousemodel,
 			    {
 #if defined(MSWIN)
 				(char_u *)"popup",
@@ -1694,123 +1725,127 @@ static struct vimoption options[] =
 				(char_u *)0L} SCTX_INIT},
     {"mousemoveevent",   "mousemev",   P_BOOL|P_VI_DEF,
 #ifdef FEAT_GUI
-			    (char_u *)&p_mousemev, PV_NONE,
+			    (char_u *)&p_mousemev, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"mouseshape",  "mouses",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_MOUSESHAPE
 			    (char_u *)&p_mouseshape, PV_NONE,
+			    did_set_mouseshape,
 			    {(char_u *)"i-r:beam,s:updown,sd:udsizing,vs:leftright,vd:lrsizing,m:no,ml:up-arrow,v:rightup-arrow", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"mousetime",   "mouset",	P_NUM|P_VI_DEF,
-			    (char_u *)&p_mouset, PV_NONE,
+			    (char_u *)&p_mouset, PV_NONE, NULL,
 			    {(char_u *)500L, (char_u *)0L} SCTX_INIT},
     {"mzschemedll", NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(DYNAMIC_MZSCHEME)
-			    (char_u *)&p_mzschemedll, PV_NONE,
+			    (char_u *)&p_mzschemedll, PV_NONE, NULL,
 			    {(char_u *)DYNAMIC_MZSCH_DLL, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"mzschemegcdll", NULL, P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(DYNAMIC_MZSCHEME)
-			    (char_u *)&p_mzschemegcdll, PV_NONE,
+			    (char_u *)&p_mzschemegcdll, PV_NONE, NULL,
 			    {(char_u *)DYNAMIC_MZGC_DLL, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"mzquantum",  "mzq",   P_NUM,
 #ifdef FEAT_MZSCHEME
-			    (char_u *)&p_mzq, PV_NONE,
+			    (char_u *)&p_mzq, PV_NONE, did_set_mzquantum,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)100L, (char_u *)100L} SCTX_INIT},
     {"novice",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"nrformats",   "nf",   P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_nf, PV_NF,
+			    (char_u *)&p_nf, PV_NF, NULL,
 			    {(char_u *)"bin,octal,hex", (char_u *)0L}
 			    SCTX_INIT},
     {"number",	    "nu",   P_BOOL|P_VI_DEF|P_RWIN,
 			    (char_u *)VAR_WIN, PV_NU,
+			    did_set_number_relativenumber,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"numberwidth", "nuw",  P_NUM|P_RWIN|P_VIM,
 #ifdef FEAT_LINEBREAK
-			    (char_u *)VAR_WIN, PV_NUW,
+			    (char_u *)VAR_WIN, PV_NUW, did_set_numberwidth,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)8L, (char_u *)4L} SCTX_INIT},
     {"omnifunc",    "ofu",  P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC,
 #ifdef FEAT_COMPL_FUNC
-			    (char_u *)&p_ofu, PV_OFU,
+			    (char_u *)&p_ofu, PV_OFU, did_set_omnifunc,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"open",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"opendevice",  "odev", P_BOOL|P_VI_DEF,
 #if defined(MSWIN)
-			    (char_u *)&p_odev, PV_NONE,
+			    (char_u *)&p_odev, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)FALSE}
 			    SCTX_INIT},
     {"operatorfunc", "opfunc", P_STRING|P_VI_DEF|P_SECURE|P_FUNC,
 			    (char_u *)&p_opfunc, PV_NONE,
+			    did_set_operatorfunc,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"optimize",    "opt",  P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"osfiletype",  "oft",  P_STRING|P_ALLOCED|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"packpath",    "pp",   P_STRING|P_VI_DEF|P_EXPAND|P_ONECOMMA|P_NODUP
 								    |P_SECURE,
-			    (char_u *)&p_pp, PV_NONE,
+			    (char_u *)&p_pp, PV_NONE, NULL,
 			    {(char_u *)DFLT_RUNTIMEPATH, (char_u *)0L}
 			    SCTX_INIT},
     {"paragraphs",  "para", P_STRING|P_VI_DEF,
-			    (char_u *)&p_para, PV_NONE,
+			    (char_u *)&p_para, PV_NONE, NULL,
 			    {(char_u *)"IPLPPPQPP TPHPLIPpLpItpplpipbp",
 				(char_u *)0L} SCTX_INIT},
     {"paste",	    NULL,   P_BOOL|P_VI_DEF|P_PRI_MKRC,
-			    (char_u *)&p_paste, PV_NONE,
+			    (char_u *)&p_paste, PV_NONE, did_set_paste,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"pastetoggle", "pt",   P_STRING|P_VI_DEF,
-			    (char_u *)&p_pt, PV_NONE,
+			    (char_u *)&p_pt, PV_NONE, did_set_pastetoggle,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"patchexpr",   "pex",  P_STRING|P_VI_DEF|P_SECURE,
 #if defined(FEAT_DIFF) && defined(FEAT_EVAL)
-			    (char_u *)&p_pex, PV_NONE,
+			    (char_u *)&p_pex, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"patchmode",   "pm",   P_STRING|P_VI_DEF|P_NFNAME,
 			    (char_u *)&p_pm, PV_NONE,
+			    did_set_backupext_or_patchmode,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"path",	    "pa",   P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP,
-			    (char_u *)&p_path, PV_PATH,
+			    (char_u *)&p_path, PV_PATH, NULL,
 			    {
 #if defined(AMIGA) || defined(MSWIN)
 			    (char_u *)".,,",
@@ -1820,69 +1855,70 @@ static struct vimoption options[] =
 				(char_u *)0L} SCTX_INIT},
     {"perldll",     NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(DYNAMIC_PERL)
-			    (char_u *)&p_perldll, PV_NONE,
+			    (char_u *)&p_perldll, PV_NONE, NULL,
 			    {(char_u *)DYNAMIC_PERL_DLL, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"preserveindent", "pi", P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_pi, PV_PI,
+			    (char_u *)&p_pi, PV_PI, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"previewheight", "pvh", P_NUM|P_VI_DEF,
 #if defined(FEAT_QUICKFIX)
-			    (char_u *)&p_pvh, PV_NONE,
+			    (char_u *)&p_pvh, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)12L, (char_u *)0L} SCTX_INIT},
     {"previewpopup", "pvp", P_STRING|P_VI_DEF|P_COMMA|P_NODUP,
 #ifdef FEAT_PROP_POPUP
-			    (char_u *)&p_pvp, PV_NONE,
+			    (char_u *)&p_pvp, PV_NONE, did_set_previewpopup,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"previewwindow", "pvw", P_BOOL|P_VI_DEF|P_RSTAT|P_NOGLOB,
 #if defined(FEAT_QUICKFIX)
-			    (char_u *)VAR_WIN, PV_PVW,
+			    (char_u *)VAR_WIN, PV_PVW, did_set_previewwindow,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"printdevice", "pdev", P_STRING|P_VI_DEF|P_SECURE,
 #ifdef FEAT_PRINTER
-			    (char_u *)&p_pdev, PV_NONE,
+			    (char_u *)&p_pdev, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"printencoding", "penc", P_STRING|P_VI_DEF,
 #ifdef FEAT_POSTSCRIPT
 			    (char_u *)&p_penc, PV_NONE,
+			    did_set_printencoding,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"printexpr", "pexpr",  P_STRING|P_VI_DEF|P_SECURE,
 #ifdef FEAT_POSTSCRIPT
-			    (char_u *)&p_pexpr, PV_NONE,
+			    (char_u *)&p_pexpr, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"printfont", "pfn",    P_STRING|P_VI_DEF,
 #ifdef FEAT_PRINTER
-			    (char_u *)&p_pfn, PV_NONE,
+			    (char_u *)&p_pfn, PV_NONE, NULL,
 			    {
 # ifdef MSWIN
 				(char_u *)"Courier_New:h10",
@@ -1891,250 +1927,253 @@ static struct vimoption options[] =
 # endif
 				(char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"printheader", "pheader",  P_STRING|P_VI_DEF|P_GETTEXT,
 #ifdef FEAT_PRINTER
-			    (char_u *)&p_header, PV_NONE,
+			    (char_u *)&p_header, PV_NONE, NULL,
 			    // untranslated to avoid problems when 'encoding'
 			    // is changed
 			    {(char_u *)"%<%f%h%m%=Page %N", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
    {"printmbcharset", "pmbcs",  P_STRING|P_VI_DEF,
 #if defined(FEAT_POSTSCRIPT)
-			    (char_u *)&p_pmcs, PV_NONE,
+			    (char_u *)&p_pmcs, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"printmbfont", "pmbfn",  P_STRING|P_VI_DEF,
 #if defined(FEAT_POSTSCRIPT)
-			    (char_u *)&p_pmfn, PV_NONE,
+			    (char_u *)&p_pmfn, PV_NONE, parse_printmbfont,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"printoptions", "popt", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_PRINTER
-			    (char_u *)&p_popt, PV_NONE,
+			    (char_u *)&p_popt, PV_NONE, parse_printoptions,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"prompt",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_prompt, PV_NONE,
+			    (char_u *)&p_prompt, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"pumheight",   "ph",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_ph, PV_NONE,
+			    (char_u *)&p_ph, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"pumwidth",    "pw",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_pw, PV_NONE,
+			    (char_u *)&p_pw, PV_NONE, NULL,
 			    {(char_u *)15L, (char_u *)15L} SCTX_INIT},
     {"pythonthreedll",  NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(DYNAMIC_PYTHON3)
-			    (char_u *)&p_py3dll, PV_NONE,
+			    (char_u *)&p_py3dll, PV_NONE, NULL,
 			    {(char_u *)DYNAMIC_PYTHON3_DLL, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"pythonthreehome", NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(FEAT_PYTHON3)
-			    (char_u *)&p_py3home, PV_NONE,
+			    (char_u *)&p_py3home, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"pythondll",   NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(DYNAMIC_PYTHON)
-			    (char_u *)&p_pydll, PV_NONE,
+			    (char_u *)&p_pydll, PV_NONE, NULL,
 			    {(char_u *)DYNAMIC_PYTHON_DLL, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"pythonhome",  NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(FEAT_PYTHON)
-			    (char_u *)&p_pyhome, PV_NONE,
+			    (char_u *)&p_pyhome, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"pyxversion", "pyx",   P_NUM|P_VI_DEF|P_SECURE,
 #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
-			    (char_u *)&p_pyx, PV_NONE,
+			    (char_u *)&p_pyx, PV_NONE, did_set_pyxversion,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)DEFAULT_PYTHON_VER, (char_u *)0L}
 			    SCTX_INIT},
     {"quickfixtextfunc", "qftf", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_SECURE|P_FUNC,
 #if defined(FEAT_QUICKFIX) && defined(FEAT_EVAL)
 			    (char_u *)&p_qftf, PV_NONE,
+			    did_set_quickfixtextfunc,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)NULL}
 #endif
 			    SCTX_INIT},
     {"quoteescape", "qe",   P_STRING|P_ALLOCED|P_VI_DEF,
-			    (char_u *)&p_qe, PV_QE,
+			    (char_u *)&p_qe, PV_QE, NULL,
 			    {(char_u *)"\\", (char_u *)0L} SCTX_INIT},
     {"readonly",    "ro",   P_BOOL|P_VI_DEF|P_RSTAT|P_NOGLOB,
-			    (char_u *)&p_ro, PV_RO,
+			    (char_u *)&p_ro, PV_RO, did_set_readonly,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"redraw",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"redrawtime",  "rdt",  P_NUM|P_VI_DEF,
 #ifdef FEAT_RELTIME
-			    (char_u *)&p_rdt, PV_NONE,
+			    (char_u *)&p_rdt, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)2000L, (char_u *)0L} SCTX_INIT},
     {"regexpengine", "re",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_re, PV_NONE,
+			    (char_u *)&p_re, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"relativenumber", "rnu", P_BOOL|P_VI_DEF|P_RWIN,
 			    (char_u *)VAR_WIN, PV_RNU,
+			    did_set_number_relativenumber,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"remap",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_remap, PV_NONE,
+			    (char_u *)&p_remap, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"renderoptions", "rop", P_STRING|P_ONECOMMA|P_RCLR|P_VI_DEF,
 #ifdef FEAT_RENDER_OPTIONS
-			    (char_u *)&p_rop, PV_NONE,
+			    (char_u *)&p_rop, PV_NONE, did_set_renderoptions,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"report",	    NULL,   P_NUM|P_VI_DEF,
-			    (char_u *)&p_report, PV_NONE,
+			    (char_u *)&p_report, PV_NONE, NULL,
 			    {(char_u *)2L, (char_u *)0L} SCTX_INIT},
     {"restorescreen", "rs", P_BOOL|P_VI_DEF,
 #ifdef MSWIN
-			    (char_u *)&p_rs, PV_NONE,
+			    (char_u *)&p_rs, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"revins",	    "ri",   P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_RIGHTLEFT
-			    (char_u *)&p_ri, PV_NONE,
+			    (char_u *)&p_ri, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"rightleft",   "rl",   P_BOOL|P_VI_DEF|P_RWIN,
 #ifdef FEAT_RIGHTLEFT
-			    (char_u *)VAR_WIN, PV_RL,
+			    (char_u *)VAR_WIN, PV_RL, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"rightleftcmd", "rlc", P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN,
 #ifdef FEAT_RIGHTLEFT
-			    (char_u *)VAR_WIN, PV_RLC,
+			    (char_u *)VAR_WIN, PV_RLC, NULL,
 			    {(char_u *)"search", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"rubydll",     NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(DYNAMIC_RUBY)
-			    (char_u *)&p_rubydll, PV_NONE,
+			    (char_u *)&p_rubydll, PV_NONE, NULL,
 			    {(char_u *)DYNAMIC_RUBY_DLL, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"ruler",	    "ru",   P_BOOL|P_VI_DEF|P_VIM|P_RSTAT,
-			    (char_u *)&p_ru, PV_NONE,
+			    (char_u *)&p_ru, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"rulerformat", "ruf",  P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT|P_MLE,
 #ifdef FEAT_STL_OPT
-			    (char_u *)&p_ruf, PV_NONE,
+			    (char_u *)&p_ruf, PV_NONE, did_set_rulerformat,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"runtimepath", "rtp",  P_STRING|P_VI_DEF|P_EXPAND|P_ONECOMMA|P_NODUP
 								    |P_SECURE,
-			    (char_u *)&p_rtp, PV_NONE,
+			    (char_u *)&p_rtp, PV_NONE, NULL,
 			    {(char_u *)DFLT_RUNTIMEPATH, (char_u *)0L}
 			    SCTX_INIT},
     {"scroll",	    "scr",  P_NUM|P_NO_MKRC|P_VI_DEF,
-			    (char_u *)VAR_WIN, PV_SCROLL,
+			    (char_u *)VAR_WIN, PV_SCROLL, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"scrollbind",  "scb",  P_BOOL|P_VI_DEF,
-			    (char_u *)VAR_WIN, PV_SCBIND,
+			    (char_u *)VAR_WIN, PV_SCBIND, did_set_scrollbind,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"scrollfocus", "scf",  P_BOOL|P_VI_DEF,
 #if defined(MSWIN) && defined(FEAT_GUI)
-			    (char_u *)&p_scf, PV_NONE,
+			    (char_u *)&p_scf, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"scrolljump",  "sj",   P_NUM|P_VI_DEF|P_VIM,
-			    (char_u *)&p_sj, PV_NONE,
+			    (char_u *)&p_sj, PV_NONE, NULL,
 			    {(char_u *)1L, (char_u *)0L} SCTX_INIT},
     {"scrolloff",   "so",   P_NUM|P_VI_DEF|P_VIM|P_RALL,
-			    (char_u *)&p_so, PV_SO,
+			    (char_u *)&p_so, PV_SO, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"scrollopt",   "sbo",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_sbo, PV_NONE,
+			    (char_u *)&p_sbo, PV_NONE, NULL,
 			    {(char_u *)"ver,jump", (char_u *)0L}
 			    SCTX_INIT},
     {"sections",    "sect", P_STRING|P_VI_DEF,
-			    (char_u *)&p_sections, PV_NONE,
+			    (char_u *)&p_sections, PV_NONE, NULL,
 			    {(char_u *)"SHNHH HUnhsh", (char_u *)0L}
 			    SCTX_INIT},
     {"secure",	    NULL,   P_BOOL|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_secure, PV_NONE,
+			    (char_u *)&p_secure, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"selection",   "sel",  P_STRING|P_VI_DEF,
-			    (char_u *)&p_sel, PV_NONE,
+			    (char_u *)&p_sel, PV_NONE, did_set_selection,
 			    {(char_u *)"inclusive", (char_u *)0L}
 			    SCTX_INIT},
     {"selectmode",  "slm",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_slm, PV_NONE,
+			    (char_u *)&p_slm, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"sessionoptions", "ssop", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_SESSION
 			    (char_u *)&p_ssop, PV_NONE,
+			    did_set_sessionoptions,
 	 {(char_u *)"blank,buffers,curdir,folds,help,options,tabpages,winsize,terminal",
 							       (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"shell",	    "sh",   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_sh, PV_NONE,
+			    (char_u *)&p_sh, PV_NONE, NULL,
 			    {
 #ifdef VMS
 			    (char_u *)"-",
@@ -2147,7 +2186,7 @@ static struct vimoption options[] =
 #endif // VMS
 				(char_u *)0L} SCTX_INIT},
     {"shellcmdflag","shcf", P_STRING|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_shcf, PV_NONE,
+			    (char_u *)&p_shcf, PV_NONE, NULL,
 			    {
 #if defined(MSWIN)
 			    (char_u *)"/c",
@@ -2157,7 +2196,7 @@ static struct vimoption options[] =
 				(char_u *)0L} SCTX_INIT},
     {"shellpipe",   "sp",   P_STRING|P_VI_DEF|P_SECURE,
 #ifdef FEAT_QUICKFIX
-			    (char_u *)&p_sp, PV_NONE,
+			    (char_u *)&p_sp, PV_NONE, NULL,
 			    {
 #if defined(UNIX)
 			    (char_u *)"| tee",
@@ -2166,35 +2205,35 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"shellquote",  "shq",  P_STRING|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_shq, PV_NONE,
+			    (char_u *)&p_shq, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"shellredir",  "srr",  P_STRING|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_srr, PV_NONE,
+			    (char_u *)&p_srr, PV_NONE, NULL,
 			    {(char_u *)">", (char_u *)0L} SCTX_INIT},
     {"shellslash",  "ssl",   P_BOOL|P_VI_DEF,
 #ifdef BACKSLASH_IN_FILENAME
-			    (char_u *)&p_ssl, PV_NONE,
+			    (char_u *)&p_ssl, PV_NONE, did_set_shellslash,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"shelltemp",   "stmp", P_BOOL,
-			    (char_u *)&p_stmp, PV_NONE,
+			    (char_u *)&p_stmp, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
     {"shelltype",   "st",   P_NUM|P_VI_DEF,
 #ifdef AMIGA
-			    (char_u *)&p_st, PV_NONE,
+			    (char_u *)&p_st, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"shellxquote", "sxq",  P_STRING|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_sxq, PV_NONE,
+			    (char_u *)&p_sxq, PV_NONE, NULL,
 			    {
 #if defined(UNIX) && defined(USE_SYSTEM)
 			    (char_u *)"\"",
@@ -2203,7 +2242,7 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"shellxescape", "sxe", P_STRING|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_sxe, PV_NONE,
+			    (char_u *)&p_sxe, PV_NONE, NULL,
 			    {
 #if defined(MSWIN)
 			    (char_u *)"\"&|<>()@^",
@@ -2212,27 +2251,28 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"shiftround",  "sr",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_sr, PV_NONE,
+			    (char_u *)&p_sr, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"shiftwidth",  "sw",   P_NUM|P_VI_DEF,
 			    (char_u *)&p_sw, PV_SW,
+			    did_set_shiftwidth_tabstop,
 			    {(char_u *)8L, (char_u *)0L} SCTX_INIT},
     {"shortmess",   "shm",  P_STRING|P_VIM|P_FLAGLIST,
-			    (char_u *)&p_shm, PV_NONE,
+			    (char_u *)&p_shm, PV_NONE, NULL,
 			    {(char_u *)"S", (char_u *)"filnxtToOS"}
 			    SCTX_INIT},
     {"shortname",   "sn",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_sn, PV_SN,
+			    (char_u *)&p_sn, PV_SN, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"showbreak",   "sbr",  P_STRING|P_VI_DEF|P_RALL,
 #ifdef FEAT_LINEBREAK
-			    (char_u *)&p_sbr, PV_SBR,
+			    (char_u *)&p_sbr, PV_SBR, did_set_showbreak,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"showcmd",	    "sc",   P_BOOL|P_VIM,
-			    (char_u *)&p_sc, PV_NONE,
+			    (char_u *)&p_sc, PV_NONE, NULL,
 			    {(char_u *)FALSE,
 #ifdef UNIX
 				(char_u *)FALSE
@@ -2241,180 +2281,181 @@ static struct vimoption options[] =
 #endif
 				} SCTX_INIT},
     {"showcmdloc",  "sloc", P_STRING|P_RSTAT,
-			    (char_u *)&p_sloc, PV_NONE,
+			    (char_u *)&p_sloc, PV_NONE, NULL,
 			    {(char_u *)"last", (char_u *)"last"} SCTX_INIT},
     {"showfulltag", "sft",  P_BOOL|P_VI_DEF,
-			    (char_u *)&p_sft, PV_NONE,
+			    (char_u *)&p_sft, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"showmatch",   "sm",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_sm, PV_NONE,
+			    (char_u *)&p_sm, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"showmode",    "smd",  P_BOOL|P_VIM,
-			    (char_u *)&p_smd, PV_NONE,
+			    (char_u *)&p_smd, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
     {"showtabline", "stal", P_NUM|P_VI_DEF|P_RALL,
-			    (char_u *)&p_stal, PV_NONE,
+			    (char_u *)&p_stal, PV_NONE, did_set_showtabline,
 			    {(char_u *)1L, (char_u *)0L} SCTX_INIT},
     {"sidescroll",  "ss",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_ss, PV_NONE,
+			    (char_u *)&p_ss, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"sidescrolloff", "siso", P_NUM|P_VI_DEF|P_VIM|P_RBUF,
-			    (char_u *)&p_siso, PV_SISO,
+			    (char_u *)&p_siso, PV_SISO, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"signcolumn",   "scl",  P_STRING|P_ALLOCED|P_VI_DEF|P_RCLR,
 #ifdef FEAT_SIGNS
-			    (char_u *)VAR_WIN, PV_SCL,
+			    (char_u *)VAR_WIN, PV_SCL, did_set_signcolumn,
 			    {(char_u *)"auto", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"slowopen",    "slow", P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"smartcase",   "scs",  P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_scs, PV_NONE,
+			    (char_u *)&p_scs, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"smartindent", "si",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_si, PV_SI,
+			    (char_u *)&p_si, PV_SI, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"smarttab",    "sta",  P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_sta, PV_NONE,
+			    (char_u *)&p_sta, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"smoothscroll", "sms", P_BOOL|P_VI_DEF|P_RWIN,
-			    (char_u *)VAR_WIN, PV_SMS,
+			    (char_u *)VAR_WIN, PV_SMS, did_set_smoothscroll,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"softtabstop", "sts",  P_NUM|P_VI_DEF|P_VIM,
-			    (char_u *)&p_sts, PV_STS,
+			    (char_u *)&p_sts, PV_STS, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"sourceany",   NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"spell",	    NULL,   P_BOOL|P_VI_DEF|P_RWIN,
 #ifdef FEAT_SPELL
-			    (char_u *)VAR_WIN, PV_SPELL,
+			    (char_u *)VAR_WIN, PV_SPELL, did_set_spell,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"spellcapcheck", "spc", P_STRING|P_ALLOCED|P_VI_DEF|P_RBUF,
 #ifdef FEAT_SPELL
-			    (char_u *)&p_spc, PV_SPC,
+			    (char_u *)&p_spc, PV_SPC, did_set_spellcapcheck,
 			    {(char_u *)"[.?!]\\_[\\])'\"	 ]\\+", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"spellfile",   "spf",  P_STRING|P_EXPAND|P_ALLOCED|P_VI_DEF|P_SECURE
 								  |P_ONECOMMA,
 #ifdef FEAT_SPELL
-			    (char_u *)&p_spf, PV_SPF,
+			    (char_u *)&p_spf, PV_SPF, did_set_spellfile,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"spelllang",   "spl",  P_STRING|P_ALLOCED|P_VI_DEF|P_ONECOMMA
 							     |P_RBUF|P_EXPAND,
 #ifdef FEAT_SPELL
-			    (char_u *)&p_spl, PV_SPL,
+			    (char_u *)&p_spl, PV_SPL, did_set_spelllang,
 			    {(char_u *)"en", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"spelloptions", "spo",  P_STRING|P_ALLOCED|P_VI_DEF
 						    |P_ONECOMMA|P_NODUP|P_RBUF,
 #ifdef FEAT_SPELL
-			    (char_u *)&p_spo, PV_SPO,
+			    (char_u *)&p_spo, PV_SPO, did_set_spelloptions,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"spellsuggest", "sps", P_STRING|P_VI_DEF|P_EXPAND|P_SECURE|P_ONECOMMA,
 #ifdef FEAT_SPELL
-			    (char_u *)&p_sps, PV_NONE,
+			    (char_u *)&p_sps, PV_NONE, did_set_spellsuggest,
 			    {(char_u *)"best", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"splitbelow",  "sb",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_sb, PV_NONE,
+			    (char_u *)&p_sb, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"splitkeep",   "spk",  P_STRING,
-			    (char_u *)&p_spk, PV_NONE,
+			    (char_u *)&p_spk, PV_NONE, NULL,
 			    {(char_u *)"cursor", (char_u *)"cursor"} SCTX_INIT},
     {"splitright",  "spr",  P_BOOL|P_VI_DEF,
-			    (char_u *)&p_spr, PV_NONE,
+			    (char_u *)&p_spr, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"startofline", "sol",  P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_sol, PV_NONE,
+			    (char_u *)&p_sol, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"statusline"  ,"stl",  P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT|P_MLE,
 #ifdef FEAT_STL_OPT
-			    (char_u *)&p_stl, PV_STL,
+			    (char_u *)&p_stl, PV_STL, did_set_statusline,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"suffixes",    "su",   P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_su, PV_NONE,
+			    (char_u *)&p_su, PV_NONE, NULL,
 			    {(char_u *)".bak,~,.o,.h,.info,.swp,.obj",
 				(char_u *)0L} SCTX_INIT},
     {"suffixesadd", "sua",  P_STRING|P_VI_DEF|P_ALLOCED|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_sua, PV_SUA,
+			    (char_u *)&p_sua, PV_SUA, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"swapfile",    "swf",  P_BOOL|P_VI_DEF|P_RSTAT,
-			    (char_u *)&p_swf, PV_SWF,
+			    (char_u *)&p_swf, PV_SWF, did_set_swapfile,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"swapsync",    "sws",  P_STRING|P_VI_DEF,
-			    (char_u *)&p_sws, PV_NONE,
+			    (char_u *)&p_sws, PV_NONE, NULL,
 			    {(char_u *)"fsync", (char_u *)0L} SCTX_INIT},
     {"switchbuf",   "swb",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_swb, PV_NONE,
+			    (char_u *)&p_swb, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"synmaxcol",   "smc",  P_NUM|P_VI_DEF|P_RBUF,
 #ifdef FEAT_SYN_HL
-			    (char_u *)&p_smc, PV_SMC,
+			    (char_u *)&p_smc, PV_SMC, NULL,
 			    {(char_u *)3000L, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"syntax",	    "syn",  P_STRING|P_ALLOCED|P_VI_DEF|P_NOGLOB|P_NFNAME,
 #ifdef FEAT_SYN_HL
-			    (char_u *)&p_syn, PV_SYN,
+			    (char_u *)&p_syn, PV_SYN, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"tabline",	    "tal",  P_STRING|P_VI_DEF|P_RALL|P_MLE,
 #ifdef FEAT_STL_OPT
-			    (char_u *)&p_tal, PV_NONE,
+			    (char_u *)&p_tal, PV_NONE, did_set_tabline,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"tabpagemax",  "tpm",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_tpm, PV_NONE,
+			    (char_u *)&p_tpm, PV_NONE, NULL,
 			    {(char_u *)10L, (char_u *)0L} SCTX_INIT},
     {"tabstop",	    "ts",   P_NUM|P_VI_DEF|P_RBUF,
 			    (char_u *)&p_ts, PV_TS,
+			    did_set_shiftwidth_tabstop,
 			    {(char_u *)8L, (char_u *)0L} SCTX_INIT},
     {"tagbsearch",  "tbs",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_tbs, PV_NONE,
+			    (char_u *)&p_tbs, PV_NONE, NULL,
 #ifdef VMS	// binary searching doesn't appear to work on VMS
 			    {(char_u *)0L, (char_u *)0L}
 #else
@@ -2422,25 +2463,25 @@ static struct vimoption options[] =
 #endif
 			    SCTX_INIT},
     {"tagcase",	    "tc",   P_STRING|P_VIM,
-			    (char_u *)&p_tc, PV_TC,
+			    (char_u *)&p_tc, PV_TC, did_set_tagcase,
 			    {(char_u *)"followic", (char_u *)"followic"} SCTX_INIT},
     {"tagfunc",    "tfu",   P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC,
 #ifdef FEAT_EVAL
-			    (char_u *)&p_tfu, PV_TFU,
+			    (char_u *)&p_tfu, PV_TFU, did_set_tagfunc,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"taglength",   "tl",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_tl, PV_NONE,
+			    (char_u *)&p_tl, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"tagrelative", "tr",   P_BOOL|P_VIM,
-			    (char_u *)&p_tr, PV_NONE,
+			    (char_u *)&p_tr, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT},
     {"tags",	    "tag",  P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_tags, PV_TAGS,
+			    (char_u *)&p_tags, PV_TAGS, NULL,
 			    {
 #if defined(FEAT_EMACS_TAGS) && !defined(CASE_INSENSITIVE_FILENAME)
 			    (char_u *)"./tags,./TAGS,tags,TAGS",
@@ -2449,85 +2490,85 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"tagstack",    "tgst", P_BOOL|P_VI_DEF,
-			    (char_u *)&p_tgst, PV_NONE,
+			    (char_u *)&p_tgst, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"tcldll",      NULL,   P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(DYNAMIC_TCL)
-			    (char_u *)&p_tcldll, PV_NONE,
+			    (char_u *)&p_tcldll, PV_NONE, NULL,
 			    {(char_u *)DYNAMIC_TCL_DLL, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"term",	    NULL,   P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RALL,
-			    (char_u *)&T_NAME, PV_NONE,
+			    (char_u *)&T_NAME, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"termbidi", "tbidi",   P_BOOL|P_VI_DEF,
 #ifdef FEAT_ARABIC
-			    (char_u *)&p_tbidi, PV_NONE,
+			    (char_u *)&p_tbidi, PV_NONE, NULL,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"termencoding", "tenc", P_STRING|P_VI_DEF|P_RCLR,
-			    (char_u *)&p_tenc, PV_NONE,
+			    (char_u *)&p_tenc, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"termguicolors", "tgc", P_BOOL|P_VI_DEF|P_VIM|P_RCLR,
 #ifdef FEAT_TERMGUICOLORS
-			    (char_u *)&p_tgc, PV_NONE,
+			    (char_u *)&p_tgc, PV_NONE, did_set_termguicolors,
 			    {(char_u *)FALSE, (char_u *)FALSE}
 #else
-			    (char_u*)NULL, PV_NONE,
+			    (char_u*)NULL, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)FALSE}
 #endif
 			    SCTX_INIT},
     {"termwinkey", "twk",   P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF,
 #ifdef FEAT_TERMINAL
-			    (char_u *)VAR_WIN, PV_TWK,
+			    (char_u *)VAR_WIN, PV_TWK, did_set_termwinkey,
 			    {(char_u *)"", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"termwinscroll", "twsl", P_NUM|P_VI_DEF|P_VIM|P_RBUF,
 #ifdef FEAT_TERMINAL
-			    (char_u *)&p_twsl, PV_TWSL,
+			    (char_u *)&p_twsl, PV_TWSL, NULL,
 			    {(char_u *)10000L, (char_u *)10000L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"termwinsize", "tws",  P_STRING|P_ALLOCED|P_RWIN|P_VI_DEF,
 #ifdef FEAT_TERMINAL
-			    (char_u *)VAR_WIN, PV_TWS,
+			    (char_u *)VAR_WIN, PV_TWS, did_set_termwinsize,
 			    {(char_u *)"", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"termwintype", "twt",  P_STRING|P_ALLOCED|P_VI_DEF,
 #if defined(MSWIN) && defined(FEAT_TERMINAL)
-			    (char_u *)&p_twt, PV_NONE,
+			    (char_u *)&p_twt, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)NULL}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"terse",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_terse, PV_NONE,
+			    (char_u *)&p_terse, PV_NONE, did_set_terse,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"textauto",    "ta",   P_BOOL|P_VIM,
-			    (char_u *)&p_ta, PV_NONE,
+			    (char_u *)&p_ta, PV_NONE, did_set_textauto,
 			    {(char_u *)DFLT_TEXTAUTO, (char_u *)TRUE}
 			    SCTX_INIT},
     {"textmode",    "tx",   P_BOOL|P_VI_DEF|P_NO_MKRC,
-			    (char_u *)&p_tx, PV_TX,
+			    (char_u *)&p_tx, PV_TX, did_set_textmode,
 			    {
 #ifdef USE_CRNL
 			    (char_u *)TRUE,
@@ -2536,105 +2577,108 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"textwidth",   "tw",   P_NUM|P_VI_DEF|P_VIM|P_RBUF,
-			    (char_u *)&p_tw, PV_TW,
+			    (char_u *)&p_tw, PV_TW, did_set_textwidth,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"thesaurus",   "tsr",  P_STRING|P_EXPAND|P_VI_DEF|P_ONECOMMA|P_NODUP|P_NDNAME,
-			    (char_u *)&p_tsr, PV_TSR,
+			    (char_u *)&p_tsr, PV_TSR, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"thesaurusfunc", "tsrfu",  P_STRING|P_ALLOCED|P_VI_DEF|P_SECURE|P_FUNC,
 #ifdef FEAT_COMPL_FUNC
 			    (char_u *)&p_tsrfu, PV_TSRFU,
+			    did_set_thesaurusfunc,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"tildeop",	    "top",  P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_to, PV_NONE,
+			    (char_u *)&p_to, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"timeout",	    "to",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_timeout, PV_NONE,
+			    (char_u *)&p_timeout, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"timeoutlen",  "tm",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_tm, PV_NONE,
+			    (char_u *)&p_tm, PV_NONE, NULL,
 			    {(char_u *)1000L, (char_u *)0L} SCTX_INIT},
     {"title",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_title, PV_NONE,
+			    (char_u *)&p_title, PV_NONE, did_set_title_icon,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"titlelen",    NULL,   P_NUM|P_VI_DEF,
-			    (char_u *)&p_titlelen, PV_NONE,
+			    (char_u *)&p_titlelen, PV_NONE, did_set_titlelen,
 			    {(char_u *)85L, (char_u *)0L} SCTX_INIT},
     {"titleold",    NULL,   P_STRING|P_VI_DEF|P_GETTEXT|P_SECURE|P_NO_MKRC,
-			    (char_u *)&p_titleold, PV_NONE,
+			    (char_u *)&p_titleold, PV_NONE, NULL,
 			    {(char_u *)N_("Thanks for flying Vim"),
 							       (char_u *)0L}
 			    SCTX_INIT},
     {"titlestring", NULL,   P_STRING|P_VI_DEF|P_MLE,
 			    (char_u *)&p_titlestring, PV_NONE,
+			    did_set_titlestring,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"toolbar",     "tb",   P_STRING|P_ONECOMMA|P_VI_DEF|P_NODUP,
 #if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)
-			    (char_u *)&p_toolbar, PV_NONE,
+			    (char_u *)&p_toolbar, PV_NONE, did_set_toolbar,
 			    {(char_u *)"icons,tooltips", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"toolbariconsize",	"tbis", P_STRING|P_VI_DEF,
 #if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
 			    (char_u *)&p_tbis, PV_NONE,
+			    did_set_toolbariconsize,
 			    {(char_u *)"small", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"ttimeout",    NULL,   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_ttimeout, PV_NONE,
+			    (char_u *)&p_ttimeout, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"ttimeoutlen", "ttm",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_ttm, PV_NONE,
+			    (char_u *)&p_ttm, PV_NONE, NULL,
 			    {(char_u *)-1L, (char_u *)0L} SCTX_INIT},
     {"ttybuiltin",  "tbi",  P_BOOL|P_VI_DEF,
-			    (char_u *)&p_tbi, PV_NONE,
+			    (char_u *)&p_tbi, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"ttyfast",	    "tf",   P_BOOL|P_NO_MKRC|P_VI_DEF,
-			    (char_u *)&p_tf, PV_NONE,
+			    (char_u *)&p_tf, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"ttymouse",    "ttym", P_STRING|P_NODEFAULT|P_NO_MKRC|P_VI_DEF,
 #if defined(UNIX) || defined(VMS)
-			    (char_u *)&p_ttym, PV_NONE,
+			    (char_u *)&p_ttym, PV_NONE, did_set_ttymouse,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"ttyscroll",   "tsl",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_ttyscroll, PV_NONE,
+			    (char_u *)&p_ttyscroll, PV_NONE, NULL,
 			    {(char_u *)999L, (char_u *)0L} SCTX_INIT},
     {"ttytype",	    "tty",  P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RALL,
-			    (char_u *)&T_NAME, PV_NONE,
+			    (char_u *)&T_NAME, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"undodir",     "udir", P_STRING|P_EXPAND|P_ONECOMMA|P_NODUP|P_SECURE
 								    |P_VI_DEF,
 #ifdef FEAT_PERSISTENT_UNDO
-			    (char_u *)&p_udir, PV_NONE,
+			    (char_u *)&p_udir, PV_NONE, NULL,
 			    {(char_u *)".", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"undofile",    "udf",  P_BOOL|P_VI_DEF|P_VIM,
 #ifdef FEAT_PERSISTENT_UNDO
-			    (char_u *)&p_udf, PV_UDF,
+			    (char_u *)&p_udf, PV_UDF, did_set_undofile,
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 #endif
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"undolevels",  "ul",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_ul, PV_UL,
+			    (char_u *)&p_ul, PV_UL, did_set_undolevels,
 			    {
 #if defined(UNIX) || defined(MSWIN) || defined(VMS)
 			    (char_u *)1000L,
@@ -2643,60 +2687,61 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"undoreload",  "ur",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_ur, PV_NONE,
+			    (char_u *)&p_ur, PV_NONE, NULL,
 			    { (char_u *)10000L, (char_u *)0L} SCTX_INIT},
     {"updatecount", "uc",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_uc, PV_NONE,
+			    (char_u *)&p_uc, PV_NONE, did_set_updatecount,
 			    {(char_u *)200L, (char_u *)0L} SCTX_INIT},
     {"updatetime",  "ut",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_ut, PV_NONE,
+			    (char_u *)&p_ut, PV_NONE, NULL,
 			    {(char_u *)4000L, (char_u *)0L} SCTX_INIT},
     {"varsofttabstop", "vsts",  P_STRING|P_VI_DEF|P_VIM|P_COMMA,
 #ifdef FEAT_VARTABS
 			    (char_u *)&p_vsts, PV_VSTS,
+			    did_set_varsofttabstop,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)NULL}
 #endif
 			    SCTX_INIT},
     {"vartabstop",  "vts",  P_STRING|P_VI_DEF|P_VIM|P_RBUF|P_COMMA,
 #ifdef FEAT_VARTABS
-			    (char_u *)&p_vts, PV_VTS,
+			    (char_u *)&p_vts, PV_VTS, did_set_vartabstop,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)NULL}
 #endif
 			    SCTX_INIT},
     {"verbose",	    "vbs",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_verbose, PV_NONE,
+			    (char_u *)&p_verbose, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"verbosefile", "vfile", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
-			    (char_u *)&p_vfile, PV_NONE,
+			    (char_u *)&p_vfile, PV_NONE, did_set_verbosefile,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"viewdir",     "vdir", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #ifdef FEAT_SESSION
-			    (char_u *)&p_vdir, PV_NONE,
+			    (char_u *)&p_vdir, PV_NONE, NULL,
 			    {(char_u *)DFLT_VDIR, (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"viewoptions", "vop",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
 #ifdef FEAT_SESSION
-			    (char_u *)&p_vop, PV_NONE,
+			    (char_u *)&p_vop, PV_NONE, NULL,
 			    {(char_u *)"folds,options,cursor,curdir",
 								  (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"viminfo",	    "vi",   P_STRING|P_ONECOMMA|P_NODUP|P_SECURE,
 #ifdef FEAT_VIMINFO
-			    (char_u *)&p_viminfo, PV_NONE,
+			    (char_u *)&p_viminfo, PV_NONE, NULL,
 #if defined(MSWIN)
 			    {(char_u *)"", (char_u *)"'100,<50,s10,h,rA:,rB:"}
 #elif defined(AMIGA)
@@ -2706,103 +2751,104 @@ static struct vimoption options[] =
 			    {(char_u *)"", (char_u *)"'100,<50,s10,h"}
 #endif
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"viminfofile", "vif",  P_STRING|P_EXPAND|P_ONECOMMA|P_NODUP
 							    |P_SECURE|P_VI_DEF,
 #ifdef FEAT_VIMINFO
-			    (char_u *)&p_viminfofile, PV_NONE,
+			    (char_u *)&p_viminfofile, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"virtualedit", "ve",   P_STRING|P_ONECOMMA|P_NODUP|P_VI_DEF
 							    |P_VIM|P_CURSWANT,
-			    (char_u *)&p_ve, PV_VE,
+			    (char_u *)&p_ve, PV_VE, did_set_virtualedit,
 			    {(char_u *)"", (char_u *)""}
 			    SCTX_INIT},
     {"visualbell",  "vb",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_vb, PV_NONE,
+			    (char_u *)&p_vb, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"w300",	    NULL,   P_NUM|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"w1200",	    NULL,   P_NUM|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"w9600",	    NULL,   P_NUM|P_VI_DEF,
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"warn",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_warn, PV_NONE,
+			    (char_u *)&p_warn, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"weirdinvert", "wiv",  P_BOOL|P_VI_DEF|P_RCLR,
-			    (char_u *)&p_wiv, PV_NONE,
+			    (char_u *)&p_wiv, PV_NONE, did_set_weirdinvert,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"whichwrap",   "ww",   P_STRING|P_VIM|P_ONECOMMA|P_FLAGLIST,
-			    (char_u *)&p_ww, PV_NONE,
+			    (char_u *)&p_ww, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)"b,s"} SCTX_INIT},
     {"wildchar",    "wc",   P_NUM|P_VIM,
-			    (char_u *)&p_wc, PV_NONE,
+			    (char_u *)&p_wc, PV_NONE, NULL,
 			    {(char_u *)(long)Ctrl_E, (char_u *)(long)TAB}
 			    SCTX_INIT},
     {"wildcharm",   "wcm",  P_NUM|P_VI_DEF,
-			    (char_u *)&p_wcm, PV_NONE,
+			    (char_u *)&p_wcm, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"wildignore",  "wig",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_wig, PV_NONE,
+			    (char_u *)&p_wig, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
     {"wildignorecase", "wic", P_BOOL|P_VI_DEF,
-			    (char_u *)&p_wic, PV_NONE,
+			    (char_u *)&p_wic, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"wildmenu",    "wmnu", P_BOOL|P_VI_DEF,
-			    (char_u *)&p_wmnu, PV_NONE,
+			    (char_u *)&p_wmnu, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"wildmode",    "wim",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_wim, PV_NONE,
+			    (char_u *)&p_wim, PV_NONE, did_set_wildmode,
 			    {(char_u *)"full", (char_u *)0L} SCTX_INIT},
     {"wildoptions", "wop",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
-			    (char_u *)&p_wop, PV_NONE,
+			    (char_u *)&p_wop, PV_NONE, NULL,
 			    {(char_u *)"", (char_u *)0L}
 			    SCTX_INIT},
     {"winaltkeys",  "wak",  P_STRING|P_VI_DEF,
 #ifdef FEAT_WAK
-			    (char_u *)&p_wak, PV_NONE,
+			    (char_u *)&p_wak, PV_NONE, did_set_winaltkeys,
 			    {(char_u *)"menu", (char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)NULL, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"wincolor", "wcr",	    P_STRING|P_ALLOCED|P_VI_DEF|P_RWIN,
-			    (char_u *)VAR_WIN, PV_WCR,
+			    (char_u *)VAR_WIN, PV_WCR, NULL,
 			    {(char_u *)"", (char_u *)NULL}
 			    SCTX_INIT},
     {"window",	    "wi",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_window, PV_NONE,
+			    (char_u *)&p_window, PV_NONE, did_set_window,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"winheight",   "wh",   P_NUM|P_VI_DEF,
 			    (char_u *)&p_wh, PV_NONE,
+			    did_set_winheight_helpheight,
 			    {(char_u *)1L, (char_u *)0L} SCTX_INIT},
     {"winfixheight", "wfh", P_BOOL|P_VI_DEF|P_RSTAT,
-			    (char_u *)VAR_WIN, PV_WFH,
+			    (char_u *)VAR_WIN, PV_WFH, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"winfixwidth", "wfw", P_BOOL|P_VI_DEF|P_RSTAT,
-			    (char_u *)VAR_WIN, PV_WFW,
+			    (char_u *)VAR_WIN, PV_WFW, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"winminheight", "wmh", P_NUM|P_VI_DEF,
-			    (char_u *)&p_wmh, PV_NONE,
+			    (char_u *)&p_wmh, PV_NONE, did_set_winminheight,
 			    {(char_u *)1L, (char_u *)0L} SCTX_INIT},
     {"winminwidth", "wmw", P_NUM|P_VI_DEF,
-			    (char_u *)&p_wmw, PV_NONE,
+			    (char_u *)&p_wmw, PV_NONE, did_set_winminwidth,
 			    {(char_u *)1L, (char_u *)0L} SCTX_INIT},
     {"winptydll", NULL,	    P_STRING|P_EXPAND|P_VI_DEF|P_SECURE,
 #if defined(MSWIN) && defined(FEAT_TERMINAL)
-			    (char_u *)&p_winptydll, PV_NONE, {
+			    (char_u *)&p_winptydll, PV_NONE, NULL, {
 # ifdef _WIN64
 			    (char_u *)"winpty64.dll",
 # else
@@ -2810,30 +2856,30 @@ static struct vimoption options[] =
 # endif
 				(char_u *)0L}
 #else
-			    (char_u *)NULL, PV_NONE,
+			    (char_u *)NULL, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L}
 #endif
 			    SCTX_INIT},
     {"winwidth",   "wiw",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_wiw, PV_NONE,
+			    (char_u *)&p_wiw, PV_NONE, did_set_winwidth,
 			    {(char_u *)20L, (char_u *)0L} SCTX_INIT},
     {"wrap",	    NULL,   P_BOOL|P_VI_DEF|P_RWIN,
-			    (char_u *)VAR_WIN, PV_WRAP,
+			    (char_u *)VAR_WIN, PV_WRAP, did_set_wrap,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"wrapmargin",  "wm",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_wm, PV_WM,
+			    (char_u *)&p_wm, PV_WM, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"wrapscan",    "ws",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_ws, PV_NONE,
+			    (char_u *)&p_ws, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"write",	    NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_write, PV_NONE,
+			    (char_u *)&p_write, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
     {"writeany",    "wa",   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_wa, PV_NONE,
+			    (char_u *)&p_wa, PV_NONE, NULL,
 			    {(char_u *)FALSE, (char_u *)0L} SCTX_INIT},
     {"writebackup", "wb",   P_BOOL|P_VI_DEF|P_VIM,
-			    (char_u *)&p_wb, PV_NONE,
+			    (char_u *)&p_wb, PV_NONE, NULL,
 			    {
 #ifdef FEAT_WRITEBACKUP
 			    (char_u *)TRUE,
@@ -2842,16 +2888,16 @@ static struct vimoption options[] =
 #endif
 				(char_u *)0L} SCTX_INIT},
     {"writedelay",  "wd",   P_NUM|P_VI_DEF,
-			    (char_u *)&p_wd, PV_NONE,
+			    (char_u *)&p_wd, PV_NONE, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
     {"xtermcodes",  NULL,   P_BOOL|P_VI_DEF,
-			    (char_u *)&p_xtermcodes, PV_NONE,
+			    (char_u *)&p_xtermcodes, PV_NONE, NULL,
 			    {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
 
 // terminal output codes
 #define p_term(sss, vvv) \
 			    {sss, NULL, P_STRING|P_VI_DEF|P_RALL|P_SECURE, \
-			    (char_u *)&vvv, PV_NONE, \
+			    (char_u *)&vvv, PV_NONE, NULL, \
 			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
 
     p_term("t_AB", T_CAB)
@@ -2947,7 +2993,7 @@ static struct vimoption options[] =
 // terminal key codes are not in here
 
     // end marker
-    {NULL, NULL, 0, NULL, PV_NONE, {NULL, NULL} SCTX_INIT}
+    {NULL, NULL, 0, NULL, PV_NONE, NULL, {NULL, NULL} SCTX_INIT}
 };
 
 #define OPTION_COUNT ARRAY_LENGTH(options)
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -541,7 +541,7 @@ set_string_option(
 	saved_newval = vim_strsave(s);
     }
 #endif
-    if ((errmsg = did_set_string_option(opt_idx, varp, oldval, errbuf,
+    if ((errmsg = did_set_string_option(opt_idx, varp, oldval, value, errbuf,
 		    opt_flags, &value_checked)) == NULL)
 	did_set_option(opt_idx, opt_flags, TRUE, value_checked);
 
@@ -691,22 +691,20 @@ did_set_term(int *opt_idx, long_u *free_
 /*
  * The 'backupcopy' option is changed.
  */
-    static char *
-did_set_backupcopy(
-    char_u	*oldval,
-    int		opt_flags)
+    char *
+did_set_backupcopy(optset_T *args)
 {
     char_u		*bkc = p_bkc;
     unsigned int	*flags = &bkc_flags;
     char		*errmsg = NULL;
 
-    if (opt_flags & OPT_LOCAL)
+    if (args->os_flags & OPT_LOCAL)
     {
 	bkc = curbuf->b_p_bkc;
 	flags = &curbuf->b_bkc_flags;
     }
 
-    if ((opt_flags & OPT_LOCAL) && *bkc == NUL)
+    if ((args->os_flags & OPT_LOCAL) && *bkc == NUL)
 	// make the local value empty: use the global value
 	*flags = 0;
     else
@@ -718,7 +716,8 @@ did_set_backupcopy(
 		+ (((int)*flags & BKC_NO) != 0) != 1)
 	{
 	    // Must have exactly one of "auto", "yes"  and "no".
-	    (void)opt_strings_flags(oldval, p_bkc_values, flags, TRUE);
+	    (void)opt_strings_flags(args->os_oldval.string, p_bkc_values,
+								  flags, TRUE);
 	    errmsg = e_invalid_argument;
 	}
     }
@@ -729,8 +728,8 @@ did_set_backupcopy(
 /*
  * The 'backupext' or the 'patchmode' option is changed.
  */
-    static char *
-did_set_backupext_or_patchmode(void)
+    char *
+did_set_backupext_or_patchmode(optset_T *args UNUSED)
 {
     if (STRCMP(*p_bex == '.' ? p_bex + 1 : p_bex,
 		*p_pm == '.' ? p_pm + 1 : p_pm) == 0)
@@ -739,12 +738,12 @@ did_set_backupext_or_patchmode(void)
     return NULL;
 }
 
-#ifdef FEAT_LINEBREAK
+#if defined(FEAT_LINEBREAK) || defined(PROTO)
 /*
  * The 'breakindentopt' option is changed.
  */
-    static char *
-did_set_breakindentopt(void)
+    char *
+did_set_breakindentopt(optset_T *args UNUSED)
 {
     char *errmsg = NULL;
 
@@ -780,14 +779,15 @@ did_set_isopt(int *did_chartab)
 /*
  * The 'helpfile' option is changed.
  */
-    static void
-did_set_helpfile(void)
+    char *
+did_set_helpfile(optset_T *args UNUSED)
 {
     // May compute new values for $VIM and $VIMRUNTIME
     if (didset_vim)
 	vim_unsetenv_ext((char_u *)"VIM");
     if (didset_vimruntime)
 	vim_unsetenv_ext((char_u *)"VIMRUNTIME");
+    return NULL;
 }
 
 #ifdef FEAT_SYN_HL
@@ -804,12 +804,12 @@ did_set_cursorlineopt(char_u **varp)
 }
 #endif
 
-#ifdef FEAT_MULTI_LANG
+#if defined(FEAT_MULTI_LANG) || defined(PROTO)
 /*
  * The 'helplang' option is changed.
  */
-    static char *
-did_set_helplang(void)
+    char *
+did_set_helplang(optset_T *args UNUSED)
 {
     char *errmsg = NULL;
 
@@ -832,8 +832,8 @@ did_set_helplang(void)
 /*
  * The 'highlight' option is changed.
  */
-    static char *
-did_set_highlight(void)
+    char *
+did_set_highlight(optset_T *args UNUSED)
 {
     if (highlight_changed() == FAIL)
 	return e_invalid_argument;	// invalid flags
@@ -868,15 +868,16 @@ did_set_opt_strings(char_u *val, char **
 /*
  * The 'sessionoptions' option is changed.
  */
-    static char *
-did_set_sessionoptions(char_u *oldval)
+    char *
+did_set_sessionoptions(optset_T *args)
 {
     if (opt_strings_flags(p_ssop, p_ssop_values, &ssop_flags, TRUE) != OK)
 	return e_invalid_argument;
     if ((ssop_flags & SSOP_CURDIR) && (ssop_flags & SSOP_SESDIR))
     {
 	// Don't allow both "sesdir" and "curdir".
-	(void)opt_strings_flags(oldval, p_ssop_values, &ssop_flags, TRUE);
+	(void)opt_strings_flags(args->os_oldval.string, p_ssop_values,
+							&ssop_flags, TRUE);
 	return e_invalid_argument;
     }
 
@@ -887,8 +888,8 @@ did_set_sessionoptions(char_u *oldval)
 /*
  * The 'ambiwidth' option is changed.
  */
-    static char *
-did_set_ambiwidth(void)
+    char *
+did_set_ambiwidth(optset_T *args UNUSED)
 {
     if (check_opt_strings(p_ambw, p_ambw_values, FALSE) != OK)
 	return e_invalid_argument;
@@ -899,8 +900,8 @@ did_set_ambiwidth(void)
 /*
  * The 'background' option is changed.
  */
-    static char *
-did_set_background(void)
+    char *
+did_set_background(optset_T *args UNUSED)
 {
     if (check_opt_strings(p_bg, p_bg_values, FALSE) == FAIL)
 	return e_invalid_argument;
@@ -935,20 +936,20 @@ did_set_background(void)
 /*
  * The 'wildmode' option is changed.
  */
-    static char *
-did_set_wildmode(void)
+    char *
+did_set_wildmode(optset_T *args UNUSED)
 {
     if (check_opt_wim() == FAIL)
 	return e_invalid_argument;
     return NULL;
 }
 
-#ifdef FEAT_WAK
+#if defined(FEAT_WAK) || defined(PROTO)
 /*
  * The 'winaltkeys' option is changed.
  */
-    static char *
-did_set_winaltkeys(void)
+    char *
+did_set_winaltkeys(optset_T *args UNUSED)
 {
     char *errmsg = NULL;
 
@@ -971,8 +972,8 @@ did_set_winaltkeys(void)
 /*
  * The 'eventignore' option is changed.
  */
-    static char *
-did_set_eventignore(void)
+    char *
+did_set_eventignore(optset_T *args UNUSED)
 {
     if (check_ei() == FAIL)
 	return e_invalid_argument;
@@ -1066,12 +1067,12 @@ did_set_encoding(char_u **varp, char_u *
     return errmsg;
 }
 
-#if defined(FEAT_POSTSCRIPT)
+#if defined(FEAT_POSTSCRIPT) || defined(PROTO)
 /*
  * The 'printencoding' option is changed.
  */
-    static void
-did_set_printencoding(void)
+    char *
+did_set_printencoding(optset_T *args UNUSED)
 {
     char_u	*s, *p;
 
@@ -1093,15 +1094,17 @@ did_set_printencoding(void)
 		*s = TOLOWER_ASC(*s);
 	}
     }
+
+    return NULL;
 }
 #endif
 
-#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
+#if (defined(FEAT_XIM) && defined(FEAT_GUI_GTK)) || defined(PROTO)
 /*
  * The 'imactivatekey' option is changed.
  */
-    static char *
-did_set_imactivatekey(void)
+    char *
+did_set_imactivatekey(optset_T *args UNUSED)
 {
     if (!im_xim_isvalid_imactivate())
 	return e_invalid_argument;
@@ -1170,12 +1173,12 @@ did_set_keymap(char_u **varp, int opt_fl
 /*
  * The 'fileformat' option is changed.
  */
-    static char *
-did_set_fileformat(char_u **varp, char_u *oldval, int opt_flags)
+    char *
+did_set_fileformat(optset_T *args)
 {
-    if (!curbuf->b_p_ma && !(opt_flags & OPT_GLOBAL))
+    if (!curbuf->b_p_ma && !(args->os_flags & OPT_GLOBAL))
 	return e_cannot_make_changes_modifiable_is_off;
-    else if (check_opt_strings(*varp, p_ff_values, FALSE) != OK)
+    else if (check_opt_strings(args->os_varp, p_ff_values, FALSE) != OK)
 	return e_invalid_argument;
 
     // may also change 'textmode'
@@ -1188,7 +1191,7 @@ did_set_fileformat(char_u **varp, char_u
     ml_setflags(curbuf);
     // Redraw needed when switching to/from "mac": a CR in the text
     // will be displayed differently.
-    if (get_fileformat(curbuf) == EOL_MAC || *oldval == 'm')
+    if (get_fileformat(curbuf) == EOL_MAC || *args->os_oldval.string == 'm')
 	redraw_curbuf_later(UPD_NOT_VALID);
 
     return NULL;
@@ -1197,8 +1200,8 @@ did_set_fileformat(char_u **varp, char_u
 /*
  * The 'fileformats' option is changed.
  */
-    static char *
-did_set_fileformats(void)
+    char *
+did_set_fileformats(optset_T *args UNUSED)
 {
     if (check_opt_strings(p_ffs, p_ff_values, TRUE) != OK)
 	return e_invalid_argument;
@@ -1212,36 +1215,38 @@ did_set_fileformats(void)
     return NULL;
 }
 
-#if defined(FEAT_CRYPT)
+#if defined(FEAT_CRYPT) || defined(PROTO)
 /*
  * The 'cryptkey' option is changed.
  */
-    static void
-did_set_cryptkey(char_u *oldval)
+    char *
+did_set_cryptkey(optset_T *args)
 {
     // Make sure the ":set" command doesn't show the new value in the
     // history.
     remove_key_from_history();
 
-    if (STRCMP(curbuf->b_p_key, oldval) != 0)
+    if (STRCMP(curbuf->b_p_key, args->os_oldval.string) != 0)
     {
 	// Need to update the swapfile.
-	ml_set_crypt_key(curbuf, oldval,
+	ml_set_crypt_key(curbuf, args->os_oldval.string,
 		*curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm);
 	changed_internal();
     }
+
+    return NULL;
 }
 
 /*
  * The 'cryptmethod' option is changed.
  */
-    static char *
-did_set_cryptmethod(char_u *oldval, int opt_flags)
+    char *
+did_set_cryptmethod(optset_T *args)
 {
     char_u  *p;
     char_u  *s;
 
-    if (opt_flags & OPT_LOCAL)
+    if (args->os_flags & OPT_LOCAL)
 	p = curbuf->b_p_cm;
     else
 	p = p_cm;
@@ -1259,7 +1264,7 @@ did_set_cryptmethod(char_u *oldval, int 
     // When using ":set cm=name" the local value is going to be empty.
     // Do that here, otherwise the crypt functions will still use the
     // local value.
-    if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
+    if ((args->os_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0)
     {
 	free_string_option(curbuf->b_p_cm);
 	curbuf->b_p_cm = empty_option;
@@ -1268,10 +1273,10 @@ did_set_cryptmethod(char_u *oldval, int 
     // Need to update the swapfile when the effective method changed.
     // Set "s" to the effective old value, "p" to the effective new
     // method and compare.
-    if ((opt_flags & OPT_LOCAL) && *oldval == NUL)
+    if ((args->os_flags & OPT_LOCAL) && *args->os_oldval.string == NUL)
 	s = p_cm;  // was previously using the global value
     else
-	s = oldval;
+	s = args->os_oldval.string;
     if (*curbuf->b_p_cm == NUL)
 	p = p_cm;  // is now using the global value
     else
@@ -1281,13 +1286,14 @@ did_set_cryptmethod(char_u *oldval, int 
 
     // If the global value changes need to update the swapfile for all
     // buffers using that value.
-    if ((opt_flags & OPT_GLOBAL) && STRCMP(p_cm, oldval) != 0)
+    if ((args->os_flags & OPT_GLOBAL)
+	    && STRCMP(p_cm, args->os_oldval.string) != 0)
     {
 	buf_T	*buf;
 
 	FOR_ALL_BUFFERS(buf)
 	    if (buf != curbuf && *buf->b_p_cm == NUL)
-		ml_set_crypt_key(buf, buf->b_p_key, oldval);
+		ml_set_crypt_key(buf, buf->b_p_key, args->os_oldval.string);
     }
     return NULL;
 }
@@ -1296,14 +1302,14 @@ did_set_cryptmethod(char_u *oldval, int 
 /*
  * The 'matchpairs' option is changed.
  */
-    static char *
-did_set_matchpairs(char_u **varp)
+    char *
+did_set_matchpairs(optset_T *args)
 {
     char_u	*p;
 
     if (has_mbyte)
     {
-	for (p = *varp; *p != NUL; ++p)
+	for (p = args->os_varp; *p != NUL; ++p)
 	{
 	    int x2 = -1;
 	    int x3 = -1;
@@ -1325,7 +1331,7 @@ did_set_matchpairs(char_u **varp)
     else
     {
 	// Check for "x:y,x:y"
-	for (p = *varp; *p != NUL; p += 4)
+	for (p = args->os_varp; *p != NUL; p += 4)
 	{
 	    if (p[1] != ':' || p[2] == NUL || (p[3] != NUL && p[3] != ','))
 		return e_invalid_argument;
@@ -1419,8 +1425,8 @@ did_set_global_listfillchars(char_u **va
 /*
  * The 'verbosefile' option is changed.
  */
-    static char *
-did_set_verbosefile(void)
+    char *
+did_set_verbosefile(optset_T *args UNUSED)
 {
     verbose_stop();
     if (*p_vfile != NUL && verbose_open() == FAIL)
@@ -1560,16 +1566,16 @@ did_set_term_option(char_u **varp, int *
     }
 }
 
-#ifdef FEAT_LINEBREAK
+#if defined(FEAT_LINEBREAK) || defined(PROTO)
 /*
  * The 'showbreak' option is changed.
  */
-    static char *
-did_set_showbreak(char_u **varp)
+    char *
+did_set_showbreak(optset_T *args)
 {
     char_u	*s;
 
-    for (s = *varp; *s; )
+    for (s = args->os_varp; *s; )
     {
 	if (ptr2cells(s) != 1)
 	    return e_showbreak_contains_unprintable_or_wide_character;
@@ -1580,12 +1586,12 @@ did_set_showbreak(char_u **varp)
 }
 #endif
 
-#ifdef FEAT_GUI
+#if defined(FEAT_GUI) || defined(PROTO)
 /*
  * The 'guifont' option is changed.
  */
-    static char *
-did_set_guifont(char_u *oldval UNUSED)
+    char *
+did_set_guifont(optset_T *args UNUSED)
 {
     char_u	*p;
     char	*errmsg = NULL;
@@ -1599,9 +1605,9 @@ did_set_guifont(char_u *oldval UNUSED)
 	// give an error message.
 	if (STRCMP(p, "*") == 0)
 	{
-	    p = gui_mch_font_dialog(oldval);
+	    p = gui_mch_font_dialog(args->os_oldval.string);
 	    free_string_option(p_guifont);
-	    p_guifont = (p != NULL) ? p : vim_strsave(oldval);
+	    p_guifont = (p != NULL) ? p : vim_strsave(args->os_oldval.string);
 	}
 # endif
 	if (p != NULL && gui_init_font(p_guifont, FALSE) != OK)
@@ -1612,7 +1618,7 @@ did_set_guifont(char_u *oldval UNUSED)
 		// Dialog was cancelled: Keep the old value without giving
 		// an error message.
 		free_string_option(p_guifont);
-		p_guifont = vim_strsave(oldval);
+		p_guifont = vim_strsave(args->os_oldval.string);
 	    }
 	    else
 # endif
@@ -1623,12 +1629,12 @@ did_set_guifont(char_u *oldval UNUSED)
     return errmsg;
 }
 
-# ifdef FEAT_XFONTSET
+# if defined(FEAT_XFONTSET) || defined(PROTO)
 /*
  * The 'guifontset' option is changed.
  */
-    static char *
-did_set_guifontset()
+    char *
+did_set_guifontset(optset_T *args UNUSED)
 {
     char *errmsg = NULL;
 
@@ -1644,8 +1650,8 @@ did_set_guifontset()
 /*
  * The 'guifontwide' option is changed.
  */
-    static char *
-did_set_guifontwide(void)
+    char *
+did_set_guifontwide(optset_T *args UNUSED)
 {
     char *errmsg = NULL;
 
@@ -1658,17 +1664,21 @@ did_set_guifontwide(void)
 }
 #endif
 
-#if defined(FEAT_GUI_GTK)
-    static void
-did_set_guiligatures(void)
+#if defined(FEAT_GUI_GTK) || defined(PROTO)
+/*
+ * The 'guiligatures' option is changed.
+ */
+    char *
+did_set_guiligatures(optset_T *args UNUSED)
 {
     gui_set_ligatures();
+    return NULL;
 }
 #endif
 
-#ifdef FEAT_MOUSESHAPE
-    static char *
-did_set_mouseshape(void)
+#if defined(FEAT_MOUSESHAPE) || defined(PROTO)
+    char *
+did_set_mouseshape(optset_T *args UNUSED)
 {
     char *errmsg = NULL;
 
@@ -1682,46 +1692,81 @@ did_set_mouseshape(void)
 /*
  * The 'titlestring' or the 'iconstring' option is changed.
  */
-    static void
-did_set_titleiconstring(char_u **varp UNUSED)
+    static char *
+did_set_titleiconstring(optset_T *args UNUSED, int flagval UNUSED)
 {
 #ifdef FEAT_STL_OPT
-    int	flagval = (varp == &p_titlestring) ? STL_IN_TITLE : STL_IN_ICON;
-
     // NULL => statusline syntax
-    if (vim_strchr(*varp, '%') && check_stl_option(*varp) == NULL)
+    if (vim_strchr(args->os_varp, '%')
+				    && check_stl_option(args->os_varp) == NULL)
 	stl_syntax |= flagval;
     else
 	stl_syntax &= ~flagval;
 #endif
     did_set_title();
+
+    return NULL;
+}
+
+/*
+ * The 'titlestring' option is changed.
+ */
+    char *
+did_set_titlestring(optset_T *args)
+{
+    int flagval = 0;
+
+#ifdef FEAT_STL_OPT
+    flagval = STL_IN_TITLE;
+#endif
+    return did_set_titleiconstring(args, flagval);
+}
+
+/*
+ * The 'iconstring' option is changed.
+ */
+    char *
+did_set_iconstring(optset_T *args)
+{
+    int flagval = 0;
+
+#ifdef FEAT_STL_OPT
+    flagval = STL_IN_ICON;
+#endif
+
+    return did_set_titleiconstring(args, flagval);
 }
 
 #ifdef FEAT_GUI
 /*
  * The 'guioptions' option is changed.
  */
-    static void
-did_set_guioptions(char_u *oldval)
+    char *
+did_set_guioptions(optset_T *args)
 {
-    gui_init_which_components(oldval);
+    gui_init_which_components(args->os_oldval.string);
+    return NULL;
 }
 #endif
 
 #if defined(FEAT_GUI_TABLINE)
-    static void
-did_set_guitablabel()
+/*
+ * The 'guitablabel' option is changed.
+ */
+    char *
+did_set_guitablabel(optset_T *args UNUSED)
 {
     redraw_tabline = TRUE;
+    return NULL;
 }
 #endif
 
-#if defined(UNIX) || defined(VMS)
+#if defined(UNIX) || defined(VMS) || defined(PROTO)
 /*
  * The 'ttymouse' option is changed.
  */
-    static char *
-did_set_ttymouse(void)
+    char *
+did_set_ttymouse(optset_T *args UNUSED)
 {
     char *errmsg = NULL;
 
@@ -1742,8 +1787,8 @@ did_set_ttymouse(void)
 /*
  * The 'selection' option is changed.
  */
-    static char *
-did_set_selection(void)
+    char *
+did_set_selection(optset_T *args UNUSED)
 {
     if (*p_sel == NUL
 	    || check_opt_strings(p_sel, p_sel_values, FALSE) != OK)
@@ -1752,12 +1797,12 @@ did_set_selection(void)
     return NULL;
 }
 
-#ifdef FEAT_BROWSE
+#if defined(FEAT_BROWSE) || defined(PROTO)
 /*
  * The 'browsedir' option is changed.
  */
-    static char *
-did_set_browsedir(void)
+    char *
+did_set_browsedir(optset_T *args UNUSED)
 {
     if (check_opt_strings(p_bsdir, p_bsdir_values, FALSE) != OK
 	    && !mch_isdir(p_bsdir))
@@ -1770,8 +1815,8 @@ did_set_browsedir(void)
 /*
  * The 'keymodel' option is changed.
  */
-    static char *
-did_set_keymodel(void)
+    char *
+did_set_keymodel(optset_T *args UNUSED)
 {
     if (check_opt_strings(p_km, p_km_values, TRUE) != OK)
 	return e_invalid_argument;
@@ -1784,8 +1829,8 @@ did_set_keymodel(void)
 /*
  * The 'keyprotocol' option is changed.
  */
-    static char *
-did_set_keyprotocol(void)
+    char *
+did_set_keyprotocol(optset_T *args UNUSED)
 {
     if (match_keyprotocol(NULL) == KEYPROTOCOL_FAIL)
 	return e_invalid_argument;
@@ -1796,8 +1841,8 @@ did_set_keyprotocol(void)
 /*
  * The 'mousemodel' option is changed.
  */
-    static char *
-did_set_mousemodel(void)
+    char *
+did_set_mousemodel(optset_T *args UNUSED)
 {
     if (check_opt_strings(p_mousem, p_mousem_values, FALSE) != OK)
 	return e_invalid_argument;
@@ -1814,8 +1859,8 @@ did_set_mousemodel(void)
 /*
  * The 'display' option is changed.
  */
-    static char *
-did_set_display(void)
+    char *
+did_set_display(optset_T *args UNUSED)
 {
     if (opt_strings_flags(p_dy, p_dy_values, &dy_flags, TRUE) != OK)
 	return e_invalid_argument;
@@ -1824,14 +1869,14 @@ did_set_display(void)
     return NULL;
 }
 
-#ifdef FEAT_SPELL
+#if defined(FEAT_SPELL) || defined(PROTO)
 /*
  * The 'spellfile' option is changed.
  */
-    static char *
-did_set_spellfile(char_u **varp)
+    char *
+did_set_spellfile(optset_T *args)
 {
-    if (!valid_spellfile(*varp))
+    if (!valid_spellfile(args->os_varp))
 	return e_invalid_argument;
 
     // If there is a window for this buffer in which 'spell' is set load the
@@ -1842,10 +1887,10 @@ did_set_spellfile(char_u **varp)
 /*
  * The 'spell' option is changed.
  */
-    static char *
-did_set_spell(char_u **varp)
+    char *
+did_set_spelllang(optset_T *args)
 {
-    if (!valid_spelllang(*varp))
+    if (!valid_spelllang(args->os_varp))
 	return e_invalid_argument;
 
     // If there is a window for this buffer in which 'spell' is set load the
@@ -1856,8 +1901,8 @@ did_set_spell(char_u **varp)
 /*
  * The 'spellcapcheck' option is changed.
  */
-    static char *
-did_set_spellcapcheck(void)
+    char *
+did_set_spellcapcheck(optset_T *args UNUSED)
 {
     // compile the regexp program.
     return compile_cap_prog(curwin->w_s);
@@ -1866,10 +1911,10 @@ did_set_spellcapcheck(void)
 /*
  * The 'spelloptions' option is changed.
  */
-    static char *
-did_set_spelloptions(char_u **varp)
+    char *
+did_set_spelloptions(optset_T *args)
 {
-    if (**varp != NUL && STRCMP("camel", *varp) != 0)
+    if (*args->os_varp != NUL && STRCMP("camel", args->os_varp) != 0)
 	return e_invalid_argument;
 
     return NULL;
@@ -1878,8 +1923,8 @@ did_set_spelloptions(char_u **varp)
 /*
  * The 'spellsuggest' option is changed.
  */
-    static char *
-did_set_spellsuggest(void)
+    char *
+did_set_spellsuggest(optset_T *args UNUSED)
 {
     if (spell_check_sps() != OK)
 	return e_invalid_argument;
@@ -1890,8 +1935,8 @@ did_set_spellsuggest(void)
 /*
  * The 'mkspellmem' option is changed.
  */
-    static char *
-did_set_mkspellmem(void)
+    char *
+did_set_mkspellmem(optset_T *args UNUSED)
 {
     if (spell_check_msm() != OK)
 	return e_invalid_argument;
@@ -1903,8 +1948,8 @@ did_set_mkspellmem(void)
 /*
  * The 'buftype' option is changed.
  */
-    static char *
-did_set_buftype(void)
+    char *
+did_set_buftype(optset_T *args UNUSED)
 {
     if (check_opt_strings(curbuf->b_p_bt, p_buftype_values, FALSE) != OK)
 	return e_invalid_argument;
@@ -1923,18 +1968,19 @@ did_set_buftype(void)
 #ifdef FEAT_STL_OPT
 /*
  * The 'statusline' or the 'tabline' or the 'rulerformat' option is changed.
+ * "rulerformat" is TRUE if the 'rulerformat' option is changed.
  */
     static char *
-did_set_statusline(char_u **varp)
+did_set_statustabline_rulerformat(optset_T *args, int rulerformat)
 {
     char_u	*s;
     char	*errmsg = NULL;
     int		wid;
 
-    if (varp == &p_ruf)	// reset ru_wid first
+    if (rulerformat)	// reset ru_wid first
 	ru_wid = 0;
-    s = *varp;
-    if (varp == &p_ruf && *s == '%')
+    s = args->os_varp;
+    if (rulerformat && *s == '%')
     {
 	// set ru_wid if 'ruf' starts with "%99("
 	if (*++s == '-')	// ignore a '-'
@@ -1946,13 +1992,41 @@ did_set_statusline(char_u **varp)
 	    errmsg = check_stl_option(p_ruf);
     }
     // check 'statusline' or 'tabline' only if it doesn't start with "%!"
-    else if (varp == &p_ruf || s[0] != '%' || s[1] != '!')
+    else if (rulerformat || s[0] != '%' || s[1] != '!')
 	errmsg = check_stl_option(s);
-    if (varp == &p_ruf && errmsg == NULL)
+    if (rulerformat && errmsg == NULL)
 	comp_col();
 
     return errmsg;
 }
+
+/*
+ * The 'statusline' option is changed.
+ */
+    char *
+did_set_statusline(optset_T *args)
+{
+    return did_set_statustabline_rulerformat(args, FALSE);
+}
+
+/*
+ * The 'tabline' option is changed.
+ */
+    char *
+did_set_tabline(optset_T *args)
+{
+    return did_set_statustabline_rulerformat(args, FALSE);
+}
+
+
+/*
+ * The 'rulerformat' option is changed.
+ */
+    char *
+did_set_rulerformat(optset_T *args)
+{
+    return did_set_statustabline_rulerformat(args, TRUE);
+}
 #endif
 
 /*
@@ -2003,8 +2077,8 @@ did_set_complete(char_u **varp, char *er
 /*
  * The 'completeopt' option is changed.
  */
-    static char *
-did_set_completeopt(void)
+    char *
+did_set_completeopt(optset_T *args UNUSED)
 {
     if (check_opt_strings(p_cot, p_cot_values, TRUE) != OK)
 	return e_invalid_argument;
@@ -2013,12 +2087,12 @@ did_set_completeopt(void)
     return NULL;
 }
 
-#ifdef BACKSLASH_IN_FILENAME
+#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
 /*
  * The 'completeslash' option is changed.
  */
-    static char *
-did_set_completeslash(void)
+    char *
+did_set_completeslash(optset_T *args UNUSED)
 {
     if (check_opt_strings(p_csl, p_csl_values, FALSE) != OK
 	    || check_opt_strings(curbuf->b_p_csl, p_csl_values, FALSE) != OK)
@@ -2028,18 +2102,18 @@ did_set_completeslash(void)
 }
 #endif
 
-#ifdef FEAT_SIGNS
+#if defined(FEAT_SIGNS) || defined(PROTO)
 /*
  * The 'signcolumn' option is changed.
  */
-    static char *
-did_set_signcolumn(char_u **varp, char_u *oldval)
+    char *
+did_set_signcolumn(optset_T *args)
 {
-    if (check_opt_strings(*varp, p_scl_values, FALSE) != OK)
+    if (check_opt_strings(args->os_varp, p_scl_values, FALSE) != OK)
 	return e_invalid_argument;
     // When changing the 'signcolumn' to or from 'number', recompute the
     // width of the number column if 'number' or 'relativenumber' is set.
-    if (((*oldval == 'n' && *(oldval + 1) == 'u')
+    if (((*args->os_oldval.string == 'n' && args->os_oldval.string[1] == 'u')
 		|| (*curwin->w_p_scl == 'n' && *(curwin->w_p_scl + 1) =='u'))
 	    && (curwin->w_p_nu || curwin->w_p_rnu))
 	curwin->w_nrwidth_line_count = 0;
@@ -2048,12 +2122,12 @@ did_set_signcolumn(char_u **varp, char_u
 }
 #endif
 
-#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)
+#if (defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)) || defined(PROTO)
 /*
  * The 'toolbar' option is changed.
  */
-    static char *
-did_set_toolbar(void)
+    char *
+did_set_toolbar(optset_T *args UNUSED)
 {
     if (opt_strings_flags(p_toolbar, p_toolbar_values,
 		&toolbar_flags, TRUE) != OK)
@@ -2066,12 +2140,12 @@ did_set_toolbar(void)
 }
 #endif
 
-#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
+#if (defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)) || defined(PROTO)
 /*
  * The 'toolbariconsize' option is changed.  GTK+ 2 only.
  */
-    static char *
-did_set_toolbariconsize(void)
+    char *
+did_set_toolbariconsize(optset_T *args UNUSED)
 {
     if (opt_strings_flags(p_tbis, p_tbis_values, &tbis_flags, FALSE) != OK)
 	return e_invalid_argument;
@@ -2086,8 +2160,8 @@ did_set_toolbariconsize(void)
 /*
  * The 'pastetoggle' option is changed.
  */
-    static void
-did_set_pastetoggle(void)
+    char *
+did_set_pastetoggle(optset_T *args UNUSED)
 {
     char_u	*p;
 
@@ -2102,13 +2176,15 @@ did_set_pastetoggle(void)
 	    p_pt = p;
 	}
     }
+
+    return NULL;
 }
 
 /*
  * The 'backspace' option is changed.
  */
-    static char *
-did_set_backspace(void)
+    char *
+did_set_backspace(optset_T *args UNUSED)
 {
     if (VIM_ISDIGIT(*p_bs))
     {
@@ -2124,13 +2200,13 @@ did_set_backspace(void)
 /*
  * The 'tagcase' option is changed.
  */
-    static char *
-did_set_tagcase(int opt_flags)
+    char *
+did_set_tagcase(optset_T *args)
 {
     unsigned int	*flags;
     char_u		*p;
 
-    if (opt_flags & OPT_LOCAL)
+    if (args->os_flags & OPT_LOCAL)
     {
 	p = curbuf->b_p_tc;
 	flags = &curbuf->b_tc_flags;
@@ -2141,7 +2217,7 @@ did_set_tagcase(int opt_flags)
 	flags = &tc_flags;
     }
 
-    if ((opt_flags & OPT_LOCAL) && *p == NUL)
+    if ((args->os_flags & OPT_LOCAL) && *p == NUL)
 	// make the local value empty: use the global value
 	*flags = 0;
     else if (*p == NUL
@@ -2151,12 +2227,12 @@ did_set_tagcase(int opt_flags)
     return NULL;
 }
 
-#ifdef FEAT_DIFF
+#if defined(FEAT_DIFF) || defined(PROTO)
 /*
  * The 'diffopt' option is changed.
  */
-    static char *
-did_set_diffopt(void)
+    char *
+did_set_diffopt(optset_T *args UNUSED)
 {
     if (diffopt_changed() == FAIL)
 	return e_invalid_argument;
@@ -2165,14 +2241,14 @@ did_set_diffopt(void)
 }
 #endif
 
-#ifdef FEAT_FOLDING
+#if defined(FEAT_FOLDING) || defined(PROTO)
 /*
  * The 'foldmethod' option is changed.
  */
-    static char *
-did_set_foldmethod(char_u **varp)
+    char *
+did_set_foldmethod(optset_T *args)
 {
-    if (check_opt_strings(*varp, p_fdm_values, FALSE) != OK
+    if (check_opt_strings(args->os_varp, p_fdm_values, FALSE) != OK
 	    || *curwin->w_p_fdm == NUL)
 	return e_invalid_argument;
 
@@ -2185,15 +2261,15 @@ did_set_foldmethod(char_u **varp)
 /*
  * The 'foldmarker' option is changed.
  */
-    static char *
-did_set_foldmarker(char_u **varp)
+    char *
+did_set_foldmarker(optset_T *args)
 {
     char_u	*p;
 
-    p = vim_strchr(*varp, ',');
+    p = vim_strchr(args->os_varp, ',');
     if (p == NULL)
 	return e_comma_required;
-    else if (p == *varp || p[1] == NUL)
+    else if (p == args->os_varp || p[1] == NUL)
 	return e_invalid_argument;
     else if (foldmethodIsMarker(curwin))
 	foldUpdateAll(curwin);
@@ -2204,10 +2280,10 @@ did_set_foldmarker(char_u **varp)
 /*
  * The 'commentstring' option is changed.
  */
-    static char *
-did_set_commentstring(char_u **varp)
+    char *
+did_set_commentstring(optset_T *args)
 {
-    if (**varp != NUL && strstr((char *)*varp, "%s") == NULL)
+    if (*args->os_varp != NUL && strstr((char *)args->os_varp, "%s") == NULL)
 	return e_commentstring_must_be_empty_or_contain_str;
 
     return NULL;
@@ -2216,37 +2292,38 @@ did_set_commentstring(char_u **varp)
 /*
  * The 'foldignore' option is changed.
  */
-    static void
-did_set_foldignore(void)
+    char *
+did_set_foldignore(optset_T *args UNUSED)
 {
     if (foldmethodIsIndent(curwin))
 	foldUpdateAll(curwin);
+    return NULL;
 }
 #endif
 
 /*
  * The 'virtualedit' option is changed.
  */
-    static char *
-did_set_virtualedit(char_u *oldval, int opt_flags)
+    char *
+did_set_virtualedit(optset_T *args)
 {
     char_u		*ve = p_ve;
     unsigned int	*flags = &ve_flags;
 
-    if (opt_flags & OPT_LOCAL)
+    if (args->os_flags & OPT_LOCAL)
     {
 	ve = curwin->w_p_ve;
 	flags = &curwin->w_ve_flags;
     }
 
-    if ((opt_flags & OPT_LOCAL) && *ve == NUL)
+    if ((args->os_flags & OPT_LOCAL) && *ve == NUL)
 	// make the local value empty: use the global value
 	*flags = 0;
     else
     {
 	if (opt_strings_flags(ve, p_ve_values, flags, TRUE) != OK)
 	    return e_invalid_argument;
-	else if (STRCMP(ve, oldval) != 0)
+	else if (STRCMP(ve, args->os_oldval.string) != 0)
 	{
 	    // Recompute cursor position in case the new 've' setting
 	    // changes something.
@@ -2258,12 +2335,12 @@ did_set_virtualedit(char_u *oldval, int 
     return NULL;
 }
 
-#if defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)
+#if (defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)) || defined(PROTO)
 /*
  * The 'cscopequickfix' option is changed.
  */
-    static char *
-did_set_cscopequickfix(void)
+    char *
+did_set_cscopequickfix(optset_T *args UNUSED)
 {
     char_u	*p;
 
@@ -2291,32 +2368,34 @@ did_set_cscopequickfix(void)
 /*
  * The 'cinoptions' option is changed.
  */
-    static void
-did_set_cinoptions(void)
+    char *
+did_set_cinoptions(optset_T *args UNUSED)
 {
     // TODO: recognize errors
     parse_cino(curbuf);
+
+    return NULL;
 }
 
 /*
  * The 'lispoptions' option is changed.
  */
-    static char *
-did_set_lispoptions(char_u **varp)
+    char *
+did_set_lispoptions(optset_T *args)
 {
-    if (**varp != NUL && STRCMP(*varp, "expr:0") != 0
-	    && STRCMP(*varp, "expr:1") != 0)
+    if (*args->os_varp != NUL && STRCMP(args->os_varp, "expr:0") != 0
+	    && STRCMP(args->os_varp, "expr:1") != 0)
 	return e_invalid_argument;
 
     return NULL;
 }
 
-#if defined(FEAT_RENDER_OPTIONS)
+#if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
 /*
  * The 'renderoptions' option is changed.
  */
-    static char *
-did_set_renderoptions(void)
+    char *
+did_set_renderoptions(optset_T *args UNUSED)
 {
     if (!gui_mch_set_rendering_options(p_rop))
 	return e_invalid_argument;
@@ -2347,12 +2426,12 @@ did_set_filetype_or_syntax(
     return NULL;
 }
 
-#ifdef FEAT_TERMINAL
+#if defined(FEAT_TERMINAL) || defined(PROTO)
 /*
  * The 'termwinkey' option is changed.
  */
-    static char *
-did_set_termwinkey(void)
+    char *
+did_set_termwinkey(optset_T *args UNUSED)
 {
     if (*curwin->w_p_twk != NUL
 	    && string_to_key(curwin->w_p_twk, TRUE) == 0)
@@ -2364,8 +2443,8 @@ did_set_termwinkey(void)
 /*
  * The 'termwinsize' option is changed.
  */
-    static char *
-did_set_termwinsize(void)
+    char *
+did_set_termwinsize(optset_T *args UNUSED)
 {
     char_u	*p;
 
@@ -2382,16 +2461,16 @@ did_set_termwinsize(void)
 }
 #endif
 
-#ifdef FEAT_VARTABS
+#if defined(FEAT_VARTABS) || defined(PROTO)
 /*
  * The 'varsofttabstop' option is changed.
  */
-    static char *
-did_set_varsofttabstop(char_u **varp)
+    char *
+did_set_varsofttabstop(optset_T *args)
 {
     char_u *cp;
 
-    if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1]))
+    if (!(args->os_varp[0]) || (args->os_varp[0] == '0' && !(args->os_varp[1])))
     {
 	if (curbuf->b_p_vsts_array)
 	{
@@ -2401,17 +2480,17 @@ did_set_varsofttabstop(char_u **varp)
     }
     else
     {
-	for (cp = *varp; *cp; ++cp)
+	for (cp = args->os_varp; *cp; ++cp)
 	{
 	    if (vim_isdigit(*cp))
 		continue;
-	    if (*cp == ',' && cp > *varp && *(cp-1) != ',')
+	    if (*cp == ',' && cp > args->os_varp && *(cp-1) != ',')
 		continue;
 	    return e_invalid_argument;
 	}
 
 	int *oldarray = curbuf->b_p_vsts_array;
-	if (tabstop_set(*varp, &(curbuf->b_p_vsts_array)) == OK)
+	if (tabstop_set(args->os_varp, &(curbuf->b_p_vsts_array)) == OK)
 	{
 	    if (oldarray)
 		vim_free(oldarray);
@@ -2426,12 +2505,12 @@ did_set_varsofttabstop(char_u **varp)
 /*
  * The 'vartabstop' option is changed.
  */
-    static char *
-did_set_vartabstop(char_u **varp)
+    char *
+did_set_vartabstop(optset_T *args)
 {
     char_u *cp;
 
-    if (!(*varp)[0] || ((*varp)[0] == '0' && !(*varp)[1]))
+    if (!(args->os_varp[0]) || (args->os_varp[0] == '0' && !(args->os_varp[1])))
     {
 	if (curbuf->b_p_vts_array)
 	{
@@ -2441,18 +2520,18 @@ did_set_vartabstop(char_u **varp)
     }
     else
     {
-	for (cp = *varp; *cp; ++cp)
+	for (cp = args->os_varp; *cp; ++cp)
 	{
 	    if (vim_isdigit(*cp))
 		continue;
-	    if (*cp == ',' && cp > *varp && *(cp-1) != ',')
+	    if (*cp == ',' && cp > args->os_varp && *(cp-1) != ',')
 		continue;
 	    return e_invalid_argument;
 	}
 
 	int *oldarray = curbuf->b_p_vts_array;
 
-	if (tabstop_set(*varp, &(curbuf->b_p_vts_array)) == OK)
+	if (tabstop_set(args->os_varp, &(curbuf->b_p_vts_array)) == OK)
 	{
 	    vim_free(oldarray);
 # ifdef FEAT_FOLDING
@@ -2468,12 +2547,12 @@ did_set_vartabstop(char_u **varp)
 }
 #endif
 
-#ifdef FEAT_PROP_POPUP
+#if defined(FEAT_PROP_POPUP) || defined(PROTO)
 /*
  * The 'previewpopup' option is changed.
  */
-    static char *
-did_set_previewpopup(void)
+    char *
+did_set_previewpopup(optset_T *args UNUSED)
 {
     if (parse_previewpopup(NULL) == FAIL)
 	return e_invalid_argument;
@@ -2481,12 +2560,12 @@ did_set_previewpopup(void)
     return NULL;
 }
 
-# ifdef FEAT_QUICKFIX
+# if defined(FEAT_QUICKFIX) || defined(PROTO)
 /*
  * The 'completepopup' option is changed.
  */
-    static char *
-did_set_completepopup(void)
+    char *
+did_set_completepopup(optset_T *args UNUSED)
 {
     if (parse_completepopup(NULL) == FAIL)
 	return e_invalid_argument;
@@ -2629,6 +2708,7 @@ did_set_string_option(
     int		opt_idx,		// index in options[] table
     char_u	**varp,			// pointer to the option variable
     char_u	*oldval,		// previous value of the option
+    char_u	*value,			// new value of the option
     char	*errbuf,		// buffer for errors, or NULL
     int		opt_flags,		// OPT_LOCAL and/or OPT_GLOBAL
     int		*value_checked)		// value was checked to be safe, no
@@ -2638,12 +2718,9 @@ did_set_string_option(
     int		did_chartab = FALSE;
     char_u	**gvarp;
     long_u	free_oldval = (get_option_flags(opt_idx) & P_ALLOCED);
-#ifdef FEAT_GUI
-    // set when changing an option that only requires a redraw in the GUI
-    int		redraw_gui_only = FALSE;
-#endif
     int		value_changed = FALSE;
     int		did_swaptcap = FALSE;
+    opt_did_set_cb_T did_set_cb = get_option_did_set_cb(opt_idx);
 
     // Get the global option to compare with, otherwise we would have to check
     // two values for all local options.
@@ -2659,25 +2736,23 @@ did_set_string_option(
     // Check for a "normal" directory or file name in some options.
     else if (check_illegal_path_names(opt_idx, varp))
 	errmsg = e_invalid_argument;
+    else if (did_set_cb != NULL)
+    {
+	optset_T   args;
+
+	args.os_varp = *varp;
+	args.os_flags = opt_flags;
+	args.os_oldval.string = oldval;
+	args.os_newval.string = value;
+	errmsg = did_set_cb(&args);
+    }
     else if (varp == &T_NAME)			// 'term'
 	errmsg = did_set_term(&opt_idx, &free_oldval);
-    else if (gvarp == &p_bkc)			// 'backupcopy'
-	errmsg = did_set_backupcopy(oldval, opt_flags);
-    else if (  varp == &p_bex			// 'backupext'
-	    || varp == &p_pm)			// 'patchmode'
-	errmsg = did_set_backupext_or_patchmode();
-#ifdef FEAT_LINEBREAK
-    else if (varp == &curwin->w_p_briopt)	// 'breakindentopt'
-	errmsg = did_set_breakindentopt();
-#endif
-
     else if (  varp == &p_isi			// 'isident'
 	    || varp == &(curbuf->b_p_isk)	// 'iskeyword'
 	    || varp == &p_isp			// 'isprint'
 	    || varp == &p_isf)			// 'isfname'
 	errmsg = did_set_isopt(&did_chartab);
-    else if (varp == &p_hf)			// 'helpfile'
-	did_set_helpfile();
 #ifdef FEAT_SYN_HL
     else if (  varp == &curwin->w_p_culopt	// 'cursorlineopt'
 	    || gvarp == &curwin->w_allbuf_opt.wo_culopt)
@@ -2685,67 +2760,25 @@ did_set_string_option(
     else if (varp == &curwin->w_p_cc)		// 'colorcolumn'
 	errmsg = check_colorcolumn(curwin);
 #endif
-#ifdef FEAT_MULTI_LANG
-    else if (varp == &p_hlg)			// 'helplang'
-	errmsg = did_set_helplang();
-#endif
-    else if (varp == &p_hl)			// 'highlight'
-	errmsg = did_set_highlight();
     else if (gvarp == &p_nf)			// 'nrformats'
 	errmsg = did_set_opt_strings(*varp, p_nf_values, TRUE);
 #ifdef FEAT_SESSION
-    else if (varp == &p_ssop)			// 'sessionoptions'
-	errmsg = did_set_sessionoptions(oldval);
     else if (varp == &p_vop)			// 'viewoptions'
 	errmsg = did_set_opt_flags(p_vop, p_ssop_values, &vop_flags, TRUE);
 #endif
     else if (varp == &p_sbo)			// 'scrollopt'
 	errmsg = did_set_opt_strings(p_sbo, p_scbopt_values, TRUE);
-    else if (  varp == &p_ambw			// 'ambiwidth'
-	    || varp == &p_emoji)		// 'emoji'
-	errmsg = did_set_ambiwidth();
-    else if (varp == &p_bg)			// 'background'
-	errmsg = did_set_background();
-    else if (varp == &p_wim)			// 'wildmode'
-	errmsg = did_set_wildmode();
     else if (varp == &p_wop)			// 'wildoptions'
 	errmsg = did_set_opt_strings(p_wop, p_wop_values, TRUE);
-#ifdef FEAT_WAK
-    else if (varp == &p_wak)			// 'winaltkeys'
-	errmsg = did_set_winaltkeys();
-#endif
-    else if (varp == &p_ei)			// 'eventignore'
-	errmsg = did_set_eventignore();
-
     else if (  varp == &p_enc			// 'encoding'
 	    || gvarp == &p_fenc			// 'fileencoding'
 	    || varp == &p_tenc			// 'termencoding'
 	    || gvarp == &p_menc)		// 'makeencoding'
 	errmsg = did_set_encoding(varp, gvarp, opt_flags);
-#if defined(FEAT_POSTSCRIPT)
-    else if (varp == &p_penc)			// 'printencoding'
-	did_set_printencoding();
-#endif
-#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
-    else if (varp == &p_imak)			// 'imactivatekey'
-	errmsg = did_set_imactivatekey();
-#endif
 #ifdef FEAT_KEYMAP
     else if (varp == &curbuf->b_p_keymap)	// 'keymap'
 	errmsg = did_set_keymap(varp, opt_flags, value_checked);
 #endif
-    else if (gvarp == &p_ff)			// 'fileformat'
-	errmsg = did_set_fileformat(varp, oldval, opt_flags);
-    else if (varp == &p_ffs)			// 'fileformats'
-	errmsg = did_set_fileformats();
-#if defined(FEAT_CRYPT)
-    else if (gvarp == &p_key)			// 'cryptkey'
-	did_set_cryptkey(oldval);
-    else if (gvarp == &p_cm)			// 'cryptmethod'
-	errmsg = did_set_cryptmethod(oldval, opt_flags);
-#endif
-    else if (gvarp == &p_mps)			// 'matchpairs'
-	errmsg = did_set_matchpairs(varp);
     else if (gvarp == &p_com)			// 'comments'
 	errmsg = did_set_comments(varp, errbuf);
     else if (  varp == &p_lcs			// global 'listchars'
@@ -2755,10 +2788,6 @@ did_set_string_option(
 	errmsg = set_chars_option(curwin, varp, TRUE);
     else if (varp == &curwin->w_p_fcs)		// local 'fillchars'
 	errmsg = set_chars_option(curwin, varp, TRUE);
-    else if (varp == &p_cedit)			// 'cedit'
-	errmsg = check_cedit();
-    else if (varp == &p_vfile)			// 'verbosefile'
-	errmsg = did_set_verbosefile();
 #ifdef FEAT_VIMINFO
     else if (varp == &p_viminfo)		// 'viminfo'
 	errmsg = did_set_viminfo(errbuf);
@@ -2766,199 +2795,36 @@ did_set_string_option(
     // terminal options
     else if (istermoption_idx(opt_idx) && full_screen)
 	did_set_term_option(varp, &did_swaptcap);
-#ifdef FEAT_LINEBREAK
-    else if (gvarp == &p_sbr)			// 'showbreak'
-	errmsg = did_set_showbreak(varp);
-#endif
-#ifdef FEAT_GUI
-    else if (varp == &p_guifont)		// 'guifont'
-    {
-	errmsg = did_set_guifont(oldval);
-	redraw_gui_only = TRUE;
-    }
-# ifdef FEAT_XFONTSET
-    else if (varp == &p_guifontset)		// 'guifontset'
-    {
-	errmsg = did_set_guifontset();
-	redraw_gui_only = TRUE;
-    }
-# endif
-    else if (varp == &p_guifontwide)		// 'guifontwide'
-    {
-	errmsg = did_set_guifontwide();
-	redraw_gui_only = TRUE;
-    }
-#endif
-#if defined(FEAT_GUI_GTK)
-    else if (varp == &p_guiligatures)		// 'guiligatures'
-    {
-	did_set_guiligatures();
-	redraw_gui_only = TRUE;
-    }
-#endif
 #ifdef CURSOR_SHAPE
     else if (varp == &p_guicursor)		// 'guicursor'
 	errmsg = parse_shape_opt(SHAPE_CURSOR);
 #endif
-#ifdef FEAT_MOUSESHAPE
-    else if (varp == &p_mouseshape)		// 'mouseshape'
-	errmsg = did_set_mouseshape();
-#endif
-#ifdef FEAT_PRINTER
-    else if (varp == &p_popt)			// 'printoptions'
-	errmsg = parse_printoptions();
-# if defined(FEAT_POSTSCRIPT)
-    else if (varp == &p_pmfn)			// 'printmbfont'
-	errmsg = parse_printmbfont();
-# endif
-#endif
-#ifdef FEAT_LANGMAP
-    else if (varp == &p_langmap)		// 'langmap'
-	langmap_set();
-#endif
-#ifdef FEAT_LINEBREAK
-    else if (varp == &p_breakat)		// 'breakat'
-	fill_breakat_flags();
-#endif
-    else if (  varp == &p_titlestring		// 'titlestring'
-	    || varp == &p_iconstring)		// 'iconstring'
-	did_set_titleiconstring(varp);
-#ifdef FEAT_GUI
-    else if (varp == &p_go)			// 'guioptions'
-    {
-	did_set_guioptions(oldval);
-	redraw_gui_only = TRUE;
-    }
-#endif
-#if defined(FEAT_GUI_TABLINE)
-    else if (varp == &p_gtl)			// 'guitablabel'
-    {
-	did_set_guitablabel();
-	redraw_gui_only = TRUE;
-    }
-    else if (varp == &p_gtt)			// 'guitabtooltip'
-	redraw_gui_only = TRUE;
-#endif
-#if defined(UNIX) || defined(VMS)
-    else if (varp == &p_ttym)			// 'ttymouse'
-	errmsg = did_set_ttymouse();
-#endif
-    else if (varp == &p_sel)			// 'selection'
-	errmsg = did_set_selection();
     else if (varp == &p_slm)			// 'selectmode'
 	errmsg = did_set_opt_strings(p_slm, p_slm_values, TRUE);
-#ifdef FEAT_BROWSE
-    else if (varp == &p_bsdir)			// 'browsedir'
-	errmsg = did_set_browsedir();
-#endif
-    else if (varp == &p_km)			// 'keymodel'
-	errmsg = did_set_keymodel();
-    else if (varp == &p_kpc)			// 'keyprotocol'
-	errmsg = did_set_keyprotocol();
-    else if (varp == &p_mousem)			// 'mousemodel'
-	errmsg = did_set_mousemodel();
     else if (varp == &p_swb)			// 'switchbuf'
 	errmsg = did_set_opt_flags(p_swb, p_swb_values, &swb_flags, TRUE);
     else if (varp == &p_spk)			// 'splitkeep'
 	errmsg = did_set_opt_strings(p_spk, p_spk_values, FALSE);
     else if (varp == &p_debug)			// 'debug'
 	errmsg = did_set_opt_strings(p_debug, p_debug_values, TRUE);
-    else if (varp == &p_dy)			// 'display'
-	errmsg = did_set_display();
     else if (varp == &p_ead)			// 'eadirection'
 	errmsg = did_set_opt_strings(p_ead, p_ead_values, FALSE);
-#ifdef FEAT_CLIPBOARD
-    else if (varp == &p_cb)			// 'clipboard'
-	errmsg = check_clipboard_option();
-#endif
-#ifdef FEAT_SPELL
-    else if (varp == &(curwin->w_s->b_p_spf))	// 'spellfile'
-	errmsg = did_set_spellfile(varp);
-    else if (varp == &(curwin->w_s->b_p_spl))	// 'spell'
-	errmsg = did_set_spell(varp);
-    else if (varp == &(curwin->w_s->b_p_spc))	// 'spellcapcheck'
-	errmsg = did_set_spellcapcheck();
-    else if (varp == &(curwin->w_s->b_p_spo))	// 'spelloptions'
-	errmsg = did_set_spelloptions(varp);
-    else if (varp == &p_sps)			// 'spellsuggest'
-	errmsg = did_set_spellsuggest();
-    else if (varp == &p_msm)			// 'mkspellmem'
-	errmsg = did_set_mkspellmem();
-#endif
     else if (gvarp == &p_bh)			// 'bufhidden'
 	errmsg = did_set_opt_strings(curbuf->b_p_bh, p_bufhidden_values,
 								FALSE);
-    else if (gvarp == &p_bt)			// 'buftype'
-	errmsg = did_set_buftype();
-#ifdef FEAT_STL_OPT
-    else if (  gvarp == &p_stl			// 'statusline'
-	    || varp == &p_tal			// 'tabline'
-	    || varp == &p_ruf)			// 'rulerformat'
-	errmsg = did_set_statusline(varp);
-#endif
     else if (gvarp == &p_cpt)			// 'complete'
 	errmsg = did_set_complete(varp, errbuf);
-    else if (varp == &p_cot)			// 'completeopt'
-	errmsg = did_set_completeopt();
-#ifdef BACKSLASH_IN_FILENAME
-    else if (gvarp == &p_csl)			// 'completeslash'
-	errmsg = did_set_completeslash();
-#endif
-#ifdef FEAT_SIGNS
-    else if (varp == &curwin->w_p_scl)		// 'signcolumn'
-	errmsg = did_set_signcolumn(varp, oldval);
-#endif
     else if (varp == &p_sloc)			// 'showcmdloc'
 	errmsg = did_set_opt_strings(p_sloc, p_sloc_values, FALSE);
-#if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_MSWIN)
-    else if (varp == &p_toolbar)		// 'toolbar'
-	errmsg = did_set_toolbar();
-#endif
-#if defined(FEAT_TOOLBAR) && defined(FEAT_GUI_GTK)
-    else if (varp == &p_tbis)			// 'toolbariconsize'
-	errmsg = did_set_toolbariconsize();
-#endif
-    else if (varp == &p_pt)			// 'pastetoggle'
-	did_set_pastetoggle();
-    else if (varp == &p_bs)			// 'backspace'
-	errmsg = did_set_backspace();
     else if (varp == &p_bo)			// 'belloff'
 	errmsg = did_set_opt_flags(p_bo, p_bo_values, &bo_flags, TRUE);
-    else if (gvarp == &p_tc)			// 'tagcase'
-	errmsg = did_set_tagcase(opt_flags);
     else if (varp == &p_cmp)			// 'casemap'
 	errmsg = did_set_opt_flags(p_cmp, p_cmp_values, &cmp_flags, TRUE);
-#ifdef FEAT_DIFF
-    else if (varp == &p_dip)			// 'diffopt'
-	errmsg = did_set_diffopt();
-#endif
 #ifdef FEAT_FOLDING
-    else if (gvarp == &curwin->w_allbuf_opt.wo_fdm)	// 'foldmethod'
-	errmsg = did_set_foldmethod(varp);
-    else if (gvarp == &curwin->w_allbuf_opt.wo_fmr)	// 'foldmarker'
-	errmsg = did_set_foldmarker(varp);
-    else if (gvarp == &p_cms)			// 'commentstring'
-	errmsg = did_set_commentstring(varp);
     else if (varp == &p_fdo)			// 'foldopen'
 	errmsg = did_set_opt_flags(p_fdo, p_fdo_values, &fdo_flags, TRUE);
     else if (varp == &p_fcl)			// 'foldclose'
 	errmsg = did_set_opt_strings(p_fcl, p_fcl_values, TRUE);
-    else if (gvarp == &curwin->w_allbuf_opt.wo_fdi)	// 'foldignore'
-	did_set_foldignore();
-#endif
-    else if (gvarp == &p_ve)			// 'virtualedit'
-	errmsg = did_set_virtualedit(oldval, opt_flags);
-#if defined(FEAT_CSCOPE) && defined(FEAT_QUICKFIX)
-    else if (varp == &p_csqf)			// 'cscopequickfix'
-	errmsg = did_set_cscopequickfix();
-#endif
-    else if (gvarp == &p_cino)			// 'cinoptions'
-	did_set_cinoptions();
-    else if (gvarp == &p_lop)			// 'lispoptions'
-	errmsg = did_set_lispoptions(varp);
-#if defined(FEAT_RENDER_OPTIONS)
-    else if (varp == &p_rop)			// 'renderoptions'
-	errmsg = did_set_renderoptions();
 #endif
     else if (gvarp == &p_ft)			// 'filetype'
 	errmsg = did_set_filetype_or_syntax(varp, oldval, value_checked,
@@ -2969,10 +2835,6 @@ did_set_string_option(
 							&value_changed);
 #endif
 #ifdef FEAT_TERMINAL
-    else if (varp == &curwin->w_p_twk)		// 'termwinkey'
-	errmsg = did_set_termwinkey();
-    else if (varp == &curwin->w_p_tws)		// 'termwinsize'
-	errmsg = did_set_termwinsize();
     else if (varp == &curwin->w_p_wcr)		// 'wincolor'
 	term_update_wincolor(curwin);
 # if defined(MSWIN)
@@ -2980,20 +2842,6 @@ did_set_string_option(
 	errmsg = did_set_opt_strings(p_twt, p_twt_values, FALSE);
 # endif
 #endif
-#ifdef FEAT_VARTABS
-    else if (varp == &(curbuf->b_p_vsts))	// 'varsofttabstop'
-	errmsg = did_set_varsofttabstop(varp);
-    else if (varp == &(curbuf->b_p_vts))	// 'vartabstop'
-	errmsg = did_set_vartabstop(varp);
-#endif
-#ifdef FEAT_PROP_POPUP
-    else if (varp == &p_pvp)			// 'previewpopup'
-	errmsg = did_set_previewpopup();
-# ifdef FEAT_QUICKFIX
-    else if (varp == &p_cpp)			// 'completepopup'
-	errmsg = did_set_completepopup();
-# endif
-#endif
 #ifdef FEAT_EVAL
     else if (
 # ifdef FEAT_BEVAL
@@ -3020,31 +2868,6 @@ did_set_string_option(
 	    varp == &p_ccv)			// 'charconvert'
 	did_set_optexpr(varp);
 #endif
-#ifdef FEAT_COMPL_FUNC
-    else if (gvarp == &p_cfu)			// 'completefunc'
-	errmsg = set_completefunc_option();
-    else if (gvarp == &p_ofu)			// 'omnifunc'
-	errmsg = set_omnifunc_option();
-    else if (gvarp == &p_tsrfu)			// 'thesaurusfunc'
-	errmsg = set_thesaurusfunc_option();
-#endif
-#if defined(FEAT_EVAL) && \
-     (defined(FEAT_XIM) || defined(IME_WITHOUT_XIM) || defined(VIMDLL))
-    else if (gvarp == &p_imaf)			// 'imactivatefunc'
-	errmsg = set_imactivatefunc_option();
-    else if (gvarp == &p_imsf)			// 'imstatusfunc'
-	errmsg = set_imstatusfunc_option();
-#endif
-    else if (varp == &p_opfunc)			// 'operatorfunc'
-	errmsg = set_operatorfunc_option();
-#ifdef FEAT_QUICKFIX
-    else if (varp == &p_qftf)			// 'quickfixtextfunc'
-	errmsg = qf_process_qftf_option();
-#endif
-#ifdef FEAT_EVAL
-    else if (gvarp == &p_tfu)			// 'tagfunc'
-	errmsg = set_tagfunc_option();
-#endif
     else if (varp == &p_ww)			// 'whichwrap'
 	errmsg = did_set_option_listflag(varp, (char_u *)WW_ALL, errbuf);
     else if (varp == &p_shm)			// 'shortmess'
@@ -3143,6 +2966,25 @@ did_set_string_option(
     if ((opt_flags & OPT_NO_REDRAW) == 0)
     {
 #ifdef FEAT_GUI
+	// set when changing an option that only requires a redraw in the GUI
+	int	redraw_gui_only = FALSE;
+
+	if (varp == &p_go			// 'guioptions'
+		|| varp == &p_guifont		// 'guifont'
+# ifdef FEAT_GUI_TABLINE
+		|| varp == &p_gtl		// 'guitablabel'
+		|| varp == &p_gtt		// 'guitabtooltip'
+# endif
+# ifdef FEAT_XFONTSET
+		|| varp == &p_guifontset	// 'guifontset'
+# endif
+		|| varp == &p_guifontwide	// 'guifontwide'
+# ifdef FEAT_GUI_GTK
+		|| varp == &p_guiligatures	// 'guiligatures'
+# endif
+	    )
+	    redraw_gui_only = TRUE;
+
 	// check redraw when it's not a GUI option or the GUI is active.
 	if (!redraw_gui_only || gui.in_use)
 #endif
@@ -3226,9 +3068,8 @@ check_ff_value(char_u *p)
 }
 
 /*
- * Save the acutal shortmess Flags and clear them
- * temporarily to avoid that file messages
- * overwrites any output from the following commands.
+ * Save the actual shortmess Flags and clear them temporarily to avoid that
+ * file messages overwrites any output from the following commands.
  *
  * Caller must make sure to first call save_clear_shm_value() and then
  * restore_shm_value() exactly the same number of times.
--- a/src/proto/clipboard.pro
+++ b/src/proto/clipboard.pro
@@ -18,7 +18,7 @@ void clip_scroll_selection(int rows);
 void clip_copy_modeless_selection(int both);
 void clip_gen_set_selection(Clipboard_T *cbd);
 int clip_gen_owner_exists(Clipboard_T *cbd);
-char *check_clipboard_option(void);
+char *did_set_clipboard(optset_T *args);
 void open_app_context(void);
 void x11_setup_atoms(Display *dpy);
 void x11_setup_selection(Widget w);
--- a/src/proto/ex_getln.pro
+++ b/src/proto/ex_getln.pro
@@ -39,7 +39,7 @@ void f_setcmdline(typval_T *argvars, typ
 void f_setcmdpos(typval_T *argvars, typval_T *rettv);
 int get_cmdline_firstc(void);
 int get_list_range(char_u **str, int *num1, int *num2);
-char *check_cedit(void);
+char *did_set_cedit(optset_T *args);
 int is_in_cmdwin(void);
 char_u *script_get(exarg_T *eap, char_u *cmd);
 void get_user_input(typval_T *argvars, typval_T *rettv, int inputdialog, int secret);
--- a/src/proto/gui_xim.pro
+++ b/src/proto/gui_xim.pro
@@ -1,6 +1,6 @@
 /* gui_xim.c */
-char *set_imactivatefunc_option(void);
-char *set_imstatusfunc_option(void);
+char *did_set_imactivatefunc(optset_T *args);
+char *did_set_imstatusfunc(optset_T *args);
 void free_xim_stuff(void);
 int set_ref_in_im_funcs(int copyID);
 void im_set_active(int active);
--- a/src/proto/hardcopy.pro
+++ b/src/proto/hardcopy.pro
@@ -1,6 +1,6 @@
 /* hardcopy.c */
-char *parse_printoptions(void);
-char *parse_printmbfont(void);
+char *parse_printoptions(optset_T *args);
+char *parse_printmbfont(optset_T *args);
 int prt_header_height(void);
 int prt_use_number(void);
 int prt_get_unit(int idx);
--- a/src/proto/if_mzsch.pro
+++ b/src/proto/if_mzsch.pro
@@ -1,7 +1,7 @@
 /* if_mzsch.c */
 int mzscheme_enabled(int verbose);
 void mzvim_check_threads(void);
-void mzvim_reset_timer(void);
+char *did_set_mzquantum(void);
 void mzscheme_end(void);
 int mzscheme_main(void);
 void mzscheme_buffer_free(buf_T *buf);
--- a/src/proto/insexpand.pro
+++ b/src/proto/insexpand.pro
@@ -44,11 +44,11 @@ int ins_compl_bs(void);
 void ins_compl_addleader(int c);
 void ins_compl_addfrommatch(void);
 int ins_compl_prep(int c);
-char *set_completefunc_option(void);
+char *did_set_completefunc(optset_T *args);
 void set_buflocal_cfu_callback(buf_T *buf);
-char *set_omnifunc_option(void);
+char *did_set_omnifunc(optset_T *args);
 void set_buflocal_ofu_callback(buf_T *buf);
-char *set_thesaurusfunc_option(void);
+char *did_set_thesaurusfunc(optset_T *args);
 int set_ref_in_insexpand_funcs(int copyID);
 void f_complete(typval_T *argvars, typval_T *rettv);
 void f_complete_add(typval_T *argvars, typval_T *rettv);
--- a/src/proto/map.pro
+++ b/src/proto/map.pro
@@ -26,7 +26,7 @@ void init_mappings(void);
 void add_map(char_u *map, int mode, int nore);
 int langmap_adjust_mb(int c);
 void langmap_init(void);
-void langmap_set(void);
+char *did_set_langmap(optset_T *args);
 void ex_abbreviate(exarg_T *eap);
 void ex_map(exarg_T *eap);
 void ex_unmap(exarg_T *eap);
--- a/src/proto/ops.pro
+++ b/src/proto/ops.pro
@@ -17,7 +17,7 @@ void block_prep(oparg_T *oap, struct blo
 void op_addsub(oparg_T *oap, linenr_T Prenum1, int g_cmd);
 void clear_oparg(oparg_T *oap);
 void cursor_pos_info(dict_T *dict);
-char *set_operatorfunc_option(void);
+char *did_set_operatorfunc(optset_T *args);
 void free_operatorfunc_option(void);
 int set_ref_in_opfunc(int copyID);
 void do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank);
--- a/src/proto/option.pro
+++ b/src/proto/option.pro
@@ -24,6 +24,68 @@ int valid_name(char_u *val, char *allowe
 void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx);
 sctx_T *get_option_sctx(char *name);
 void set_term_option_sctx_idx(char *name, int opt_idx);
+char *did_set_compatible(optset_T *args);
+char *did_set_langremap(optset_T *args);
+char *did_set_langnoremap(optset_T *args);
+char *did_set_undofile(optset_T *args);
+char *did_set_readonly(optset_T *args);
+char *did_set_mousehide(optset_T *args);
+char *did_set_modifiable(optset_T *args);
+char *did_set_eof_eol_fixeol_bomb(optset_T *args);
+char *did_set_binary(optset_T *args);
+char *did_set_buflisted(optset_T *args);
+char *did_set_swapfile(optset_T *args);
+char *did_set_terse(optset_T *args);
+char *did_set_paste(optset_T *args);
+char *did_set_insertmode(optset_T *args);
+char *did_set_ignorecase(optset_T *args);
+char *did_set_hlsearch(optset_T *args);
+char *did_set_scrollbind(optset_T *args);
+char *did_set_previewwindow(optset_T *args);
+char *did_set_smoothscroll(optset_T *args);
+char *did_set_textmode(optset_T *args);
+char *did_set_textauto(optset_T *args);
+char *did_set_lisp(optset_T *args);
+char *did_set_title_icon(optset_T *args);
+char *did_set_modified(optset_T *args);
+char *did_set_shellslash(optset_T *args);
+char *did_set_wrap(optset_T *args);
+char *did_set_equalalways(optset_T *args);
+char *did_set_weirdinvert(optset_T *args);
+char *did_set_ballooneval(optset_T *args);
+char *did_set_balloonevalterm(optset_T *args);
+char *did_set_autochdir(optset_T *args);
+char *did_set_diff(optset_T *args);
+char *did_set_imdisable(optset_T *args);
+char *did_set_spell(optset_T *args);
+char *did_set_arabic(optset_T *args);
+char *did_set_number_relativenumber(optset_T *args);
+char *did_set_termguicolors(optset_T *args);
+char *did_set_winheight_helpheight(optset_T *args);
+char *did_set_winminheight(optset_T *args);
+char *did_set_winwidth(optset_T *args);
+char *did_set_winminwidth(optset_T *args);
+char *did_set_laststatus(optset_T *args);
+char *did_set_showtabline(optset_T *args);
+char *did_set_linespace(optset_T *args);
+char *did_set_foldlevel(optset_T *args);
+char *did_set_foldminlines(optset_T *args);
+char *did_set_foldnestmax(optset_T *args);
+char *did_set_foldcolumn(optset_T *args);
+char *did_set_shiftwidth_tabstop(optset_T *args);
+char *did_set_maxcombine(optset_T *args);
+char *did_set_iminsert(optset_T *args);
+char *did_set_imstyle(optset_T *args);
+char *did_set_window(optset_T *args);
+char *did_set_imsearch(optset_T *args);
+char *did_set_titlelen(optset_T *args);
+char *did_set_cmdheight(optset_T *args);
+char *did_set_updatecount(optset_T *args);
+char *did_set_conceallevel(optset_T *args);
+char *did_set_pyxversion(optset_T *args);
+char *did_set_numberwidth(optset_T *args);
+char *did_set_textwidth(optset_T *args);
+char *did_set_undolevels(optset_T *args);
 void check_redraw(long_u flags);
 int findoption(char_u *arg);
 getoption_T get_option_value(char_u *name, long *numval, char_u **stringval, int *flagsp, int scope);
@@ -55,6 +117,7 @@ void unset_global_local_option(char_u *n
 char_u *get_option_varp_scope(int opt_idx, int scope);
 char_u *get_option_var(int opt_idx);
 char_u *get_option_fullname(int opt_idx);
+opt_did_set_cb_T get_option_did_set_cb(int opt_idx);
 char_u *get_equalprg(void);
 void win_copy_options(win_T *wp_from, win_T *wp_to);
 void after_copy_winopt(win_T *wp);
@@ -72,7 +135,7 @@ void vimrc_found(char_u *fname, char_u *
 void change_compatible(int on);
 int option_was_set(char_u *name);
 int reset_option_was_set(char_u *name);
-void fill_breakat_flags(void);
+char *did_set_breakat(optset_T *args);
 int can_bs(int what);
 long get_scrolloff_value(void);
 long get_sidescrolloff_value(void);
--- a/src/proto/optionstr.pro
+++ b/src/proto/optionstr.pro
@@ -9,7 +9,78 @@ void set_string_option_direct(char_u *na
 void set_string_option_direct_in_win(win_T *wp, char_u *name, int opt_idx, char_u *val, int opt_flags, int set_sid);
 void set_string_option_direct_in_buf(buf_T *buf, char_u *name, int opt_idx, char_u *val, int opt_flags, int set_sid);
 char *set_string_option(int opt_idx, char_u *value, int opt_flags, char *errbuf);
-char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char *errbuf, int opt_flags, int *value_checked);
+char *did_set_backupcopy(optset_T *args);
+char *did_set_backupext_or_patchmode(optset_T *args);
+char *did_set_breakindentopt(optset_T *args);
+char *did_set_helpfile(optset_T *args);
+char *did_set_helplang(optset_T *args);
+char *did_set_highlight(optset_T *args);
+char *did_set_sessionoptions(optset_T *args);
+char *did_set_ambiwidth(optset_T *args);
+char *did_set_background(optset_T *args);
+char *did_set_wildmode(optset_T *args);
+char *did_set_winaltkeys(optset_T *args);
+char *did_set_eventignore(optset_T *args);
+char *did_set_printencoding(optset_T *args);
+char *did_set_imactivatekey(optset_T *args);
+char *did_set_fileformat(optset_T *args);
+char *did_set_fileformats(optset_T *args);
+char *did_set_cryptkey(optset_T *args);
+char *did_set_cryptmethod(optset_T *args);
+char *did_set_matchpairs(optset_T *args);
+char *did_set_verbosefile(optset_T *args);
+char *did_set_showbreak(optset_T *args);
+char *did_set_guifont(optset_T *args);
+char *did_set_guifontset(optset_T *args);
+char *did_set_guifontwide(optset_T *args);
+char *did_set_guiligatures(optset_T *args);
+char *did_set_mouseshape(optset_T *args);
+char *did_set_titlestring(optset_T *args);
+char *did_set_iconstring(optset_T *args);
+char *did_set_guioptions(optset_T *args);
+char *did_set_guitablabel(optset_T *args);
+char *did_set_ttymouse(optset_T *args);
+char *did_set_selection(optset_T *args);
+char *did_set_browsedir(optset_T *args);
+char *did_set_keymodel(optset_T *args);
+char *did_set_keyprotocol(optset_T *args);
+char *did_set_mousemodel(optset_T *args);
+char *did_set_display(optset_T *args);
+char *did_set_spellfile(optset_T *args);
+char *did_set_spelllang(optset_T *args);
+char *did_set_spellcapcheck(optset_T *args);
+char *did_set_spelloptions(optset_T *args);
+char *did_set_spellsuggest(optset_T *args);
+char *did_set_mkspellmem(optset_T *args);
+char *did_set_buftype(optset_T *args);
+char *did_set_statusline(optset_T *args);
+char *did_set_tabline(optset_T *args);
+char *did_set_rulerformat(optset_T *args);
+char *did_set_completeopt(optset_T *args);
+char *did_set_completeslash(optset_T *args);
+char *did_set_signcolumn(optset_T *args);
+char *did_set_toolbar(optset_T *args);
+char *did_set_toolbariconsize(optset_T *args);
+char *did_set_pastetoggle(optset_T *args);
+char *did_set_backspace(optset_T *args);
+char *did_set_tagcase(optset_T *args);
+char *did_set_diffopt(optset_T *args);
+char *did_set_foldmethod(optset_T *args);
+char *did_set_foldmarker(optset_T *args);
+char *did_set_commentstring(optset_T *args);
+char *did_set_foldignore(optset_T *args);
+char *did_set_virtualedit(optset_T *args);
+char *did_set_cscopequickfix(optset_T *args);
+char *did_set_cinoptions(optset_T *args);
+char *did_set_lispoptions(optset_T *args);
+char *did_set_renderoptions(optset_T *args);
+char *did_set_termwinkey(optset_T *args);
+char *did_set_termwinsize(optset_T *args);
+char *did_set_varsofttabstop(optset_T *args);
+char *did_set_vartabstop(optset_T *args);
+char *did_set_previewpopup(optset_T *args);
+char *did_set_completepopup(optset_T *args);
+char *did_set_string_option(int opt_idx, char_u **varp, char_u *oldval, char_u *value, char *errbuf, int opt_flags, int *value_checked);
 int check_ff_value(char_u *p);
 void save_clear_shm_value(void);
 void restore_shm_value(void);
--- a/src/proto/quickfix.pro
+++ b/src/proto/quickfix.pro
@@ -15,7 +15,7 @@ void ex_cclose(exarg_T *eap);
 void ex_copen(exarg_T *eap);
 void ex_cbottom(exarg_T *eap);
 linenr_T qf_current_entry(win_T *wp);
-char *qf_process_qftf_option(void);
+char *did_set_quickfixtextfunc(optset_T *args);
 int grep_internal(cmdidx_T cmdidx);
 void ex_make(exarg_T *eap);
 int qf_get_size(exarg_T *eap);
--- a/src/proto/spell.pro
+++ b/src/proto/spell.pro
@@ -16,7 +16,7 @@ void slang_clear_sug(slang_T *lp);
 void count_common_word(slang_T *lp, char_u *word, int len, int count);
 int byte_in_str(char_u *str, int n);
 int init_syl_tab(slang_T *slang);
-char *did_set_spelllang(win_T *wp);
+char *parse_spelllang(win_T *wp);
 int captype(char_u *word, char_u *end);
 void spell_delete_wordlist(void);
 void spell_free_all(void);
--- a/src/proto/tag.pro
+++ b/src/proto/tag.pro
@@ -1,5 +1,5 @@
 /* tag.c */
-char *set_tagfunc_option(void);
+char *did_set_tagfunc(optset_T *args);
 void free_tagfunc_option(void);
 int set_ref_in_tagfunc(int copyID);
 void set_buflocal_tfu_callback(buf_T *buf);
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -4534,7 +4534,7 @@ qf_find_buf(qf_info_T *qi)
  * Returns OK or FAIL.
  */
     char *
-qf_process_qftf_option(void)
+did_set_quickfixtextfunc(optset_T *args UNUSED)
 {
     if (option_set_callback_func(p_qftf, &qftf_cb) == FAIL)
 	return e_invalid_argument;
--- a/src/spell.c
+++ b/src/spell.c
@@ -1987,7 +1987,7 @@ count_syllables(slang_T *slang, char_u *
  * Returns NULL if it's OK, an untranslated error message otherwise.
  */
     char *
-did_set_spelllang(win_T *wp)
+parse_spelllang(win_T *wp)
 {
     garray_T	ga;
     char_u	*splp;
@@ -2503,7 +2503,7 @@ spell_reload(void)
 	{
 		if (wp->w_p_spell)
 		{
-		    (void)did_set_spelllang(wp);
+		    (void)parse_spelllang(wp);
 		    break;
 		}
 	}
@@ -4410,7 +4410,7 @@ did_set_spell_option(int is_spellfile)
     FOR_ALL_WINDOWS(wp)
 	if (wp->w_buffer == curbuf && wp->w_p_spell)
 	{
-	    errmsg = did_set_spelllang(wp);
+	    errmsg = parse_spelllang(wp);
 	    break;
 	}
     return errmsg;
--- a/src/spellfile.c
+++ b/src/spellfile.c
@@ -1771,7 +1771,7 @@ spell_reload_one(
     // When "zg" was used and the file wasn't loaded yet, should redo
     // 'spelllang' to load it now.
     if (added_word && !didit)
-	did_set_spelllang(curwin);
+	parse_spelllang(curwin);
 }
 
 
--- a/src/spellsuggest.c
+++ b/src/spellsuggest.c
@@ -480,7 +480,7 @@ spell_suggest(int count)
 
     if (!curwin->w_p_spell)
     {
-	did_set_spelllang(curwin);
+	parse_spelllang(curwin);
 	curwin->w_p_spell = TRUE;
     }
 
--- a/src/structs.h
+++ b/src/structs.h
@@ -4789,3 +4789,33 @@ typedef struct {
 #endif
     int		cts_vcol;	    // virtual column at current position
 } chartabsize_T;
+
+/*
+ * Argument for the callback function (opt_did_set_cb_T) invoked after an
+ * option value is modified.
+ */
+typedef struct
+{
+    int		os_flags;
+    char_u	*os_varp;		// pointer to the option variable
+
+    // old value of the option (can be a string, number or a boolean)
+    union
+    {
+	long	number;
+	int	boolean;
+	char_u	*string;
+    } os_oldval;
+
+    // new value of the option (can be a string, number or a boolean)
+    union
+    {
+	long	number;
+	int	boolean;
+	char_u	*string;
+    } os_newval;
+
+    // When set by the called function: Stop processing the option further.
+    // Currently only used for boolean options.
+    int		os_doskip;
+} optset_T;
--- a/src/tag.c
+++ b/src/tag.c
@@ -171,7 +171,7 @@ static callback_T tfu_cb;	    // 'tagfun
  * a function (string), or function(<name>) or funcref(<name>) or a lambda.
  */
     char *
-set_tagfunc_option(void)
+did_set_tagfunc(optset_T *args UNUSED)
 {
 #ifdef FEAT_EVAL
     free_callback(&tfu_cb);
--- 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 */
 /**/
+    1330,
+/**/
     1329,
 /**/
     1328,
--- a/src/vim.h
+++ b/src/vim.h
@@ -2284,6 +2284,12 @@ typedef enum {
     FCERR_FAILED,	// error while executing the function
 } funcerror_T;
 
+/*
+ * Type for the callback function that is invoked after an option value is
+ * changed to validate and apply the new value.
+ */
+typedef char *(*opt_did_set_cb_T)(optset_T *args);
+
 // Flags for assignment functions.
 #define ASSIGN_VAR	0     // ":var" (nothing special)
 #define ASSIGN_FINAL	0x01  // ":final"