diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/vim.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 22 | ||||
-rw-r--r-- | src/nvim/lua/vim.lua | 246 | ||||
-rw-r--r-- | src/nvim/option.c | 4 | ||||
-rw-r--r-- | src/nvim/regexp.c | 32 | ||||
-rw-r--r-- | src/nvim/regexp_nfa.c | 59 | ||||
-rw-r--r-- | src/nvim/testdir/test_regexp_utf8.vim | 46 | ||||
-rw-r--r-- | src/nvim/testdir/test_search.vim | 19 | ||||
-rw-r--r-- | src/nvim/testdir/test_writefile.vim | 21 |
9 files changed, 231 insertions, 220 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index e9a0b0df2e..a76cefe294 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -984,7 +984,7 @@ Dictionary nvim_get_all_options_info(Error *err) /// Resulting dictionary has keys: /// - name: Name of the option (like 'filetype') /// - shortname: Shortened name of the option (like 'ft') -/// - type: type of option ("string", "integer" or "boolean") +/// - type: type of option ("string", "number" or "boolean") /// - default: The default value for the option /// - was_set: Whether the option was set. /// diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index c93f9fe6f2..29347def4c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -5017,7 +5017,7 @@ char_u *check_nextcmd(char_u *p) static int check_more( int message, // when FALSE check only, no messages - int forceit + bool forceit ) { int n = ARGCOUNT - curwin->w_arg_idx - 1; @@ -6340,7 +6340,7 @@ void not_exiting(void) exiting = false; } -static bool before_quit_autocmds(win_T *wp, bool quit_all, int forceit) +bool before_quit_autocmds(win_T *wp, bool quit_all, bool forceit) { apply_autocmds(EVENT_QUITPRE, NULL, NULL, false, wp->w_buffer); @@ -6406,7 +6406,7 @@ static void ex_quit(exarg_T *eap) return; } - // If there are more files or windows we won't exit. + // If there is only one relevant window we will exit. if (check_more(false, eap->forceit) == OK && only_one_window()) { exiting = true; } @@ -6749,7 +6749,7 @@ static void ex_stop(exarg_T *eap) apply_autocmds(EVENT_VIMRESUME, NULL, NULL, false, NULL); } -// ":exit", ":xit" and ":wq": Write file and quite the current window. +// ":exit", ":xit" and ":wq": Write file and quit the current window. static void ex_exit(exarg_T *eap) { if (cmdwin_type != 0) { @@ -6762,17 +6762,15 @@ static void ex_exit(exarg_T *eap) return; } - if (before_quit_autocmds(curwin, false, eap->forceit)) { - return; - } - - // if more files or windows we won't exit + // we plan to exit if there is only one relevant window if (check_more(false, eap->forceit) == OK && only_one_window()) { exiting = true; } - if (((eap->cmdidx == CMD_wq - || curbufIsChanged()) - && do_write(eap) == FAIL) + // Write the buffer for ":wq" or when it was changed. + // Trigger QuitPre and ExitPre. + // Check if we can exit now, after autocommands have changed things. + if (((eap->cmdidx == CMD_wq || curbufIsChanged()) && do_write(eap) == FAIL) + || before_quit_autocmds(curwin, false, eap->forceit) || check_more(true, eap->forceit) == FAIL || (only_one_window() && check_changed_any(eap->forceit, false))) { not_exiting(); diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index bc0770da31..5c9c5103a7 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -39,6 +39,75 @@ assert(vim) vim.inspect = package.loaded['vim.inspect'] assert(vim.inspect) +local pathtrails = {} +vim._so_trails = {} +for s in (package.cpath..';'):gmatch('[^;]*;') do + s = s:sub(1, -2) -- Strip trailing semicolon + -- Find out path patterns. pathtrail should contain something like + -- /?.so, \?.dll. This allows not to bother determining what correct + -- suffixes are. + local pathtrail = s:match('[/\\][^/\\]*%?.*$') + if pathtrail and not pathtrails[pathtrail] then + pathtrails[pathtrail] = true + table.insert(vim._so_trails, pathtrail) + end +end + +function vim._load_package(name) + local basename = name:gsub('%.', '/') + local paths = {"lua/"..basename..".lua", "lua/"..basename.."/init.lua"} + for _,path in ipairs(paths) do + local found = vim.api.nvim_get_runtime_file(path, false) + if #found > 0 then + local f, err = loadfile(found[1]) + return f or error(err) + end + end + + for _,trail in ipairs(vim._so_trails) do + local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash + local found = vim.api.nvim_get_runtime_file(path, false) + if #found > 0 then + -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is + -- a) strip prefix up to and including the first dash, if any + -- b) replace all dots by underscores + -- c) prepend "luaopen_" + -- So "foo-bar.baz" should result in "luaopen_bar_baz" + local dash = name:find("-", 1, true) + local modname = dash and name:sub(dash + 1) or name + local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_")) + return f or error(err) + end + end + return nil +end + +table.insert(package.loaders, 1, vim._load_package) + +-- These are for loading runtime modules lazily since they aren't available in +-- the nvim binary as specified in executor.c +setmetatable(vim, { + __index = function(t, key) + if key == 'treesitter' then + t.treesitter = require('vim.treesitter') + return t.treesitter + elseif key == 'F' then + t.F = require('vim.F') + return t.F + elseif require('vim.uri')[key] ~= nil then + -- Expose all `vim.uri` functions on the `vim` module. + t[key] = require('vim.uri')[key] + return t[key] + elseif key == 'lsp' then + t.lsp = require('vim.lsp') + return t.lsp + elseif key == 'highlight' then + t.highlight = require('vim.highlight') + return t.highlight + end + end +}) + vim.log = { levels = { TRACE = 0; @@ -105,51 +174,6 @@ function vim._os_proc_children(ppid) return children end -local pathtrails = {} -vim._so_trails = {} -for s in (package.cpath..';'):gmatch('[^;]*;') do - s = s:sub(1, -2) -- Strip trailing semicolon - -- Find out path patterns. pathtrail should contain something like - -- /?.so, \?.dll. This allows not to bother determining what correct - -- suffixes are. - local pathtrail = s:match('[/\\][^/\\]*%?.*$') - if pathtrail and not pathtrails[pathtrail] then - pathtrails[pathtrail] = true - table.insert(vim._so_trails, pathtrail) - end -end - -function vim._load_package(name) - local basename = name:gsub('%.', '/') - local paths = {"lua/"..basename..".lua", "lua/"..basename.."/init.lua"} - for _,path in ipairs(paths) do - local found = vim.api.nvim_get_runtime_file(path, false) - if #found > 0 then - local f, err = loadfile(found[1]) - return f or error(err) - end - end - - for _,trail in ipairs(vim._so_trails) do - local path = "lua"..trail:gsub('?', basename) -- so_trails contains a leading slash - local found = vim.api.nvim_get_runtime_file(path, false) - if #found > 0 then - -- Making function name in Lua 5.1 (see src/loadlib.c:mkfuncname) is - -- a) strip prefix up to and including the first dash, if any - -- b) replace all dots by underscores - -- c) prepend "luaopen_" - -- So "foo-bar.baz" should result in "luaopen_bar_baz" - local dash = name:find("-", 1, true) - local modname = dash and name:sub(dash + 1) or name - local f, err = package.loadlib(found[1], "luaopen_"..modname:gsub("%.", "_")) - return f or error(err) - end - end - return nil -end - -table.insert(package.loaders, 1, vim._load_package) - -- TODO(ZyX-I): Create compatibility layer. --- Return a human-readable representation of the given object. @@ -282,32 +306,6 @@ vim.funcref = function(viml_func_name) return vim.fn[viml_func_name] end --- These are for loading runtime modules lazily since they aren't available in --- the nvim binary as specified in executor.c -local function __index(t, key) - if key == 'treesitter' then - t.treesitter = require('vim.treesitter') - return t.treesitter - elseif require('vim.uri')[key] ~= nil then - -- Expose all `vim.uri` functions on the `vim` module. - t[key] = require('vim.uri')[key] - return t[key] - elseif key == 'lsp' then - t.lsp = require('vim.lsp') - return t.lsp - elseif key == 'highlight' then - t.highlight = require('vim.highlight') - return t.highlight - elseif key == 'F' then - t.F = require('vim.F') - return t.F - end -end - -setmetatable(vim, { - __index = __index -}) - -- An easier alias for commands. vim.cmd = function(command) return vim.api.nvim_exec(command, false) @@ -315,32 +313,8 @@ end -- These are the vim.env/v/g/o/bo/wo variable magic accessors. do - local a = vim.api local validate = vim.validate - local function make_meta_accessor(get, set, del) - validate { - get = {get, 'f'}; - set = {set, 'f'}; - del = {del, 'f', true}; - } - local mt = {} - if del then - function mt:__newindex(k, v) - if v == nil then - return del(k) - end - return set(k, v) - end - else - function mt:__newindex(k, v) - return set(k, v) - end - end - function mt:__index(k) - return get(k) - end - return setmetatable({}, mt) - end + local function make_dict_accessor(scope) validate { scope = {scope, 's'}; @@ -354,88 +328,12 @@ do end return setmetatable({}, mt) end + vim.g = make_dict_accessor('g') vim.v = make_dict_accessor('v') vim.b = make_dict_accessor('b') vim.w = make_dict_accessor('w') vim.t = make_dict_accessor('t') - vim.o = make_meta_accessor(a.nvim_get_option, a.nvim_set_option) - - local function getenv(k) - local v = vim.fn.getenv(k) - if v == vim.NIL then - return nil - end - return v - end - vim.env = make_meta_accessor(getenv, vim.fn.setenv) - -- TODO(ashkan) if/when these are available from an API, generate them - -- instead of hardcoding. - local window_options = { - arab = true; arabic = true; breakindent = true; breakindentopt = true; - bri = true; briopt = true; cc = true; cocu = true; - cole = true; colorcolumn = true; concealcursor = true; conceallevel = true; - crb = true; cuc = true; cul = true; cursorbind = true; - cursorcolumn = true; cursorline = true; diff = true; fcs = true; - fdc = true; fde = true; fdi = true; fdl = true; - fdm = true; fdn = true; fdt = true; fen = true; - fillchars = true; fml = true; fmr = true; foldcolumn = true; - foldenable = true; foldexpr = true; foldignore = true; foldlevel = true; - foldmarker = true; foldmethod = true; foldminlines = true; foldnestmax = true; - foldtext = true; lbr = true; lcs = true; linebreak = true; - list = true; listchars = true; nu = true; number = true; - numberwidth = true; nuw = true; previewwindow = true; pvw = true; - relativenumber = true; rightleft = true; rightleftcmd = true; rl = true; - rlc = true; rnu = true; scb = true; scl = true; - scr = true; scroll = true; scrollbind = true; signcolumn = true; - spell = true; statusline = true; stl = true; wfh = true; - wfw = true; winbl = true; winblend = true; winfixheight = true; - winfixwidth = true; winhighlight = true; winhl = true; wrap = true; - } - - --@private - local function new_buf_opt_accessor(bufnr) - --@private - local function get(k) - if window_options[k] then - return a.nvim_err_writeln(k.." is a window option, not a buffer option") - end - if bufnr == nil and type(k) == "number" then - return new_buf_opt_accessor(k) - end - return a.nvim_buf_get_option(bufnr or 0, k) - end - - --@private - local function set(k, v) - if window_options[k] then - return a.nvim_err_writeln(k.." is a window option, not a buffer option") - end - return a.nvim_buf_set_option(bufnr or 0, k, v) - end - - return make_meta_accessor(get, set) - end - vim.bo = new_buf_opt_accessor(nil) - - --@private - local function new_win_opt_accessor(winnr) - - --@private - local function get(k) - if winnr == nil and type(k) == "number" then - return new_win_opt_accessor(k) - end - return a.nvim_win_get_option(winnr or 0, k) - end - - --@private - local function set(k, v) - return a.nvim_win_set_option(winnr or 0, k, v) - end - return make_meta_accessor(get, set) - end - vim.wo = new_win_opt_accessor(nil) end --- Get a table of lines with start, end columns for a region marked by two points @@ -738,4 +636,6 @@ vim._expand_pat_get_parts = function(lua_string) return parts, search_index end +pcall(require, 'vim._meta') + return module diff --git a/src/nvim/option.c b/src/nvim/option.c index 1454af1a73..67fb78bcc8 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -4883,7 +4883,7 @@ int get_option_value_strict(char *name, if (p->flags & P_STRING) { *stringval = xstrdup(*(char **)(varp)); } else if (p->flags & P_NUM) { - *numval = *(long *) varp; + *numval = *(long *)varp; } else { *numval = *(int *)varp; } @@ -7705,7 +7705,7 @@ Dictionary get_vimoption(String name, Error *err) Dictionary get_all_vimoptions(void) { Dictionary retval = ARRAY_DICT_INIT; - for (size_t i = 0; i < PARAM_COUNT; i++) { + for (size_t i = 0; options[i].fullname != NULL; i++) { Dictionary opt_dict = vimoption2dict(&options[i]); PUT(retval, options[i].fullname, DICTIONARY_OBJ(opt_dict)); } diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index e0cc25421a..accf9b0bb5 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -692,6 +692,7 @@ static char_u *regparse; ///< Input-scan pointer. static int prevchr_len; ///< byte length of previous char static int num_complex_braces; ///< Complex \{...} count static int regnpar; ///< () count. +static bool wants_nfa; ///< regex should use NFA engine static int regnzpar; ///< \z() count. static int re_has_z; ///< \z item detected static char_u *regcode; ///< Code-emit pointer, or JUST_CALC_SIZE @@ -3974,17 +3975,25 @@ static bool regmatch( pos = getmark_buf(rex.reg_buf, mark, false); if (pos == NULL // mark doesn't exist - || pos->lnum <= 0 // mark isn't set in reg_buf - || (pos->lnum == rex.lnum + rex.reg_firstlnum - ? (pos->col == (colnr_T)(rex.input - rex.line) - ? (cmp == '<' || cmp == '>') - : (pos->col < (colnr_T)(rex.input - rex.line) - ? cmp != '>' - : cmp != '<')) - : (pos->lnum < rex.lnum + rex.reg_firstlnum - ? cmp != '>' - : cmp != '<'))) { + || pos->lnum <= 0) { // mark isn't set in reg_buf status = RA_NOMATCH; + } else { + const colnr_T pos_col = pos->lnum == rex.lnum + rex.reg_firstlnum + && pos->col == MAXCOL + ? (colnr_T)STRLEN(reg_getline(pos->lnum - rex.reg_firstlnum)) + : pos->col; + + if (pos->lnum == rex.lnum + rex.reg_firstlnum + ? (pos_col == (colnr_T)(rex.input - rex.line) + ? (cmp == '<' || cmp == '>') + : (pos_col < (colnr_T)(rex.input - rex.line) + ? cmp != '>' + : cmp != '<')) + : (pos->lnum < rex.lnum + rex.reg_firstlnum + ? cmp != '>' + : cmp != '<')) { + status = RA_NOMATCH; + } } } break; @@ -7240,7 +7249,7 @@ regprog_T *vim_regcomp(char_u *expr_arg, int re_flags) // Check for error compiling regexp with initial engine. if (prog == NULL) { #ifdef BT_REGEXP_DEBUG_LOG - // Debugging log for NFA. + // Debugging log for BT engine. if (regexp_engine != BACKTRACKING_ENGINE) { FILE *f = fopen(BT_REGEXP_DEBUG_LOG_NAME, "a"); if (f) { @@ -7257,6 +7266,7 @@ regprog_T *vim_regcomp(char_u *expr_arg, int re_flags) // But don't try if an error message was given. if (regexp_engine == AUTOMATIC_ENGINE && !called_emsg) { regexp_engine = BACKTRACKING_ENGINE; + report_re_switch(expr); prog = bt_regengine.regcomp(expr, re_flags); } } diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 923db6422e..5047e0db03 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -328,6 +328,11 @@ static int *post_start; ///< holds the postfix form of r.e. static int *post_end; static int *post_ptr; +// Set when the pattern should use the NFA engine. +// E.g. [[:upper:]] only allows 8bit characters for BT engine, +// while NFA engine handles multibyte characters correctly. +static bool wants_nfa; + static int nstate; ///< Number of states in the NFA. Also used when executing. static int istate; ///< Index in the state vector, used in alloc_state() @@ -377,6 +382,7 @@ nfa_regcomp_start ( post_start = (int *)xmalloc(postfix_size); post_ptr = post_start; post_end = post_start + nstate_max; + wants_nfa = false; rex.nfa_has_zend = false; rex.nfa_has_backref = false; @@ -1618,6 +1624,7 @@ collection: EMIT(NFA_CLASS_GRAPH); break; case CLASS_LOWER: + wants_nfa = true; EMIT(NFA_CLASS_LOWER); break; case CLASS_PRINT: @@ -1630,6 +1637,7 @@ collection: EMIT(NFA_CLASS_SPACE); break; case CLASS_UPPER: + wants_nfa = true; EMIT(NFA_CLASS_UPPER); break; case CLASS_XDIGIT: @@ -1998,10 +2006,17 @@ static int nfa_regpiece(void) return OK; } - // The engine is very inefficient (uses too many states) when the maximum - // is much larger than the minimum and when the maximum is large. Bail out - // if we can use the other engine. - if ((nfa_re_flags & RE_AUTO) && (maxval > 500 || maxval > minval + 200)) { + // The engine is very inefficient (uses too many states) when the + // maximum is much larger than the minimum and when the maximum is + // large. However, when maxval is MAX_LIMIT, it is okay, as this + // will emit NFA_STAR. + // Bail out if we can use the other engine, but only, when the + // pattern does not need the NFA engine like (e.g. [[:upper:]]\{2,\} + // does not work with with characters > 8 bit with the BT engine) + if ((nfa_re_flags & RE_AUTO) + && (maxval > 500 || maxval > minval + 200) + && (maxval != MAX_LIMIT && minval < 200) + && !wants_nfa) { return FAIL; } @@ -6055,21 +6070,27 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, { pos_T *pos = getmark_buf(rex.reg_buf, t->state->val, false); - // Compare the mark position to the match position. - result = (pos != NULL // mark doesn't exist - && pos->lnum > 0 // mark isn't set in reg_buf - && (pos->lnum == rex.lnum + rex.reg_firstlnum - ? (pos->col == (colnr_T)(rex.input - rex.line) - ? t->state->c == NFA_MARK - : (pos->col < (colnr_T)(rex.input - rex.line) - ? t->state->c == NFA_MARK_GT - : t->state->c == NFA_MARK_LT)) - : (pos->lnum < rex.lnum + rex.reg_firstlnum - ? t->state->c == NFA_MARK_GT - : t->state->c == NFA_MARK_LT))); - if (result) { - add_here = true; - add_state = t->state->out; + // Compare the mark position to the match position, if the mark + // exists and mark is set in reg_buf. + if (pos != NULL && pos->lnum > 0) { + const colnr_T pos_col = pos->lnum == rex.lnum + rex.reg_firstlnum + && pos->col == MAXCOL + ? (colnr_T)STRLEN(reg_getline(pos->lnum - rex.reg_firstlnum)) + : pos->col; + + result = pos->lnum == rex.lnum + rex.reg_firstlnum + ? (pos_col == (colnr_T)(rex.input - rex.line) + ? t->state->c == NFA_MARK + : (pos_col < (colnr_T)(rex.input - rex.line) + ? t->state->c == NFA_MARK_GT + : t->state->c == NFA_MARK_LT)) + : (pos->lnum < rex.lnum + rex.reg_firstlnum + ? t->state->c == NFA_MARK_GT + : t->state->c == NFA_MARK_LT); + if (result) { + add_here = true; + add_state = t->state->out; + } } break; } diff --git a/src/nvim/testdir/test_regexp_utf8.vim b/src/nvim/testdir/test_regexp_utf8.vim index 513780938e..d8d5797dcf 100644 --- a/src/nvim/testdir/test_regexp_utf8.vim +++ b/src/nvim/testdir/test_regexp_utf8.vim @@ -542,6 +542,52 @@ func Test_match_start_of_line_combining() bwipe! endfunc +" Check that [[:upper:]] matches for automatic engine +func Test_match_char_class_upper() + new + let _engine=®expengine + + " Test 1: [[:upper:]]\{2,\} + set regexpengine=0 + call setline(1, ['05. ПЕСНЯ О ГЕРОЯХ муз. А. Давиденко, М. Коваля и Б. Шехтера ...', '05. PJESNJA O GJEROJAKH mus. A. Davidjenko, M. Kovalja i B. Shjekhtjera ...']) + call cursor(1,1) + let search_cmd='norm /\<[[:upper:]]\{2,\}\>' .. "\<CR>" + exe search_cmd + call assert_equal(4, searchcount().total, 'TEST 1') + set regexpengine=1 + exe search_cmd + call assert_equal(2, searchcount().total, 'TEST 1') + set regexpengine=2 + exe search_cmd + call assert_equal(4, searchcount().total, 'TEST 1') + + " Test 2: [[:upper:]].\+ + let search_cmd='norm /\<[[:upper:]].\+\>' .. "\<CR>" + set regexpengine=0 + exe search_cmd + call assert_equal(2, searchcount().total, 'TEST 2') + set regexpengine=1 + exe search_cmd + call assert_equal(1, searchcount().total, 'TEST 2') + set regexpengine=2 + exe search_cmd + call assert_equal(2, searchcount().total, 'TEST 2') + + " Test 3: [[:lower:]]\+ + let search_cmd='norm /\<[[:lower:]]\+\>' .. "\<CR>" + set regexpengine=0 + exe search_cmd + call assert_equal(4, searchcount().total, 'TEST 3 lower') + set regexpengine=1 + exe search_cmd + call assert_equal(2, searchcount().total, 'TEST 3 lower') + set regexpengine=2 + exe search_cmd + call assert_equal(4, searchcount().total, 'TEST 3 lower') + " clean up + let ®expengine=_engine + bwipe! +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index 75d42b986b..b391663e0f 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -1177,13 +1177,28 @@ func Test_look_behind() bwipe! endfunc +func Test_search_visual_area_linewise() + new + call setline(1, ['aa', 'bb', 'cc']) + exe "normal 2GV\<Esc>" + for engine in [1, 2] + exe 'set regexpengine=' .. engine + exe "normal gg/\\%'<\<CR>>" + call assert_equal([0, 2, 1, 0, 1], getcurpos(), 'engine ' .. engine) + exe "normal gg/\\%'>\<CR>" + call assert_equal([0, 2, 2, 0, 2], getcurpos(), 'engine ' .. engine) + endfor + + bwipe! + set regexpengine& +endfunc + func Test_search_sentence() new " this used to cause a crash - call assert_fails("/\\%')", 'E486') - call assert_fails("/", 'E486') /\%'( / + bwipe endfunc " Test that there is no crash when there is a last search pattern but no last diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim index c7710ff198..6922e2185d 100644 --- a/src/nvim/testdir/test_writefile.vim +++ b/src/nvim/testdir/test_writefile.vim @@ -361,4 +361,25 @@ func Test_write_file_encoding() %bw! endfunc +" Check that buffer is written before triggering QuitPre +func Test_wq_quitpre_autocommand() + edit Xsomefile + call setline(1, 'hello') + split + let g:seq = [] + augroup Testing + au QuitPre * call add(g:seq, 'QuitPre - ' .. (&modified ? 'modified' : 'not modified')) + au BufWritePost * call add(g:seq, 'written') + augroup END + wq + call assert_equal(['written', 'QuitPre - not modified'], g:seq) + + augroup Testing + au! + augroup END + bwipe! + unlet g:seq + call delete('Xsomefile') +endfunc + " vim: shiftwidth=2 sts=2 expandtab |