Hi Bram!
On Fr, 19 Jun 2015, Bram Moolenaar wrote:
>
> Christian Brabandt wrote:
>
> > here is a patch, that implements an OptionSet autocommand. This can be
> > used, to execute certain actions when an option is set. The pattern is
> > matched against the long option name, so one can react to specific
> > options. E.g. Checking that the 'backupdir' directory exists and can be
> > created if necessary. It therefore provides the new v:option_new,
> > v:option_old and v:option_type so one can check the old and new value
> > and one can also get the scope of the set command.
> >
> > This still needs some work and I am also have to write some test for it,
> > but I figured I ask, whether this feature would be interesting enough to
> > be included, before I proceed with some more work on it.
> >
> > This is also mentioned in the todo list
> > ,----
> > | 7 Autocommand for when an option is changed. Match buffer name or
> > | option name?
> > `----
> >
> > Comments?
>
> Although this can be useful, it can also cause lots of trouble.
> Perhaps a big warning in the documentation could be enough?
> It should at least mention ":noautocommand" to avoid triggering the
> autocommands when it's not wanted.
Done.
> Some options have a side effect, I suppose the autocommand would only be
> triggered after the side effect?
Yes and only, if not error occurred.
> And when I set several options with one :set command, will all the new
> values be set before the first autocommand is triggered, or will the
> second value be set after the first triggered?
The second.
Updated patch attached. Fixes some bugs, includes tests and has
documentation updated.
Best,
Christian
--
In Sachen Umweltschutz sind die meisten Regierungen kriminelle
Vereinigungen.
-- Oliver Hassencamp
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.
Add an autocommand when an option is set.
Includes test
# HG changeset patch
# Parent d80ec0e36fea8d583a79ff63000d89a2b5f3f380
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -259,6 +259,7 @@ Name triggered by ~
|Syntax| when the 'syntax' option has been set
|EncodingChanged| after the 'encoding' option has been changed
|TermChanged| after the value of 'term' has changed
+|OptionSet| after setting an option
Startup and exit
|VimEnter| after doing all the startup stuff
@@ -742,6 +743,27 @@ MenuPopup Just before showing the popu
o Operator-pending
i Insert
c Command line
+ *OptionSet*
+OptionSet After setting an option. The pattern is
+ matched against the long option name.
+ The |v:option_old| variable indicates the
+ old option value, |v:option_new| variable
+ indicates the newly set value, the
+ |v:option_type| variable indicates whether
+ it's global or local scoped and |<amatch>|
+ indicates what option has been set.
+
+ Is not triggered on startup and for the 'key'
+ option for obvious reasons.
+
+ Note: It's a bad idea, to reset an option
+ during this autocommand, since this will
+ probably break plugins. You can always use
+ |noa| to prevent triggering this autocommand.
+ Could be used, to check for existence of the
+ 'backupdir' and 'undodir' options and create
+ directories, if they don't exist yet.
+
*QuickFixCmdPre*
QuickFixCmdPre Before a quickfix command is run (|:make|,
|:lmake|, |:grep|, |:lgrep|, |:grepadd|,
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1527,6 +1527,15 @@ v:oldfiles List of file names that is lo
than String this will cause trouble.
{only when compiled with the |+viminfo| feature}
+ *v:option_new*
+v:option_new Value of the new option. Valid while executing |OptionSet|
+ autocommand.
+ *v:option_old*
+v:option_old Value of the old option. Valid while executing |OptionSet|
+ autocommand.
+ *v:option_type*
+v:option_type Scope of the last option. Valid while executing
+ |OptionSet| autocommand. Can be either "global" or "local"
*v:operator* *operator-variable*
v:operator The last operator given in Normal mode. This is a single
character except for commands starting with <g> or <z>,
diff --git a/src/eval.c b/src/eval.c
--- a/src/eval.c
+++ b/src/eval.c
@@ -364,6 +364,9 @@ static struct vimvar
{VV_NAME("oldfiles", VAR_LIST), 0},
{VV_NAME("windowid", VAR_NUMBER), VV_RO},
{VV_NAME("progpath", VAR_STRING), VV_RO},
+ {VV_NAME("option_new", VAR_STRING), VV_RO},
+ {VV_NAME("option_old", VAR_STRING), VV_RO},
+ {VV_NAME("option_type", VAR_STRING), VV_RO},
};
/* shorthand */
@@ -12628,6 +12631,7 @@ f_has(argvars, rettv)
#endif
#ifdef FEAT_AUTOCMD
"autocmd",
+ "autocmd_option",
#endif
#ifdef FEAT_BEVAL
"balloon_eval",
@@ -24676,6 +24680,16 @@ ex_oldfiles(eap)
}
}
+/* reset v:option_new, v:option_old and v:option_type */
+ void
+reset_v_option_vars()
+{
+ set_vim_var_string(VV_OPTION_NEW, NULL, -1);
+ set_vim_var_string(VV_OPTION_OLD, NULL, -1);
+ set_vim_var_string(VV_OPTION_TYPE, NULL, -1);
+}
+
+
#endif /* FEAT_EVAL */
diff --git a/src/fileio.c b/src/fileio.c
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -7699,6 +7699,7 @@ static struct event_name
{"InsertLeave", EVENT_INSERTLEAVE},
{"InsertCharPre", EVENT_INSERTCHARPRE},
{"MenuPopup", EVENT_MENUPOPUP},
+ {"OptionSet", EVENT_OPTIONSET},
{"QuickFixCmdPost", EVENT_QUICKFIXCMDPOST},
{"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
{"QuitPre", EVENT_QUITPRE},
@@ -7736,7 +7737,7 @@ static AutoPat *first_autopat[NUM_EVENTS
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
/*
@@ -9321,7 +9322,7 @@ apply_autocmds_group(event, fname, fname
*/
if (fname_io == NULL)
{
- if (event == EVENT_COLORSCHEME)
+ if (event == EVENT_COLORSCHEME || event == EVENT_OPTIONSET)
autocmd_fname = NULL;
else if (fname != NULL && *fname != NUL)
autocmd_fname = fname;
@@ -9385,6 +9386,7 @@ apply_autocmds_group(event, fname, fname
|| event == EVENT_SPELLFILEMISSING
|| event == EVENT_QUICKFIXCMDPRE
|| event == EVENT_COLORSCHEME
+ || event == EVENT_OPTIONSET
|| event == EVENT_QUICKFIXCMDPOST)
fname = vim_strsave(fname);
else
diff --git a/src/option.c b/src/option.c
--- a/src/option.c
+++ b/src/option.c
@@ -3078,7 +3078,7 @@ static long_u *insecure_flag __ARGS((int
#endif
static void set_string_option_global __ARGS((int opt_idx, char_u **varp));
static char_u *set_string_option __ARGS((int opt_idx, char_u *value, int
opt_flags));
-static char_u *did_set_string_option __ARGS((int opt_idx, char_u **varp, int
new_value_alloced, char_u *oldval, char_u *errbuf, int opt_flags));
+static char_u *did_set_string_option __ARGS((int opt_idx, char_u **varp, int
new_value_alloced, char_u **oldval, char_u *errbuf, int opt_flags));
static char_u *set_chars_option __ARGS((char_u **varp));
#ifdef FEAT_SYN_HL
static int int_cmp __ARGS((const void *a, const void *b));
@@ -4586,7 +4586,7 @@ do_set(arg, opt_flags)
{
char_u *save_arg = NULL;
char_u *s = NULL;
- char_u *oldval; /* previous value if *varp */
+ char_u *oldval = NULL; /* previous value if
*varp */
char_u *newval;
char_u *origval;
unsigned newlen;
@@ -4911,11 +4911,29 @@ do_set(arg, opt_flags)
/* Handle side effects, and set the global value for
* ":set" on local options. */
errmsg = did_set_string_option(opt_idx, (char_u **)varp,
- new_value_alloced, oldval, errbuf, opt_flags);
+ new_value_alloced, &oldval, errbuf, opt_flags);
/* If error detected, print the error message. */
if (errmsg != NULL)
goto skip;
+#ifdef FEAT_AUTOCMD
+#ifdef FEAT_EVAL
+ if (!starting && options[opt_idx].indir != PV_KEY)
+ {
+ char_u buf_type[7];
+
+ sprintf((char *)buf_type, "%s",
+ (opt_flags & OPT_LOCAL) ? "local" : "global");
+ set_vim_var_string(VV_OPTION_NEW, newval, -1);
+ set_vim_var_string(VV_OPTION_OLD, origval, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ apply_autocmds(EVENT_OPTIONSET, (char_u
*)options[opt_idx].fullname,
+ NULL, FALSE, NULL);
+ reset_v_option_vars();
+ }
+#endif
+#endif
+
}
else /* key code option */
{
@@ -5677,9 +5695,27 @@ set_string_option(opt_idx, value, opt_fl
: opt_flags);
oldval = *varp;
*varp = s;
- if ((r = did_set_string_option(opt_idx, varp, TRUE, oldval, NULL,
+
+ if ((r = did_set_string_option(opt_idx, varp, TRUE, &oldval, NULL,
opt_flags)) == NULL)
did_set_option(opt_idx, opt_flags, TRUE);
+
+ /* call autocomamnd after handling side effects */
+#ifdef FEAT_AUTOCMD
+#ifdef FEAT_EVAL
+ if (!starting && options[opt_idx].indir != PV_KEY)
+ {
+ char_u buf_type[7];
+ sprintf((char *)buf_type, "%s",
+ (opt_flags & OPT_LOCAL) ? "local" : "global");
+ set_vim_var_string(VV_OPTION_NEW, s, -1);
+ set_vim_var_string(VV_OPTION_OLD, oldval, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ apply_autocmds(EVENT_OPTIONSET, (char_u
*)options[opt_idx].fullname, NULL, FALSE, NULL);
+ reset_v_option_vars();
+ }
+#endif
+#endif
}
return r;
}
@@ -5694,7 +5730,7 @@ did_set_string_option(opt_idx, varp, new
int opt_idx; /* index in options[] table */
char_u **varp; /* pointer to the option variable */
int new_value_alloced; /* new value was allocated */
- char_u *oldval; /* previous value of the option */
+ char_u **oldval; /* previous value of the option */
char_u *errbuf; /* buffer for errors, or NULL */
int opt_flags; /* OPT_LOCAL and/or OPT_GLOBAL
*/
{
@@ -5773,7 +5809,7 @@ did_set_string_option(opt_idx, varp, new
+ (((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(*oldval, p_bkc_values, flags, TRUE);
errmsg = e_invarg;
}
}
@@ -5875,7 +5911,7 @@ did_set_string_option(opt_idx, varp, new
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(*oldval, p_ssop_values, &ssop_flags, TRUE);
errmsg = e_invarg;
}
}
@@ -6151,7 +6187,7 @@ did_set_string_option(opt_idx, varp, new
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 || **oldval == 'm')
redraw_curbuf_later(NOT_VALID);
}
}
@@ -6180,9 +6216,9 @@ did_set_string_option(opt_idx, varp, new
* history. */
remove_key_from_history();
# endif
- if (STRCMP(curbuf->b_p_key, oldval) != 0)
+ if (STRCMP(curbuf->b_p_key, *oldval) != 0)
/* Need to update the swapfile. */
- ml_set_crypt_key(curbuf, oldval,
+ ml_set_crypt_key(curbuf, *oldval,
*curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm);
}
@@ -6218,10 +6254,10 @@ did_set_string_option(opt_idx, varp, new
/* 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 ((opt_flags & OPT_LOCAL) && **oldval == NUL)
s = p_cm; /* was previously using the global value */
else
- s = oldval;
+ s = *oldval;
if (*curbuf->b_p_cm == NUL)
p = p_cm; /* is now using the global value */
else
@@ -6231,13 +6267,13 @@ did_set_string_option(opt_idx, varp, new
/* 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 ((opt_flags & OPT_GLOBAL) && STRCMP(p_cm, *oldval) != 0)
{
buf_T *buf;
for (buf = firstbuf; buf != NULL; buf = buf->b_next)
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, *oldval);
}
}
}
@@ -6482,12 +6518,12 @@ did_set_string_option(opt_idx, varp, new
*/
if (STRCMP(p, "*") == 0)
{
- p = gui_mch_font_dialog(oldval);
+ p = gui_mch_font_dialog(*oldval);
if (new_value_alloced)
free_string_option(p_guifont);
- p_guifont = (p != NULL) ? p : vim_strsave(oldval);
+ p_guifont = (p != NULL) ? p : vim_strsave(*oldval);
new_value_alloced = TRUE;
}
# endif
@@ -6500,7 +6536,7 @@ did_set_string_option(opt_idx, varp, new
* an error message. */
if (new_value_alloced)
free_string_option(p_guifont);
- p_guifont = vim_strsave(oldval);
+ p_guifont = vim_strsave(*oldval);
new_value_alloced = TRUE;
}
else
@@ -6590,7 +6626,7 @@ did_set_string_option(opt_idx, varp, new
/* 'guioptions' */
else if (varp == &p_go)
{
- gui_init_which_components(oldval);
+ gui_init_which_components(*oldval);
redraw_gui_only = TRUE;
}
#endif
@@ -6668,7 +6704,7 @@ did_set_string_option(opt_idx, varp, new
if (check_opt_strings(p_mousem, p_mousem_values, FALSE) != OK)
errmsg = e_invarg;
#if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU) && (XmVersion <= 1002)
- else if (*p_mousem != *oldval)
+ else if (*p_mousem != **oldval)
/* Changed from "extend" to "popup" or "popup_setpos" or vv: need
* to create or delete the popup menus. */
gui_motif_update_mousemodel(root_menu);
@@ -7014,7 +7050,7 @@ did_set_string_option(opt_idx, varp, new
{
if (opt_strings_flags(p_ve, p_ve_values, &ve_flags, TRUE) != OK)
errmsg = e_invarg;
- else if (STRCMP(p_ve, oldval) != 0)
+ else if (STRCMP(p_ve, *oldval) != 0)
{
/* Recompute cursor position in case the new 've' setting
* changes something. */
@@ -7113,7 +7149,7 @@ did_set_string_option(opt_idx, varp, new
{
if (new_value_alloced)
free_string_option(*varp);
- *varp = oldval;
+ *varp = *oldval;
/*
* When resetting some values, need to act on it.
*/
@@ -7134,7 +7170,7 @@ did_set_string_option(opt_idx, varp, new
* our fingers (esp. init_highlight()).
*/
if (free_oldval)
- free_string_option(oldval);
+ clear_string_option(oldval);
if (new_value_alloced)
options[opt_idx].flags |= P_ALLOCED;
else
@@ -8219,8 +8255,27 @@ set_bool_option(opt_idx, varp, value, op
* End of handling side effects for bool options.
*/
+ /* after handling side effects, call autocommand */
+
options[opt_idx].flags |= P_WAS_SET;
+#ifdef FEAT_AUTOCMD
+#ifdef FEAT_EVAL
+ if (!starting)
+ {
+ char_u buf_old[2], buf_new[2], buf_type[7];
+ snprintf((char *)buf_old, 2, "%d", old_value ? TRUE: FALSE);
+ snprintf((char *)buf_new, 2, "%d", value ? TRUE: FALSE);
+ sprintf((char *)buf_type, "%s", (opt_flags & OPT_LOCAL) ? "local" :
"global");
+ set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
+ set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ apply_autocmds(EVENT_OPTIONSET, (char_u *) options[opt_idx].fullname,
NULL, FALSE, NULL);
+ reset_v_option_vars();
+ }
+#endif
+#endif
+
comp_col(); /* in case 'ruler' or 'showcmd'
changed */
if (curwin->w_curswant != MAXCOL
&& (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
@@ -8756,6 +8811,23 @@ set_num_option(opt_idx, varp, value, err
options[opt_idx].flags |= P_WAS_SET;
+#ifdef FEAT_AUTOCMD
+#ifdef FEAT_EVAL
+ if (!starting && errmsg == NULL)
+ {
+ char_u buf_old[11], buf_new[11], buf_type[7];
+ snprintf((char *)buf_old, 10, "%ld", old_value);
+ snprintf((char *)buf_new, 10, "%ld", value);
+ snprintf((char *)buf_type, 7, "%s", (opt_flags & OPT_LOCAL) ? "local" :
"global");
+ set_vim_var_string(VV_OPTION_NEW, buf_new, -1);
+ set_vim_var_string(VV_OPTION_OLD, buf_old, -1);
+ set_vim_var_string(VV_OPTION_TYPE, buf_type, -1);
+ apply_autocmds(EVENT_OPTIONSET, (char_u *) options[opt_idx].fullname,
NULL, FALSE, NULL);
+ reset_v_option_vars();
+ }
+#endif
+#endif
+
comp_col(); /* in case 'columns' or 'ls'
changed */
if (curwin->w_curswant != MAXCOL
&& (options[opt_idx].flags & (P_CURSWANT | P_RALL)) != 0)
diff --git a/src/proto/eval.pro b/src/proto/eval.pro
--- a/src/proto/eval.pro
+++ b/src/proto/eval.pro
@@ -134,4 +134,5 @@ void last_set_msg __ARGS((scid_T scriptI
void ex_oldfiles __ARGS((exarg_T *eap));
int modify_fname __ARGS((char_u *src, int *usedlen, char_u **fnamep, char_u
**bufp, int *fnamelen));
char_u *do_string_sub __ARGS((char_u *str, char_u *pat, char_u *sub, char_u
*flags));
+void reset_v_option_vars __ARGS((void));
/* vim: set ft=c : */
diff --git a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak
--- a/src/testdir/Make_amiga.mak
+++ b/src/testdir/Make_amiga.mak
@@ -38,6 +38,7 @@ SCRIPTS = test1.out test3.out test4.out
test104.out test105.out test106.out test107.out \
test_argument_0count.out \
test_argument_count.out \
+ test_autocmd_option.out \
test_autoformat_join.out \
test_breakindent.out \
test_changelist.out \
diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak
--- a/src/testdir/Make_dos.mak
+++ b/src/testdir/Make_dos.mak
@@ -37,6 +37,7 @@ SCRIPTS = test3.out test4.out test5.out
test105.out test106.out test107.out\
test_argument_0count.out \
test_argument_count.out \
+ test_autocmd_option.out \
test_autoformat_join.out \
test_breakindent.out \
test_changelist.out \
diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -59,6 +59,7 @@ SCRIPTS = test3.out test4.out test5.out
test105.out test106.out test107.out \
test_argument_0count.out \
test_argument_count.out \
+ test_autocmd_option.out \
test_autoformat_join.out \
test_breakindent.out \
test_changelist.out \
diff --git a/src/testdir/Make_os2.mak b/src/testdir/Make_os2.mak
--- a/src/testdir/Make_os2.mak
+++ b/src/testdir/Make_os2.mak
@@ -39,6 +39,7 @@ SCRIPTS = test1.out test3.out test4.out
test105.out test106.out test107.out \
test_argument_0count.out \
test_argument_count.out \
+ test_autocmd_option.out \
test_autoformat_join.out \
test_breakindent.out \
test_changelist.out \
diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms
--- a/src/testdir/Make_vms.mms
+++ b/src/testdir/Make_vms.mms
@@ -98,6 +98,7 @@ SCRIPT = test1.out test2.out test3.out
test105.out test106.out test107.out \
test_argument_0count.out \
test_argument_count.out \
+ test_autocmd_option.out \
test_autoformat_join.out \
test_breakindent.out \
test_changelist.out \
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -35,6 +35,7 @@ SCRIPTS = test1.out test2.out test3.out
test104.out test105.out test106.out test107.out \
test_argument_0count.out \
test_argument_count.out \
+ test_autocmd_option.out \
test_autoformat_join.out \
test_breakindent.out \
test_changelist.out \
diff --git a/src/testdir/test_autocmd_option.in
b/src/testdir/test_autocmd_option.in
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_autocmd_option.in
@@ -0,0 +1,73 @@
+Test for option autocommand
+
+STARTTEST
+:so small.vim
+:if !has("eval") || !has("autocmd") | e! test.ok | w! test.out | qa! | endif
+:fu! AutoCommand(match)
+: let c=g:testcase
+: let item=remove(g:options, 0)
+: let c.=printf("Expected: Name: <%s>, Oldval: <%s>, NewVal: <%s>,
Scope: <%s>\n", item[0], item[1], item[2], item[3])
+: let c.=printf("Autocmd Option: <%s>,", a:match)
+: let c.=printf(" OldVal: <%s>,", v:option_old)
+: let c.=printf(" NewVal: <%s>,", v:option_new)
+: let c.=printf(" Scope: <%s>\n", v:option_type)
+: call setreg('r', printf("%s\n%s", getreg('r'), c))
+:endfu
+:au OptionSet * :call AutoCommand(expand("<amatch>"))
+:let g:testcase="1: Setting number option\n"
+:let g:options=[['number', 0, 1, 'global']]
+:set nu
+:let g:testcase="2: Setting local number option\n"
+:let g:options=[['number', 1, 0, 'local']]
+:setlocal nonu
+:let g:testcase="3: Setting global number option\n"
+:let g:options=[['number', 1, 0, 'global']]
+:setglobal nonu
+:let g:testcase="4: Setting local autoindent option\n"
+:let g:options=[['autoindent', 0, 1, 'local']]
+:setlocal ai
+:let g:testcase="5: Setting global autoindent option\n"
+:let g:options=[['autoindent', 0, 1, 'global']]
+:setglobal ai
+:let g:testcase="6: Setting global autoindent option\n"
+:let g:options=[['autoindent', 1, 0, 'global']]
+:set ai!
+: Should not print anything, use :noa
+:noa :set nonu
+:let g:testcase="7: Setting several global list and number option\n"
+:let g:options=[['list', 0, 1, 'global'], ['number', 0, 1, 'global']]
+:set list nu
+:noa set nolist nonu
+:let g:testcase="8: Setting global acd\n"
+:let g:options=[['autochdir', 0, 1, 'global']]
+:setlocal acd
+:let g:testcase="9: Setting global autoread\n"
+:let g:options=[['autoread', 0, 1, 'global']]
+:set ar
+:let g:testcase="10: Setting local autoread\n"
+:let g:options=[['autoread', 0, 1, 'local']]
+:setlocal ar
+:let g:testcase="11: Setting global autoread\n"
+:let g:options=[['autoread', 1, 0, 'global']]
+:setglobal invar
+:let g:testcase="12: Setting option backspace through :let\n"
+:let g:options=[['backspace', '', 'eol,indent,start', 'global']]
+:let &bs="eol,indent,start"
+:let g:testcase="13: Setting option backspace through setbufvar()\n"
+:let g:options=[['backup', '', '1', 'local']]
+: "try twice, first time, shouldn't trigger because option name is invalid,
second time, it should trigger
+:call setbufvar(1, '&l:bk', 1)
+: "should trigger, use correct option name
+:call setbufvar(1, '&backup', 1)
+:" Write register now, because next test shouldn't output anything.
+:$put r
+:let @r=''
+:let g:testcase="\n14: Setting key option, shouldn't trigger\n"
+:let g:options=[['key', 'invalid', 'invalid1', 'invalid']]
+:setlocal key=blah
+:setlocal key=
+:$put =g:testcase
+:%w! test.out
+:qa!
+ENDTEST
+dummy text
diff --git a/src/testdir/test_autocmd_option.ok
b/src/testdir/test_autocmd_option.ok
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_autocmd_option.ok
@@ -0,0 +1,131 @@
+Test for option autocommand
+
+STARTTEST
+:so small.vim
+:if !has("eval") || !has("autocmd") | e! test.ok | w! test.out | qa! | endif
+:fu! AutoCommand(match)
+: let c=g:testcase
+: let item=remove(g:options, 0)
+: let c.=printf("Expected: Name: <%s>, Oldval: <%s>, NewVal: <%s>,
Scope: <%s>\n", item[0], item[1], item[2], item[3])
+: let c.=printf("Autocmd Option: <%s>,", a:match)
+: let c.=printf(" OldVal: <%s>,", v:option_old)
+: let c.=printf(" NewVal: <%s>,", v:option_new)
+: let c.=printf(" Scope: <%s>\n", v:option_type)
+: call setreg('r', printf("%s\n%s", getreg('r'), c))
+:endfu
+:au OptionSet * :call AutoCommand(expand("<amatch>"))
+:let g:testcase="1: Setting number option\n"
+:let g:options=[['number', 0, 1, 'global']]
+:set nu
+:let g:testcase="2: Setting local number option\n"
+:let g:options=[['number', 1, 0, 'local']]
+:setlocal nonu
+:let g:testcase="3: Setting global number option\n"
+:let g:options=[['number', 1, 0, 'global']]
+:setglobal nonu
+:let g:testcase="4: Setting local autoindent option\n"
+:let g:options=[['autoindent', 0, 1, 'local']]
+:setlocal ai
+:let g:testcase="5: Setting global autoindent option\n"
+:let g:options=[['autoindent', 0, 1, 'global']]
+:setglobal ai
+:let g:testcase="6: Setting global autoindent option\n"
+:let g:options=[['autoindent', 1, 0, 'global']]
+:set ai!
+: Should not print anything, use :noa
+:noa :set nonu
+:let g:testcase="7: Setting several global list and number option\n"
+:let g:options=[['list', 0, 1, 'global'], ['number', 0, 1, 'global']]
+:set list nu
+:noa set nolist nonu
+:let g:testcase="8: Setting global acd\n"
+:let g:options=[['autochdir', 0, 1, 'global']]
+:setlocal acd
+:let g:testcase="9: Setting global autoread\n"
+:let g:options=[['autoread', 0, 1, 'global']]
+:set ar
+:let g:testcase="10: Setting local autoread\n"
+:let g:options=[['autoread', 0, 1, 'local']]
+:setlocal ar
+:let g:testcase="11: Setting global autoread\n"
+:let g:options=[['autoread', 1, 0, 'global']]
+:setglobal invar
+:let g:testcase="12: Setting option backspace through :let\n"
+:let g:options=[['backspace', '', 'eol,indent,start', 'global']]
+:let &bs="eol,indent,start"
+:let g:testcase="13: Setting option backspace through setbufvar()\n"
+:let g:options=[['backup', '', '1', 'local']]
+: "try twice, first time, shouldn't trigger because option name is invalid,
second time, it should trigger
+:call setbufvar(1, '&l:bk', 1)
+: "should trigger, use correct option name
+:call setbufvar(1, '&backup', 1)
+:" Write register now, because next test shouldn't output anything.
+:$put r
+:let @r=''
+:let g:testcase="\n14: Setting key option, shouldn't trigger\n"
+:let g:options=[['key', 'invalid', 'invalid1', 'invalid']]
+:setlocal key=blah
+:setlocal key=
+:$put =g:testcase
+:%w! test.out
+:qa!
+ENDTEST
+dummy text
+
+1: Setting number option
+Expected: Name: <number>, Oldval: <0>, NewVal: <1>, Scope: <global>
+Autocmd Option: <number>, OldVal: <0>, NewVal: <1>, Scope: <global>
+
+2: Setting local number option
+Expected: Name: <number>, Oldval: <1>, NewVal: <0>, Scope: <local>
+Autocmd Option: <number>, OldVal: <1>, NewVal: <0>, Scope: <local>
+
+3: Setting global number option
+Expected: Name: <number>, Oldval: <1>, NewVal: <0>, Scope: <global>
+Autocmd Option: <number>, OldVal: <1>, NewVal: <0>, Scope: <global>
+
+4: Setting local autoindent option
+Expected: Name: <autoindent>, Oldval: <0>, NewVal: <1>, Scope: <local>
+Autocmd Option: <autoindent>, OldVal: <0>, NewVal: <1>, Scope: <local>
+
+5: Setting global autoindent option
+Expected: Name: <autoindent>, Oldval: <0>, NewVal: <1>, Scope: <global>
+Autocmd Option: <autoindent>, OldVal: <0>, NewVal: <1>, Scope: <global>
+
+6: Setting global autoindent option
+Expected: Name: <autoindent>, Oldval: <1>, NewVal: <0>, Scope: <global>
+Autocmd Option: <autoindent>, OldVal: <1>, NewVal: <0>, Scope: <global>
+
+7: Setting several global list and number option
+Expected: Name: <list>, Oldval: <0>, NewVal: <1>, Scope: <global>
+Autocmd Option: <list>, OldVal: <0>, NewVal: <1>, Scope: <global>
+
+7: Setting several global list and number option
+Expected: Name: <number>, Oldval: <0>, NewVal: <1>, Scope: <global>
+Autocmd Option: <number>, OldVal: <0>, NewVal: <1>, Scope: <global>
+
+8: Setting global acd
+Expected: Name: <autochdir>, Oldval: <0>, NewVal: <1>, Scope: <global>
+Autocmd Option: <autochdir>, OldVal: <0>, NewVal: <1>, Scope: <local>
+
+9: Setting global autoread
+Expected: Name: <autoread>, Oldval: <0>, NewVal: <1>, Scope: <global>
+Autocmd Option: <autoread>, OldVal: <0>, NewVal: <1>, Scope: <global>
+
+10: Setting local autoread
+Expected: Name: <autoread>, Oldval: <0>, NewVal: <1>, Scope: <local>
+Autocmd Option: <autoread>, OldVal: <1>, NewVal: <1>, Scope: <local>
+
+11: Setting global autoread
+Expected: Name: <autoread>, Oldval: <1>, NewVal: <0>, Scope: <global>
+Autocmd Option: <autoread>, OldVal: <1>, NewVal: <0>, Scope: <global>
+
+12: Setting option backspace through :let
+Expected: Name: <backspace>, Oldval: <>, NewVal: <eol,indent,start>, Scope:
<global>
+Autocmd Option: <backspace>, OldVal: <>, NewVal: <eol,indent,start>, Scope:
<global>
+
+13: Setting option backspace through setbufvar()
+Expected: Name: <backup>, Oldval: <>, NewVal: <1>, Scope: <local>
+Autocmd Option: <backup>, OldVal: <0>, NewVal: <1>, Scope: <local>
+
+14: Setting key option, shouldn't trigger
diff --git a/src/version.c b/src/version.c
--- a/src/version.c
+++ b/src/version.c
@@ -2252,6 +2252,7 @@ static int included_patches[] =
*/
static char *(extra_patches[]) =
{ /* Add your patch description below this line */
+ "option_autocmd",
/**/
NULL
};
diff --git a/src/vim.h b/src/vim.h
--- a/src/vim.h
+++ b/src/vim.h
@@ -1335,6 +1335,7 @@ enum auto_event
EVENT_TEXTCHANGED, /* text was modified */
EVENT_TEXTCHANGEDI, /* text was modified in Insert mode*/
EVENT_CMDUNDEFINED, /* command undefined */
+ EVENT_OPTIONSET, /* option was set */
NUM_EVENTS /* MUST be the last one */
};
@@ -1897,7 +1898,10 @@ typedef int proftime_T; /* dummy for
#define VV_OLDFILES 55
#define VV_WINDOWID 56
#define VV_PROGPATH 57
-#define VV_LEN 58 /* number of v: vars */
+#define VV_OPTION_NEW 58
+#define VV_OPTION_OLD 59
+#define VV_OPTION_TYPE 60
+#define VV_LEN 61 /* number of v: vars */
#ifdef FEAT_CLIPBOARD