diff --git a/lua/jj/cmd/init.lua b/lua/jj/cmd/init.lua index 48b19b0..1f89d39 100644 --- a/lua/jj/cmd/init.lua +++ b/lua/jj/cmd/init.lua @@ -1326,13 +1326,13 @@ function M.j(args) local cmd = nil if #args == 0 then local default_cmd_str, success = runner.execute( - { "jj", "config", "list", "ui.default-command" }, + { "jj", "config", "list", "ui.default-command", "-T", 'json(value) ++ "\\n"' }, "Error getting user's default command", nil, true ) if success then - cmd = parser.parse_default_cmd(default_cmd_str or "") + cmd = parser.parse_json_command(default_cmd_str or "") end -- jj's built-in default command is "log" if cmd == nil then diff --git a/lua/jj/core/parser.lua b/lua/jj/core/parser.lua index e6cd3dd..3692c5c 100644 --- a/lua/jj/core/parser.lua +++ b/lua/jj/core/parser.lua @@ -1,33 +1,47 @@ --- @class jj.core.parser local M = {} ---- Parse the default command from jj config +--- Checks if the given value is a list of strings. +local function is_string_list(value) + if type(value) ~= "table" then + return false + end + for _, item in ipairs(value) do + if type(item) ~= "string" then + return false + end + end + return true +end + +--- Parses and converts the given JSON command output into an array of command arguments. +--- the command can either be a single string or an array of strings. If the output is empty or invalid, returns nil. --- @param cmd_output string The output from `jj config get ui.default-command` --- @return table|nil args Array of command arguments, or nil if parsing fails -function M.parse_default_cmd(cmd_output) +function M.parse_json_command(cmd_output) if not cmd_output or cmd_output == "" then return nil end - -- Remove whitespace and strip "key = " prefix from `jj config list` output + -- Remove whitespace local trimmed_cmd = vim.trim(cmd_output) - trimmed_cmd = trimmed_cmd:gsub("^[%w._-]+ = ", "") + if trimmed_cmd == "" then + return nil + end - -- Try to parse as TOML array: ["item1", "item2", ...] - -- Pattern "%[(.*)%]" captures everything between square brackets - local array_items = trimmed_cmd:match("%[(.*)%]") - if array_items then - local args = {} - -- Pattern '"([^"]+)"' captures content between double quotes (non-greedy) - for item in array_items:gmatch('"([^"]+)"') do - table.insert(args, item) + if trimmed_cmd:match("^Warning:%s+No matching config key") then + return nil + end + + local ok, decoded = pcall(vim.json.decode, trimmed_cmd) + if ok then + if type(decoded) == "string" then + return decoded ~= "" and { decoded } or nil end - return #args > 0 and args or nil - else - -- Single string value, remove surrounding quotes if present - -- Pattern '^"?(.-)"?$' optionally matches quotes at start/end, captures content - local single_value = trimmed_cmd:match('^"?(.-)"?$') - return single_value and { single_value } or nil + if is_string_list(decoded) then + return #decoded > 0 and decoded or nil + end + return nil end end diff --git a/tests/run_tests.lua b/tests/run_tests.lua index ff9069a..03b4cd3 100755 --- a/tests/run_tests.lua +++ b/tests/run_tests.lua @@ -436,35 +436,35 @@ print("\n=== Running parse_default_cmd tests ===\n") run_test("parse_default_cmd: parses config list array output", function() local output = 'ui.default-command = ["log", "--no-pager", "--limit", "18"]' - assert_table_equals({ "log", "--no-pager", "--limit", "18" }, parser.parse_default_cmd(output)) + assert_table_equals({ "log", "--no-pager", "--limit", "18" }, parser.parse_json_command(output)) end) run_test("parse_default_cmd: parses config list single string output", function() local output = 'ui.default-command = "log"' - assert_table_equals({ "log" }, parser.parse_default_cmd(output)) + assert_table_equals({ "log" }, parser.parse_json_command(output)) end) run_test("parse_default_cmd: parses bare array (config get format)", function() local output = '["log", "--limit", "10"]' - assert_table_equals({ "log", "--limit", "10" }, parser.parse_default_cmd(output)) + assert_table_equals({ "log", "--limit", "10" }, parser.parse_json_command(output)) end) run_test("parse_default_cmd: parses bare string (config get format)", function() local output = '"log"' - assert_table_equals({ "log" }, parser.parse_default_cmd(output)) + assert_table_equals({ "log" }, parser.parse_json_command(output)) end) run_test("parse_default_cmd: parses unquoted string", function() local output = "log" - assert_table_equals({ "log" }, parser.parse_default_cmd(output)) + assert_table_equals({ "log" }, parser.parse_json_command(output)) end) run_test("parse_default_cmd: returns nil for empty string", function() - assert_is_nil(parser.parse_default_cmd("")) + assert_is_nil(parser.parse_json_command("")) end) run_test("parse_default_cmd: returns nil for nil", function() - assert_is_nil(parser.parse_default_cmd(nil)) + assert_is_nil(parser.parse_json_command(nil)) end) print("\n=== Running parse_push_args tests ===\n")