From 4486dd27cfae345bfbf35f9be71fe3cebb3994e3 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Singh Date: Mon, 11 May 2026 17:56:29 +0530 Subject: [PATCH 1/8] Extracted out telescope picker from the core platformio code --- lua/platformio/pickers/init.lua | 49 ++++++++ lua/platformio/pickers/telescope.lua | 179 +++++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 lua/platformio/pickers/init.lua create mode 100644 lua/platformio/pickers/telescope.lua diff --git a/lua/platformio/pickers/init.lua b/lua/platformio/pickers/init.lua new file mode 100644 index 0000000..332e4e5 --- /dev/null +++ b/lua/platformio/pickers/init.lua @@ -0,0 +1,49 @@ +local M = {} + +local config = require('platformio').config + +local function load_backend(name) + local ok, backend = pcall(require, 'platformio.pickers.' .. name) + if ok then + return backend + end + return nil +end + +local function get_backend() + local backend_name = config.picker_backend or 'auto' + + if backend_name == 'telescope' then + return load_backend('telescope') or load_backend('ui_select') + end + return load_backend('telescope') or load_backend('ui_select') +end + +function M.pick_board(boards, on_select) + local backend = get_backend() + if not backend then + vim.notify('No picker backend available for PlatformIO.', vim.log.levels.ERROR) + return + end + backend.pick_board(boards, on_select) +end + +function M.pick_framework(frameworks, on_select) + local backend = get_backend() + if not backend then + vim.notify('No picker backend available for PlatformIO.', vim.log.levels.ERROR) + return + end + backend.pick_framework(frameworks, on_select) +end + +function M.pick_library(libraries, on_select) + local backend = get_backend() + if not backend then + vim.notify('No picker backend available for PlatformIO.', vim.log.levels.ERROR) + return + end + backend.pick_library(libraries, on_select) +end + +return M diff --git a/lua/platformio/pickers/telescope.lua b/lua/platformio/pickers/telescope.lua new file mode 100644 index 0000000..549df35 --- /dev/null +++ b/lua/platformio/pickers/telescope.lua @@ -0,0 +1,179 @@ +local M = {} + +local pickers = require('telescope.pickers') +local finders = require('telescope.finders') +local telescope_conf = require('telescope.config').values +local actions = require('telescope.actions') +local action_state = require('telescope.actions.state') +local entry_display = require('telescope.pickers.entry_display') +local make_entry = require('telescope.make_entry') +local previewers = require('telescope.previewers') +local utils = require('platformio.utils') + +local function boardentry_maker(opts) + local displayer = entry_display.create({ + separator = '▏', + items = { + { width = 35 }, + { width = 20 }, + { width = 15 }, + }, + }) + + local make_display = function(entry) + return displayer({ + entry.value.name, + entry.value.vendor, + entry.value.platform, + }) + end + + return function(entry) + return make_entry.set_default_entry_mt({ + value = { + id = entry.id, + name = entry.name, + vendor = entry.vendor, + platform = entry.platform, + data = entry, + }, + ordinal = entry.name .. ' ' .. entry.vendor .. ' ' .. entry.platform, + display = make_display, + }, opts) + end +end + +local function libentry_maker(opts) + local displayer = entry_display.create({ + separator = '▏', + items = { + { width = 20 }, + { width = 20 }, + { remaining = true }, + }, + }) + + local make_display = function(entry) + return displayer({ + entry.value.name, + entry.value.owner, + entry.value.description, + }) + end + + return function(entry) + return make_entry.set_default_entry_mt({ + value = { + name = entry.name, + owner = entry.owner and entry.owner.username or '', + description = entry.description, + data = entry, + }, + ordinal = (entry.name or '') .. ' ' .. (entry.owner and entry.owner.username or '') .. ' ' .. (entry.description or ''), + display = make_display, + }, opts) + end +end + +function M.pick_framework(frameworks, on_select) + local opts = {} + pickers + .new(opts, { + prompt_title = 'frameworks', + finder = finders.new_table({ + results = frameworks, + }), + attach_mappings = function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + if selection then + on_select(selection[1] or selection.value) + end + end) + return true + end, + sorter = telescope_conf.generic_sorter(opts), + }) + :find() +end + +function M.pick_board(boards, on_select) + local opts = {} + pickers + .new(opts, { + prompt_title = 'Boards', + finder = finders.new_table({ + results = boards, + entry_maker = opts.entry_maker or boardentry_maker(opts), + }), + attach_mappings = function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + if selection and selection.value then + on_select(selection.value.data) + end + end) + return true + end, + previewer = previewers.new_buffer_previewer({ + title = 'Board Info', + define_preview = function(self, entry, _) + local json = utils.strsplit(vim.inspect(entry.value.data), '\n') + local bufnr = self.state.bufnr + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, json) + vim.api.nvim_set_option_value('filetype', 'lua', { buf = bufnr }) + vim.defer_fn(function() + local win = self.state.winid + vim.api.nvim_set_option_value('wrap', true, { scope = 'local', win = win }) + vim.api.nvim_set_option_value('linebreak', true, { scope = 'local', win = win }) + vim.api.nvim_set_option_value('wrapmargin', 2, { buf = bufnr }) + end, 0) + end, + }), + sorter = telescope_conf.generic_sorter(opts), + }) + :find() +end + +function M.pick_library(libraries, on_select) + local opts = {} + pickers + .new(opts, { + prompt_title = 'Libraries', + finder = finders.new_table({ + results = libraries, + entry_maker = opts.entry_maker or libentry_maker(opts), + }), + attach_mappings = function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + if selection and selection.value then + on_select(selection.value.data) + end + end) + return true + end, + previewer = previewers.new_buffer_previewer({ + title = 'Package Info', + define_preview = function(self, entry, _) + local json = utils.strsplit(vim.inspect(entry.value.data), '\n') + local bufnr = self.state.bufnr + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, json) + vim.api.nvim_set_option_value('filetype', 'lua', { buf = bufnr }) + vim.defer_fn(function() + local win = self.state.winid + vim.api.nvim_set_option_value('wrap', true, { scope = 'local', win = win }) + vim.api.nvim_set_option_value('linebreak', true, { scope = 'local', win = win }) + vim.api.nvim_set_option_value('wrapmargin', 2, { buf = bufnr }) + end, 0) + end, + }), + sorter = telescope_conf.generic_sorter(opts), + }) + :find() +end + +return M From 322e21a0aa824e7fb5453798c3afdaa55f2299c7 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Singh Date: Mon, 11 May 2026 18:01:04 +0530 Subject: [PATCH 2/8] Base UI selector which uses neovim builtins --- lua/platformio/pickers/init.lua | 5 ++++ lua/platformio/pickers/ui_select.lua | 45 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 lua/platformio/pickers/ui_select.lua diff --git a/lua/platformio/pickers/init.lua b/lua/platformio/pickers/init.lua index 332e4e5..3de19e6 100644 --- a/lua/platformio/pickers/init.lua +++ b/lua/platformio/pickers/init.lua @@ -16,6 +16,11 @@ local function get_backend() if backend_name == 'telescope' then return load_backend('telescope') or load_backend('ui_select') end + + if backend_name == 'ui_select' then + return load_backend('ui_select') + end + return load_backend('telescope') or load_backend('ui_select') end diff --git a/lua/platformio/pickers/ui_select.lua b/lua/platformio/pickers/ui_select.lua new file mode 100644 index 0000000..12ca9bb --- /dev/null +++ b/lua/platformio/pickers/ui_select.lua @@ -0,0 +1,45 @@ +local M = {} + +local function board_label(board) + return string.format('%s | %s | %s', board.name or '', board.vendor or '', board.platform or '') +end + +function M.pick_framework(frameworks, on_select) + vim.ui.select(frameworks, { + prompt = 'Select framework:', + format_item = function(item) + return item + end, + }, function(chosen) + if chosen then + on_select(chosen) + end + end) +end + +function M.pick_board(boards, on_select) + vim.ui.select(boards, { + prompt = 'Select board:', + format_item = board_label, + }, function(chosen) + if chosen then + on_select(chosen) + end + end) +end + +function M.pick_library(libraries, on_select) + vim.ui.select(libraries, { + prompt = 'Select library:', + format_item = function(item) + local owner = (item.owner and item.owner.username) or '' + return string.format('%s | %s | %s', item.name or '', owner, item.description or '') + end, + }, function(chosen) + if chosen then + on_select(chosen) + end + end) +end + +return M From 053ac0aedfbf1a977a89e09198bc8d67f10f44da Mon Sep 17 00:00:00 2001 From: Anurag Kumar Singh Date: Mon, 11 May 2026 18:01:35 +0530 Subject: [PATCH 3/8] Config options to pick the picker backend --- lua/platformio/init.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lua/platformio/init.lua b/lua/platformio/init.lua index e1307d5..9251896 100644 --- a/lua/platformio/init.lua +++ b/lua/platformio/init.lua @@ -5,6 +5,7 @@ M.config = { menu_name = 'PlatformIO', debug = false, clangd_source = 'ccls', + picker_backend = 'auto', menu_bindings = { { node = 'item', desc = '[L]ist terminals', shortcut = 'l', command = 'PioTermList' }, @@ -160,6 +161,7 @@ function M.setup(user_config) menu_bindings = true, debug = true, clangd_source = true, + picker_backend = true, } local err = false for key, value in pairs(user_config or {}) do @@ -187,6 +189,14 @@ function M.setup(user_config) user_config.clangd_source = M.config.clangd_source end end + if user_config.picker_backend and user_config.picker_backend ~= 'auto' and user_config.picker_backend ~= 'telescope' and user_config.picker_backend ~= 'ui_select' then + vim.api.nvim_echo( + { { 'Invalid picker backend {allowed "auto", "telescope" or "ui_select"} (default "' .. M.config.picker_backend .. '" will be used)', 'ErrorMsg' } }, + true, + {} + ) + user_config.picker_backend = M.config.picker_backend + end if not err then -- if no error, merge user_config to M.config if user_config.menu_bindings then From 2187a730d233f697f14a3a3331736eee3cc44a72 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Singh Date: Mon, 11 May 2026 18:02:18 +0530 Subject: [PATCH 4/8] Modified pioinit to be UI agnostic and use the standered picker api --- lua/platformio/pioinit.lua | 121 ++++++------------------------------- 1 file changed, 19 insertions(+), 102 deletions(-) diff --git a/lua/platformio/pioinit.lua b/lua/platformio/pioinit.lua index f00ecf6..6cee0d3 100644 --- a/lua/platformio/pioinit.lua +++ b/lua/platformio/pioinit.lua @@ -1,115 +1,32 @@ local M = {} -local pickers = require('telescope.pickers') -local finders = require('telescope.finders') -local telescope_conf = require('telescope.config').values -local actions = require('telescope.actions') -local action_state = require('telescope.actions.state') -local entry_display = require('telescope.pickers.entry_display') -local make_entry = require('telescope.make_entry') local utils = require('platformio.utils') -local previewers = require('telescope.previewers') -local config = require('platformio').config +local picker = require('platformio.pickers') local boilerplate_gen = require('platformio.boilerplate').boilerplate_gen -local boardentry_maker = function(opts) - local displayer = entry_display.create({ - separator = '▏', - items = { - { width = 35 }, - { width = 20 }, - { width = 15 }, - }, - }) - - local make_display = function(entry) - return displayer({ - entry.value.name, - entry.value.vendor, - entry.value.platform, - }) - end - - return function(entry) - return make_entry.set_default_entry_mt({ - value = { - id = entry.id, - name = entry.name, - vendor = entry.vendor, - platform = entry.platform, - data = entry, - }, - ordinal = entry.name .. ' ' .. entry.vendor .. ' ' .. entry.platform, - display = make_display, - }, opts) +local function init_project(board_details, selected_framework) + local framework = selected_framework + if framework == 'none' then + framework = '' end + local command = 'pio project init --board ' .. board_details.id .. ' --project-option "framework=' .. framework .. '"' + utils.ToggleTerminal(command, 'float', function() + vim.cmd(':PioLSP') + boilerplate_gen(framework) + end) end local function pick_framework(board_details) - local opts = {} - pickers - .new(opts, { - prompt_title = 'frameworks', - finder = finders.new_table({ - results = vim.list_extend({ 'none' }, board_details['frameworks']), - }), - attach_mappings = function(prompt_bufnr, _) - actions.select_default:replace(function() - actions.close(prompt_bufnr) - local selection = action_state.get_selected_entry() - local selected_framework = selection[1] - if selected_framework == 'none' then - selected_framework = '' - end - local command = 'pio project init --board ' .. board_details['id'] .. ' --project-option "framework=' .. selected_framework .. '"' - -- .. utils.extra - utils.ToggleTerminal(command, 'float', function() - vim.cmd(':PioLSP') - boilerplate_gen(selected_framework) - end) - end) - return true - end, - sorter = telescope_conf.generic_sorter(opts), - }) - :find() + local framework_list = vim.list_extend({ 'none' }, board_details.frameworks or {}) + picker.pick_framework(framework_list, function(selected_framework) + init_project(board_details, selected_framework) + end) end -local function pick_board(json_data) - local opts = {} - pickers - .new(opts, { - prompt_title = 'Boards', - finder = finders.new_table({ - results = json_data, - entry_maker = opts.entry_maker or boardentry_maker(opts), - }), - attach_mappings = function(prompt_bufnr, _) - actions.select_default:replace(function() - actions.close(prompt_bufnr) - local selection = action_state.get_selected_entry() - pick_framework(selection['value']['data']) - end) - return true - end, - previewer = previewers.new_buffer_previewer({ - title = 'Board Info', - define_preview = function(self, entry, _) - local json = utils.strsplit(vim.inspect(entry['value']['data']), '\n') - local bufnr = self.state.bufnr - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, json) - vim.api.nvim_set_option_value('filetype', 'lua', { buf = bufnr }) --fix deprecated function - vim.defer_fn(function() - local win = self.state.winid - vim.api.nvim_set_option_value('wrap', true, { scope = 'local', win = win }) - vim.api.nvim_set_option_value('linebreak', true, { scope = 'local', win = win }) - vim.api.nvim_set_option_value('wrapmargin', 2, { buf = bufnr }) - end, 0) - end, - }), - sorter = telescope_conf.generic_sorter(opts), - }) - :find() +local function pick_board(boards) + picker.pick_board(boards, function(selected_board) + pick_framework(selected_board) + end) end function M.pioinit() @@ -140,7 +57,7 @@ function M.pioinit() end local json_data = vim.json.decode(json_str) - pick_board(json_data) + pick_board(json_data or {}) end return M From a5feddd0693533e4f6f48fa859173820681137c9 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Singh Date: Mon, 11 May 2026 18:02:55 +0530 Subject: [PATCH 5/8] Modified piolib to be UI agnostic and use the standered picker api --- lua/platformio/piolib.lua | 100 ++++++-------------------------------- 1 file changed, 14 insertions(+), 86 deletions(-) diff --git a/lua/platformio/piolib.lua b/lua/platformio/piolib.lua index 98b7e51..ee025d4 100644 --- a/lua/platformio/piolib.lua +++ b/lua/platformio/piolib.lua @@ -1,91 +1,8 @@ local M = {} -local config = require('platformio').config local curl = require('plenary.curl') - -local pickers = require('telescope.pickers') -local finders = require('telescope.finders') -local entry_display = require('telescope.pickers.entry_display') -local make_entry = require('telescope.make_entry') -local conf = require('telescope.config').values -local actions = require('telescope.actions') -local action_state = require('telescope.actions.state') local utils = require('platformio.utils') -local previewers = require('telescope.previewers') - -local libentry_maker = function(opts) - local displayer = entry_display.create({ - separator = '▏', - items = { - { width = 20 }, - { width = 20 }, - { remaining = true }, - }, - }) - - local make_display = function(entry) - return displayer({ - entry.value.name, - entry.value.owner, - entry.value.description, - }) - end - - return function(entry) - return make_entry.set_default_entry_mt({ - value = { - name = entry.name, - owner = entry.owner.username, - description = entry.description, - data = entry, - }, - ordinal = entry.name .. ' ' .. entry.owner.username .. ' ' .. entry.description, - display = make_display, - }, opts) - end -end - -local function pick_library(json_data) - local opts = {} - pickers - .new(opts, { - prompt_title = 'Libraries', - finder = finders.new_table({ - results = json_data['items'], - entry_maker = opts.entry_maker or libentry_maker(opts), - }), - attach_mappings = function(prompt_bufnr, _) - actions.select_default:replace(function() - actions.close(prompt_bufnr) - local selection = action_state.get_selected_entry() - local pkg_name = selection['value']['owner'] .. '/' .. selection['value']['name'] - local command = 'pio pkg install --library "' .. pkg_name .. '"' - utils.ToggleTerminal(command, 'float', function() - vim.cmd(':PioLSP') - end) - end) - return true - end, - - previewer = previewers.new_buffer_previewer({ - title = 'Package Info', - define_preview = function(self, entry, _) - local json = utils.strsplit(vim.inspect(entry['value']['data']), '\n') - local bufnr = self.state.bufnr - vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, json) - vim.api.nvim_set_option_value('filetype', 'lua', { buf = bufnr }) --fix deprecated function - vim.defer_fn(function() - local win = self.state.winid - vim.api.nvim_set_option_value('wrap', true, { scope = 'local', win = win }) - vim.api.nvim_set_option_value('linebreak', true, { scope = 'local', win = win }) - vim.api.nvim_set_option_value('wrapmargin', 2, { buf = bufnr }) - end, 0) - end, - }), - sorter = conf.generic_sorter(opts), - }) - :find() -end +local picker = require('platformio.pickers') function M.piolib(lib_arg_list) if not utils.pio_install_check() then @@ -114,8 +31,19 @@ function M.piolib(lib_arg_list) if res['status'] == 200 then local json_data = vim.json.decode(res['body']) - - pick_library(json_data) + picker.pick_library(json_data.items or {}, function(selected_library) + local owner = (selected_library.owner and selected_library.owner.username) or '' + local name = selected_library.name or '' + if owner == '' or name == '' then + vim.notify('Invalid library selection: missing owner or name.', vim.log.levels.ERROR) + return + end + local pkg_name = owner .. '/' .. name + local command = 'pio pkg install --library "' .. pkg_name .. '"' + utils.ToggleTerminal(command, 'float', function() + vim.cmd(':PioLSP') + end) + end) else vim.notify( 'API Request to platformio return HTTP code: ' .. res['status'] .. '\nplease run `curl -LI ' .. url .. '` for complete information', From ed2301848f7e94b34b3cfbce08a1522f5eab2fe0 Mon Sep 17 00:00:00 2001 From: Anurag Kumar Singh Date: Tue, 12 May 2026 11:26:54 +0530 Subject: [PATCH 6/8] Updated the docs and README for new picker_backend config option --- README.md | 5 ++++- doc/platformio.txt | 26 ++++++++++++++++++++++++++ doc/tags | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 63cef54..b1611a3 100644 --- a/README.md +++ b/README.md @@ -37,12 +37,14 @@ return { -- Dependencies are lazy-loaded by default unless specified otherwise. dependencies = { - { 'akinsho/toggleterm.nvim' }, { 'nvim-telescope/telescope.nvim' }, { 'nvim-telescope/telescope-ui-select.nvim' }, { 'nvim-lua/plenary.nvim' }, { 'folke/which-key.nvim' }, { 'nvim-treesitter/nvim-treesitter' } + + -- install picker based on your likeing + { 'akinsho/toggleterm.nvim' }, }, } ``` @@ -53,6 +55,7 @@ return { vim.g.pioConfig ={ lsp = 'clangd', -- value: clangd | ccls clangd_source = 'ccls', -- value: ccls | compiledb, For detailed explation check :help platformio-clangd_source + picker_backend = 'auto', -- value: auto | telescope | ui_select, default: auto, check :help platformio-picker menu_key = '\\', -- replace this menu key to your convenience debug = false -- enable debug messages } diff --git a/doc/platformio.txt b/doc/platformio.txt index c16d9a7..278d369 100644 --- a/doc/platformio.txt +++ b/doc/platformio.txt @@ -116,4 +116,30 @@ clangd_source *platformio-clangd_source Try both methods and choose the one that works best for your setup. I am also open to suggestions to further improve clangd support. +picker_backend *platformio-picker* + The plugin uses a picker abstraction for interactive selection flows used + by `:Pioinit` and `:Piolib`. This keeps command logic separate from UI so + different picker UIs can be used without changing command behavior. + + Set this in `setup()`: + >lua + require('platformio').setup({ + picker_backend = 'auto', + }) + < + + Allowed values: + - `auto` + Default. Tries Telescope backend first. If Telescope is unavailable, + falls back to `vim.ui.select` backend. + + - `telescope` + Force Telescope picker backend. If Telescope backend cannot be loaded, + plugin falls back to `vim.ui.select` as a safety fallback. + + - `ui_select` + Force `vim.ui.select` backend. This works with Neovim built-in + `vim.ui.select` or any plugin that overrides it (for example, + telescope-ui-select, dressing.nvim, snacks picker adapters, etc.). + vim:tw=78:sw=4:ts=8:ft=help:norl:noet: diff --git a/doc/tags b/doc/tags index 047d661..fac6b44 100644 --- a/doc/tags +++ b/doc/tags @@ -9,5 +9,6 @@ PlatformIO platformio.txt /*PlatformIO* platformio-clangd_source platformio.txt /*platformio-clangd_source* platformio-configuration platformio.txt /*platformio-configuration* +platformio-picker platformio.txt /*platformio-picker* platformio-usage platformio.txt /*platformio-usage* platformio.lua platformio.txt /*platformio.lua* From f7411ac79377f1d16ce2ce19f85c455cbf19395e Mon Sep 17 00:00:00 2001 From: Anurag Kumar Singh Date: Tue, 12 May 2026 11:41:53 +0530 Subject: [PATCH 7/8] Abstracted away PioTermList and picker specific implementation --- lua/platformio/pickers/init.lua | 9 ++++ lua/platformio/pickers/telescope.lua | 32 ++++++++++++ lua/platformio/pickers/ui_select.lua | 17 +++++++ lua/platformio/piotermlist.lua | 46 +++++++++++++++++ plugin/platformio.lua | 76 +--------------------------- 5 files changed, 105 insertions(+), 75 deletions(-) create mode 100644 lua/platformio/piotermlist.lua diff --git a/lua/platformio/pickers/init.lua b/lua/platformio/pickers/init.lua index 3de19e6..b9e6163 100644 --- a/lua/platformio/pickers/init.lua +++ b/lua/platformio/pickers/init.lua @@ -51,4 +51,13 @@ function M.pick_library(libraries, on_select) backend.pick_library(libraries, on_select) end +function M.pick_terminal(terminals, on_select) + local backend = get_backend() + if not backend then + vim.notify('No picker backend available for PlatformIO.', vim.log.levels.ERROR) + return + end + backend.pick_terminal(terminals, on_select) +end + return M diff --git a/lua/platformio/pickers/telescope.lua b/lua/platformio/pickers/telescope.lua index 549df35..d180099 100644 --- a/lua/platformio/pickers/telescope.lua +++ b/lua/platformio/pickers/telescope.lua @@ -176,4 +176,36 @@ function M.pick_library(libraries, on_select) :find() end +function M.pick_terminal(terminals, on_select) + local opts = {} + pickers + .new(opts, { + prompt_title = 'PIO terminals', + finder = finders.new_table({ + results = terminals, + entry_maker = function(entry) + local is_hidden = vim.api.nvim_buf_is_loaded(entry.term.bufnr) and (vim.fn.bufwinid(entry.term.bufnr) == -1) + local label = string.format('%d:%s (hidden: %s)', entry.term.id, entry.termtype, tostring(is_hidden)) + return { + value = entry, + display = label, + ordinal = label, + } + end, + }), + attach_mappings = function(prompt_bufnr, _) + actions.select_default:replace(function() + actions.close(prompt_bufnr) + local selection = action_state.get_selected_entry() + if selection and selection.value then + on_select(selection.value) + end + end) + return true + end, + sorter = telescope_conf.generic_sorter(opts), + }) + :find() +end + return M diff --git a/lua/platformio/pickers/ui_select.lua b/lua/platformio/pickers/ui_select.lua index 12ca9bb..aa2ead8 100644 --- a/lua/platformio/pickers/ui_select.lua +++ b/lua/platformio/pickers/ui_select.lua @@ -42,4 +42,21 @@ function M.pick_library(libraries, on_select) end) end +function M.pick_terminal(terminals, on_select) + vim.ui.select(terminals, { + prompt = 'Select a PIO terminal window:', + kind = 'PioTerminals', + format_item = function(item) + local is_hidden = vim.api.nvim_buf_is_loaded(item.term.bufnr) and (vim.fn.bufwinid(item.term.bufnr) == -1) + return string.format('%d:%s (hidden: %s)', item.term.id, item.termtype, tostring(is_hidden)) + end, + }, function(chosen) + if chosen then + on_select(chosen) + else + on_select(nil) + end + end) +end + return M diff --git a/lua/platformio/piotermlist.lua b/lua/platformio/piotermlist.lua new file mode 100644 index 0000000..7e35087 --- /dev/null +++ b/lua/platformio/piotermlist.lua @@ -0,0 +1,46 @@ +local M = {} + +local utils = require('platformio.utils') +local picker = require('platformio.pickers') + +local function switch_to_terminal(chosen) + if not chosen or not chosen.term then + vim.api.nvim_echo({ { 'No PIO terminal window selected.', 'Normal' } }, true, {}) + return + end + + local win_type = vim.fn.win_gettype(chosen.term.window) + local win_open = win_type == '' or win_type == 'popup' + if chosen.term.window and (win_open and vim.api.nvim_win_get_buf(chosen.term.window) == chosen.term.bufnr) then + vim.api.nvim_set_current_win(chosen.term.window) + else + chosen.term:open() + end + vim.api.nvim_echo({ { 'Switched to PIO terminal: ' .. chosen.termtype, 'Normal' } }, true, {}) +end + +function M.piotermlist() + local toggleterm_list = {} + local terms = require('toggleterm.terminal').get_all(true) + + if #terms ~= 0 then + for i = 1, #terms do + if terms[i].display_name and terms[i].display_name ~= '' and terms[i].display_name:find('pio', 1) then + local termtype = utils.strsplit(terms[i].display_name, ':')[1] + table.insert(toggleterm_list, { + term = terms[i], + termtype = termtype, + }) + end + end + end + + if #toggleterm_list == 0 then + vim.api.nvim_echo({ { 'No PIO terminal windows found.', 'Normal' } }, true, {}) + return + end + + picker.pick_terminal(toggleterm_list, switch_to_terminal) +end + +return M diff --git a/plugin/platformio.lua b/plugin/platformio.lua index 35020c1..63462ee 100644 --- a/plugin/platformio.lua +++ b/plugin/platformio.lua @@ -91,82 +91,8 @@ vim.api.nvim_create_user_command('Piodebug', function() require('platformio.piodebug').piodebug() end, {}) ------------------------------------------------------- --- require('telescope').load_extension('ui-select') -- INFO: List ToggleTerminals vim.api.nvim_create_user_command('PioTermList', function() - local telescope = require('telescope') - telescope.setup({ - extensions = { - ['ui-select'] = { - require('telescope.themes').get_dropdown({ - borderchars = { - prompt = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, - results = { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' }, - preview = { '─', '│', '─', '│', '╭', '╮', '╯', '╰' }, - }, - prompt_position = 'top', -- "top" or "bottom" - prompt_prefix = '🔍 ', -- Prompt prefix - selection_caret = '❯ ', -- Selection indicator - entry_prefix = ' ', -- Entry prefix - initial_mode = 'insert', -- "insert" or "normal" - scroll_strategy = 'cycle', -- "cycle" or "limit" - sorting_strategy = 'ascending', -- "ascending" or "descending" - color_devicons = true, -- Color file icons - use_less = true, -- Use less for preview - -- prompt_prefix = " ", - -- selection_caret = " ", - -- color_devicons = true, - }), - }, - }, - }) - telescope.load_extension('ui-select') - local utils = require('platformio.utils') - local toggleterm_list = {} - - local terms = require('toggleterm.terminal').get_all(true) - if #terms ~= 0 then - for i = 1, #terms do - if terms[i].display_name and terms[i].display_name ~= '' and terms[i].display_name:find('pio', 1) then - local termtype = utils.strsplit(terms[i].display_name, ':')[1] - table.insert(toggleterm_list, { - term = terms[i], - termtype = termtype, -- Store the terminal type [piomon or piocli] - }) - end - end - end - - if #toggleterm_list == 0 then - vim.api.nvim_echo({ { 'No PIO terminal windows found.', 'Normal' } }, true, {}) - return - end - - vim.ui.select(toggleterm_list, { - prompt = 'Select a PIO terminal window:', - format_item = function(item) - return string.format( - '%d:%s (hidden: %s)', - item.term.id, - item.termtype, - vim.api.nvim_buf_is_loaded(item.term.bufnr) and (vim.fn.bufwinid(item.term.bufnr) == -1) - ) - end, - kind = 'PioTerminals', - }, function(chosen, _) - if chosen then - local win_type = vim.fn.win_gettype(chosen.term.window) - local win_open = win_type == '' or win_type == 'popup' - if chosen.term.window and (win_open and vim.api.nvim_win_get_buf(chosen.term.window) == chosen.term.bufnr) then - vim.api.nvim_set_current_win(chosen.term.window) - else - chosen.term:open() - end - vim.api.nvim_echo({ { 'Switched to PIO terminal: ' .. chosen.termtype, 'Normal' } }, true, {}) - else - vim.api.nvim_echo({ { 'No PIO terminal window selected.', 'Normal' } }, true, {}) - end - end) + require('platformio.piotermlist').piotermlist() end, {}) From 702a47adeb596c8da1da79bd8e2dd455e4b857d2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 12 May 2026 06:27:27 +0000 Subject: [PATCH 8/8] style: auto format lua --- lua/platformio/init.lua | 7 ++++++- plugin/platformio.lua | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lua/platformio/init.lua b/lua/platformio/init.lua index 9251896..8f0e5bd 100644 --- a/lua/platformio/init.lua +++ b/lua/platformio/init.lua @@ -189,7 +189,12 @@ function M.setup(user_config) user_config.clangd_source = M.config.clangd_source end end - if user_config.picker_backend and user_config.picker_backend ~= 'auto' and user_config.picker_backend ~= 'telescope' and user_config.picker_backend ~= 'ui_select' then + if + user_config.picker_backend + and user_config.picker_backend ~= 'auto' + and user_config.picker_backend ~= 'telescope' + and user_config.picker_backend ~= 'ui_select' + then vim.api.nvim_echo( { { 'Invalid picker backend {allowed "auto", "telescope" or "ui_select"} (default "' .. M.config.picker_backend .. '" will be used)', 'ErrorMsg' } }, true, diff --git a/plugin/platformio.lua b/plugin/platformio.lua index 63462ee..2373403 100644 --- a/plugin/platformio.lua +++ b/plugin/platformio.lua @@ -91,7 +91,6 @@ vim.api.nvim_create_user_command('Piodebug', function() require('platformio.piodebug').piodebug() end, {}) - -- INFO: List ToggleTerminals vim.api.nvim_create_user_command('PioTermList', function() require('platformio.piotermlist').piotermlist()