Skip to content

Commit

Permalink
fixup! fix: tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mfussenegger committed Aug 9, 2024
1 parent 0a22899 commit 10db2b1
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 58 deletions.
78 changes: 28 additions & 50 deletions lua/dap/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -302,64 +302,42 @@ function M.pick_file(opts)
end


--- Split args string into a table of arguments.
--- Works with single and double quoted strings. Escaped quotes are supported.
--- Split an argument string on whitespace characters into a list,
--- except if the whitespace is contained within single or double quotes.
---
--- <pre>
--- require("dap.utils").split_args("runserver --debug true --reason 'I\'m dumb'")
--- {runserver, --debug, true, I'm dumb}
--- </pre>
--- Quotes can be escaped to preserve them.
---
--- <pre>
--- require("dap.utils").split_args('--comment "I\'m \"this\" close"')
--- {--comment, I'm "this" close}
--- </pre>
--- Examples:
---
--- ```lua
--- require("dap.utils").split_args("hello world")
--- {"hello", "world"}
--- ```
---
--- ```lua
--- require("dap.utils").split_args('a "quoted string" is preserved')
--- {"a", "quoted string", "is, "preserved"}
--- ```
---
--- Inspired by http://lua-users.org/wiki/LpegRecipes
--- @param args string
--- @return table
--- @return string[]
function M.split_args(args)
local lpeg = vim.lpeg

local P, S, C, Cc, Ct = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Ct

--- @param id string
--- @param patt vim.lpeg.Capture
--- @return vim.lpeg.Pattern
local function token(id, patt)
return Ct(Cc(id) * C(patt))
end

local single_quoted = P("'") * ((1 - S("'\r\n\f\\")) + (P("\\") * 1)) ^ 0 * "'"
local double_quoted = P('"') * ((1 - S('"\r\n\f\\')) + (P("\\") * 1)) ^ 0 * '"'

local whitespace = token("whitespace", S("\r\n\f\t ") ^ 1)
local word = token("word", (1 - S("' \r\n\f\t\"")) ^ 1)
local string = token("string", single_quoted + double_quoted)

local pattern = Ct((string + whitespace + word) ^ 0)

local t = {}
local tokens = lpeg.match(pattern, args)

-- somehow, this did not work out
if tokens == nil or type(tokens) == "integer" then
return t
end

for _, tok in ipairs(tokens) do
if tok[1] ~= "whitespace" then
if tok[1] == "string" then
-- cut off quotes and replace escaped quotes
local v, _ = tok[2]:sub(2, -2):gsub("\\(['\"])", "%1")
table.insert(t, v)
else
table.insert(t, tok[2])
end
end
local P, S, C = lpeg.P, lpeg.S, lpeg.C

---@param quotestr string
---@return vim.lpeg.Pattern
local function qtext(quotestr)
local quote = P(quotestr)
local escaped_quote = P('\\') * quote
return quote * C(((1 - P(quote)) + escaped_quote) ^ 0) * quote
end

return t
local space = S(" \t\n\r") ^ 1
local unquoted = C((1 - space) ^ 0)
local element = qtext('"') + qtext("'") + unquoted
local p = lpeg.Ct(element * (space * element) ^ 0)
return lpeg.match(p, args)
end


Expand Down
35 changes: 27 additions & 8 deletions spec/utils_spec.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
if os.getenv("LOCAL_LUA_DEBUGGER_VSCODE") == "1" then
require("lldebugger").start()
end
local utils = require('dap.utils')

describe('utils.index_of', function()
Expand Down Expand Up @@ -91,19 +94,35 @@ describe('utils.fmt_error', function ()
end)

describe('utils.split_args', function ()
it('works with standard string', function ()
assert.are.same({'this', 'is', 'a', 'standard', 'string'}, require('dap.utils').split_args('this is a standard string'))
it('works with plain string', function ()
assert.are.same({"hello", "world"}, utils.split_args("hello world"))
end)

it('with "double quoted" string', function ()
assert.are.same({'with', 'double quoted', 'string'}, require('dap.utils').split_args('with "double quoted" string'))
it('works extra whitespace', function ()
assert.are.same({"hello", "world"}, utils.split_args('hello world'))
end)

it("with 'single quoted' string", function ()
assert.are.same({'with', 'single quoted', 'string'}, require('dap.utils').split_args("with 'single quoted' string"))
it('empty quoted', function ()
assert.are.same({"hello", "", "world"}, utils.split_args('hello "" world'))
end)

it('"double \"escaped\" quoted" string', function ()
assert.are.same({'double "escaped" quoted', 'string'}, require('dap.utils').split_args('"double \"escaped\" quoted" string'))
it('with double quoted string', function ()
assert.are.same({'with', 'double quoted', 'string'}, utils.split_args('with "double quoted" string'))
end)

it("with single quoted string", function ()
assert.are.same({'with', 'single quoted', 'string'}, utils.split_args("with 'single quoted' string"))
end)

it("with unbalanced quote", function ()
assert.are.same({"with", "\"single", "quoted", "string"}, utils.split_args("with \"single quoted string"))
end)

it("with unbalanced single quoted string", function ()
assert.are.same({"with", "'single", "quoted", "string"}, utils.split_args("with 'single quoted string"))
end)

it('escaped quote', function ()
assert.are.same({'foo', '"bar'}, utils.split_args('foo \"bar'))
end)
end)

0 comments on commit 10db2b1

Please sign in to comment.