refactor(lua): use vim.system #34707

This commit is contained in:
Yochem van Rosmalen
2025-07-24 05:03:30 +02:00
committed by GitHub
parent 54b8c99e51
commit 35af766de6
9 changed files with 77 additions and 61 deletions

View File

@@ -277,7 +277,7 @@ add_glob_target(
TOUCH_STRATEGY PER_DIR) TOUCH_STRATEGY PER_DIR)
add_custom_target(lintcommit add_custom_target(lintcommit
COMMAND $<TARGET_FILE:nvim_bin> -u NONE -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main) COMMAND $<TARGET_FILE:nvim_bin> --clean -l ${PROJECT_SOURCE_DIR}/scripts/lintcommit.lua main)
add_dependencies(lintcommit nvim_bin) add_dependencies(lintcommit nvim_bin)
add_custom_target(lint) add_custom_target(lint)

View File

@@ -3895,7 +3895,7 @@ conforming to the https://semver.org spec. Plugins, and plugin managers, can
use this to check available tools and dependencies on the current system. use this to check available tools and dependencies on the current system.
Example: >lua Example: >lua
local v = vim.version.parse(vim.fn.system({'tmux', '-V'}), {strict=false}) local v = vim.version.parse(vim.system({'tmux', '-V'}):wait().stdout, {strict=false})
if vim.version.gt(v, {3, 2, 0}) then if vim.version.gt(v, {3, 2, 0}) then
-- ... -- ...
end end

View File

@@ -76,7 +76,7 @@ vim.api.nvim_create_autocmd('TextYankPost', {
vim.api.nvim_create_user_command('GitBlameLine', function() vim.api.nvim_create_user_command('GitBlameLine', function()
local line_number = vim.fn.line('.') -- Get the current line number. See `:h line()` local line_number = vim.fn.line('.') -- Get the current line number. See `:h line()`
local filename = vim.api.nvim_buf_get_name(0) local filename = vim.api.nvim_buf_get_name(0)
print(vim.fn.system({ 'git', 'blame', '-L', line_number .. ',+1', filename })) print(vim.system({ 'git', 'blame', '-L', line_number .. ',+1', filename }):wait().stdout)
end, { desc = 'Print the git blame for the current line' }) end, { desc = 'Print the git blame for the current line' })
-- [[ Add optional packages ]] -- [[ Add optional packages ]]

View File

@@ -1,8 +1,13 @@
local M = {} local M = {}
local health = require('vim.health') local health = require('vim.health')
local shell_error = function() ---Run a system command and return ok and its stdout and stderr combined.
return vim.v.shell_error ~= 0 ---@param cmd string[]
---@return boolean
---@return string
local function system(cmd)
local result = vim.system(cmd, { text = true }):wait()
return result.code == 0, vim.trim(('%s\n%s'):format(result.stdout, result.stderr))
end end
local suggest_faq = 'https://github.com/neovim/neovim/blob/master/BUILD.md#building' local suggest_faq = 'https://github.com/neovim/neovim/blob/master/BUILD.md#building'
@@ -168,10 +173,10 @@ local function check_performance()
end end
-- check for slow shell invocation -- check for slow shell invocation
local slow_cmd_time = 1.5 local slow_cmd_time = 1.5e9
local start_time = vim.fn.reltime() local start_time = vim.uv.hrtime()
vim.fn.system('echo') system({ 'echo' })
local elapsed_time = vim.fn.reltimefloat(vim.fn.reltime(start_time)) local elapsed_time = vim.uv.hrtime() - start_time
if elapsed_time > slow_cmd_time then if elapsed_time > slow_cmd_time then
health.warn( health.warn(
'Slow shell invocation (took ' .. vim.fn.printf('%.2f', elapsed_time) .. ' seconds).' 'Slow shell invocation (took ' .. vim.fn.printf('%.2f', elapsed_time) .. ' seconds).'
@@ -252,17 +257,17 @@ local function check_tmux()
---@param option string ---@param option string
local get_tmux_option = function(option) local get_tmux_option = function(option)
local cmd = 'tmux show-option -qvg ' .. option -- try global scope local cmd = { 'tmux', 'show-option', '-qvg', option } -- try global scope
local out = vim.fn.system(vim.fn.split(cmd)) local ok, out = system(cmd)
local val = vim.fn.substitute(out, [[\v(\s|\r|\n)]], '', 'g') local val = vim.fn.substitute(out, [[\v(\s|\r|\n)]], '', 'g')
if shell_error() then if not ok then
health.error('command failed: ' .. cmd .. '\n' .. out) health.error('command failed: ' .. cmd .. '\n' .. out)
return 'error' return 'error'
elseif val == '' then elseif val == '' then
cmd = 'tmux show-option -qvgs ' .. option -- try session scope cmd = { 'tmux', 'show-option', '-qvgs', option } -- try session scope
out = vim.fn.system(vim.fn.split(cmd)) ok, out = system(cmd)
val = vim.fn.substitute(out, [[\v(\s|\r|\n)]], '', 'g') val = vim.fn.substitute(out, [[\v(\s|\r|\n)]], '', 'g')
if shell_error() then if not ok then
health.error('command failed: ' .. cmd .. '\n' .. out) health.error('command failed: ' .. cmd .. '\n' .. out)
return 'error' return 'error'
end end
@@ -301,16 +306,16 @@ local function check_tmux()
-- check default-terminal and $TERM -- check default-terminal and $TERM
health.info('$TERM: ' .. vim.env.TERM) health.info('$TERM: ' .. vim.env.TERM)
local cmd = 'tmux show-option -qvg default-terminal' local cmd = { 'tmux', 'show-option', '-qvg', 'default-terminal' }
local out = vim.fn.system(vim.fn.split(cmd)) local ok, out = system(cmd)
local tmux_default_term = vim.fn.substitute(out, [[\v(\s|\r|\n)]], '', 'g') local tmux_default_term = vim.fn.substitute(out, [[\v(\s|\r|\n)]], '', 'g')
if tmux_default_term == '' then if tmux_default_term == '' then
cmd = 'tmux show-option -qvgs default-terminal' cmd = { 'tmux', 'show-option', '-qvgs', 'default-terminal' }
out = vim.fn.system(vim.fn.split(cmd)) ok, out = system(cmd)
tmux_default_term = vim.fn.substitute(out, [[\v(\s|\r|\n)]], '', 'g') tmux_default_term = vim.fn.substitute(out, [[\v(\s|\r|\n)]], '', 'g')
end end
if shell_error() then if not ok then
health.error('command failed: ' .. cmd .. '\n' .. out) health.error('command failed: ' .. cmd .. '\n' .. out)
elseif tmux_default_term ~= vim.env.TERM then elseif tmux_default_term ~= vim.env.TERM then
health.info('default-terminal: ' .. tmux_default_term) health.info('default-terminal: ' .. tmux_default_term)
@@ -329,7 +334,7 @@ local function check_tmux()
end end
-- check for RGB capabilities -- check for RGB capabilities
local info = vim.fn.system({ 'tmux', 'show-messages', '-T' }) local _, info = system({ 'tmux', 'show-messages', '-T' })
local has_setrgbb = vim.fn.stridx(info, ' setrgbb: (string)') ~= -1 local has_setrgbb = vim.fn.stridx(info, ' setrgbb: (string)') ~= -1
local has_setrgbf = vim.fn.stridx(info, ' setrgbf: (string)') ~= -1 local has_setrgbf = vim.fn.stridx(info, ' setrgbf: (string)') ~= -1
if not has_setrgbb or not has_setrgbf then if not has_setrgbb or not has_setrgbf then
@@ -349,13 +354,13 @@ local function check_terminal()
end end
health.start('terminal') health.start('terminal')
local cmd = 'infocmp -L' local cmd = { 'infocmp', '-L' }
local out = vim.fn.system(vim.fn.split(cmd)) local ok, out = system(cmd)
local kbs_entry = vim.fn.matchstr(out, 'key_backspace=[^,[:space:]]*') local kbs_entry = vim.fn.matchstr(out, 'key_backspace=[^,[:space:]]*')
local kdch1_entry = vim.fn.matchstr(out, 'key_dc=[^,[:space:]]*') local kdch1_entry = vim.fn.matchstr(out, 'key_dc=[^,[:space:]]*')
if if
shell_error() not ok
and ( and (
vim.fn.has('win32') == 0 vim.fn.has('win32') == 0
or vim.fn.matchstr( or vim.fn.matchstr(

View File

@@ -4,8 +4,13 @@ local iswin = vim.fn.has('win32') == 1
local M = {} local M = {}
local function cmd_ok(cmd) local function cmd_ok(cmd)
local out = vim.fn.system(cmd) local result = vim.system(cmd, { text = true }):wait()
return vim.v.shell_error == 0, out return result.code == 0, result.stdout
end
local function cli_version(cmd)
local ok, out = cmd_ok(cmd)
return ok, vim.version.parse(out, { strict = false })
end end
-- Attempts to construct a shell command from an args list. -- Attempts to construct a shell command from an args list.
@@ -127,14 +132,14 @@ local function clipboard()
os.getenv('TMUX') os.getenv('TMUX')
and vim.fn.executable('tmux') == 1 and vim.fn.executable('tmux') == 1
and vim.fn.executable('pbpaste') == 1 and vim.fn.executable('pbpaste') == 1
and not cmd_ok('pbpaste') and not cmd_ok({ 'pbpaste' })
then then
local tmux_version = string.match(vim.fn.system('tmux -V'), '%d+%.%d+') local _, tmux_version = cli_version({ 'tmux', '-V' })
local advice = { local advice = {
'Install tmux 2.6+. https://superuser.com/q/231130', 'Install tmux 2.6+. https://superuser.com/q/231130',
'or use tmux with reattach-to-user-namespace. https://superuser.com/a/413233', 'or use tmux with reattach-to-user-namespace. https://superuser.com/a/413233',
} }
health.error('pbcopy does not work with tmux version: ' .. tmux_version, advice) health.error('pbcopy does not work with tmux version: ' .. tostring(tmux_version), advice)
end end
local clipboard_tool = vim.fn['provider#clipboard#Executable']() ---@type string local clipboard_tool = vim.fn['provider#clipboard#Executable']() ---@type string
@@ -178,9 +183,8 @@ local function node()
return return
end end
-- local node_v = vim.fn.split(system({'node', '-v'}), "\n")[1] or '' local ok, node_v = cli_version({ 'node', '-v' })
local ok, node_v = cmd_ok({ 'node', '-v' }) health.info('Node.js: ' .. tostring(node_v))
health.info('Node.js: ' .. node_v)
if not ok or vim.version.lt(node_v, '6.0.0') then if not ok or vim.version.lt(node_v, '6.0.0') then
health.warn('Nvim node.js host does not support Node ' .. node_v) health.warn('Nvim node.js host does not support Node ' .. node_v)
-- Skip further checks, they are nonsense if nodejs is too old. -- Skip further checks, they are nonsense if nodejs is too old.
@@ -213,13 +217,14 @@ local function node()
end end
local latest_npm_cmd = ( local latest_npm_cmd = (
iswin and 'cmd /c ' .. manager .. ' info neovim --json' or manager .. ' info neovim --json' iswin and { 'cmd', '/c', manager, 'info', 'neovim', '--json' }
or { manager, 'info', 'neovim', '--json' }
) )
local latest_npm local latest_npm
ok, latest_npm = cmd_ok(vim.split(latest_npm_cmd, ' ')) ok, latest_npm = cmd_ok(latest_npm_cmd)
if not ok or latest_npm:find('^%s$') then if not ok or latest_npm:find('^%s$') then
health.error( health.error(
'Failed to run: ' .. latest_npm_cmd, 'Failed to run: ' .. shellify(latest_npm_cmd),
{ "Make sure you're connected to the internet.", 'Are you behind a firewall or proxy?' } { "Make sure you're connected to the internet.", 'Are you behind a firewall or proxy?' }
) )
return return
@@ -237,8 +242,8 @@ local function node()
ok, current_npm = cmd_ok(current_npm_cmd) ok, current_npm = cmd_ok(current_npm_cmd)
if not ok then if not ok then
health.error( health.error(
'Failed to run: ' .. table.concat(current_npm_cmd, ' '), 'Failed to run: ' .. shellify(current_npm_cmd),
{ 'Report this issue with the output of: ', table.concat(current_npm_cmd, ' ') } { 'Report this issue with the output of: ', shellify(current_npm_cmd) }
) )
return return
end end
@@ -298,7 +303,7 @@ local function perl()
ok, latest_cpan = cmd_ok(latest_cpan_cmd) ok, latest_cpan = cmd_ok(latest_cpan_cmd)
if not ok or latest_cpan:find('^%s*$') then if not ok or latest_cpan:find('^%s*$') then
health.error( health.error(
'Failed to run: ' .. table.concat(latest_cpan_cmd, ' '), 'Failed to run: ' .. shellify(latest_cpan_cmd),
{ "Make sure you're connected to the internet.", 'Are you behind a firewall or proxy?' } { "Make sure you're connected to the internet.", 'Are you behind a firewall or proxy?' }
) )
return return
@@ -329,8 +334,8 @@ local function perl()
ok, current_cpan = cmd_ok(current_cpan_cmd) ok, current_cpan = cmd_ok(current_cpan_cmd)
if not ok then if not ok then
health.error( health.error(
'Failed to run: ' .. table.concat(current_cpan_cmd, ' '), 'Failed to run: ' .. shellify(current_cpan_cmd),
{ 'Report this issue with the output of: ', table.concat(current_cpan_cmd, ' ') } { 'Report this issue with the output of: ', shellify(current_cpan_cmd) }
) )
return return
end end
@@ -426,12 +431,15 @@ end
--- @param url string --- @param url string
local function download(url) local function download(url)
local has_curl = vim.fn.executable('curl') == 1 local has_curl = vim.fn.executable('curl') == 1
if has_curl and vim.fn.system({ 'curl', '-V' }):find('Protocols:.*https') then if has_curl then
local out, rc = system({ 'curl', '-sL', url }, { stderr = true, ignore_error = true }) local ok, out = cmd_ok({ 'curl', '-V' })
if ok and out:find('Protocols:.*https') then
local content, rc = system({ 'curl', '-sL', url }, { stderr = true, ignore_error = true })
if rc ~= 0 then if rc ~= 0 then
return 'curl error with ' .. url .. ': ' .. rc return 'curl error with ' .. url .. ': ' .. rc
else else
return out return content
end
end end
elseif vim.fn.executable('python') == 1 then elseif vim.fn.executable('python') == 1 then
local script = ([[ local script = ([[
@@ -872,7 +880,8 @@ local function ruby()
) )
return return
end end
health.info('Ruby: ' .. system({ 'ruby', '-v' })) local _, ruby_v = cli_version({ 'ruby', '-v' })
health.info('Ruby: ' .. tostring(ruby_v))
local host, _ = vim.provider.ruby.detect() local host, _ = vim.provider.ruby.detect()
if (not host) or host:find('^%s*$') then if (not host) or host:find('^%s*$') then
@@ -887,11 +896,14 @@ local function ruby()
end end
health.info('Host: ' .. host) health.info('Host: ' .. host)
local latest_gem_cmd = (iswin and 'cmd /c gem list -ra "^^neovim$"' or 'gem list -ra ^neovim$') local latest_gem_cmd = (
local ok, latest_gem = cmd_ok(vim.split(latest_gem_cmd, ' ')) iswin and { 'cmd', '/c', 'gem', 'list', '-ra', '"^^neovim$"' }
or { 'gem', 'list', '-ra', '^neovim$' }
)
local ok, latest_gem = cmd_ok(latest_gem_cmd)
if not ok or latest_gem:find('^%s*$') then if not ok or latest_gem:find('^%s*$') then
health.error( health.error(
'Failed to run: ' .. latest_gem_cmd, 'Failed to run: ' .. shellify(latest_gem_cmd),
{ "Make sure you're connected to the internet.", 'Are you behind a firewall or proxy?' } { "Make sure you're connected to the internet.", 'Are you behind a firewall or proxy?' }
) )
return return
@@ -904,8 +916,8 @@ local function ruby()
ok, current_gem = cmd_ok(current_gem_cmd) ok, current_gem = cmd_ok(current_gem_cmd)
if not ok then if not ok then
health.error( health.error(
'Failed to run: ' .. table.concat(current_gem_cmd, ' '), 'Failed to run: ' .. shellify(current_gem_cmd),
{ 'Report this issue with the output of: ', table.concat(current_gem_cmd, ' ') } { 'Report this issue with the output of: ', shellify(current_gem_cmd) }
) )
return return
end end

View File

@@ -25,14 +25,12 @@ function M.detect()
end end
-- if perl is available, make sure we have 5.22+ -- if perl is available, make sure we have 5.22+
vim.fn.system({ prog, '-e', 'use v5.22' }) if vim.system({ prog, '-e', 'use v5.22' }):wait().code ~= 0 then
if vim.v.shell_error ~= 0 then
return nil, 'Perl version is too old, 5.22+ required' return nil, 'Perl version is too old, 5.22+ required'
end end
-- if perl is available, make sure the required module is available -- if perl is available, make sure the required module is available
vim.fn.system({ prog, '-W', '-MNeovim::Ext', '-e', '' }) if vim.system({ prog, '-W', '-MNeovim::Ext', '-e', '' }):wait().code ~= 0 then
if vim.v.shell_error ~= 0 then
return nil, '"Neovim::Ext" cpan module is not installed' return nil, '"Neovim::Ext" cpan module is not installed'
end end
return prog, nil return prog, nil

View File

@@ -45,8 +45,8 @@ function M.detect()
prog = '' prog = ''
else else
-- neovim-ruby-host could be an rbenv shim for another Ruby version. -- neovim-ruby-host could be an rbenv shim for another Ruby version.
vim.fn.system(p) local result = vim.system({ p }):wait()
prog = vim.v.shell_error ~= 0 and '' or p prog = result.code ~= 0 and '' or p
end end
end end
local err = prog == '' and 'missing ruby or ruby-host' or '' local err = prog == '' and 'missing ruby or ruby-host' or ''

View File

@@ -6,7 +6,7 @@
--- Example: --- Example:
--- ---
--- ```lua --- ```lua
--- local v = vim.version.parse(vim.fn.system({'tmux', '-V'}), {strict=false}) --- local v = vim.version.parse(vim.system({'tmux', '-V'}):wait().stdout, {strict=false})
--- if vim.version.gt(v, {3, 2, 0}) then --- if vim.version.gt(v, {3, 2, 0}) then
--- -- ... --- -- ...
--- end --- end

View File

@@ -27,8 +27,9 @@ local function run(cmd, or_die)
if _trace then if _trace then
p('run: ' .. vim.inspect(cmd)) p('run: ' .. vim.inspect(cmd))
end end
local rv = vim.trim(vim.fn.system(cmd)) or '' local res = vim.system(cmd):wait()
if vim.v.shell_error ~= 0 then local rv = vim.trim(res.stdout)
if res.code ~= 0 then
if or_die then if or_die then
p(rv) p(rv)
os.exit(1) os.exit(1)