Skip to content

Commit

Permalink
feat: custom status line hints (#21)
Browse files Browse the repository at this point in the history
Co-authored-by: benlubas <[email protected]>
  • Loading branch information
benlubas and benlubas authored Jan 11, 2024
1 parent 4507a00 commit 56cf39c
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 73 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

[*]
indent_style = space
indent_size = 3
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ Hydra({

By default, a one line hint is generated and displayed in the cmdline. Heads and their
descriptions are placed in the order they were passed into the `heads` table. Heads with
`{opts = {desc = false}}` don't appear in auto-generated hints.
`{ opts = { desc = false }}` don't appear in auto-generated hints.

Values in the hint string are parsed with the following rules:

Expand All @@ -208,12 +208,12 @@ Values in the hint string are parsed with the following rules:
inserted into the hint
- Updated each time a head is called
- Pass these functions to `config.hint.funcs` (discussed below)
- There are built-in functions located here: [this
file](https://github.com/nvimtools/hydra.nvim/blob/main/lua/hydra/hint/vim-options.lua)
- There are built-in functions located
[here](https://github.com/nvimtools/hydra.nvim/blob/main/lua/hydra/hint/vim-options.lua)

**Heads not in the manually created hint, will be automatically added to the bottom of the
hint window, following the same rules as auto-generated hint. You can avoid this with
`{desc = false}`**
`{ desc = false }`**

### Hint Configuration

Expand All @@ -225,10 +225,12 @@ Hydra({
config = {
-- either a table like below, or `false` to disable the hint
hint = {
-- "window" | "cmdline" | "statusline"
-- "window" : show hint in a floating window
-- "cmdline" : show hint in the echo area
-- "window" | "cmdline" | "statusline" | "statuslinemanual"
-- "window": show hint in a floating window
-- "cmdline": show hint in the echo area
-- "statusline": show auto-generated hint in the status line
-- "statuslinemanual": Do not show a hint, but return a custom status
-- line hint from require("hydra.statusline").get_hint()
type = "window", -- defaults to "window" if `hint` is passed to the hydra
-- otherwise defaults to "cmdline"

Expand Down Expand Up @@ -482,7 +484,7 @@ you to integrate Hydra in your statusline:
- `get_name()` get the name of an active hydra if it has it;
- `get_color()` get the color of an active hydra;
- `get_hint()` get an active hydra's statusline hint. Return not `nil` only when
`config.hint` is set to `false.`
`config.hint` is set to `false` or when `config.hint.type == "statuslinemanual"`

## Limitations

Expand Down
20 changes: 11 additions & 9 deletions doc/hydra.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*hydra.txt* For NVIM v0.9.4 Last change: 2024 January 06
*hydra.txt* For NVIM v0.9.4 Last change: 2024 January 10

==============================================================================
Table of Contents *hydra-table-of-contents*
Expand Down Expand Up @@ -205,7 +205,7 @@ The string for the hint is passed directly to the hydra:

By default, a one line hint is generated and displayed in the cmdline. Heads
and their descriptions are placed in the order they were passed into the
`heads` table. Heads with `{opts = {desc = false}}` don’t appear in
`heads` table. Heads with `{ opts = { desc = false }}` don’t appear in
auto-generated hints.

Values in the hint string are parsed with the following rules:
Expand All @@ -218,12 +218,12 @@ Values in the hint string are parsed with the following rules:
inserted into the hint
- Updated each time a head is called
- Pass these functions to `config.hint.funcs` (discussed below)
- There are built-in functions located here: this
file <https://github.com/nvimtools/hydra.nvim/blob/main/lua/hydra/hint/vim-options.lua>
- There are built-in functions located
here <https://github.com/nvimtools/hydra.nvim/blob/main/lua/hydra/hint/vim-options.lua>

**Heads not in the manually created hint, will be automatically added to the
bottom of the hint window, following the same rules as auto-generated hint. You
can avoid this with {desc = false}**
can avoid this with { desc = false }**


HINT CONFIGURATION *hydra-hint-hint-configuration*
Expand All @@ -236,10 +236,12 @@ disable the hint by setting this value to `false`.
config = {
-- either a table like below, or `false` to disable the hint
hint = {
-- "window" | "cmdline" | "statusline"
-- "window" : show hint in a floating window
-- "cmdline" : show hint in the echo area
-- "window" | "cmdline" | "statusline" | "statuslinemanual"
-- "window": show hint in a floating window
-- "cmdline": show hint in the echo area
-- "statusline": show auto-generated hint in the status line
-- "statuslinemanual": Do not show a hint, but return a custom status
-- line hint from require("hydra.statusline").get_hint()
type = "window", -- defaults to "window" if `hint` is passed to the hydra
-- otherwise defaults to "cmdline"

Expand Down Expand Up @@ -506,7 +508,7 @@ can help you to integrate Hydra in your statusline:
- `get_name()` — get the name of an active hydra if it has it;
- `get_color()` — get the color of an active hydra;
- `get_hint()` — get an active hydra’s statusline hint. Return not `nil` only when
`config.hint` is set to `false.`
`config.hint` is set to `false` or when `config.hint.type == "statuslinemanual"`


==============================================================================
Expand Down
9 changes: 7 additions & 2 deletions lua/hydra/hint/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ local HintManualCmdline = cmdline.HintManualCmdline
local HintAutoWindow = window.HintAutoWindow
local HintManualWindow = window.HintManualWindow

local HintStatusLine = statusline.HintStatusLine
local HintAutoStatusLine = statusline.HintAutoStatusLine
local HintManualStatusLine = statusline.HintManualStatusLine
local HintStatusLineMute = statusline.HintStatusLineMute

---@return hydra.Hint
Expand All @@ -19,12 +20,16 @@ local function make_hint(input)
return HintStatusLineMute(input)
elseif hint and config.type == 'window' then
return HintManualWindow(input)
elseif hint and config.type == 'statusline' then
return HintManualStatusLine(input)
elseif hint and config.type == 'statuslinemanual' then
return HintStatusLineMute(input)
elseif hint then
return HintManualCmdline(input)
elseif config.type == 'cmdline' then
return HintAutoCmdline(input)
elseif config.type == 'statusline' then
return HintStatusLine(input)
return HintAutoStatusLine(input)
elseif config.type == 'window' then
return HintAutoWindow(input)
end
Expand Down
55 changes: 55 additions & 0 deletions lua/hydra/hint/parser.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
local Parser = {}

---Evaluate function values
---@param line string
---@param funcs table
---@return string
---@return boolean
function Parser.eval_funcs(line, funcs)
local start, stop, fname = 0, nil, nil
local need_to_update = false
while start do
start, stop, fname = line:find("%%{(.-)}", 1)
if start then
need_to_update = true

local fun = funcs[fname]
if not fun then
error(string.format('[Hydra] "%s" not present in "config.hint.functions" table', fname))
end

line = table.concat({
line:sub(1, start - 1),
fun(),
line:sub(stop + 1),
})
end
end

return line, need_to_update
end

---Parse the heads in a hint string, adding highlights with the given function
--- modifies the heads table
---@param line string
---@param heads table
---@param highlight function
Parser.parse_heads = function(line, heads, highlight)
local start, stop, head = 0, 0, nil
while start do
start, stop, head = line:find('_(.-)_', stop + 1)
if head and vim.startswith(head, [[\]]) then head = head:sub(2) end
if start then
if not heads[head] then
error(string.format('[Hydra] docsting error, head "%s" does not exist', head))
end
local color = heads[head].color
-- TODO: create this function. and pass it.
-- buffer:add_highlight(namespace, 'Hydra' .. color, n - 1, start, stop - 1)
highlight(color, start, stop - 1)
heads[head] = nil
end
end
end

return Parser
97 changes: 88 additions & 9 deletions lua/hydra/hint/statusline.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ local class = require('hydra.lib.class')
local BaseHint = require('hydra.hint.basehint')
local M = {}

---Auto generated status line
---@class hydra.hint.StatusLine : hydra.Hint
---@field update nil
local HintStatusLine = class(BaseHint)
local HintAutoStatusLine = class(BaseHint)

function HintStatusLine:initialize(input)
function HintAutoStatusLine:initialize(input)
BaseHint.initialize(self, input)
end

function HintStatusLine:_make_statusline()
function HintAutoStatusLine:_make_statusline()
if self.statusline then return end

require('hydra.lib.highlight')
Expand All @@ -32,7 +33,7 @@ function HintStatusLine:_make_statusline()
self.statusline = statusline:gsub(', $', '')
end

function HintStatusLine:show()
function HintAutoStatusLine:show()
if not self.statusline then self:_make_statusline() end

local statusline = { ' ', self.statusline } ---@type string[]
Expand All @@ -45,7 +46,7 @@ function HintStatusLine:show()
vim.wo.statusline = statusline
end

function HintStatusLine:close()
function HintAutoStatusLine:close()
if self.original_statusline then
vim.wo.statusline = self.original_statusline
self.original_statusline = nil
Expand All @@ -54,13 +55,90 @@ end

--------------------------------------------------------------------------------

---Statusline with custom hint string
---@class hydra.hint.ManualStatusLine : hydra.hint.StatusLine
---@field need_to_update boolean
local HintManualStatusLine = class(HintAutoStatusLine)

local vim_options = require('hydra.hint.vim-options')
function HintManualStatusLine:initialize(input)
HintAutoStatusLine.initialize(self, input)
self.need_to_update = false

if type(self.config) == "table" then
self.config.funcs = setmetatable(self.config.funcs or {}, {
__index = vim_options
})
end
end

function HintManualStatusLine:_make_statusline()
if self.statusline then return end
if not self.hint then return HintAutoStatusLine._make_statusline(self) end

require('hydra.lib.highlight')
local parser = require("hydra.hint.parser")

---@type string
local hint = self.hint
hint = hint:gsub("%^", "")

---@type table<string, hydra.HeadSpec>
local heads = vim.deepcopy(self.heads)

---@type string[]
local statusline = {}

-- eval funcs
local parsed_line, need_to_update = parser.eval_funcs(hint, self.config.funcs)
self.need_to_update = self.need_to_update or need_to_update
hint = parsed_line

local last_end = nil
parser.parse_heads(hint, heads, function(color, start, end_)
if last_end ~= nil then
vim.list_extend(statusline, {
hint:sub(last_end + 2, start - 1)
})
end
local head_key = hint:sub(start + 1, end_)
vim.list_extend(statusline, {
string.format('%%#HydraStatusLine%s#', color),
head_key,
'%#StatusLine#',
})
last_end = end_
end)

vim.list_extend(statusline, {
hint:sub(last_end + 2)
})

statusline = table.concat(statusline) ---@diagnostic disable-line
self.statusline = statusline
end

function HintManualStatusLine:update()
print("hi")
if not self.need_to_update then return end
print("need to update")

local saved_statusline = self.original_statusline
self.statusline = nil
self:_make_statusline()
self:show()
self.original_statusline = saved_statusline
end

--------------------------------------------------------------------------------

---Statusline hint that won't be shown. It is used in "hydra.statusline" module.
---@class hydra.hint.StatusLineMute : hydra.hint.StatusLine
---@class hydra.hint.StatusLineMute : hydra.hint.ManualStatusLine
---@field config nil
local HintStatusLineMute = class(HintStatusLine)
local HintStatusLineMute = class(HintManualStatusLine)

function HintStatusLineMute:initialize(input)
HintStatusLine.initialize(self, input)
HintManualStatusLine.initialize(self, input)
end

---@param do_return? boolean Do return statusline hint string?
Expand All @@ -74,6 +152,7 @@ end

--------------------------------------------------------------------------------

M.HintStatusLine = HintStatusLine
M.HintAutoStatusLine = HintAutoStatusLine
M.HintManualStatusLine = HintManualStatusLine
M.HintStatusLineMute = HintStatusLineMute
return M
Loading

0 comments on commit 56cf39c

Please sign in to comment.