From 9978efd6bcaeb0f1c423accbc3f6cca1bf8cec99 Mon Sep 17 00:00:00 2001 From: Harrison DiAmbrosio Date: Thu, 12 Mar 2026 16:27:39 -0400 Subject: [PATCH] batman --- .luarc.json | 14 +++ README.md | 1 + lua/euclid/init.lua | 268 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 283 insertions(+) create mode 100644 .luarc.json create mode 100644 README.md create mode 100644 lua/euclid/init.lua diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..4cba9c9 --- /dev/null +++ b/.luarc.json @@ -0,0 +1,14 @@ +{ + "runtime.version": "LuaJIT", + "runtime.path": [ + "lua/?.lua", + "lua/?/init.lua" + ], + "diagnostics.globals": ["mez"], + "workspace.checkThirdParty": false, + "completion.autoRequire": false, + "workspace.library": [ + "/usr/share/mez/runtime", + "./runtime" + ] +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..c6fd7c3 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# euclid.mez diff --git a/lua/euclid/init.lua b/lua/euclid/init.lua new file mode 100644 index 0000000..84c71f5 --- /dev/null +++ b/lua/euclid/init.lua @@ -0,0 +1,268 @@ +---@module "mez_types" + +---@class Euclid +---@field default_config EuclidConfig +---@field config EuclidConfig +---@field state EuclidState +local M = {} + +local utils = {} + +---@param view_id integer +---@return integer? view_idx +---@return integer? tag_idx +utils.find_view = function (view_id) + for tag_idx = 1, M.config.tag_count do + for view_idx, v in ipairs(M.state.tags[tag_idx].views) do + if v == view_id then + return view_idx, tag_idx + end + end + end + + return nil, nil +end + +---@class EuclidConfig +---@field mod_key string +---@field tag_count number +---@field focus_on_spawn boolean +---@field refocus_on_kill boolean +local default_config = { + mod_key = "alt", + tag_count = 5, + focus_on_spawn = true, + refocus_on_kill = true, +} + +---@class EuclidTag +---@field views number[] +---@field last_focused number | nil + +---@class EuclidState +---@field tag_id number +---@field tags EuclidTag[] + +---Add the id of a new view +---@param view_id number +M.add_view = function(view_id) + local tag = M.state.tags[M.state.tag_id] + + tag.views[#tag.views + 1] = view_id + + local res = mez.output.get_available_area(0) + if res == nil then return end + mez.view.set_geometry(view_id, { + x = (0.25 / 2) * res.width, + y = (0.25 / 2) * res.height, + width = res.width * 0.75, + height = res.height * 0.75 + }) + + if M.config.focus_on_spawn then mez.view.set_focused(view_id) end +end + +---Move the focus in a tag to the next view +M.focus_next = function() + local view_id = mez.view.get_focused_id() + if view_id == nil then return end + + local view_idx, tag_idx = utils.find_view(view_id) + if view_idx == nil or tag_idx == nil then return end + + local tag = M.state.tags[tag_idx] + + if view_idx == #tag.views then + mez.view.set_focused(tag.views[1]) + else + mez.view.set_focused(tag.views[view_idx + 1]) + end +end + +---Move the focus in a tag to the previous view +M.focus_prev = function() + local view_id = mez.view.get_focused_id() + if view_id == nil then return end + + local view_idx, tag_idx = utils.find_view(view_id) + if view_idx == nil or tag_idx == nil then return end + + local tag = M.state.tags[tag_idx] + + if view_idx == 1 then + mez.view.set_focused(tag.views[#tag.views]) + else + mez.view.set_focused(tag.views[view_idx - 1]) + end +end + +---Remove a view_id from the layout +---@param view_id integer +M.remove_view = function(view_id) + local view_idx, tag_idx = utils.find_view(view_id) + if view_idx == nil or tag_idx == nil then return end + local tag = M.state.tags[tag_idx] + + + + if M.config.refocus_on_kill then + if #tag.views == 0 then + mez.view.set_focused(nil) + else + mez.view.set_focused(tag.views[#tag.views == view_idx and view_idx - 1 or view_idx]) + end + end +end + +---Switch to a tag by enabling all views for 1 tag, +---and disabling all the views for the old tag +---@param tag_idx number +M.tag_enable = function (tag_idx) + ---@param t number + ---@param enabled boolean + local set_tag_enable = function (t, enabled) + local tag = M.state.tags[t] + + local focused = mez.view.get_focused_id() + if not enabled and focused ~= nil then + tag.last_focused = focused + end + + for _, v in ipairs(tag.views) do + mez.view.set_enabled(v, enabled) + end + end + + set_tag_enable(M.state.tag_id, false) + set_tag_enable(tag_idx, true) + + M.state.tag_id = tag_idx +end + +---@param view_id number +---@param tag_id number +M.send_view = function (view_id, tag_id) + -- if view_id == 0 then view_id = mez.view.get_focused_id() end + -- if tag_id == M.state.tag_id then return end + -- + -- local type, _, _ = utils.find_view(view_id) + -- + -- local tag = M.state.tags[tag_id] + -- + -- M.remove_view(view_id) + -- + -- if type == "floating" then + -- table.insert(tag.floating, #tag.floating, view_id) + -- else + -- if tag.master == nil then + -- tag.master = view_id + -- else + -- table.insert(tag.stack, #tag.stack, view_id) + -- end + -- end + -- + -- mez.view.set_enabled(view_id, false) + -- M.tile_tag(M.state.tag_id) + -- M.tile_tag(tag_id) +end + +M.setup = function() + --- Take a user config + M.config = default_config + + M.state = { + tag_id = 1, + tags = {}, + } + + -- Create all tags for the state + for i = 1, M.config.tag_count do + M.state.tags[i] = { + views = {}, + last_focused = nil + } + end + + mez.hook.add("ViewMapPre", { callback = function(view_id) M.add_view(view_id) end }) + mez.hook.add("ViewUnmapPost", { callback = function(view_id) M.remove_view(view_id) end }) + + mez.input.add_keymap(M.config.mod_key, "j", { press = function () M.focus_next() end }) + mez.input.add_keymap(M.config.mod_key, "k", { press = function () M.focus_prev() end }) + + local fullscreen = function() mez.view.toggle_fullscreen(0) end + mez.input.add_keymap(M.config.mod_key.."|shift", "F", { press = fullscreen }) + mez.hook.add("ViewRequestFullscreen", { callback = fullscreen }) + + for i = 1, M.config.tag_count do + mez.input.add_keymap(M.config.mod_key, tostring(i), { press = function () M.tag_enable(i) end }) + end + + mez.input.add_mousemap(M.config.mod_key, "BTN_LEFT", { + press = function () return false end, + drag = function(view_id, pos, _, offset) + if view_id ~= nil then + mez.view.set_geometry(view_id, { x = pos.x - offset.x, y = pos.y - offset.y }) + end + + end + }) + + ---@type {x: number, y: number}[] + local move_all = {} + mez.input.add_mousemap(M.config.mod_key, "BTN_MIDDLE", { + press = function () + move_all = {} + for i, v in ipairs(M.state.tags[M.state.tag_id].views) do + local geo = mez.view.get_geometry(v) + move_all[i] = { x = geo.x, y = geo.y } + end + end, + drag = function(_, pos, start, offset) + for i, v in ipairs(M.state.tags[M.state.tag_id].views) do + local geo = move_all[i] + mez.view.set_geometry(v, { + x = geo.x + (pos.x - start.x), + y = geo.y + (pos.y - start.y) + }) + end + end + }) + + mez.input.add_mousemap(M.config.mod_key, "BTN_RIGHT", { + drag = function(view_id, pos, start, offset) + if view_id ~= nil then + local geo = mez.view.get_geometry(view_id) + + local width = offset.x + pos.x - start.x + local height = offset.y + pos.y - start.y + + if width <= 10 then width = 10 end + if height <= 10 then height = 10 end + mez.view.set_geometry(view_id, { width = width, height = height }) + end + end + }) + + mez.input.add_mousemap(M.config.mod_key, "REL_WHEEL", { + scroll = function (view_id, pos, delta, discrete_delta) + delta = -delta / 250; + mez.output.set_scale(0, mez.output.get_scale(0) + delta) + print(mez.output.get_scale(0)) + end + }) + + mez.input.add_keymap(M.config.mod_key.."|shift", "equal", { + press = function () + print("pressed") + local _, err = pcall(function () + mez.output.set_scale(0, mez.output.get_scale(0) + 0.1) + print(mez.output.get_scale(0)) + end) + if err then + print(err) + end + end + }) +end + +return M