From d74af818c085e1ffdcf7e9afc101de8cbe3ad883 Mon Sep 17 00:00:00 2001 From: xeluxee <88047141+xeluxee@users.noreply.github.com> Date: Sat, 14 Aug 2021 15:13:56 +0200 Subject: [PATCH] system_open: use asynchronous vim.loop to spawn process + let user customize the command to be used to open a file/folder with default system application (#551) --- README.md | 2 +- doc/nvim-tree-lua.txt | 14 ++++++++++ lua/nvim-tree.lua | 61 ++++++++++++++++++++++++++----------------- 3 files changed, 52 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 0477b738..49676a8a 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ highlight NvimTreeFolderIcon guibg=blue - type `]c` to go to next git item - type `[c` to go to prev git item - type `-` to navigate up to the parent directory of the current file/directory -- type `s` to open a file with default system application or a folder with default file manager +- type `s` to open a file with default system application or a folder with default file manager (if you want to change the command used to do it see `:h g:nvim_tree_system_open_command` and `:h g:nvim_tree_system_open_command_args`) - if the file is a directory, `` will open the directory otherwise it will open the file in the buffer near the tree - if the file is a symlink, `` will follow the symlink (if the target is a file) - `` will open the file in a vertical split diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 320aa6d0..9a949068 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -198,6 +198,20 @@ Can be `0` or `1`. When `1`, will close the tree when a file is opened. Applies to: `edit`, `vsplit`, `split`, `tabnew`. Default is 0 +|g:nvim_tree_system_open_command| *g:nvim_tree_system_open_command* + +A string containing the command used to open a file/folder with default system +application. If left unset it will be automatically filled with the right +command, depending on the operating system. If your operating system isn't +recognized or if you want to use another command you can edit it. +Default: depends on the operating system + +|g:nvim_tree_system_open_command_args| *g:nvim_tree_system_open_command_args* + +An array of strings containing the arguments to be passed to the command +specified in |g:nvim_tree_system_open_command|. +Default: unset if not using Windows + |g:nvim_tree_disable_keybindings| *g:nvim_tree_disable_keybindings* Can be `0` or `1`. When `1`, will disable all keybindings by the plugin. diff --git a/lua/nvim-tree.lua b/lua/nvim-tree.lua index f22f81f5..badfd2e9 100644 --- a/lua/nvim-tree.lua +++ b/lua/nvim-tree.lua @@ -97,34 +97,47 @@ local keypress_funcs = { return lib.open_file('preview', node.absolute_path) end, system_open = function(node) - local system_command - if vim.fn.has('win16') == 1 or vim.fn.has('win32') == 1 or vim.fn.has('win64') == 1 then - system_command = 'start "" ' - elseif vim.fn.has('win32unix') == 1 then - if vim.fn.stridx(vim.fn.system('uname'), 'CYGWIN') ~= -1 then - system_command = 'cygstart ' + if vim.g.nvim_tree_system_open_command == nil then + if vim.fn.has('win32') == 1 or vim.fn.has('win32unix') == 1 then + vim.g.nvim_tree_system_open_command = 'cmd' + vim.g.nvim_tree_system_open_command_args = {'/c', 'start', '""'} + elseif vim.fn.has('mac') == 1 or vim.fn.has('macunix') == 1 then + vim.g.nvim_tree_system_open_command = 'open' + elseif vim.fn.has('unix') == 1 then + vim.g.nvim_tree_system_open_command = 'xdg-open' else - system_command = 'start "" ' + error('\nNvimTree system_open: cannot open file with system application. Unrecognized platform.\nPlease fill g:nvim_tree_system_open_command with the name of the system file launcher.') + return end - elseif vim.fn.has('mac') == 1 or vim.fn.has('macunix') == 1 then - system_command = 'open ' - elseif vim.fn.has('unix') == 1 then - system_command = 'xdg-open ' - else - vim.cmd('echohl ErrorMsg') - vim.cmd('echomsg "NvimTree system_open: cannot open file with system application. Unsupported platform."') - vim.cmd('echohl None') + end + + local process = {} + process.args = vim.g.nvim_tree_system_open_command_args or {} + table.insert(process.args, node.link_to or node.absolute_path) + process.errors = '\n' + process.stderr = luv.new_pipe(false) + process.handle, process.pid = luv.spawn(vim.g.nvim_tree_system_open_command, + {args = process.args, stdio = {nil, nil, process.stderr}}, + function(code) + process.stderr:read_stop() + process.stderr:close() + process.handle:close() + if code ~= 0 then + process.errors = process.errors .. string.format('NvimTree system_open: return code %d.', code) + error(process.errors) + end + end + ) + if not process.handle then + error("\n" .. process.pid .. "\nNvimTree system_open: failed to spawn process using '" .. vim.g.nvim_tree_system_open_command .. "'.") return end - - local command_output = vim.fn.system(system_command .. '"' .. vim.fn.substitute(node.absolute_path, '"', '\\\\"', 'g') .. '"') - - if vim.v.shell_error ~= 0 then - vim.cmd('echohl ErrorMsg') - vim.cmd(string.format('echomsg "NvimTree system_open: return code %d."', vim.v.shell_error)) - vim.cmd('echomsg "' .. vim.fn.substitute(command_output, '\n', '" | echomsg "', 'g') .. '"') - vim.cmd('echohl None') - end + luv.read_start(process.stderr, + function(err, data) + if err then return end + if data then process.errors = process.errors .. data end + end + ) end, }