{"id":15148934,"url":"https://github.com/intrntbrn/modalisa","last_synced_at":"2025-09-29T18:31:29.501Z","repository":{"id":208127110,"uuid":"704643733","full_name":"intrntbrn/modalisa","owner":"intrntbrn","description":"hybrid modal keymap framework for awesomewm","archived":false,"fork":false,"pushed_at":"2023-12-14T23:40:46.000Z","size":373,"stargazers_count":14,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-09-21T20:30:54.661Z","etag":null,"topics":["awesome","awesomewm","hotkey","keybind","keygrabber","leader","modal","picker","plugin","sequence","vim","whichkey"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/intrntbrn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-13T18:02:03.000Z","updated_at":"2024-03-21T14:53:55.000Z","dependencies_parsed_at":"2023-11-19T22:24:56.893Z","dependency_job_id":"c5a9c299-b902-4bfb-bfa3-c457741f8a02","html_url":"https://github.com/intrntbrn/modalisa","commit_stats":null,"previous_names":["intrntbrn/modalisa"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intrntbrn%2Fmodalisa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intrntbrn%2Fmodalisa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intrntbrn%2Fmodalisa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/intrntbrn%2Fmodalisa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/intrntbrn","download_url":"https://codeload.github.com/intrntbrn/modalisa/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219874663,"owners_count":16554606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["awesome","awesomewm","hotkey","keybind","keygrabber","leader","modal","picker","plugin","sequence","vim","whichkey"],"created_at":"2024-09-26T13:40:33.650Z","updated_at":"2025-09-29T18:31:29.116Z","avatar_url":"https://github.com/intrntbrn.png","language":"Lua","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ⌨️ modalisa 🎨\n\n`modalisa` is a hybrid modal keymap framework for AwesomeWM.\nIt combines the best of both traditional and modal input modes while also providing a visually appealing interface.\n\nTraditional input modes in tiling window managers often require\ncomplex keymaps that involve pressing multiple modifiers simultaneously\ndue to limited keyspace. Additionally, users have to rely on their memory or\nunpractical cheatsheets as there are no key suggestions while typing.\nOn the other hand, modal input modes allow for easy entry of key sequences\nbut can become cumbersome when repeating actions. Users either have to\nrepeat the entire sequence or specify a count beforehand, making the process\ninefficient.\n\n`modalisa` addresses these shortcomings by providing a flexible hybrid approach.\nIt keeps track of modifier states to provide distinct input modes that can be tailored to the user's needs for each key and at every stage of the sequence individually.\nIt allows for traditional keybinds for common operations that can be repeated by holding down the modifier,\nwhile also enabling users to tap the modifier (like a leader key) to enter modal mode followed by a key sequence for less common commands.\nThis flexibility makes it possible to transition into a more modal-esque keymap gradually without having to relearn most of the AwesomeWM controls.\n\nIn addition, `modalisa` comes with a preconfigured default keymap that includes improved default AwesomeWM controls (and a lot more) to provide a starting point and to give an overview about the possibilities using this framework.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eWhich Key Hints\u003c/th\u003e\n    \u003cth\u003eAwesomeWM Controls\u003c/th\u003e\n    \u003cth\u003eSystem Controls\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"https://user-images.githubusercontent.com/1234183/284088067-73f1d696-c5ed-47fc-a502-776d9ba718f6.gif\" /\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"https://user-images.githubusercontent.com/1234183/284087983-de9dcb2c-9314-4439-bf70-36bfb33c2ddc.gif\" /\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"https://user-images.githubusercontent.com/1234183/284088055-abcc634d-deb9-4315-b22b-1f82706ad089.gif\" /\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003cth\u003eClient Labels\u003c/th\u003e\n    \u003cth\u003eMouse Menu\u003c/th\u003e\n    \u003cth\u003eFile Picker\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"https://user-images.githubusercontent.com/1234183/284088127-fc91a8b5-40d6-43eb-8d88-3c96a84309ba.gif\" /\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"https://user-images.githubusercontent.com/1234183/284088114-ef598194-7b33-445e-98d8-e5dc14e811aa.gif\" /\u003e\n    \u003c/td\u003e\n    \u003ctd\u003e\n      \u003cimg src=\"https://user-images.githubusercontent.com/1234183/284088084-1cd651c7-4a5b-42b3-8c3d-a72bb5930fd0.gif\" /\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## ✨ Features\n\n- 🪄 Unique input modes\n- 💥 Which key hints with mouse support\n- 🌳 Keymap trees with property inheritance\n- 💄 UI building blocks (prompt, echo, labels)\n- 🌐 Define options for every key individually\n- 🪟 Preconfigured AwesomeWM and system keymap\n- 🧙 Use vim syntax to define key sequences\n- ♿ Easy and intuitive configuration\n- 📡 Highly extensible and customizable (200+ parameters)\n\n## 💡 Example\n\n```\n{\n\t[\"t\"] = { desc = \"tag\", opts = { mode = \"hybrid\", hints = { enabled = true } } },\n\t-- opts are inherited from predecessor t\n\t[\"t\u003cTab\u003e\"] = {\n\t\tdesc = \"view last tag\",\n\t\tfn = function(opts)\n\t\t\tawful.tag.history.restore()\n\t\tend,\n\t},\n\t[\"tD\"] = {\n\t\tdesc = \"delete current tag\",\n\t\topts = { hints = { placement = \"centered\" } },\n\t\tcond = function()\n\t\t\treturn awful.screen.focused().selected_tag.index \u003e 1\n\t\tend,\n\t\tfn = function(opts)\n\t\t\tlocal dynamic_menu = {\n\t\t\t\ty = {\n\t\t\t\t\tdesc = function()\n\t\t\t\t\t\treturn \"yes, delete tag \" .. awful.screen.focused().selected_tag.index\n\t\t\t\t\tend,\n\t\t\t\t\thighlight = { bg = \"#FF0000\", desc = { bold = true } },\n\t\t\t\t\tfunction(opts)\n\t\t\t\t\t\tawful.screen.focused().selected_tag:delete()\n\t\t\t\t\tend,\n\t\t\t\t},\n\t\t\t\tn = { desc = \"no, cancel delete\" },\n\t\t\t}\n\t\t\treturn dynamic_menu\n\t\tend,\n\t},\n}\n```\n\n## ⚠️ Warning\n\n`modalisa` is in early development and breaking changes might occur.\n\n## 📋 Requirements\n\n- awesome-git\n- nerd-font (optional)\n\n## 📦 Installation\n\n1. Clone the repo:\n\n`git clone https://github.com/intrntbrn/modalisa ~/.config/awesome/modalisa`\n\n2. Import and configure the module in `rc.lua`:\n\n```lua\n-- NOTE:\n-- modalisa is designed to be used in conjunction with a modifier as the leader\n-- key (e.g. Super_L), but this prevents all current keybinds utilizing\n-- that modifier from functioning.\nrequire(\"modalisa\").setup({\n\t-- root_keys = { \"\u003cM-a\u003e\" }, -- \"Mod4\" + \"a\"\n\troot_keys = { \"\u003cSuper_L\u003e\" }, -- or \"\u003cAlt_L\u003e\"\n\tback_keys = { \"\u003cBackSpace\u003e\" },\n\tstop_keys = { \"\u003cEscape\u003e\" },\n\tmode = \"hybrid\",\n\tinclude_default_keys = true,\n\t-- try the auto-generated theme first\n\ttheme = {\n\t\t-- fg = \"#eceffc\",\n\t\t-- bg = \"#24283B\",\n\t\t-- grey = \"#959cbc\",\n\t\t-- border = \"#444A73\",\n\t\t-- accent = \"#82AAFF\",\n\t},\n})\n```\n\n### Create Your Own Keymap\n\n1. Copy the default keymap `keys.lua` as `modalisa_keys.lua` into the home AwesomeWM directory:\n\n`cp ~/.config/awesome/modalisa/keys.lua ~/.config/awesome/modalisa_keys.lua`\n\n2. Disable the default keymap by setting `include_default_keys = false` during setup.\n\n3. Edit the copy. Restart AwesomeWM for the changes to take effect.\n\nYou can retrieve keynames by running the command\n\n```sh\nawesome-client \"awesome.emit_signal('modalisa::showkey')\"\n```\n\nfrom the terminal.\nPress any key combination to show the respective keyname.\n\n## ⚙️ Configuration\n\nMost configuration options can be explored interactively by pressing `i` on the\ndefault keymap.\n\n\u003cdetails\u003e\u003csummary\u003eDefault Settings\u003c/summary\u003e\n\n\u003c!-- config:start --\u003e\n\n```lua\n{\n\troot_keys = { \"\u003cM-a\u003e\" },\n\tback_keys = { \"\u003cBackSpace\u003e\" },\n\tstop_keys = { \"\u003cEscape\u003e\" },\n\ttoggle_keys = { \".\" },\n\tinclude_default_keys = true,\n\n\tmode = \"hybrid\", -- \"modal\" | \"hold\" | \"hybrid\" | \"forever\"\n\tsmart_modifiers = true, -- like smartcase but for all root key modifiers\n\tstop_on_unknown_key = false,\n\ttimeout = 0, -- ms\n\tlabels = \"1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\\\"#$%\u0026'()*+,-./:;\u003c=\u003e?@\\\\^_`{|}~\",\n\tignore_shift_state_for_special_characters = true,\n\n\ttoggle_false = \"on\", -- \"\", \"\", \"toggle\", \"on\"\n\ttoggle_true = \"off\", -- \"\", -\"\", \"toggle\", \"off\"\n\n\ttheme = {\n\t\tfg = beautiful.fg_focus or \"#eceffc\",\n\t\tbg = beautiful.bg_focus or \"#24283B\",\n\t\tgrey = beautiful.fg_normal or \"#959cbc\",\n\t\tborder = beautiful.border_color_normal or \"#444A73\",\n\t\taccent = \"#82AAFF\",\n\t},\n\n\thints = {\n\t\tenabled = true,\n\t\tdelay = 0, -- ms\n\t\tshow_header = false,\n\t\tshow_disabled_keys = true,\n\t\tlow_priority = true, -- generate hints when idling\n\t\tsort = \"group\", -- group | id | key | none\n\t\tmouse_button_select = 1, -- left click\n\t\tmouse_button_select_continue = 3, -- right click\n\t\tmouse_button_stop = 2, -- middle click\n\t\tmouse_button_back = 8, -- back click\n\t\tcolor_border = nil,\n\t\tcolor_odd_bg = -8, -- color or luminosity delta\n\t\tcolor_hover_bg = 15, -- color or luminosity delta\n\t\tcolor_disabled_fg = nil,\n\t\tfont_header = \"Monospace 12\",\n\t\tcolor_header_fg = nil,\n\t\tcolor_header_bg = nil,\n\t\thighlight = {\n\t\t\tbg = nil,\n\t\t\tkey = {\n\t\t\t\tfont = \"Monospace 12\",\n\t\t\t},\n\t\t\tdesc = {\n\t\t\t\tfont = \"Monospace 12\",\n\t\t\t\titalic = true,\n\t\t\t},\n\t\t\tseparator = {\n\t\t\t\tfont = \"Monospace 12\",\n\t\t\t},\n\t\t},\n\t\tmenu_highlight = {\n\t\t\tdesc = {\n\t\t\t\tbold = true,\n\t\t\t},\n\t\t},\n\t\tgroup_highlights = {\n\t\t\t-- [\"^awesome\"] = {\n\t\t\t-- \tdesc = {\n\t\t\t-- \t\tunderline = true,\n\t\t\t-- \t},\n\t\t\t-- },\n\t\t},\n\t\tseparator = \" ➜ \",\n\t\tentry_key_width = 5, -- chars\n\t\tmin_entry_width = 25, -- chars\n\t\tmax_entry_width = 30, -- chars\n\t\tentry_padding = {\n\t\t\ttop = 0,\n\t\t\tbottom = 0,\n\t\t\tleft = 0,\n\t\t\tright = 0,\n\t\t},\n\t\tpadding = {\n\t\t\ttop = 0,\n\t\t\tbottom = 0,\n\t\t\tleft = 0,\n\t\t\tright = 0,\n\t\t},\n\t\tmargin = {\n\t\t\ttop = 0,\n\t\t\tbottom = 0,\n\t\t\tleft = 0,\n\t\t\tright = 0,\n\t\t},\n\t\twidth = 0.75, -- fraction or abs pixel count\n\t\theight = 0.35, -- fraction or abs pixel count\n\t\tstretch_vertical = false, -- use all available height\n\t\tstretch_horizontal = false, -- use all available width\n\t\tflow_horizontal = false, -- fill from left to right\n\t\texpand_horizontal = true, -- use all available columns first\n\t\tplacement = function(h) -- function, placement (e.g. \"centered\") or false (last position)\n\t\t\tawful.placement.bottom(h, { honor_workarea = true })\n\t\tend,\n\t\tborder_width = beautiful.border_width or dpi(1),\n\t\topacity = 1,\n\t\tshape = nil,\n\t\todd_style = \"row\", -- row  | column | checkered | none\n\t\todd_empty = true, -- continue odd pattern for empty entries\n\t\tkey_aliases = {\n\t\t\t[\" \"] = \"space\",\n\t\t\tLeft = \"←\",\n\t\t\tRight = \"→\",\n\t\t\t[\"^Up\"] = \"↑\",\n\t\t\t[\"[%-]Up\"] = \"↑\",\n\t\t\t[\"^Down\"] = \"↓\",\n\t\t\t[\"[%-]Down\"] = \"↓\",\n\t\t\tXF86MonBrightnessUp = \"󰃝 +\",\n\t\t\tXF86MonBrightnessDown = \"󰃝 -\",\n\t\t\tXF86AudioRaiseVolume = \"󰝝\",\n\t\t\tXF86AudioLowerVolume = \"󰝞\",\n\t\t\tXF86AudioMute = \"󰝟\",\n\t\t\tXF86AudioPlay = \"󰐊\",\n\t\t\tXF86AudioPrev = \"󰒮\",\n\t\t\tXF86AudioNext = \"󰒭\",\n\t\t\tXF86AudioStop = \"󰓛\",\n\t\t},\n\t},\n\n\techo = {\n\t\tenabled = true,\n\t\tshow_percentage_as_progressbar = false, -- display 0-1.0 as progressbar\n\t\tplacement = \"centered\", -- or any awful.placement func\n\t\ttimeout = 1000, -- ms\n\t\talign_vertical = true, -- key above value\n\t\tvertical_layout = false, -- kvs from top to bottom\n\t\tsort = true,\n\n\t\tentry_width = 20, -- chars\n\t\tentry_width_strategy = \"exact\", -- min | max | exact\n\t\tpadding = {\n\t\t\ttop = dpi(3),\n\t\t\tbottom = dpi(3),\n\t\t\tleft = dpi(3),\n\t\t\tright = dpi(3),\n\t\t},\n\t\tspacing = 0,\n\t\tborder_width = beautiful.border_width or dpi(1),\n\t\tshape = nil,\n\t\topacity = 1,\n\t\tcolor_border = nil,\n\t\thighlight = {\n\t\t\tkey = {\n\t\t\t\tfont = \"Monospace 20\",\n\t\t\t\tbg = nil,\n\t\t\t\tfg = nil,\n\t\t\t\titalic = true,\n\t\t\t\tbold = true,\n\t\t\t},\n\t\t\tvalue = {\n\t\t\t\tfont = \"Monospace 20\",\n\t\t\t\tbg = nil,\n\t\t\t\tfg = nil,\n\t\t\t},\n\t\t},\n\n\t\tprogressbar = {\n\t\t\tshape = gears.shape.rounded_rect,\n\t\t\tbar_shape = gears.shape.rounded_rect,\n\t\t\tborder_width = dpi(2),\n\t\t\tbar_border_width = dpi(2),\n\t\t\tcolor = nil,\n\t\t\tbackground_color = nil,\n\t\t\tborder_color = nil,\n\t\t\tbar_border_color = nil,\n\t\t\tmargin = {\n\t\t\t\tleft = dpi(8),\n\t\t\t\tright = dpi(8),\n\t\t\t\ttop = dpi(8),\n\t\t\t\tbottom = dpi(8),\n\t\t\t},\n\t\t\tpadding = {\n\t\t\t\tleft = 0,\n\t\t\t\tright = 0,\n\t\t\t\ttop = 0,\n\t\t\t\tbottom = 0,\n\t\t\t},\n\t\t\topacity = 1,\n\t\t},\n\t},\n\n\tprompt = {\n\t\tplacement = \"centered\", -- or any awful.placement func\n\t\tvertical_layout = true, -- from top to bottom\n\t\twidth = 20, -- chars\n\t\twidth_strategy = \"min\", -- min | max | exact\n\t\tpadding = {\n\t\t\ttop = dpi(5),\n\t\t\tbottom = dpi(5),\n\t\t\tleft = dpi(5),\n\t\t\tright = dpi(5),\n\t\t},\n\t\tspacing = 0,\n\t\tborder_width = beautiful.border_width or dpi(1),\n\t\tshape = nil,\n\t\topacity = 1,\n\t\tcolor_border = nil,\n\t\theader_highlight = {\n\t\t\tfont = \"Monospace 20\",\n\t\t\tfg = nil,\n\t\t\tbg = nil,\n\t\t\tbold = true,\n\t\t\titalic = true,\n\t\t},\n\t\tfont = \"Monospace 20\",\n\t\tcolor_bg = nil,\n\t\tcolor_fg = nil,\n\t\tcolor_cursor_fg = nil,\n\t\tcolor_cursor_bg = nil,\n\t},\n\n\tlabel = {\n\t\tshape = gears.shape.rounded_rect,\n\t\tborder_width = beautiful.border_width or dpi(1),\n\t\tcolor_border = nil,\n\t\twidth = dpi(100),\n\t\theight = dpi(100),\n\t\topacity = 1,\n\t\thighlight = {\n\t\t\tfont = \"Monospace 40\",\n\t\t\tbg = nil,\n\t\t\tfg = nil,\n\t\t\tbold = true,\n\t\t},\n\t},\n\n\tawesome = {\n\t\tauto_select_the_only_choice = false,\n\t\tresize_delta = dpi(32),\n\t\tresize_factor = 0.025,\n\t\twallpaper_dir = os.getenv(\"HOME\") .. \"/.config/awesome/\",\n\t\tbrowser = \"firefox || chromium || google-chrome-stable || qutebrowser\",\n\t\tterminal = terminal or \"alacritty || kitty || wezterm || st || urxvt || xterm\",\n\t\tapp_menu = \"rofi -show drun || dmenu_run\",\n\t},\n}\n```\n\n\u003c!-- config:end --\u003e\n\n\u003c/details\u003e\n\n## 📖 Documentation\n\n### 🌲Tree\n\nKeymaps are organized and represented using hierarchical tree structures.\nEach key is stored as a node in the tree.\nWhen a character is input, the tree is traversed to find the corresponding key.\nIf a node has been found and there are no possible successors (leaf), the key's function is executed.\nUsers can also use a specific key (by default, `BackSpace`) to go back a level in the tree.\n\nThe tree structure implements property inheritance, which means that options (`opts`) defined at a higher level in the tree will be inherited by the successor keys, unless overridden.\nThis provides a convenient way to define common options for groups of keys without repeating them for each individual key.\n\nBy default, the keymap is stored in the root tree, which is accessed by pressing the keybind defined in `root_keys` during setup.\nHowever, it is possible to create additional trees if needed.\n\n### ✨ Modes\n\n| Mode      | Description                                                                                  |\n| --------- | -------------------------------------------------------------------------------------------- |\n| `hold`    | Run until the (last remaining) modifier has been released.                                   |\n| `modal`   | Run until a command has been executed (by entering a valid key sequence).                    |\n| `hybrid`  | Run until a command has been executed _and_ the (last remaining) modifier has been released. |\n| `forever` | Run indefinitely until explicitly stopped (by pressing a stop key).                          |\n\nPlease note that the exact behaviour is also dependent on other config parameters.\nWhen `stop_on_unknown_key` is active and an unknown key has\nbeen input, operation will stop regardless of the current mode.\nOperation will also always stop when a `timeout` (no valid input within\na timeframe) occurs.\nThe keys itself can also override the behaviour by explicitly setting a `continue` flag.\n\n### 🔑 Key\n\nKeys can be configured by using the following properties:\n\n| Property    | Type                 | Description                                                                                                                                                                                                                                                              |\n| ----------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| (`seq`)     | string               | The sequence of keys to be pressed.                                                                                                                                                                                                                                      |\n| (`fn`)      | function(opts, tree) | The function to be executed when the key sequence has been entered. If the key has successors (is a menu) it will only be executed if a timeout occurs (similar to vim). Successor keys can get dynamically created by returning a table containing the key definitions. |\n| `desc`      | string or function   | Provides a brief description of the key.                                                                                                                                                                                                                                 |\n| `opts`      | table                | Specifies custom options for the key that will be merged with options from predecessors.                                                                                                                                                                                 |\n| `cond`      | function(opts)       | A condition that determines whether the key is active (nil means it is always active)                                                                                                                                                                                    |\n| `group`     | string               | Assigns the key to a group, used for sorting purposes.                                                                                                                                                                                                                   |\n| `global`    | string or boolean    | Creates a global keybinding in AwesomeWM to run the key's function (e.g. \"\\\u003cM-a\\\u003e\"). If set to true, the key sequence will be used as the global keybinding.                                                                                                             |\n| `continue`  | boolean              | Forces continuation after executing the key's function regardless of the current input mode.                                                                                                                                                                             |\n| `hidden`    | boolean              | Hides the key in hints.                                                                                                                                                                                                                                                  |\n| `highlight` | table                | Custom attributes to display the key in hints (font, fg, bg, bold, italic, underline, strikethrough, etc.)                                                                                                                                                               |\n| `is_menu`   | boolean              | Marks the key explicitly as a menu, even if it has no successsors (purely cosmetic, used for dynamic menus).                                                                                                                                                             |\n| `temp`      | boolean              | Marks the key as temporary, indicating that it is dynamically created and only available for a single use.                                                                                                                                                               |\n| `pre`       | function(opts, tree) | The function to be executed before the main function `fn`.                                                                                                                                                                                                               |\n| `post`      | function(opts, tree) | The function to be executed after the main function `fn`.                                                                                                                                                                                                                |\n| `on_enter`  | function(opts, tree) | The function to be executed when entering a menu (non-leaf node).                                                                                                                                                                                                        |\n| `on_leave`  | function(opts, tree) | The function to be executed when leaving a menu (non-leaf node).                                                                                                                                                                                                         |\n| `result`    | table                | Specifies the results or notifications to be shown using `echo` after executing the key's function (e.g. { volume = 0.5 }).                                                                                                                                              |\n\n### 🖌️ Custom UI\n\nOne of the design principles is to fully isolate core functionality from UI.\nEvery UI building block (echo, prompt, label) can be disabled individually\nallowing users to build custom versions by solely implementing signal handlers.\n\nTo implement custom UI please refer to the sourcecode.\n\n## 📡 API\n\nTodo.\n\n## 💡 More Examples\n\n\u003cdetails\u003e\u003csummary\u003eClient Menu\u003c/summary\u003e\n\n```lua\nlocal function client_menu(c)\n\tif not c then\n\t\treturn\n\tend\n\tlocal pc = require(\"modalisa.presets.client\")\n\n\tlocal opts = {\n\t\tstop_on_unknown_key = true,\n\t\thints = {\n\t\t\tenabled = true,\n\t\t\tsort = \"id\",\n\t\t\tshow_header = true,\n\t\t\tdelay = 0,\n\t\t\tfill_remaining_space = false,\n\t\t\tplacement = function(x)\n\t\t\t\tawful.placement.under_mouse(x)\n\t\t\t\tawful.placement.no_offscreen(x)\n\t\t\tend,\n\t\t\tflow_horizontal = false,\n\t\t\tstretch_vertical = false,\n\t\t\tstretch_horizontal = false,\n\t\t\texpand_horizontal = false,\n\t\t\twidth = 0.3,\n\t\t\theight = 0.3,\n\t\t\tshow_disabled_keys = false,\n\t\t\tmin_entry_width = 11,\n\t\t\tmax_entry_width = 11,\n\t\t\tentry_key_width = 0,\n\t\t\tentry_padding = {\n\t\t\t\tleft = dpi(10),\n\t\t\t},\n\t\t\tseparator = \"\",\n\t\t},\n\t}\n\n\tlocal function chrome_tabbar(cl)\n\t\treturn {\n\t\t\t\"x\",\n\t\t\tdesc = \"tabbar toggle\",\n\t\t\tcond = function()\n\t\t\t\treturn string.find(cl.class, \".*chrome.*\")\n\t\t\tend,\n\t\t\tfn = function()\n\t\t\t\tkeygrabber.stop()\n\t\t\t\troot.fake_input(\"key_press\", \"F11\")\n\t\t\t\tawful.spawn.easy_async_with_shell(\"sleep 0.15\", function()\n\t\t\t\t\tcl.fullscreen = false\n\t\t\t\tend)\n\t\t\t\troot.fake_input(\"key_release\", \"F11\")\n\t\t\tend,\n\t\t}\n\tend\n\n\tlocal list = {\n\t\tpc.kill(c) + { \"k\", desc = \"kill\", highlight = { bg = \"#F7768E\" } },\n\t\tpc.minimize(c) + { \"n\" },\n\t\tpc.toggle_property(\"fullscreen\", c, true) + { \"f\" },\n\t\tpc.toggle_property(\"maximized\", c, true) + { \"m\" },\n\t\tpc.toggle_property(\"floating\", c) + { \"o\", desc = \"floating\" },\n\t\tpc.move_to_tag_menu(c) + { \"t\", desc = \"send to tag ➜\", opts = { hints = { placement = \"no_offscreen\" } } },\n\t\tpc.unminimize_menu(false)\n\t\t\t+ { \"u\", desc = \"unminimize  ➜\", opts = { hints = { placement = \"no_offscreen\" } } },\n\t\tchrome_tabbar(c),\n\t}\n\n\trequire(\"modalisa\").fake_input(\"stop\")\n\trequire(\"modalisa\").run_tree(list, opts, c.name or \"\")\nend\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eTag Menu\u003c/summary\u003e\n\n```lua\nlocal function tag_menu(t)\n\tlocal mt = require(\"modalisa.presets.tag\")\n\n\tlocal opts = {\n\t\tstop_on_unknown_key = true,\n\t\thints = {\n\t\t\tenabled = true,\n\t\t\tsort = \"id\",\n\t\t\tshow_header = true,\n\t\t\tdelay = 0,\n\t\t\tfill_remaining_space = false,\n\t\t\tplacement = function(x)\n\t\t\t\tawful.placement.under_mouse(x)\n\t\t\t\tawful.placement.no_offscreen(x)\n\t\t\tend,\n\t\t\tflow_horizontal = false,\n\t\t\tstretch_vertical = false,\n\t\t\tstretch_horizontal = false,\n\t\t\texpand_horizontal = false,\n\t\t\twidth = 0.3,\n\t\t\theight = 0.3,\n\t\t\tshow_disabled_keys = false,\n\t\t\tmin_entry_width = 15, -- chars\n\t\t\tmax_entry_width = 15, -- chars\n\t\t\tentry_key_width = 0, -- chars\n\t\t\tentry_padding = {\n\t\t\t\tleft = dpi(10),\n\t\t\t},\n\t\t\tseparator = \"\",\n\t\t},\n\t}\n\n\tlocal list = {\n\t\tmt.new_tag_copy(\"\") + { \"n\", desc = \"new tag\", highlight = { desc = { fg = \"#94CF95\" } } },\n\t\tmt.layout_select_menu(t) + { \" \", desc = \"layout ➜\", opts = { hints = { placement = \"no_offscreen\" } } },\n\t\tmt.rename(t) + { \"r\", desc = \"rename\", opts = { hints = { placement = \"no_offscreen\" } } },\n\t\tmt.set_gap(t) + { \"g\", desc = \"gap\" },\n\t\tmt.master_width_increase(t) + { \"w\", desc = \"master_width +\", continue = false },\n\t\tmt.master_width_decrease(t) + { \"W\", desc = \"master_width -\", continue = false },\n\t\tmt.master_count_increase(t) + { \"m\", desc = \"master_count +\", continue = false },\n\t\tmt.master_count_decrease(t) + { \"M\", desc = \"master_count -\", continue = false },\n\t\tmt.move_all_clients_to_tag_menu(t)\n\t\t\t+ { \"a\", desc = \"move all to ➜\", opts = { hints = { placement = \"no_offscreen\" } } },\n\t\tmt.move_tag_to_screen_menu(t)\n\t\t\t+ { \"s\", desc = \"move to screen ➜\", opts = { hints = { placement = \"no_offscreen\" } } },\n\t\tmt.delete(t) + { \"D\", desc = \"delete tag\", highlight = { desc = { fg = \"#F7768E\" } } },\n\t}\n\n\trequire(\"modalisa\").fake_input(\"stop\")\n\trequire(\"modalisa\").run_tree(list, opts, t.name or t.index or \"\")\nend\n```\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintrntbrn%2Fmodalisa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fintrntbrn%2Fmodalisa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fintrntbrn%2Fmodalisa/lists"}