aboutsummaryrefslogtreecommitdiff
path: root/.config/awesome/quarrel
diff options
context:
space:
mode:
authordelta <darkussdelta@gmail.com>2025-07-04 00:38:29 +0200
committerdelta <darkussdelta@gmail.com>2025-07-04 00:38:29 +0200
commitb3530d7c4a102935fa26498a160ee1dc6c1e9c03 (patch)
treed7751206a694bc5de2d6b34b0c077cfcd1855798 /.config/awesome/quarrel
parentdf75ec5ed5e3848c497f0439acb43ec9246ad3e7 (diff)
:3
Diffstat (limited to '.config/awesome/quarrel')
-rw-r--r--.config/awesome/quarrel/animation/bezier.lua89
-rw-r--r--.config/awesome/quarrel/animation/init.lua249
-rw-r--r--.config/awesome/quarrel/animation/subscribable/init.lua47
-rw-r--r--.config/awesome/quarrel/animation/tween/init.lua554
-rw-r--r--.config/awesome/quarrel/bezier.lua343
-rw-r--r--.config/awesome/quarrel/bind/consts.lua27
-rw-r--r--.config/awesome/quarrel/bind/init.lua (renamed from .config/awesome/quarrel/bind.lua)31
-rw-r--r--.config/awesome/quarrel/color.lua64
-rw-r--r--.config/awesome/quarrel/const.lua22
-rw-r--r--.config/awesome/quarrel/debugger.lua865
-rw-r--r--.config/awesome/quarrel/delegate.lua10
-rw-r--r--.config/awesome/quarrel/fs.lua21
-rw-r--r--.config/awesome/quarrel/iconset.lua21
-rw-r--r--.config/awesome/quarrel/init.lua10
-rw-r--r--.config/awesome/quarrel/lua-rust.tar.gzbin18878 -> 0 bytes
-rw-r--r--.config/awesome/quarrel/markup.lua10
-rw-r--r--.config/awesome/quarrel/math/consts.lua5
-rw-r--r--.config/awesome/quarrel/math/init.lua (renamed from .config/awesome/quarrel/math.lua)14
-rw-r--r--.config/awesome/quarrel/native/Cargo.toml19
-rw-r--r--.config/awesome/quarrel/native/init.lua4
-rw-r--r--.config/awesome/quarrel/native/src/http.rs22
-rw-r--r--.config/awesome/quarrel/native/src/lenses/application.rs85
-rw-r--r--.config/awesome/quarrel/native/src/lenses/calculator.rs47
-rw-r--r--.config/awesome/quarrel/native/src/lenses/entry.rs19
-rw-r--r--.config/awesome/quarrel/native/src/lenses/mod.rs78
-rw-r--r--.config/awesome/quarrel/native/src/lib.rs14
-rw-r--r--.config/awesome/quarrel/native/src/moondrop.rs3
-rw-r--r--.config/awesome/quarrel/native/src/mpd.rs142
-rw-r--r--.config/awesome/quarrel/native/src/net/mod.rs4
-rw-r--r--.config/awesome/quarrel/native/src/util.rs3
-rw-r--r--.config/awesome/quarrel/persistent.lua62
-rw-r--r--.config/awesome/quarrel/store.lua4
-rw-r--r--.config/awesome/quarrel/ui.lua145
-rw-r--r--.config/awesome/quarrel/ui/consts.lua24
-rw-r--r--.config/awesome/quarrel/ui/init.lua167
-rw-r--r--.config/awesome/quarrel/vars.lua254
36 files changed, 2626 insertions, 852 deletions
diff --git a/.config/awesome/quarrel/animation/bezier.lua b/.config/awesome/quarrel/animation/bezier.lua
new file mode 100644
index 0000000..a505e48
--- /dev/null
+++ b/.config/awesome/quarrel/animation/bezier.lua
@@ -0,0 +1,89 @@
+local gtable = require "gears.table"
+
+-- port of https://github.com/WebKit/WebKit/blob/da934454c84ac2dcbf9fca9e5f4ac2644ef25d72/Source/WebCore/platform/graphics/UnitBezier.h
+
+local bezier = {}
+
+function bezier:sample_x(t)
+ -- `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
+ return ((self.ax * t + self.bx) * t + self.cx) * t
+end
+
+function bezier:sample_y(t)
+ return ((self.ay * t + self.by) * t + self.cy) * t
+end
+
+function bezier:sample_derivative_x(t)
+ return (3.0 * self.ax * t + 2.0 * self.bx) * t + self.cx
+end
+
+function bezier:solve_x(x, epsilon)
+ local x2, d2
+ local t2 = x
+
+ -- First try a few iterations of Newton's method -- normally very fast.
+ for _ = 1, 8 do
+ x2 = self:sample_x(t2) - x
+ if math.abs(x2) < epsilon then
+ return t2
+ end
+ d2 = self:sample_derivative_x(t2)
+ if math.abs(d2) < 1e-6 then
+ break
+ end
+ t2 = t2 - x2 / d2
+ end
+
+ -- Fall back to the bisection method for reliability.
+ local t0 = 0
+ local t1 = 1
+ t2 = x
+
+ if t2 < t0 then
+ return t0
+ end
+ if t2 > t1 then
+ return t1
+ end
+
+ while t0 < t1 do
+ x2 = self:sample_x(t2)
+ if math.abs(x2 - x) < epsilon then
+ return t2
+ end
+ if x > x2 then
+ t0 = t2
+ else
+ t1 = t2
+ end
+ t2 = (t1 - t0) * 0.5 + t0
+ end
+
+ -- Failure.
+ return t2
+end
+
+function bezier:solve(x, epsilon)
+ return self:sample_y(self:solve_x(x, epsilon))
+end
+
+local function new(x1, y1, x2, y2)
+ local obj = gtable.crush({}, bezier)
+
+ -- Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
+ obj.cx = 3.0 * x1
+ obj.bx = 3.0 * (x2 - x1) - obj.cx
+ obj.ax = 1.0 - obj.cx - obj.bx
+
+ obj.cy = 3.0 * y1
+ obj.by = 3.0 * (y2 - y1) - obj.cy
+ obj.ay = 1.0 - obj.cy - obj.by
+
+ return obj
+end
+
+return setmetatable(bezier, {
+ __call = function(_, ...)
+ return new(...)
+ end,
+})
diff --git a/.config/awesome/quarrel/animation/init.lua b/.config/awesome/quarrel/animation/init.lua
new file mode 100644
index 0000000..c57b01a
--- /dev/null
+++ b/.config/awesome/quarrel/animation/init.lua
@@ -0,0 +1,249 @@
+-------------------------------------------
+-- @author https://github.com/Kasper24
+-- @copyright 2021-2025 Kasper24
+-------------------------------------------
+local GLib = require("lgi").GLib
+local gobject = require "gears.object"
+local gpcall = require "gears.protected_call"
+local gtable = require "gears.table"
+local gtimer = require "gears.timer"
+local subscribable = require "quarrel.animation.subscribable"
+-- local qconsts = require "quarrel.consts"
+local qtween = require "quarrel.animation.tween"
+-- local qbezier = require "quarrel.animation.bezier"
+local ipairs = ipairs
+local table = table
+local pairs = pairs
+
+local animation_manager = {}
+
+-- local easing_bezier = qbezier(0.2, 0, 0, 1)
+-- animation_manager.consts = qconsts.protect(function()
+-- local duration = 0.3
+-- return {
+-- DURATION = duration,
+-- INTRO = duration / 4,
+-- EASING = function(t, b, c, d)
+-- local epsilon = 1000 / d
+-- return c * easing_bezier:solve(t/d, epsilon) + b
+-- end
+-- }
+-- end)
+
+local animation = {}
+
+local function second_to_micro(sec)
+ return sec * 1000000
+end
+
+local function framerate_tomilli(framerate)
+ return 1000 / framerate
+end
+
+local function on_no_running_animations(self, callback)
+ gtimer.start_new(0.1, function()
+ if #self._private.animations <= 0 then
+ callback()
+ return false
+ else
+ local has_non_looped_anim = false
+ for _, animation in ipairs(self._private.animations) do
+ if animation.loop == false then
+ has_non_looped_anim = true
+ end
+ end
+
+ if has_non_looped_anim == false then
+ callback()
+ return false
+ end
+ end
+
+ return true
+ end)
+end
+
+local function animation_loop(self)
+ self._private.source_id = GLib.timeout_add(
+ GLib.PRIORITY_DEFAULT,
+ framerate_tomilli(self._private.framerate),
+ function()
+ for index, animation in ipairs(self._private.animations) do
+ if animation.state == true then
+ -- compute delta time
+ local time = GLib.get_monotonic_time()
+ local delta = time - animation.last_elapsed
+ animation.last_elapsed = time
+
+ -- If pos is true, the animation has ended
+ local pos = gpcall(animation.tween.update, animation.tween, delta)
+ if pos == true then
+ -- Loop the animation, don't end it.
+ -- Useful for widgets like the spinning cicle
+ if animation.loop == true then
+ animation.tween:reset()
+ else
+ animation.state = false
+
+ -- Snap to end
+ animation.pos = animation.tween.target
+
+ gpcall(animation.emit_signal, animation, "update", animation.pos)
+ gpcall(animation.fire, animation, animation.pos)
+
+ gpcall(animation.emit_signal, animation, "ended", animation.pos)
+ gpcall(animation.ended.fire, animation, animation.pos)
+
+ table.remove(self._private.animations, index)
+ end
+ -- Animation in process, keep updating
+ else
+ animation.pos = pos
+
+ gpcall(animation.emit_signal, animation, "update", animation.pos)
+ gpcall(animation.fire, animation, animation.pos)
+ end
+ else
+ table.remove(self._private.animations, index)
+ end
+ end
+
+ -- call again the function after cooldown
+ return true
+ end
+ )
+end
+
+function animation:set(args)
+ args = args or {}
+
+ -- Awestoer/Rubbto compatibility
+ -- I'd rather this always be a table, but Awestore/Rubbto
+ -- except the :set() method to have 1 number value parameter
+ -- used to set the target
+ local is_table = type(args) == "table"
+ local initial = is_table and (args.pos or self.pos) or self.pos
+ local subject = is_table and (args.subject or self.subject) or self.subject
+ local target = is_table and (args.target or self.target) or args
+ local duration = is_table and (args.duration or self.duration) or self.duration
+ local easing = is_table and (args.easing or self.easing) or self.easing
+
+ if self.tween == nil or self.reset_on_stop == true then
+ self.tween = qtween.new {
+ initial = initial,
+ subject = subject,
+ target = target,
+ duration = second_to_micro(duration),
+ easing = easing,
+ }
+ end
+
+ if self._private.anim_manager._private.instant and self.override_instant ~= true then
+ self.pos = self.tween.target
+ self:fire(self.pos)
+ self:emit_signal("update", self.pos)
+
+ self.state = false
+ self.ended:fire(self.pos)
+ self:emit_signal("ended", self.pos)
+ return
+ end
+
+ if self._private.anim_manager._private.animations[self.index] == nil then
+ table.insert(self._private.anim_manager._private.animations, self)
+ end
+
+ self.state = true
+ self.last_elapsed = GLib.get_monotonic_time()
+
+ self.started:fire()
+ self:emit_signal "started"
+end
+
+-- Rubato compatibility
+function animation:abort()
+ self.state = false
+end
+
+function animation:stop()
+ self.state = false
+end
+
+function animation:initial()
+ return self._private.initial
+end
+
+function animation_manager:set_instant(value)
+ if value == true and self._private.instant == false then
+ on_no_running_animations(self, function()
+ -- GLib.source_remove(self._private.source_id)
+ self._private.instant = true
+ end)
+ elseif self._private.instant == true then
+ self._private.instant = false
+ -- animation_loop(self)
+ end
+end
+
+function animation_manager:set_framerate(value)
+ self._private.framerate = value
+ -- if self._private.instant == false then
+ on_no_running_animations(self, function()
+ GLib.source_remove(self._private.source_id)
+ animation_loop(self)
+ end)
+ -- end
+end
+
+function animation_manager:new(args)
+ args = args or {}
+
+ args.pos = args.pos or 0
+ args.subject = args.subject or nil
+ args.target = args.target or nil
+ args.duration = args.duration or 0
+ args.easing = args.easing or nil
+ args.loop = args.loop or false
+ args.signals = args.signals or {}
+ args.update = args.update or nil
+ args.reset_on_stop = args.reset_on_stop == nil and true or args.reset_on_stop
+
+ -- Awestoer/Rubbto compatibility
+ args.subscribed = args.subscribed or nil
+ local ret = subscribable()
+ ret.started = subscribable()
+ ret.ended = subscribable()
+ if args.subscribed ~= nil then
+ ret:subscribe(args.subscribed)
+ end
+
+ for sig, sigfun in pairs(args.signals) do
+ ret:connect_signal(sig, sigfun)
+ end
+ if args.update ~= nil then
+ ret:connect_signal("update", args.update)
+ end
+
+ gtable.crush(ret, args, true)
+ gtable.crush(ret, animation, true)
+
+ ret._private = {}
+ ret._private.anim_manager = self
+ ret._private.initial = args.pos
+ -- Can't have it private for rubato compatibility
+ ret.state = false
+
+ return ret
+end
+
+local instance = gobject {}
+gtable.crush(instance, animation_manager, true)
+
+instance._private = {}
+instance._private.animations = {}
+instance._private.instant = false
+instance._private.framerate = 60
+
+animation_loop(instance)
+
+return instance
diff --git a/.config/awesome/quarrel/animation/subscribable/init.lua b/.config/awesome/quarrel/animation/subscribable/init.lua
new file mode 100644
index 0000000..9542704
--- /dev/null
+++ b/.config/awesome/quarrel/animation/subscribable/init.lua
@@ -0,0 +1,47 @@
+-------------------------------------------
+-- @author https://github.com/Kasper24
+-- @copyright 2021-2025 Kasper24
+-- Adopted from rubato
+-------------------------------------------
+local gobject = require "gears.object"
+
+-- Kidna copying awesotre's stores on a surface level for added compatibility
+local function subscribable(args)
+ local ret = gobject {}
+ local subscribed = {}
+
+ -- Subscrubes a function to the object so that it's called when `fire` is
+ -- Calls subscribe_callback if it exists as well
+ function ret:subscribe(func)
+ local id = tostring(func):gsub("function: ", "")
+ subscribed[id] = func
+
+ if self.subscribe_callback then
+ self.subscribe_callback(func)
+ end
+ end
+
+ -- Unsubscribes a function and calls unsubscribe_callback if it exists
+ function ret:unsubscribe(func)
+ if not func then
+ subscribed = {}
+ else
+ local id = tostring(func):gsub("function: ", "")
+ subscribed[id] = nil
+ end
+
+ if self.unsubscribe_callback then
+ self.unsubscribe_callback(func)
+ end
+ end
+
+ function ret:fire(...)
+ for _, func in pairs(subscribed) do
+ func(...)
+ end
+ end
+
+ return ret
+end
+
+return subscribable
diff --git a/.config/awesome/quarrel/animation/tween/init.lua b/.config/awesome/quarrel/animation/tween/init.lua
new file mode 100644
index 0000000..5f4ce51
--- /dev/null
+++ b/.config/awesome/quarrel/animation/tween/init.lua
@@ -0,0 +1,554 @@
+-------------------------------------------
+-- @author https://github.com/Kasper24
+-- @copyright 2021-2025 Kasper24
+-------------------------------------------
+-- easing
+-- Adapted from https://github.com/EmmanuelOga/easing. See LICENSE.txt for credits.
+-- For all easing functions:
+-- t = time == how much time has to pass for the tweening to complete
+-- b = begin == starting property value
+-- c = change == ending - beginning
+-- d = duration == running time. How much time has passed *right now*
+-- local Color = require "external.lua-color"
+local gobject = require "gears.object"
+local gtable = require "gears.table"
+local tostring = tostring
+local assert = assert
+local table = table
+local pairs = pairs
+local error = error
+
+local type = type
+
+local tween = {
+ _VERSION = "tween 2.1.1",
+ _DESCRIPTION = "tweening for lua",
+ _URL = "https://github.com/kikito/tween.lua",
+ _LICENSE = [[
+ MIT LICENSE
+ Copyright (c) 2014 Enrique GarcĂ­a Cota, Yuichi Tateno, Emmanuel Oga
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ ]],
+}
+
+local pow, sin, cos, pi, sqrt, abs, asin = math.pow, math.sin, math.cos, math.pi, math.sqrt, math.abs, math.asin
+
+-- linear
+local function linear(t, b, c, d)
+ return c * t / d + b
+end
+
+-- quad
+local function inQuad(t, b, c, d)
+ return c * pow(t / d, 2) + b
+end
+local function outQuad(t, b, c, d)
+ t = t / d
+ return -c * t * (t - 2) + b
+end
+local function inOutQuad(t, b, c, d)
+ t = t / d * 2
+ if t < 1 then
+ return c / 2 * pow(t, 2) + b
+ end
+ return -c / 2 * ((t - 1) * (t - 3) - 1) + b
+end
+local function outInQuad(t, b, c, d)
+ if t < d / 2 then
+ return outQuad(t * 2, b, c / 2, d)
+ end
+ return inQuad((t * 2) - d, b + c / 2, c / 2, d)
+end
+
+-- cubic
+local function inCubic(t, b, c, d)
+ return c * pow(t / d, 3) + b
+end
+local function outCubic(t, b, c, d)
+ return c * (pow(t / d - 1, 3) + 1) + b
+end
+local function inOutCubic(t, b, c, d)
+ t = t / d * 2
+ if t < 1 then
+ return c / 2 * t * t * t + b
+ end
+ t = t - 2
+ return c / 2 * (t * t * t + 2) + b
+end
+local function outInCubic(t, b, c, d)
+ if t < d / 2 then
+ return outCubic(t * 2, b, c / 2, d)
+ end
+ return inCubic((t * 2) - d, b + c / 2, c / 2, d)
+end
+
+-- quart
+local function inQuart(t, b, c, d)
+ return c * pow(t / d, 4) + b
+end
+local function outQuart(t, b, c, d)
+ return -c * (pow(t / d - 1, 4) - 1) + b
+end
+local function inOutQuart(t, b, c, d)
+ t = t / d * 2
+ if t < 1 then
+ return c / 2 * pow(t, 4) + b
+ end
+ return -c / 2 * (pow(t - 2, 4) - 2) + b
+end
+local function outInQuart(t, b, c, d)
+ if t < d / 2 then
+ return outQuart(t * 2, b, c / 2, d)
+ end
+ return inQuart((t * 2) - d, b + c / 2, c / 2, d)
+end
+
+-- quint
+local function inQuint(t, b, c, d)
+ return c * pow(t / d, 5) + b
+end
+local function outQuint(t, b, c, d)
+ return c * (pow(t / d - 1, 5) + 1) + b
+end
+local function inOutQuint(t, b, c, d)
+ t = t / d * 2
+ if t < 1 then
+ return c / 2 * pow(t, 5) + b
+ end
+ return c / 2 * (pow(t - 2, 5) + 2) + b
+end
+local function outInQuint(t, b, c, d)
+ if t < d / 2 then
+ return outQuint(t * 2, b, c / 2, d)
+ end
+ return inQuint((t * 2) - d, b + c / 2, c / 2, d)
+end
+
+-- sine
+local function inSine(t, b, c, d)
+ return -c * cos(t / d * (pi / 2)) + c + b
+end
+local function outSine(t, b, c, d)
+ return c * sin(t / d * (pi / 2)) + b
+end
+local function inOutSine(t, b, c, d)
+ return -c / 2 * (cos(pi * t / d) - 1) + b
+end
+local function outInSine(t, b, c, d)
+ if t < d / 2 then
+ return outSine(t * 2, b, c / 2, d)
+ end
+ return inSine((t * 2) - d, b + c / 2, c / 2, d)
+end
+
+-- expo
+local function inExpo(t, b, c, d)
+ if t == 0 then
+ return b
+ end
+ return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001
+end
+local function outExpo(t, b, c, d)
+ if t == d then
+ return b + c
+ end
+ return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b
+end
+local function inOutExpo(t, b, c, d)
+ if t == 0 then
+ return b
+ end
+ if t == d then
+ return b + c
+ end
+ t = t / d * 2
+ if t < 1 then
+ return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005
+ end
+ return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b
+end
+local function outInExpo(t, b, c, d)
+ if t < d / 2 then
+ return outExpo(t * 2, b, c / 2, d)
+ end
+ return inExpo((t * 2) - d, b + c / 2, c / 2, d)
+end
+
+-- circ
+local function inCirc(t, b, c, d)
+ return (-c * (sqrt(1 - pow(t / d, 2)) - 1) + b)
+end
+local function outCirc(t, b, c, d)
+ return (c * sqrt(1 - pow(t / d - 1, 2)) + b)
+end
+local function inOutCirc(t, b, c, d)
+ t = t / d * 2
+ if t < 1 then
+ return -c / 2 * (sqrt(1 - t * t) - 1) + b
+ end
+ t = t - 2
+ return c / 2 * (sqrt(1 - t * t) + 1) + b
+end
+local function outInCirc(t, b, c, d)
+ if t < d / 2 then
+ return outCirc(t * 2, b, c / 2, d)
+ end
+ return inCirc((t * 2) - d, b + c / 2, c / 2, d)
+end
+
+-- elastic
+local function calculatePAS(p, a, c, d)
+ p, a = p or d * 0.3, a or 0
+ if a < abs(c) then
+ return p, c, p / 4
+ end -- p, a, s
+ return p, a, p / (2 * pi) * asin(c / a) -- p,a,s
+end
+local function inElastic(t, b, c, d, a, p)
+ local s
+ if t == 0 then
+ return b
+ end
+ t = t / d
+ if t == 1 then
+ return b + c
+ end
+ p, a, s = calculatePAS(p, a, c, d)
+ t = t - 1
+ return -(a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
+end
+local function outElastic(t, b, c, d, a, p)
+ local s
+ if t == 0 then
+ return b
+ end
+ t = t / d
+ if t == 1 then
+ return b + c
+ end
+ p, a, s = calculatePAS(p, a, c, d)
+ return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) + c + b
+end
+local function inOutElastic(t, b, c, d, a, p)
+ local s
+ if t == 0 then
+ return b
+ end
+ t = t / d * 2
+ if t == 2 then
+ return b + c
+ end
+ p, a, s = calculatePAS(p, a, c, d)
+ t = t - 1
+ if t < 0 then
+ return -0.5 * (a * pow(2, 10 * t) * sin((t * d - s) * (2 * pi) / p)) + b
+ end
+ return a * pow(2, -10 * t) * sin((t * d - s) * (2 * pi) / p) * 0.5 + c + b
+end
+local function outInElastic(t, b, c, d, a, p)
+ if t < d / 2 then
+ return outElastic(t * 2, b, c / 2, d, a, p)
+ end
+ return inElastic((t * 2) - d, b + c / 2, c / 2, d, a, p)
+end
+
+-- back
+local function inBack(t, b, c, d, s)
+ s = s or 1.70158
+ t = t / d
+ return c * t * t * ((s + 1) * t - s) + b
+end
+local function outBack(t, b, c, d, s)
+ s = s or 1.70158
+ t = t / d - 1
+ return c * (t * t * ((s + 1) * t + s) + 1) + b
+end
+local function inOutBack(t, b, c, d, s)
+ s = (s or 1.70158) * 1.525
+ t = t / d * 2
+ if t < 1 then
+ return c / 2 * (t * t * ((s + 1) * t - s)) + b
+ end
+ t = t - 2
+ return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b
+end
+local function outInBack(t, b, c, d, s)
+ if t < d / 2 then
+ return outBack(t * 2, b, c / 2, d, s)
+ end
+ return inBack((t * 2) - d, b + c / 2, c / 2, d, s)
+end
+
+-- bounce
+local function outBounce(t, b, c, d)
+ t = t / d
+ if t < 1 / 2.75 then
+ return c * (7.5625 * t * t) + b
+ end
+ if t < 2 / 2.75 then
+ t = t - (1.5 / 2.75)
+ return c * (7.5625 * t * t + 0.75) + b
+ elseif t < 2.5 / 2.75 then
+ t = t - (2.25 / 2.75)
+ return c * (7.5625 * t * t + 0.9375) + b
+ end
+ t = t - (2.625 / 2.75)
+ return c * (7.5625 * t * t + 0.984375) + b
+end
+local function inBounce(t, b, c, d)
+ return c - outBounce(d - t, 0, c, d) + b
+end
+local function inOutBounce(t, b, c, d)
+ if t < d / 2 then
+ return inBounce(t * 2, 0, c, d) * 0.5 + b
+ end
+ return outBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b
+end
+local function outInBounce(t, b, c, d)
+ if t < d / 2 then
+ return outBounce(t * 2, b, c / 2, d)
+ end
+ return inBounce((t * 2) - d, b + c / 2, c / 2, d)
+end
+
+tween.easing = {
+ linear = linear,
+ inQuad = inQuad,
+ outQuad = outQuad,
+ inOutQuad = inOutQuad,
+ outInQuad = outInQuad,
+ inCubic = inCubic,
+ outCubic = outCubic,
+ inOutCubic = inOutCubic,
+ outInCubic = outInCubic,
+ inQuart = inQuart,
+ outQuart = outQuart,
+ inOutQuart = inOutQuart,
+ outInQuart = outInQuart,
+ inQuint = inQuint,
+ outQuint = outQuint,
+ inOutQuint = inOutQuint,
+ outInQuint = outInQuint,
+ inSine = inSine,
+ outSine = outSine,
+ inOutSine = inOutSine,
+ outInSine = outInSine,
+ inExpo = inExpo,
+ outExpo = outExpo,
+ inOutExpo = inOutExpo,
+ outInExpo = outInExpo,
+ inCirc = inCirc,
+ outCirc = outCirc,
+ inOutCirc = inOutCirc,
+ outInCirc = outInCirc,
+ inElastic = inElastic,
+ outElastic = outElastic,
+ inOutElastic = inOutElastic,
+ outInElastic = outInElastic,
+ inBack = inBack,
+ outBack = outBack,
+ inOutBack = inOutBack,
+ outInBack = outInBack,
+ inBounce = inBounce,
+ outBounce = outBounce,
+ inOutBounce = inOutBounce,
+ outInBounce = outInBounce,
+}
+
+-- Private interface
+local function copyTables(destination, keysTable, valuesTable)
+ valuesTable = valuesTable or keysTable
+ local mt = getmetatable(keysTable)
+ if mt and getmetatable(destination) == nil then
+ setmetatable(destination, mt)
+ end
+
+ for k, v in pairs(keysTable) do
+ if type(v) == "table" then
+ destination[k] = copyTables({}, v, valuesTable[k])
+ else
+ destination[k] = valuesTable[k]
+ end
+ end
+ return destination
+end
+
+local function checkSubjectAndTargetRecursively(subject, target, path)
+ path = path or {}
+ local targetType, newPath
+ for k, targetValue in pairs(target) do
+ targetType, newPath = type(targetValue), copyTables({}, path)
+ table.insert(newPath, tostring(k))
+ if targetType == "number" then
+ assert(
+ type(subject[k]) == "number",
+ "Parameter '" .. table.concat(newPath, "/") .. "' is missing from subject or isn't a number"
+ )
+ elseif targetType == "table" then
+ checkSubjectAndTargetRecursively(subject[k], targetValue, newPath)
+ else
+ assert(
+ targetType == "number",
+ "Parameter '" .. table.concat(newPath, "/") .. "' must be a number or table of numbers"
+ )
+ end
+ end
+end
+
+local function checkNewParams(initial, duration, subject, target, easing)
+ -- assert(type(initial) == 'number' and duration > 0, "duration must be a positive number. Was " .. tostring(duration))
+ -- assert(type(duration) == 'number' and duration > 0, "duration must be a positive number. Was " .. tostring(duration))
+ assert(type(easing) == "function", "easing must be a function. Was " .. tostring(easing))
+
+ if subject and target then
+ local tsubject = type(subject)
+ assert(
+ tsubject == "table" or tsubject == "userdata",
+ "subject must be a table or userdata. Was " .. tostring(subject)
+ )
+ assert(type(target) == "table", "target must be a table. Was " .. tostring(target))
+ checkSubjectAndTargetRecursively(subject, target)
+ end
+end
+
+local function getEasingFunction(easing)
+ easing = easing or "linear"
+ if type(easing) == "string" then
+ local name = easing
+ easing = tween.easing[name]
+ if type(easing) ~= "function" then
+ error("The easing function name '" .. name .. "' is invalid")
+ end
+ end
+ return easing
+end
+
+local function performEasingOnSubject(subject, target, initial, clock, duration, easing)
+ local t, b, c, d
+ for k, v in pairs(target) do
+ if type(v) == "table" then
+ performEasingOnSubject(subject[k], v, initial[k], clock, duration, easing)
+ else
+ t, b, c, d = clock, initial[k], v - initial[k], duration
+ subject[k] = easing(t, b, c, d)
+ end
+ end
+end
+
+-- local function performEasingOnColor(initial, target, clock, duration, easing)
+-- initial = Color(initial)
+-- target = Color(target)
+--
+-- local r = easing(clock, initial.r, target.r - initial.r, duration)
+-- local g = easing(clock, initial.g, target.g - initial.g, duration)
+-- local b = easing(clock, initial.b, target.b - initial.b, duration)
+-- local a = easing(clock, initial.a, target.a - initial.a, duration)
+--
+-- return tostring(Color { r = r, g = g, b = b, a = a })
+-- end
+
+local function performEasing(table, initial, target, clock, duration, easing)
+ if type(target) == "table" then
+ local t, b, c, d
+ for k, target in pairs(target) do
+ if type(target) == "table" then
+ table[k] = {}
+ performEasing(table[k], initial[k], target, clock, duration, easing)
+ -- elseif type(target) == "string" and target:sub(1, 1) == "#" then
+ -- table[k] = performEasingOnColor(initial[k], target, clock, duration, easing)
+ else
+ t, b, c, d = clock, initial[k], target - initial[k], duration
+ table[k] = easing(t, b, c, d)
+ end
+ end
+
+ return table
+ -- elseif type(target) == "string" and target:sub(1, 1) == "#" then
+ -- return performEasingOnColor(initial, target, clock, duration, easing)
+ else
+ local t, b, c, d = clock, initial, target - initial, duration
+ return easing(t, b, c, d)
+ end
+end
+
+-- Public interface
+local Tween = {}
+
+function Tween:set(clock)
+ assert(type(clock) == "number", "clock must be a positive number or 0")
+
+ if self.subject and self.initial == 0 then
+ self.initial = copyTables({}, self.target, self.subject)
+ end
+
+ self.clock = clock
+
+ if self.clock <= 0 then
+ self.clock = 0
+ if self.subject then
+ copyTables(self.subject, self.initial)
+ end
+ elseif self.clock >= self.duration then -- the tween has expired
+ self.clock = self.duration
+
+ if self.subject then
+ copyTables(self.subject, self.target)
+ end
+ else
+ if self.subject then
+ performEasingOnSubject(self.subject, self.target, self.initial, self.clock, self.duration, self.easing)
+ else
+ local pos = {}
+ return performEasing(pos, self.initial, self.target, self.clock, self.duration, self.easing)
+ end
+ end
+
+ return self.clock >= self.duration
+end
+
+function Tween:update(dt)
+ assert(type(dt) == "number", "dt must be a number")
+ return self:set(self.clock + dt)
+end
+
+function Tween:reset()
+ return self:set(0)
+end
+
+function tween.new(args)
+ args = args or {}
+
+ args.initial = args.initial or 0
+ args.subject = args.subject or nil
+ args.target = args.target or nil
+ args.duration = args.duration or 0
+ args.easing = args.easing or nil
+
+ args.easing = getEasingFunction(args.easing)
+ checkNewParams(args.initial, args.duration, args.subject, args.target, args.easing)
+
+ local ret = gobject {}
+ ret.clock = 0
+
+ gtable.crush(ret, args, true)
+ gtable.crush(ret, Tween, true)
+
+ return ret
+end
+
+return tween
diff --git a/.config/awesome/quarrel/bezier.lua b/.config/awesome/quarrel/bezier.lua
deleted file mode 100644
index 4229961..0000000
--- a/.config/awesome/quarrel/bezier.lua
+++ /dev/null
@@ -1,343 +0,0 @@
----------------------------------------------------------------------------
---- A helper module for computations involving Bézier curves
---
--- @author Alex Belykh &lt;albel727@ngs.ru&gt;
--- @copyright 2021 Alex Belykh
--- @submodule gears.math
----------------------------------------------------------------------------
-
-local table_insert = table.insert
-
-local bezier = {}
-
---- Compute the value of a Bézier curve at a given value of the t parameter.
---
--- This function evaluates the given curve `B` of an arbitrary degree
--- at a given point t.
---
--- @tparam {number,...} c The table of control points of the curve.
--- @tparam number t The value of the t parameter to evaluate the curve at.
--- @treturn[1] number The value of `B(t)`.
--- @treturn[2] nil `nil`, if c is empty.
--- @staticfct gears.math.bezier.curve_evaluate_at
--- @see wibox.widget.graph.step_hook
-function bezier.curve_evaluate_at(c, t)
- local from = c
- local tmp = { nil, nil, nil, nil }
- while #from > 1 do
- for i = 1, #from - 1 do
- tmp[i] = from[i] * (1 - t) + from[i + 1] * t
- end
- tmp[#from] = nil
- from = tmp
- end
-
- return from[1]
-end
-
---- Split a Bézier curve into two curves at a given value of the t parameter.
---
--- This function splits the given curve `B` of an arbitrary degree at a point t
--- into two curves of the same degree `B_left` and `B_right`, such that
--- `B_left(0)=B(0)`, `B_left(1)=B(t)=B_right(0)`, `B_right(1)=B(1)`.
---
--- @tparam {number,...} c The table of control points of the curve.
--- @tparam number t The value of the t parameter to split the curve at.
--- @treturn {number,...} The table of control points for `B_left`.
--- @treturn {number,...} The table of control points for `B_right`.
--- @staticfct gears.math.bezier.curve_split_at
--- @see wibox.widget.graph.step_hook
-function bezier.curve_split_at(c, t)
- local coefs_left, coefs_right = {}, {}
- local from = c
- local tmp = { nil, nil, nil, nil }
- while #from > 0 do
- table_insert(coefs_left, from[1])
- table_insert(coefs_right, 1, from[#from])
- for i = 1, #from - 1 do
- tmp[i] = from[i] * (1 - t) + from[i + 1] * t
- end
- tmp[#from] = nil
- from = tmp
- end
-
- return coefs_left, coefs_right
-end
-
---- Get the n-th derivative Bézier curve of a Bézier curve.
---
--- This function computes control points for the curve that is
--- the derivative of order `n` in `t`, i.e. `B^(n)(t)`,
--- of the given curve `B(t)` of an arbitrary degree.
---
--- @tparam {number,...} c The table of control points of the curve.
--- @tparam[opt=1] integer n The order of the derivative to take.
--- @treturn[1] {number,...} The table of control points of `B^(n)(t)`.
--- @treturn[2] nil If n is less than 0.
--- @staticfct gears.math.bezier.curve_derivative
--- @see wibox.widget.graph.step_hook
-function bezier.curve_derivative(c, n)
- n = n or 1
- if n < 0 then
- return
- end
- if n < 1 then
- return c
- end
- local c_len = #c
- if c_len < n + 1 then
- return {}
- end
-
- local from = c
- local tmp = {}
-
- for l = c_len - 1, c_len - n, -1 do
- for i = 1, l do
- tmp[i] = (from[i + 1] - from[i]) * l
- end
- tmp[l + 1] = nil
- from = tmp
- end
-
- return from
-end
-
--- This is used instead of plain 0 to try and be compatible
--- with objects that implement their own arithmetic via metatables.
-local function get_zero(c, zero)
- return c and c * 0 or zero
-end
-
---- Compute the value of the n-th derivative of a Bézier curve
---- at a given value of the t parameter.
---
--- This is roughly the same as
--- `curve_evaluate_at(curve_derivative(c, n), t)`, but the latter
--- would throw errors or return nil instead of 0 in some cases.
---
--- @tparam {number,...} c The table of control points of the curve.
--- @tparam number t The value of the t parameter to compute the derivative at.
--- @tparam[opt=1] integer n The order of the derivative to take.
--- @tparam[opt=nil] number|nil zero The value to return if c is empty.
--- @treturn[1] number The value of `B^(n)(t)`.
--- @treturn[2] nil nil, if n is less than 0.
--- @treturn[3] number|nil The value of the zero parameter, if c is empty.
--- @staticfct gears.math.bezier.curve_derivative_at
--- @see wibox.widget.graph.step_hook
-function bezier.curve_derivative_at(c, t, n, zero)
- local d = bezier.curve_derivative(c, n)
- if not d then
- return
- end
-
- return bezier.curve_evaluate_at(d, t) or get_zero(c[1], zero)
-end
-
---- Compute the value of the 1-st derivative of a Bézier curve at t=0.
---
--- This is the same as `curve_derivative_at(c, 0)`, but since it's particularly
--- computationally simple and useful in practice, it has its own function.
---
--- @tparam {number,...} c The table of control points of the curve.
--- @tparam[opt=nil] number|nil zero The value to return if c is empty.
--- @treturn[1] number The value of `B'(0)`.
--- @treturn[2] number|nil The value of the zero parameter, if c is empty.
--- @staticfct gears.math.bezier.curve_derivative_at_zero
--- @see wibox.widget.graph.step_hook
-function bezier.curve_derivative_at_zero(c, zero)
- local l = #c
- if l < 2 then
- return get_zero(c[1], zero)
- end
- return (c[2] - c[1]) * (l - 1)
-end
-
---- Compute the value of the 1-st derivative of a Bézier curve at t=1.
---
--- This is the same as `curve_derivative_at(c, 1)`, but since it's particularly
--- computationally simple and useful in practice, it has its own function.
---
--- @tparam {number,...} c The table of control points of the curve.
--- @tparam[opt=nil] number|nil zero The value to return if c is empty.
--- @treturn[1] number The value of `B'(1)`.
--- @treturn[2] number|nil The value of the zero parameter, if c is empty.
--- @staticfct gears.math.bezier.curve_derivative_at_one
--- @see wibox.widget.graph.step_hook
-function bezier.curve_derivative_at_one(c, zero)
- local l = #c
- if l < 2 then
- return get_zero(c[1], zero)
- end
- return (c[l] - c[l - 1]) * (l - 1)
-end
-
---- Get the (n+1)-th degree Bézier curve, that has the same shape as
--- a given n-th degree Bézier curve.
---
--- Given the control points of a curve B of degree n, this function computes
--- the control points for the curve Q, such that `Q(t) = B(t)`, and
--- Q has the degree n+1, i.e. it has one control point more.
---
--- @tparam {number,...} c The table of control points of the curve B.
--- @treturn {number,...} The table of control points of the curve Q.
--- @staticfct gears.math.bezier.curve_elevate_degree
--- @see wibox.widget.graph.step_hook
-function bezier.curve_elevate_degree(c)
- local ret = { c[1] }
- local len = #c
-
- for i = 1, len - 1 do
- ret[i + 1] = (i * c[i] + (len - i) * c[i + 1]) / len
- end
-
- ret[len + 1] = c[len]
- return ret
-end
-
---- Get a cubic Bézier curve that passes through given points (up to 4).
---
--- This function takes up to 4 values and returns the 4 control points
--- for a cubic curve
---
--- `B(t) = c0\*(1-t)^3 + 3\*c1\*t\*(1-t)^2 + 3\*c2\*t^2\*(1-t) + c3\*t^3`,
--- that takes on these values at equidistant values of the t parameter.
---
--- If only p0 is given, `B(0)=B(1)=B(for all t)=p0`.
---
--- If p0 and p1 are given, `B(0)=p0` and `B(1)=p1`.
---
--- If p0, p1 and p2 are given, `B(0)=p0`, `B(1/2)=p1` and `B(1)=p2`.
---
--- For 4 points given, `B(0)=p0`, `B(1/3)=p1`, `B(2/3)=p2`, `B(1)=p3`.
---
--- @tparam number p0
--- @tparam[opt] number p1
--- @tparam[opt] number p2
--- @tparam[opt] number p3
--- @treturn number c0
--- @treturn number c1
--- @treturn number c2
--- @treturn number c3
--- @staticfct gears.math.bezier.cubic_through_points
--- @see wibox.widget.graph.step_hook
-function bezier.cubic_through_points(p0, p1, p2, p3)
- if not p1 then
- return p0, p0, p0, p0
- end
- if not p2 then
- local c1 = (2 * p0 + p1) / 3
- local c2 = (2 * p1 + p0) / 3
- return p0, c1, c2, p1
- end
- if not p3 then
- local c1 = (4 * p1 - p2) / 3
- local c2 = (4 * p1 - p0) / 3
- return p0, c1, c2, p2
- end
- local c1 = (-5 * p0 + 18 * p1 - 9 * p2 + 2 * p3) / 6
- local c2 = (-5 * p3 + 18 * p2 - 9 * p1 + 2 * p0) / 6
- return p0, c1, c2, p3
-end
-
---- Get a cubic Bézier curve with given values and derivatives at endpoints.
---
--- This function computes the 4 control points for the cubic curve B, such that
--- `B(0)=p0`, `B'(0)=d0`, `B(1)=p3`, `B'(1)=d3`.
---
--- @tparam number d0 The value of the derivative at t=0.
--- @tparam number p0 The value of the curve at t=0.
--- @tparam number p3 The value of the curve at t=1.
--- @tparam number d3 The value of the derivative at t=1.
--- @treturn number c0
--- @treturn number c1
--- @treturn number c2
--- @treturn number c3
--- @staticfct gears.math.bezier.cubic_from_points_and_derivatives
--- @see wibox.widget.graph.step_hook
-function bezier.cubic_from_points_and_derivatives(d0, p0, p3, d3)
- local c1 = p0 + d0 / 3
- local c2 = p3 - d3 / 3
- return p0, c1, c2, p3
-end
-
---- Get a cubic Bézier curve with given values at endpoints and starting
---- derivative, while minimizing (an approximation of) the stretch energy.
---
--- This function computes the 4 control points for the cubic curve B, such that
--- `B(0)=p0`, `B'(0)=d0`, `B(1)=p3`, and
--- the integral of `(B'(t))^2` on `t=[0,1]` is minimal.
--- (The actual stretch energy is the integral of `|B'(t)|`)
---
--- In practical terms this is almost the same as "the curve of shortest length
--- connecting given points and having the given starting speed".
---
--- @tparam number d0 The value of the derivative at t=0.
--- @tparam number p0 The value of the curve at t=0.
--- @tparam number p3 The value of the curve at t=1.
--- @treturn number c0
--- @treturn number c1
--- @treturn number c2
--- @treturn number c3
--- @staticfct gears.math.bezier.cubic_from_derivative_and_points_min_stretch
--- @see wibox.widget.graph.step_hook
-function bezier.cubic_from_derivative_and_points_min_stretch(d0, p0, p3)
- local c1 = p0 + d0 / 3
- local c2 = (2 * p0 - c1 + 3 * p3) / 4
- return p0, c1, c2, p3
-end
-
---- Get a cubic Bézier curve with given values at endpoints and starting
---- derivative, while minimizing (an approximation of) the strain energy.
---
--- This function computes the 4 control points for the cubic curve B, such that
--- `B(0)=p0`, `B'(0)=d0`, `B(1)=p3`, and
--- the integral of `(B''(t))^2` on `t=[0,1]` is minimal.
---
--- In practical terms this is almost the same as "the curve of smallest
--- speed change connecting given points and having the given starting speed".
---
--- @tparam number d0 The value of the derivative at t=0.
--- @tparam number p0 The value of the curve at t=0.
--- @tparam number p3 The value of the curve at t=1.
--- @treturn number c0
--- @treturn number c1
--- @treturn number c2
--- @treturn number c3
--- @staticfct gears.math.bezier.cubic_from_derivative_and_points_min_strain
--- @see wibox.widget.graph.step_hook
-function bezier.cubic_from_derivative_and_points_min_strain(d, p0, p3)
- local c1 = p0 + d / 3
- local c2 = (c1 + p3) / 2
- return p0, c1, c2, p3
-end
-
---- Get a cubic Bézier curve with given values at endpoints and starting
---- derivative, while minimizing the jerk energy.
---
--- This function computes the 4 control points for the cubic curve B, such that
--- `B(0)=p0`, `B'(0)=d0`, `B(1)=p3`, and
--- the integral of `(B'''(t))^2` on `t=[0,1]` is minimal.
---
--- In practical terms this is almost the same as "the curve of smallest
--- acceleration change connecting given points and having the given
--- starting speed".
---
--- @tparam number d0 The value of the derivative at t=0.
--- @tparam number p0 The value of the curve at t=0.
--- @tparam number p3 The value of the curve at t=1.
--- @treturn number c0
--- @treturn number c1
--- @treturn number c2
--- @treturn number c3
--- @staticfct gears.math.bezier.cubic_from_derivative_and_points_min_jerk
--- @see wibox.widget.graph.step_hook
-function bezier.cubic_from_derivative_and_points_min_jerk(d, p0, p3)
- local c1 = p0 + d / 3
- local c2 = c1 + (p3 - p0) / 3
- return p0, c1, c2, p3
-end
-
-return bezier
-
--- vim: filetype=lua:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80
diff --git a/.config/awesome/quarrel/bind/consts.lua b/.config/awesome/quarrel/bind/consts.lua
new file mode 100644
index 0000000..5a91d84
--- /dev/null
+++ b/.config/awesome/quarrel/bind/consts.lua
@@ -0,0 +1,27 @@
+local awful = require "awful"
+
+local C = {}
+
+-- taken from https://github.com/bew/dotfiles/blob/ab9bb1935783f7a31ef777b1d7e26d53f35df864/gui/wezterm/cfg_utils.lua
+C.mods = setmetatable({ _SHORT_MAP = { C = "Control", S = "Shift", A = "Mod1", M = "Mod4" } }, {
+ __index = function(self, key)
+ local resolved_mods = {}
+ for i = 1, #key do
+ resolved_mods[i] = self._SHORT_MAP[key:sub(i, i)]
+ end
+ return resolved_mods
+ end,
+})
+
+local btns = awful.button.names
+
+---@enum buttons
+C.btns = {
+ left = btns.LEFT,
+ right = btns.RIGHT,
+ middle = btns.MIDDLE,
+ up = btns.SCROLL_UP,
+ down = btns.SCROLL_DOWN,
+}
+
+return C
diff --git a/.config/awesome/quarrel/bind.lua b/.config/awesome/quarrel/bind/init.lua
index a1abf29..a851440 100644
--- a/.config/awesome/quarrel/bind.lua
+++ b/.config/awesome/quarrel/bind/init.lua
@@ -1,11 +1,10 @@
+local C = require "quarrel.bind.consts"
local awful = require "awful"
local gtable = require "gears.table"
-local qstore = require "quarrel.store"
----@class QuarrelBind
-local qbind = {}
-
-qstore.bindings = {}
+local M = gtable.crush({
+ bindings = {},
+}, C)
---@alias mouse_button
---| 0 Left mouse button
@@ -35,7 +34,7 @@ qstore.bindings = {}
---@field press fun(...) | fun(any, ...) Function to run when the trigger is pressed
---@field desc string? Description
---@field group string? What group the binding will show up in
----@field triggers Trigger[] | bind
+---@field triggers Trigger[] | bind[] | bind
---Get the corresponding binding creation function for a trigger
---@param bind bind
@@ -83,24 +82,30 @@ end
--- Create a new binding
---@param binding Binding
---@return awful.key[]
-function qbind:new(binding)
+function M:new(binding)
if not binding.hidden then
- table.insert(qstore.bindings, binding)
+ table.insert(self.bindings, binding)
end
binding.mods = binding.mods or {}
local awful_bindings = {}
if type(binding.triggers) == "table" then
- for _, trigger in
- ipairs(binding.triggers --[[@as Trigger[]])
+ for _, _trigger in
+ ipairs(binding.triggers --[[@as bind[] | Trigger[]])
do
+ local trigger
+ if type(_trigger) == "table" then
+ trigger = _trigger
+ elseif type(_trigger) == "string" or type(_trigger) == "number" then
+ trigger = { _trigger, _trigger }
+ end
table.insert(awful_bindings, translate_binding(binding, trigger, true))
end
elseif type(binding.triggers) == "string" or type(binding.triggers) == "number" then
return translate_binding(binding, binding.triggers --[[@as bind]], false)
else
- error "binding.triggers can only be a string or a table"
+ error("binding.triggers can only be a string or a table (passed in " .. type(binding.triggers) .. ")")
end
-- for some reason multi-trigger bindings only work if i do this
@@ -109,4 +114,6 @@ function qbind:new(binding)
return gtable.join(table.unpack(awful_bindings))
end
-return qbind
+return setmetatable(M, {
+ __call = M.new,
+})
diff --git a/.config/awesome/quarrel/color.lua b/.config/awesome/quarrel/color.lua
new file mode 100644
index 0000000..b96ef57
--- /dev/null
+++ b/.config/awesome/quarrel/color.lua
@@ -0,0 +1,64 @@
+-- autogenerated from palette.json
+local M = {}
+
+local function tone_set(colors)
+ return setmetatable(colors, {
+ __call = function(self)
+ return self[1]
+ end,
+ })
+end
+
+M.palette = {
+ bg = tone_set {
+ high = "#171c22",
+ highest = "#1d2228",
+ low = "#0c1116",
+ lowest = "#070c11",
+ "#12161c",
+ },
+ blue = tone_set {
+ bright = "#abe4ff",
+ "#8bc3fc",
+ },
+ border = tone_set {
+ "#323b46",
+ variant = "#262f39",
+ },
+ cyan = tone_set {
+ bright = "#8ef4e2",
+ "#6dd3c2",
+ },
+ fg = tone_set {
+ high = "#e8eff8",
+ low = "#a8afb7",
+ "#c8ced7",
+ },
+ green = tone_set {
+ bright = "#abf3b3",
+ "#8bd294",
+ },
+ orange = tone_set {
+ bright = "#ffc08e",
+ "#ff9f6f",
+ },
+ pink = tone_set {
+ bright = "#ffccd4",
+ "#e5acb4",
+ },
+ purple = tone_set {
+ bright = "#e4d1ff",
+ "#c4b1f6",
+ },
+ red = tone_set {
+ bright = "#ffb2a9",
+ "#ff928a",
+ },
+ yellow = tone_set {
+ bright = "#ffd278",
+ "#ecb256",
+ },
+ transparent = "#00000000",
+}
+
+return M
diff --git a/.config/awesome/quarrel/const.lua b/.config/awesome/quarrel/const.lua
new file mode 100644
index 0000000..342ae41
--- /dev/null
+++ b/.config/awesome/quarrel/const.lua
@@ -0,0 +1,22 @@
+local M = {}
+
+---@param protected (fun(): table) | table
+function M.protect(protected)
+ ---@type table
+ local tbl
+ if type(protected) == "table" then
+ tbl = protected
+ elseif type(protected) == "function" then
+ tbl = protected()
+ else
+ error("expected a table or a function that returns a table, got " .. type(protected), 2)
+ end
+ return setmetatable({}, {
+ __index = tbl,
+ __newindex = function(_, k, v)
+ error("attempted to change constant " .. tostring(k) .. " to " .. tostring(v), 2)
+ end,
+ })
+end
+
+return M
diff --git a/.config/awesome/quarrel/debugger.lua b/.config/awesome/quarrel/debugger.lua
new file mode 100644
index 0000000..b1a272a
--- /dev/null
+++ b/.config/awesome/quarrel/debugger.lua
@@ -0,0 +1,865 @@
+-- SPDX-License-Identifier: MIT
+-- Copyright (c) 2024 Scott Lembcke and Howling Moon Software
+
+local dbg
+
+-- Use ANSI color codes in the prompt by default.
+local COLOR_GRAY = ""
+local COLOR_RED = ""
+local COLOR_BLUE = ""
+local COLOR_YELLOW = ""
+local COLOR_RESET = ""
+local GREEN_CARET = " => "
+
+local function pretty(obj, max_depth)
+ if max_depth == nil then
+ max_depth = dbg.pretty_depth
+ end
+
+ -- Returns true if a table has a __tostring metamethod.
+ local function coerceable(tbl)
+ local meta = getmetatable(tbl)
+ return (meta and meta.__tostring)
+ end
+
+ local function recurse(obj, depth)
+ if type(obj) == "string" then
+ -- Dump the string so that escape sequences are printed.
+ return string.format("%q", obj)
+ elseif type(obj) == "table" and depth < max_depth and not coerceable(obj) then
+ local str = "{"
+
+ for k, v in pairs(obj) do
+ local pair = pretty(k, 0) .. " = " .. recurse(v, depth + 1)
+ str = str .. (str == "{" and pair or ", " .. pair)
+ end
+
+ return str .. "}"
+ else
+ -- tostring() can fail if there is an error in a __tostring metamethod.
+ local success, value = pcall(function()
+ return tostring(obj)
+ end)
+ return (success and value or "<!!error in __tostring metamethod!!>")
+ end
+ end
+
+ return recurse(obj, 0)
+end
+
+-- The stack level that cmd_* functions use to access locals or info
+-- The structure of the code very carefully ensures this.
+local CMD_STACK_LEVEL = 6
+
+-- Location of the top of the stack outside of the debugger.
+-- Adjusted by some debugger entrypoints.
+local stack_top = 0
+
+-- The current stack frame index.
+-- Changed using the up/down commands
+local stack_inspect_offset = 0
+
+-- LuaJIT has an off by one bug when setting local variables.
+local LUA_JIT_SETLOCAL_WORKAROUND = 0
+
+-- Default dbg.read function
+local function dbg_read(prompt)
+ dbg.write(prompt)
+ io.flush()
+ return io.read()
+end
+
+-- Default dbg.write function
+local function dbg_write(str)
+ io.write(str)
+end
+
+local function dbg_writeln(str, ...)
+ if select("#", ...) == 0 then
+ dbg.write((str or "<NULL>") .. "\n")
+ else
+ dbg.write(string.format(str .. "\n", ...))
+ end
+end
+
+local function format_loc(file, line)
+ return COLOR_BLUE .. file .. COLOR_RESET .. ":" .. COLOR_YELLOW .. line .. COLOR_RESET
+end
+local function format_stack_frame_info(info)
+ local filename = info.source:match "@(.*)"
+ local source = filename and dbg.shorten_path(filename) or info.short_src
+ local namewhat = (info.namewhat == "" and "chunk at" or info.namewhat)
+ local name = (
+ info.name and "'" .. COLOR_BLUE .. info.name .. COLOR_RESET .. "'" or format_loc(source, info.linedefined)
+ )
+ return format_loc(source, info.currentline) .. " in " .. namewhat .. " " .. name
+end
+
+local repl
+
+-- Return false for stack frames without source,
+-- which includes C frames, Lua bytecode, and `loadstring` functions
+local function frame_has_line(info)
+ return info.currentline >= 0
+end
+
+local function hook_factory(repl_threshold)
+ return function(offset, reason)
+ return function(event, _)
+ -- Skip events that don't have line information.
+ if not frame_has_line(debug.getinfo(2)) then
+ return
+ end
+
+ -- Tail calls are specifically ignored since they also will have tail returns to balance out.
+ if event == "call" then
+ offset = offset + 1
+ elseif event == "return" and offset > repl_threshold then
+ offset = offset - 1
+ elseif event == "line" and offset <= repl_threshold then
+ repl(reason)
+ end
+ end
+ end
+end
+
+local hook_step = hook_factory(1)
+local hook_next = hook_factory(0)
+local hook_finish = hook_factory(-1)
+
+-- Create a table of all the locally accessible variables.
+-- Globals are not included when running the locals command, but are when running the print command.
+local function local_bindings(offset, include_globals)
+ local level = offset + stack_inspect_offset + CMD_STACK_LEVEL
+ local func = debug.getinfo(level).func
+ local bindings = {}
+
+ -- Retrieve the upvalues
+ do
+ local i = 1
+ while true do
+ local name, value = debug.getupvalue(func, i)
+ if not name then
+ break
+ end
+ bindings[name] = value
+ i = i + 1
+ end
+ end
+
+ -- Retrieve the locals (overwriting any upvalues)
+ do
+ local i = 1
+ while true do
+ local name, value = debug.getlocal(level, i)
+ if not name then
+ break
+ end
+ bindings[name] = value
+ i = i + 1
+ end
+ end
+
+ -- Retrieve the varargs (works in Lua 5.2 and LuaJIT)
+ local varargs = {}
+ do
+ local i = 1
+ while true do
+ local name, value = debug.getlocal(level, -i)
+ if not name then
+ break
+ end
+ varargs[i] = value
+ i = i + 1
+ end
+ end
+ if #varargs > 0 then
+ bindings["..."] = varargs
+ end
+
+ if include_globals then
+ -- In Lua 5.2, you have to get the environment table from the function's locals.
+ local env = (_VERSION <= "Lua 5.1" and getfenv(func) or bindings._ENV)
+ return setmetatable(bindings, { __index = env or _G })
+ else
+ return bindings
+ end
+end
+
+-- Used as a __newindex metamethod to modify variables in cmd_eval().
+local function mutate_bindings(_, name, value)
+ local FUNC_STACK_OFFSET = 3 -- Stack depth of this function.
+ local level = stack_inspect_offset + FUNC_STACK_OFFSET + CMD_STACK_LEVEL
+
+ -- Set a local.
+ do
+ local i = 1
+ repeat
+ local var = debug.getlocal(level, i)
+ if name == var then
+ dbg_writeln(
+ COLOR_YELLOW
+ .. "debugger.lua"
+ .. GREEN_CARET
+ .. "Set local variable "
+ .. COLOR_BLUE
+ .. name
+ .. COLOR_RESET
+ )
+ return debug.setlocal(level + LUA_JIT_SETLOCAL_WORKAROUND, i, value)
+ end
+ i = i + 1
+ until var == nil
+ end
+
+ -- Set an upvalue.
+ local func = debug.getinfo(level).func
+ do
+ local i = 1
+ repeat
+ local var = debug.getupvalue(func, i)
+ if name == var then
+ dbg_writeln(
+ COLOR_YELLOW .. "debugger.lua" .. GREEN_CARET .. "Set upvalue " .. COLOR_BLUE .. name .. COLOR_RESET
+ )
+ return debug.setupvalue(func, i, value)
+ end
+ i = i + 1
+ until var == nil
+ end
+
+ -- Set a global.
+ dbg_writeln(
+ COLOR_YELLOW .. "debugger.lua" .. GREEN_CARET .. "Set global variable " .. COLOR_BLUE .. name .. COLOR_RESET
+ )
+ _G[name] = value
+end
+
+-- Compile an expression with the given variable bindings.
+local function compile_chunk(block, env)
+ local source = "debugger.lua REPL"
+ local chunk = nil
+
+ if _VERSION <= "Lua 5.1" then
+ chunk = loadstring(block, source)
+ if chunk then
+ setfenv(chunk, env)
+ end
+ else
+ -- The Lua 5.2 way is a bit cleaner
+ chunk = load(block, source, "t", env)
+ end
+
+ if not chunk then
+ dbg_writeln(COLOR_RED .. "Error: Could not compile block:\n" .. COLOR_RESET .. block)
+ end
+ return chunk
+end
+
+local SOURCE_CACHE = {}
+
+local function where(info, context_lines)
+ local source = SOURCE_CACHE[info.source]
+ if not source then
+ source = {}
+ local filename = info.source:match "@(.*)"
+ if filename then
+ pcall(function()
+ for line in io.lines(filename) do
+ table.insert(source, line)
+ end
+ end)
+ elseif info.source then
+ for line in info.source:gmatch "[^\n]+" do
+ table.insert(source, line)
+ end
+ end
+ SOURCE_CACHE[info.source] = source
+ end
+
+ if source and source[info.currentline] then
+ for i = info.currentline - context_lines, info.currentline + context_lines do
+ local tab_or_caret = (i == info.currentline and GREEN_CARET or " ")
+ local line = source[i]
+ if line then
+ dbg_writeln(COLOR_GRAY .. "% 4d" .. tab_or_caret .. "%s", i, line)
+ end
+ end
+ else
+ dbg_writeln(COLOR_RED .. "Error: Source not available for " .. COLOR_BLUE .. info.short_src)
+ end
+
+ return false
+end
+
+-- Wee version differences
+local unpack = unpack or table.unpack
+local pack = function(...)
+ return { n = select("#", ...), ... }
+end
+
+local function cmd_step()
+ stack_inspect_offset = stack_top
+ return true, hook_step
+end
+
+local function cmd_next()
+ stack_inspect_offset = stack_top
+ return true, hook_next
+end
+
+local function cmd_finish()
+ local offset = stack_top - stack_inspect_offset
+ stack_inspect_offset = stack_top
+ return true, offset < 0 and hook_factory(offset - 1) or hook_finish
+end
+
+local function cmd_print(expr)
+ local env = local_bindings(1, true)
+ local chunk = compile_chunk("return " .. expr, env)
+ if chunk == nil then
+ return false
+ end
+
+ -- Call the chunk and collect the results.
+ local results = pack(pcall(chunk, unpack(rawget(env, "...") or {})))
+
+ -- The first result is the pcall error.
+ if not results[1] then
+ dbg_writeln(COLOR_RED .. "Error:" .. COLOR_RESET .. " " .. results[2])
+ else
+ local output = ""
+ for i = 2, results.n do
+ output = output .. (i ~= 2 and ", " or "") .. dbg.pretty(results[i])
+ end
+
+ if output == "" then
+ output = "<no result>"
+ end
+ dbg_writeln(COLOR_BLUE .. expr .. GREEN_CARET .. output)
+ end
+
+ return false
+end
+
+local function cmd_eval(code)
+ local env = local_bindings(1, true)
+ local mutable_env = setmetatable({}, {
+ __index = env,
+ __newindex = mutate_bindings,
+ })
+
+ local chunk = compile_chunk(code, mutable_env)
+ if chunk == nil then
+ return false
+ end
+
+ -- Call the chunk and collect the results.
+ local success, err = pcall(chunk, unpack(rawget(env, "...") or {}))
+ if not success then
+ dbg_writeln(COLOR_RED .. "Error:" .. COLOR_RESET .. " " .. tostring(err))
+ end
+
+ return false
+end
+
+local function cmd_down()
+ local offset = stack_inspect_offset
+ local info
+
+ repeat -- Find the next frame with a file.
+ offset = offset + 1
+ info = debug.getinfo(offset + CMD_STACK_LEVEL)
+ until not info or frame_has_line(info)
+
+ if info then
+ stack_inspect_offset = offset
+ dbg_writeln("Inspecting frame: " .. format_stack_frame_info(info))
+ if tonumber(dbg.auto_where) then
+ where(info, dbg.auto_where)
+ end
+ else
+ info = debug.getinfo(stack_inspect_offset + CMD_STACK_LEVEL)
+ dbg_writeln "Already at the bottom of the stack."
+ end
+
+ return false
+end
+
+local function cmd_up()
+ local offset = stack_inspect_offset
+ local info
+
+ repeat -- Find the next frame with a file.
+ offset = offset - 1
+ if offset < stack_top then
+ info = nil
+ break
+ end
+ info = debug.getinfo(offset + CMD_STACK_LEVEL)
+ until frame_has_line(info)
+
+ if info then
+ stack_inspect_offset = offset
+ dbg_writeln("Inspecting frame: " .. format_stack_frame_info(info))
+ if tonumber(dbg.auto_where) then
+ where(info, dbg.auto_where)
+ end
+ else
+ info = debug.getinfo(stack_inspect_offset + CMD_STACK_LEVEL)
+ dbg_writeln "Already at the top of the stack."
+ end
+
+ return false
+end
+
+local function cmd_inspect(offset)
+ offset = stack_top + tonumber(offset)
+ local info = debug.getinfo(offset + CMD_STACK_LEVEL)
+ if info then
+ stack_inspect_offset = offset
+ dbg.writeln("Inspecting frame: " .. format_stack_frame_info(info))
+ else
+ dbg.writeln(COLOR_RED .. "ERROR: " .. COLOR_BLUE .. "Invalid stack frame index." .. COLOR_RESET)
+ end
+end
+
+local function cmd_where(context_lines)
+ local info = debug.getinfo(stack_inspect_offset + CMD_STACK_LEVEL)
+ return (info and where(info, tonumber(context_lines) or 5))
+end
+
+local function cmd_trace()
+ dbg_writeln("Inspecting frame %d", stack_inspect_offset - stack_top)
+ local i = 0
+ while true do
+ local info = debug.getinfo(stack_top + CMD_STACK_LEVEL + i)
+ if not info then
+ break
+ end
+
+ local is_current_frame = (i + stack_top == stack_inspect_offset)
+ local tab_or_caret = (is_current_frame and GREEN_CARET or " ")
+ dbg_writeln(COLOR_GRAY .. "% 4d" .. COLOR_RESET .. tab_or_caret .. "%s", i, format_stack_frame_info(info))
+ i = i + 1
+ end
+
+ return false
+end
+
+local function cmd_locals()
+ local bindings = local_bindings(1, false)
+
+ -- Get all the variable binding names and sort them
+ local keys = {}
+ for k, _ in pairs(bindings) do
+ table.insert(keys, k)
+ end
+ table.sort(keys)
+
+ for _, k in ipairs(keys) do
+ local v = bindings[k]
+
+ -- Skip the debugger object itself, "(*internal)" values, and Lua 5.2's _ENV object.
+ if not rawequal(v, dbg) and k ~= "_ENV" and not k:match "%(.*%)" then
+ dbg_writeln(" " .. COLOR_BLUE .. k .. GREEN_CARET .. dbg.pretty(v))
+ end
+ end
+
+ return false
+end
+
+local function cmd_help()
+ dbg.write(
+ ""
+ .. COLOR_BLUE
+ .. " <return>"
+ .. GREEN_CARET
+ .. "re-run last command\n"
+ .. COLOR_BLUE
+ .. " c"
+ .. COLOR_YELLOW
+ .. "(ontinue)"
+ .. GREEN_CARET
+ .. "continue execution\n"
+ .. COLOR_BLUE
+ .. " s"
+ .. COLOR_YELLOW
+ .. "(tep)"
+ .. GREEN_CARET
+ .. "step forward by one line (into functions)\n"
+ .. COLOR_BLUE
+ .. " n"
+ .. COLOR_YELLOW
+ .. "(ext)"
+ .. GREEN_CARET
+ .. "step forward by one line (skipping over functions)\n"
+ .. COLOR_BLUE
+ .. " f"
+ .. COLOR_YELLOW
+ .. "(inish)"
+ .. GREEN_CARET
+ .. "step forward until exiting the current function\n"
+ .. COLOR_BLUE
+ .. " u"
+ .. COLOR_YELLOW
+ .. "(p)"
+ .. GREEN_CARET
+ .. "move up the stack by one frame\n"
+ .. COLOR_BLUE
+ .. " d"
+ .. COLOR_YELLOW
+ .. "(own)"
+ .. GREEN_CARET
+ .. "move down the stack by one frame\n"
+ .. COLOR_BLUE
+ .. " i"
+ .. COLOR_YELLOW
+ .. "(nspect) "
+ .. COLOR_BLUE
+ .. "[index]"
+ .. GREEN_CARET
+ .. "move to a specific stack frame\n"
+ .. COLOR_BLUE
+ .. " w"
+ .. COLOR_YELLOW
+ .. "(here) "
+ .. COLOR_BLUE
+ .. "[line count]"
+ .. GREEN_CARET
+ .. "print source code around the current line\n"
+ .. COLOR_BLUE
+ .. " e"
+ .. COLOR_YELLOW
+ .. "(val) "
+ .. COLOR_BLUE
+ .. "[statement]"
+ .. GREEN_CARET
+ .. "execute the statement\n"
+ .. COLOR_BLUE
+ .. " p"
+ .. COLOR_YELLOW
+ .. "(rint) "
+ .. COLOR_BLUE
+ .. "[expression]"
+ .. GREEN_CARET
+ .. "execute the expression and print the result\n"
+ .. COLOR_BLUE
+ .. " t"
+ .. COLOR_YELLOW
+ .. "(race)"
+ .. GREEN_CARET
+ .. "print the stack trace\n"
+ .. COLOR_BLUE
+ .. " l"
+ .. COLOR_YELLOW
+ .. "(ocals)"
+ .. GREEN_CARET
+ .. "print the function arguments, locals and upvalues.\n"
+ .. COLOR_BLUE
+ .. " h"
+ .. COLOR_YELLOW
+ .. "(elp)"
+ .. GREEN_CARET
+ .. "print this message\n"
+ .. COLOR_BLUE
+ .. " q"
+ .. COLOR_YELLOW
+ .. "(uit)"
+ .. GREEN_CARET
+ .. "halt execution\n"
+ )
+ return false
+end
+
+local last_cmd = false
+
+local commands = {
+ ["^c$"] = function()
+ return true
+ end,
+ ["^s$"] = cmd_step,
+ ["^n$"] = cmd_next,
+ ["^f$"] = cmd_finish,
+ ["^p%s+(.*)$"] = cmd_print,
+ ["^e%s+(.*)$"] = cmd_eval,
+ ["^u$"] = cmd_up,
+ ["^d$"] = cmd_down,
+ ["i%s*(%d+)"] = cmd_inspect,
+ ["^w%s*(%d*)$"] = cmd_where,
+ ["^t$"] = cmd_trace,
+ ["^l$"] = cmd_locals,
+ ["^h$"] = cmd_help,
+ ["^q$"] = function()
+ dbg.exit(0)
+ return true
+ end,
+}
+
+local function match_command(line)
+ for pat, func in pairs(commands) do
+ -- Return the matching command and capture argument.
+ if line:find(pat) then
+ return func, line:match(pat)
+ end
+ end
+end
+
+-- Run a command line
+-- Returns true if the REPL should exit and the hook function factory
+local function run_command(line)
+ -- GDB/LLDB exit on ctrl-d
+ if line == nil then
+ dbg.exit(1)
+ return true
+ end
+
+ -- Re-execute the last command if you press return.
+ if line == "" then
+ line = last_cmd or "h"
+ end
+
+ local command, command_arg = match_command(line)
+ if command then
+ last_cmd = line
+ -- unpack({...}) prevents tail call elimination so the stack frame indices are predictable.
+ return unpack { command(command_arg) }
+ elseif dbg.auto_eval then
+ return unpack { cmd_eval(line) }
+ else
+ dbg_writeln(
+ COLOR_RED
+ .. "Error:"
+ .. COLOR_RESET
+ .. " command '%s' not recognized.\nType 'h' and press return for a command list.",
+ line
+ )
+ return false
+ end
+end
+
+repl = function(reason)
+ -- Skip frames without source info.
+ while not frame_has_line(debug.getinfo(stack_inspect_offset + CMD_STACK_LEVEL - 3)) do
+ stack_inspect_offset = stack_inspect_offset + 1
+ end
+
+ local info = debug.getinfo(stack_inspect_offset + CMD_STACK_LEVEL - 3)
+ reason = reason and (COLOR_YELLOW .. "break via " .. COLOR_RED .. reason .. GREEN_CARET) or ""
+ dbg_writeln(reason .. format_stack_frame_info(info))
+
+ if tonumber(dbg.auto_where) then
+ where(info, dbg.auto_where)
+ end
+
+ repeat
+ local success, done, hook = pcall(run_command, dbg.read(COLOR_RED .. "debugger.lua> " .. COLOR_RESET))
+ if success then
+ debug.sethook(hook and hook(0), "crl")
+ else
+ local message = COLOR_RED .. "INTERNAL DEBUGGER.LUA ERROR. ABORTING\n:" .. COLOR_RESET .. " " .. done
+ dbg_writeln(message)
+ error(message)
+ end
+ until done
+end
+
+-- Make the debugger object callable like a function.
+dbg = setmetatable({}, {
+ __call = function(_, condition, top_offset, source)
+ if condition then
+ return
+ end
+
+ top_offset = (top_offset or 0)
+ stack_inspect_offset = top_offset
+ stack_top = top_offset
+
+ debug.sethook(hook_next(1, source or "dbg()"), "crl")
+ return
+ end,
+})
+
+-- Expose the debugger's IO functions.
+dbg.read = dbg_read
+dbg.write = dbg_write
+dbg.shorten_path = function(path)
+ return path
+end
+dbg.exit = function(err)
+ os.exit(err)
+end
+
+dbg.writeln = dbg_writeln
+
+dbg.pretty_depth = 3
+dbg.pretty = pretty
+dbg.pp = function(value, depth)
+ dbg_writeln(dbg.pretty(value, depth))
+end
+
+dbg.auto_where = false
+dbg.auto_eval = false
+
+local lua_error, lua_assert = error, assert
+
+-- Works like error(), but invokes the debugger.
+function dbg.error(err, level)
+ level = level or 1
+ dbg_writeln(COLOR_RED .. "ERROR: " .. COLOR_RESET .. dbg.pretty(err))
+ dbg(false, level, "dbg.error()")
+
+ lua_error(err, level)
+end
+
+-- Works like assert(), but invokes the debugger on a failure.
+function dbg.assert(condition, message)
+ message = message or "assertion failed!"
+ if not condition then
+ dbg_writeln(COLOR_RED .. "ERROR: " .. COLOR_RESET .. message)
+ dbg(false, 1, "dbg.assert()")
+ end
+
+ return lua_assert(condition, message)
+end
+
+-- Works like pcall(), but invokes the debugger on an error.
+function dbg.call(f, ...)
+ return xpcall(f, function(err)
+ dbg_writeln(COLOR_RED .. "ERROR: " .. COLOR_RESET .. dbg.pretty(err))
+ dbg(false, 1, "dbg.call()")
+
+ return err
+ end, ...)
+end
+
+-- Error message handler that can be used with lua_pcall().
+function dbg.msgh(...)
+ if debug.getinfo(2) then
+ dbg_writeln(COLOR_RED .. "ERROR: " .. COLOR_RESET .. dbg.pretty(...))
+ dbg(false, 1, "dbg.msgh()")
+ else
+ dbg_writeln(
+ COLOR_RED
+ .. "debugger.lua: "
+ .. COLOR_RESET
+ .. "Error did not occur in Lua code. Execution will continue after dbg_pcall()."
+ )
+ end
+
+ return ...
+end
+
+-- Assume stdin/out are TTYs unless we can use LuaJIT's FFI to properly check them.
+local stdin_isatty = true
+local stdout_isatty = true
+
+-- Conditionally enable the LuaJIT FFI.
+local ffi = (jit and require "ffi")
+if ffi then
+ ffi.cdef [[
+ int isatty(int); // Unix
+ int _isatty(int); // Windows
+ void free(void *ptr);
+
+ char *readline(const char *);
+ int add_history(const char *);
+ ]]
+
+ local function get_func_or_nil(sym)
+ local success, func = pcall(function()
+ return ffi.C[sym]
+ end)
+ return success and func or nil
+ end
+
+ local isatty = get_func_or_nil "isatty" or get_func_or_nil "_isatty" or (ffi.load "ucrtbase")["_isatty"]
+ stdin_isatty = isatty(0)
+ stdout_isatty = isatty(1)
+end
+
+-- Conditionally enable color support.
+local color_maybe_supported = (stdout_isatty and os.getenv "TERM" and os.getenv "TERM" ~= "dumb")
+if color_maybe_supported and not os.getenv "DBG_NOCOLOR" then
+ COLOR_GRAY = string.char(27) .. "[90m"
+ COLOR_RED = string.char(27) .. "[91m"
+ COLOR_BLUE = string.char(27) .. "[94m"
+ COLOR_YELLOW = string.char(27) .. "[33m"
+ COLOR_RESET = string.char(27) .. "[0m"
+ GREEN_CARET = string.char(27) .. "[92m => " .. COLOR_RESET
+end
+
+if stdin_isatty and not os.getenv "DBG_NOREADLINE" then
+ pcall(function()
+ local linenoise = require "linenoise"
+
+ -- Load command history from ~/.lua_history
+ local hist_path = os.getenv "HOME" .. "/.lua_history"
+ linenoise.historyload(hist_path)
+ linenoise.historysetmaxlen(50)
+
+ local function autocomplete(env, input, matches)
+ for name, _ in pairs(env) do
+ if name:match("^" .. input .. ".*") then
+ linenoise.addcompletion(matches, name)
+ end
+ end
+ end
+
+ -- Auto-completion for locals and globals
+ linenoise.setcompletion(function(matches, input)
+ -- First, check the locals and upvalues.
+ local env = local_bindings(1, true)
+ autocomplete(env, input, matches)
+
+ -- Then, check the implicit environment.
+ env = getmetatable(env).__index
+ autocomplete(env, input, matches)
+ end)
+
+ dbg.read = function(prompt)
+ local str = linenoise.linenoise(prompt)
+ if str and not str:match "^%s*$" then
+ linenoise.historyadd(str)
+ linenoise.historysave(hist_path)
+ end
+ return str
+ end
+ dbg_writeln(COLOR_YELLOW .. "debugger.lua: " .. COLOR_RESET .. "Linenoise support enabled.")
+ end)
+
+ -- Conditionally enable LuaJIT readline support.
+ pcall(function()
+ if dbg.read == dbg_read and ffi then
+ local readline = ffi.load "readline"
+ dbg.read = function(prompt)
+ local cstr = readline.readline(prompt)
+ if cstr ~= nil then
+ local str = ffi.string(cstr)
+ if string.match(str, "[^%s]+") then
+ readline.add_history(cstr)
+ end
+
+ ffi.C.free(cstr)
+ return str
+ else
+ return nil
+ end
+ end
+ dbg_writeln(COLOR_YELLOW .. "debugger.lua: " .. COLOR_RESET .. "Readline support enabled.")
+ end
+ end)
+end
+
+-- Detect Lua version.
+if jit then -- LuaJIT
+ LUA_JIT_SETLOCAL_WORKAROUND = -1
+ dbg_writeln(COLOR_YELLOW .. "debugger.lua: " .. COLOR_RESET .. "Loaded for " .. jit.version)
+elseif "Lua 5.1" <= _VERSION and _VERSION <= "Lua 5.4" then
+ dbg_writeln(COLOR_YELLOW .. "debugger.lua: " .. COLOR_RESET .. "Loaded for " .. _VERSION)
+else
+ dbg_writeln(COLOR_YELLOW .. "debugger.lua: " .. COLOR_RESET .. "Not tested against " .. _VERSION)
+ dbg_writeln "Please send me feedback!"
+end
+
+return dbg
diff --git a/.config/awesome/quarrel/delegate.lua b/.config/awesome/quarrel/delegate.lua
index 54db786..3ea6d75 100644
--- a/.config/awesome/quarrel/delegate.lua
+++ b/.config/awesome/quarrel/delegate.lua
@@ -1,8 +1,10 @@
+local M = {}
+
--- Capture `fn`'s upvalues and pass to `delegate`
---@param delegate fun(env: table<string, any>, _: ...): ...
---@param fn function
---@return fun(...): ...
-return function(delegate, fn)
+function M.new(delegate, fn)
local upvalues = {}
for i = 1, debug.getinfo(fn, "u").nups do
local name, value = debug.getupvalue(fn, i)
@@ -12,3 +14,9 @@ return function(delegate, fn)
return delegate(upvalues, ...)
end
end
+
+return setmetatable(M, {
+ __call = function(_, ...)
+ return M.new(...)
+ end,
+})
diff --git a/.config/awesome/quarrel/fs.lua b/.config/awesome/quarrel/fs.lua
index 502f189..fa3fc21 100644
--- a/.config/awesome/quarrel/fs.lua
+++ b/.config/awesome/quarrel/fs.lua
@@ -1,24 +1,35 @@
+local gdebug = require "gears.debug"
local GFile = require("lgi").Gio.File
---@class QuarrelFs
-local qfs = {}
+local M = {}
--- Read a file with the specified format (or "a") and close the file
---@param path string
----@param format openmode
+---@param format? openmode
---@return any
-function qfs.read(path, format)
+function M.read(path, format)
local f = assert(io.open(path, "r"))
local c = f:read(format or "a")
f:close()
return c
end
+--- Write a file with the specified format (or "a") and close the file
+---@param path string
+---@param format? openmode
+---@return any
+function M.write(content, path, format)
+ local f = assert(io.open(path, format or "w+"))
+ f:write(content)
+ f:close()
+end
+
--- List files in a directory
---@param path string
---@param absolute boolean?
---@return table
-function qfs.ls_files(path, absolute)
+function M.ls_files(path, absolute)
local files = GFile.new_for_path(path):enumerate_children("standard::*", 0)
local files_filtered = {}
@@ -41,4 +52,4 @@ function qfs.ls_files(path, absolute)
return files_filtered
end
-return qfs
+return M
diff --git a/.config/awesome/quarrel/iconset.lua b/.config/awesome/quarrel/iconset.lua
new file mode 100644
index 0000000..43b7104
--- /dev/null
+++ b/.config/awesome/quarrel/iconset.lua
@@ -0,0 +1,21 @@
+local gstring = require "gears.string"
+
+local M = {}
+
+--- Generate a shim to allow indexing an iconset as a Lua table
+---@param path string
+---@return table
+function M.new(path)
+ return setmetatable({}, {
+ ---@param icon string
+ __index = function(self, icon)
+ return path .. (gstring.endswith(path, "/") and "" or "/") .. icon:gsub("_", "-") .. ".svg"
+ end,
+ })
+end
+
+return setmetatable(M, {
+ __call = function(_, ...)
+ return M.new(...)
+ end,
+})
diff --git a/.config/awesome/quarrel/init.lua b/.config/awesome/quarrel/init.lua
index 96f7f5b..5617c1a 100644
--- a/.config/awesome/quarrel/init.lua
+++ b/.config/awesome/quarrel/init.lua
@@ -9,14 +9,4 @@ function quarrel.debug(message)
n { message = tostring(message) }
end
---- Check if there was a restart
----@return boolean
-function quarrel.is_restart()
- awesome.register_xproperty("is_restart", "boolean")
- local restart_detected = awesome.get_xproperty "is_restart" ~= nil
- awesome.set_xproperty("is_restart", true)
-
- return restart_detected
-end
-
return quarrel
diff --git a/.config/awesome/quarrel/lua-rust.tar.gz b/.config/awesome/quarrel/lua-rust.tar.gz
deleted file mode 100644
index 5ff33fd..0000000
--- a/.config/awesome/quarrel/lua-rust.tar.gz
+++ /dev/null
Binary files differ
diff --git a/.config/awesome/quarrel/markup.lua b/.config/awesome/quarrel/markup.lua
index d206530..f89368c 100644
--- a/.config/awesome/quarrel/markup.lua
+++ b/.config/awesome/quarrel/markup.lua
@@ -1,8 +1,10 @@
+local M = {}
+
--- Apply markup to a file
---@param content string
---@param args { bold: boolean, italic: boolean, fg: string, bg: string }
---@return string
-return function(content, args)
+function M.convert(content, args)
args = args or {}
if args.bold then
content = "<b>" .. content .. "</b>"
@@ -28,3 +30,9 @@ return function(content, args)
return content
end
+
+return setmetatable(M, {
+ __call = function(_, ...)
+ return M.convert(...)
+ end,
+})
diff --git a/.config/awesome/quarrel/math/consts.lua b/.config/awesome/quarrel/math/consts.lua
new file mode 100644
index 0000000..f18a093
--- /dev/null
+++ b/.config/awesome/quarrel/math/consts.lua
@@ -0,0 +1,5 @@
+local C = {}
+
+C.EPSILON = 2 ^ -52
+
+return C
diff --git a/.config/awesome/quarrel/math.lua b/.config/awesome/quarrel/math/init.lua
index b16547b..d437654 100644
--- a/.config/awesome/quarrel/math.lua
+++ b/.config/awesome/quarrel/math/init.lua
@@ -1,11 +1,9 @@
+local M = require "quarrel.math.consts"
local gmath = require "gears.math"
----@class QuarrelMath
-local qmath = {}
-
-- TODO: Finish documenting these functions
-function qmath.step_value(value, steps)
+function M.step_value(value, steps)
if value > steps[#steps - 1][1] then
return steps[#steps - 1][2]
end
@@ -16,16 +14,16 @@ function qmath.step_value(value, steps)
end
end
-function qmath.translate_range(value, in_min, in_max, out_min, out_max)
+function M.translate_range(value, in_min, in_max, out_min, out_max)
return out_min + ((out_max - out_min) / (in_max - in_min)) * (value - in_min)
end
-function qmath.percentage(value, max)
+function M.percentage(value, max)
return gmath.round(value / max * 100)
end
-function qmath.clamp(value, min, max)
+function M.clamp(value, min, max)
return math.max(math.min(value, max), min)
end
-return qmath
+return M
diff --git a/.config/awesome/quarrel/native/Cargo.toml b/.config/awesome/quarrel/native/Cargo.toml
index 8d56c9f..2551507 100644
--- a/.config/awesome/quarrel/native/Cargo.toml
+++ b/.config/awesome/quarrel/native/Cargo.toml
@@ -8,22 +8,21 @@ edition = "2021"
[dependencies]
freedesktop_entry_parser = "1.3.0"
cpc = "1.9.1"
-mlua = { version = "0.8.7", features = [ "module", "lua54", "serialize" ] }
+mlua = { version = "0.10.3", features = [ "module", "lua54", "serialize" ] }
rayon = "1.6.1"
serde = { version = "1.0.152", features = [ "derive" ] }
url = "2.3.1"
-rodio = "0.17.1"
-nix = "0.26.2"
+rodio = "0.20.1"
+nix = { version = "0.29.0", features = [ "ioctl", "socket" ] }
chrono = "0.4.24"
-itertools = "0.10.5"
+itertools = "0.14.0"
html-escape = "0.2.13"
-mpd = { git = "https://github.com/kstep/rust-mpd", features = [ "serde" ], version = "0.1.0" }
-cairo-rs = { git = "https://github.com/gtk-rs/gtk-rs-core.git", version = "0.18.0" }
-gdk-pixbuf = { git = "https://github.com/gtk-rs/gtk-rs-core.git", version = "0.18.0" }
-symphonia = "0.5.3"
-dirs = "5.0.1"
+dirs = "6.0.0"
once_cell = "1.18.0"
-
+ureq = "3.0.9"
+anyhow = { version = "1.0.97", features = ["backtrace"] }
+mdrop = { git = "https://github.com/frahz/mdrop" }
+sysinfo = "0.35.0"
[lib]
crate-type = ["cdylib"]
diff --git a/.config/awesome/quarrel/native/init.lua b/.config/awesome/quarrel/native/init.lua
index e5d5aab..6a823ba 100644
--- a/.config/awesome/quarrel/native/init.lua
+++ b/.config/awesome/quarrel/native/init.lua
@@ -26,16 +26,12 @@ package.cpath = package.cpath .. ";" .. cfg .. "quarrel/native/lib?.so"
---@field decode_html fun(input: string): string
---@field open_file fun(path: string): FileHandle
----@class Mpd
----@field init
-
---@class Net
---@field get_essid fun(): string
---@class QuarrelNative
---@field lenses Lenses
---@field util Util
----@field mpd Mpd
---@field net Net
local qnative = require "qnative"
diff --git a/.config/awesome/quarrel/native/src/http.rs b/.config/awesome/quarrel/native/src/http.rs
new file mode 100644
index 0000000..e995556
--- /dev/null
+++ b/.config/awesome/quarrel/native/src/http.rs
@@ -0,0 +1,22 @@
+use ureq::{Agent, agent};
+use std::{sync::LazyLock, thread};
+use mlua::prelude::*;
+
+static AGENT: LazyLock<Agent> = LazyLock::new(|| agent());
+
+struct Stream(ureq::Body);
+
+pub fn get(_: &Lua, url: String, callback: LuaFunction, err_callback: LuaFunction) -> LuaResult<()> {
+ thread::spawn(|| {
+ match AGENT.get(url).call() {
+ Ok(body) => {
+
+ },
+ Err(err) => {
+ err_callback.call(err.to_string());
+ }
+ }
+ // callback.call::<>()
+ });
+ Ok(())
+}
diff --git a/.config/awesome/quarrel/native/src/lenses/application.rs b/.config/awesome/quarrel/native/src/lenses/application.rs
index 72aba8d..89b7bb4 100644
--- a/.config/awesome/quarrel/native/src/lenses/application.rs
+++ b/.config/awesome/quarrel/native/src/lenses/application.rs
@@ -1,6 +1,5 @@
use std::{
- fs::read_dir,
- path::PathBuf,
+ fs::read_dir, path::PathBuf
};
use freedesktop_entry_parser as fd;
@@ -8,12 +7,54 @@ use mlua::prelude::*;
use rayon::prelude::*;
use url::Url;
-use crate::lenses::entry::{
- entries_to_lua_table,
+use crate::lenses::{
Entry,
+ Lense,
+ Cache
};
-fn parse_entry(entry: &fd::Entry, path: &PathBuf) -> Result<Entry, ()> {
+#[derive(Default)]
+pub struct Application(pub Cache);
+
+impl Lense for Application {
+ const NAME: &str = "Application";
+
+ fn get_cache(&self) -> &Cache {
+ &self.0
+ }
+
+ fn set_cache(&mut self, cache: Cache) {
+ self.0 = cache;
+ }
+
+ fn query(_: &Lua, input: String) -> Result<Vec<Entry>, anyhow::Error> {
+ let applications_dir = "/usr/share/applications";
+ let entries = read_dir(applications_dir)?
+ .map(|result| result.map(|e| e.path()))
+ .collect::<Result<Vec<_>, std::io::Error>>()?;
+
+ let parsed_entries: Vec<Entry> = entries
+ .into_par_iter()
+ .filter(|path| path.extension().is_some_and(|ext| ext == "desktop"))
+ .filter_map(|path| {
+ parse_entry(path).ok().flatten()
+ })
+ .collect();
+
+ Ok(
+ parsed_entries
+ .into_iter()
+ .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase()))
+ .collect(),
+ )
+ }
+}
+
+fn parse_entry(path: PathBuf) -> Result<Option<Entry>, ()> {
+ let Ok(entry) = fd::parse_entry(&path) else {
+ return Err(())
+ };
+
let section = entry.section("Desktop Entry");
let name = section.attr("Name").ok_or(())?.to_string();
@@ -38,14 +79,14 @@ fn parse_entry(entry: &fd::Entry, path: &PathBuf) -> Result<Entry, ()> {
}
}
'c' => new_exec.replace_range(index..index + 2, &name),
- 'k' => new_exec.replace_range(index..index + 2, Url::from_file_path(path)?.as_str()),
+ 'k' => new_exec.replace_range(index..index + 2, Url::from_file_path(&path)?.as_str()),
'f' | 'u' | 'v' | 'm' | 'd' | 'n' => new_exec.replace_range(index..index + 2, ""),
_ => continue,
}
}
- Ok(Entry {
+ Ok(Some(Entry {
message: name,
exec: Some((
new_exec,
@@ -55,33 +96,5 @@ fn parse_entry(entry: &fd::Entry, path: &PathBuf) -> Result<Entry, ()> {
.parse()
.map_err(drop)?,
)),
- provider: "Application".to_string(),
- })
-}
-
-pub fn query(lua: &Lua, input: String) -> LuaResult<LuaTable> {
- let applications_dir = "/usr/share/applications";
- let entries = read_dir(applications_dir)?
- .map(|result| result.map(|e| e.path()))
- .collect::<Result<Vec<_>, std::io::Error>>()?;
-
- let parsed_entries: Vec<Entry> = entries
- .into_par_iter()
- .filter(|path| matches!(path.extension(), Some(ext) if ext == "desktop"))
- .filter_map(|path| {
- let Ok(entry) = fd::parse_entry(&path) else {
- return None
- };
-
- parse_entry(&entry, &path).ok()
- })
- .collect();
-
- Ok(entries_to_lua_table(
- parsed_entries
- .into_iter()
- .filter(|entry| entry.message.to_lowercase().contains(&input.to_lowercase()))
- .collect(),
- lua,
- ))
+ }))
}
diff --git a/.config/awesome/quarrel/native/src/lenses/calculator.rs b/.config/awesome/quarrel/native/src/lenses/calculator.rs
index 07f1ee2..640bdeb 100644
--- a/.config/awesome/quarrel/native/src/lenses/calculator.rs
+++ b/.config/awesome/quarrel/native/src/lenses/calculator.rs
@@ -5,25 +5,36 @@ use cpc::{
};
use mlua::prelude::*;
-use crate::lenses::entry::{
- entries_to_lua_table,
+use crate::lenses::{
Entry,
+ Cache,
+ Lense
};
-pub fn query(lua: &Lua, input: String) -> LuaResult<LuaTable> {
- let result = match eval(input.trim(), true, Unit::Celsius, false) {
- Ok(result) => {
- format!("{result}")
- }
- Err(_) => return lua.create_table(),
- };
-
- Ok(entries_to_lua_table(
- vec![Entry {
- message: result,
- exec: None,
- provider: "Calculator".to_string(),
- }],
- lua,
- ))
+pub struct Calculator;
+
+impl Lense for Calculator {
+ const NAME: &str = "Calculator";
+
+ fn get_cache(&self) -> &Cache {
+ &Cache::Stale
+ }
+
+ fn set_cache(&mut self, _: Cache) {}
+
+ fn query(_: &Lua, input: String) -> Result<Vec<Entry>, anyhow::Error> {
+ let result = match eval(input.trim(), true, Unit::Celsius, false) {
+ Ok(result) => {
+ format!("{result}")
+ }
+ Err(err) => { return Err(anyhow::anyhow!(err)); },
+ };
+
+ Ok(vec![Entry {
+ message: result,
+ exec: None,
+ }; 1]
+ )
+ }
}
+
diff --git a/.config/awesome/quarrel/native/src/lenses/entry.rs b/.config/awesome/quarrel/native/src/lenses/entry.rs
deleted file mode 100644
index c7ac09e..0000000
--- a/.config/awesome/quarrel/native/src/lenses/entry.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use mlua::{
- prelude::*,
- LuaSerdeExt,
-};
-use serde::Serialize;
-
-#[derive(Serialize, Clone)]
-pub struct Entry {
- pub message: String,
- pub exec: Option<(String, bool)>,
- pub provider: String,
-}
-
-pub fn entries_to_lua_table(entries: Vec<Entry>, lua: &Lua) -> LuaTable {
- match lua.to_value(&entries).unwrap() {
- LuaValue::Table(t) => t,
- _ => unreachable!(),
- }
-}
diff --git a/.config/awesome/quarrel/native/src/lenses/mod.rs b/.config/awesome/quarrel/native/src/lenses/mod.rs
index d0db6f7..6eb5b58 100644
--- a/.config/awesome/quarrel/native/src/lenses/mod.rs
+++ b/.config/awesome/quarrel/native/src/lenses/mod.rs
@@ -1,3 +1,79 @@
pub mod application;
pub mod calculator;
-pub mod entry;
+
+use mlua::{
+ prelude::*,
+ LuaSerdeExt,
+};
+use serde::{Serialize, Deserialize};
+
+#[derive(Deserialize, Serialize, Clone)]
+pub struct Entry {
+ pub message: String,
+ pub exec: Option<(String, bool)>,
+}
+
+impl IntoLua for Entry {
+ fn into_lua(self, lua: &Lua) -> LuaResult<LuaValue> {
+ return lua.to_value(&self)
+ }
+}
+
+impl FromLua for Entry {
+ fn from_lua(value: LuaValue, lua: &Lua) -> LuaResult<Self> {
+ return lua.from_value(value);
+ }
+}
+
+#[derive(Default)]
+pub enum Cache {
+ Valid(Vec<Entry>),
+ #[default]
+ Stale
+}
+
+pub struct _Lense<T: Lense>(pub T);
+
+pub trait Lense {
+ const NAME: &'static str;
+
+ fn set_cache(&mut self, cache: Cache);
+ fn get_cache(&self) -> &Cache;
+
+ fn query(lua: &Lua, input: String) -> Result<Vec<Entry>, anyhow::Error>;
+}
+
+impl<T: Lense + 'static> LuaUserData for _Lense<T> {
+ fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
+ // fields.add_field_method_get("cache", |lua, this| {
+ // let cache = this.0.get_cache();
+ // match cache {
+ // Cache::Valid(cache) => Ok(cache.clone().into_lua(lua)?),
+ // Cache::Stale => Ok(LuaNil)
+ // }
+ // });
+
+ // fields.add_field_method_set("cache", |_, this, cache: Vec<Entry>| {
+ // Ok(this.0.set_cache(Cache::Valid(cache)))
+ // });
+
+ fields.add_field_method_get("stale", |_, this| Ok(matches!(this.0.get_cache(), Cache::Stale)));
+
+ fields.add_field("name", T::NAME);
+ }
+
+ fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
+ methods.add_method_mut("query", |lua, this, input: String| {
+ return Ok(match this.0.get_cache() {
+ Cache::Valid(entries) => entries.clone(),
+ Cache::Stale => {
+ let entries = T::query(lua, input).map_err(LuaError::external)?;
+ this.0.set_cache(Cache::Valid(entries.clone()));
+ entries
+ }
+ });
+ });
+
+ methods.add_method_mut("mark_stale", |_, this, _: ()| Ok(this.0.set_cache(Cache::Stale)) );
+ }
+}
diff --git a/.config/awesome/quarrel/native/src/lib.rs b/.config/awesome/quarrel/native/src/lib.rs
index 472313e..4f1780d 100644
--- a/.config/awesome/quarrel/native/src/lib.rs
+++ b/.config/awesome/quarrel/native/src/lib.rs
@@ -1,29 +1,29 @@
mod lenses;
-mod mpd;
mod net;
+// mod http;
mod util;
+mod moondrop;
use mlua::prelude::*;
+use lenses::{ _Lense };
#[mlua::lua_module]
fn qnative(lua: &Lua) -> LuaResult<LuaTable> {
let lenses = lua.create_table()?;
- lenses.set("1", lua.create_function(lenses::calculator::query)?)?;
- lenses.set("2", lua.create_function(lenses::application::query)?)?;
+ lenses.push(_Lense(lenses::calculator::Calculator))?;
+ lenses.push(_Lense(lenses::application::Application::default()))?;
+ // lenses.set("1", lua.create_function(lenses::calculator::Application::query)?)?;
+ // lenses.set("2", lua.create_function(lenses::application::Application::query)?)?;
let util = lua.create_table()?;
util.set("decode_html", lua.create_function(util::decode_html)?)?;
util.set("open_file", lua.create_function(util::FileHandle::new)?)?;
- let mpd = lua.create_table()?;
- mpd.set("init", lua.create_function(mpd::init)?)?;
-
let net = lua.create_table()?;
net.set("get_essid", lua.create_function(net::get_first_essid)?)?;
let exports = lua.create_table()?;
exports.set("lenses", lenses)?;
- exports.set("mpd", mpd)?;
exports.set("net", net)?;
exports.set("util", util)?;
diff --git a/.config/awesome/quarrel/native/src/moondrop.rs b/.config/awesome/quarrel/native/src/moondrop.rs
new file mode 100644
index 0000000..d416ef6
--- /dev/null
+++ b/.config/awesome/quarrel/native/src/moondrop.rs
@@ -0,0 +1,3 @@
+use mdrop::Moondrop;
+
+
diff --git a/.config/awesome/quarrel/native/src/mpd.rs b/.config/awesome/quarrel/native/src/mpd.rs
deleted file mode 100644
index 08c9e42..0000000
--- a/.config/awesome/quarrel/native/src/mpd.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-use std::{
- ffi::c_void,
- fs::File,
- net::TcpStream,
- path::PathBuf,
- sync::mpsc::channel,
-};
-
-use dirs::home_dir;
-use gdk_pixbuf::{
- ffi::GdkPixbuf,
- glib::translate::IntoGlibPtr,
- traits::PixbufLoaderExt,
- Pixbuf,
- PixbufLoader,
-};
-use mlua::{
- prelude::*,
- LuaSerdeExt,
-};
-use mpd::Client;
-use once_cell::sync::Lazy;
-use symphonia::{
- core::{
- formats::FormatOptions,
- io::{
- MediaSourceStream,
- MediaSourceStreamOptions,
- },
- meta::MetadataOptions,
- probe::Hint,
- },
- default::get_probe,
-};
-
-static MPD_MUSIC_PATH: Lazy<PathBuf> = Lazy::new(|| {
- [
- home_dir().expect("home directory should be set"),
- "Music".into(),
- ]
- .iter()
- .collect()
-});
-
-static COVER_FORMATS: [&str; 2] = ["png", "jpg"];
-
-pub struct Connection(Client<TcpStream>);
-
-impl LuaUserData for Connection {
- fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
- methods.add_method_mut("status", |lua, this: &mut Connection, (): ()| {
- lua.to_value(&this.0.status().map_err(LuaError::external)?)
- });
-
- methods.add_method_mut("song", |lua, this: &mut Connection, (): ()| {
- Ok(
- if let Some(song) = this.0.currentsong().map_err(LuaError::external)? {
- lua.to_value(&song)?
- } else {
- LuaNil
- },
- )
- });
-
- methods.add_method(
- "get_cover_pixbuf",
- |_, _: &Connection, file: String| {
- let song_path = MPD_MUSIC_PATH.join(file);
- let mut has_external_cover = false;
- let mut cover_path = PathBuf::new();
-
- for format in COVER_FORMATS {
- let cover = song_path
- .parent()
- .unwrap()
- .to_owned()
- .join(format!("cover.{}", format));
- if cover.exists() {
- has_external_cover = cover.exists();
- cover_path = cover;
- break;
- }
- }
-
- let mss = MediaSourceStream::new(
- Box::new(File::open(song_path)?),
- MediaSourceStreamOptions::default(),
- );
-
- let mut probed = get_probe()
- .format(
- &Hint::default(),
- mss,
- &FormatOptions::default(),
- &MetadataOptions::default(),
- )
- .map_err(LuaError::external)?;
-
- let visuals;
-
- if let Some(metadata) = probed.format.metadata().skip_to_latest() {
- visuals = metadata.visuals();
- if visuals.is_empty() && has_external_cover {
- let pixbuf = Pixbuf::from_file(cover_path).map_err(LuaError::external)?;
-
- return Ok((
- Some(LuaLightUserData(unsafe {
- <Pixbuf as IntoGlibPtr<*mut GdkPixbuf>>::into_glib_ptr(pixbuf)
- .cast::<c_void>()
- })),
- Some(true),
- ));
- }
-
- let loader = PixbufLoader::new();
- loader
- .write(visuals.first().unwrap().data.as_ref())
- .map_err(LuaError::external)?;
- loader.close().map_err(LuaError::external)?;
-
- return Ok((
- Some(LuaLightUserData(unsafe {
- <Pixbuf as IntoGlibPtr<*mut GdkPixbuf>>::into_glib_ptr(
- loader.pixbuf().expect("Pixbuf should be initialized"),
- )
- .cast::<c_void>()
- })),
- Some(false),
- ));
- }
-
- Ok((None, None))
- },
- );
- }
-}
-
-pub fn init(_: &Lua, _: ()) -> LuaResult<Connection> {
- Ok(Connection(
- Client::connect("localhost:6600").map_err(LuaError::external)?,
- ))
-}
diff --git a/.config/awesome/quarrel/native/src/net/mod.rs b/.config/awesome/quarrel/native/src/net/mod.rs
index 96c853e..dbd87b9 100644
--- a/.config/awesome/quarrel/native/src/net/mod.rs
+++ b/.config/awesome/quarrel/native/src/net/mod.rs
@@ -9,7 +9,7 @@ use std::{
c_void,
},
mem::size_of,
- os::fd::RawFd,
+ os::fd::{IntoRawFd, RawFd},
};
use mlua::prelude::*;
@@ -108,7 +108,7 @@ fn get_first_socket() -> LuaResult<RawFd> {
for family in families {
if let Ok(socket) = open_socket(family, SockType::Datagram, SockFlag::empty(), None) {
- return Ok(socket);
+ return Ok(socket.into_raw_fd());
}
}
diff --git a/.config/awesome/quarrel/native/src/util.rs b/.config/awesome/quarrel/native/src/util.rs
index 85a2574..41096d8 100644
--- a/.config/awesome/quarrel/native/src/util.rs
+++ b/.config/awesome/quarrel/native/src/util.rs
@@ -1,7 +1,6 @@
use std::{
cell::RefCell,
fs::File,
- fs::OpenOptions,
io::{
Read,
Seek,
@@ -49,7 +48,7 @@ enum StringOrNumber {
pub struct FileHandle(Rc<RefCell<File>>);
impl LuaUserData for FileHandle {
- fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
+ fn add_methods<'lua, M: LuaUserDataMethods<Self>>(methods: &mut M) {
methods.add_method("read", |lua, this: &FileHandle, mode: String| {
let content = this.read()?;
Ok(lua.to_value(&match ReadMode::from_str(&mode).unwrap() {
diff --git a/.config/awesome/quarrel/persistent.lua b/.config/awesome/quarrel/persistent.lua
new file mode 100644
index 0000000..2b15c89
--- /dev/null
+++ b/.config/awesome/quarrel/persistent.lua
@@ -0,0 +1,62 @@
+local gdebug = require "gears.debug"
+local qfs = require "quarrel.fs"
+local qjson = require "quarrel.json"
+
+awesome.register_xproperty("is_restart", "boolean")
+
+---@alias QPersistentValue string|number|table|nil|boolean
+
+---@class QuarrelPersistent
+local qpersistent = {}
+
+---@type table<string, QPersistentValue>
+local inner = {}
+
+--- Store a key-value pair in a persistent store
+---@param key string
+---@param value QPersistentValue
+function qpersistent.store(key, value)
+ inner[key] = value
+end
+
+--- Get a key-value pair in a persistent store
+---@param key string
+---@return QPersistentValue
+function qpersistent.get(key)
+ return inner[key]
+end
+
+--- Check if there was a restart
+---@return boolean
+function qpersistent.is_restart()
+ return awesome.get_xproperty "is_restart" ~= nil
+end
+
+do
+ local ok, content = pcall(qfs.read, "/tmp/qpersistent-store")
+
+ if not ok and not qpersistent.is_restart() then
+ gdebug.print_error "failed to read persistent store"
+ inner = {}
+ else
+ inner = qjson.decode(content)
+ end
+end
+
+awesome.connect_signal("exit", function(restart)
+ if not restart then
+ return
+ end -- we probably errored
+
+ local ok = pcall(qfs.write, qjson.encode(inner), "/tmp/qpersistent-store")
+ if not ok then
+ gdebug.print_error "failed to open persistent store"
+ return
+ end
+
+ if not qpersistent.is_restart() then
+ awesome.set_xproperty("is_restart", true)
+ end
+end)
+
+return qpersistent
diff --git a/.config/awesome/quarrel/store.lua b/.config/awesome/quarrel/store.lua
deleted file mode 100644
index 9422c21..0000000
--- a/.config/awesome/quarrel/store.lua
+++ /dev/null
@@ -1,4 +0,0 @@
----@type table
-local qstore = {}
-
-return qstore
diff --git a/.config/awesome/quarrel/ui.lua b/.config/awesome/quarrel/ui.lua
deleted file mode 100644
index 1db4a70..0000000
--- a/.config/awesome/quarrel/ui.lua
+++ /dev/null
@@ -1,145 +0,0 @@
-local awful = require "awful"
-local gtable = require "gears.table"
-local qbind = require "quarrel.bind"
-local qvars = require "quarrel.vars"
-local rtimed = require "lib.rubato.timed"
-local wibox = require "wibox"
-
----@class QuarrelUi
-local qui = {}
-
---- Return qvars.text_font with size scaled by factor
----@param factor number
----@return string
----@see QuarrelVars.text_font
-function qui.font(factor)
- return qvars.text_font .. " " .. qvars.font_size * (factor or 1)
-end
-
---- Inject background widget styling into target
----@param target table
----@return table
-function qui.styled(target)
- return gtable.crush({
- bg = qvars.colors.bg,
- border_color = qvars.colors.bright.black,
- border_width = qvars.border_width,
- shape = qvars.shape,
- }, target)
-end
-
---- Generate a styled popup
----@param target table
----@return table
-function qui.popup(target)
- target.widget = {
- widget = wibox.container.margin,
- margins = qvars.big_padding,
- target.widget,
- }
-
- return awful.popup(qui.styled(target))
-end
-
---- Generate svg recolor string
----@param color string
----@return string
-function qui.recolor(color)
- return "svg{fill:" .. color .. "}"
-end
-
---- Generate icon widget
----@param args table
----@return table
-function qui.icon(args)
- return gtable.crush({
- widget = wibox.widget.imagebox,
- image = args.icon,
- forced_width = qvars.char_height,
- forced_height = qvars.char_height,
- stylesheet = qui.recolor(args.color or qvars.colors.fg),
- }, args.widget or {})
-end
-
---- Generate button widget
----@param args table
----@return table
-function qui.button(args)
- args.press = args.press or function(_) end
- local widget = wibox.widget(gtable.crush({
- widget = wibox.widget.imagebox,
- image = args.image,
- forced_height = qvars.char_height,
- forced_width = qvars.char_height,
- stylesheet = qui.recolor(qvars.colors.fg),
- press = args.press,
- }, args.widget or {}))
-
- widget.buttons = {
- qbind:new {
- triggers = qvars.btns.left,
- press = function()
- widget:press()
- end,
- hidden = true,
- },
- }
-
- return widget
-end
-
---- Generate toggle widget
----@param args table
----@return table
-function qui.toggle(args)
- args.press = args.press or function(_) end
- local widget = qui.button {
- widget = gtable.crush({
- toggled = false,
- silent_press = function(self, state)
- if state then
- self.toggled = state
- else
- self.toggled = not self.toggled
- end
-
- if self.toggled then
- self.image = args.on
- else
- self.image = args.off
- end
- end,
- }, args.widget or {}),
- image = args.off,
- press = function(self)
- if not args.manual then
- self:silent_press()
- end
- args.press(self)
- end,
- }
-
- return widget
-end
-
----@param widget wibox.widget.base
----@param cursor string
-function qui.hoverable(widget, cursor)
- local hovering = false
-
- widget:connect_signal("mouse::enter", function()
- local w = mouse.current_wibox
- if w then
- w.cursor = cursor
- end
- end)
-
- widget:connect_signal("mouse::leave", function()
- local w = mouse.current_wibox
- if w then
- w.cursor = "left_ptr"
- end
- end)
-end
-
-return qui
diff --git a/.config/awesome/quarrel/ui/consts.lua b/.config/awesome/quarrel/ui/consts.lua
new file mode 100644
index 0000000..e6e12d0
--- /dev/null
+++ b/.config/awesome/quarrel/ui/consts.lua
@@ -0,0 +1,24 @@
+local awful = require "awful"
+local qconst = require "quarrel.const"
+local wibox = require "wibox"
+
+local C = {}
+
+C.BORDER_WIDTH = 1
+C.BORDER_RADIUS = 4
+C.PADDING = 4
+C.BIG_PADDING = 8
+C.TEXT_FONT = "Iosevka Comfy Regular"
+C.FONT_SIZE = 9
+
+local char_width, char_height = wibox
+ .widget({
+ widget = wibox.widget.textbox,
+ text = "a",
+ })
+ :get_preferred_size_at_dpi(awful.screen.focused().dpi)
+
+C.CHAR_HEIGHT = char_height
+C.CHAR_WIDTH = char_width
+
+return C
diff --git a/.config/awesome/quarrel/ui/init.lua b/.config/awesome/quarrel/ui/init.lua
new file mode 100644
index 0000000..5acaa51
--- /dev/null
+++ b/.config/awesome/quarrel/ui/init.lua
@@ -0,0 +1,167 @@
+local M = require "quarrel.ui.consts"
+local awful = require "awful"
+local gshape = require "gears.shape"
+local gtable = require "gears.table"
+local qbind = require "quarrel.bind"
+local qcolor = require "quarrel.color"
+local wibox = require "wibox"
+
+--- Clip Cairo context
+---@param cr cairo_surface Cairo surface
+---@param w integer Widget width
+---@param h integer Widget height
+---@return nil
+function M.shape(cr, w, h)
+ -- gears.shape.rounded_rect(cr, w, h, dpi(4))
+ gshape.rounded_rect(cr, w, h, M.BORDER_RADIUS)
+ -- gshape.rectangle(cr, w, h)
+end
+
+--- Returns qvars.text_font with size scaled by factor
+---@param factor number?
+---@return string
+function M.font(factor)
+ return M.TEXT_FONT .. " " .. M.FONT_SIZE * (factor or 1)
+end
+
+--- Injects background widget styling into target
+---@param target table
+---@return table
+function M.styled(target)
+ return gtable.crush({
+ bg = qcolor.palette.bg(),
+ border_color = qcolor.palette.border(),
+ border_width = M.BORDER_WIDTH,
+ shape = M.shape,
+ }, target)
+end
+
+--- Generates a styled popup
+---@param target table
+---@return table
+function M.popup(target, debug)
+ target.widget = {
+ widget = wibox.container.margin,
+ margins = M.BIG_PADDING,
+ target.widget,
+ }
+
+ return awful.popup(M.styled(target))
+end
+
+--- Generates svg recolor string
+---@param color string
+---@return string
+function M.recolor(color)
+ return "svg{fill:" .. color .. "}"
+end
+
+--- Generates icon widget
+---@param args table
+---@return table
+function M.icon(args)
+ return wibox.widget(gtable.crush({
+ widget = wibox.widget.imagebox,
+ image = args.icon,
+ forced_width = (not args.unsized) and M.CHAR_HEIGHT,
+ forced_height = (not args.unsized) and M.CHAR_HEIGHT,
+ stylesheet = M.recolor(args.color or qcolor.palette.fg()),
+ }, args.widget or {}))
+end
+
+--- Generates button widget
+---@param args table
+---@return table
+function M.button(args)
+ args.press = args.press or function(_) end
+ local widget = wibox.widget(gtable.crush({
+ widget = wibox.widget.imagebox,
+ image = args.icon,
+ forced_height = M.CHAR_HEIGHT,
+ forced_width = M.CHAR_HEIGHT,
+ stylesheet = M.recolor(qcolor.palette.fg()),
+ press = args.press,
+ }, args.widget or {}))
+
+ widget.buttons = {
+ qbind {
+ triggers = qbind.btns.left,
+ press = function()
+ widget:press()
+ end,
+ hidden = true,
+ },
+ }
+
+ return widget
+end
+
+--- Generates toggle widget
+---@param args table
+---@return table
+function M.toggle(args)
+ args.press = args.press or function(_) end
+ local widget = M.button {
+ widget = gtable.crush({
+ toggled = false,
+ silent_press = function(self, state)
+ if state then
+ self.toggled = state
+ else
+ self.toggled = not self.toggled
+ end
+
+ if self.toggled then
+ self.image = args.on
+ else
+ self.image = args.off
+ end
+ end,
+ }, args.widget or {}),
+ icon = args.off,
+ press = function(self)
+ if not args.manual then
+ self:silent_press()
+ end
+ args.press(self)
+ end,
+ }
+
+ return widget
+end
+
+---@param widget wibox.widget.base
+---@param cursor string
+---@return wibox.widget.base
+function M.hoverable(widget, cursor)
+ local last_wibox
+
+ widget:connect_signal("mouse::enter", function()
+ local w = mouse.current_wibox
+ last_wibox = w
+ if w then
+ w.cursor = cursor
+ end
+
+ if type(widget.hover) == "function" then -- on enter bind
+ widget.hover()
+ elseif type(widget.hover) == "table" and widget.hover.enter then -- { enter: fun(), leave: fun() }
+ widget.hover.enter()
+ end
+ end)
+
+ widget:connect_signal("mouse::leave", function()
+ local w = last_wibox or mouse.current_wibox
+ if w then
+ w.cursor = "left_ptr"
+ end
+
+ if type(widget.hover) == "table" and widget.hover.leave then -- { enter: fun(), leave: fun() }
+ widget.hover.leave()
+ end
+ end)
+
+ return widget
+end
+
+return M
diff --git a/.config/awesome/quarrel/vars.lua b/.config/awesome/quarrel/vars.lua
index 1983343..5c3b178 100644
--- a/.config/awesome/quarrel/vars.lua
+++ b/.config/awesome/quarrel/vars.lua
@@ -1,37 +1,38 @@
local awful = require "awful"
local btns = awful.button.names
-local gears = require "gears"
-local xresources = require "beautiful.xresources"
-local x_col = xresources.get_current_theme()
-local dpi = xresources.apply_dpi
+local gshape = require "gears.shape"
local wibox = require "wibox"
+-- local qconts = require "quarrel.consts"
+local qbezier = require "quarrel.animation.bezier"
----@class QuarrelVars
local qvars = {}
-qvars.anim_duration = 0.20
-qvars.anim_intro = qvars.anim_duration / 4
-
-qvars.notif_timeout = 3
+-- ---@param protected (fun(): table) | table
+-- function qconsts.protect(protected)
+-- ---@type table
+-- local tbl
+-- if type(protected) == "table" then
+-- tbl = protected
+-- elseif type(protected) == "function" then
+-- tbl = protected()
+-- else
+-- error("expected a table or a function that returns a table, got " .. type(protected), 2)
+-- end
+-- return setmetatable({}, {
+-- __index = tbl,
+-- __newindex = function(t, k, v)
+-- error("attempted to change constant " .. tostring(k) .. " to " .. tostring(v), 2)
+-- end
+-- })
+-- end
+
+-- qui.BORDER_WIDTH = 1
+-- qui.BORDER_RADIUS = 4
+
+-- qui.PADDING = 4
+-- qui.BIG_PADDING = 8
---- Clip Cairo context
----@param cr cairo_surface Cairo surface
----@param w integer Widget width
----@param h integer Widget height
----@return nil
-function qvars.shape(cr, w, h)
- gears.shape.rounded_rect(cr, w, h, dpi(4))
-end
-
-qvars.border_width = dpi(1.5)
-
-qvars.padding = dpi(4)
-qvars.big_padding = dpi(8)
-
--- qvars.text_font = "Fira Code Nerd Font Mono Medium"
--- qvars.text_font = "Iosevka Comfy SemiBold"
qvars.text_font = "Iosevka Comfy Regular"
--- qvars.font_size = 8
qvars.font_size = 9
qvars.font = qvars.text_font .. " " .. qvars.font_size
@@ -42,63 +43,152 @@ local char_width, char_height = wibox
})
:get_preferred_size_at_dpi(awful.screen.focused().dpi)
-qvars.char_height = char_height
-qvars.char_width = char_width
-
-qvars.bar_size = dpi(24) + qvars.big_padding * 2
-qvars.element_size = dpi(12)
-qvars.expanded_bar_size = qvars.big_padding + (qvars.big_padding * 2 + qvars.element_size * 4) * 3 + qvars.padding * 2
-
-qvars.colors = {
- fg = x_col.foreground,
- bg = x_col.background,
-
- black = x_col.color0,
- red = x_col.color1,
- green = x_col.color2,
- yellow = x_col.color3,
- blue = x_col.color4,
- pink = x_col.color5,
- cyan = x_col.color6,
- white = x_col.color7,
-
- bright = {
- black = x_col.color8,
- red = x_col.color9,
- green = x_col.color10,
- yellow = x_col.color11,
- blue = x_col.color12,
- pink = x_col.color13,
- cyan = x_col.color14,
- white = x_col.color15,
- },
-
- dim = {
- fg = "#77828c",
- bg = "#161b22",
- },
-
- transparent = "#00000000",
-}
+-- qui.CHAR_HEIGHT = char_height
+-- qui.CHAR_WIDTH = char_width
+
+--- Clip Cairo context
+---@param cr cairo_surface Cairo surface
+---@param w integer Widget width
+---@param h integer Widget height
+---@return nil
+-- function qui.shape(cr, w, h)
+-- -- gears.shape.rounded_rect(cr, w, h, dpi(4))
+-- gshape.rounded_rect(cr, w, h, qui.BORDER_RADIUS)
+-- end
+
+qvars.anim_duration = 0.30
+qvars.anim_intro = qvars.anim_duration / 4
+
+local easing_bezier = qbezier(0.2, 0, 0, 1)
+function qvars.easing(t, b, c, d)
+ local epsilon = 1000 / d
+ return c * easing_bezier:solve(t / d, epsilon) + b
+end
+
+qvars.notif_timeout = 3
+
+-- qvars.bar_size = dpi(24) + qui.BIG_PADDING * 2
+-- qvars.element_size = dpi(12)
+-- qvars.bar_size = 24 + qui.BIG_PADDING * 2
+-- qvars.element_size = 12
+-- qvars.expanded_bar_size = qui.BIG_PADDING + (qui.BIG_PADDING * 2 + qvars.element_size * 4) * 4 + qui.PADDING * 2
+
+-- local function palette(colors)
+-- return setmetatable(colors, {
+-- __call = function(self)
+-- return self[1]
+-- end,
+-- })
+-- end
+
+-- local colors = require "quarrel.color"
+-- qcolor.palette = colors.palette
+-- qcolor.palette = {
+-- fg = palette {
+-- low = "#a8afb7",
+-- "#c8ced7",
+-- high = "#e8eff8",
+-- },
+--
+-- bg = palette {
+-- lowest = "#070c11",
+-- low = "#0c1116",
+-- "#12161c",
+-- high = "#171c22",
+-- highest = "#1d2228",
+-- },
+--
+-- border = palette {
+-- "#323b46",
+-- variant = "#262f39",
+-- },
+--
+-- red = palette {
+-- "#ff928a",
+-- bright = "#ffb2a9",
+-- },
+-- orange = palette {
+-- "#ff9f6f",
+-- bright = "#ffc08e",
+-- },
+-- yellow = palette {
+-- "#ecb256",
+-- bright = "#ffd278",
+-- },
+-- green = palette {
+-- "#8bd294",
+-- bright = "#abf3b3",
+-- },
+-- cyan = palette {
+-- "#6dd3c2",
+-- bright = "#8ef4e2",
+-- },
+-- blue = palette {
+-- "#8bc3fc",
+-- bright = "#abe4ff",
+-- },
+-- purple = palette {
+-- "#c4b1f6",
+-- bright = "#e4d1ff",
+-- },
+-- pink = palette {
+-- "#e5acb4",
+-- bright = "#ffccd4",
+-- },
+--
+-- transparent = "#00000000",
+-- }
+
+-- qcolor.palette = {
+-- fg = x_col.foreground,
+-- bg = x_col.background,
+--
+-- black = x_col.color0,
+-- red = x_col.color1,
+-- green = x_col.color2,
+-- yellow = x_col.color3,
+-- blue = x_col.color4,
+-- pink = x_col.color5,
+-- cyan = x_col.color6,
+-- white = x_col.color7,
+--
+-- bright = {
+-- black = x_col.color8,
+-- red = x_col.color9,
+-- green = x_col.color10,
+-- yellow = x_col.color11,
+-- blue = x_col.color12,
+-- pink = x_col.color13,
+-- cyan = x_col.color14,
+-- white = x_col.color15,
+-- },
+--
+-- dim = {
+-- fg = "#77828c",
+-- bg = "#161b22",
+-- },
+--
+-- transparent = "#00000000",
+-- }
-- taken from https://github.com/bew/dotfiles/blob/ab9bb1935783f7a31ef777b1d7e26d53f35df864/gui/wezterm/cfg_utils.lua
-qvars.mods = setmetatable({ _SHORT_MAP = { C = "Control", S = "Shift", A = "Mod1", M = "Mod4" } }, {
- __index = function(self, key)
- local resolved_mods = {}
- for i = 1, #key do
- resolved_mods[i] = self._SHORT_MAP[key:sub(i, i)]
- end
- return resolved_mods
- end,
-})
-
----@enum buttons
-qvars.btns = {
- left = btns.LEFT,
- right = btns.RIGHT,
- middle = btns.MIDDLE,
- up = btns.SCROLL_UP,
- down = btns.SCROLL_DOWN,
-}
+-- qbind.mods = setmetatable({ _SHORT_MAP = { C = "Control", S = "Shift", A = "Mod1", M = "Mod4" } }, {
+-- __index = function(self, key)
+-- local resolved_mods = {}
+-- for i = 1, #key do
+-- resolved_mods[i] = self._SHORT_MAP[key:sub(i, i)]
+-- end
+-- return resolved_mods
+-- end,
+-- })
+--
+-- ---@enum buttons
+-- qbind.btns = {
+-- left = btns.LEFT,
+-- right = btns.RIGHT,
+-- middle = btns.MIDDLE,
+-- up = btns.SCROLL_UP,
+-- down = btns.SCROLL_DOWN,
+-- }
return qvars