Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions lua/code_runner/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ function Utils:replaceVars(command, path)
dir = vim.fn.shellescape(vim.fn.fnamemodify(path, ":p:h")),
}

-- Compiled-language commands combine these variables into one executable path.
-- Escape that complete path first; escaping each fragment separately
-- produces '"dir"/"name"', which cmd.exe treats as two tokens.
local file_without_ext = vim.fn.shellescape(vim.fn.fnamemodify(path, ":p:r"))
command = command:gsub("%$dir/%$fileNameWithoutExt", function()
return file_without_ext
end)
command = command:gsub("%$dir\\%$fileNameWithoutExt", function()
return file_without_ext
end)

command = command:gsub("%$(%w+)", function(var)
if var == "fileNameWithoutExt" then
return file_info.nameWithoutExt
Expand Down
25 changes: 25 additions & 0 deletions tests/code_runner_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,23 @@ do

contains(u:replaceVars("python $fileName", path), "'bar.py'", "$fileName expands to the escaped basename")
contains(u:replaceVars("run $fileNameWithoutExt", path), "'bar'", "$fileNameWithoutExt drops the extension")
local file_without_ext = vim.fn.shellescape(vim.fn.fnamemodify(path, ":p:r"))
eq(
u:replaceVars("run $dir/$fileNameWithoutExt", path),
"run " .. file_without_ext,
"the slash-separated executable path is escaped as one argument"
)
eq(
u:replaceVars([[run $dir\$fileNameWithoutExt]], path),
"run " .. file_without_ext,
"the backslash-separated executable path is escaped as one argument"
)
local percent_path = "/home/100% real/main.c"
eq(
u:replaceVars("run $dir/$fileNameWithoutExt", percent_path),
"run " .. vim.fn.shellescape(vim.fn.fnamemodify(percent_path, ":p:r")),
"percent signs in the executable path are preserved"
)
contains(u:replaceVars("cd $dir", path), "'/home/foo'", "$dir expands to the escaped parent dir")
contains(u:replaceVars("cat $file", path), "'/home/foo/bar.py'", "$file expands to the escaped full path")
eq(u:replaceVars("end$end here", path), "end here", "$end expands to empty string")
Expand Down Expand Up @@ -167,6 +184,14 @@ do
nil,
"function command returning a non string/table yields nil"
)

for _, filetype in ipairs({ "c", "cpp", "rust" }) do
contains(
u:getCommand(filetype, path),
file_without_ext,
"default " .. filetype .. " runner escapes the executable path as one shell argument"
)
end
end

-- ---------------------------------------------------------------------------
Expand Down