diff --git a/lua/oil/adapters/files.lua b/lua/oil/adapters/files.lua index ffc970d..a02a789 100644 --- a/lua/oil/adapters/files.lua +++ b/lua/oil/adapters/files.lua @@ -46,6 +46,7 @@ local file_columns = {} local fs_stat_meta_fields = { stat = function(parent_url, entry, cb) local _, path = util.parse_url(parent_url) + assert(path) local dir = fs.posix_to_os_path(path) vim.loop.fs_stat(fs.join(dir, entry[FIELD_NAME]), cb) end, @@ -108,6 +109,7 @@ if not fs.is_windows then render_action = function(action) local _, path = util.parse_url(action.url) + assert(path) return string.format( "CHMOD %s %s", permissions.mode_to_octal_str(action.value), @@ -117,11 +119,13 @@ if not fs.is_windows then perform_action = function(action, callback) local _, path = util.parse_url(action.url) + assert(path) path = fs.posix_to_os_path(path) vim.loop.fs_stat(path, function(err, stat) if err then return callback(err) end + assert(stat) -- We are only changing the lower 12 bits of the mode local mask = bit.bnot(bit.lshift(1, 12) - 1) local old_mode = bit.band(stat.mode, mask) @@ -178,6 +182,7 @@ end ---@param callback fun(url: string) M.normalize_url = function(url, callback) local scheme, path = util.parse_url(url) + assert(path) local os_path = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":p") vim.loop.fs_realpath(os_path, function(err, new_os_path) local realpath = new_os_path or os_path @@ -210,6 +215,7 @@ end ---@param callback fun(err: nil|string, entries: nil|oil.InternalEntry[]) M.list = function(url, column_defs, callback) local _, path = util.parse_url(url) + assert(path) local dir = fs.posix_to_os_path(path) local fetch_meta = columns.get_metadata_fetcher(M, column_defs) cache.begin_update_url(url) @@ -300,6 +306,7 @@ end M.is_modifiable = function(bufnr) local bufname = vim.api.nvim_buf_get_name(bufnr) local _, path = util.parse_url(bufname) + assert(path) local dir = fs.posix_to_os_path(path) local stat = vim.loop.fs_stat(dir) if not stat then @@ -329,6 +336,7 @@ end M.render_action = function(action) if action.type == "create" then local _, path = util.parse_url(action.url) + assert(path) local ret = string.format("CREATE %s", M.to_short_os_path(path, action.entry_type)) if action.link then ret = ret .. " -> " .. fs.posix_to_os_path(action.link) @@ -336,12 +344,15 @@ M.render_action = function(action) return ret elseif action.type == "delete" then local _, path = util.parse_url(action.url) + assert(path) return string.format("DELETE %s", M.to_short_os_path(path, action.entry_type)) elseif action.type == "move" or action.type == "copy" then local dest_adapter = config.get_adapter_by_scheme(action.dest_url) if dest_adapter == M then local _, src_path = util.parse_url(action.src_url) + assert(src_path) local _, dest_path = util.parse_url(action.dest_url) + assert(dest_path) return string.format( " %s %s -> %s", action.type:upper(), @@ -362,6 +373,7 @@ end M.perform_action = function(action, cb) if action.type == "create" then local _, path = util.parse_url(action.url) + assert(path) path = fs.posix_to_os_path(path) if action.entry_type == "directory" then vim.loop.fs_mkdir(path, 493, function(err) @@ -387,6 +399,7 @@ M.perform_action = function(action, cb) end elseif action.type == "delete" then local _, path = util.parse_url(action.url) + assert(path) path = fs.posix_to_os_path(path) if config.delete_to_trash then trash.recursive_delete(path, cb) @@ -397,7 +410,9 @@ M.perform_action = function(action, cb) local dest_adapter = config.get_adapter_by_scheme(action.dest_url) if dest_adapter == M then local _, src_path = util.parse_url(action.src_url) + assert(src_path) local _, dest_path = util.parse_url(action.dest_url) + assert(dest_path) src_path = fs.posix_to_os_path(src_path) dest_path = fs.posix_to_os_path(dest_path) fs.recursive_move(action.entry_type, src_path, dest_path, vim.schedule_wrap(cb)) @@ -409,7 +424,9 @@ M.perform_action = function(action, cb) local dest_adapter = config.get_adapter_by_scheme(action.dest_url) if dest_adapter == M then local _, src_path = util.parse_url(action.src_url) + assert(src_path) local _, dest_path = util.parse_url(action.dest_url) + assert(dest_path) src_path = fs.posix_to_os_path(src_path) dest_path = fs.posix_to_os_path(dest_path) fs.recursive_copy(action.entry_type, src_path, dest_path, cb) diff --git a/lua/oil/adapters/ssh.lua b/lua/oil/adapters/ssh.lua index cc21051..fb87166 100644 --- a/lua/oil/adapters/ssh.lua +++ b/lua/oil/adapters/ssh.lua @@ -261,9 +261,11 @@ M.render_action = function(action) local dest = action.dest_url if config.get_adapter_by_scheme(src) == M then local _, path = util.parse_url(dest) + assert(path) dest = files.to_short_os_path(path, action.entry_type) else local _, path = util.parse_url(src) + assert(path) src = files.to_short_os_path(path, action.entry_type) end return string.format(" %s %s -> %s", action.type:upper(), src, dest) @@ -328,9 +330,11 @@ M.perform_action = function(action, cb) if src_adapter == M then src_arg = url_to_scp(M.parse_url(action.src_url)) local _, path = util.parse_url(action.dest_url) + assert(path) dest_arg = fs.posix_to_os_path(path) else local _, path = util.parse_url(action.src_url) + assert(path) src_arg = fs.posix_to_os_path(path) dest_arg = url_to_scp(M.parse_url(action.dest_url)) end @@ -353,7 +357,9 @@ M.read_file = function(bufnr) local tmpdir = fs.join(vim.fn.stdpath("cache"), "oil") fs.mkdirp(tmpdir) local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, "ssh_XXXXXX")) - vim.loop.fs_close(fd) + if fd then + vim.loop.fs_close(fd) + end local tmp_bufnr = vim.fn.bufadd(tmpfile) shell.run({ "scp", "-C", scp_url, tmpfile }, function(err) @@ -371,7 +377,10 @@ M.read_file = function(bufnr) vim.api.nvim_buf_set_lines(bufnr, 0, 1, true, {}) end vim.bo[bufnr].modified = false - vim.bo[bufnr].filetype = vim.filetype.match({ buf = bufnr, filename = basename }) + local filetype = vim.filetype.match({ buf = bufnr, filename = basename }) + if filetype then + vim.bo[bufnr].filetype = filetype + end vim.cmd.doautocmd({ args = { "BufReadPost", bufname }, mods = { silent = true } }) vim.api.nvim_buf_delete(tmp_bufnr, { force = true }) end) @@ -385,7 +394,9 @@ M.write_file = function(bufnr) local scp_url = url_to_scp(url) local tmpdir = fs.join(vim.fn.stdpath("cache"), "oil") local fd, tmpfile = vim.loop.fs_mkstemp(fs.join(tmpdir, "ssh_XXXXXXXX")) - vim.loop.fs_close(fd) + if fd then + vim.loop.fs_close(fd) + end vim.cmd.doautocmd({ args = { "BufWritePre", bufname }, mods = { silent = true } }) vim.cmd.write({ args = { tmpfile }, bang = true, mods = { silent = true } }) local tmp_bufnr = vim.fn.bufadd(tmpfile) diff --git a/lua/oil/adapters/ssh/connection.lua b/lua/oil/adapters/ssh/connection.lua index 8e592d0..3ebee70 100644 --- a/lua/oil/adapters/ssh/connection.lua +++ b/lua/oil/adapters/ssh/connection.lua @@ -3,6 +3,8 @@ local util = require("oil.util") ---@class oil.sshConnection ---@field meta {user?: string, groups?: string[]} +---@field private term_bufnr integer +---@field private jid integer local SSHConnection = {} local function output_extend(agg, output) @@ -76,20 +78,21 @@ function SSHConnection.new(url) -- anything prior to that, it *will* appear. The first line gets swallowed. "echo '_make_newline_'; echo '===READY==='; exec /bin/bash --norc", }) + local term_bufnr = vim.api.nvim_create_buf(false, true) local self = setmetatable({ meta = {}, commands = {}, connected = false, connection_error = nil, + term_bufnr = term_bufnr, }, { __index = SSHConnection, }) - self.term_bufnr = vim.api.nvim_create_buf(false, true) local term_id local mode = vim.api.nvim_get_mode().mode - util.run_in_fullscreen_win(self.term_bufnr, function() - term_id = vim.api.nvim_open_term(self.term_bufnr, { + util.run_in_fullscreen_win(term_bufnr, function() + term_id = vim.api.nvim_open_term(term_bufnr, { on_input = function(_, _, _, data) pcall(vim.api.nvim_chan_send, self.jid, data) end, @@ -195,6 +198,7 @@ function SSHConnection:_handle_output(start_i) end else for i = start_i, #self._stdout - 1 do + ---@type string local line = self._stdout[i] if line:match("^===BEGIN===%s*$") then self._stdout = util.tbl_slice(self._stdout, i + 1) diff --git a/lua/oil/adapters/test.lua b/lua/oil/adapters/test.lua index b127dfc..0cd0eec 100644 --- a/lua/oil/adapters/test.lua +++ b/lua/oil/adapters/test.lua @@ -7,7 +7,7 @@ M.normalize_url = function(url, callback) callback(url) end ----@param path string +---@param url string ---@param column_defs string[] ---@param cb fun(err: nil|string, entries: nil|oil.InternalEntry[]) M.list = function(url, column_defs, cb) diff --git a/lua/oil/cache.lua b/lua/oil/cache.lua index da04b49..04d82eb 100644 --- a/lua/oil/cache.lua +++ b/lua/oil/cache.lua @@ -136,7 +136,7 @@ M.get_entry_by_url = function(url) return cache and cache[name] end ----@param oil.Action +---@param action oil.Action M.perform_action = function(action) if action.type == "create" then local scheme, path = util.parse_url(action.url) diff --git a/lua/oil/columns.lua b/lua/oil/columns.lua index 43a4d14..625ecae 100644 --- a/lua/oil/columns.lua +++ b/lua/oil/columns.lua @@ -15,7 +15,10 @@ local all_columns = {} ---@class oil.ColumnDefinition ---@field render fun(entry: oil.InternalEntry, conf: nil|table): nil|oil.TextChunk ---@field parse fun(line: string, conf: nil|table): nil|string, nil|string ----@field meta_fields nil|table +---@field meta_fields nil|table +---@field compare? fun(entry: oil.InternalEntry, parsed_value: any): boolean +---@field render_action? fun(action: oil.ChangeAction): string +---@field perform_action? fun(action: oil.ChangeAction, callback: fun(err: nil|string)) ---@param name string ---@param column oil.ColumnDefinition @@ -40,6 +43,7 @@ M.get_supported_columns = function(adapter_or_scheme) else adapter = adapter_or_scheme end + assert(adapter) local ret = {} for _, def in ipairs(config.columns) do if get_column(adapter, def) then diff --git a/lua/oil/fs.lua b/lua/oil/fs.lua index 7c9002a..ab6431b 100644 --- a/lua/oil/fs.lua +++ b/lua/oil/fs.lua @@ -31,6 +31,7 @@ M.touch = function(path, cb) if err then cb(err) else + assert(fd) vim.loop.fs_close(fd, cb) end end) @@ -44,7 +45,8 @@ M.posix_to_os_path = function(path) local drive, rem = path:match("^/([^/]+)/(.*)$") return string.format("%s:\\%s", drive, rem:gsub("/", "\\")) else - return path:gsub("/", "\\") + local newpath = path:gsub("/", "\\") + return newpath end else return path @@ -59,14 +61,15 @@ M.os_to_posix_path = function(path) local drive, rem = path:match("^([^:]+):\\(.*)$") return string.format("/%s/%s", drive:upper(), rem:gsub("\\", "/")) else - return path:gsub("\\", "/") + local newpath = path:gsub("\\", "/") + return newpath end else return path end end -local home_dir = vim.loop.os_homedir() +local home_dir = assert(vim.loop.os_homedir()) ---@param path string ---@return string @@ -189,7 +192,8 @@ M.recursive_copy = function(entry_type, src_path, dest_path, cb) if link_err then return cb(link_err) end - vim.loop.fs_symlink(link, dest_path, nil, cb) + assert(link) + vim.loop.fs_symlink(link, dest_path, 0, cb) end) return end @@ -201,6 +205,7 @@ M.recursive_copy = function(entry_type, src_path, dest_path, cb) if stat_err then return cb(stat_err) end + assert(src_stat) vim.loop.fs_mkdir(dest_path, src_stat.mode, function(mkdir_err) if mkdir_err then return cb(mkdir_err) diff --git a/lua/oil/init.lua b/lua/oil/init.lua index ebe655e..ba16347 100644 --- a/lua/oil/init.lua +++ b/lua/oil/init.lua @@ -11,7 +11,7 @@ local M = {} ---@class oil.Adapter ---@field name string ----@field list fun(path: string, cb: fun(err: nil|string, entries: nil|oil.InternalEntry[])) +---@field list fun(path: string, column_defs: string[], cb: fun(err: nil|string, entries: nil|oil.InternalEntry[])) ---@field is_modifiable fun(bufnr: integer): boolean ---@field get_column fun(name: string): nil|oil.ColumnDefinition ---@field normalize_url fun(url: string, callback: fun(url: string)) @@ -119,6 +119,7 @@ M.empty_trash = function() return end local _, path = util.parse_url(trash_url) + assert(path) local dir = fs.posix_to_os_path(path) if vim.fn.isdirectory(dir) == 1 then fs.recursive_delete("directory", dir, function(err) @@ -157,6 +158,7 @@ M.get_current_dir = function() local util = require("oil.util") local scheme, path = util.parse_url(vim.api.nvim_buf_get_name(0)) if config.adapters[scheme] == "files" then + assert(path) return fs.posix_to_os_path(path) end end @@ -209,6 +211,7 @@ M.get_buffer_parent_url = function(bufname) local parent_url = util.addslash(scheme .. parent) return parent_url, basename else + assert(path) -- TODO maybe we should remove this special case and turn it into a config if scheme == "term://" then path = vim.fn.expand(path:match("^(.*)//")) @@ -310,6 +313,7 @@ M.open_float = function(dir) local title = vim.api.nvim_buf_get_name(src_buf) local scheme, path = util.parse_url(title) if config.adapters[scheme] == "files" then + assert(path) local fs = require("oil.fs") title = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":~") end @@ -750,7 +754,7 @@ local function load_oil_buffer(bufnr) util.rename_buffer(bufnr, bufname) end - local adapter = config.get_adapter_by_scheme(scheme) + local adapter = assert(config.get_adapter_by_scheme(scheme)) if vim.endswith(bufname, "/") then -- This is a small quality-of-life thing. If the buffer name ends with a `/`, we know it's a @@ -885,6 +889,7 @@ M.setup = function(opts) vim.cmd.doautocmd({ args = { "BufWritePost", params.file }, mods = { silent = true } }) else local adapter = config.get_adapter_by_scheme(bufname) + assert(adapter) adapter.write_file(params.buf) end end, diff --git a/lua/oil/keymap_util.lua b/lua/oil/keymap_util.lua index 3a582fd..42d09d7 100644 --- a/lua/oil/keymap_util.lua +++ b/lua/oil/keymap_util.lua @@ -5,7 +5,7 @@ local M = {} local function resolve(rhs) if type(rhs) == "string" and vim.startswith(rhs, "actions.") then - return resolve(actions[vim.split(rhs, ".", true)[2]]) + return resolve(actions[vim.split(rhs, ".", { plain = true })[2]]) elseif type(rhs) == "table" then local opts = vim.deepcopy(rhs) opts.callback = nil diff --git a/lua/oil/loading.lua b/lua/oil/loading.lua index 9ec6006..54a3cdd 100644 --- a/lua/oil/loading.lua +++ b/lua/oil/loading.lua @@ -16,7 +16,7 @@ local spinners = { } ---@param name_or_frames string|string[] ----@return fun() +---@return fun(): string M.get_iter = function(name_or_frames) local frames if type(name_or_frames) == "string" then diff --git a/lua/oil/mutator/init.lua b/lua/oil/mutator/init.lua index cca4bcb..3aa0eb5 100644 --- a/lua/oil/mutator/init.lua +++ b/lua/oil/mutator/init.lua @@ -184,8 +184,9 @@ M.enforce_action_order = function(actions) -- a. TODO optimization: check immediate parents to see if they have no dependencies now -- 5. repeat - -- Gets the dependencies of a particular action. Effectively dynamically calculates the dependency - -- "edges" of the graph. + ---Gets the dependencies of a particular action. Effectively dynamically calculates the dependency + ---"edges" of the graph. + ---@param action oil.Action local function get_deps(action) local ret = {} if action.type == "delete" then @@ -357,7 +358,9 @@ M.process_actions = function(actions, cb) if v.type == "delete" then local scheme, path = util.parse_url(v.url) if config.adapters[scheme] == "files" then - actions[i] = { + assert(path) + ---@type oil.MoveAction + local move_action = { type = "move", src_url = v.url, entry_type = v.entry_type, @@ -366,6 +369,7 @@ M.process_actions = function(actions, cb) math.random(999999) ), } + actions[i] = move_action end end end @@ -439,6 +443,7 @@ M.process_actions = function(actions, cb) end end) if action.type == "change" then + ---@cast action oil.ChangeAction columns.perform_change_action(adapter, action, callback) else adapter.perform_action(action, callback) diff --git a/lua/oil/mutator/preview.lua b/lua/oil/mutator/preview.lua index 54297e8..5e41898 100644 --- a/lua/oil/mutator/preview.lua +++ b/lua/oil/mutator/preview.lua @@ -76,6 +76,7 @@ M.show = vim.schedule_wrap(function(actions, should_confirm, cb) local adapter = util.get_adapter_for_action(action) local line if action.type == "change" then + ---@cast action oil.ChangeAction line = columns.render_change_action(adapter, action) else line = adapter.render_action(action) diff --git a/lua/oil/mutator/progress.lua b/lua/oil/mutator/progress.lua index d208c2d..d007150 100644 --- a/lua/oil/mutator/progress.lua +++ b/lua/oil/mutator/progress.lua @@ -169,6 +169,7 @@ function Progress:set_action(action, idx, total) local adapter = util.get_adapter_for_action(action) local change_line if action.type == "change" then + ---@cast action oil.ChangeAction change_line = columns.render_change_action(adapter, action) else change_line = adapter.render_action(action) diff --git a/lua/oil/mutator/trie.lua b/lua/oil/mutator/trie.lua index cb10bbd..85ec40e 100644 --- a/lua/oil/mutator/trie.lua +++ b/lua/oil/mutator/trie.lua @@ -1,6 +1,10 @@ local util = require("oil.util") + +---@class oil.Trie +---@field private root table local Trie = {} +---@return oil.Trie Trie.new = function() return setmetatable({ root = { values = {}, children = {} }, @@ -13,6 +17,7 @@ end ---@return string[] function Trie:_url_to_path_pieces(url) local scheme, path = util.parse_url(url) + assert(path) local pieces = vim.split(path, "/") table.insert(pieces, 1, scheme) return pieces @@ -131,7 +136,7 @@ end ---Add all actions at a specific path ---@param url string ---@param ret oil.InternalEntry[] ----@param filter nil|fun(entry: oil.InternalEntry): boolean +---@param filter? fun(entry: oil.InternalEntry): boolean function Trie:accum_actions_at(url, ret, filter) local pieces = self:_url_to_path_pieces(url) local current = self.root diff --git a/lua/oil/util.lua b/lua/oil/util.lua index ba3d140..dd2f5df 100644 --- a/lua/oil/util.lua +++ b/lua/oil/util.lua @@ -218,6 +218,7 @@ local function get_possible_buffer_names_from_url(url) local fs = require("oil.fs") local scheme, path = M.parse_url(url) if config.adapters[scheme] == "files" then + assert(path) return { fs.posix_to_os_path(path) } end return { url } @@ -347,6 +348,7 @@ M.add_title_to_win = function(winid, opts) local title = vim.api.nvim_buf_get_name(src_buf) local scheme, path = M.parse_url(title) if config.adapters[scheme] == "files" then + assert(path) local fs = require("oil.fs") title = vim.fn.fnamemodify(fs.posix_to_os_path(path), ":~") end @@ -456,7 +458,7 @@ M.get_adapter_for_action = function(action) error("no adapter found") end if action.dest_url then - local dest_adapter = config.get_adapter_by_scheme(action.dest_url) + local dest_adapter = assert(config.get_adapter_by_scheme(action.dest_url)) if adapter ~= dest_adapter then if adapter.supports_xfer and adapter.supports_xfer[dest_adapter.name] then return adapter diff --git a/lua/oil/view.lua b/lua/oil/view.lua index e92587a..2342d37 100644 --- a/lua/oil/view.lua +++ b/lua/oil/view.lua @@ -476,6 +476,7 @@ M.format_entry_cols = function(entry, column_defs, col_width, adapter) for i, column in ipairs(column_defs) do local chunk = columns.render_col(adapter, column, entry) local text = type(chunk) == "table" and chunk[1] or chunk + ---@cast text string col_width[i + 1] = math.max(col_width[i + 1], vim.api.nvim_strwidth(text)) table.insert(cols, chunk) end