From bafd48d3df9b43a1d49ec015eff30619d595468b Mon Sep 17 00:00:00 2001 From: Aylur Date: Tue, 15 Oct 2024 13:25:45 +0000 Subject: update lua and gjs layout installing the gjs package through meson or npm now results in the same exposed structure lua: fix rockspec docs: aur package --- lang/lua/astal/binding.lua | 71 ++++++++++ lang/lua/astal/file.lua | 45 +++++++ lang/lua/astal/gtk3/app.lua | 96 ++++++++++++++ lang/lua/astal/gtk3/astalify.lua | 236 +++++++++++++++++++++++++++++++++ lang/lua/astal/gtk3/init.lua | 5 + lang/lua/astal/gtk3/widget.lua | 90 +++++++++++++ lang/lua/astal/init.lua | 27 ++++ lang/lua/astal/process.lua | 78 +++++++++++ lang/lua/astal/time.lua | 27 ++++ lang/lua/astal/variable.lua | 276 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 951 insertions(+) create mode 100644 lang/lua/astal/binding.lua create mode 100644 lang/lua/astal/file.lua create mode 100644 lang/lua/astal/gtk3/app.lua create mode 100644 lang/lua/astal/gtk3/astalify.lua create mode 100644 lang/lua/astal/gtk3/init.lua create mode 100644 lang/lua/astal/gtk3/widget.lua create mode 100644 lang/lua/astal/init.lua create mode 100644 lang/lua/astal/process.lua create mode 100644 lang/lua/astal/time.lua create mode 100644 lang/lua/astal/variable.lua (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/binding.lua b/lang/lua/astal/binding.lua new file mode 100644 index 0000000..ba1e6e4 --- /dev/null +++ b/lang/lua/astal/binding.lua @@ -0,0 +1,71 @@ +local lgi = require("lgi") +local GObject = lgi.require("GObject", "2.0") + +---@class Binding +---@field emitter table|Variable +---@field property? string +---@field transformFn function +local Binding = {} + +---@param emitter table +---@param property? string +---@return Binding +function Binding.new(emitter, property) + return setmetatable({ + emitter = emitter, + property = property, + transformFn = function(v) + return v + end, + }, Binding) +end + +function Binding:__tostring() + local str = "Binding<" .. tostring(self.emitter) + if self.property ~= nil then + str = str .. ", " .. self.property + end + return str .. ">" +end + +function Binding:get() + if self.property ~= nil and GObject.Object:is_type_of(self.emitter) then + return self.transformFn(self.emitter[self.property]) + end + if type(self.emitter.get) == "function" then + return self.transformFn(self.emitter:get()) + end + error("can not get: Not a GObject or a Variable " + self) +end + +---@param transform fun(value: any): any +---@return Binding +function Binding:as(transform) + local b = Binding.new(self.emitter, self.property) + b.transformFn = function(v) + return transform(self.transformFn(v)) + end + return b +end + +---@param callback fun(value: any) +---@return function +function Binding:subscribe(callback) + if self.property ~= nil and GObject.Object:is_type_of(self.emitter) then + local id = self.emitter.on_notify:connect(function() + callback(self:get()) + end, self.property, false) + return function() + GObject.signal_handler_disconnect(self.emitter, id) + end + end + if type(self.emitter.subscribe) == "function" then + return self.emitter:subscribe(function() + callback(self:get()) + end) + end + error("can not subscribe: Not a GObject or a Variable " + self) +end + +Binding.__index = Binding +return Binding diff --git a/lang/lua/astal/file.lua b/lang/lua/astal/file.lua new file mode 100644 index 0000000..e3be783 --- /dev/null +++ b/lang/lua/astal/file.lua @@ -0,0 +1,45 @@ +local lgi = require("lgi") +local Astal = lgi.require("AstalIO", "0.1") +local GObject = lgi.require("GObject", "2.0") + +local M = {} + +---@param path string +---@return string +function M.read_file(path) + return Astal.read_file(path) +end + +---@param path string +---@param callback fun(content: string, err: string): nil +function M.read_file_async(path, callback) + Astal.read_file_async(path, function(_, res) + local content, err = Astal.read_file_finish(res) + callback(content, err) + end) +end + +---@param path string +---@param content string +function M.write_file(path, content) + Astal.write_file(path, content) +end + +---@param path string +---@param content string +---@param callback? fun(err: string): nil +function M.write_file_async(path, content, callback) + Astal.write_file_async(path, content, function(_, res) + if type(callback) == "function" then + callback(Astal.write_file_finish(res)) + end + end) +end + +---@param path string +---@param callback fun(file: string, event: integer): nil +function M.monitor_file(path, callback) + return Astal.monitor_file(path, GObject.Closure(callback)) +end + +return M diff --git a/lang/lua/astal/gtk3/app.lua b/lang/lua/astal/gtk3/app.lua new file mode 100644 index 0000000..7895f69 --- /dev/null +++ b/lang/lua/astal/gtk3/app.lua @@ -0,0 +1,96 @@ +local lgi = require("lgi") +local Astal = lgi.require("Astal", "3.0") +local AstalIO = lgi.require("AstalIO", "0.1") + +local AstalLua = Astal.Application:derive("AstalLua") +local request_handler + +function AstalLua:do_request(msg, conn) + if type(request_handler) == "function" then + request_handler(msg, function(response) + AstalIO.write_sock(conn, tostring(response), function(_, res) + AstalIO.write_sock_finish(res) + end) + end) + else + Astal.Application.do_request(self, msg, conn) + end +end + +function AstalLua:quit(code) + Astal.Application.quit(self) + os.exit(code) +end + +local app = AstalLua() + +---@class StartConfig +---@field icons? string +---@field instance_name? string +---@field gtk_theme? string +---@field icon_theme? string +---@field cursor_theme? string +---@field css? string +---@field hold? boolean +---@field request_handler? fun(msg: string, response: fun(res: any)) +---@field main? fun(...): unknown +---@field client? fun(message: fun(msg: string): string, ...): unknown + +---@param config StartConfig | nil +function Astal.Application:start(config) + if config == nil then + config = {} + end + + if config.client == nil then + config.client = function() + print('Astal instance "' .. app.instance_name .. '" is already running') + os.exit(1) + end + end + + if config.hold == nil then + config.hold = true + end + + request_handler = config.request_handler + + if config.css then + self:apply_css(config.css) + end + if config.icons then + self:add_icons(config.icons) + end + if config.instance_name then + self.instance_name = config.instance_name + end + if config.gtk_theme then + self.gtk_theme = config.gtk_theme + end + if config.icon_theme then + self.icon_theme = config.icon_theme + end + if config.cursor_theme then + self.cursor_theme = config.cursor_theme + end + + app.on_activate = function() + if type(config.main) == "function" then + config.main(table.unpack(arg)) + end + if config.hold then + self:hold() + end + end + + local _, err = app:acquire_socket() + if err ~= nil then + return config.client(function(msg) + return AstalIO.send_message(self.instance_name, msg) + end, table.unpack(arg)) + end + + self:run(nil) +end + +return app diff --git a/lang/lua/astal/gtk3/astalify.lua b/lang/lua/astal/gtk3/astalify.lua new file mode 100644 index 0000000..065de40 --- /dev/null +++ b/lang/lua/astal/gtk3/astalify.lua @@ -0,0 +1,236 @@ +local lgi = require("lgi") +local Astal = lgi.require("Astal", "3.0") +local Gtk = lgi.require("Gtk", "3.0") +local GObject = lgi.require("GObject", "2.0") +local Binding = require("astal.lib.binding") +local Variable = require("astal.lib.variable") +local exec_async = require("astal.lib.process").exec_async + +local function filter(tbl, fn) + local copy = {} + for key, value in pairs(tbl) do + if fn(value, key) then + if type(key) == "number" then + table.insert(copy, value) + else + copy[key] = value + end + end + end + return copy +end + +local function map(tbl, fn) + local copy = {} + for key, value in pairs(tbl) do + copy[key] = fn(value) + end + return copy +end + +local flatten +flatten = function(tbl) + local copy = {} + for _, value in pairs(tbl) do + if type(value) == "table" and getmetatable(value) == nil then + for _, inner in pairs(flatten(value)) do + table.insert(copy, inner) + end + else + table.insert(copy, value) + end + end + return copy +end + +local function includes(tbl, elem) + for _, value in pairs(tbl) do + if value == elem then + return true + end + end + return false +end + +local function set_children(parent, children) + children = map(flatten(children), function(item) + if Gtk.Widget:is_type_of(item) then + return item + end + return Gtk.Label({ + visible = true, + label = tostring(item), + }) + end) + + -- remove + if Gtk.Bin:is_type_of(parent) then + local ch = parent:get_child() + if ch ~= nil then + parent:remove(ch) + end + if ch ~= nil and not includes(children, ch) and not parent.no_implicit_destroy then + ch:destroy() + end + elseif Gtk.Container:is_type_of(parent) then + for _, ch in ipairs(parent:get_children()) do + parent:remove(ch) + if ch ~= nil and not includes(children, ch) and not parent.no_implicit_destroy then + ch:destroy() + end + end + end + + -- TODO: add more container types + if Astal.Box:is_type_of(parent) then + parent:set_children(children) + elseif Astal.Stack:is_type_of(parent) then + parent:set_children(children) + elseif Astal.CenterBox:is_type_of(parent) then + parent.start_widget = children[1] + parent.center_widget = children[2] + parent.end_widget = children[3] + elseif Astal.Overlay:is_type_of(parent) then + parent:set_child(children[1]) + children[1] = nil + parent:set_overlays(children) + elseif Gtk.Container:is_type_of(parent) then + for _, child in pairs(children) do + if Gtk.Widget:is_type_of(child) then + parent:add(child) + end + end + end +end + +local function merge_bindings(array) + local function get_values(...) + local args = { ... } + local i = 0 + return map(array, function(value) + if getmetatable(value) == Binding then + i = i + 1 + return args[i] + else + return value + end + end) + end + + local bindings = filter(array, function(v) + return getmetatable(v) == Binding + end) + + if #bindings == 0 then + return array + end + + if #bindings == 1 then + return bindings[1]:as(get_values) + end + + return Variable.derive(bindings, get_values)() +end + +return function(ctor) + function ctor:hook(object, signalOrCallback, callback) + if GObject.Object:is_type_of(object) and type(signalOrCallback) == "string" then + local id + if string.sub(signalOrCallback, 1, 8) == "notify::" then + local prop = string.gsub(signalOrCallback, "notify::", "") + id = object.on_notify:connect(function() + callback(self, object[prop]) + end, prop, false) + else + id = object["on_" .. signalOrCallback]:connect(function(_, ...) + callback(self, ...) + end) + end + self.on_destroy = function() + GObject.signal_handler_disconnect(object, id) + end + elseif type(object.subscribe) == "function" then + local unsub = object.subscribe(function(...) + signalOrCallback(self, ...) + end) + self.on_destroy = unsub + else + error("can not hook: not gobject+signal or subscribable") + end + end + + function ctor:toggle_class_name(name, on) + Astal.widget_toggle_class_name(self, name, on) + end + + return function(tbl) + if tbl == nil then + tbl = {} + end + + local bindings = {} + local setup = tbl.setup + + -- collect children + local children = merge_bindings(flatten(filter(tbl, function(_, key) + return type(key) == "number" + end))) + + -- default visible to true + if type(tbl.visible) ~= "boolean" then + tbl.visible = true + end + + -- collect props + local props = filter(tbl, function(_, key) + return type(key) == "string" and key ~= "setup" + end) + + -- collect signal handlers + for prop, value in pairs(props) do + if string.sub(prop, 0, 2) == "on" and type(value) ~= "function" then + props[prop] = function() + exec_async(value, print) + end + end + end + + -- collect bindings + for prop, value in pairs(props) do + if getmetatable(value) == Binding then + bindings[prop] = value + props[prop] = value:get() + end + end + + -- construct, attach bindings, add children + local widget = ctor() + + if getmetatable(children) == Binding then + set_children(widget, children:get()) + widget.on_destroy = children:subscribe(function(v) + set_children(widget, v) + end) + else + if #children > 0 then + set_children(widget, children) + end + end + + for prop, binding in pairs(bindings) do + widget.on_destroy = binding:subscribe(function(v) + widget[prop] = v + end) + end + + for prop, value in pairs(props) do + widget[prop] = value + end + + if type(setup) == "function" then + setup(widget) + end + + return widget + end +end diff --git a/lang/lua/astal/gtk3/init.lua b/lang/lua/astal/gtk3/init.lua new file mode 100644 index 0000000..6fb5455 --- /dev/null +++ b/lang/lua/astal/gtk3/init.lua @@ -0,0 +1,5 @@ +return { + App = require("astal.gtk3.app"), + astalify = require("astal.gtk3.astalify"), + Widget = require("astal.gtk3.widget"), +} diff --git a/lang/lua/astal/gtk3/widget.lua b/lang/lua/astal/gtk3/widget.lua new file mode 100644 index 0000000..beaad6c --- /dev/null +++ b/lang/lua/astal/gtk3/widget.lua @@ -0,0 +1,90 @@ +local lgi = require("lgi") +local Astal = lgi.require("Astal", "3.0") +local Gtk = lgi.require("Gtk", "3.0") +local astalify = require("astal.gtk3.astalify") + +local Widget = { + astalify = astalify, + Box = astalify(Astal.Box), + Button = astalify(Astal.Button), + CenterBox = astalify(Astal.CenterBox), + CircularProgress = astalify(Astal.CircularProgress), + DrawingArea = astalify(Gtk.DrawingArea), + Entry = astalify(Gtk.Entry), + EventBox = astalify(Astal.EventBox), + -- TODO: Fixed + -- TODO: FlowBox + Icon = astalify(Astal.Icon), + Label = astalify(Gtk.Label), + LevelBar = astalify(Astal.LevelBar), + -- TODO: ListBox + Overlay = astalify(Astal.Overlay), + Revealer = astalify(Gtk.Revealer), + Scrollable = astalify(Astal.Scrollable), + Slider = astalify(Astal.Slider), + Stack = astalify(Astal.Stack), + Switch = astalify(Gtk.Switch), + Window = astalify(Astal.Window), +} + +Gtk.Widget._attribute.css = { + get = Astal.widget_get_css, + set = Astal.widget_set_css, +} + +Gtk.Widget._attribute.class_name = { + get = function(self) + local result = "" + local strings = Astal.widget_get_class_names(self) + for i, str in ipairs(strings) do + result = result .. str + if i < #strings then + result = result .. " " + end + end + return result + end, + set = function(self, class_name) + local names = {} + for word in class_name:gmatch("%S+") do + table.insert(names, word) + end + Astal.widget_set_class_names(self, names) + end, +} + +Gtk.Widget._attribute.cursor = { + get = Astal.widget_get_cursor, + set = Astal.widget_set_cursor, +} + +Gtk.Widget._attribute.click_through = { + get = Astal.widget_get_click_through, + set = Astal.widget_set_click_through, +} + +local no_implicit_destroy = {} +Gtk.Widget._attribute.no_implicit_destroy = { + get = function(self) + return no_implicit_destroy[self] or false + end, + set = function(self, v) + if no_implicit_destroy[self] == nil then + self.on_destroy = function() + no_implicit_destroy[self] = nil + end + end + no_implicit_destroy[self] = v + end, +} + +Astal.Box._attribute.children = { + get = Astal.Box.get_children, + set = Astal.Box.set_children, +} + +return setmetatable(Widget, { + __call = function(_, ctor) + return astalify(ctor) + end, +}) diff --git a/lang/lua/astal/init.lua b/lang/lua/astal/init.lua new file mode 100644 index 0000000..f442db0 --- /dev/null +++ b/lang/lua/astal/init.lua @@ -0,0 +1,27 @@ +local lgi = require("lgi") +local Binding = require("astal.binding") +local File = require("astal.file") +local Process = require("astal.proc") +local Time = require("astal.time") +local Variable = require("astal.variable") + +return { + Variable = Variable, + bind = Binding.new, + + interval = Time.interval, + timeout = Time.timeout, + idle = Time.idle, + + subprocess = Process.subprocess, + exec = Process.exec, + exec_async = Process.exec_async, + + read_file = File.read_file, + read_file_async = File.read_file_async, + write_file = File.write_file, + write_file_async = File.write_file_async, + monitor_file = File.monitor_file, + + require = lgi.require, +} diff --git a/lang/lua/astal/process.lua b/lang/lua/astal/process.lua new file mode 100644 index 0000000..b8b7436 --- /dev/null +++ b/lang/lua/astal/process.lua @@ -0,0 +1,78 @@ +local lgi = require("lgi") +local Astal = lgi.require("AstalIO", "0.1") + +local M = {} + +---@param commandline string | string[] +---@param on_stdout? fun(out: string): nil +---@param on_stderr? fun(err: string): nil +---@return { kill: function } | nil proc +function M.subprocess(commandline, on_stdout, on_stderr) + if on_stdout == nil then + on_stdout = function(out) + io.stdout:write(tostring(out) .. "\n") + end + end + + if on_stderr == nil then + on_stderr = function(err) + io.stderr:write(tostring(err) .. "\n") + end + end + + local proc, err + if type(commandline) == "table" then + proc, err = Astal.Process.subprocessv(commandline) + else + proc, err = Astal.Process.subprocess(commandline) + end + if err ~= nil then + err(err) + return nil + end + proc.on_stdout = function(_, stdoud) + on_stdout(stdoud) + end + proc.on_stderr = function(_, stderr) + on_stderr(stderr) + end + return proc +end + +---@param commandline string | string[] +---@return string, string +function M.exec(commandline) + if type(commandline) == "table" then + return Astal.Process.execv(commandline) + else + return Astal.Process.exec(commandline) + end +end + +---@param commandline string | string[] +---@param callback? fun(out: string, err: string): nil +function M.exec_async(commandline, callback) + if callback == nil then + callback = function(out, err) + if err ~= nil then + io.stdout:write(tostring(out) .. "\n") + else + io.stderr:write(tostring(err) .. "\n") + end + end + end + + if type(commandline) == "table" then + Astal.Process.exec_asyncv(commandline, function(_, res) + local out, err = Astal.Process.exec_asyncv_finish(res) + callback(out, err) + end) + else + Astal.Process.exec_async(commandline, function(_, res) + local out, err = Astal.Process.exec_finish(res) + callback(out, err) + end) + end +end + +return M diff --git a/lang/lua/astal/time.lua b/lang/lua/astal/time.lua new file mode 100644 index 0000000..7719da9 --- /dev/null +++ b/lang/lua/astal/time.lua @@ -0,0 +1,27 @@ +local lgi = require("lgi") +local Astal = lgi.require("AstalIO", "0.1") +local GObject = lgi.require("GObject", "2.0") + +local M = {} + +---@param interval number +---@param fn function +---@return { cancel: function, on_now: function } +function M.interval(interval, fn) + return Astal.Time.interval(interval, GObject.Closure(fn)) +end + +---@param timeout number +---@param fn function +---@return { cancel: function, on_now: function } +function M.timeout(timeout, fn) + return Astal.Time.timeout(timeout, GObject.Closure(fn)) +end + +---@param fn function +---@return { cancel: function, on_now: function } +function M.idle(fn) + return Astal.Time.idle(GObject.Closure(fn)) +end + +return M diff --git a/lang/lua/astal/variable.lua b/lang/lua/astal/variable.lua new file mode 100644 index 0000000..5a5e169 --- /dev/null +++ b/lang/lua/astal/variable.lua @@ -0,0 +1,276 @@ +local lgi = require("lgi") +local Astal = lgi.require("AstalIO", "0.1") +local GObject = lgi.require("GObject", "2.0") +local Binding = require("astal.binding") +local Time = require("astal.time") +local Process = require("astal.process") + +---@class Variable +---@field private variable table +---@field private err_handler? function +---@field private _value any +---@field private _poll? table +---@field private _watch? table +---@field private poll_interval number +---@field private poll_exec? string[] | string +---@field private poll_transform? fun(next: any, prev: any): any +---@field private poll_fn? function +---@field private watch_transform? fun(next: any, prev: any): any +---@field private watch_exec? string[] | string +local Variable = {} +Variable.__index = Variable + +---@param value any +---@return Variable +function Variable.new(value) + local v = Astal.VariableBase() + local variable = setmetatable({ + variable = v, + _value = value, + }, Variable) + v.on_dropped = function() + variable:stop_watch() + variable:stop_watch() + end + v.on_error = function(_, err) + if variable.err_handler then + variable.err_handler(err) + end + end + return variable +end + +---@param transform function +---@return Binding +function Variable:__call(transform) + if transform == nil then + transform = function(v) + return v + end + return Binding.new(self) + end + return Binding.new(self):as(transform) +end + +function Variable:__tostring() + return "Variable<" .. tostring(self:get()) .. ">" +end + +function Variable:get() + return self._value or nil +end + +function Variable:set(value) + if value ~= self:get() then + self._value = value + self.variable:emit_changed() + end +end + +function Variable:start_poll() + if self._poll ~= nil then + return + end + + if self.poll_fn then + self._poll = Time.interval(self.poll_interval, function() + self:set(self.poll_fn(self:get())) + end) + elseif self.poll_exec then + self._poll = Time.interval(self.poll_interval, function() + Process.exec_async(self.poll_exec, function(out, err) + if err ~= nil then + return self.variable.emit_error(err) + end + self:set(self.poll_transform(out, self:get())) + end) + end) + end +end + +function Variable:start_watch() + if self._watch then + return + end + + self._watch = Process.subprocess(self.watch_exec, function(out) + self:set(self.watch_transform(out, self:get())) + end, function(err) + self.variable.emit_error(err) + end) +end + +function Variable:stop_poll() + if self._poll then + self._poll.cancel() + end + self._poll = nil +end + +function Variable:stop_watch() + if self._watch then + self._watch.kill() + end + self._watch = nil +end + +function Variable:is_polling() + return self._poll ~= nil +end + +function Variable:is_watching() + return self._watch ~= nil +end + +function Variable:drop() + self.variable.emit_dropped() +end + +---@param callback function +---@return Variable +function Variable:on_dropped(callback) + self.variable.on_dropped = callback + return self +end + +---@param callback function +---@return Variable +function Variable:on_error(callback) + self.err_handler = nil + self.variable.on_eror = function(_, err) + callback(err) + end + return self +end + +---@param callback fun(value: any) +---@return function +function Variable:subscribe(callback) + local id = self.variable.on_changed:connect(function() + callback(self:get()) + end) + return function() + GObject.signal_handler_disconnect(self.variable, id) + end +end + +---@param interval number +---@param exec string | string[] | function +---@param transform? fun(next: any, prev: any): any +function Variable:poll(interval, exec, transform) + if transform == nil then + transform = function(next) + return next + end + end + self:stop_poll() + self.poll_interval = interval + self.poll_transform = transform + + if type(exec) == "function" then + self.poll_fn = exec + self.poll_exec = nil + else + self.poll_exec = exec + self.poll_fn = nil + end + self:start_poll() + return self +end + +---@param exec string | string[] +---@param transform? fun(next: any, prev: any): any +function Variable:watch(exec, transform) + if transform == nil then + transform = function(next) + return next + end + end + self:stop_poll() + self.watch_exec = exec + self.watch_transform = transform + self:start_watch() + return self +end + +---@param object table | table[] +---@param sigOrFn string | fun(...): any +---@param callback fun(...): any +---@return Variable +function Variable:observe(object, sigOrFn, callback) + local f + if type(sigOrFn) == "function" then + f = sigOrFn + elseif type(callback) == "function" then + f = callback + else + f = function() + return self:get() + end + end + local set = function(...) + self:set(f(...)) + end + + if type(sigOrFn) == "string" then + object["on_" .. sigOrFn]:connect(set) + else + for _, obj in ipairs(object) do + obj[1]["on_" .. obj[2]]:connect(set) + end + end + return self +end + +---@param deps Variable | (Binding | Variable)[] +---@param transform? fun(...): any +---@return Variable +function Variable.derive(deps, transform) + if type(transform) == "nil" then + transform = function(...) + return { ... } + end + end + + if getmetatable(deps) == Variable then + local var = Variable.new(transform(deps:get())) + deps:subscribe(function(v) + var:set(transform(v)) + end) + return var + end + + for i, var in ipairs(deps) do + if getmetatable(var) == Variable then + deps[i] = Binding.new(var) + end + end + + local update = function() + local params = {} + for i, binding in ipairs(deps) do + params[i] = binding:get() + end + return transform(table.unpack(params), 1, #deps) + end + + local var = Variable.new(update()) + + local unsubs = {} + for i, b in ipairs(deps) do + unsubs[i] = b:subscribe(update) + end + + var.variable.on_dropped = function() + for _, unsub in ipairs(unsubs) do + unsub() + end + end + return var +end + +return setmetatable(Variable, { + __call = function(_, v) + return Variable.new(v) + end, +}) -- cgit v1.2.3 From 4dd0b1840d343dc65f1c781c3d6b8731b6e79eda Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 13 Oct 2024 12:57:37 -0300 Subject: core: lua compat 5.1/5.4/luajit --- lang/lua/astal/gtk3/app.lua | 16 +++++++++++++++- lang/lua/astal/gtk3/astalify.lua | 3 +-- lang/lua/astal/init.lua | 7 ++++++- lang/lua/astal/variable.lua | 3 ++- 4 files changed, 24 insertions(+), 5 deletions(-) (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/gtk3/app.lua b/lang/lua/astal/gtk3/app.lua index 7895f69..13347c3 100644 --- a/lang/lua/astal/gtk3/app.lua +++ b/lang/lua/astal/gtk3/app.lua @@ -5,6 +5,15 @@ local AstalIO = lgi.require("AstalIO", "0.1") local AstalLua = Astal.Application:derive("AstalLua") local request_handler +local function unpack(t, i) + i = i or 1 + if t[i] == nil then + return nil + else + return t[i], unpack(t, i + 1) + end +end + function AstalLua:do_request(msg, conn) if type(request_handler) == "function" then request_handler(msg, function(response) @@ -76,7 +85,7 @@ function Astal.Application:start(config) app.on_activate = function() if type(config.main) == "function" then - config.main(table.unpack(arg)) + config.main(unpack(arg)) end if config.hold then self:hold() @@ -86,8 +95,13 @@ function Astal.Application:start(config) local _, err = app:acquire_socket() if err ~= nil then return config.client(function(msg) +<<<<<<< HEAD:lang/lua/astal/gtk3/app.lua return AstalIO.send_message(self.instance_name, msg) end, table.unpack(arg)) +======= + return Astal.Application.send_message(self.instance_name, msg) + end, unpack(arg)) +>>>>>>> 18df91b (core: lua compat 5.1/5.4/luajit):core/lua/astal/application.lua end self:run(nil) diff --git a/lang/lua/astal/gtk3/astalify.lua b/lang/lua/astal/gtk3/astalify.lua index 065de40..c344c07 100644 --- a/lang/lua/astal/gtk3/astalify.lua +++ b/lang/lua/astal/gtk3/astalify.lua @@ -28,8 +28,7 @@ local function map(tbl, fn) return copy end -local flatten -flatten = function(tbl) +local function flatten(tbl) local copy = {} for _, value in pairs(tbl) do if type(value) == "table" and getmetatable(value) == nil then diff --git a/lang/lua/astal/init.lua b/lang/lua/astal/init.lua index f442db0..783c78a 100644 --- a/lang/lua/astal/init.lua +++ b/lang/lua/astal/init.lua @@ -1,7 +1,12 @@ +if not table.unpack then + table.unpack = unpack +end + + local lgi = require("lgi") local Binding = require("astal.binding") local File = require("astal.file") -local Process = require("astal.proc") +local Process = require("astal.process") local Time = require("astal.time") local Variable = require("astal.variable") diff --git a/lang/lua/astal/variable.lua b/lang/lua/astal/variable.lua index 5a5e169..c2ed337 100644 --- a/lang/lua/astal/variable.lua +++ b/lang/lua/astal/variable.lua @@ -5,6 +5,7 @@ local Binding = require("astal.binding") local Time = require("astal.time") local Process = require("astal.process") + ---@class Variable ---@field private variable table ---@field private err_handler? function @@ -273,4 +274,4 @@ return setmetatable(Variable, { __call = function(_, v) return Variable.new(v) end, -}) +}) \ No newline at end of file -- cgit v1.2.3 From 9e255738f835c0e47cc6ae4d0cfbb96a261b4a2f Mon Sep 17 00:00:00 2001 From: Kevin Date: Mon, 14 Oct 2024 10:27:57 -0300 Subject: core: table.unpack compat in lua, fix typo in astal/init.lua --- lang/lua/astal/gtk3/app.lua | 16 +--------------- lang/lua/astal/init.lua | 1 - lang/lua/astal/variable.lua | 1 - 3 files changed, 1 insertion(+), 17 deletions(-) (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/gtk3/app.lua b/lang/lua/astal/gtk3/app.lua index 13347c3..7895f69 100644 --- a/lang/lua/astal/gtk3/app.lua +++ b/lang/lua/astal/gtk3/app.lua @@ -5,15 +5,6 @@ local AstalIO = lgi.require("AstalIO", "0.1") local AstalLua = Astal.Application:derive("AstalLua") local request_handler -local function unpack(t, i) - i = i or 1 - if t[i] == nil then - return nil - else - return t[i], unpack(t, i + 1) - end -end - function AstalLua:do_request(msg, conn) if type(request_handler) == "function" then request_handler(msg, function(response) @@ -85,7 +76,7 @@ function Astal.Application:start(config) app.on_activate = function() if type(config.main) == "function" then - config.main(unpack(arg)) + config.main(table.unpack(arg)) end if config.hold then self:hold() @@ -95,13 +86,8 @@ function Astal.Application:start(config) local _, err = app:acquire_socket() if err ~= nil then return config.client(function(msg) -<<<<<<< HEAD:lang/lua/astal/gtk3/app.lua return AstalIO.send_message(self.instance_name, msg) end, table.unpack(arg)) -======= - return Astal.Application.send_message(self.instance_name, msg) - end, unpack(arg)) ->>>>>>> 18df91b (core: lua compat 5.1/5.4/luajit):core/lua/astal/application.lua end self:run(nil) diff --git a/lang/lua/astal/init.lua b/lang/lua/astal/init.lua index 783c78a..5630ba4 100644 --- a/lang/lua/astal/init.lua +++ b/lang/lua/astal/init.lua @@ -2,7 +2,6 @@ if not table.unpack then table.unpack = unpack end - local lgi = require("lgi") local Binding = require("astal.binding") local File = require("astal.file") diff --git a/lang/lua/astal/variable.lua b/lang/lua/astal/variable.lua index c2ed337..f9be161 100644 --- a/lang/lua/astal/variable.lua +++ b/lang/lua/astal/variable.lua @@ -5,7 +5,6 @@ local Binding = require("astal.binding") local Time = require("astal.time") local Process = require("astal.process") - ---@class Variable ---@field private variable table ---@field private err_handler? function -- cgit v1.2.3 From dcb7cb325d5525a864098dfcba3100a6151d4d13 Mon Sep 17 00:00:00 2001 From: Kevin Date: Wed, 16 Oct 2024 02:32:56 -0300 Subject: core: lua fix require --- lang/lua/astal/gtk3/astalify.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/gtk3/astalify.lua b/lang/lua/astal/gtk3/astalify.lua index c344c07..211a1d4 100644 --- a/lang/lua/astal/gtk3/astalify.lua +++ b/lang/lua/astal/gtk3/astalify.lua @@ -2,9 +2,9 @@ local lgi = require("lgi") local Astal = lgi.require("Astal", "3.0") local Gtk = lgi.require("Gtk", "3.0") local GObject = lgi.require("GObject", "2.0") -local Binding = require("astal.lib.binding") -local Variable = require("astal.lib.variable") -local exec_async = require("astal.lib.process").exec_async +local Binding = require("astal.binding") +local Variable = require("astal.variable") +local exec_async = require("astal.process").exec_async local function filter(tbl, fn) local copy = {} -- cgit v1.2.3 From 3ea9d58587754931989dae390ca119fb33aa634c Mon Sep 17 00:00:00 2001 From: Kevin Date: Wed, 16 Oct 2024 18:07:33 -0300 Subject: core: lua refactor --- lang/lua/astal/process.lua | 31 +++++++++----------- lang/lua/astal/variable.lua | 71 ++++++++++++++++++++++----------------------- 2 files changed, 49 insertions(+), 53 deletions(-) (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/process.lua b/lang/lua/astal/process.lua index b8b7436..2886164 100644 --- a/lang/lua/astal/process.lua +++ b/lang/lua/astal/process.lua @@ -8,30 +8,29 @@ local M = {} ---@param on_stderr? fun(err: string): nil ---@return { kill: function } | nil proc function M.subprocess(commandline, on_stdout, on_stderr) - if on_stdout == nil then - on_stdout = function(out) - io.stdout:write(tostring(out) .. "\n") - end + on_stdout = on_stdout or function(out) + io.stdout:write(tostring(out) .. "\n") end - if on_stderr == nil then - on_stderr = function(err) - io.stderr:write(tostring(err) .. "\n") - end + on_stderr = on_stderr or function(err) + io.stderr:write(tostring(err) .. "\n") end + local proc, err + if type(commandline) == "table" then proc, err = Astal.Process.subprocessv(commandline) else proc, err = Astal.Process.subprocess(commandline) end + if err ~= nil then err(err) return nil end - proc.on_stdout = function(_, stdoud) - on_stdout(stdoud) + proc.on_stdout = function(_, stdout) + on_stdout(stdout) end proc.on_stderr = function(_, stderr) on_stderr(stderr) @@ -52,13 +51,11 @@ end ---@param commandline string | string[] ---@param callback? fun(out: string, err: string): nil function M.exec_async(commandline, callback) - if callback == nil then - callback = function(out, err) - if err ~= nil then - io.stdout:write(tostring(out) .. "\n") - else - io.stderr:write(tostring(err) .. "\n") - end + callback = callback or function(out, err) + if err ~= nil then + io.stdout:write(tostring(out) .. "\n") + else + io.stderr:write(tostring(err) .. "\n") end end diff --git a/lang/lua/astal/variable.lua b/lang/lua/astal/variable.lua index f9be161..ec563fb 100644 --- a/lang/lua/astal/variable.lua +++ b/lang/lua/astal/variable.lua @@ -20,7 +20,7 @@ local Process = require("astal.process") local Variable = {} Variable.__index = Variable ----@param value any +---@param value? any ---@return Variable function Variable.new(value) local v = Astal.VariableBase() @@ -30,7 +30,7 @@ function Variable.new(value) }, Variable) v.on_dropped = function() variable:stop_watch() - variable:stop_watch() + variable:stop_poll() end v.on_error = function(_, err) if variable.err_handler then @@ -40,16 +40,14 @@ function Variable.new(value) return variable end ----@param transform function +---@param transform? fun(v: any): any ---@return Binding function Variable:__call(transform) - if transform == nil then - transform = function(v) - return v - end + if type(transform) == "nil" then return Binding.new(self) + else + return Binding.new(self):as(transform) end - return Binding.new(self):as(transform) end function Variable:__tostring() @@ -57,7 +55,7 @@ function Variable:__tostring() end function Variable:get() - return self._value or nil + return self._value end function Variable:set(value) @@ -67,8 +65,16 @@ function Variable:set(value) end end +function Variable:is_polling() + return self._poll ~= nil +end + +function Variable:is_watching() + return self._watch ~= nil +end + function Variable:start_poll() - if self._poll ~= nil then + if not self:is_polling() then return end @@ -81,15 +87,16 @@ function Variable:start_poll() Process.exec_async(self.poll_exec, function(out, err) if err ~= nil then return self.variable.emit_error(err) + else + self:set(self.poll_transform(out, self:get())) end - self:set(self.poll_transform(out, self:get())) end) end) end end function Variable:start_watch() - if self._watch then + if not self:is_watching() then return end @@ -100,27 +107,21 @@ function Variable:start_watch() end) end + function Variable:stop_poll() - if self._poll then + if self:is_polling() then self._poll.cancel() end self._poll = nil end function Variable:stop_watch() - if self._watch then + if self:is_watching() then self._watch.kill() end self._watch = nil end -function Variable:is_polling() - return self._poll ~= nil -end - -function Variable:is_watching() - return self._watch ~= nil -end function Variable:drop() self.variable.emit_dropped() @@ -137,7 +138,7 @@ end ---@return Variable function Variable:on_error(callback) self.err_handler = nil - self.variable.on_eror = function(_, err) + self.variable.on_error = function(_, err) callback(err) end return self @@ -158,11 +159,10 @@ end ---@param exec string | string[] | function ---@param transform? fun(next: any, prev: any): any function Variable:poll(interval, exec, transform) - if transform == nil then - transform = function(next) - return next - end + transform = transform or function(next) + return next end + self:stop_poll() self.poll_interval = interval self.poll_transform = transform @@ -181,12 +181,11 @@ end ---@param exec string | string[] ---@param transform? fun(next: any, prev: any): any function Variable:watch(exec, transform) - if transform == nil then - transform = function(next) - return next - end + transform = transform or function (next) + return next end - self:stop_poll() + + self:stop_watch() self.watch_exec = exec self.watch_transform = transform self:start_watch() @@ -208,6 +207,7 @@ function Variable:observe(object, sigOrFn, callback) return self:get() end end + local set = function(...) self:set(f(...)) end @@ -226,10 +226,8 @@ end ---@param transform? fun(...): any ---@return Variable function Variable.derive(deps, transform) - if type(transform) == "nil" then - transform = function(...) - return { ... } - end + transform = transform or function(...) + return { ... } end if getmetatable(deps) == Variable then @@ -246,7 +244,7 @@ function Variable.derive(deps, transform) end end - local update = function() + local function update() local params = {} for i, binding in ipairs(deps) do params[i] = binding:get() @@ -257,6 +255,7 @@ function Variable.derive(deps, transform) local var = Variable.new(update()) local unsubs = {} + for i, b in ipairs(deps) do unsubs[i] = b:subscribe(update) end -- cgit v1.2.3 From 61f7c53529722f6754ebca567149125710a864c6 Mon Sep 17 00:00:00 2001 From: Kevin Date: Thu, 17 Oct 2024 03:17:50 -0300 Subject: core: fix typo --- lang/lua/astal/variable.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/variable.lua b/lang/lua/astal/variable.lua index ec563fb..2305a71 100644 --- a/lang/lua/astal/variable.lua +++ b/lang/lua/astal/variable.lua @@ -74,7 +74,7 @@ function Variable:is_watching() end function Variable:start_poll() - if not self:is_polling() then + if self:is_polling() then return end @@ -96,7 +96,7 @@ function Variable:start_poll() end function Variable:start_watch() - if not self:is_watching() then + if self:is_watching() then return end -- cgit v1.2.3 From e7762eb33a8d5d8c216a42fb6634b8cd87fa9f14 Mon Sep 17 00:00:00 2001 From: Aylur Date: Fri, 18 Oct 2024 12:07:13 +0000 Subject: reexport modules - Gio from file - GLib from gobject - AstalIO.Process from process - AstalIO.Time from time --- lang/lua/astal/process.lua | 2 ++ lang/lua/astal/time.lua | 2 ++ 2 files changed, 4 insertions(+) (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/process.lua b/lang/lua/astal/process.lua index b8b7436..800e83a 100644 --- a/lang/lua/astal/process.lua +++ b/lang/lua/astal/process.lua @@ -3,6 +3,8 @@ local Astal = lgi.require("AstalIO", "0.1") local M = {} +M.Process = Astal.Process + ---@param commandline string | string[] ---@param on_stdout? fun(out: string): nil ---@param on_stderr? fun(err: string): nil diff --git a/lang/lua/astal/time.lua b/lang/lua/astal/time.lua index 7719da9..2b81dbd 100644 --- a/lang/lua/astal/time.lua +++ b/lang/lua/astal/time.lua @@ -4,6 +4,8 @@ local GObject = lgi.require("GObject", "2.0") local M = {} +M.Time = Astal.Time + ---@param interval number ---@param fn function ---@return { cancel: function, on_now: function } -- cgit v1.2.3 From 8306ec0789854f9e04bc1708c4a7dc2afc1b4c90 Mon Sep 17 00:00:00 2001 From: Kevin <119447307+tokyob0t@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:50:00 -0300 Subject: docs: lua docs (#50) --- lang/lua/astal/binding.lua | 10 +++++----- lang/lua/astal/gtk3/init.lua | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/binding.lua b/lang/lua/astal/binding.lua index ba1e6e4..a21fc26 100644 --- a/lang/lua/astal/binding.lua +++ b/lang/lua/astal/binding.lua @@ -4,7 +4,7 @@ local GObject = lgi.require("GObject", "2.0") ---@class Binding ---@field emitter table|Variable ---@field property? string ----@field transformFn function +---@field transform_fn function local Binding = {} ---@param emitter table @@ -30,10 +30,10 @@ end function Binding:get() if self.property ~= nil and GObject.Object:is_type_of(self.emitter) then - return self.transformFn(self.emitter[self.property]) + return self.transform_fn(self.emitter[self.property]) end if type(self.emitter.get) == "function" then - return self.transformFn(self.emitter:get()) + return self.transform_fn(self.emitter:get()) end error("can not get: Not a GObject or a Variable " + self) end @@ -42,8 +42,8 @@ end ---@return Binding function Binding:as(transform) local b = Binding.new(self.emitter, self.property) - b.transformFn = function(v) - return transform(self.transformFn(v)) + b.transform_fn = function(v) + return transform(self.transform_fn(v)) end return b end diff --git a/lang/lua/astal/gtk3/init.lua b/lang/lua/astal/gtk3/init.lua index 6fb5455..e5cc0e6 100644 --- a/lang/lua/astal/gtk3/init.lua +++ b/lang/lua/astal/gtk3/init.lua @@ -1,5 +1,11 @@ +local lgi = require("lgi") + return { App = require("astal.gtk3.app"), astalify = require("astal.gtk3.astalify"), Widget = require("astal.gtk3.widget"), + + Gtk = lgi.require("Gtk", "3.0"), + Gdk = lgi.require("Gdk", "3.0"), + Astal = lgi.require("Astal", "3.0"), } -- cgit v1.2.3 From 4a5308c82e0134f87b7e1ccc56e4fa2778b69fdd Mon Sep 17 00:00:00 2001 From: Aylur Date: Sat, 26 Oct 2024 11:50:43 +0200 Subject: fix: lua flake and lib --- lang/lua/astal/binding.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lang/lua/astal') diff --git a/lang/lua/astal/binding.lua b/lang/lua/astal/binding.lua index a21fc26..2944ec4 100644 --- a/lang/lua/astal/binding.lua +++ b/lang/lua/astal/binding.lua @@ -14,7 +14,7 @@ function Binding.new(emitter, property) return setmetatable({ emitter = emitter, property = property, - transformFn = function(v) + transform_fn = function(v) return v end, }, Binding) -- cgit v1.2.3