Script plugins can now declare tab_label and search_noun in their
plugin.toml [[providers]] section. These flow through the Provider
trait, IPC ProviderDesc, and into the UI via provider_meta::resolve().
Unknown plugins auto-generate labels from type_id instead of showing
a generic "Plugin" label.
Tests using execute_action() triggered Config::save() with a default
Config, silently overwriting ~/.config/owlry/config.toml on every
`cargo test` run. Guard the save call with #[cfg(not(test))].
Wrap LoadedRuntime._library in ManuallyDrop so dlclose() is never called.
dlclose() unmaps the library code; thread-local destructors inside liblua.so
then SIGSEGV when they try to run against the unmapped addresses.
Also filter out non-.lua plugins in the Lua runtime's discover_plugins()
so liblua.so does not attempt to load Rune plugins.
- owlry-core/manifest: add entry_point alias for entry field, add ProviderSpec
struct for [[providers]] array, change default entry to main.lua
- owlry-lua/manifest: add ProviderDecl struct and providers: Vec<ProviderDecl>
for [[providers]] support
- owlry-lua/loader: fall back to manifest [[providers]] when script has no API
registrations; fall back to global refresh() for manifest-declared providers
- owlry-lua/api: expose call_global_refresh() that calls the top-level Lua
refresh() function directly
- owlry/plugin_commands: update create templates to emit new format:
entry_point instead of entry, [[providers]] instead of [provides],
main.rn/main.lua instead of init.rn/init.lua, Rune uses Item::new() builder
pattern, Lua uses standalone refresh() function
- cmd_validate: accept [[providers]] declarations as a valid provides source
- Config::save() now merges into existing file via toml_edit to preserve
user comments and unknown keys instead of overwriting
- Remove 16 dead ProvidersConfig plugin-toggle fields (uuctl, ssh, clipboard,
bookmarks, emoji, scripts, files, media, weather_*, pomodoro_*) that became
unreachable after accept_all=true was introduced
- Wire general.tabs to ProviderFilter::new() to drive UI tab display
- Fix set_single_mode() and toggle() not clearing accept_all, making tab
filtering a no-op in default launch mode
- Add restore_all_mode() for cycle-back-to-All path in tab cycling
- Reduce PROVIDER_TOGGLES to built-in providers only
reqwest 0.13 defaults to rustls -> aws-lc-rs which requires cmake/nasm
in minimal build environments (AUR chroot). Switch all direct reqwest
users to native-tls (system OpenSSL) to fix clean chroot build failures
reported by users.
Affected crates: owlry-core, owlry-lua, owlry-rune
PKGBUILD: add openssl to depends for all three runtime packages
Also add scripts/aur-local-test for clean chroot testing workflow
Merge four separate prefix arrays (core full, plugin full, core
partial, plugin partial) into two arrays with a single loop each
that checks both full and partial match. Halves the data and
eliminates the duplicate iteration.
Replace while-contains-replace loop with a single-pass char
iterator. Eliminates O(n²) behavior and repeated allocations
on pathological desktop file Exec values.
record_launch no longer calls save() synchronously. The dirty flag
is set and the Drop impl flushes on shutdown. Removes a JSON
serialize + fs::write from the hot launch path.
Refactor search_with_frecency to score static provider items by
reference (&LaunchItem, i64) instead of cloning every match.
Use select_nth_unstable_by for O(n) partial sort, then clone
only the max_results survivors. Reduces clones from O(total_matches)
to O(max_results) — typically from hundreds to ~15.
Replace RwLock<Vec<LaunchItem>> with plain Vec. The inner RwLock
was unnecessary — refresh() takes &mut self (exclusive access
guaranteed by the outer Arc<RwLock<ProviderManager>>). The unsafe
block in items() dropped the RwLockReadGuard while returning a
slice backed by the raw pointer, creating a dangling reference.
:config and :conv were not in the prefix lists, so typing them
showed 'Plugin' mode but didn't route to the config/converter
providers. Also added :settings, :converter aliases.
Register ConfigProvider as built-in dynamic provider. Extend
execute_plugin_action to dispatch CONFIG:* commands via the
DynamicProvider::execute_action trait method.
Calculator and converter registered as built-in dynamic providers.
System registered as built-in static provider. All gated by config
toggles (calculator, converter, system — default true).
Foundation for built-in calculator, converter, and system providers.
DynamicProvider trait for per-keystroke providers. ProviderManager
iterates builtin_dynamic alongside native dynamic plugins in search.
Calculator and converter results now get a 10k grouping bonus so all
their results stay together above websearch/filesearch. Previously
websearch (priority 9000) would interleave with converter results
(9000, 8999, 8998...) since they had the same base priority.
Highlighting:
- Dynamic plugin results (calculator, converter, websearch, filesearch)
get a subtle accent left-border + background tint when auto-detected
- Exact name matches (case-insensitive) are highlighted the same way
- Exact match on apps gets a higher score boost (50k) than other
providers (30k), so apps rank first when names match exactly
Shadow:
- Removed hardcoded box-shadow from all theme CSS files
- Added --owlry-shadow variable in base.css (defaults to none)
- Themes can opt into shadow via --owlry-shadow if desired
CSS class: .owlry-result-highlight on ResultRow
get_score() called Utc::now() inside calculate_frecency() for every
item in the search loop. Added get_score_at() that accepts a pre-sampled
timestamp. Eliminates hundreds of unnecessary clock_gettime syscalls
per keystroke.
detect_terminal() was spawning up to 17 'which' subprocesses sequentially
on every startup. Replace with std::env::split_paths + is_file() check.
Eliminates 200-500ms of fork+exec overhead on cold cache.
Watch ~/.config/owlry/plugins/ for changes using notify-debouncer-mini
(500ms debounce) and trigger a full runtime reload on file modifications.
Respects OWLRY_SKIP_RUNTIMES=1 to skip watcher in tests.
- Shrink Lua RuntimeInfo from 5 fields to 2 (name, version), matching
core and Rune. The mismatch caused SIGSEGV across the ABI boundary.
- Add owlry_version parameter to vtable init in all three crates
(core, Lua, Rune) so runtimes receive the version at init time
instead of hardcoding it.
- Remove unused Lua constants (RUNTIME_ID, RUNTIME_NAME, etc.) and
LUA_RUNTIME_API_VERSION.
- Update plugin_commands.rs call sites to pass CARGO_PKG_VERSION.