From afa40bebc83679ea36ceb5d7e0de5989230ae2b8 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Thu, 17 Oct 2024 21:23:42 +0200 Subject: [PATCH 01/13] Add find textbox --- lib/awful/hotkeys_popup/widget.lua | 52 ++++++++++++++++++------------ 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index 20fb3d77bc..29362333e8 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -628,6 +628,10 @@ function widget.new(args) local wibox_width = (self.width < wa.width) and self.width or (wa.width - self.border_width * 2) + local find_textbox = wibox.widget.textbox("", true) + local find_textbox_container = wibox.container.margin(find_textbox, self.group_margin, self.group_margin, self.group_margin, self.group_margin) + local find_textbox_height = wibox.widget.textbox.get_markup_geometry("X", s).height + 2 * self.group_margin + -- arrange hotkey groups into columns local column_layouts = {} for _, group in ipairs(available_groups) do @@ -636,7 +640,7 @@ function widget.new(args) self._additional_hotkeys[group] ) if #keys > 0 then - self:_create_group_columns(column_layouts, group, keys, s, wibox_height) + self:_create_group_columns(column_layouts, group, keys, s, wibox_height - find_textbox_height) end end @@ -645,12 +649,16 @@ function widget.new(args) local pages = {} local columns = wibox.layout.fixed.horizontal() local previous_page_last_layout + local function add_page() + local page_widget = wibox.layout.align.vertical(nil, columns, find_textbox_container) + table.insert(pages, page_widget) + end for _, item in ipairs(column_layouts) do if item.max_width > available_width_px then previous_page_last_layout:add( self:_group_label("PgDn - Next Page", self.label_bg) ) - table.insert(pages, columns) + add_page() columns = wibox.layout.fixed.horizontal() available_width_px = wibox_width - item.max_width item.layout:insert( @@ -665,7 +673,7 @@ function widget.new(args) columns:add(column_margin) previous_page_last_layout = item.layout end - table.insert(pages, columns) + add_page() -- Function to place the widget in the center and account for the -- workarea. This will be called in the placement field of the @@ -693,6 +701,7 @@ function widget.new(args) local widget_obj = { current_page = 1, popup = mypopup, + find_textbox = find_textbox, } -- Set up the mouse buttons to hide the popup @@ -715,12 +724,29 @@ function widget.new(args) end function widget_obj.show(w_self) w_self.popup.visible = true + awful.prompt.run { + textbox = w_self.find_textbox, + changed_callback = function(input) + end, + done_callback = function() + w_self:hide() + end, + keypressed_callback = function(_, key) + if key == "Return" or key == "KP_Enter" then + return true + elseif key == "Prior" or key == "Up" then + w_self:page_prev() + return true + elseif key == "Next" or key == "Down" then + w_self:page_next() + return true + end + end, + } end function widget_obj.hide(w_self) + awful.keygrabber.stop() w_self.popup.visible = false - if w_self.keygrabber then - awful.keygrabber.stop(w_self.keygrabber) - end end return widget_obj @@ -776,20 +802,6 @@ function widget.new(args) end local help_wibox = self._cached_wiboxes[s][joined_groups] help_wibox:show() - - help_wibox.keygrabber = awful.keygrabber.run(function(_, key, event) - if event == "release" then return end - if key then - if key == "Next" then - help_wibox:page_next() - elseif key == "Prior" then - help_wibox:page_prev() - else - help_wibox:hide() - end - end - end) - return help_wibox.keygrabber end --- Add hotkey descriptions for third-party applications. From fff78956fd6c9e165d35ac8c550bbff5942f42f4 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Thu, 17 Oct 2024 23:55:19 +0200 Subject: [PATCH 02/13] Add searching --- lib/awful/hotkeys_popup/widget.lua | 212 +++++++++++++++++++++++++---- 1 file changed, 183 insertions(+), 29 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index 29362333e8..954c8a3b2f 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -69,6 +69,8 @@ local capi = { screen = screen, client = client, } +local table = table +local string = string local awful = require("awful") local gtable = require("gears.table") local gstring = require("gears.string") @@ -81,9 +83,15 @@ local matcher = require("gears.matcher")() -- Stripped copy of this module https://github.com/copycat-killer/lain/blob/master/util/markup.lua: local markup = {} +function markup.font_start(font) + return '' +end +function markup.font_end() + return '' +end -- Set the font. function markup.font(font, text) - return '' .. tostring(text) ..'' + return markup.font_start(font) .. tostring(text) .. markup.font_end() end -- Set the foreground. function markup.fg(color, text) @@ -371,6 +379,20 @@ function widget.new(args) beautiful.hotkeys_description_font or "Monospace 8" self.group_margin = args.group_margin or beautiful.hotkeys_group_margin or dpi(6) + self.highlight_bg = args.highlight_bg or + beautiful.hotkeys_highlight_bg or "#ffff00" + self.highlight_fg = args.highlight_fg or + beautiful.hotkeys_highlight_fg or "#000000" + self.find_prompt = args.find_prompt or + beautiful.hotkeys_find_prompt or "Find: " + self.find_fg_cursor = args.find_fg_cursor or + beautiful.hotkeys_find_fg_cursor + self.find_bg_cursor = args.find_bg_cursor or + beautiful.hotkeys_find_bg_cursor + self.find_ul_cursor = args.find_ul_cursor or + beautiful.hotkeys_find_ul_cursor + self.find_font = args.find_font or + beautiful.hotkeys_find_font or self.font self.label_colors = beautiful.xresources.get_current_theme() self._widget_settings_loaded = true end @@ -523,14 +545,86 @@ function widget.new(args) return margin end - function widget_instance:_create_group_columns(column_layouts, group, keys, s, wibox_height) + function widget_instance:_render_hotkey(label, find_keywords) + local rendered_text = label.text or "" + + if #rendered_text > 0 and find_keywords and #find_keywords > 0 then + local text = string.lower(rendered_text) + + local parts = {} + local found_keyword_count = 0 + + local function is_available(from, to) + for _, s in ipairs(parts) do + if from <= s.to and to >= s.from then + return false + end + end + return true + end + + for _, keyword in ipairs(find_keywords) do + local from, to = 1, nil + while true do + from, to = string.find(text, keyword, from, true) + if not from then + break + end + if is_available(from, to) then + table.insert(parts, { highlight = true, from = from, to = to }) + found_keyword_count = found_keyword_count + 1 + break + end + from = to + 1 + end + end + + if found_keyword_count == #find_keywords then + table.sort(parts, function(a, b) return a.from < b.from end) + + local merged_parts = {} + local length = #text + local next_part = parts[1] + local i = 1 + while i <= length do + if next_part then + if next_part.from == i then + table.insert(merged_parts, next_part) + i = next_part.to + 1 + table.remove(parts, 1) + next_part = parts[1] + else + table.insert(merged_parts, { from = i, to = next_part.from - 1 }) + i = next_part.from + end + else + table.insert(merged_parts, { from = i, to = length }) + break + end + end + + rendered_text = table.concat(gtable.map(function(part) + local capture = string.sub(text, part.from, part.to) + if part.highlight then + return markup.bg(self.highlight_bg, markup.fg(self.highlight_fg, capture)) + else + return capture + end + end, merged_parts), "") + end + end + + return label.prefix .. rendered_text .. label.suffix + end + + function widget_instance:_create_group_columns(column_layouts, group, keys, s, wibox_height, find_data) local line_height = math.max( beautiful.get_font_height(self.font), beautiful.get_font_height(self.description_font) ) local group_label_height = line_height + self.group_margin -- -1 for possible pagination: - local max_height_px = wibox_height - group_label_height + local max_height_px = wibox_height - group_label_height - find_data.height local joined_descriptions = "" for i, key in ipairs(keys) do @@ -569,6 +663,7 @@ function widget.new(args) current_column.layout:add(self:_group_label(group)) local function insert_keys(ik_keys, ik_add_new_column) + local labels = {} local max_label_width = 0 local joined_labels = "" for i, key in ipairs(ik_keys) do @@ -589,18 +684,25 @@ function widget.new(args) elseif key.key then key_label = gstring.xml_escape(key.key) end - local rendered_hotkey = markup.font(self.font, - modifiers .. key_label .. " " - ) .. markup.font(self.description_font, - key.description or "" - ) + local label = { + prefix = markup.font(self.font, modifiers .. key_label .. " ") .. markup.font_start(self.description_font), + suffix = markup.font_end(), + text = tostring(key.description or ""), + } + table.insert(labels, label) + local rendered_hotkey = self:_render_hotkey(label) local label_width = wibox.widget.textbox.get_markup_geometry(rendered_hotkey, s).width if label_width > max_label_width then max_label_width = label_width end joined_labels = joined_labels .. rendered_hotkey .. (i~=#ik_keys and "\n" or "") - end - current_column.layout:add(wibox.widget.textbox(joined_labels)) + end + local textbox = wibox.widget.textbox(joined_labels) + current_column.layout:add(textbox) + table.insert(find_data.rows, { + textbox = textbox, + labels = labels, + }) local max_width = max_label_width + self.group_margin if not current_column.max_width or (max_width > current_column.max_width) then current_column.max_width = max_width @@ -620,17 +722,7 @@ function widget.new(args) end end - function widget_instance:_create_wibox(s, available_groups, show_awesome_keys) - s = get_screen(s) - local wa = s.workarea - local wibox_height = (self.height < wa.height) and self.height or - (wa.height - self.border_width * 2) - local wibox_width = (self.width < wa.width) and self.width or - (wa.width - self.border_width * 2) - - local find_textbox = wibox.widget.textbox("", true) - local find_textbox_container = wibox.container.margin(find_textbox, self.group_margin, self.group_margin, self.group_margin, self.group_margin) - local find_textbox_height = wibox.widget.textbox.get_markup_geometry("X", s).height + 2 * self.group_margin + function widget_instance:_create_pages(s, available_groups, show_awesome_keys, wibox_width, wibox_height, find_data) -- arrange hotkey groups into columns local column_layouts = {} @@ -640,7 +732,7 @@ function widget.new(args) self._additional_hotkeys[group] ) if #keys > 0 then - self:_create_group_columns(column_layouts, group, keys, s, wibox_height - find_textbox_height) + self:_create_group_columns(column_layouts, group, keys, s, wibox_height, find_data) end end @@ -650,7 +742,7 @@ function widget.new(args) local columns = wibox.layout.fixed.horizontal() local previous_page_last_layout local function add_page() - local page_widget = wibox.layout.align.vertical(nil, columns, find_textbox_container) + local page_widget = wibox.layout.align.vertical(nil, columns, find_data.container) table.insert(pages, page_widget) end for _, item in ipairs(column_layouts) do @@ -675,6 +767,35 @@ function widget.new(args) end add_page() + return pages + end + + function widget_instance:_create_find_data() + local margin = self.group_margin + local textbox = wibox.widget.textbox("", true) + local container = wibox.container.margin(textbox, margin, margin, margin, margin) + local height = beautiful.get_font_height(self.find_font) + 2 * margin + return { + textbox = textbox, + container = container, + height = height, + rows = {}, + last_query = "", + } + end + + function widget_instance:_create_wibox(s, available_groups, show_awesome_keys) + s = get_screen(s) + local wa = s.workarea + local wibox_height = (self.height < wa.height) and self.height or + (wa.height - self.border_width * 2) + local wibox_width = (self.width < wa.width) and self.width or + (wa.width - self.border_width * 2) + + local find_data = self:_create_find_data() + + local pages = self:_create_pages(s, available_groups, show_awesome_keys, wibox_width, wibox_height, find_data) + -- Function to place the widget in the center and account for the -- workarea. This will be called in the placement field of the -- awful.popup constructor. @@ -701,7 +822,7 @@ function widget.new(args) local widget_obj = { current_page = 1, popup = mypopup, - find_textbox = find_textbox, + find_data = find_data, } -- Set up the mouse buttons to hide the popup @@ -723,18 +844,22 @@ function widget.new(args) w_self.popup:set_widget(pages[w_self.current_page]) end function widget_obj.show(w_self) - w_self.popup.visible = true + w_self:find(nil) awful.prompt.run { - textbox = w_self.find_textbox, + textbox = w_self.find_data.textbox, + prompt = self.find_prompt, + fg_cursor = self.find_fg_cursor, + bg_cursor = self.find_bg_cursor, + ul_cursor = self.find_ul_cursor, + font = self.find_font, changed_callback = function(input) + w_self:find(input) end, done_callback = function() w_self:hide() end, keypressed_callback = function(_, key) - if key == "Return" or key == "KP_Enter" then - return true - elseif key == "Prior" or key == "Up" then + if key == "Prior" or key == "Up" then w_self:page_prev() return true elseif key == "Next" or key == "Down" then @@ -743,11 +868,40 @@ function widget.new(args) end end, } + w_self.popup.visible = true end function widget_obj.hide(w_self) awful.keygrabber.stop() w_self.popup.visible = false end + function widget_obj.find(w_self, input) + local keywords = {} + for keyword in string.gmatch(input or "", "([^%s]+)") do + keyword = string.lower(keyword) + if #keyword > 0 and not keywords[keyword] then + keywords[keyword] = true + if pcall(string.find, "", keyword) then + table.insert(keywords, keyword) + end + end + end + + table.sort(keywords, function(a, b) return #a > #b end) + + local query = table.concat(keywords, " ") + if w_self.find_data.last_query == query then + return + end + w_self.find_data.last_query = query + + for _, row in ipairs(w_self.find_data.rows) do + local rendered_hotkeys = {} + for _, label in ipairs(row.labels) do + table.insert(rendered_hotkeys, self:_render_hotkey(label, keywords)) + end + row.textbox:set_markup(table.concat(rendered_hotkeys, "\n")) + end + end return widget_obj end From d073a831889b20ff1724f538706184e73fcea039 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Fri, 18 Oct 2024 00:41:22 +0200 Subject: [PATCH 03/13] Rename property --- lib/awful/hotkeys_popup/widget.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index 954c8a3b2f..8ff4cf5671 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -699,7 +699,7 @@ function widget.new(args) end local textbox = wibox.widget.textbox(joined_labels) current_column.layout:add(textbox) - table.insert(find_data.rows, { + table.insert(find_data.groups, { textbox = textbox, labels = labels, }) @@ -779,7 +779,7 @@ function widget.new(args) textbox = textbox, container = container, height = height, - rows = {}, + groups = {}, last_query = "", } end @@ -894,7 +894,7 @@ function widget.new(args) end w_self.find_data.last_query = query - for _, row in ipairs(w_self.find_data.rows) do + for _, row in ipairs(w_self.find_data.groups) do local rendered_hotkeys = {} for _, label in ipairs(row.labels) do table.insert(rendered_hotkeys, self:_render_hotkey(label, keywords)) From ed55dbe1e726f161faec9276581ea7f58a488f14 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Fri, 18 Oct 2024 00:55:18 +0200 Subject: [PATCH 04/13] Add theme variable `find_margin` --- lib/awful/hotkeys_popup/widget.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index 8ff4cf5671..6782336074 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -393,6 +393,8 @@ function widget.new(args) beautiful.hotkeys_find_ul_cursor self.find_font = args.find_font or beautiful.hotkeys_find_font or self.font + self.find_margin = args.find_margin or + beautiful.hotkeys_find_margin or self.group_margin self.label_colors = beautiful.xresources.get_current_theme() self._widget_settings_loaded = true end @@ -771,8 +773,8 @@ function widget.new(args) end function widget_instance:_create_find_data() - local margin = self.group_margin - local textbox = wibox.widget.textbox("", true) + local margin = self.find_margin + local textbox = wibox.widget.textbox() local container = wibox.container.margin(textbox, margin, margin, margin, margin) local height = beautiful.get_font_height(self.find_font) + 2 * margin return { From 1db1aba7e904c866761f9198bf9ebb7b7a5fe460 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Fri, 18 Oct 2024 00:56:37 +0200 Subject: [PATCH 05/13] Fix rendering label --- lib/awful/hotkeys_popup/widget.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index 6782336074..19298ab137 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -606,7 +606,7 @@ function widget.new(args) end rendered_text = table.concat(gtable.map(function(part) - local capture = string.sub(text, part.from, part.to) + local capture = string.sub(rendered_text, part.from, part.to) if part.highlight then return markup.bg(self.highlight_bg, markup.fg(self.highlight_fg, capture)) else From 6dc87960ad941c607b831cf8cd6184f4c8914210 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Fri, 18 Oct 2024 01:24:51 +0200 Subject: [PATCH 06/13] Add documentation --- lib/awful/hotkeys_popup/widget.lua | 58 ++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index 19298ab137..30e8624345 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -274,6 +274,38 @@ widget.labels = { -- @beautiful beautiful.hotkeys_group_margin -- @tparam int hotkeys_group_margin +--- The highlighted text background color. +-- @beautiful beautiful.hotkeys_highlight_bg +-- @tparam color hotkeys_highlight_bg + +--- The highlighted text foreground color. +-- @beautiful beautiful.hotkeys_highlight_fg +-- @tparam color hotkeys_highlight_fg + +--- The find prompt cursor foreground color. +-- @beautiful beautiful.hotkeys_find_fg_cursor +-- @tparam color hotkeys_find_fg_cursor + +--- The find prompt cursor background color. +-- @beautiful beautiful.hotkeys_find_bg_cursor +-- @tparam color hotkeys_find_bg_cursor + +--- The find prompt cursor underline style. +-- @beautiful beautiful.hotkeys_find_ul_cursor +-- @tparam string hotkeys_find_ul_cursor + +--- The find prompt text. +-- @beautiful beautiful.hotkeys_find_prompt +-- @tparam string hotkeys_find_prompt + +--- The find prompt text font. +-- @beautiful beautiful.hotkeys_find_font +-- @tparam string|lgi.Pango.FontDescription hotkeys_find_font + +--- Margin around the find prompt. +-- @beautiful beautiful.hotkeys_find_margin +-- @tparam int hotkeys_find_margin + --- Create an instance of widget with hotkeys help. -- @tparam[opt] table args Configuration options for the widget. @@ -296,6 +328,14 @@ widget.labels = { -- @tparam[opt] color args.label_fg Foreground color used for group and other -- labels. -- @tparam[opt] int args.group_margin Margin between hotkeys groups. +-- @tparam[opt] color args.highlight_bg The highlighted text background color. +-- @tparam[opt] color args.highlight_fg The highlighted text foreground color. +-- @tparam[opt] color args.find_fg_cursor The find prompt cursor foreground color. +-- @tparam[opt] color args.find_bg_cursor The find prompt cursor background color. +-- @tparam[opt] string args.find_ul_cursor The find prompt cursor underline style. +-- @tparam[opt] string args.find_prompt The find prompt text. +-- @tparam[opt] string|lgi.Pango.FontDescription args.find_font The find prompt text font. +-- @tparam[opt] int args.find_margin Margin around the find prompt. -- @tparam[opt] table args.labels Labels used for displaying human-readable keynames. -- @tparam[opt] table args.group_rules Rules for showing 3rd-party hotkeys. @see `awful.hotkeys_popup.keys.vim`. -- @return Widget instance. @@ -311,6 +351,14 @@ widget.labels = { -- @usebeautiful beautiful.hotkeys_font -- @usebeautiful beautiful.hotkeys_description_font -- @usebeautiful beautiful.hotkeys_group_margin +-- @usebeautiful beautiful.hotkeys_highlight_bg +-- @usebeautiful beautiful.hotkeys_highlight_fg +-- @usebeautiful beautiful.hotkeys_find_fg_cursor +-- @usebeautiful beautiful.hotkeys_find_bg_cursor +-- @usebeautiful beautiful.hotkeys_find_ul_cursor +-- @usebeautiful beautiful.hotkeys_find_prompt +-- @usebeautiful beautiful.hotkeys_find_font +-- @usebeautiful beautiful.hotkeys_find_margin -- @usebeautiful beautiful.bg_normal Fallback. -- @usebeautiful beautiful.fg_normal Fallback. -- @usebeautiful beautiful.fg_minimize Fallback. @@ -828,8 +876,6 @@ function widget.new(args) } -- Set up the mouse buttons to hide the popup - -- Any keybinding except what the keygrabber wants wil hide the popup - -- too mypopup.buttons = { awful.button({ }, 1, function () widget_obj:hide() end), awful.button({ }, 3, function () widget_obj:hide() end) @@ -915,8 +961,7 @@ function widget.new(args) -- @tparam[opt={}] table show_args Additional arguments. -- @tparam[opt=true] boolean show_args.show_awesome_keys Show AwesomeWM hotkeys. -- When set to `false` only app-specific hotkeys will be shown. - -- @treturn awful.keygrabber The keybrabber used to detect when the key is - -- released. + -- @noreturn -- @method show_help function widget_instance:show_help(c, s, show_args) show_args = show_args or {} @@ -1009,11 +1054,10 @@ end -- @tparam[opt] table args Additional arguments. -- @tparam[opt=true] boolean args.show_awesome_keys Show AwesomeWM hotkeys. -- When set to `false` only app-specific hotkeys will be shown. --- @treturn awful.keygrabber The keybrabber used to detect when the key is --- released. +-- @noreturn -- @staticfct awful.hotkeys_popup.widget.show_help function widget.show_help(...) - return get_default_widget():show_help(...) + get_default_widget():show_help(...) end --- Add hotkey descriptions for third-party applications From 3cca359a54f86bbc815cef2fe2bfab2c5f79bb5f Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Fri, 18 Oct 2024 01:53:49 +0200 Subject: [PATCH 07/13] Refactor --- lib/awful/hotkeys_popup/widget.lua | 39 ++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index 30e8624345..d9c5c3a743 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -791,16 +791,12 @@ function widget.new(args) local pages = {} local columns = wibox.layout.fixed.horizontal() local previous_page_last_layout - local function add_page() - local page_widget = wibox.layout.align.vertical(nil, columns, find_data.container) - table.insert(pages, page_widget) - end for _, item in ipairs(column_layouts) do if item.max_width > available_width_px then previous_page_last_layout:add( self:_group_label("PgDn - Next Page", self.label_bg) ) - add_page() + table.insert(pages, columns) columns = wibox.layout.fixed.horizontal() available_width_px = wibox_width - item.max_width item.layout:insert( @@ -815,7 +811,7 @@ function widget.new(args) columns:add(column_margin) previous_page_last_layout = item.layout end - add_page() + table.insert(pages, columns) return pages end @@ -846,6 +842,8 @@ function widget.new(args) local pages = self:_create_pages(s, available_groups, show_awesome_keys, wibox_width, wibox_height, find_data) + local popup_widget = wibox.layout.align.vertical(nil, pages[1], find_data.container) + -- Function to place the widget in the center and account for the -- workarea. This will be called in the placement field of the -- awful.popup constructor. @@ -855,7 +853,7 @@ function widget.new(args) -- Construct the popup with the widget local mypopup = awful.popup { - widget = pages[1], + widget = popup_widget, ontop = true, bg=self.bg, fg=self.fg, @@ -875,6 +873,21 @@ function widget.new(args) find_data = find_data, } + local function set_page(page) + if page < 1 then + page = 1 + elseif page >= #pages then + page = #pages + end + + if widget_obj.current_page == page then + return + end + widget_obj.current_page = page + + popup_widget:set_middle(pages[page]) + end + -- Set up the mouse buttons to hide the popup mypopup.buttons = { awful.button({ }, 1, function () widget_obj:hide() end), @@ -882,14 +895,10 @@ function widget.new(args) } function widget_obj.page_next(w_self) - if w_self.current_page == #pages then return end - w_self.current_page = w_self.current_page + 1 - w_self.popup:set_widget(pages[w_self.current_page]) + set_page(w_self.current_page + 1) end function widget_obj.page_prev(w_self) - if w_self.current_page == 1 then return end - w_self.current_page = w_self.current_page - 1 - w_self.popup:set_widget(pages[w_self.current_page]) + set_page(w_self.current_page - 1) end function widget_obj.show(w_self) w_self:find(nil) @@ -907,10 +916,10 @@ function widget.new(args) w_self:hide() end, keypressed_callback = function(_, key) - if key == "Prior" or key == "Up" then + if key == "Prior" then w_self:page_prev() return true - elseif key == "Next" or key == "Down" then + elseif key == "Next" then w_self:page_next() return true end From d76fd4b58ffd0fa9a29f969a6fde481cf6f786de Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Fri, 18 Oct 2024 02:11:08 +0200 Subject: [PATCH 08/13] Refactor --- lib/awful/hotkeys_popup/widget.lua | 34 ++++++++++++++---------------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index d9c5c3a743..a9df8b875e 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -403,7 +403,7 @@ function widget.new(args) function widget_instance:_load_widget_settings() if self._widget_settings_loaded then return end self.width = args.width or dpi(1200) - self.height = args.height or dpi(800) + self.height = args.height or dpi(300) self.bg = args.bg or beautiful.hotkeys_bg or beautiful.bg_normal self.fg = args.fg or @@ -595,6 +595,14 @@ function widget.new(args) return margin end + function widget_instance:_render_all_hotkeys(labels, find_keywords) + local rendered_hotkeys = {} + for _, label in ipairs(labels) do + table.insert(rendered_hotkeys, self:_render_hotkey(label, find_keywords)) + end + return table.concat(rendered_hotkeys, "\n") + end + function widget_instance:_render_hotkey(label, find_keywords) local rendered_text = label.text or "" @@ -714,9 +722,7 @@ function widget.new(args) local function insert_keys(ik_keys, ik_add_new_column) local labels = {} - local max_label_width = 0 - local joined_labels = "" - for i, key in ipairs(ik_keys) do + for _, key in ipairs(ik_keys) do local modifiers = key.mod if not modifiers or modifiers == "none" then modifiers = "" @@ -740,26 +746,22 @@ function widget.new(args) text = tostring(key.description or ""), } table.insert(labels, label) - local rendered_hotkey = self:_render_hotkey(label) - local label_width = wibox.widget.textbox.get_markup_geometry(rendered_hotkey, s).width - if label_width > max_label_width then - max_label_width = label_width - end - joined_labels = joined_labels .. rendered_hotkey .. (i~=#ik_keys and "\n" or "") end - local textbox = wibox.widget.textbox(joined_labels) + local rendered_hotkeys = self:_render_all_hotkeys(labels) + local textbox = wibox.widget.textbox(rendered_hotkeys) current_column.layout:add(textbox) table.insert(find_data.groups, { textbox = textbox, labels = labels, }) + local max_label_width = wibox.widget.textbox.get_markup_geometry(rendered_hotkeys, s).width local max_width = max_label_width + self.group_margin if not current_column.max_width or (max_width > current_column.max_width) then current_column.max_width = max_width end -- +1 for group label: current_column.height_px = (current_column.height_px or 0) + - gstring.linecount(joined_labels)*line_height + group_label_height + gstring.linecount(rendered_hotkeys)*line_height + group_label_height if ik_add_new_column then table.insert(column_layouts, current_column) end @@ -951,12 +953,8 @@ function widget.new(args) end w_self.find_data.last_query = query - for _, row in ipairs(w_self.find_data.groups) do - local rendered_hotkeys = {} - for _, label in ipairs(row.labels) do - table.insert(rendered_hotkeys, self:_render_hotkey(label, keywords)) - end - row.textbox:set_markup(table.concat(rendered_hotkeys, "\n")) + for _, group in ipairs(w_self.find_data.groups) do + group.textbox:set_markup(self:_render_all_hotkeys(group.labels, keywords)) end end From 24ee110715573894f4d9132790ba0a2ecd072a49 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Fri, 18 Oct 2024 02:17:11 +0200 Subject: [PATCH 09/13] Oops --- lib/awful/hotkeys_popup/widget.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index a9df8b875e..42f27f1c09 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -403,7 +403,7 @@ function widget.new(args) function widget_instance:_load_widget_settings() if self._widget_settings_loaded then return end self.width = args.width or dpi(1200) - self.height = args.height or dpi(300) + self.height = args.height or dpi(800) self.bg = args.bg or beautiful.hotkeys_bg or beautiful.bg_normal self.fg = args.fg or From cdee6b8e482491237f4d114075fb058a35190804 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Sat, 19 Oct 2024 15:02:16 +0200 Subject: [PATCH 10/13] Change fallback colors --- lib/awful/hotkeys_popup/widget.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index 42f27f1c09..d498abfde5 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -428,9 +428,9 @@ function widget.new(args) self.group_margin = args.group_margin or beautiful.hotkeys_group_margin or dpi(6) self.highlight_bg = args.highlight_bg or - beautiful.hotkeys_highlight_bg or "#ffff00" + beautiful.hotkeys_highlight_bg or beautiful.bg_urgent self.highlight_fg = args.highlight_fg or - beautiful.hotkeys_highlight_fg or "#000000" + beautiful.hotkeys_highlight_fg or beautiful.fg_urgent self.find_prompt = args.find_prompt or beautiful.hotkeys_find_prompt or "Find: " self.find_fg_cursor = args.find_fg_cursor or From 41c46af7f77f37ad3a01312bc195d9f6b8512127 Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Sat, 19 Oct 2024 18:53:19 +0200 Subject: [PATCH 11/13] Update tests --- tests/test-awesomerc.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test-awesomerc.lua b/tests/test-awesomerc.lua index 448d25c2b1..407bb2877d 100644 --- a/tests/test-awesomerc.lua +++ b/tests/test-awesomerc.lua @@ -282,12 +282,12 @@ local steps = { if count == 2 then assert(hotkeys_popup ~= nil) assert(hotkeys_popup.visible) - -- Should disappear on anykey - root.fake_input("key_press", "Super_L") + -- Should disappear on escape (awful.prompt) + root.fake_input("key_press", "Escape") elseif count == 3 then assert(not hotkeys_popup.visible) - root.fake_input("key_release", "Super_L") + root.fake_input("key_release", "Escape") test_context.hotkeys01_clients_before = #client.get() -- imitate fake client with name "vim" -- so hotkeys widget will offer vim hotkeys: @@ -314,11 +314,11 @@ local steps = { assert(visible_hotkeys_widget ~= nil) assert(visible_hotkeys_widget.current_page == 2) root.fake_input("key_release", "Next") - -- Should disappear on anykey - root.fake_input("key_press", "Super_L") + -- Should disappear on escape (awful.prompt) + root.fake_input("key_press", "Escape") elseif (count - test_context.hotkeys01_count_vim) == 3 then assert(not visible_hotkeys_widget) - root.fake_input("key_release", "Super_L") + root.fake_input("key_release", "Escape") return true end end From 626bd1818bafd9de3fb2289d34fabae4516c042e Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Sat, 19 Oct 2024 18:53:30 +0200 Subject: [PATCH 12/13] Add "enable_find" option (default: true) --- lib/awful/hotkeys_popup/init.lua | 1 + lib/awful/hotkeys_popup/widget.lua | 48 +++++++++++++++++++----------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/lib/awful/hotkeys_popup/init.lua b/lib/awful/hotkeys_popup/init.lua index 058bae1282..9b019e4398 100644 --- a/lib/awful/hotkeys_popup/init.lua +++ b/lib/awful/hotkeys_popup/init.lua @@ -22,6 +22,7 @@ local hotkeys_popup = { -- see `awful.hotkeys_popup.widget.show_help` for more information -- @tparam[opt] client c The hostkeys for the client "c". -- @tparam[opt] screen s The screen. +-- @tparam[opt=true] boolean show_args.enable_find Enable find. -- @tparam[opt=true] boolean show_args.show_awesome_keys Show AwesomeWM hotkeys. -- When set to `false` only app-specific hotkeys will be shown. -- @staticfct awful.hotkeys_popup.show_help diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index d498abfde5..e272fc83c1 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -682,7 +682,7 @@ function widget.new(args) ) local group_label_height = line_height + self.group_margin -- -1 for possible pagination: - local max_height_px = wibox_height - group_label_height - find_data.height + local max_height_px = wibox_height - group_label_height - find_data.container_height local joined_descriptions = "" for i, key in ipairs(keys) do @@ -818,21 +818,27 @@ function widget.new(args) return pages end - function widget_instance:_create_find_data() - local margin = self.find_margin - local textbox = wibox.widget.textbox() - local container = wibox.container.margin(textbox, margin, margin, margin, margin) - local height = beautiful.get_font_height(self.find_font) + 2 * margin - return { - textbox = textbox, - container = container, - height = height, + function widget_instance:_create_find_data(enable_find) + local data = { + enabled = enable_find, + textbox = wibox.widget.textbox(), groups = {}, last_query = "", } + + if enable_find then + local margin = self.find_margin + data.container = wibox.container.margin(data.textbox, margin, margin, margin, margin) + data.container_height = beautiful.get_font_height(self.find_font) + 2 * margin + else + data.container = wibox.widget.empty + data.container_height = 0 + end + + return data end - function widget_instance:_create_wibox(s, available_groups, show_awesome_keys) + function widget_instance:_create_wibox(s, available_groups, show_awesome_keys, enable_find) s = get_screen(s) local wa = s.workarea local wibox_height = (self.height < wa.height) and self.height or @@ -840,7 +846,7 @@ function widget.new(args) local wibox_width = (self.width < wa.width) and self.width or (wa.width - self.border_width * 2) - local find_data = self:_create_find_data() + local find_data = self:_create_find_data(enable_find) local pages = self:_create_pages(s, available_groups, show_awesome_keys, wibox_width, wibox_height, find_data) @@ -920,10 +926,10 @@ function widget.new(args) keypressed_callback = function(_, key) if key == "Prior" then w_self:page_prev() - return true elseif key == "Next" then w_self:page_next() - return true + elseif not w_self.find_data.enabled then + w_self:hide() end end, } @@ -934,6 +940,10 @@ function widget.new(args) w_self.popup.visible = false end function widget_obj.find(w_self, input) + if not w_self.find_data.enabled then + return + end + local keywords = {} for keyword in string.gmatch(input or "", "([^%s]+)") do keyword = string.lower(keyword) @@ -972,6 +982,7 @@ function widget.new(args) -- @method show_help function widget_instance:show_help(c, s, show_args) show_args = show_args or {} + local enable_find = show_args.enable_find ~= false local show_awesome_keys = show_args.show_awesome_keys ~= false self:_import_awful_keys() @@ -1001,14 +1012,14 @@ function widget.new(args) if not need_match then table.insert(available_groups, group) end end - local joined_groups = join_plus_sort(available_groups)..tostring(show_awesome_keys) + local cache_key = join_plus_sort(available_groups)..tostring(show_awesome_keys)..tostring(enable_find) if not self._cached_wiboxes[s] then self._cached_wiboxes[s] = {} end - if not self._cached_wiboxes[s][joined_groups] then - self._cached_wiboxes[s][joined_groups] = self:_create_wibox(s, available_groups, show_awesome_keys) + if not self._cached_wiboxes[s][cache_key] then + self._cached_wiboxes[s][cache_key] = self:_create_wibox(s, available_groups, show_awesome_keys, enable_find) end - local help_wibox = self._cached_wiboxes[s][joined_groups] + local help_wibox = self._cached_wiboxes[s][cache_key] help_wibox:show() end @@ -1059,6 +1070,7 @@ end -- @tparam[opt] client c Client. -- @tparam[opt] screen s Screen. -- @tparam[opt] table args Additional arguments. +-- @tparam[opt=true] boolean args.enable_find Enable find. -- @tparam[opt=true] boolean args.show_awesome_keys Show AwesomeWM hotkeys. -- When set to `false` only app-specific hotkeys will be shown. -- @noreturn From 38b3f8a67dbc297b5f922920c0e1e6a31529033d Mon Sep 17 00:00:00 2001 From: David Kosorin Date: Sat, 30 Nov 2024 17:38:19 +0100 Subject: [PATCH 13/13] Move `find_prompt` from theme to args --- lib/awful/hotkeys_popup/widget.lua | 43 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/lib/awful/hotkeys_popup/widget.lua b/lib/awful/hotkeys_popup/widget.lua index e272fc83c1..081da28ee8 100644 --- a/lib/awful/hotkeys_popup/widget.lua +++ b/lib/awful/hotkeys_popup/widget.lua @@ -294,10 +294,6 @@ widget.labels = { -- @beautiful beautiful.hotkeys_find_ul_cursor -- @tparam string hotkeys_find_ul_cursor ---- The find prompt text. --- @beautiful beautiful.hotkeys_find_prompt --- @tparam string hotkeys_find_prompt - --- The find prompt text font. -- @beautiful beautiful.hotkeys_find_font -- @tparam string|lgi.Pango.FontDescription hotkeys_find_font @@ -333,7 +329,6 @@ widget.labels = { -- @tparam[opt] color args.find_fg_cursor The find prompt cursor foreground color. -- @tparam[opt] color args.find_bg_cursor The find prompt cursor background color. -- @tparam[opt] string args.find_ul_cursor The find prompt cursor underline style. --- @tparam[opt] string args.find_prompt The find prompt text. -- @tparam[opt] string|lgi.Pango.FontDescription args.find_font The find prompt text font. -- @tparam[opt] int args.find_margin Margin around the find prompt. -- @tparam[opt] table args.labels Labels used for displaying human-readable keynames. @@ -356,7 +351,6 @@ widget.labels = { -- @usebeautiful beautiful.hotkeys_find_fg_cursor -- @usebeautiful beautiful.hotkeys_find_bg_cursor -- @usebeautiful beautiful.hotkeys_find_ul_cursor --- @usebeautiful beautiful.hotkeys_find_prompt -- @usebeautiful beautiful.hotkeys_find_font -- @usebeautiful beautiful.hotkeys_find_margin -- @usebeautiful beautiful.bg_normal Fallback. @@ -431,8 +425,6 @@ function widget.new(args) beautiful.hotkeys_highlight_bg or beautiful.bg_urgent self.highlight_fg = args.highlight_fg or beautiful.hotkeys_highlight_fg or beautiful.fg_urgent - self.find_prompt = args.find_prompt or - beautiful.hotkeys_find_prompt or "Find: " self.find_fg_cursor = args.find_fg_cursor or beautiful.hotkeys_find_fg_cursor self.find_bg_cursor = args.find_bg_cursor or @@ -622,7 +614,8 @@ function widget.new(args) end for _, keyword in ipairs(find_keywords) do - local from, to = 1, nil + local from = 1 + local to while true do from, to = string.find(text, keyword, from, true) if not from then @@ -741,7 +734,8 @@ function widget.new(args) key_label = gstring.xml_escape(key.key) end local label = { - prefix = markup.font(self.font, modifiers .. key_label .. " ") .. markup.font_start(self.description_font), + prefix = markup.font(self.font, modifiers .. key_label .. " ") .. + markup.font_start(self.description_font), suffix = markup.font_end(), text = tostring(key.description or ""), } @@ -818,15 +812,15 @@ function widget.new(args) return pages end - function widget_instance:_create_find_data(enable_find) + function widget_instance:_create_find_data(find_args) local data = { - enabled = enable_find, + enabled = find_args.enabled, textbox = wibox.widget.textbox(), groups = {}, last_query = "", } - if enable_find then + if find_args.enabled then local margin = self.find_margin data.container = wibox.container.margin(data.textbox, margin, margin, margin, margin) data.container_height = beautiful.get_font_height(self.find_font) + 2 * margin @@ -838,7 +832,7 @@ function widget.new(args) return data end - function widget_instance:_create_wibox(s, available_groups, show_awesome_keys, enable_find) + function widget_instance:_create_wibox(s, available_groups, show_awesome_keys, find_args) s = get_screen(s) local wa = s.workarea local wibox_height = (self.height < wa.height) and self.height or @@ -846,7 +840,7 @@ function widget.new(args) local wibox_width = (self.width < wa.width) and self.width or (wa.width - self.border_width * 2) - local find_data = self:_create_find_data(enable_find) + local find_data = self:_create_find_data(find_args) local pages = self:_create_pages(s, available_groups, show_awesome_keys, wibox_width, wibox_height, find_data) @@ -912,7 +906,7 @@ function widget.new(args) w_self:find(nil) awful.prompt.run { textbox = w_self.find_data.textbox, - prompt = self.find_prompt, + prompt = find_args.prompt, fg_cursor = self.find_fg_cursor, bg_cursor = self.find_bg_cursor, ul_cursor = self.find_ul_cursor, @@ -976,15 +970,26 @@ function widget.new(args) -- @tparam[opt=client.focus] client c Client. -- @tparam[opt=c.screen] screen s Screen. -- @tparam[opt={}] table show_args Additional arguments. + -- @tparam[opt=true] boolean show_args.enable_find Enable find feature. + -- @tparam[opt="Find: "] string show_args.find_prompt The find prompt text. -- @tparam[opt=true] boolean show_args.show_awesome_keys Show AwesomeWM hotkeys. -- When set to `false` only app-specific hotkeys will be shown. -- @noreturn -- @method show_help function widget_instance:show_help(c, s, show_args) show_args = show_args or {} - local enable_find = show_args.enable_find ~= false local show_awesome_keys = show_args.show_awesome_keys ~= false + local find_args = { + enabled = show_args.enable_find ~= false, + prompt = type(show_args.find_prompt) == "string" + and show_args.find_prompt + or "Find: ", + get_cache_key = function(self) + return tostring(self.enabled) .. self.prompt + end, + } + self:_import_awful_keys() self:_load_widget_settings() @@ -1012,12 +1017,12 @@ function widget.new(args) if not need_match then table.insert(available_groups, group) end end - local cache_key = join_plus_sort(available_groups)..tostring(show_awesome_keys)..tostring(enable_find) + local cache_key = join_plus_sort(available_groups)..tostring(show_awesome_keys)..find_args:get_cache_key() if not self._cached_wiboxes[s] then self._cached_wiboxes[s] = {} end if not self._cached_wiboxes[s][cache_key] then - self._cached_wiboxes[s][cache_key] = self:_create_wibox(s, available_groups, show_awesome_keys, enable_find) + self._cached_wiboxes[s][cache_key] = self:_create_wibox(s, available_groups, show_awesome_keys, find_args) end local help_wibox = self._cached_wiboxes[s][cache_key] help_wibox:show()