From ab0c30f719460e127332d82a84704e1114cbace6 Mon Sep 17 00:00:00 2001 From: Yessiest Date: Sun, 4 Sep 2022 14:25:18 +0400 Subject: [PATCH] Configurable keybindings --- desktop.conf | 31 +++++++++++++++++ libs/parser_test.lua | 47 +++++++++++++++++++++++++ libs/parsers.lua | 82 ++++++++++++++++++++++++++++++++++++++++++++ libs/utils.lua | 16 +++++++++ modules/binds.lua | 67 +++++++++++++++++++++++++++--------- modules/global.lua | 26 ++++++++++---- 6 files changed, 245 insertions(+), 24 deletions(-) create mode 100644 desktop.conf create mode 100644 libs/parser_test.lua create mode 100644 libs/parsers.lua create mode 100644 libs/utils.lua diff --git a/desktop.conf b/desktop.conf new file mode 100644 index 0000000..b8ff721 --- /dev/null +++ b/desktop.conf @@ -0,0 +1,31 @@ +# Global variables +[global] +terminal = "$HOME/.local/bin/st" +browser = "prime-run librewolf" +modkey = "Mod4" +theme = "reno98" +shell = "zsh" + +# Keybindings +# Format: (++...)+ = "" +# "modkey" as modifier will be substituted for modkey variable in [global] +[keys] +modkey+Up = ":root.client_next" +modkey+Down = ":root.client_previous" +modkey+Control+Up = ":root.screen_next" +modkey+Control+Down = ":root.screen_previous" +modkey+Tab = ":root.client_swap" +modkey+Return = ":root.spawn_terminal" +modkey+Shift+Return = ":root.spawn_browser" + +# Client keys only work if a focused client exists +modkey+Shift+c = ":client.kill" +modkey+t = ":client.cycle_screen" +modkey+o = ":client.ontop" +modkey+b = ":client.below" +modkey+f = ":client.fullscreen" +modkey+n = ":client.minimize" +modkey+m = ":client.maximize" + +# Custom keys +modkey+v = "notify-send test" diff --git a/libs/parser_test.lua b/libs/parser_test.lua new file mode 100644 index 0000000..ce5c28c --- /dev/null +++ b/libs/parser_test.lua @@ -0,0 +1,47 @@ +-- This file is part of Reno desktop. +-- +-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +-- +-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see . + +local parsers = require("parsers") +-- Conf parser +local data = [[ +# Global variables +[global] +terminal = "$HOME/.local/bin/st" +browser = "prime-run librewolf" +modkey = "Mod4" +theme = "reno98" +shell = "zsh" + +# Keybindings +# Format: (++...)+ = "" +# "modkey" as modifier will be substituted for modkey variable in [global] +[keys] +modkey+Up = ":root.client_next" +modkey+Down = ":root.client_previous" +modkey+Control+Up = ":root.screen_next" +modkey+Control+Down = ":root.screen_previous" +modkey+Tab = ":root.client_swap" +modkey+Return = ":root.spawn_terminal" +modkey+Shift+Return = ":root.spawn_browser" + +# Client keys only work if a focused client exists +modkey+Shift+c = ":client.kill" +modkey+t = ":client.cycle_screen" +modkey+o = ":client.ontop" +modkey+b = ":client.below" +modkey+f = ":client.fullscreen" +modkey+n = ":client.minimize" +modkey+m = ":client.maximize" + +]] +for k,v in pairs(parsers.conf(data)) do + print("Block: ["..k.."]") + for kk,vv in pairs(v) do + print(kk,vv) + end +end diff --git a/libs/parsers.lua b/libs/parsers.lua new file mode 100644 index 0000000..e739c85 --- /dev/null +++ b/libs/parsers.lua @@ -0,0 +1,82 @@ +-- This file is part of Reno desktop. +-- +-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +-- +-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see . + +-- Various utilitiy parsers +local parsers = {} + +local function split_strings(text) + -- probably the cleanest function to split by strings i've written + local split = {} + while text:find("\"") do + local strstart = text:find("\"") + while text:sub(strstart-1,strstart-1) == "\\" do + strstart = text:find("\"",strstart+1) + end + local strend = text:find("\"",strstart+1) + while text:sub(strend-1,strend-1) == "\\" do + strend = text:find("\"",strend+1) + end + if not strend then + return nil, "String not closed at "..strstart + end + local before_string = text:sub(1,strstart-1) + local string = text:sub(strstart,strend):gsub("\\\"","\"") + text = text:sub(strend+1,-1) + table.insert(split,before_string) + table.insert(split,string) + end + table.insert(split,text) + return split +end + +parsers.conf = function(cfgtext) + cfgtext = cfgtext:gsub("#[^\n]*","") + local split_by_strings,err = split_strings(cfgtext) + if not split_by_strings then + error(err) + end + local struct = {global = {}} + local block = "global" + local last_string_key = nil + local err + for k,v in pairs(split_by_strings) do + if not v:match("^\".*\"$") then + v:gsub("[^\n]*",function(line) + -- Nothing + if line:match("^%s*$") then + return + end + -- Namespace block + if line:match("^%s*%[[^%]]-%]%s*$") then + block = line:match("%[([^%]]-)%]") + struct[block] = {} + return + end + -- String/Multiline string assignment + if line:match("^%s*[^=]-%s*=%s*$") then + last_string_key = line:match("^%s*([^=]-)%s*=%s*$") + return + end + -- Number/boolean assignment + local key,value = line:match("^%s*([^=]-)%s*=%s*(.-)%s*$") + -- number + if value:match("^[%d%.]*$") then + value = tonumber(value) + -- bool + elseif (value:lower() == "yes") or (value:lower() == "no") then + value = (value:lower() == "yes") + end + struct[block][key] = value + end) + else + struct[block][last_string_key] = v:sub(2,-2) + end + end + return struct +end +return parsers diff --git a/libs/utils.lua b/libs/utils.lua new file mode 100644 index 0000000..b14dcff --- /dev/null +++ b/libs/utils.lua @@ -0,0 +1,16 @@ +-- This file is part of Reno desktop. +-- +-- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. +-- +-- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see . + +-- Various utilities that are not included into awesomewm +local utils = {} +utils.substitute_env = function(str) + return str:gsub("$[%w_]+",function(var) + return os.getenv(var:sub(2,-1)) or "" + end) +end +return utils diff --git a/modules/binds.lua b/modules/binds.lua index ab4eec5..6b85612 100644 --- a/modules/binds.lua +++ b/modules/binds.lua @@ -8,30 +8,62 @@ -- Module that adds default keybindings local awful = require("awful") local gears = require("gears") - global.modkey = global.modkey or "Mod4" + +local function get_keycomb(name) + local modifiers = {} + name = name:gsub("[^%s%+]+%+",function(v) + if v == "modkey+" then v = global.modkey.."+" end + table.insert(modifiers,v:sub(1,-2)) + return "" + end) + return modifiers,name +end + +local keymap = keybindings + +local function k(name,callback,description) + if not keymap[name] then + return {} + end + local modifiers,key = get_keycomb(keymap[name]) + return awful.key(modifiers,key, + callback, + description) +end + +local custom_keys = {} + +for comm,bind in pairs(keymap) do + if not comm:match("^:.*") then + table.insert(custom_keys,k(comm,function() + awful.spawn(comm) + end,{description = bind, group = "custom"})) + end +end + local keys = gears.table.join( - awful.key({global.modkey}, "Up", + k(':root.client_next', function() awful.client.focus.byidx(1) end, {description = "switch to next client", group = "client"}), - awful.key({global.modkey}, "Down", + k(":root.client_previous", function() awful.client.focus.byidx(-1) end, {description = "switch to previous client", group = "client"}), - awful.key({global.modkey, "Control"}, "Up", + k(":root.screen_next", function() awful.screen.focus_relative(1) end, {description = "switch to next screen", group = "screen"}), - awful.key({global.modkey, "Control"}, "Down", + k(":root.screen_previous", function() awful.screen.focus_relative(-1) end, {description = "switch to previous screen", group = "screen"}), - awful.key({global.modkey}, "Tab", + k(":root.client_swap", function() awful.client.focus.history.previous() if client.focus then @@ -39,16 +71,17 @@ local keys = gears.table.join( end end, {description = "go back", group = "client"}), - awful.key({global.modkey}, "Return", + k(":root.spawn_terminal", function() awful.spawn(global.terminal) end, - {description = "Open terminal", group = "launcher"}), - awful.key({global.modkey, "Shift"}, "Return", + {description = "open terminal", group = "launcher"}), + k(":root.spawn_browser", function() awful.spawn(global.browser) end, - {description = "Open browser", group = "launcher"})) + {description = "open browser", group = "launcher"}), + table.unpack(custom_keys)) root.keys(keys) local buttons = gears.table.join( @@ -59,38 +92,38 @@ local buttons = gears.table.join( root.buttons(buttons) local clientkeys = gears.table.join( - awful.key({global.modkey, "Shift"},"c", + k(":client.kill", function(c) c:kill() end, {description = "close client", group = "client"}), - awful.key({global.modkey}, "o", + k(":client.cycle_screen", function(c) c:move_to_screen() end, {description = "move to screen", group = "client"}), - awful.key({global.modkey}, "t", + k(":client.ontop", function(c) c.ontop = not c.ontop end, {description = "toggle ontop", group = "client"}), - awful.key({global.modkey}, "b", + k(":client.below", function(c) c.below = not c.below end, {description = "toggle below", group = "client"}), - awful.key({global.modkey}, "f", + k(":client.fullscreen", function(c) c.fullscreen = not c.fullscreen c:raise() end, {description = "toggle fullscreen", group = "client"}), - awful.key({ global.modkey }, "n", + k(":client.minimize", function (c) c.minimized = true end , {description = "minimize", group = "client"}), - awful.key({ global.modkey }, "m", + k(":client.maximize", function (c) c.maximized = not c.maximized c:raise() diff --git a/modules/global.lua b/modules/global.lua index fbe7e72..d194eab 100644 --- a/modules/global.lua +++ b/modules/global.lua @@ -6,10 +6,22 @@ -- -- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see . -- Global settings -global = {} -global.terminal = os.getenv("HOME").."/.local/bin/st" --Mod+Enter (spawn terminal) -global.browser = "prime-run librewolf" --Mod+Shift+Enter (spawn browser) -global.modkey = "Mod4" -- Default modifier key -global.theme = "reno98" -global.shell = "zsh" - +local conf = require("parsers").conf +local envsub = require("utils").substitute_env +local conf_file = io.open(root_path.."/desktop.conf","r") +if not conf_file then + error("desktop.conf is missing or not readable") +end +local config = conf(conf_file:read("*a")) +conf_file:close() +global = config.global +global.terminal = envsub(global.terminal) +global.browser = envsub(global.browser) +local function invert(t) + local new_t = {} + for k,v in pairs(t) do + new_t[v] = k + end + return new_t +end +keybindings = invert(config.keys)