From 45fc81000dc356c2eef4547a80845d74fdadf273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tautvydas=20S=CC=8Cidlauskas?= Date: Fri, 30 Oct 2026 14:54:00 +0200 Subject: [PATCH] feat(config): support env variables in project configurations --- README.md | 3 +- lua/flutter-tools/config.lua | 1 + lua/flutter-tools/runners/debugger_runner.lua | 3 ++ lua/flutter-tools/runners/job_runner.lua | 3 ++ lua/flutter-tools/utils/config_utils.lua | 11 +++++ tests/debugger_runner_spec.lua | 24 +++++++++++ tests/job_runner_spec.lua | 40 +++++++++++++++++++ 7 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/job_runner_spec.lua diff --git a/README.md b/README.md index f0011c5..d69334b 100644 --- a/README.md +++ b/README.md @@ -407,7 +407,8 @@ require('flutter-tools').setup_project({ }, pre_run_callback = nil, -- optional callback to run before the configuration -- exposes a table containing name, target, flavor and device in the arguments - dart_define_from_file = 'config.json' -- the path to a JSON configuration file + dart_define_from_file = 'config.json', -- the path to a JSON configuration file + env = { API_KEY = 'abc' }, -- environment variables for the run process, added to Neovim's }, { name = 'Web', diff --git a/lua/flutter-tools/config.lua b/lua/flutter-tools/config.lua index 86ef260..01358bd 100644 --- a/lua/flutter-tools/config.lua +++ b/lua/flutter-tools/config.lua @@ -15,6 +15,7 @@ local utils = lazy.require("flutter-tools.utils") ---@module "flutter-tools.util ---@field web_port? string ---@field cwd? string full path of current working directory, defaults to LSP root ---@field additional_args? string[] additional arguments to pass to the flutter run command +---@field env? {[string]: string} environment variables for the run process, on top of Neovim's --- ---@class flutter.DevLogOpts ---@field filter? fun(data: string): boolean diff --git a/lua/flutter-tools/runners/debugger_runner.lua b/lua/flutter-tools/runners/debugger_runner.lua index 8cd91dd..9bba37b 100644 --- a/lua/flutter-tools/runners/debugger_runner.lua +++ b/lua/flutter-tools/runners/debugger_runner.lua @@ -6,6 +6,7 @@ local utils = lazy.require("flutter-tools.utils") ---@module "flutter-tools.util local path = lazy.require("flutter-tools.utils.path") ---@module "flutter-tools.utils.path" local vm_service_extensions = lazy.require("flutter-tools.runners.vm_service_extensions") ---@module "flutter-tools.runners.vm_service_extensions" local vm_service = lazy.require("flutter-tools.vm_service") ---@module "flutter-tools.vm_service" +local config_utils = lazy.require("flutter-tools.utils.config_utils") ---@module "flutter-tools.utils.config_utils" local success, dap = pcall(require, "dap") if not success then ui.notify(string.format("nvim-dap is not installed!\n%s", dap), ui.ERROR) @@ -394,6 +395,8 @@ function DebuggerRunner:run( launch_config.args = vim.list_extend(launch_config.args or {}, args or {}) launch_config.dartSdkPath = paths.dart_sdk launch_config.flutterSdkPath = paths.flutter_sdk + local env = config_utils.get_env(project_config) + if env then launch_config.env = vim.tbl_extend("force", launch_config.env or {}, env) end if config.debugger.evaluate_to_string_in_debug_views then launch_config.evaluateToStringInDebugViews = true end diff --git a/lua/flutter-tools/runners/job_runner.lua b/lua/flutter-tools/runners/job_runner.lua index d070c6a..cab4d7a 100644 --- a/lua/flutter-tools/runners/job_runner.lua +++ b/lua/flutter-tools/runners/job_runner.lua @@ -2,6 +2,7 @@ local Job = require("plenary.job") local ui = require("flutter-tools.ui") local dev_tools = require("flutter-tools.dev_tools") local utils = require("flutter-tools.utils") ---@module "flutter-tools.utils" +local config_utils = require("flutter-tools.utils.config_utils") ---@module "flutter-tools.utils.config_utils" ---@type flutter.Runner local JobRunner = {} @@ -46,10 +47,12 @@ function JobRunner:run( table.insert(command_args, project_config.target) end end + local env = config_utils.get_env(project_config) run_job = Job:new({ command = command, args = command_args, cwd = cwd, + env = env and vim.tbl_extend("force", vim.fn.environ(), env), on_start = function() utils.emit_event(utils.events.APP_STARTED) end, on_stdout = vim.schedule_wrap(function(_, data, _) on_run_data(false, data) diff --git a/lua/flutter-tools/utils/config_utils.lua b/lua/flutter-tools/utils/config_utils.lua index 762ca7f..ce8b61a 100644 --- a/lua/flutter-tools/utils/config_utils.lua +++ b/lua/flutter-tools/utils/config_utils.lua @@ -20,6 +20,17 @@ function M.get_cwd(project_conf) return lsp.get_project_root_dir() end +---@param project_conf flutter.ProjectConfig? +---@return {[string]: string}? +function M.get_env(project_conf) + if not project_conf or not project_conf.env then return nil end + local env = {} + for key, value in pairs(project_conf.env) do + env[key] = tostring(value) + end + return env +end + --@return table? local function parse_yaml(str) local ok, yaml = pcall(parser.parse, str) diff --git a/tests/debugger_runner_spec.lua b/tests/debugger_runner_spec.lua index bd320bb..08ceb6b 100644 --- a/tests/debugger_runner_spec.lua +++ b/tests/debugger_runner_spec.lua @@ -164,4 +164,28 @@ describe("debugger runner", function() assert.are.equal(1, started_events) assert.is_nil(exit_logs) end) + + it("passes the project configuration env to the launch configuration", function() + local debugger = require("flutter-tools.config").debugger + local run, register_configurations = dap.run, debugger.register_configurations + local launched + dap.run = function(c) launched = c end + debugger.register_configurations = function() + dap.configurations.dart = { + { + type = "dart", + request = "launch", + name = "Mine", + env = { KEEP = "1", LOG_LEVEL = "info" }, + }, + } + end + + runner:run({}, paths, {}, "/project", function() end, function() end, true, { + env = { LOG_LEVEL = "debug", RETRIES = 3 }, + }) + dap.run, debugger.register_configurations = run, register_configurations + + assert.are.same({ KEEP = "1", LOG_LEVEL = "debug", RETRIES = "3" }, launched.env) + end) end) diff --git a/tests/job_runner_spec.lua b/tests/job_runner_spec.lua new file mode 100644 index 0000000..996c443 --- /dev/null +++ b/tests/job_runner_spec.lua @@ -0,0 +1,40 @@ +describe("job runner", function() + local runner + + before_each(function() runner = require("flutter-tools.runners.job_runner") end) + + after_each(function() + runner:cleanup() + package.loaded["flutter-tools.runners.job_runner"] = nil + end) + + ---@param project_config flutter.ProjectConfig? + ---@return string[] + local function run_and_collect_output(project_config) + local output, exited = {}, false + runner:run( + {}, + { flutter_bin = "sh" }, + { "-c", 'echo "$FLUTTER_TOOLS_SPEC_VAR|$HOME"' }, + vim.uv.cwd(), + function(_, line) table.insert(output, line) end, + function() exited = true end, + true, + project_config + ) + vim.wait(5000, function() return exited end) + return output + end + + it("adds the project configuration env to the inherited environment", function() + local output = run_and_collect_output({ env = { FLUTTER_TOOLS_SPEC_VAR = "dev" } }) + + assert.are.same({ "dev|" .. vim.env.HOME }, output) + end) + + it("inherits the environment unchanged without a project configuration env", function() + local output = run_and_collect_output({}) + + assert.are.same({ "|" .. vim.env.HOME }, output) + end) +end)