From fbb18a5b92e2f11aaaef379d74d4a1132a138cb3 Mon Sep 17 00:00:00 2001 From: Steven Arcangeli <506791+stevearc@users.noreply.github.com> Date: Fri, 15 Sep 2023 08:35:28 -0700 Subject: feat: allow running commands in a shell (#49) --- README.md | 1 + doc/conform.txt | 1 + lua/conform/init.lua | 4 ++-- lua/conform/runner.lua | 25 ++++++++++++++++--------- scripts/options_doc.lua | 1 + tests/runner_spec.lua | 43 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 3d312b8..e20dcc9 100644 --- a/README.md +++ b/README.md @@ -261,6 +261,7 @@ require("conform").setup({ command = "my_cmd", -- OPTIONAL - all fields below this are optional -- A list of strings, or a function that returns a list of strings + -- Return a single string instead to run the command in a shell args = { "--stdin-from-filename", "$FILENAME" }, -- If the formatter supports range formatting, create the range arguments here range_args = function(ctx) diff --git a/doc/conform.txt b/doc/conform.txt index e0dd9ff..1d29bdd 100644 --- a/doc/conform.txt +++ b/doc/conform.txt @@ -50,6 +50,7 @@ OPTIONS *conform-option command = "my_cmd", -- OPTIONAL - all fields below this are optional -- A list of strings, or a function that returns a list of strings + -- Return a single string instead to run the command in a shell args = { "--stdin-from-filename", "$FILENAME" }, -- If the formatter supports range formatting, create the range arguments here range_args = function(ctx) diff --git a/lua/conform/init.lua b/lua/conform/init.lua index ff30686..a19813e 100644 --- a/lua/conform/init.lua +++ b/lua/conform/init.lua @@ -9,8 +9,8 @@ local M = {} ---@class (exact) conform.FormatterConfig ---@field command string|fun(ctx: conform.Context): string ----@field args? string[]|fun(ctx: conform.Context): string[] ----@field range_args? fun(ctx: conform.RangeContext): string[] +---@field args? string|string[]|fun(ctx: conform.Context): string|string[] +---@field range_args? fun(ctx: conform.RangeContext): string|string[] ---@field cwd? fun(ctx: conform.Context): nil|string ---@field require_cwd? boolean When cwd is not found, don't run the formatter (default false) ---@field stdin? boolean Send buffer contents to stdin (default true) diff --git a/lua/conform/runner.lua b/lua/conform/runner.lua index ff8fbef..fff638b 100644 --- a/lua/conform/runner.lua +++ b/lua/conform/runner.lua @@ -48,12 +48,13 @@ end ---@param ctx conform.Context ---@param config conform.FormatterConfig +---@return string|string[] M.build_cmd = function(ctx, config) local command = config.command if type(command) == "function" then command = command(ctx) end - local cmd = { command } + ---@type string|string[] local args = {} if ctx.range and config.range_args then ---@cast ctx conform.RangeContext @@ -67,16 +68,22 @@ M.build_cmd = function(ctx, config) end end - ---@diagnostic disable-next-line: param-type-mismatch - for _, v in ipairs(args) do - if v == "$FILENAME" then - v = ctx.filename - elseif v == "$DIRNAME" then - v = ctx.dirname + if type(args) == "string" then + local interpolated = args:gsub("$FILENAME", ctx.filename):gsub("$DIRNAME", ctx.dirname) + return command .. " " .. interpolated + else + local cmd = { command } + ---@diagnostic disable-next-line: param-type-mismatch + for _, v in ipairs(args) do + if v == "$FILENAME" then + v = ctx.filename + elseif v == "$DIRNAME" then + v = ctx.dirname + end + table.insert(cmd, v) end - table.insert(cmd, v) + return cmd end - return cmd end ---@param range? conform.Range diff --git a/scripts/options_doc.lua b/scripts/options_doc.lua index 9073369..af7b10c 100644 --- a/scripts/options_doc.lua +++ b/scripts/options_doc.lua @@ -36,6 +36,7 @@ require("conform").setup({ command = "my_cmd", -- OPTIONAL - all fields below this are optional -- A list of strings, or a function that returns a list of strings + -- Return a single string instead to run the command in a shell args = { "--stdin-from-filename", "$FILENAME" }, -- If the formatter supports range formatting, create the range arguments here range_args = function(ctx) diff --git a/tests/runner_spec.lua b/tests/runner_spec.lua index 10ea075..56cf8e2 100644 --- a/tests/runner_spec.lua +++ b/tests/runner_spec.lua @@ -102,6 +102,49 @@ describe("runner", function() local cmd = runner.build_cmd(ctx, config) assert.are.same({ "echo", "--stdin" }, cmd) end) + + it("replaces $FILENAME in string args", function() + vim.cmd.edit({ args = { "README.md" } }) + local bufnr = vim.api.nvim_get_current_buf() + conform.formatters.test = { + meta = { url = "", description = "" }, + command = "echo", + args = "$FILENAME | patch", + } + local config = assert(conform.get_formatter_config("test")) + local ctx = runner.build_context(0, config) + local cmd = runner.build_cmd(ctx, config) + assert.equal("echo " .. vim.api.nvim_buf_get_name(bufnr) .. " | patch", cmd) + end) + + it("replaces $DIRNAME in string args", function() + vim.cmd.edit({ args = { "README.md" } }) + local bufnr = vim.api.nvim_get_current_buf() + conform.formatters.test = { + meta = { url = "", description = "" }, + command = "echo", + args = "$DIRNAME | patch", + } + local config = assert(conform.get_formatter_config("test")) + local ctx = runner.build_context(0, config) + local cmd = runner.build_cmd(ctx, config) + assert.equal("echo " .. vim.fs.dirname(vim.api.nvim_buf_get_name(bufnr)) .. " | patch", cmd) + end) + + it("resolves arg function with string results", function() + vim.cmd.edit({ args = { "README.md" } }) + conform.formatters.test = { + meta = { url = "", description = "" }, + command = "echo", + args = function() + return "| patch" + end, + } + local config = assert(conform.get_formatter_config("test")) + local ctx = runner.build_context(0, config) + local cmd = runner.build_cmd(ctx, config) + assert.equal("echo | patch", cmd) + end) end) describe("e2e", function() -- cgit v1.2.3-70-g09d2