diff options
-rw-r--r-- | .github/workflows/backport.yml | 2 | ||||
-rw-r--r-- | runtime/doc/api.txt | 18 | ||||
-rw-r--r-- | runtime/doc/deprecated.txt | 114 | ||||
-rw-r--r-- | runtime/doc/lua.txt | 9 | ||||
-rw-r--r-- | runtime/doc/news.txt | 7 | ||||
-rw-r--r-- | runtime/lua/provider/ruby/health.lua | 3 | ||||
-rw-r--r-- | runtime/lua/vim/iter.lua | 121 | ||||
-rw-r--r-- | scripts/gen_help_html.lua | 4 | ||||
-rw-r--r-- | src/nvim/api/deprecated.c | 20 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 30 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 4 | ||||
-rw-r--r-- | src/nvim/generators/gen_api_dispatch.lua | 6 | ||||
-rw-r--r-- | src/nvim/generators/nvim_version.lua.in | 2 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel.c | 74 | ||||
-rw-r--r-- | src/nvim/msgpack_rpc/channel_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/os/env.c | 14 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 14 | ||||
-rw-r--r-- | src/nvim/path.c | 43 | ||||
-rw-r--r-- | test/functional/api/server_notifications_spec.lua | 23 | ||||
-rw-r--r-- | test/functional/lua/iter_spec.lua | 31 | ||||
-rw-r--r-- | test/functional/vimscript/api_functions_spec.lua | 4 | ||||
-rw-r--r-- | test/unit/path_spec.lua | 60 |
22 files changed, 270 insertions, 334 deletions
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 4b53793aa7..9fbe837106 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -32,5 +32,5 @@ jobs: issue_number: ${{steps.backport.outputs.created_pull_numbers}}, owner: context.repo.owner, repo: context.repo.repo, - labels: ['backport'] + labels: ['target:release'] }) diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 13884e865d..2aa147770d 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -1461,24 +1461,6 @@ nvim_strwidth({text}) *nvim_strwidth()* Return: ~ Number of cells -nvim_subscribe({event}) *nvim_subscribe()* - Subscribes to event broadcasts. - - Attributes: ~ - |RPC| only - - Parameters: ~ - • {event} Event type string - -nvim_unsubscribe({event}) *nvim_unsubscribe()* - Unsubscribes to event broadcasts. - - Attributes: ~ - |RPC| only - - Parameters: ~ - • {event} Event type string - nvim__complete_set({index}, {opts}) *nvim__complete_set()* EXPERIMENTAL: this API may change in the future. diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 3fc2d872f6..646ba72bd8 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -12,76 +12,82 @@ They should not be used in new scripts, and old scripts should be updated. ============================================================================== Deprecated features -DEPRECATED IN 0.11 *deprecated-0.11* +------------------------------------------------------------------------------ +DEPRECATED IN 0.11 *deprecated-0.11* + +API +- nvim_subscribe() Plugins must maintain their own "multicast" channels list. +- nvim_unsubscribe() Plugins must maintain their own "multicast" channels list. -• N/A -DEPRECATED IN 0.10 *deprecated-0.10* +------------------------------------------------------------------------------ +DEPRECATED IN 0.10 *deprecated-0.10* +API +• *nvim_buf_get_option()* Use |nvim_get_option_value()| instead. +• *nvim_buf_set_option()* Use |nvim_set_option_value()| instead. +• *nvim_call_atomic()* Use |nvim_exec_lua()| instead. +• *nvim_get_option()* Use |nvim_get_option_value()| instead. +• *nvim_set_option()* Use |nvim_set_option_value()| instead. +• *nvim_win_get_option()* Use |nvim_get_option_value()| instead. +• *nvim_win_set_option()* Use |nvim_set_option_value()| instead. + +CHECKHEALTH +• *health#report_error* *vim.health.report_error()* Use |vim.health.error()| instead. +• *health#report_info* *vim.health.report_info()* Use |vim.health.info()| instead. +• *health#report_ok* *vim.health.report_ok()* Use |vim.health.ok()| instead. +• *health#report_start* *vim.health.report_start()* Use |vim.health.start()| instead. +• *health#report_warn* *vim.health.report_warn()* Use |vim.health.warn()| instead. + +DIAGNOSTICS • Configuring |diagnostic-signs| using |:sign-define| or |sign_define()|. Use the "signs" key of |vim.diagnostic.config()| instead. - -• Checkhealth functions: - - *health#report_error* *vim.health.report_error()* Use |vim.health.error()| instead. - - *health#report_info* *vim.health.report_info()* Use |vim.health.info()| instead. - - *health#report_ok* *vim.health.report_ok()* Use |vim.health.ok()| instead. - - *health#report_start* *vim.health.report_start()* Use |vim.health.start()| instead. - - *health#report_warn* *vim.health.report_warn()* Use |vim.health.warn()| instead. - -• |API| functions: - - *nvim_buf_get_option()* Use |nvim_get_option_value()| instead. - - *nvim_buf_set_option()* Use |nvim_set_option_value()| instead. - - *nvim_call_atomic()* Use |nvim_exec_lua()| instead. - - *nvim_get_option()* Use |nvim_get_option_value()| instead. - - *nvim_set_option()* Use |nvim_set_option_value()| instead. - - *nvim_win_get_option()* Use |nvim_get_option_value()| instead. - - *nvim_win_set_option()* Use |nvim_set_option_value()| instead. - • vim.diagnostic functions: - - *vim.diagnostic.disable()* Use |vim.diagnostic.enable()| - - *vim.diagnostic.is_disabled()* Use |vim.diagnostic.is_enabled()| - - Legacy signature: `vim.diagnostic.enable(buf:number, namespace:number)` - -• vim.lsp functions: - - *vim.lsp.util.get_progress_messages()* Use |vim.lsp.status()| instead. - - *vim.lsp.get_active_clients()* Use |vim.lsp.get_clients()| instead. - - *vim.lsp.for_each_buffer_client()* Use |vim.lsp.get_clients()| instead. - - *vim.lsp.util.trim_empty_lines()* Use |vim.split()| with `trimempty` instead. - - *vim.lsp.util.try_trim_markdown_code_blocks()* - - *vim.lsp.util.set_lines()* - - *vim.lsp.util.extract_completion_items()* - - *vim.lsp.util.parse_snippet()* - - *vim.lsp.util.text_document_completion_list_to_complete_items()* - - *vim.lsp.util.lookup_section()* Use |vim.tbl_get()| instead: > + • *vim.diagnostic.disable()* Use |vim.diagnostic.enable()| + • *vim.diagnostic.is_disabled()* Use |vim.diagnostic.is_enabled()| + • Legacy signature: `vim.diagnostic.enable(buf:number, namespace:number)` + +LSP +• *vim.lsp.util.get_progress_messages()* Use |vim.lsp.status()| instead. +• *vim.lsp.get_active_clients()* Use |vim.lsp.get_clients()| instead. +• *vim.lsp.for_each_buffer_client()* Use |vim.lsp.get_clients()| instead. +• *vim.lsp.util.trim_empty_lines()* Use |vim.split()| with `trimempty` instead. +• *vim.lsp.util.try_trim_markdown_code_blocks()* +• *vim.lsp.util.set_lines()* +• *vim.lsp.util.extract_completion_items()* +• *vim.lsp.util.parse_snippet()* +• *vim.lsp.util.text_document_completion_list_to_complete_items()* +• *vim.lsp.util.lookup_section()* Use |vim.tbl_get()| instead: > local keys = vim.split(section, '.', { plain = true }) local vim.tbl_get(table, unpack(keys)) +LUA • *vim.loop* Use |vim.uv| instead. +• *vim.tbl_add_reverse_lookup()* +• *vim.tbl_flatten()* Use |Iter:flatten()| instead. +• *vim.tbl_islist()* Use |vim.islist()| instead. -• vim.treesitter functions: - - *LanguageTree:for_each_child()* Use |LanguageTree:children()| (non-recursive) instead. - +OPTIONS • The "term_background" UI option |ui-ext-options| is deprecated and no longer populated. Background color detection is now performed in Lua by the Nvim core, not the TUI. -• Lua stdlib: - - *vim.tbl_add_reverse_lookup()* - - *vim.tbl_flatten()* Use |Iter:flatten()| instead. - - *vim.tbl_islist()* Use |vim.islist()| instead. - -DEPRECATED IN 0.9 *deprecated-0.9* +TREESITTER +• *LanguageTree:for_each_child()* Use |LanguageTree:children()| (non-recursive) instead. -• vim.treesitter functions - - *vim.treesitter.language.require_language()* Use |vim.treesitter.language.add()| instead. - - *vim.treesitter.get_node_at_pos()* Use |vim.treesitter.get_node()| instead. - - *vim.treesitter.get_node_at_cursor()* Use |vim.treesitter.get_node()| - and |TSNode:type()| instead. -• |API| functions: - - *nvim_get_hl_by_name()* Use |nvim_get_hl()| instead. - - *nvim_get_hl_by_id()* Use |nvim_get_hl()| instead. +------------------------------------------------------------------------------ +DEPRECATED IN 0.9 *deprecated-0.9* +API +- *nvim_get_hl_by_name()* Use |nvim_get_hl()| instead. +- *nvim_get_hl_by_id()* Use |nvim_get_hl()| instead. + +TREESITTER +- *vim.treesitter.language.require_language()* Use |vim.treesitter.language.add()| instead. +- *vim.treesitter.get_node_at_pos()* Use |vim.treesitter.get_node()| instead. +- *vim.treesitter.get_node_at_cursor()* Use |vim.treesitter.get_node()| + and |TSNode:type()| instead. • The following top level Treesitter functions have been moved: - *vim.treesitter.inspect_language()* -> |vim.treesitter.language.inspect()| - *vim.treesitter.get_query_files()* -> |vim.treesitter.query.get_files()| @@ -98,10 +104,12 @@ DEPRECATED IN 0.9 *deprecated-0.9* - *vim.treesitter.query.get_range()* -> |vim.treesitter.get_range()| - *vim.treesitter.query.get_node_text()* -> |vim.treesitter.get_node_text()| -• Lua stdlib: +LUA - *nvim_exec()* Use |nvim_exec2()| instead. - *vim.pretty_print()* Use |vim.print()| instead. + +------------------------------------------------------------------------------ DEPRECATED IN 0.8 OR EARLIER API diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index 0be3c24b0a..fccda177d2 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -3830,6 +3830,7 @@ chained to create iterator "pipelines": the output of each pipeline stage is input to the next stage. The first stage depends on the type passed to `vim.iter()`: • List tables (arrays, |lua-list|) yield only the value of each element. + • Holes (nil values) are allowed. • Use |Iter:enumerate()| to also pass the index to the next stage. • Or initialize with ipairs(): `vim.iter(ipairs(…))`. • Non-list tables (|lua-dict|) yield both the key and value of each element. @@ -4287,9 +4288,9 @@ Iter:totable() *Iter:totable()* 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. + pipeline. Array-like tables and function iterators will be collected into + an array-like table. If multiple values are returned from the final stage + in the iterator pipeline, each value will be included in a table. Examples: >lua vim.iter(string.gmatch('100 20 50', '%d+')):map(tonumber):totable() @@ -4302,7 +4303,7 @@ Iter:totable() *Iter:totable()* -- { { 'a', 1 }, { 'c', 3 } } < - The generated table is a list-like table with consecutive, numeric + The generated table is an array-like table with consecutive, numeric indices. To create a map-like table with arbitrary keys, use |Iter:fold()|. diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index a1859d19cf..0730faa441 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -25,7 +25,12 @@ These changes may require adaptations in your config or plugins. API -• TODO +• `vim.rpcnotify(0)` and `rpcnotify(0)` broadcast to ALL channels. Previously + they would "multicast" only to subscribed channels (controlled by + `nvim_subscribe()`). Plugins and clients that want "multicast" behavior must + now maintain their own list of channels. + • In the future, |vim.rpcnotify()| may accept a list of channels, if there + is demand for this use-case. DEFAULTS diff --git a/runtime/lua/provider/ruby/health.lua b/runtime/lua/provider/ruby/health.lua index 4d859597a4..31c2fe3201 100644 --- a/runtime/lua/provider/ruby/health.lua +++ b/runtime/lua/provider/ruby/health.lua @@ -19,8 +19,7 @@ function M.check() end health.info('Ruby: ' .. health.system({ 'ruby', '-v' })) - local ruby_detect_table = vim.provider.ruby.detect() - local host = ruby_detect_table[1] + local host, _ = vim.provider.ruby.detect() if (not host) or host:find('^%s*$') then health.warn('`neovim-ruby-host` not found.', { 'Run `gem install neovim` to ensure the neovim RubyGem is installed.', diff --git a/runtime/lua/vim/iter.lua b/runtime/lua/vim/iter.lua index 06415773bc..1093759efe 100644 --- a/runtime/lua/vim/iter.lua +++ b/runtime/lua/vim/iter.lua @@ -7,6 +7,7 @@ --- `vim.iter()`: --- --- - List tables (arrays, |lua-list|) yield only the value of each element. +--- - Holes (nil values) are allowed. --- - Use |Iter:enumerate()| to also pass the index to the next stage. --- - Or initialize with ipairs(): `vim.iter(ipairs(…))`. --- - Non-list tables (|lua-dict|) yield both the key and value of each element. @@ -80,13 +81,13 @@ end --- Special case implementations for iterators on list tables. ---@nodoc ----@class ListIter : Iter +---@class ArrayIter : Iter ---@field _table table Underlying table data ---@field _head number Index to the front of a table iterator ---@field _tail number Index to the end of a table iterator (exclusive) -local ListIter = {} -ListIter.__index = setmetatable(ListIter, Iter) -ListIter.__call = function(self) +local ArrayIter = {} +ArrayIter.__index = setmetatable(ArrayIter, Iter) +ArrayIter.__call = function(self) return self:next() end @@ -110,36 +111,34 @@ end local function sanitize(t) if type(t) == 'table' and getmetatable(t) == packedmt then - -- Remove length tag + -- Remove length tag and metatable t.n = nil + setmetatable(t, nil) end return t end ---- Flattens a single list-like table. Errors if it attempts to flatten a +--- Flattens a single array-like table. Errors if it attempts to flatten a --- dict-like table ----@param v table table which should be flattened +---@param t table table which should be flattened ---@param max_depth number depth to which the table should be flattened ---@param depth number current iteration depth ---@param result table output table that contains flattened result ---@return table|nil flattened table if it can be flattened, otherwise nil -local function flatten(v, max_depth, depth, result) - if depth < max_depth and type(v) == 'table' then - local i = 0 - for _ in pairs(v) do - i = i + 1 - - if v[i] == nil then +local function flatten(t, max_depth, depth, result) + if depth < max_depth and type(t) == 'table' then + for k, v in pairs(t) do + if type(k) ~= 'number' or k <= 0 or math.floor(k) ~= k then -- short-circuit: this is not a list like table return nil end - if flatten(v[i], max_depth, depth + 1, result) == nil then + if flatten(v, max_depth, depth + 1, result) == nil then return nil end end - else - result[#result + 1] = v + elseif t ~= nil then + result[#result + 1] = t end return result @@ -198,7 +197,7 @@ function Iter:filter(f) end ---@private -function ListIter:filter(f) +function ArrayIter:filter(f) local inc = self._head < self._tail and 1 or -1 local n = self._head for i = self._head, self._tail - inc, inc do @@ -233,11 +232,11 @@ end ---@return Iter ---@diagnostic disable-next-line:unused-local function Iter:flatten(depth) -- luacheck: no unused args - error('flatten() requires a list-like table') + error('flatten() requires an array-like table') end ---@private -function ListIter:flatten(depth) +function ArrayIter:flatten(depth) depth = depth or 1 local inc = self._head < self._tail and 1 or -1 local target = {} @@ -247,7 +246,7 @@ function ListIter:flatten(depth) -- exit early if we try to flatten a dict-like table if flattened == nil then - error('flatten() requires a list-like table') + error('flatten() requires an array-like table') end for _, v in pairs(flattened) do @@ -327,7 +326,7 @@ function Iter:map(f) end ---@private -function ListIter:map(f) +function ArrayIter:map(f) local inc = self._head < self._tail and 1 or -1 local n = self._head for i = self._head, self._tail - inc, inc do @@ -360,7 +359,7 @@ function Iter:each(f) end ---@private -function ListIter:each(f) +function ArrayIter:each(f) local inc = self._head < self._tail and 1 or -1 for i = self._head, self._tail - inc, inc do f(unpack(self._table[i])) @@ -371,7 +370,7 @@ 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 +--- Array-like tables and function iterators will be collected into an array-like --- table. If multiple values are returned from the final stage in the iterator --- pipeline, each value will be included in a table. --- @@ -388,7 +387,7 @@ end --- -- { { 'a', 1 }, { 'c', 3 } } --- ``` --- ---- The generated table is a list-like table with consecutive, numeric indices. +--- The generated table is an array-like table with consecutive, numeric indices. --- To create a map-like table with arbitrary keys, use |Iter:fold()|. --- --- @@ -408,12 +407,12 @@ function Iter:totable() end ---@private -function ListIter:totable() - if self.next ~= ListIter.next or self._head >= self._tail then +function ArrayIter:totable() + if self.next ~= ArrayIter.next or self._head >= self._tail then return Iter.totable(self) end - local needs_sanitize = getmetatable(self._table[1]) == packedmt + local needs_sanitize = getmetatable(self._table[self._head]) == packedmt -- Reindex and sanitize. local len = self._tail - self._head @@ -493,7 +492,7 @@ function Iter:fold(init, f) end ---@private -function ListIter:fold(init, f) +function ArrayIter:fold(init, f) local acc = init local inc = self._head < self._tail and 1 or -1 for i = self._head, self._tail - inc, inc do @@ -525,7 +524,7 @@ function Iter:next() end ---@private -function ListIter:next() +function ArrayIter:next() if self._head ~= self._tail then local v = self._table[self._head] local inc = self._head < self._tail and 1 or -1 @@ -548,11 +547,11 @@ end --- ---@return Iter function Iter:rev() - error('rev() requires a list-like table') + error('rev() requires an array-like table') end ---@private -function ListIter:rev() +function ArrayIter:rev() local inc = self._head < self._tail and 1 or -1 self._head, self._tail = self._tail - inc, self._head - inc return self @@ -576,11 +575,11 @@ end --- ---@return any function Iter:peek() - error('peek() requires a list-like table') + error('peek() requires an array-like table') end ---@private -function ListIter:peek() +function ArrayIter:peek() if self._head ~= self._tail then return self._table[self._head] end @@ -657,11 +656,11 @@ end ---@return any ---@diagnostic disable-next-line: unused-local function Iter:rfind(f) -- luacheck: no unused args - error('rfind() requires a list-like table') + error('rfind() requires an array-like table') end ---@private -function ListIter:rfind(f) +function ArrayIter:rfind(f) if type(f) ~= 'function' then local val = f f = function(v) @@ -709,10 +708,10 @@ function Iter:take(n) end ---@private -function ListIter:take(n) - local inc = self._head < self._tail and 1 or -1 +function ArrayIter:take(n) + local inc = self._head < self._tail and n or -n local cmp = self._head < self._tail and math.min or math.max - self._tail = cmp(self._tail, self._head + n * inc) + self._tail = cmp(self._tail, self._head + inc) return self end @@ -730,11 +729,11 @@ end --- ---@return any function Iter:pop() - error('pop() requires a list-like table') + error('pop() requires an array-like table') end --- @nodoc -function ListIter:pop() +function ArrayIter:pop() if self._head ~= self._tail then local inc = self._head < self._tail and 1 or -1 self._tail = self._tail - inc @@ -760,11 +759,11 @@ end --- ---@return any function Iter:rpeek() - error('rpeek() requires a list-like table') + error('rpeek() requires an array-like table') end ---@nodoc -function ListIter:rpeek() +function ArrayIter:rpeek() if self._head ~= self._tail then local inc = self._head < self._tail and 1 or -1 return self._table[self._tail - inc] @@ -793,7 +792,7 @@ function Iter:skip(n) end ---@private -function ListIter:skip(n) +function ArrayIter:skip(n) local inc = self._head < self._tail and n or -n self._head = self._head + inc if (inc > 0 and self._head > self._tail) or (inc < 0 and self._head < self._tail) then @@ -818,11 +817,11 @@ end ---@return Iter ---@diagnostic disable-next-line: unused-local function Iter:rskip(n) -- luacheck: no unused args - error('rskip() requires a list-like table') + error('rskip() requires an array-like table') end ---@private -function ListIter:rskip(n) +function ArrayIter:rskip(n) local inc = self._head < self._tail and n or -n self._tail = self._tail - inc if (inc > 0 and self._head > self._tail) or (inc < 0 and self._head < self._tail) then @@ -870,11 +869,11 @@ end ---@return Iter ---@diagnostic disable-next-line: unused-local function Iter:slice(first, last) -- luacheck: no unused args - error('slice() requires a list-like table') + error('slice() requires an array-like table') end ---@private -function ListIter:slice(first, last) +function ArrayIter:slice(first, last) return self:skip(math.max(0, first - 1)):rskip(math.max(0, self._tail - last - 1)) end @@ -955,7 +954,7 @@ function Iter:last() end ---@private -function ListIter:last() +function ArrayIter:last() local inc = self._head < self._tail and 1 or -1 local v = self._table[self._tail - inc] self._head = self._tail @@ -1000,7 +999,7 @@ function Iter:enumerate() end ---@private -function ListIter:enumerate() +function ArrayIter:enumerate() local inc = self._head < self._tail and 1 or -1 for i = self._head, self._tail - inc, inc do local v = self._table[i] @@ -1030,17 +1029,14 @@ function Iter.new(src, ...) local t = {} - -- O(n): scan the source table to decide if it is a list (consecutive integer indices 1…n). - local count = 0 - for _ in pairs(src) do - count = count + 1 - local v = src[count] - if v == nil then + -- O(n): scan the source table to decide if it is an array (only positive integer indices). + for k, v in pairs(src) do + if type(k) ~= 'number' or k <= 0 or math.floor(k) ~= k then return Iter.new(pairs(src)) end - t[count] = v + t[#t + 1] = v end - return ListIter.new(t) + return ArrayIter.new(t) end if type(src) == 'function' then @@ -1068,17 +1064,18 @@ function Iter.new(src, ...) return it end ---- Create a new ListIter +--- Create a new ArrayIter --- ----@param t table List-like table. Caller guarantees that this table is a valid list. +---@param t table Array-like table. Caller guarantees that this table is a valid array. Can have +--- holes (nil values). ---@return Iter ---@private -function ListIter.new(t) +function ArrayIter.new(t) local it = {} it._table = t it._head = 1 it._tail = #t + 1 - setmetatable(it, ListIter) + setmetatable(it, ArrayIter) return it end diff --git a/scripts/gen_help_html.lua b/scripts/gen_help_html.lua index b33a94dca5..b712cf1475 100644 --- a/scripts/gen_help_html.lua +++ b/scripts/gen_help_html.lua @@ -532,6 +532,8 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) return ('%s<a href="%s">%s</a>%s'):format(ws(), fixed_url, fixed_url, removed_chars) elseif node_name == 'word' or node_name == 'uppercase_name' then return text + elseif node_name == 'note' then + return ('<b>%s</b>'):format(text) elseif node_name == 'h1' or node_name == 'h2' or node_name == 'h3' then if is_noise(text, stats.noise_lines) then return '' -- Discard common "noise" lines. @@ -694,6 +696,8 @@ local function visit_node(root, level, lang_tree, headings, opt, stats) return string.format('%s</span>', s) end return s + elseif node_name == 'modeline' then + return '' elseif node_name == 'ERROR' then if ignore_parse_error(opt.fname, trimmed) then return text diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index d63b8411e8..af3bfe2c03 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -786,3 +786,23 @@ theend: api_clear_error(&nested_error); return rv; } + +/// @deprecated +/// +/// @param channel_id Channel id (passed automatically by the dispatcher) +/// @param event Event type string +void nvim_subscribe(uint64_t channel_id, String event) + FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY +{ + // Does nothing. `rpcnotify(0,…)` broadcasts to all channels, there are no "subscriptions". +} + +/// @deprecated +/// +/// @param channel_id Channel id (passed automatically by the dispatcher) +/// @param event Event type string +void nvim_unsubscribe(uint64_t channel_id, String event) + FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY +{ + // Does nothing. `rpcnotify(0,…)` broadcasts to all channels, there are no "subscriptions". +} diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index f5b7c8abdd..fc780e1248 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1334,36 +1334,6 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, }); } -/// Subscribes to event broadcasts. -/// -/// @param channel_id Channel id (passed automatically by the dispatcher) -/// @param event Event type string -void nvim_subscribe(uint64_t channel_id, String event) - FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY -{ - size_t length = (event.size < METHOD_MAXLEN ? event.size : METHOD_MAXLEN); - char e[METHOD_MAXLEN + 1]; - memcpy(e, event.data, length); - e[length] = NUL; - rpc_subscribe(channel_id, e); -} - -/// Unsubscribes to event broadcasts. -/// -/// @param channel_id Channel id (passed automatically by the dispatcher) -/// @param event Event type string -void nvim_unsubscribe(uint64_t channel_id, String event) - FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY -{ - size_t length = (event.size < METHOD_MAXLEN - ? event.size - : METHOD_MAXLEN); - char e[METHOD_MAXLEN + 1]; - memcpy(e, event.data, length); - e[length] = NUL; - rpc_unsubscribe(channel_id, e); -} - /// Returns the 24-bit RGB value of a |nvim_get_color_map()| color name or /// "#rrggbb" hexadecimal string. /// diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index b1ee33929c..1fc80e88c4 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -6479,7 +6479,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char *v = os_resolve_shortcut(fname); if (v == NULL) { if (os_is_reparse_point_include(fname)) { - v = os_realpath(fname, v); + v = os_realpath(fname, NULL, MAXPATHL + 1); } } rettv->vval.v_string = (v == NULL ? xstrdup(fname) : v); @@ -6631,7 +6631,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) xfree(buf); } # else - char *v = os_realpath(fname, NULL); + char *v = os_realpath(fname, NULL, MAXPATHL + 1); rettv->vval.v_string = v == NULL ? xstrdup(fname) : v; # endif #endif diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 8ad5858c12..62c99ce082 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -260,7 +260,11 @@ fixdict(1 + #version) for _, item in ipairs(version) do -- NB: all items are mandatory. But any error will be less confusing -- with placeholder vim.NIL (than invalid mpack data) - put(item[1], item[2] or vim.NIL) + local val = item[2] + if val == nil then + val = vim.NIL + end + put(item[1], val) end put('build', version_build) diff --git a/src/nvim/generators/nvim_version.lua.in b/src/nvim/generators/nvim_version.lua.in index d0dbf77922..c29141fc68 100644 --- a/src/nvim/generators/nvim_version.lua.in +++ b/src/nvim/generators/nvim_version.lua.in @@ -2,7 +2,7 @@ return { {"major", ${NVIM_VERSION_MAJOR}}, {"minor", ${NVIM_VERSION_MINOR}}, {"patch", ${NVIM_VERSION_PATCH}}, - {"prerelease", "$NVIM_VERSION_PRERELEASE" ~= ""}, + {"prerelease", "${NVIM_VERSION_PRERELEASE}" ~= ""}, {"api_level", ${NVIM_API_LEVEL}}, {"api_compatible", ${NVIM_API_LEVEL_COMPAT}}, {"api_prerelease", ${NVIM_API_PRERELEASE}}, diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index 268d6fe6e4..5737a0440f 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -67,8 +67,6 @@ static void log_notify(char *dir, uint64_t channel_id, const char *name) # define log_notify(...) #endif -static Set(cstr_t) event_strings = SET_INIT; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "msgpack_rpc/channel.c.generated.h" #endif @@ -111,9 +109,9 @@ static Channel *find_rpc_channel(uint64_t id) return chan; } -/// Publishes an event to a channel. +/// Publishes an event to a channel (emits a notification to method `name`). /// -/// @param id Channel id. 0 means "broadcast to all subscribed channels" +/// @param id Channel id, or 0 to broadcast to all RPC channels. /// @param name Event name (application-defined) /// @param args Array of event arguments /// @return True if the event was sent successfully, false otherwise. @@ -204,41 +202,6 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem return frame.errored ? NIL : frame.result; } -/// Subscribes to event broadcasts -/// -/// @param id The channel id -/// @param event The event type string -void rpc_subscribe(uint64_t id, char *event) -{ - Channel *channel; - - if (!(channel = find_rpc_channel(id))) { - abort(); - } - - const char **key_alloc = NULL; - if (set_put_ref(cstr_t, &event_strings, event, &key_alloc)) { - *key_alloc = xstrdup(event); - } - - set_put(cstr_t, channel->rpc.subscribed_events, *key_alloc); -} - -/// Unsubscribes to event broadcasts -/// -/// @param id The channel id -/// @param event The event type string -void rpc_unsubscribe(uint64_t id, char *event) -{ - Channel *channel; - - if (!(channel = find_rpc_channel(id))) { - abort(); - } - - unsubscribe(channel, event); -} - static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, bool eof) { Channel *channel = data; @@ -494,34 +457,24 @@ static void send_error(Channel *chan, MsgpackRpcRequestHandler handler, MessageT api_clear_error(&e); } +/// Broadcasts a notification to all RPC channels. static void broadcast_event(const char *name, Array args) { - kvec_withinit_t(Channel *, 4) subscribed = KV_INITIAL_VALUE; - kvi_init(subscribed); + kvec_withinit_t(Channel *, 4) chans = KV_INITIAL_VALUE; + kvi_init(chans); Channel *channel; map_foreach_value(&channels, channel, { - if (channel->is_rpc - && set_has(cstr_t, channel->rpc.subscribed_events, name)) { - kv_push(subscribed, channel); + if (channel->is_rpc) { + kv_push(chans, channel); } }); - if (kv_size(subscribed)) { - serialize_request(subscribed.items, kv_size(subscribed), 0, name, args); + if (kv_size(chans)) { + serialize_request(chans.items, kv_size(chans), 0, name, args); } - kvi_destroy(subscribed); -} - -static void unsubscribe(Channel *channel, char *event) -{ - if (!set_has(cstr_t, &event_strings, event)) { - WLOG("RPC: ch %" PRIu64 ": tried to unsubscribe unknown event '%s'", - channel->id, event); - return; - } - set_del(cstr_t, channel->rpc.subscribed_events, event); + kvi_destroy(chans); } /// Mark rpc state as closed, and release its reference to the channel. @@ -551,7 +504,6 @@ void rpc_free(Channel *channel) unpacker_teardown(channel->rpc.unpacker); xfree(channel->rpc.unpacker); - set_destroy(cstr_t, channel->rpc.subscribed_events); kv_destroy(channel->rpc.call_stack); api_free_dictionary(channel->rpc.info); } @@ -719,12 +671,6 @@ const char *get_client_info(Channel *chan, const char *key) #ifdef EXITFREE void rpc_free_all_mem(void) { - cstr_t key; - set_foreach(&event_strings, key, { - xfree((void *)key); - }); - set_destroy(cstr_t, &event_strings); - multiqueue_free(ch_before_blocking_events); } #endif diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h index 56dbb332e0..7dc1374964 100644 --- a/src/nvim/msgpack_rpc/channel_defs.h +++ b/src/nvim/msgpack_rpc/channel_defs.h @@ -37,7 +37,6 @@ typedef struct { } RequestEvent; typedef struct { - Set(cstr_t) subscribed_events[1]; bool closed; Unpacker *unpacker; uint32_t next_request_id; diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index fbc3a243a6..5a79004c41 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -474,17 +474,9 @@ void init_homedir(void) var = os_homedir(); } - if (var != NULL) { - // Change to the directory and get the actual path. This resolves - // links. Don't do it when we can't return. - if (os_dirname(os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) { - if (!os_chdir(var) && os_dirname(IObuff, IOSIZE) == OK) { - var = IObuff; - } - if (os_chdir(os_buf) != 0) { - emsg(_(e_prev_dir)); - } - } + // Get the actual path. This resolves links. + if (var != NULL && os_realpath(var, IObuff, IOSIZE) != NULL) { + var = IObuff; } // Fall back to current working directory if home is not found diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 2eca906d4e..19bdf30311 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -1320,22 +1320,22 @@ bool os_fileid_equal_fileinfo(const FileID *file_id, const FileInfo *file_info) /// Return the canonicalized absolute pathname. /// /// @param[in] name Filename to be canonicalized. -/// @param[out] buf Buffer to store the canonicalized values. A minimum length -// of MAXPATHL+1 is required. If it is NULL, memory is -// allocated. In that case, the caller should deallocate this -// buffer. +/// @param[out] buf Buffer to store the canonicalized values. +/// If it is NULL, memory is allocated. In that case, the caller +/// should deallocate this buffer. +/// @param[in] len The length of the buffer. /// /// @return pointer to the buf on success, or NULL. -char *os_realpath(const char *name, char *buf) +char *os_realpath(const char *name, char *buf, size_t len) FUNC_ATTR_NONNULL_ARG(1) { uv_fs_t request; int result = uv_fs_realpath(NULL, &request, name, NULL); if (result == kLibuvSuccess) { if (buf == NULL) { - buf = xmallocz(MAXPATHL); + buf = xmalloc(len); } - xstrlcpy(buf, request.ptr, MAXPATHL + 1); + xstrlcpy(buf, request.ptr, len); } uv_fs_req_cleanup(&request); return result == kLibuvSuccess ? buf : NULL; diff --git a/src/nvim/path.c b/src/nvim/path.c index f7e8b2b65c..96330e000b 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -2273,13 +2273,20 @@ bool match_suffix(char *fname) /// @return `FAIL` for failure, `OK` for success. int path_full_dir_name(char *directory, char *buffer, size_t len) { - int SUCCESS = 0; - int retval = OK; - if (strlen(directory) == 0) { return os_dirname(buffer, len); } + if (os_realpath(directory, buffer, len) != NULL) { + return OK; + } + + // Path does not exist (yet). For a full path fail, will use the path as-is. + if (path_is_absolute(directory)) { + return FAIL; + } + // For a relative path use the current directory and append the file name. + char old_dir[MAXPATHL]; // Get current directory name. @@ -2287,36 +2294,12 @@ int path_full_dir_name(char *directory, char *buffer, size_t len) return FAIL; } - // We have to get back to the current dir at the end, check if that works. - if (os_chdir(old_dir) != SUCCESS) { + xstrlcpy(buffer, old_dir, len); + if (append_path(buffer, directory, len) == FAIL) { return FAIL; } - if (os_chdir(directory) != SUCCESS) { - // Path does not exist (yet). For a full path fail, - // will use the path as-is. For a relative path use - // the current directory and append the file name. - if (path_is_absolute(directory)) { - // Do not return immediately since we may be in the wrong directory. - retval = FAIL; - } else { - xstrlcpy(buffer, old_dir, len); - if (append_path(buffer, directory, len) == FAIL) { - retval = FAIL; - } - } - } else if (os_dirname(buffer, len) == FAIL) { - // Do not return immediately since we are in the wrong directory. - retval = FAIL; - } - - if (os_chdir(old_dir) != SUCCESS) { - // That shouldn't happen, since we've tested if it works. - retval = FAIL; - emsg(_(e_prev_dir)); - } - - return retval; + return OK; } // Append to_append to path with a slash in between. diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index b8efbfbd0e..7b4c4e8312 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -1,7 +1,6 @@ local t = require('test.testutil') local n = require('test.functional.testnvim')() -local assert_log = t.assert_log local eq, clear, eval, command, next_msg = t.eq, n.clear, n.eval, n.command, n.next_msg local api = n.api local exec_lua = n.exec_lua @@ -34,18 +33,18 @@ describe('notify', function() end) end) - describe('passing 0 as the channel id', function() - it('sends the notification/args to all subscribed channels', function() - api.nvim_subscribe('event2') + describe('channel id 0', function() + it('broadcasts the notification/args to all channels', function() eval('rpcnotify(0, "event1", 1, 2, 3)') eval('rpcnotify(0, "event2", 4, 5, 6)') eval('rpcnotify(0, "event2", 7, 8, 9)') + eq({ 'notification', 'event1', { 1, 2, 3 } }, next_msg()) eq({ 'notification', 'event2', { 4, 5, 6 } }, next_msg()) eq({ 'notification', 'event2', { 7, 8, 9 } }, next_msg()) - api.nvim_unsubscribe('event2') - api.nvim_subscribe('event1') + eval('rpcnotify(0, "event2", 10, 11, 12)') eval('rpcnotify(0, "event1", 13, 14, 15)') + eq({ 'notification', 'event2', { 10, 11, 12 } }, next_msg()) eq({ 'notification', 'event1', { 13, 14, 15 } }, next_msg()) end) @@ -78,17 +77,6 @@ describe('notify', function() end) end) - it('unsubscribe non-existing event #8745', function() - clear { env = { - NVIM_LOG_FILE = testlog, - } } - api.nvim_subscribe('event1') - api.nvim_unsubscribe('doesnotexist') - assert_log("tried to unsubscribe unknown event 'doesnotexist'", testlog, 10) - api.nvim_unsubscribe('event1') - assert_alive() - end) - it('cancels stale events on channel close', function() local catchan = eval("jobstart(['cat'], {'rpc': v:true})") local catpath = eval('exepath("cat")') @@ -97,7 +85,6 @@ describe('notify', function() exec_lua( [[ vim.rpcnotify(..., "nvim_call_function", 'chanclose', {..., 'rpc'}) - vim.rpcnotify(..., "nvim_subscribe", "daily_rant") return vim.api.nvim_get_chan_info(...) ]], catchan diff --git a/test/functional/lua/iter_spec.lua b/test/functional/lua/iter_spec.lua index 676b83a801..79e92e6a7d 100644 --- a/test/functional/lua/iter_spec.lua +++ b/test/functional/lua/iter_spec.lua @@ -117,6 +117,9 @@ describe('vim.iter', function() eq({ { 1, 1 }, { 2, 4 }, { 3, 9 } }, it:totable()) end + -- Holes in array-like tables are removed + eq({ 1, 2, 3 }, vim.iter({ 1, nil, 2, nil, 3 }):totable()) + do local it = vim.iter(string.gmatch('1,4,lol,17,blah,2,9,3', '%d+')):map(tonumber) eq({ 1, 4, 17, 2, 9, 3 }, it:totable()) @@ -142,7 +145,7 @@ describe('vim.iter', function() eq({ 3, 2, 1 }, vim.iter({ 1, 2, 3 }):rev():totable()) local it = vim.iter(string.gmatch('abc', '%w')) - matches('rev%(%) requires a list%-like table', pcall_err(it.rev, it)) + matches('rev%(%) requires an array%-like table', pcall_err(it.rev, it)) end) it('skip()', function() @@ -181,7 +184,7 @@ describe('vim.iter', function() end local it = vim.iter(vim.gsplit('a|b|c|d', '|')) - matches('rskip%(%) requires a list%-like table', pcall_err(it.rskip, it, 0)) + matches('rskip%(%) requires an array%-like table', pcall_err(it.rskip, it, 0)) end) it('slice()', function() @@ -195,7 +198,7 @@ describe('vim.iter', function() eq({ 8, 9, 10 }, vim.iter(q):slice(8, 11):totable()) local it = vim.iter(vim.gsplit('a|b|c|d', '|')) - matches('slice%(%) requires a list%-like table', pcall_err(it.slice, it, 1, 3)) + matches('slice%(%) requires an array%-like table', pcall_err(it.slice, it, 1, 3)) end) it('nth()', function() @@ -234,7 +237,7 @@ describe('vim.iter', function() end local it = vim.iter(vim.gsplit('a|b|c|d', '|')) - matches('rskip%(%) requires a list%-like table', pcall_err(it.nth, it, -1)) + matches('rskip%(%) requires an array%-like table', pcall_err(it.nth, it, -1)) end) it('take()', function() @@ -356,7 +359,7 @@ describe('vim.iter', function() do local it = vim.iter(vim.gsplit('hi', '')) - matches('peek%(%) requires a list%-like table', pcall_err(it.peek, it)) + matches('peek%(%) requires an array%-like table', pcall_err(it.peek, it)) end end) @@ -417,7 +420,7 @@ describe('vim.iter', function() do local it = vim.iter(vim.gsplit('AbCdE', '')) - matches('rfind%(%) requires a list%-like table', pcall_err(it.rfind, it, 'E')) + matches('rfind%(%) requires an array%-like table', pcall_err(it.rfind, it, 'E')) end end) @@ -434,7 +437,7 @@ describe('vim.iter', function() do local it = vim.iter(vim.gsplit('hi', '')) - matches('pop%(%) requires a list%-like table', pcall_err(it.pop, it)) + matches('pop%(%) requires an array%-like table', pcall_err(it.pop, it)) end end) @@ -448,7 +451,7 @@ describe('vim.iter', function() do local it = vim.iter(vim.gsplit('hi', '')) - matches('rpeek%(%) requires a list%-like table', pcall_err(it.rpeek, it)) + matches('rpeek%(%) requires an array%-like table', pcall_err(it.rpeek, it)) end end) @@ -482,18 +485,20 @@ describe('vim.iter', function() local m = { a = 1, b = { 2, 3 }, d = { 4 } } local it = vim.iter(m) - local flat_err = 'flatten%(%) requires a list%-like table' + local flat_err = 'flatten%(%) requires an array%-like table' matches(flat_err, pcall_err(it.flatten, it)) -- cases from the documentation local simple_example = { 1, { 2 }, { { 3 } } } eq({ 1, 2, { 3 } }, vim.iter(simple_example):flatten():totable()) - local not_list_like = vim.iter({ [2] = 2 }) - matches(flat_err, pcall_err(not_list_like.flatten, not_list_like)) + local not_list_like = { [2] = 2 } + eq({ 2 }, vim.iter(not_list_like):flatten():totable()) + + local also_not_list_like = { nil, 2 } + eq({ 2 }, vim.iter(also_not_list_like):flatten():totable()) - local also_not_list_like = vim.iter({ nil, 2 }) - matches(flat_err, pcall_err(not_list_like.flatten, also_not_list_like)) + eq({ 1, 2, 3 }, vim.iter({ nil, { 1, nil, 2 }, 3 }):flatten():totable()) local nested_non_lists = vim.iter({ 1, { { a = 2 } }, { { nil } }, { 3 } }) eq({ 1, { a = 2 }, { nil }, 3 }, nested_non_lists:flatten():totable()) diff --git a/test/functional/vimscript/api_functions_spec.lua b/test/functional/vimscript/api_functions_spec.lua index 40d96ec281..b2865d2b4c 100644 --- a/test/functional/vimscript/api_functions_spec.lua +++ b/test/functional/vimscript/api_functions_spec.lua @@ -181,8 +181,8 @@ describe('eval-API', function() eq('Vim(call):E117: Unknown function: buffer_get_line', err) -- some api functions are only useful from a msgpack-rpc channel - err = exc_exec('call nvim_subscribe("fancyevent")') - eq('Vim(call):E117: Unknown function: nvim_subscribe', err) + err = exc_exec('call nvim_set_client_info()') + eq('Vim(call):E117: Unknown function: nvim_set_client_info', err) end) it('have metadata accessible with api_info()', function() diff --git a/test/unit/path_spec.lua b/test/unit/path_spec.lua index 44919368bf..6f6a80f44e 100644 --- a/test/unit/path_spec.lua +++ b/test/unit/path_spec.lua @@ -22,11 +22,16 @@ local buffer = nil describe('path.c', function() describe('path_full_dir_name', function() + local old_dir + setup(function() + old_dir = uv.cwd() mkdir('unit-test-directory') + uv.fs_symlink(old_dir .. '/unit-test-directory', 'unit-test-symlink') end) teardown(function() + uv.fs_unlink('unit-test-symlink') uv.fs_rmdir('unit-test-directory') end) @@ -37,35 +42,64 @@ describe('path.c', function() before_each(function() -- Create empty string buffer which will contain the resulting path. - length = string.len(uv.cwd()) + 22 + length = string.len(old_dir) + 22 buffer = cstr(length, '') end) + after_each(function() + uv.chdir(old_dir) + end) + itp('returns the absolute directory name of a given relative one', function() - local result = path_full_dir_name('..', buffer, length) - eq(OK, result) - local old_dir = uv.cwd() + eq(OK, path_full_dir_name('..', buffer, length)) uv.chdir('..') local expected = uv.cwd() uv.chdir(old_dir) - eq(expected, (ffi.string(buffer))) + eq(expected, ffi.string(buffer)) end) itp('returns the current directory name if the given string is empty', function() - eq(OK, (path_full_dir_name('', buffer, length))) - eq(uv.cwd(), (ffi.string(buffer))) + eq(OK, path_full_dir_name('', buffer, length)) + eq(old_dir, ffi.string(buffer)) + end) + + local function test_full_dir_absolute() + itp('works with a normal absolute dir', function() + eq(OK, path_full_dir_name(old_dir .. '/unit-test-directory', buffer, length)) + eq(old_dir .. '/unit-test-directory', ffi.string(buffer)) + end) + + itp('works with a symlinked absolute dir', function() + eq(OK, path_full_dir_name(old_dir .. '/unit-test-symlink', buffer, length)) + eq(old_dir .. '/unit-test-directory', ffi.string(buffer)) + end) + end + + test_full_dir_absolute() + + describe('when cwd does not exist #28786', function() + before_each(function() + mkdir('dir-to-remove') + uv.chdir('dir-to-remove') + uv.fs_rmdir(old_dir .. '/dir-to-remove') + end) + + test_full_dir_absolute() end) itp('works with a normal relative dir', function() - local result = path_full_dir_name('unit-test-directory', buffer, length) - eq(uv.cwd() .. '/unit-test-directory', (ffi.string(buffer))) - eq(OK, result) + eq(OK, path_full_dir_name('unit-test-directory', buffer, length)) + eq(old_dir .. '/unit-test-directory', ffi.string(buffer)) + end) + + itp('works with a symlinked relative dir', function() + eq(OK, path_full_dir_name('unit-test-symlink', buffer, length)) + eq(old_dir .. '/unit-test-directory', ffi.string(buffer)) end) itp('works with a non-existing relative dir', function() - local result = path_full_dir_name('does-not-exist', buffer, length) - eq(uv.cwd() .. '/does-not-exist', (ffi.string(buffer))) - eq(OK, result) + eq(OK, path_full_dir_name('does-not-exist', buffer, length)) + eq(old_dir .. '/does-not-exist', ffi.string(buffer)) end) itp('fails with a non-existing absolute dir', function() |