From 51f506372f0fa27ade84cd747f498894e490eeff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tautvydas=20S=CC=8Cidlauskas?= Date: Sun, 27 Sep 2026 21:55:31 +0300 Subject: [PATCH] feat(devices): show progress while listing devices and allow extra args - FlutterDevices and FlutterEmulators report native progress (Neovim 0.12+), which terminals supporting OSC 9;4 show as a progress bar - devices.args passes extra arguments to flutter devices, e.g. --device-connection attached to skip the slow wireless scan Refs #334 --- README.md | 7 ++++++ lua/flutter-tools/config.lua | 7 ++++++ lua/flutter-tools/devices.lua | 44 ++++++++++++++++++++++++++++------- tests/devices_spec.lua | 17 +++++++++++++- 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fc3ad95..58bedb4 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,8 @@ require("flutter-tools").setup {} -- use defaults - `FlutterRun` - Run the current project. Respects `config.debugger.enabled` setting. - `FlutterDebug` - Force run current project in debug mode. - `FlutterDevices` - Brings up a list of connected devices to select from. + Set `devices.args` to pass extra arguments to `flutter devices`, e.g. `{ "--device-connection", "attached" }` + to skip the slow wireless device scan. - `FlutterEmulators` - Similar to devices but shows a list of emulators to choose from. Set `emulators.launcher` to start the selected emulator with your own command instead of `flutter emulator --launch`, see the [full configuration](#full-configuration). @@ -288,6 +290,11 @@ require("flutter-tools").setup { widget_preview = { web_server = true, -- open the widget previewer with vim.ui.open; false lets Flutter launch its own Chrome }, + devices = { + -- extra arguments for `flutter devices` in `FlutterDevices`, e.g. { "--device-connection", "attached" } + -- skips the slow wireless device scan (mostly iOS on macOS) if you never deploy wirelessly + args = {}, + }, emulators = { -- optional function to launch the emulator picked in `FlutterEmulators` with your own command, -- e.g. the Android SDK `emulator` binary with extra flags; return nil to use `flutter emulator --launch` diff --git a/lua/flutter-tools/config.lua b/lua/flutter-tools/config.lua index fc1a289..43976b9 100644 --- a/lua/flutter-tools/config.lua +++ b/lua/flutter-tools/config.lua @@ -34,6 +34,9 @@ local utils = lazy.require("flutter-tools.utils") ---@module "flutter-tools.util ---@class flutter.EmulatorsOpts ---@field launcher? fun(emulator: Device, paths: flutter.Paths): flutter.EmulatorLaunchSpec? --- +---@class flutter.DevicesOpts +---@field args? string[] extra arguments passed to `flutter devices` +--- ---@class flutter.Config ---@field flutter_path? string Path to the Flutter SDK ---@field flutter_lookup_cmd? string Command to find Flutter SDK @@ -51,6 +54,7 @@ local utils = lazy.require("flutter-tools.utils") ---@module "flutter-tools.util ---@field dev_log? flutter.DevLogOpts ---@field dev_tools? {autostart: boolean, auto_open_browser: boolean} ---@field widget_preview? {web_server: boolean} +---@field devices? flutter.DevicesOpts ---@field emulators? flutter.EmulatorsOpts ---@field analyzer_web_port? number @@ -164,6 +168,9 @@ local config = { widget_preview = { web_server = true, }, + devices = { + args = {}, + }, emulators = { launcher = nil, }, diff --git a/lua/flutter-tools/devices.lua b/lua/flutter-tools/devices.lua index 91fdc21..e2a33c8 100644 --- a/lua/flutter-tools/devices.lua +++ b/lua/flutter-tools/devices.lua @@ -6,6 +6,7 @@ local commands = lazy.require("flutter-tools.commands") ---@module "flutter-tool local executable = lazy.require("flutter-tools.executable") ---@module "flutter-tools.executable" local config = lazy.require("flutter-tools.config") ---@module "flutter-tools.config" local fmt = string.format +local api = vim.api ---@alias Device {name: string, id: string, platform: string, system: string, type: integer, cold_boot: boolean} @@ -171,6 +172,24 @@ function M.get_default_device(project_root, callback) end) end +---@param title string +---@return fun(status: "success"|"failed") +local function start_progress(title) + if vim.fn.has("nvim-0.12") == 0 then + return function() end + end + local opts = { kind = "progress", source = "flutter-tools", title = title, status = "running" } + local id = api.nvim_echo({ { "Loading" } }, false, opts) + return function(status) + local message = status == "success" and "Done" or "Failed" + api.nvim_echo( + { { message } }, + false, + vim.tbl_extend("force", opts, { id = id, status = status }) + ) + end +end + -----------------------------------------------------------------------------// -- Emulators -----------------------------------------------------------------------------// @@ -230,13 +249,16 @@ end function M.list_emulators() executable.flutter(function(cmd) + local finish = start_progress("Flutter emulators") local job = Job:new({ command = cmd, args = { "emulators" } }) - job:after_success(vim.schedule_wrap(function(j) show_emulators(j:result()) end)) - job:after_failure( - vim.schedule_wrap( - function(j) return ui.notify(utils.join(j:stderr_result()), ui.ERROR, { timeout = 5000 }) end - ) - ) + job:after_success(vim.schedule_wrap(function(j) + finish("success") + show_emulators(j:result()) + end)) + job:after_failure(vim.schedule_wrap(function(j) + finish("failed") + ui.notify(utils.join(j:stderr_result()), ui.ERROR, { timeout = 5000 }) + end)) job:start() end) end @@ -258,9 +280,15 @@ end function M.list_devices() executable.flutter(function(cmd) - local job = Job:new({ command = cmd, args = { "devices" } }) - job:after_success(vim.schedule_wrap(show_devices)) + local finish = start_progress("Flutter devices") + local args = vim.list_extend({ "devices" }, config.devices.args or {}) + local job = Job:new({ command = cmd, args = args }) + job:after_success(vim.schedule_wrap(function(j) + finish("success") + show_devices(j) + end)) job:after_failure(vim.schedule_wrap(function(j) + finish("failed") local result = j:result() local message = not vim.tbl_isempty(result) and result or j:stderr_result() ui.notify(utils.join(message), ui.ERROR) diff --git a/tests/devices_spec.lua b/tests/devices_spec.lua index 73e15ce..1a999b2 100644 --- a/tests/devices_spec.lua +++ b/tests/devices_spec.lua @@ -145,7 +145,7 @@ INFO | Storing crashdata in: /tmp/android-ts/emu-crash-34.2.14.db, detection end) end) - describe("emulator launch - ", function() + describe("flutter jobs - ", function() local devices local config local jobs @@ -192,6 +192,7 @@ INFO | Storing crashdata in: /tmp/android-ts/emu-crash-34.2.14.db, detection } package.loaded["flutter-tools.executable"] = { get = function(callback) callback(paths) end, + flutter = function(callback) callback(paths.flutter_bin) end, } config = require("flutter-tools.config") devices = require("flutter-tools.devices") @@ -269,5 +270,19 @@ INFO | Storing crashdata in: /tmp/android-ts/emu-crash-34.2.14.db, detection assert.equal("/sdk/bin/flutter", jobs[1].opts.command) assert.same({ "emulator", "--launch", "Pixel_8" }, jobs[1].opts.args) end) + + it("should list devices with only the devices subcommand by default", function() + devices.list_devices() + + assert.same({ "devices" }, jobs[1].opts.args) + end) + + it("should pass configured arguments to flutter devices", function() + config.set({ devices = { args = { "--device-connection", "attached" } } }) + + devices.list_devices() + + assert.same({ "devices", "--device-connection", "attached" }, jobs[1].opts.args) + end) end) end)