diff --git a/README.md b/README.md
index 8e36387..404ec62 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,9 @@
> [!IMPORTANT]
-> This plugin is intended for personal and demonstration purposes only and have a lot of limitations.
-> It is not recommended to use this plugin.
+> This plugin is mainly for personal and demonstration purposes and have a lot of limitations.
+> Limited support will be provided for issues and pull requests.
+> I would prefer to have this plugin integrated directly into edgy.nvim.
https://github.com/lucobellic/edgy-group.nvim/assets/6067072/00feeae1-6d6c-486c-a93c-25688ff37766
@@ -23,7 +24,8 @@ https://github.com/lucobellic/edgy-group.nvim/assets/6067072/00feeae1-6d6c-486c-
- Switch between groups of windows within **edgebar**.
- Add a command to navigate through groups of windows.
-- Allow the creation of custom icon indicators in the statusline, bufferline, etc.
+- Allow the creation of custom icon indicators in statusline, bufferline, etc.
+- Pick mode to select group from statusline
## ⚠️ Limitations
@@ -79,13 +81,31 @@ local default_options = {
clickable = false, -- enable `open_group` on click
colored = false, -- enable highlight support
colors = { -- highlight colors
- active = 'Normal',
- inactive = 'Normal',
+ active = 'Normal', -- highlight color for open group
+ inactive = 'Normal', -- highlight color for closed group
+ pick_active = 'PmenuSel', -- highlight color for pick key for open group
+ pick_inactive = 'PmenuSel', -- highlight color for pick key for closed group
},
},
}
```
+#### Groups
+
+```lua
+groups = {
+ right = { -- group position (right, left, bottom, top)
+ {
+ icon = '', -- icon used in statusline and vim.ui.select
+ titles = { 'Neo-Tree', 'Neo-Tree Buffers' }, -- list of titles from edgy.nvim
+ pick_key = 'f' -- key to pick a group in statusline
+ },
+ },
+}
+```
+
+Groups without pick_key will be assigned to the first available key in alphabetical order.
+
### 🔌 API
- **EdgyGroupSelect** select group to open with **vim.ui.select**.
@@ -94,6 +114,7 @@ local default_options = {
- **require('edgy-group').open_group_offset(position, offset)** open group with offset relative to the current group.
- **require('edgy-group').open_group_index(position, index)** open group with index relative to the current position.
- **require('edgy-group.stl.statusline').get_statusline(position)** get a list of string in statusline format for each group icons with optional highlight and click support.
+- **require('edgy-group.stl.statusline').pick(callback)** enable picking mode to select group from statusline.
## Example Setup
@@ -119,6 +140,13 @@ Usage of **edgy-group.nvim** to create three groups for the left **edgebar**:
function() require('edgy-group').open_group_offset('left', -1) end,
desc = 'Edgy Group Prev Left',
},
+ {
+ '',
+ function()
+ require('edgy-group.stl.statusline').pick()
+ end,
+ desc = 'Edgy Group Pick',
+ },
},
opts = {
groups = {
@@ -183,5 +211,10 @@ Examples of how to use **edgy-group.nvim** with [bufferline.nvim](https://github
},
},
}
+```
+
+##### Picking
+```lua
+require('edgy-group.stl.statusline').pick(function() require('lualine').refresh() end)
```
diff --git a/lua/edgy-group/options.lua b/lua/edgy-group/options.lua
index 9384b4b..b992081 100644
--- a/lua/edgy-group/options.lua
+++ b/lua/edgy-group/options.lua
@@ -5,6 +5,7 @@ local Groups = require('edgy-group.groups')
---@class EdgyGroup
---@field icon number
---@field titles string[]
+---@field pick_key? string Key to use for group pick.
---@class EdgyGroup.Statusline.Opts
---@field separators string[]
@@ -15,6 +16,8 @@ local Groups = require('edgy-group.groups')
---@class EdgyGroup.Statusline.Colors
---@field active string
---@field inactive string
+---@field pick_active string
+---@field pick_inactive string
---@class EdgyGroup.Opts
---@field groups table
@@ -35,6 +38,8 @@ local default_options = {
colors = {
active = 'Normal',
inactive = 'Normal',
+ pick_active = 'PmenuSel',
+ pick_inactive = 'PmenuSel',
},
},
}
diff --git a/lua/edgy-group/stl/cache.lua b/lua/edgy-group/stl/cache.lua
index f157083..dcf94b2 100644
--- a/lua/edgy-group/stl/cache.lua
+++ b/lua/edgy-group/stl/cache.lua
@@ -1,11 +1,15 @@
-local Group = require('edgy-group')
-
-- TODO: Extend cache to not recompute highlight if selected_group didn't change
-- Otherwise update the statusline directly after group change
+---@class EdgyGroup.Statusline.Cache.GroupIndex
+---@field position Edgy.Pos
+---@field index number
+
---@class EdgyGroup.Statusline.Cache
---@field opts EdgyGroup.Statusline.Opts
---@field status_lines table
+---@field pick_keys table pick keys for each position and group
+---@field key_to_group table associate a key to a group
local Cache = {}
---@param groups table
@@ -13,10 +17,49 @@ local Cache = {}
function Cache.new(groups, opts)
local self = setmetatable({}, { __index = Cache })
self.opts = opts
- self.status_lines = self:build_cache(groups)
+ self.status_lines = self:build_status_lines(groups)
+ self:build_keys(groups)
return self
end
+-- Get a list of all keys not used by the user
+---@private
+---@param groups table
+---@return string[] available_keys keys not used by the user
+function Cache:get_available_keys(groups)
+ local user_keys = {}
+ for _, group in ipairs(groups) do
+ if group.pick_key then table.insert(user_keys, group.pick_key) end
+ end
+
+ local pick_keys = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
+ local keys_table = {}
+ for i = 1, #pick_keys do
+ keys_table[i] = pick_keys:sub(i, i)
+ end
+
+ return vim.tbl_filter(function(key)
+ return not vim.tbl_contains(user_keys, key)
+ end, keys_table)
+end
+
+-- Build picking keys for each positions and group and associate them to the group
+---@private
+---@param groups table
+function Cache:build_keys(groups)
+ local available_keys = self:get_available_keys(groups)
+ self.pick_keys = {}
+ self.key_to_group = {}
+ for _, pos in ipairs({ 'right', 'left', 'bottom', 'top' }) do
+ self.pick_keys[pos] = {}
+ for i, group in ipairs(groups[pos] and groups[pos].groups or {}) do
+ local key = group.pick_key or table.remove(available_keys, 1)
+ self.pick_keys[pos][i] = key
+ self.key_to_group[key] = { position = pos, index = i }
+ end
+ end
+end
+
-- Create callback function on click if clickable
---@private
---@param position Edgy.Pos
@@ -51,7 +94,7 @@ end
---@private
---@param groups table
---@return table
-function Cache:build_cache(groups)
+function Cache:build_status_lines(groups)
local status_lines = {}
for _, pos in ipairs({ 'right', 'left', 'bottom', 'top' }) do
status_lines[pos] = self:build_statusline(pos, groups[pos] and groups[pos].groups or {})
diff --git a/lua/edgy-group/stl/statusline.lua b/lua/edgy-group/stl/statusline.lua
index d52db56..47df837 100644
--- a/lua/edgy-group/stl/statusline.lua
+++ b/lua/edgy-group/stl/statusline.lua
@@ -3,16 +3,18 @@ local Group = require('edgy-group')
---@class EdgyGroup.Statusline
---@field private cache EdgyGroup.Statusline.Cache
----@diagnostic disable-next-line: missing-fields
+---@field private pick_mode boolean True when pick is active, false otherwise
+------@diagnostic disable-next-line: missing-fields
local M = {}
---@param groups table
---@param opts EdgyGroup.Statusline.Opts
function M.setup(groups, opts)
M.cache = require('edgy-group.stl.cache').new(groups, opts)
+ M.pick_mode = false
end
----@private
+---@package
---@param is_visible boolean
---@return string
function M.get_highlight(is_visible)
@@ -20,11 +22,28 @@ function M.get_highlight(is_visible)
return M.cache.opts.colored and '%#' .. highlight .. '#' or ''
end
+---@package
+---@param is_visible boolean
+---@param position Edgy.Pos
+---@param index number
+function M.get_pick_text(is_visible, position, index)
+ local pick = ''
+ if M.pick_mode then
+ local pick_per_pos = M.cache.pick_keys[position]
+ local character = pick_per_pos[index] or ''
+ local highlight = is_visible and M.cache.opts.colors.pick_active or M.cache.opts.colors.pick_inactive
+ local pick_highlight = M.cache.opts.colored and '%#' .. highlight .. '#' or ''
+ pick = pick_highlight .. character
+ end
+ return pick
+end
+
-- Get a list of statusline at the given position for each group icons
-- Also provide optional highlight and click support
+---@public
---@param position Edgy.Pos The position to get the statusline for
---@return table
-M.get_statusline = function(position)
+function M.get_statusline(position)
local statusline = {}
local edgebar = Config and Config.layout and Config.layout[position]
local g = Group.groups_by_pos
@@ -33,10 +52,49 @@ M.get_statusline = function(position)
for index, group_line in ipairs(M.cache.status_lines[position]) do
local is_visible = edgebar.visible ~= 0 and index == indexed_groups.selected_index
local highlight = M.get_highlight(is_visible)
- table.insert(statusline, highlight .. group_line)
+ local pick = M.get_pick_text(is_visible, position, index)
+ table.insert(statusline, pick .. highlight .. group_line)
end
end
return statusline
end
+-- Find the group position and index for the given key
+---@private
+---@param key string
+---@return EdgyGroup.Statusline.Cache.GroupIndex?
+function M.find_pos_index(key)
+ return M.cache.key_to_group[key] or {}
+end
+
+-- Enable pick mode and wait for a key to be pressed
+-- Redraw statusline and tabline before and after pick
+-- Optional callback could be used to trigger external plugin refresh/update
+---@public
+---@param callback? function Callback function to call after pick mode have been enabled
+M.pick = function(callback)
+ M.pick_mode = true
+
+ -- callback function before redraw
+ if callback then pcall(callback) end
+ vim.schedule(function()
+ vim.cmd.redrawtabline()
+ vim.cmd.redrawstatus()
+ end)
+
+ -- Wait for key and open the corresponding group
+ local key = vim.fn.getcharstr()
+ if key then
+ local group_index = M.find_pos_index(key)
+ if group_index then pcall(Group.open_group_index, group_index.position, group_index.index) end
+ end
+
+ -- Disable pick mode and redraw
+ M.pick_mode = false
+ vim.schedule(function()
+ vim.cmd.redrawtabline()
+ vim.cmd.redrawstatus()
+ end)
+end
+
return M