From 35f6501de20bc5136b474c85bbacbda5eeb4d541 Mon Sep 17 00:00:00 2001 From: vikingowl Date: Wed, 13 May 2026 12:39:48 +0200 Subject: [PATCH] docs(phase 3.10): owlry.example.lua + refresh user-facing docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation, example config, and one validator-test fix. Version bump and AUR push intentionally deferred. data/owlry.example.lua (new): - Annotated reference config exercising every surface (set / providers / tabs / theme / profiles / provider / util). Active section is minimal and validates clean. aur/owlry/PKGBUILD: - Ships data/owlry.example.lua to /usr/share/doc/owlry/owlry.example.lua. pkgver kept at 2.0.1. README.md: - Config table puts owlry.lua first (preferred from 2.1), config.toml marked legacy/fallback with precedence note linking lua-api.md §2. - New "Quick Start (Lua config)" section with migrate-config blurb. - migrate-config row: [--force], deterministic. config validate row: exit 1 errors / exit 2 warnings. - Roadmap section flips Lua config from "lands in 2.1/3.0" to "shipped in 2.1"; lists 2.2 follow-ups (dynamic providers, owlry.bind, util.http_get). CLAUDE.md: - Project shape tree expands lua/ module with per-file descriptions. - Build section documents the `lua` cargo feature. - CLI shape line for migrate-config: [--force]. config validate: exit codes 1/2 mentioned. - New "Lua config layer (2.1+)" section covers precedence, the notify-based watcher, desktop-notification errors, and the Arc / LoadedConfig invariants. data/owlry.1: - --profile mentions both owlry.profiles (lua) and [profiles.] (toml). - config validate paragraph describes the categorised report and lists 0/1/2 exit codes. - migrate-config description no longer says "stub" — covers determinism, --force/-f, pre-v2 alias normalisation, links §9. - FILES adds ~/.config/owlry/owlry.lua and the example .lua; config.toml labelled legacy. ROADMAP.md: - "Lua-driven configuration" reworded as shipped in 2.1; example uses owlry.lua and the v2 API; 2.2 follow-ups listed. cli.rs help: migrate-config stub-era text → "TOML → owlry.lua (--force to overwrite)". lua/validate.rs: loosen pre_v2_aliases_are_known to assert only that aliases aren't flagged as unknown ids. is_clean() failed under --no-default-features --features lua because uuctl correctly triggered the compiled-out warning (uuctl → systemd, systemd feature off → silently dropped at runtime). Test matrix (all green): - --features full 352 lib tests - --no-default-features 182 lib tests - --no-default-features --features lua 305 lib tests Clippy silent in all three configurations. Smoke (release build, isolated XDG): 1. config validate on the shipped owlry.example.lua → OK exit 0 2. migrate-config: TOML → owlry.lua with the precedence notice 3. Daemon loads, watcher armed; appending owlry.provider triggers hot-reload within the debounce window 4. :phase310 prefix routes the empty query to the new provider 5. config validate against the live file still OK --- CLAUDE.md | 59 +++++++++++-- README.md | 35 ++++++-- ROADMAP.md | 20 +++-- aur/owlry/PKGBUILD | 1 + crates/owlry/src/cli.rs | 2 +- crates/owlry/src/lua/validate.rs | 16 +++- data/owlry.1 | 63 ++++++++++++-- data/owlry.example.lua | 144 +++++++++++++++++++++++++++++++ 8 files changed, 307 insertions(+), 33 deletions(-) create mode 100644 data/owlry.example.lua diff --git a/CLAUDE.md b/CLAUDE.md index 26cb6b2..614106f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -20,7 +20,17 @@ crates/owlry/ -- everything │ ├── backend.rs -- SearchBackend abstraction │ ├── app.rs -- GTK4 setup │ ├── ui/ -- GTK widgets -│ ├── config/ -- TOML config loader +│ ├── config/ -- TOML + Lua config loader; defines LoadedConfig +│ ├── lua/ -- Lua config layer (feature: lua) +│ │ ├── api.rs -- owlry.set / providers / tabs / provider / theme / profiles +│ │ ├── config.rs -- LuaConfig accumulator + merge_into(Config) +│ │ ├── error.rs -- LuaConfigError (thiserror) +│ │ ├── migrate.rs -- TOML → owlry.lua serializer (deterministic) +│ │ ├── provider.rs -- LuaProvider impl Provider +│ │ ├── runtime.rs -- LuaContext (Arc) + eval_file/snapshot +│ │ ├── util.rs -- owlry.util.{shell, read_file, glob, env, hostname, …} +│ │ ├── validate.rs -- ValidationReport with categorised findings +│ │ └── watcher.rs -- notify-based hot reload (desktop-notification errors) │ ├── data/ -- FrecencyStore │ ├── filter.rs -- ProviderFilter + prefix parser │ ├── ipc.rs -- Request/Response types @@ -47,27 +57,36 @@ There is no `crates/owlry-core`, `owlry-plugin-api`, `owlry-lua`, or `owlry-rune ## Build & development ```bash -# Default features (minimal — app, cmd, calc, conv, power, dmenu) +# Default features (minimal — app, cmd, calc, conv, power, dmenu, systemd) cargo build -# Full features (matches AUR build) +# Full features (matches AUR build) — includes lua + every optional provider cargo build --release --features full +# Lua-only opt-in on top of the default minimal set +cargo build --features lua + # Tests -cargo test --workspace --features full # 252+ tests -cargo test --workspace --no-default-features +cargo test --features full # 350+ tests including lua + watcher + migrate +cargo test --no-default-features # Verbose dev logging cargo run -- --features dev-logging -- -d # Format + lint cargo fmt --all -cargo clippy --workspace --features full +cargo clippy --features full +cargo clippy --no-default-features # must also stay silent # Install locally (sudo) just install-local ``` +The `lua` cargo feature pulls in `mlua` (vendored Lua 5.4), `glob` (for +`owlry.util.glob`), and `notify` (for hot reload). It's part of the `full` +set; minimal builds (`cargo install` without flags) compile without it +and the `migrate-config` / Lua-load paths gracefully fall back to TOML. + The daemon binary is `owlry`. There is no separate `owlryd` binary anywhere — the daemon is `owlry -d` (or `owlry daemon`). The systemd user unit is `owlry.service` (pre-2.0 name: `owlryd.service`). ## Running locally without disturbing prod @@ -94,13 +113,37 @@ owlry daemon run the daemon (alias: -d) owlry dmenu [-p ] dmenu mode (reads stdin, prints selection) owlry doctor config + socket + providers status owlry providers [] list providers (or show one) -owlry config validate parse config, report errors +owlry config validate parse config, report errors (1) and warnings (2) owlry config show print resolved effective config -owlry migrate-config TOML → init.lua (stub; lands with Lua config) +owlry migrate-config [--force] TOML → owlry.lua (functional from 2.1; --force to overwrite) ``` The `owlry plugin ...` subcommand tree from 1.x is **gone** in 2.0. Nothing to install, manage, or run via the CLI. +## Lua config layer (2.1+) + +`~/.config/owlry/owlry.lua` is the canonical config from 2.1 onwards. +`config.toml` remains supported but is ignored entirely when `owlry.lua` +exists (an info log at daemon start surfaces this). The daemon spawns a +`notify` watcher on the config dir; saves are debounced (200ms), +re-evaluated in a fresh `LuaContext`, and hot-swapped atomically. Eval +failures are kept off the live state and surfaced via both the journal +**and** a `notify-rust` desktop notification with the precise mlua +line/column. See [`docs/lua-api.md`](docs/lua-api.md) for the full API +surface (`owlry.set`, `owlry.providers`, `owlry.tabs`, `owlry.provider`, +`owlry.theme`, `owlry.profiles`, `owlry.util.*`). + +Implementation notes worth keeping straight: +- `LuaContext::lua: Arc` — `mlua::Function` references don't bump + the Lua refcount, so user providers hold their own `Arc` clone + via `LuaContext::lua_handle()` to outlive the context. +- `LoadedConfig` (in `config/mod.rs`) is the resolution result that + keeps the `LuaContext` alive past `Config::load`. The daemon uses + this; `Config::load` itself drops the context after merging scalars + (so it can't be used to wire user providers — only `LoadedConfig`). +- `owlry config validate` runs `lua::validate::validate` against the + snapshot and exits 0 / 1 / 2 per `docs/lua-api.md` §8. + ## Provider model Two traits in `src/providers/mod.rs`: diff --git a/README.md b/README.md index cf2664e..47a8d25 100644 --- a/README.md +++ b/README.md @@ -141,9 +141,9 @@ owlry -d run the daemon (alias: `owlry daemon`) owlry dmenu [-p ] dmenu mode (reads stdin, prints selection) owlry doctor diagnostics: config + socket + providers owlry providers [] list providers (or show details for one) -owlry config validate parse config, report errors +owlry config validate parse config, report errors (exit 1) and warnings (exit 2) owlry config show print the resolved effective config as TOML -owlry migrate-config TOML → init.lua (stub in 2.0; lands in a later 2.x release) +owlry migrate-config [--force] TOML → owlry.lua (deterministic; refuses to overwrite without --force) ``` ### Profiles @@ -229,15 +229,37 @@ Owlry follows the [XDG Base Directory Specification](https://specifications.free | Path | Purpose | |------|---------| -| `~/.config/owlry/config.toml` | Main configuration | +| `~/.config/owlry/owlry.lua` | Lua configuration (preferred, takes precedence over `config.toml`) | +| `~/.config/owlry/config.toml` | TOML configuration (legacy; ignored when `owlry.lua` exists) | | `~/.config/owlry/themes/*.css` | Custom themes | | `~/.config/owlry/style.css` | CSS overrides | | `~/.local/share/owlry/frecency.json` | Usage history | | `$XDG_RUNTIME_DIR/owlry/owlry.sock` | IPC socket (overridable via `$OWLRY_SOCKET`) | -| `/usr/share/doc/owlry/config.example.toml` | Example configuration | +| `/usr/share/doc/owlry/owlry.example.lua` | Example Lua configuration | +| `/usr/share/doc/owlry/config.example.toml` | Example TOML configuration | | `/usr/share/owlry/themes/` | Bundled themes | -### Quick Start +Config resolution order (per [`docs/lua-api.md`](docs/lua-api.md) §2): `owlry.lua` → `config.toml` → built-in defaults. When `owlry.lua` is present `config.toml` is ignored entirely (an info log notes this at daemon startup). The daemon watches `owlry.lua` and hot-reloads on save; broken edits surface as desktop notifications and keep the previous state alive. + +### Quick Start (Lua config — preferred from 2.1+) + +```bash +mkdir -p ~/.config/owlry +cp /usr/share/doc/owlry/owlry.example.lua ~/.config/owlry/owlry.lua +$EDITOR ~/.config/owlry/owlry.lua +owlry config validate +``` + +Already have a `config.toml`? Migrate it in one shot: + +```bash +owlry migrate-config # writes owlry.lua; refuses to overwrite +owlry migrate-config --force # overwrite an existing owlry.lua +``` + +The migrator is deterministic, emits only values that differ from defaults, and normalises pre-v2 aliases (`system` → `power`, `badge_sys` → `badge_power`). + +### Quick Start (TOML config — still supported in 2.x) ```bash mkdir -p ~/.config/owlry @@ -377,9 +399,10 @@ Set `OWLRY_SOCKET=/path/to/sock` to override the socket location — useful for See [ROADMAP.md](ROADMAP.md) for feature ideas and [docs/RESTRUCTURE-V2.md](docs/RESTRUCTURE-V2.md) for the v2 rewrite story. Headline upcoming work: -- **Lua-driven configuration** (2.1 / 3.0) — `~/.config/owlry/init.lua` replaces TOML. User-defined providers via `owlry.provider {}` in the same file (Hyprland-style configs-as-code). `owlry migrate-config` lands at the same time. +- **Lua-driven configuration shipped in 2.1** — `~/.config/owlry/owlry.lua` is the canonical config from 2.1, with TOML kept as a back-compat fallback until 3.0. User-defined providers via `owlry.provider {}`, host helpers under `owlry.util.*`, hot reload, named profiles, theme overrides, and `owlry migrate-config` are all live. See [`docs/lua-api.md`](docs/lua-api.md) for the full surface. - **Widget providers return** — weather, MPRIS media controls, pomodoro timer. Deferred from 2.0 while the UI positioning is reworked. - **Bookmarks return** — Firefox + Chromium. Deferred from 2.0 to avoid a hard rusqlite/`libsqlite3-sys` dep in the chroot build path; returns with a pure-Rust reader (likely via Firefox's JSON backup files). +- **Dynamic Lua providers** (2.2) — `owlry.provider { dynamic = true }` for per-keystroke items. 2.1 ships only static (`dynamic = false`) providers. ## License diff --git a/ROADMAP.md b/ROADMAP.md index 2597dbb..9ba8dd7 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,14 +4,20 @@ Feature ideas and future development plans. For the v2 rewrite story (where 14 p ## Locked-in for an upcoming 2.x release -### Lua-driven configuration (Phase 3) -Replace `config.toml` with `~/.config/owlry/init.lua`. The config is real Lua, evaluated at startup via embedded `mlua` (Lua 5.4). User-defined providers, keybindings, and theme overrides all live in the same file — Hyprland-style configs-as-code. Ships with `owlry migrate-config` (TOML → init.lua) and hot-reload on save. +### Lua-driven configuration — **shipped in 2.1** +`~/.config/owlry/owlry.lua` is the canonical config from 2.1 onwards (TOML stays supported as a back-compat fallback until 3.0). Real Lua 5.4 via vendored `mlua`. The full surface is documented in [`docs/lua-api.md`](docs/lua-api.md): + +- `owlry.set` / `owlry.providers` / `owlry.tabs` / `owlry.theme` / `owlry.profiles` for declarative config +- `owlry.provider {}` for user-defined providers (Hyprland-style configs-as-code) +- `owlry.util.{shell, shell_lines, read_file, glob, env, hostname}` host helpers inside provider callbacks +- Hot reload on save via the `notify` crate — broken edits surface as desktop notifications and keep the previous state live +- `owlry migrate-config [--force]` — deterministic TOML → Lua migration +- `owlry config validate` — categorised report (errors exit 1, warnings exit 2) ```lua -local owlry = require("owlry") - -owlry.set { theme = "owl", width = 850, tabs = { "app", "cmd", "uuctl" } } -owlry.providers { "app", "cmd", "power", "bookmarks", "systemd" } +owlry.set { theme = "owl", width = 850 } +owlry.providers { "app", "cmd", "power", "systemd" } +owlry.tabs { "app", "cmd", "uuctl" } owlry.provider { id = "hs", prefix = ":hs", tab_label = "Shutdown", @@ -19,6 +25,8 @@ owlry.provider { } ``` +**2.2 follow-ups:** dynamic (per-keystroke) Lua providers via `dynamic = true`; `owlry.bind` for runtime keybindings; `owlry.util.http_get`. + ### Widget providers return Weather, MPRIS media controls, and pomodoro timer were deferred from 2.0 while the widget-row UI is redesigned. They'll come back as a feature group once the placement model is settled. ([D20 in the v2 plan](docs/RESTRUCTURE-V2.md).) diff --git a/aur/owlry/PKGBUILD b/aur/owlry/PKGBUILD index ecb727a..f038858 100644 --- a/aur/owlry/PKGBUILD +++ b/aur/owlry/PKGBUILD @@ -111,6 +111,7 @@ package() { # Documentation + example configuration. install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md" + install -Dm644 data/owlry.example.lua "$pkgdir/usr/share/doc/$pkgname/owlry.example.lua" install -Dm644 data/config.example.toml "$pkgdir/usr/share/doc/$pkgname/config.example.toml" install -Dm644 data/style.example.css "$pkgdir/usr/share/doc/$pkgname/style.example.css" diff --git a/crates/owlry/src/cli.rs b/crates/owlry/src/cli.rs index 8247538..d22fda0 100644 --- a/crates/owlry/src/cli.rs +++ b/crates/owlry/src/cli.rs @@ -24,7 +24,7 @@ EXAMPLES: owlry providers [] List providers (or show one) owlry config validate Check config for errors owlry config show Print resolved effective config - owlry migrate-config TOML → init.lua (Phase 3+; stub for now) + owlry migrate-config [--force] TOML → owlry.lua (--force to overwrite) SEARCH PREFIXES (inside the UI): :app firefox Search applications diff --git a/crates/owlry/src/lua/validate.rs b/crates/owlry/src/lua/validate.rs index 4e27980..8eb9722 100644 --- a/crates/owlry/src/lua/validate.rs +++ b/crates/owlry/src/lua/validate.rs @@ -331,13 +331,23 @@ mod tests { #[test] fn pre_v2_aliases_are_known() { + // `sys` and `uuctl` resolve to power and systemd respectively. + // We only assert they're NOT reported as unknown ids — a + // compiled-out warning is environment-dependent (running this + // with `--no-default-features --features lua` omits the systemd + // feature, which legitimately flags uuctl as compiled-out). let mut cfg = empty_cfg(); cfg.providers = Some(vec!["sys".into(), "uuctl".into()]); cfg.tabs = Some(vec!["sys".into(), "uuctl".into()]); let report = validate(&cfg); - assert!( - report.is_clean(), - "pre-v2 aliases must validate cleanly; got: {:?}", + let unknown_count = report + .warnings + .iter() + .filter(|w| w.contains("unknown id")) + .count(); + assert_eq!( + unknown_count, 0, + "pre-v2 aliases must not be flagged as unknown ids; got: {:?}", report.warnings ); } diff --git a/data/owlry.1 b/data/owlry.1 index a1a914c..336d399 100644 --- a/data/owlry.1 +++ b/data/owlry.1 @@ -32,6 +32,10 @@ Optional modes (depend on cargo features at build time): .TP .BI \-\-profile " NAME" Launch the UI with a named profile. Profiles are defined under +.B owlry.profiles +in +.IR ~/.config/owlry/owlry.lua +or .B [profiles.] in .IR ~/.config/owlry/config.toml . @@ -64,18 +68,45 @@ List all registered providers, or print details (icon, prefix, position, tab label, search noun) for one. Requires a running daemon. .TP .B "config validate" -Parse the config file and report errors. Exits 0 on success, 1 on parse failure. +Parse the config file and report errors and warnings. When +.I ~/.config/owlry/owlry.lua +exists it is evaluated and the snapshot is checked for unknown keys, +unknown provider ids, tabs not in +.BR owlry.providers , +duplicate +.B owlry.provider +ids, and providers compiled out of the running build. Exit codes: +.B 0 +clean, +.B 1 +on errors (syntax / eval / TOML parse failure), +.B 2 +on warnings only. .TP .B "config show" Print the resolved effective configuration (defaults merged with the user file) as TOML. .TP -.B migrate-config -Migrate TOML configuration to a future -.B init.lua -format. Stub in 2.0; functional once the Lua config layer lands in a later 2.x -release. See -.IR docs/RESTRUCTURE-V2.md . +.BR "migrate-config " [\fB\-\-force\fR] +Migrate +.I ~/.config/owlry/config.toml +to +.I ~/.config/owlry/owlry.lua +with equivalent settings. Output is deterministic and minimal — only values +differing from the built-in defaults are emitted. Pre-v2 aliases +.RB ( system " \(-> " power , +.B badge_sys +\(-> +.BR badge_power ) +are normalised to v2 names. The migrator refuses to overwrite an existing +.B owlry.lua +unless +.B \-\-force +(or +.BR \-f ) +is passed. See +.IR docs/lua-api.md +\(sc9 for the full mapping. .SH ENVIRONMENT .TP .B XDG_RUNTIME_DIR @@ -102,8 +133,19 @@ Auto-detected terminal for items marked as needing a terminal. Overridden by in the config. .SH FILES .TP +.I ~/.config/owlry/owlry.lua +Lua configuration (preferred from 2.1). Takes precedence over +.B config.toml +when both exist; an info log notes this at daemon start. The daemon +hot-reloads on save; broken edits surface as desktop notifications and +keep the previous state alive. See +.IR docs/lua-api.md +for the API. +.TP .I ~/.config/owlry/config.toml -Main configuration. See +TOML configuration (legacy; ignored when +.B owlry.lua +exists). See .B owlry config show for the effective state. .TP @@ -122,8 +164,11 @@ IPC Unix socket. See .B OWLRY_SOCKET to override. .TP +.I /usr/share/doc/owlry/owlry.example.lua +Annotated example Lua configuration. +.TP .I /usr/share/doc/owlry/config.example.toml -Annotated example configuration. +Annotated example TOML configuration. .TP .I /usr/share/owlry/themes/ Bundled themes. diff --git a/data/owlry.example.lua b/data/owlry.example.lua new file mode 100644 index 0000000..fb304cf --- /dev/null +++ b/data/owlry.example.lua @@ -0,0 +1,144 @@ +-- ~/.config/owlry/owlry.lua — example configuration. +-- +-- Drop this file in place to switch from config.toml to the Lua config +-- layer. owlry.lua takes precedence over config.toml when both exist +-- (info-logged at daemon start). The daemon watches this file and +-- hot-reloads on save; broken edits surface as desktop notifications +-- and keep the previous state alive. +-- +-- Spec: https://somegit.dev/Owlibou/owlry/src/branch/main/docs/lua-api.md + +-- ────────────────────────────────────────────────────────────────────── +-- 1. Global settings. +-- Every key here is OPTIONAL — defaults apply for anything you omit. +-- ────────────────────────────────────────────────────────────────────── +owlry.set { + theme = "owl", -- bundled themes: owl, catppuccin-mocha, + -- nord, rose-pine, dracula, gruvbox-dark, + -- tokyo-night, solarized-dark, one-dark, + -- apex-neon. Plus any *.css under + -- ~/.config/owlry/themes/. + width = 850, + height = 650, + font_size = 14, + border_radius = 12, + -- terminal = "kitty", -- omit to auto-detect ($TERMINAL → xdg- + -- terminal-exec → DE-native → fallback). + use_uwsm = false, -- launch desktop entries via `uwsm app --` + -- for proper systemd session integration. + show_icons = true, + max_results = 100, + frecency = true, -- boost recently / frequently launched items + frecency_weight = 0.3, -- 0.0 = off, 1.0 = strong + search_engine = "duckduckgo", -- google | duckduckgo | bing | + -- startpage | searxng | brave | + -- ecosia, or a custom "{query}" URL. +} + +-- ────────────────────────────────────────────────────────────────────── +-- 2. Enabled providers. +-- Omit this call to enable every built-in provider (the default). +-- Listing a subset disables anything not mentioned. Pre-v2 aliases +-- (sys / system → power; uuctl → systemd) still work. +-- ────────────────────────────────────────────────────────────────────── +owlry.providers { + "app", "cmd", -- core launchers + "calc", "conv", -- = / > triggers + "power", -- shutdown / reboot / lock + "systemd", -- user units (:uuctl) + "ssh", "websearch", "filesearch", -- search-style providers + "emoji", "clipboard", -- pickers +} + +-- ────────────────────────────────────────────────────────────────────── +-- 3. Tab bar order (subset of providers). +-- Omit to give every enabled provider a tab. Order is preserved; +-- Ctrl+1 jumps to the first entry, Ctrl+2 the second, and so on. +-- ────────────────────────────────────────────────────────────────────── +owlry.tabs { "app", "cmd", "uuctl" } + +-- ────────────────────────────────────────────────────────────────────── +-- 4. Theme overrides. +-- owlry.theme("name") picks a bundled / user theme. +-- owlry.theme {} layers individual colour overrides on top. +-- Both forms compose — call as many times as you like. +-- ────────────────────────────────────────────────────────────────────── +-- owlry.theme { +-- background = "#1e1e2e", +-- background_secondary = "#313244", +-- border = "#45475a", +-- text = "#cdd6f4", +-- text_secondary = "#a6adc8", +-- accent = "#cba6f7", +-- accent_bright = "#f5c2e7", +-- -- Per-provider badges (each is optional): +-- badge_app = "#a6e3a1", +-- badge_cmd = "#fab387", +-- badge_power = "#f38ba8", +-- badge_uuctl = "#9ece6a", +-- } + +-- ────────────────────────────────────────────────────────────────────── +-- 5. Named profiles, selected by `owlry --profile `. +-- Each profile overrides the default enabled-provider set for that +-- launch but inherits owlry.set / owlry.theme / owlry.tabs. +-- ────────────────────────────────────────────────────────────────────── +-- owlry.profiles { +-- dev = { "app", "cmd", "ssh" }, +-- media = { "emoji", "clipboard" }, +-- minimal = { "app" }, +-- } + +-- ────────────────────────────────────────────────────────────────────── +-- 6. User-defined providers. +-- Register your own search source. Every field except `id` and +-- `items` is optional. `items` is called once at startup and the +-- results cached (dynamic per-keystroke providers land in 2.2). +-- ────────────────────────────────────────────────────────────────────── +-- owlry.provider { +-- id = "hs", +-- prefix = ":hs", +-- tab_label = "Shutdown", +-- icon = "system-shutdown", +-- search_noun = "shutdown actions", +-- items = function() +-- return { +-- { name = "Lock", command = "hyprlock" }, +-- { name = "Shutdown", command = "systemctl poweroff" }, +-- { name = "Reboot", command = "systemctl reboot" }, +-- } +-- end, +-- } + +-- ────────────────────────────────────────────────────────────────────── +-- 7. Host helpers (use inside provider `items` callbacks). +-- Available under owlry.util.*: +-- shell(cmd) -> string (stdout, trimmed) +-- shell_lines(cmd) -> {string} +-- read_file(path) -> string | nil +-- glob(pattern) -> {string} (~ expansion supported) +-- env(name, default?) -> string | nil +-- hostname() -> string +-- ────────────────────────────────────────────────────────────────────── +-- owlry.provider { +-- id = "docker-ps", +-- prefix = ":docker", +-- items = function() +-- local lines = owlry.util.shell_lines( +-- "docker ps --format '{{.Names}}\t{{.Image}}'" +-- ) +-- local items = {} +-- for _, line in ipairs(lines) do +-- local name, image = line:match("([^\t]+)\t(.+)") +-- if name then +-- items[#items + 1] = { +-- name = name, +-- description = image, +-- command = "docker exec -it " .. name .. " bash", +-- terminal = true, +-- } +-- end +-- end +-- return items +-- end, +-- }