From 96a334abeb85a26af87585ec3810116c7cb7d172 Mon Sep 17 00:00:00 2001 From: Steven Arcangeli <506791+stevearc@users.noreply.github.com> Date: Fri, 22 Sep 2023 12:20:37 -0700 Subject: [PATCH] feat: action for opening entry in an external program (#183) --- README.md | 1 + doc/oil.txt | 4 ++++ lua/oil/actions.lua | 43 +++++++++++++++++++++++++++++++++++++++++++ lua/oil/config.lua | 1 + lua/oil/init.lua | 2 +- 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 14404de8..10c8a1c3 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ require("oil").setup({ ["`"] = "actions.cd", ["~"] = "actions.tcd", ["gs"] = "actions.change_sort", + ["gx"] = "actions.open_external", ["g."] = "actions.toggle_hidden", }, -- Set to false to disable all of the above keymaps diff --git a/doc/oil.txt b/doc/oil.txt index 6c3890f1..17071e8a 100644 --- a/doc/oil.txt +++ b/doc/oil.txt @@ -69,6 +69,7 @@ OPTIONS *oil-option ["`"] = "actions.cd", ["~"] = "actions.tcd", ["gs"] = "actions.change_sort", + ["gx"] = "actions.open_external", ["g."] = "actions.toggle_hidden", }, -- Set to false to disable all of the above keymaps @@ -360,6 +361,9 @@ open_cmdline_dir *actions.open_cmdline_di open_cwd *actions.open_cwd* Open oil in Neovim's current working directory +open_external *actions.open_external* + Open the entry under the cursor in an external program + open_terminal *actions.open_terminal* Open a terminal in the current directory diff --git a/lua/oil/actions.lua b/lua/oil/actions.lua index 7596a186..e810ba6d 100644 --- a/lua/oil/actions.lua +++ b/lua/oil/actions.lua @@ -168,6 +168,49 @@ M.open_terminal = { end, } +---Copied from vim.ui.open in Neovim 0.10+ +---@param path string +---@return nil|string[] cmd +---@return nil|string error +local function get_open_cmd(path) + if vim.fn.has("mac") == 1 then + return { "open", path } + elseif vim.fn.has("win32") == 1 then + if vim.fn.executable("rundll32") == 1 then + return { "rundll32", "url.dll,FileProtocolHandler", path } + else + return nil, "rundll32 not found" + end + elseif vim.fn.executable("wslview") == 1 then + return { "wslview", path } + elseif vim.fn.executable("xdg-open") == 1 then + return { "xdg-open", path } + else + return nil, "no handler found" + end +end + +M.open_external = { + desc = "Open the entry under the cursor in an external program", + callback = function() + local entry = oil.get_cursor_entry() + local dir = oil.get_current_dir() + if not entry or not dir then + return + end + local path = dir .. entry.name + -- TODO use vim.ui.open once this is resolved + -- https://github.com/neovim/neovim/issues/24567 + local cmd, err = get_open_cmd(path) + if not cmd then + vim.notify(string.format("Could not open %s: %s", path, err), vim.log.levels.ERROR) + return + end + local jid = vim.fn.jobstart(cmd, { detach = true }) + assert(jid > 0, "Failed to start job") + end, +} + M.refresh = { desc = "Refresh current directory list", callback = function() diff --git a/lua/oil/config.lua b/lua/oil/config.lua index b5e9a689..60fc1b86 100644 --- a/lua/oil/config.lua +++ b/lua/oil/config.lua @@ -54,6 +54,7 @@ local default_config = { ["`"] = "actions.cd", ["~"] = "actions.tcd", ["gs"] = "actions.change_sort", + ["gx"] = "actions.open_external", ["g."] = "actions.toggle_hidden", }, -- Set to false to disable all of the above keymaps diff --git a/lua/oil/init.lua b/lua/oil/init.lua index 1dca041c..9ce7c120 100644 --- a/lua/oil/init.lua +++ b/lua/oil/init.lua @@ -15,7 +15,7 @@ local M = {} ---@field is_modifiable fun(bufnr: integer): boolean Return true if this directory is modifiable (allows for directories with read-only permissions). ---@field get_column fun(name: string): nil|oil.ColumnDefinition If the adapter has any adapter-specific columns, return them when fetched by name. ---@field normalize_url fun(url: string, callback: fun(url: string)) Before oil opens a url it will be normalized. This allows for link following, path normalizing, and converting an oil file url to the actual path of a file. ----@field get_entry_path? fun(url: string, entry: oil.Entry, callback: fun(path: nil|string)) Similar to normalize_url, but used when selecting an entry +---@field get_entry_path? fun(url: string, entry: oil.Entry, callback: fun(path: string)) Similar to normalize_url, but used when selecting an entry ---@field render_action? fun(action: oil.Action): string Render a mutation action for display in the preview window. Only needed if adapter is modifiable. ---@field perform_action? fun(action: oil.Action, cb: fun(err: nil|string)) Perform a mutation action. Only needed if adapter is modifiable. ---@field read_file? fun(bufnr: integer) Used for adapters that deal with remote/virtual files. Read the contents of the file into a buffer.