Skip to content

Commit

Permalink
feat: add detection of button under cursor
Browse files Browse the repository at this point in the history
Also resizes the keyboard window
  • Loading branch information
jokajak committed Jul 10, 2023
1 parent 1960571 commit 295ba8b
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 57 deletions.
4 changes: 3 additions & 1 deletion lua/keyseer/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,16 @@ KeySeer.config = {
-- Initial neovim mode to display keybindings
initial_mode = "n",

-- TODO: Represent modifier toggling in highlights
include_modifiers = false,
-- Boolean to include built in keymaps in display
include_builtin_keymaps = false,
-- Boolean to include global keymaps in display
include_global_keymaps = true,
-- Boolean to include buffer keymaps in display
include_buffer_keymaps = true,
-- TODO: Represent modifier toggling in highlights
-- Boolean to include modified keys (e.g. <C-x> or <A-y> or C) in display
include_modified_keypresses = false,

-- Configuration for ui:
-- - `height` and `width` are maximum dimensions.
Expand Down
9 changes: 9 additions & 0 deletions lua/keyseer/keyboard/button.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ function Button:new(keycap, keycode, row_index, padding_box, highlight_box)
keycode = keycode,
left_pad = left_pad,
right_pad = right_pad,
top_row = row - top_pad,
row = row,
bottom_row = row + bottom_pad,
width = left_pad + keycap_width + right_pad,
is_modifier = modifiers[keycode] or false,
_keycap_width = keycap_width,
Expand Down Expand Up @@ -189,6 +191,13 @@ function Button:set_button_byte_position(col)
self.right_byte_col = col + self.width
end

---Set the start column for the button
---@param col integer The start column
function Button:set_button_start_col(col)
self.left_col = col
self.right_col = col + self.width
end

---Highlight a buffer
---@param bufnr buffer A buffer
---@param namespace number The namespace for the highlights
Expand Down
65 changes: 40 additions & 25 deletions lua/keyseer/keyboard/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
-- Each button on the keyboard can be highlighted
local Button = require("keyseer.keyboard.button")
local Utils = require("keyseer.utils")
local D = require("keyseer.util.debug")

-- Border characters for buttons
local _borders = {
Expand Down Expand Up @@ -72,7 +73,7 @@ end
---@field private _shifted_buttons Button[] A mapping table from keycode to button when shift is pressed
---@field private _normal_lines string[] The string representation of the keyboard without shift pressed
---@field private _shifted_lines string[] The string representation of the keyboard with shift pressed
---@field private _locations Button[] A table of button positions
---@field private _locations Button[] A table of buttons for their position
local Keyboard = {}
Keyboard.__index = Keyboard

Expand Down Expand Up @@ -361,44 +362,55 @@ end
---Return button at coordinates
---@param row integer
---@param col integer
---@return Button ret the button at the position
function Keyboard:get_keycap_at_position(row, col)
-- We need to convert the row to a row index
-- Each row is keycap_height + top_padding + bottom_padding tall
-- We need to convert the col to a column index
-- Converting a column back to a column index is hard because the buttons are different width
print("Looking for " .. row .. " and " .. col)
print("Not yet implemented")
local ret = nil
D.log("Keyboard", "Looking for keycap under " .. row .. ", " .. col)
for _, keycaps in pairs(self._locations) do
for _, button in pairs(keycaps) do
D.log("Keyboard", string.format("Checking button: %s", button.keycap))
if button.top_row <= row and button.bottom_row >= row then
if button.left_col < col and button.right_col >= col then
if not ret then
ret = button
else
Utils.notify("Found multiple matching buttons!")
end
end
end
D.log(
"Keyboard",
string.format(
"%s: (%d, %d) and (%d, %d)",
button.keycap,
button.top_row,
button.bottom_row,
button.left_col,
button.right_col
)
)
end
end
if ret then
Utils.notify(string.format("Found %s!", ret.keycap))
end
return ret
end

---Populate lines in a display
---@param ui KeySeerUI The UI to display to
---@param keycaps KeyMapTreeNode The keycaps to display
---@return number height The height of the window
---@return number width The width of the window
function Keyboard:populate_lines(ui, keycaps)
-- generate a string representation of the layout, e.g.
-- ┌──────┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬──────┐
-- │ ` │1│2│3│4│5│6│7│8│9│0│-│=│ <BS> │
-- ├──────┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼──────┤
-- │<TAB> │q│w│e│r│t│y│u│i│o│p│[│]│ \ │
-- ├──────┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┴──────┤
-- │<CAPS>│a│s│d│f│g│h│j│k│l│;│'│ <ENTER>│
-- ├──────┴─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼────────┤
-- │<SHIFT> │z│x│c│v│b│n│m│,│.│/│ <SHIFT>│
-- └────────┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴────────┘
-- ┌───────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬──────┐
-- │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │ <BS> │
-- ├───────┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼──────┤
-- │ <TAB> │ q │ w │ e │ r │ t │ y │ u │ i │ o │ p │ [ │ ] │ \ │
-- ├───────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴──────┤
-- │ <CAPS> │ a │ s │ d │ f │ g │ h │ j │ k │ l │ ; │ ' │ <ENTER> │
-- ├────────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─────────┤
-- │ <SHIFT> │ z │ x │ c │ v │ b │ n │ m │ , │ . │ / │ <SHIFT> │
-- └──────────┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───────────┘
local display = ui.render
local shift_pressed = ui.state.modifiers.shift
local button_lookup = Utils.default_table()
if shift_pressed then
button_lookup = self._shifted_buttons
end
self._locations = button_lookup

local rows = {}
local keycap_separator_columns = {}
Expand Down Expand Up @@ -459,6 +471,7 @@ function Keyboard:populate_lines(ui, keycaps)
local row_text = _borders["ss "]
keycap_separator_columns[row_index] = {}
for _, button in ipairs(row) do
button:set_button_start_col(row_length + 1)
row_text = row_text .. tostring(button) .. _borders["ss "]
local start_col, _ = Utils.get_str_bytes(row_text, row_length + 1, row_length + button.width)
button:set_button_byte_position(start_col)
Expand Down Expand Up @@ -534,5 +547,7 @@ function Keyboard:populate_lines(ui, keycaps)
end
display:nl()
end
D.log("Keyboard", string.format("Columns: %d", display:col()))
return display:row(), display:col()
end
return Keyboard
31 changes: 13 additions & 18 deletions lua/keyseer/ui/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ function M.visible()
return M.ui and M.ui.win and vim.api.nvim_win_is_valid(M.ui.win)
end

local function get_button_under_cursor(ui)
local cursorposition = vim.fn.getcursorcharpos(ui.win)
local row, col = cursorposition[2], cursorposition[3]
-- size of the title is statically calculated
local row_offset = 4
D.log("UI", "Button row, col: " .. row - row_offset .. ", " .. col)
---@type Keyboard
local keyboard = ui.state.keyboard
local button = keyboard:get_keycap_at_position(row - row_offset, col)
return button
end

---@param pane? string The starting pane
---@param mode? string The neovim mode for keymaps
---@param bufnr? integer The buffer for keymaps
Expand Down Expand Up @@ -80,7 +92,7 @@ function M.create(bufnr)
for k, v in pairs(UIConfig.panes) do
self:on_key(v["key"], function()
if self.state.pane == "home" then
local button = self.render:get_button()
local button = get_button_under_cursor(self)
if button then
self.state.button = button
end
Expand Down Expand Up @@ -112,23 +124,6 @@ function M.create(bufnr)
end
end

-- open details for the keycap under the cursor
self:on_key(UIConfig.keys.details, function()
if self.state.pane == "home" then
local button = self.render:get_button()
if button then
if button.is_modifier then
self.state.modifiers[button.keycode] = not self.state.modifiers[button.keycode]
else
self.state.button = button
self.state.prev_pane = self.state.pane
self.state.pane = "details"
end
self:update()
end
end
end)

return self
end

Expand Down
38 changes: 37 additions & 1 deletion lua/keyseer/ui/panes/home.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ local M = {

function M.render(ui)
local current_keycaps = ui.state.keymaps:get_current_keycaps(ui.state.modifiers)
ui.state.keyboard:populate_lines(ui, current_keycaps)
local height, width = ui.state.keyboard:populate_lines(ui, current_keycaps)
D.log("UI", string.format("Resizing to %dx%d (HxW)", height, width))
ui.win_opts.height = height - 1
ui.opts.size.height = height - 1
if width ~= 0 then
ui.win_opts.width = width
ui.opts.size.width = width
end
ui:layout()
for _, keypress in pairs(ui.state.current_keymaps) do
vim.keymap.del("n", "g" .. keypress, { buffer = ui.buf })
end
Expand All @@ -37,6 +45,18 @@ function M.render(ui)
end
end

local function get_button_under_cursor(ui)
local cursorposition = vim.fn.getcursorcharpos(ui.win)
local row, col = cursorposition[2], cursorposition[3]
-- size of the title is statically calculated
local row_offset = 4
D.log("UI", "Button row, col: " .. row - row_offset .. ", " .. col)
---@type Keyboard
local keyboard = ui.state.keyboard
local button = keyboard:get_keycap_at_position(row - row_offset, col)
return button
end

---Update keymaps when entering the pane
function M.on_enter(ui)
-- for _, keypress in pairs(ui.state.current_keymaps) do
Expand All @@ -51,6 +71,21 @@ function M.on_enter(ui)
ui.state.keymaps:pop()
ui:update()
end, { buffer = ui.buf })

-- open details for the keycap under the cursor
vim.keymap.set("n", UIConfig.keys.details, function()
local button = get_button_under_cursor(ui)
if button then
if button.is_modifier then
ui.state.modifiers[button.keycode] = not ui.state.modifiers[button.keycode]
else
ui.state.button = button
ui.state.prev_pane = ui.state.pane
ui.state.pane = "details"
end
ui:update()
end
end, { buffer = ui.buf })
end

---Update keymaps when exiting the pane
Expand All @@ -61,6 +96,7 @@ function M.on_exit(ui)
end
ui.state.current_keymaps = {}
vim.keymap.del("n", UIConfig.keys.back, { buffer = ui.buf })
vim.keymap.del("n", UIConfig.keys.details, { buffer = ui.buf })
end

return M
11 changes: 0 additions & 11 deletions lua/keyseer/ui/render.lua
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,4 @@ function M:title()
self:nl():nl()
end

function M:get_button()
if not (self.ui.win and vim.api.nvim_win_is_valid(self.ui.win)) then
return
end
if not (self.ui.state.pane == "home") then
return
end
local cursorposition = vim.fn.getcursorcharpos(self.ui.win)
local row, col = cursorposition[1], cursorposition[2]
end

return M
2 changes: 1 addition & 1 deletion lua/keyseer/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ function Utils.default_table()
})
end

---Get the start column and end column
---Get the start column and end column in bytes
---@param line string The string of characters to find byte positions
---@param from number The start column
---@param to number The end column
Expand Down

0 comments on commit 295ba8b

Please sign in to comment.