diff options
-rw-r--r-- | runtime/doc/lua.txt | 23 | ||||
-rw-r--r-- | runtime/lua/vim/iter.lua | 92 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 8 | ||||
-rw-r--r-- | src/nvim/fileio.c | 2 | ||||
-rw-r--r-- | src/nvim/memline.c | 4 | ||||
-rw-r--r-- | src/nvim/option.c | 3 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 38 | ||||
-rw-r--r-- | test/old/testdir/test_user_func.vim | 40 |
8 files changed, 133 insertions, 77 deletions
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 60067f1bc3..8e68e9a792 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -3037,6 +3037,19 @@ Iter:find({self}, {f}) *Iter:find()* Iter:fold({self}, {init}, {f}) *Iter:fold()* Fold an iterator or table into a single value. + Examples: > + + -- Create a new table with only even values + local t = { a = 1, b = 2, c = 3, d = 4 } + local it = vim.iter(t) + it:filter(function(k, v) return v % 2 == 0 end) + it:fold({}, function(t, k, v) + t[k] = v + return t + end) + -- { b = 2, d = 4 } +< + Parameters: ~ • {init} any Initial value of the accumulator. • {f} function(acc:any, ...):A Accumulation function. @@ -3297,9 +3310,7 @@ Iter:totable({self}) *Iter:totable()* The resulting table depends on the initial source in the iterator pipeline. List-like tables and function iterators will be collected into a list-like table. If multiple values are returned from the final stage in - the iterator pipeline, each value will be included in a table. If a - map-like table was used as the initial source, then a map-like table is - returned. + the iterator pipeline, each value will be included in a table. Examples: >lua @@ -3310,9 +3321,13 @@ Iter:totable({self}) *Iter:totable()* -- { { 1, 2 }, { 2, 4 }, { 3, 6 } } vim.iter({ a = 1, b = 2, c = 3 }):filter(function(k, v) return v % 2 ~= 0 end):totable() - -- { a = 1, c = 3 } + -- { { 'a', 1 }, { 'c', 3 } } < + The generated table is a list-like table with consecutive, numeric + indices. To create a map-like table with arbitrary keys, use + |Iter:fold()|. + Return: ~ (table) diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua index b73c03ba9a..c5d5ef835b 100644 --- a/runtime/lua/vim/iter.lua +++ b/runtime/lua/vim/iter.lua @@ -18,26 +18,19 @@ ListIter.__call = function(self) return self:next() end ---- Special case implementations for iterators on non-list tables. ----@class TableIter : Iter -local TableIter = {} -TableIter.__index = setmetatable(TableIter, Iter) -TableIter.__call = function(self) - return self:next() -end - ---@private local function unpack(t) - if type(t) == 'table' then - return _G.unpack(t) + if type(t) == 'table' and t.__n ~= nil then + return _G.unpack(t, 1, t.__n) end return t end ---@private local function pack(...) - if select('#', ...) > 1 then - return { ... } + local n = select('#', ...) + if n > 1 then + return { __n = n, ... } end return ... end @@ -184,10 +177,10 @@ end --- Collect the iterator into a table. --- ---- The resulting table depends on the initial source in the iterator pipeline. List-like tables ---- and function iterators will be collected into a list-like table. If multiple values are returned ---- from the final stage in the iterator pipeline, each value will be included in a table. If a ---- map-like table was used as the initial source, then a map-like table is returned. +--- The resulting table depends on the initial source in the iterator pipeline. +--- List-like tables and function iterators will be collected into a list-like +--- table. If multiple values are returned from the final stage in the iterator +--- pipeline, each value will be included in a table. --- --- Examples: --- <pre>lua @@ -198,9 +191,13 @@ end --- -- { { 1, 2 }, { 2, 4 }, { 3, 6 } } --- --- vim.iter({ a = 1, b = 2, c = 3 }):filter(function(k, v) return v % 2 ~= 0 end):totable() ---- -- { a = 1, c = 3 } +--- -- { { 'a', 1 }, { 'c', 3 } } --- </pre> --- +--- The generated table is a list-like table with consecutive, numeric indices. +--- To create a map-like table with arbitrary keys, use |Iter:fold()|. +--- +--- ---@return table function Iter.totable(self) local t = {} @@ -210,6 +207,12 @@ function Iter.totable(self) if args == nil then break end + + if type(args) == 'table' then + -- Removed packed table tag if it exists + args.__n = nil + end + t[#t + 1] = args end return t @@ -218,23 +221,35 @@ end ---@private function ListIter.totable(self) if self._head == 1 and self._tail == #self._table + 1 and self.next == ListIter.next then + -- Remove any packed table tags + for i = 1, #self._table do + local v = self._table[i] + if type(v) == 'table' then + v.__n = nil + self._table[i] = v + end + end return self._table end return Iter.totable(self) end ----@private -function TableIter.totable(self) - local t = {} - for k, v in self do - t[k] = v - end - return t -end - --- Fold an iterator or table into a single value. --- +--- Examples: +--- <pre> +--- -- Create a new table with only even values +--- local t = { a = 1, b = 2, c = 3, d = 4 } +--- local it = vim.iter(t) +--- it:filter(function(k, v) return v % 2 == 0 end) +--- it:fold({}, function(t, k, v) +--- t[k] = v +--- return t +--- end) +--- -- { b = 2, d = 4 } +--- </pre> +--- ---@generic A --- ---@param init A Initial value of the accumulator. @@ -747,7 +762,7 @@ function ListIter.enumerate(self) local inc = self._head < self._tail and 1 or -1 for i = self._head, self._tail - inc, inc do local v = self._table[i] - self._table[i] = { i, v } + self._table[i] = pack(i, v) end return self end @@ -768,7 +783,7 @@ function Iter.new(src, ...) count = count + 1 local v = src[count] if v == nil then - return TableIter.new(src) + return Iter.new(pairs(src)) end t[count] = v end @@ -812,25 +827,4 @@ function ListIter.new(t) return it end ---- Create a new TableIter ---- ----@param t table Table to iterate over. For list-like tables, use ListIter.new instead. ----@return Iter ----@private -function TableIter.new(t) - local it = {} - - local index = nil - function it.next() - local k, v = next(t, index) - if k ~= nil then - index = k - return k, v - end - end - - setmetatable(it, TableIter) - return it -end - return Iter diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 4cb2f9bd2b..51e109fdfb 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -3270,15 +3270,15 @@ static void handle_defer_one(funccall_T *funccal) /// Called when exiting: call all defer functions. void invoke_all_defer(void) { + for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->fc_caller) { + handle_defer_one(fc); + } + for (funccal_entry_T *fce = funccal_stack; fce != NULL; fce = fce->next) { for (funccall_T *fc = fce->top_funccal; fc != NULL; fc = fc->fc_caller) { handle_defer_one(fc); } } - - for (funccall_T *fc = current_funccal; fc != NULL; fc = fc->fc_caller) { - handle_defer_one(fc); - } } /// ":1,25call func(arg1, arg2)" function call. diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 52fafa6a21..bb17382f98 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -3484,7 +3484,7 @@ char *vim_gettempdir(void) static int notfound = 0; bool exists = false; if (vim_tempdir == NULL || !(exists = os_isdir(vim_tempdir))) { - if (vim_tempdir != NULL && !exists) { + if (vim_tempdir != NULL) { notfound++; if (notfound == 1) { ELOG("tempdir disappeared (antivirus or broken cleanup job?): %s", vim_tempdir); diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 2528b5c0d3..cb58cbc86f 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1366,9 +1366,7 @@ int recover_names(char *fname, bool do_list, list_T *ret_list, int nr, char **fn } else if (ret_list != NULL) { for (int i = 0; i < num_files; i++) { char *name = concat_fnames(dir_name, files[i], true); - if (name != NULL) { - tv_list_append_allocated_string(ret_list, name); - } + tv_list_append_allocated_string(ret_list, name); } } else { file_count += num_files; diff --git a/src/nvim/option.c b/src/nvim/option.c index 3b674ce726..aff824e9e2 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3257,8 +3257,7 @@ static void showoptions(bool all, int opt_flags) } else { varp = get_varp(p); } - if (varp != NULL - && (all == 1 || (all == 0 && !optval_default(p, varp)))) { + if (varp != NULL && (all || !optval_default(p, varp))) { int len; if (opt_flags & OPT_ONECOLUMN) { len = Columns; diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index e5caf6f6f7..e37d477376 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3374,13 +3374,45 @@ describe('lua stdlib', function() end) it('handles map-like tables', function() - local t = { a = 1, b = 2, c = 3 } - local it = vim.iter(t):map(function(k, v) + local it = vim.iter({ a = 1, b = 2, c = 3 }):map(function(k, v) if v % 2 ~= 0 then return k:upper(), v * 2 end end) - eq({ A = 2, C = 6 }, it:totable()) + + local t = it:fold({}, function(t, k, v) + t[k] = v + return t + end) + eq({ A = 2, C = 6 }, t) + end) + + it('handles table values mid-pipeline', function() + local map = { + item = { + file = 'test', + }, + item_2 = { + file = 'test', + }, + item_3 = { + file = 'test', + }, + } + + local output = vim.iter(map):map(function(key, value) + return { [key] = value.file } + end):totable() + + table.sort(output, function(a, b) + return next(a) < next(b) + end) + + eq({ + { item = 'test' }, + { item_2 = 'test' }, + { item_3 = 'test' }, + }, output) end) end) end) diff --git a/test/old/testdir/test_user_func.vim b/test/old/testdir/test_user_func.vim index 5f6229258d..dc36ab98cb 100644 --- a/test/old/testdir/test_user_func.vim +++ b/test/old/testdir/test_user_func.vim @@ -663,20 +663,37 @@ endfunc func Test_defer_quitall_autocmd() let lines =<< trim END - autocmd User DeferAutocmdThree qa! + func DeferLevelFive() + defer writefile(['5'], 'XQuitallAutocmd', 'a') + qa! + endfunc + autocmd User DeferAutocmdFive call DeferLevelFive() + + " def DeferLevelFour() + func DeferLevelFour() + defer writefile(['4'], 'XQuitallAutocmd', 'a') + doautocmd User DeferAutocmdFive + " enddef + endfunc + + func DeferLevelThree() + defer writefile(['3'], 'XQuitallAutocmd', 'a') + call DeferLevelFour() + endfunc + + autocmd User DeferAutocmdThree ++nested call DeferLevelThree() + + " def DeferLevelTwo() func DeferLevelTwo() - call writefile(['text'], 'XQuitallAutocmdTwo', 'D') + defer writefile(['2'], 'XQuitallAutocmd', 'a') doautocmd User DeferAutocmdThree + " enddef endfunc - autocmd User DeferAutocmdTwo ++nested call DeferLevelTwo() - - " def DeferLevelOne() func DeferLevelOne() - call writefile(['text'], 'XQuitallAutocmdOne', 'D') - doautocmd User DeferAutocmdTwo - " enddef + defer writefile(['1'], 'XQuitallAutocmd', 'a') + call DeferLevelTwo() endfunc autocmd User DeferAutocmdOne ++nested call DeferLevelOne() @@ -684,10 +701,11 @@ func Test_defer_quitall_autocmd() doautocmd User DeferAutocmdOne END call writefile(lines, 'XdeferQuitallAutocmd', 'D') - let res = system(GetVimCommand() .. ' -X -S XdeferQuitallAutocmd') + call system(GetVimCommand() .. ' -X -S XdeferQuitallAutocmd') call assert_equal(0, v:shell_error) - call assert_false(filereadable('XQuitallAutocmdOne')) - call assert_false(filereadable('XQuitallAutocmdTwo')) + call assert_equal(['5', '4', '3', '2', '1'], readfile('XQuitallAutocmd')) + + call delete('XQuitallAutocmd') endfunc func Test_defer_quitall_in_expr_func() |