From 05820914d3cf872c65a5cc9f6aadc3838d812aa7 Mon Sep 17 00:00:00 2001 From: Lemmy Date: Wed, 15 Jul 2026 00:22:44 -0400 Subject: [PATCH] refactor: enforce noctalia.getConfig across community plugins --- .github/workflows/test_validate_plugins.py | 38 +++++++++++ .github/workflows/validate-plugins.py | 74 ++++++++++++++++++++++ color_picker/plugin.toml | 2 +- color_picker/widget.luau | 4 +- mangowm-keymode/keymode.luau | 4 +- mangowm-keymode/plugin.toml | 2 +- shelly/plugin.toml | 2 +- shelly/widget.luau | 12 ++-- upbeat/plugin.toml | 4 +- upbeat/upbeat.luau | 8 +-- 10 files changed, 131 insertions(+), 19 deletions(-) diff --git a/.github/workflows/test_validate_plugins.py b/.github/workflows/test_validate_plugins.py index 46c0a00..126873b 100644 --- a/.github/workflows/test_validate_plugins.py +++ b/.github/workflows/test_validate_plugins.py @@ -65,5 +65,43 @@ class AllowedTagsTests(unittest.TestCase): self.assertTrue(any("tags[2] must be a non-empty string" in error for error in errors)) +class PluginConfigAccessorTests(unittest.TestCase): + def test_accepts_universal_accessor(self) -> None: + self.assertEqual( + validate_plugins.obsolete_config_accessors('local value = noctalia.getConfig("key")'), + [], + ) + + def test_rejects_every_entry_specific_alias(self) -> None: + source = "\n".join( + [ + 'barWidget.getConfig("one")', + 'desktopWidget.getConfig("two")', + 'panel . getConfig("three")', + 'launcher.getConfig("four")', + ] + ) + self.assertEqual( + validate_plugins.obsolete_config_accessors(source), + [ + ("barWidget.getConfig", 1), + ("desktopWidget.getConfig", 2), + ("panel.getConfig", 3), + ("launcher.getConfig", 4), + ], + ) + + def test_ignores_comments_and_strings(self) -> None: + source = "\n".join( + [ + '-- barWidget.getConfig("comment")', + '--[[ panel.getConfig("block comment") ]]', + 'local text = "launcher.getConfig(\\\"string\\\")"', + 'local block = [[desktopWidget.getConfig("long string")]]', + ] + ) + self.assertEqual(validate_plugins.obsolete_config_accessors(source), []) + + if __name__ == "__main__": unittest.main() diff --git a/.github/workflows/validate-plugins.py b/.github/workflows/validate-plugins.py index 976c9fe..7428cf1 100644 --- a/.github/workflows/validate-plugins.py +++ b/.github/workflows/validate-plugins.py @@ -151,6 +151,9 @@ HTML_RE = re.compile( ) INLINE_CODE_RE = re.compile(r"(? bool: @@ -208,6 +211,62 @@ def raw_html_line(markdown: str) -> int | None: return text.count("\n", 0, match.start()) + 1 +def obsolete_config_accessors(source: str) -> list[tuple[str, int]]: + """Find removed entry-specific getConfig aliases outside Luau comments and strings.""" + visible = list(source) + length = len(source) + index = 0 + + def mask(start: int, end: int) -> None: + for offset in range(start, end): + if visible[offset] not in "\r\n": + visible[offset] = " " + + while index < length: + if source.startswith("--[[", index): + end = source.find("]]", index + 4) + end = length if end == -1 else end + 2 + mask(index, end) + index = end + continue + + if source.startswith("--", index): + end = source.find("\n", index + 2) + end = length if end == -1 else end + mask(index, end) + index = end + continue + + if source.startswith("[[", index): + end = source.find("]]", index + 2) + end = length if end == -1 else end + 2 + mask(index, end) + index = end + continue + + if source[index] in "\"'": + quote = source[index] + end = index + 1 + while end < length: + if source[end] == "\\" and end + 1 < length: + end += 2 + continue + end += 1 + if source[end - 1] == quote: + break + mask(index, end) + index = end + continue + + index += 1 + + code = "".join(visible) + return [ + (f"{match.group(1)}.getConfig", code.count("\n", 0, match.start()) + 1) + for match in OBSOLETE_CONFIG_ACCESSOR_RE.finditer(code) + ] + + def webp_dimensions(header: bytes) -> tuple[int, int] | None: """Width and height from a WebP header, or None if it is not one we can read. @@ -880,6 +939,20 @@ class Validator: if line is not None: self.add_error(readme, f"raw HTML on line {line} is not allowed; use Markdown instead") + def validate_luau_api(self, plugin_dir: Path) -> None: + for source_path in sorted(plugin_dir.rglob("*.luau")): + try: + source = source_path.read_text(encoding="utf-8") + except UnicodeDecodeError: + self.add_error(source_path, "must be UTF-8 text") + continue + + for accessor, line in obsolete_config_accessors(source): + self.add_error( + source_path, + f"'{accessor}' on line {line} was removed; use noctalia.getConfig", + ) + def validate_no_symlinks(self, manifest_path: Path, plugin_dir: Path) -> None: for path in plugin_dir.rglob("*"): if path.is_symlink(): @@ -897,6 +970,7 @@ class Validator: self.validate_required_files(manifest_path, plugin_dir) self.validate_thumbnail(manifest_path, plugin_dir) self.validate_readme(plugin_dir) + self.validate_luau_api(plugin_dir) self.validate_no_symlinks(manifest_path, plugin_dir) if "setting" in manifest: diff --git a/color_picker/plugin.toml b/color_picker/plugin.toml index 0cabff5..a5feeab 100644 --- a/color_picker/plugin.toml +++ b/color_picker/plugin.toml @@ -3,7 +3,7 @@ id = "oldirtty/color_picker" name = "Color Picker" description = "Pick a color from your screen with hyprpicker." license = "MIT" -version = "1.0.0" +version = "1.0.1" min_noctalia = "5.0.0" icon = "palette" dependencies = ["hyprpicker"] diff --git a/color_picker/widget.luau b/color_picker/widget.luau index ec4769c..87dd93c 100644 --- a/color_picker/widget.luau +++ b/color_picker/widget.luau @@ -3,7 +3,7 @@ -- Right Click: picks a color directly -- and copies the hex to clipboard (no panel). -local glyph = barWidget.getConfig("glyph") +local glyph = noctalia.getConfig("glyph") local tr_color_picker = noctalia.tr("color_picker"); local function render() @@ -23,4 +23,4 @@ function onRightClick() end) end -render() \ No newline at end of file +render() diff --git a/mangowm-keymode/keymode.luau b/mangowm-keymode/keymode.luau index 1ca2958..8924061 100644 --- a/mangowm-keymode/keymode.luau +++ b/mangowm-keymode/keymode.luau @@ -1,5 +1,5 @@ -local showText = barWidget.getConfig("show_text") -local notifyChange = barWidget.getConfig("notify_change") +local showText = noctalia.getConfig("show_text") +local notifyChange = noctalia.getConfig("notify_change") local currentKeymode = "default" diff --git a/mangowm-keymode/plugin.toml b/mangowm-keymode/plugin.toml index c8f428c..8b27d6d 100644 --- a/mangowm-keymode/plugin.toml +++ b/mangowm-keymode/plugin.toml @@ -1,6 +1,6 @@ id = "gambled23/mangowm-keymode" name = "Mangowm Keymode" -version = "1.0.0" +version = "1.0.1" min_noctalia = "5.0.0" author = "gambled23" license = "MIT" diff --git a/shelly/plugin.toml b/shelly/plugin.toml index 4978028..c1b1aa6 100644 --- a/shelly/plugin.toml +++ b/shelly/plugin.toml @@ -1,7 +1,7 @@ id = "joshuaslate/shelly" name = "Shelly" icon = "package" -version = "1.0.0" +version = "1.0.1" min_noctalia = "5.0.0" license = "MIT" author = "joshuaslate" diff --git a/shelly/widget.luau b/shelly/widget.luau index 6c9ec87..2d793f7 100644 --- a/shelly/widget.luau +++ b/shelly/widget.luau @@ -1,11 +1,11 @@ --!nonstrict -local glyph = barWidget.getConfig("glyph") -local color = barWidget.getConfig("color") or "on_surface" -local glyphColor = barWidget.getConfig("glyph_color") or color +local glyph = noctalia.getConfig("glyph") +local color = noctalia.getConfig("color") or "on_surface" +local glyphColor = noctalia.getConfig("glyph_color") or color local updateError = noctalia.state.get("update_error") -local notifyOnNewUpdates = barWidget.getConfig("notify") -local hideWhenUpToDate = barWidget.getConfig("hide_when_up_to_date") -local click_action = barWidget.getConfig("click_action") or "open_gui" +local notifyOnNewUpdates = noctalia.getConfig("notify") +local hideWhenUpToDate = noctalia.getConfig("hide_when_up_to_date") +local click_action = noctalia.getConfig("click_action") or "open_gui" local updates = noctalia.state.get("updates") or { Packages = {}, Aur = {}, Flatpak = {} } local function countUpdates(scopedUpdates) diff --git a/upbeat/plugin.toml b/upbeat/plugin.toml index cc9d7b0..23c9c16 100644 --- a/upbeat/plugin.toml +++ b/upbeat/plugin.toml @@ -1,6 +1,6 @@ id = "neuro/upbeat" name = "Upbeat" -version = "1.0.0" +version = "1.0.1" min_noctalia = "5.0.0" author = "neuro" license = "MIT" @@ -33,4 +33,4 @@ key = "time_format_toggle" type = "bool" label_key = "settings.time_format_toggle.label" default = false -description_key = "settings.time_format_toggle.description" \ No newline at end of file +description_key = "settings.time_format_toggle.description" diff --git a/upbeat/upbeat.luau b/upbeat/upbeat.luau index 8a2c6cc..007f9db 100644 --- a/upbeat/upbeat.luau +++ b/upbeat/upbeat.luau @@ -13,10 +13,10 @@ function update() local secondsSinceMidnight: number = (os.time() + BIEL_OFFSET_SECONDS) % 86400 -- 86400 = seconds in one day local totalCentibeats: number = math.floor(secondsSinceMidnight / SECONDS_PER_CENTIBEAT) -- define display of subbeat toggle - local useCentibeats: boolean = barWidget.getConfig("show_centibeats") + local useCentibeats: boolean = noctalia.getConfig("show_centibeats") -- define display of @beats toggle - local showSuffix: boolean = barWidget.getConfig("beat_display") - local timeFormatToggle: boolean = barWidget.getConfig("time_format_toggle") + local showSuffix: boolean = noctalia.getConfig("beat_display") + local timeFormatToggle: boolean = noctalia.getConfig("time_format_toggle") local checkValue: number = useCentibeats and totalCentibeats or math.floor(totalCentibeats / 100) -- layout updates when values tick if checkValue ~= lastValue then @@ -42,4 +42,4 @@ function update() -- defines targeting of next whole beat change (+100ms padding) noctalia.setUpdateInterval(math.floor((secondsToNextBeat * 1000) + 100)) end -end \ No newline at end of file +end