diff options
Diffstat (limited to 'plugins/tab_switcher.lua')
-rw-r--r-- | plugins/tab_switcher.lua | 131 |
1 files changed, 115 insertions, 16 deletions
diff --git a/plugins/tab_switcher.lua b/plugins/tab_switcher.lua index 3d55eed..41fdf84 100644 --- a/plugins/tab_switcher.lua +++ b/plugins/tab_switcher.lua @@ -5,7 +5,62 @@ local keymap = require "core.keymap" local common = require "core.common" local DocView = require "core.docview" +local nodes_visit_order = setmetatable({}, {__mode = "k"}) + +---When true, releasing all the modifier keys will accept the selection +local hold_mode = false +---Whether or not the CommandView relative to this plugin is active +local in_switcher = false + +---@param t table<any, boolean?> +---@return boolean +local function any_true(t) + for _, v in pairs(t) do + if v then return true end + end + return false +end + +-- We need to override keymap.on_key_released to detect that all the modifier +-- keys were released while in "hold" mode, to accept the current selection. +local old_keymap_on_key_released = keymap.on_key_released +function keymap.on_key_released(k) + -- Check if hold_mode has been triggered erroneously + if hold_mode and not in_switcher then + hold_mode = false + core.warning("Something went wrong with the tab_switcher plugin. " .. + "Please open an issue about it in the plugins repository on Github.") + end + + local was_pressed = any_true(keymap.modkeys) + old_keymap_on_key_released(k) + local still_pressed = any_true(keymap.modkeys) + + if hold_mode and was_pressed and not still_pressed then + hold_mode = false + command.perform("command:submit") + end +end + + +local order_counter = 0 + +local core_set_active_view = core.set_active_view +function core.set_active_view(view) + nodes_visit_order[view] = order_counter + order_counter = order_counter + 1 + return core_set_active_view(view) +end + local tab_switcher = {} + +---@class tab_switcher.tab_item +---@field text string The tab name +---@field view core.view + +---Returns the list of DocView tabs under a specific node tree. +---@param base_node core.node Where to start the search from +---@return tab_switcher.tab_item[] function tab_switcher.get_tab_list(base_node) local raw_list = base_node:get_children() local list = {} @@ -21,40 +76,84 @@ function tab_switcher.get_tab_list(base_node) }, mt)) end end + table.sort(list, function(a, b) + return (nodes_visit_order[a.view] or -1) > (nodes_visit_order[b.view] or -1) + end) return list end +local function set_active_view(view) + local n = core.root_view.root_node:get_node_for_view(view) + if n then n:set_active_view(view) end +end + +---@param label string +---@param items tab_switcher.tab_item[] local function ask_selection(label, items) - if #items == 0 then - core.warn("No tabs available") - return - end + in_switcher = true core.command_view:enter(label, { submit = function(_, item) - local n = core.root_view.root_node:get_node_for_view(item.view) - if n then n:set_active_view(item.view) end + in_switcher = false + set_active_view(item.view) end, suggest = function(text) - return common.fuzzy_match(items, text, true) + if #text > 1 then + return common.fuzzy_match(items, text, true) + else + return items + end end, validate = function(_, item) return item - end + end, + cancel = function() + in_switcher = false + end, }) end -command.add(nil,{ - ["tab-switcher:tab-list"] = function() - ask_selection("Switch to tab", tab_switcher.get_tab_list(core.root_view.root_node)) +command.add(function(items) + items = items or tab_switcher.get_tab_list(core.root_view.root_node) + return #items > 0, items + end, { + ["tab-switcher:tab-list"] = function(items) + ask_selection("Switch to tab", items) + end, + ["tab-switcher:switch-to-last-tab"] = function(items) + command.perform("tab-switcher:tab-list", items) + command.perform("tab-switcher:previous-tab") + end, +}) + +command.add(function(items) + items = items or tab_switcher.get_tab_list(core.root_view:get_active_node()) + return #items > 0, items + end, { + ["tab-switcher:tab-list-current-split"] = function(items) + ask_selection("Switch to tab in current split", items) + end, + ["tab-switcher:switch-to-last-tab-in-current-split"] = function(items) + command.perform("tab-switcher:tab-list-current-split", items) + command.perform("tab-switcher:previous-tab") + end, +}) + +command.add(function() return in_switcher end, { + ["tab-switcher:next-tab"] = function() + hold_mode = true + command.perform("command:select-next") + end, + ["tab-switcher:previous-tab"] = function() + hold_mode = true + command.perform("command:select-previous") end, - ["tab-switcher:tab-list-current-split"] = function() - ask_selection("Switch to tab in current split", tab_switcher.get_tab_list(core.root_view:get_active_node())) - end }) keymap.add({ - ["alt+p"] = "tab-switcher:tab-list", - ["alt+shift+p"] = "tab-switcher:tab-list-current-split" + ["alt+p"] = { "tab-switcher:previous-tab", "tab-switcher:tab-list" }, + ["ctrl+alt+p"] = { "tab-switcher:previous-tab", "tab-switcher:switch-to-last-tab" }, + ["alt+shift+p"] = { "tab-switcher:next-tab", "tab-switcher:tab-list-current-split" }, + ["ctrl+alt+shift+p"] = { "tab-switcher:next-tab", "tab-switcher:switch-to-last-tab-in-current-split" }, }) return tab_switcher |