Skip to content

Commit d645ac7

Browse files
committed
feat: add statusline & winbar hint
1 parent 4dc0cd7 commit d645ac7

File tree

3 files changed

+163
-45
lines changed

3 files changed

+163
-45
lines changed

lua/window-picker/config.lua

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,28 @@ local config = {
1111
-- following letters on them so you can use that letter to select the window
1212
selection_chars = 'FJDKSLA;CMRUEIWOQP',
1313

14+
-- You can change the display string in status bar.
15+
-- It supports '%' printf style. Such as `return char .. ': %f'` to display
16+
-- buffer filepath. See :h 'stl' for details.
17+
selection_display = function(char, windowid)
18+
return '%=' .. char .. '%='
19+
end,
20+
21+
-- whether you want to use winbar instead of the statusline
22+
-- "always" means to always use winbar,
23+
-- "never" means to never use winbar
24+
-- "smart" means to use winbar if cmdheight=0 and statusline if cmdheight > 0
25+
use_winbar = 'smart', -- "always" | "never" | "smart"
26+
27+
-- whether to show 'Pick window:' prompt
28+
show_prompt = true,
29+
1430
-- if you want to manually filter out the windows, pass in a function that
15-
-- takes two parameters. you should return window ids that should be
31+
-- takes two parameters. You should return window ids that should be
1632
-- included in the selection
1733
-- EX:-
1834
-- function(window_ids, filters)
19-
-- -- filder the window_ids
35+
-- -- folder the window_ids
2036
-- -- return only the ones you want to include
2137
-- return {1000, 1001}
2238
-- end
@@ -47,6 +63,9 @@ local config = {
4763
file_name_contains = {},
4864
},
4965

66+
-- the foreground (text) color of the picker
67+
fg_color = '#ededed',
68+
5069
-- if you have include_current_win == true, then current_win_hl_color will
5170
-- be highlighted using this background color
5271
current_win_hl_color = '#e35e4f',

lua/window-picker/hints/statusline-hint.lua

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,91 +2,98 @@
22
---@field window_options table<string, any> window options
33
---@field global_options table<string, any> global options
44
---@field laststatus string current value of the laststatus
5+
---@field chars string[] list of chars to hint
6+
---@field selection_display function function to customize the hint
57
local M = {}
68

79
function M:new()
810
local o = {
911
window_options = {},
1012
global_options = {},
11-
laststatus = vim.o.laststatus,
1213
}
1314

14-
setmetatable(o, M)
15+
setmetatable(o, self)
1516
self.__index = self
1617

1718
return o
1819
end
1920

2021
function M:set_config(config)
2122
self.chars = config.chars
22-
self.current_win_hl_color = config.current_win_hl_color
23-
self.other_win_hl_color = config.other_win_hl_color
23+
self.selection_display = config.selection_display
24+
25+
vim.api.nvim_set_hl(0, 'WindowPickerStatusLine', {
26+
fg = '#ededed',
27+
bg = config.current_win_hl_color,
28+
bold = true,
29+
})
30+
31+
vim.api.nvim_set_hl(0, 'WindowPickerStatusLineNC', {
32+
fg = '#ededed',
33+
bg = config.other_win_hl_color,
34+
bold = true,
35+
})
2436
end
2537

26-
-- M:_set_highlight_groups sets highlight groups
27-
-- @param { any } config passes colors
28-
function M:_set_highlight_groups()
29-
vim.cmd(
30-
'highlight NvimWindoSwitch gui=bold guifg=#ededed guibg='
31-
.. self.current_win_hl_color
32-
)
33-
vim.cmd(
34-
'highlight NvimWindoSwitchNC gui=bold guifg=#ededed guibg='
35-
.. self.other_win_hl_color
36-
)
37-
end
38+
--- M:_save_window_options saves the initial window options later will be changed
39+
--- @param windows number[]
40+
function M:save_window_options(windows, win_opt_to_cap)
41+
self.window_options = {}
3842

39-
-- M:_save_window_options saves the initial window options later will be changed
40-
-- @param { Array<number> } window_ids list of window IDs
41-
function M:_save_window_options(windows)
4243
for _, window in ipairs(windows) do
43-
self.window_options[window] = {
44-
statusline = vim.wo[window].statusline,
45-
winhl = vim.wo[window].winhl,
46-
}
47-
end
44+
self.window_options[window] = {}
4845

49-
self.global_options['cmdheight'] = vim.o.cmdheight
46+
for _, opt_key in ipairs(win_opt_to_cap) do
47+
self.window_options[window][opt_key] = vim.wo[window][opt_key]
48+
end
49+
end
5050
end
5151

52-
-- M:print shows the characters in status line
53-
-- @param { table } data window-letter mapping to show on status line
52+
--- Shows the characters in status line
53+
--- @param windows number[] windows to draw the hints on
5454
function M:draw(windows)
55-
self:_save_window_options(windows)
56-
self:_set_highlight_groups()
55+
local win_opt_to_cap = { 'statusline', 'winhl' }
56+
57+
if vim.o.cmdheight < 1 then
58+
self.global_options['cmdheight'] = vim.o['cmdheight']
59+
vim.o.cmdheight = 1
60+
end
61+
62+
if vim.o.laststatus ~= 2 then
63+
self.global_options['laststatus'] = vim.o['laststatus']
64+
vim.o.laststatus = 2
65+
end
5766

58-
-- make sure every window has status line
59-
vim.o.laststatus = 2
67+
self:save_window_options(windows, win_opt_to_cap)
6068

6169
for index, window in ipairs(windows) do
6270
local char = self.chars[index]
63-
vim.wo[window].statusline = '%=' .. char .. '%='
64-
vim.wo[window].winhl =
65-
'StatusLine:NvimWindoSwitch,StatusLineNC:NvimWindoSwitchNC'
66-
end
6771

68-
if self.global_options.cmdheight == 0 then
69-
vim.o.cmdheight = 1
72+
vim.wo[window].statusline = self.selection_display
73+
and self.selection_display(char, window)
74+
or '%=' .. char .. '%='
75+
76+
vim.wo[window].winhl =
77+
'StatusLine:WindowPickerStatusLine,StatusLineNC:WindowPickerStatusLineNC'
7078
end
7179

72-
vim.cmd('redraw')
80+
vim.cmd.redraw()
7381
end
7482

75-
-- M:clear the screen after print
83+
--- clear the screen after print
7684
function M:clear()
77-
vim.o.laststatus = self.laststatus
78-
7985
for window, options in pairs(self.window_options) do
8086
for opt_key, opt_value in pairs(options) do
8187
vim.wo[window][opt_key] = opt_value
8288
end
8389
end
8490

85-
self.window_options = {}
86-
8791
for key, value in pairs(self.global_options) do
8892
vim.o[key] = value
8993
end
94+
95+
self.window_options = {}
96+
self.global_options = {}
9097
end
9198

9299
return M
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
local StatuslineHint = require('window-picker.hints.statusline-hint')
2+
3+
---@class StatuslineWinbarHint
4+
---@field window_options table<string, any> window options
5+
---@field global_options table<string, any> global options
6+
---@field chars string[] list of chars to hint
7+
---@field selection_display function function to customize the hint
8+
local M = StatuslineHint:new()
9+
10+
function M:set_config(config)
11+
self.chars = config.chars
12+
self.selection_display = config.selection_display
13+
self.use_winbar = config.use_winbar
14+
self.show_prompt = config.show_prompt
15+
16+
vim.api.nvim_set_hl(0, 'WindowPickerStatusLine', {
17+
fg = '#ededed',
18+
bg = config.current_win_hl_color,
19+
bold = true,
20+
})
21+
22+
vim.api.nvim_set_hl(0, 'WindowPickerStatusLineNC', {
23+
fg = '#ededed',
24+
bg = config.other_win_hl_color,
25+
bold = true,
26+
})
27+
28+
vim.api.nvim_set_hl(0, 'WindowPickerWinBar', {
29+
fg = '#ededed',
30+
bg = config.current_win_hl_color,
31+
bold = true,
32+
})
33+
34+
vim.api.nvim_set_hl(0, 'WindowPickerWinBarNC', {
35+
fg = '#ededed',
36+
bg = config.other_win_hl_color,
37+
bold = true,
38+
})
39+
end
40+
41+
--- Shows the characters in status line
42+
--- @param windows number[] windows to draw the hints on
43+
function M:draw(windows)
44+
local use_winbar = false
45+
46+
-- calculate if we should use winbar or not
47+
if self.use_winbar == 'always' then
48+
use_winbar = true
49+
elseif self.use_winbar == 'never' then
50+
use_winbar = false
51+
elseif self.use_winbar == 'smart' then
52+
use_winbar = vim.o.cmdheight == 0
53+
end
54+
55+
local indicator_setting = use_winbar and 'winbar' or 'statusline'
56+
local indicator_hl = use_winbar and 'WinBar' or 'StatusLine'
57+
58+
if not use_winbar then
59+
if vim.o.laststatus ~= 2 then
60+
self.global_options['laststatus'] = vim.o['laststatus']
61+
vim.o.laststatus = 2
62+
end
63+
64+
if self.show_prompt and vim.o.cmdheight < 1 then
65+
self.global_options['cmdheight'] = vim.o['cmdheight']
66+
vim.o.cmdheight = 1
67+
end
68+
end
69+
70+
local win_opt_to_cap = { indicator_setting, 'winhl' }
71+
self:save_window_options(windows, win_opt_to_cap)
72+
73+
for index, window in ipairs(windows) do
74+
local char = self.chars[index]
75+
76+
vim.wo[window][indicator_setting] = self.selection_display
77+
and self.selection_display(char, window)
78+
or '%=' .. char .. '%='
79+
80+
vim.wo[window].winhl = string.format(
81+
'%s:WindowPicker%s,%sNC:WindowPicker%sNC',
82+
indicator_hl,
83+
indicator_hl,
84+
indicator_hl,
85+
indicator_hl
86+
)
87+
end
88+
89+
vim.cmd.redraw()
90+
end
91+
92+
return M

0 commit comments

Comments
 (0)