Skip to content

Releases

WayRun v0.12.0

Choose a tag to compare

@github-actions github-actions released this 12 Nov 04:31
v0.12.0
4a47aa0

Added

  • theme.toml's [motion].entrance_ms sets how long the launcher's entrance
    fade and rise take, in milliseconds (0–2000, default 240). 0 skips the
    entrance while the card height spring and result-row motion still run;
    reduced = true still disables all motion. It applies live.
  • theme.toml's [layout].fixed_height (default false) holds the card at
    the height of max_rows rows once there is a query or results, so results,
    split previews and the action panel no longer resize it. A pristine show
    (no query, no results) stays the compact search-only card. It applies live.
  • Lua plugins can read the session's desktop id with wayrun.desktop()
    (kde, niri, hyprland, …), resolved once at startup.
  • The session action ({"type":"session","verb":"reboot"}) lets a row ask
    for lock, suspend, reboot, shutdown or logout without embedding a
    desktop-specific command; the executor resolves it for the session.
  • A run_in_terminal action takes keep_open
    ({"type":"run_in_terminal","cmd":"pacman -S x","keep_open":true}): once the
    command exits, the terminal continues in an interactive $SHELL instead of
    closing, so a plugin's install or build output stays readable. The plugin
    that emits the action decides; rows without the field behave as before, and
    the field is additive, so PLUGIN_API stays at 1.
  • wayrun.apps() lists the installed applications as { id, name, icon, exec }, with the name in the interface language and the icon resolved to an
    absolute path exactly as an app-search row shows them, so a plugin does not
    parse .desktop files to label a process. The binding is additive: a script
    can test for it, and PLUGIN_API stays at 1.
  • wayrun.fs.readlink(path) returns a symbolic link's target, or nil when the
    path is absent or not a link. The link itself must lie in the plugin's
    readable places while its target may point anywhere, so a plugin can read
    /proc/<pid>/exe to tell apart processes that share a name. The binding is
    additive: a script can test for it, and PLUGIN_API stays at 1.

Changed

  • The action panel no longer draws a header band: the actions start where the
    first result row would, and the parent row or group title moves to the right
    of the footer, beside the action count. [layout].panel_header is gone; an
    existing entry is ignored. A panel now matches a list with the same number
    of rows in height.
  • The text family moved from config.toml's [font].family to
    theme.toml's [font].family, next to the interface size it belongs with.
    It still applies live. A [font] table left in config.toml is ignored, so
    move the key to theme.toml.
  • On KDE Plasma, reboot, shutdown and logout ask org.kde.Shutdown to
    end the session first and fall back to systemctl/loginctl, so systemd no
    longer stops plasmashell itself and waits out its timeout.
  • wayrun status reports the detected desktop, the daemon pid, the socket path
    and the version after the visible/hidden line.
  • The built-in system command rows describe the action instead of showing the
    shell command they run.

Removed

  • Breaking: wayrun open and wayrun close are gone; wayrun toggle
    covers both, and the socket accepts only toggle and status. Update
    scripts that used them.

Fixed

  • The footer no longer paints hints or the no-match note over the search field
    while the card is still compact. "No results" waits for the search to land
    and uses the count pill's chip style instead of the accent colour.

WayRun v0.11.0

Choose a tag to compare

@github-actions github-actions released this 07 Nov 15:34
v0.11.0
2297986

Added

  • A text preview can render Markdown. Add format = "markdown" to a text
    preview to lay out headings, emphasis, inline code, code blocks, lists,
    quotes, rules and link text in the preview column; plain remains the
    default and the wire field is additive, so PLUGIN_API stays at 1.
    Over-long plain and CJK tokens split on character boundaries instead of
    being elided.
  • wayrun.date(seconds?) answers the UTC civil fields (year, month, day,
    hour, minute and second) for a Unix timestamp, defaulting to now. The
    binding is additive: a script can test for it, and PLUGIN_API stays at 1.
  • The LuaLS stub types the row, action, preview and plugin tables, and the
    two new exec flags, so a misspelled row field is caught at edit time.

Changed

  • The installation guide and both READMEs now lead with the prebuilt x86_64
    tarball (built on Ubuntu 24.04); building from source remains the path for
    other architectures and older distributions.
  • The guides are also published as a VitePress site at
    https://prslc.github.io/WayRun/, in English and Chinese, with the same
    pages kept in the repository.
  • The guides gain a plugin directory listing the worked Lua and Python
    examples from the WayRun-Plugins workspace, with what each needs and how
    to register one.

Fixed

  • A keyword-less external host gets 250ms in the default chain instead of
    50ms. A cold host such as the KDE settings plugin, which runs
    kcmshell6 --list, took about 140ms and was silently dropped, so a query
    such as 输入法 returned nothing.
  • The blur region is committed only after the card fades in, so the first
    entrance frame no longer shows the smeared wallpaper across the card's
    rect before the card covers it.
  • wayrun.exec reports stdout_truncated and stderr_truncated when a
    stream exceeds its cap (1 MiB stdout, 8 KiB stderr); a stream that exactly
    fills its cap stays false.

WayRun v0.10.0

Choose a tag to compare

@github-actions github-actions released this 04 Nov 15:45
v0.10.0
5059171

Added

  • A KDE session follows its colour scheme. The accent is [General] AccentColor, else the scheme's DecorationFocus; the mode is the window
    background's luminance; and ~/.config/kdeglobals is watched like the DMS
    palette. A leftover dms-colors.json no longer decides the mode.
  • An action entry can be a group: file and directory rows gather their content
    type's handlers under one Open with entry instead of flattening them into
    the row's own commands. Enter descends, Esc backs out one level and
    Shift+Enter closes the panel from any level. The remembered default and a
    resumed command follow the tree, and a group carries a trailing chevron.

Changed

  • Breaking: the built-in w open-window search and the
    compositor-niri / compositor-hyprland build features are gone; one
    binary runs on every supported compositor. A user who wants window search
    needs a plugin that provides it.

Fixed

  • A desktop action runs once. g_desktop_app_info_launch_action returns
    void, and reading its return register as a success flag made launch()
    run the hand-expanded Exec= after GLib had already started the action.
  • KWin: the launcher uses Layer::Top and the utility namespace, so it no
    longer covers the input-method candidate window and KWin does not animate
    the dimmed backdrop as a normal window on open.
  • A settled repaint no longer accumulates the hairline: the antialiased rim
    falls outside the card rect, and the restore and damage now carry a
    one-logical-pixel pad.
  • The blur region follows the card's rounded corner instead of a rectangle
    that left a staircase on it.

WayRun v0.9.0

Choose a tag to compare

@github-actions github-actions released this 26 Oct 18:27
v0.9.0
a2d93eb

Added

  • A keyword-routed host streams its results. With "stream": true in the
    request, a Lua host receives an emit callback as search's second
    argument and each emit replaces the rows on screen; a forked or resident
    host writes the same partial lines. The core forwards them as
    results_partial notifications, the shell keeps the search pending until
    the final results, and a superseded search drops its queued partials.
  • A result's icon and an image preview's path may be an https:// URL. The
    core fetches it into a bounded background cache — four workers, superseded
    when a new search starts — rewrites it to a local path and sends
    image_ready when it lands, so the row or preview reloads without a new
    payload. icon_shape: "circle" clips a row's icon.
  • The selected row can carry a split-view preview: an image or plain UTF-8
    text in one fixed column of 46% of the content width, so the column does not
    move when the row changes kind. A short list reserves a square for an image
    or a readable minimum for text, and host text is capped at 64 KiB.
    [preview] enabled = false turns the column off.
  • File and directory rows list the system's handlers for their content type,
    after the built-in terminal, reveal and copy actions. open_with launches
    one through GIO with the launcher's language context, and the list is cached
    per content type over the .desktop and mimeapps.list roots.
  • wayrun plugin add|enable|disable|set-keyword|remove|list|check and
    wayrun config get|list|set|unset edit the user's plugins.toml and
    config.toml through toml_edit, keeping the template's comments,
    re-parsing the typed model and writing atomically; a running launcher
    reloads the file through its watcher. plugin add loads the script first
    and refuses a configured id or a keyword another entry owns, and
    plugin check reports a script's shebang, exec bit, manifest, API version
    and registration.
  • plugin{plugin,action,payload} hands a row's command back to its host:
    command routes it to the named plugin's command method, inside the
    plugin's sandbox, and runs it as a pending command so a dismissal cannot cut
    it.
  • Lua plugins declare the PATH programs they may run, and
    wayrun.exec(program, args?) runs one with argv, no shell, in $HOME and
    under a 1.5 s deadline. The sandbox keeps its env whitelist. A plugin also
    gains a writable cache directory, fs.write/fs.delete, wayrun.import
    for modules loaded in the same _ENV, wayrun.file_uri, wayrun.locale,
    wayrun.http.get_many, and wayrun.http.cached, which answers from the
    store with stale = true when expired. print and wayrun.log write to
    the journal, with a per-call budget.
  • A Lua host reloads when its script or a module it imported changes, and a
    failed reload keeps the last good VM serving.
  • theme.toml can pin any derived surface: [surfaces] takes color and/or
    alpha (and the hairline's width), [surfaces.dark]/[surfaces.light]
    layer per mode, and an omitted field keeps deriving from the palette.
    [footer] enabled = false drops the hint bar and gives its band back to the
    card.
  • The list reports its wait: after 150 ms the footer says Searching… and
    suppresses the no-results note, and a host's search error becomes one
    display-only row with the first line of the message.
  • A LuaLS stub ships for editor completion.

Changed

  • Breaking: the clipboard history is no longer built in. The c keyword,
    its provider, strings and glyph are gone; install examples/lua/cliphist.lua
    from the WayRun-Plugins workspace and register it with keyword = "c" and
    resident = true. The Lua exec stdout cap is now 1 MiB so a full
    cliphist list fits. wl-clipboard stays for copy and paste.
  • Breaking: the command line is clap's. A bare wayrun on a terminal
    prints the command list, and wayrun run starts the launcher; a spawn
    without a terminal still runs it. --list-plugins is gone, wayrun-core
    always serves the protocol, --help and --version work, and a second
    instance says the launcher is already running and points at
    wayrun toggle.
  • Breaking: a Lua plugin's relative filesystem names resolve under its own
    directory, absolute and ~ reads stay inside a declared area, fs.write
    lands in the plugin directory, and kv.db and its siblings are reserved.
  • A built-in file row no longer previews an image; the split column is a
    plugin capability now, and [preview] enabled governs plugin previews.
  • The card animates: results extend it through a critically damped height
    spring (growth ~150 ms, shrink ~240 ms), a reordered row slides from where
    it is drawn, and a list appearing from nothing fades in with a 4 px rise.
    The entrance eases its opacity out while the card rises 8 px, and the
    default card sits at 0.20 of the output height.
  • The UI is its own wayrun-ui crate, holding the drawing and the
    presentation it derives from, and the large modules are split by concern.
  • The render buffer and its shm pool stay for the process's life, so every
    show after the first commits a warm frame; the allocator is trimmed on
    dismissal and the shaped-line cache is capped at 32 entries.
  • A search and its dispatch share one lifetime: a newer query aborts the stale
    dispatch, so a forked host dies with its future, and a resident host whose
    caller was dropped is replaced instead of leaving the next call to wait out
    its deadline.
  • Remote images are fetched concurrently and pruned by the newest search; a
    preview PNG streams row by row and a JPEG decodes at the smallest DCT scale
    that covers the pane, so a 4K wallpaper no longer builds the full buffers.
  • The dark card is more opaque and its hairline is white 0.12; the light
    card's hairline is black 0.10.

Fixed

  • Enter no longer launches the row still on screen while a search is pending:
    the press is held until the final payload lands, and an edit, the action
    panel or a dismissal drops it.
  • A list refresh faded every row in on each keystroke; only a list appearing
    from nothing animates now.
  • A keystroke inside the 150 ms loading delay no longer restarts it, so the
    footer does not keep deferring its first show.
  • A plugin action that runs the row's command stands in for the synthesized
    Open entry, so the plugin's title and icon lead the panel.
  • The Lua HTTP cache is keyed by the request headers, so an authenticated or
    language-specific reply never answers another request, and query parameters
    are sorted so one parameter set builds one URL.
  • An SVG preview reads the SVG's intrinsic size, and an image preview is
    fitted to its aspect and averaged on a downscale.
  • The builtin icons are packaged from ui/assets/icons, so a release build
    keeps its glyphs.
  • plugin list pads by display width (a CJK name takes the columns its glyphs
    take), clips an overflowing cell, and says enabled or disabled.
  • A host's identity is re-resolved on a chmod as well as an edit, and a spawn
    failure other than "not found" is named on stderr.
  • An exec child starts in $HOME under a 1.5 s deadline, and a run action's
    stderr stays on the journal.
  • The resident unit's template no longer sets PATH= (it replaces the user
    manager's environment; use environment.d), and the open-with docs name a
    content type's handlers correctly.

WayRun v0.8.0

Choose a tag to compare

@github-actions github-actions released this 18 Oct 06:04
v0.8.0
8b82a13

Added

  • The resident core's disk-backed caches have a lifecycle. Source/Live
    watches the roots behind the app list, the $PATH scan, the icon chain and
    the window icons, bumps an epoch when one changes, and rebuilds on the next
    query; a synchronous consumer still reads the last snapshot without touching
    the filesystem. An installed application, a new $PATH executable, a theme
    install or a [icon] theme edit no longer waits for a restart. Access events
    are ignored and a rebuild never runs inside the notify callback.
  • An external host's identity is re-resolved when its executable's
    (mtime, size) stamp moves, and the configured executables are watched, so
    editing a script updates its name, icon and ready hint live. Results were
    already fresh: the host forks per call.
  • c and w list their content — the clipboard history and the open
    windows — instead of the identity card. A default view revalidates its burst
    cache before answering, because the shell redraws only on the next query
    change and a stale-while-revalidate answer would leave the first show one
    fetch behind.
  • A path query needs no keyword: ~/Project, /etc/hosts or
    Project/WayRun is one row for the existing path, and otherwise the typed
    directory's entries matching the last component are listed. Only the typed
    directory is read, the listing is capped, and an exact hit leads. f/d
    keep their file/directory filter.
  • A plain query no provider answers lists the first $HOME level, one
    readdir, so a partial name still finds the directory it starts with
    without walking the home.
  • Tab completes the last /- or space-separated component from the visible
    rows: it grows to the candidates' common prefix, else takes the selected
    row, replacing only that component. It is off during IME preedit and while
    the action panel is open.
  • A desktop entry's actions launch through GLib's
    g_desktop_app_info_launch_action, so DBusActivatable (an action with no
    Exec at all), Path=, Terminal= and the field codes are GLib's; the
    hand-expanded Exec remains the fallback. Nested ids (foo/bar.desktop)
    resolve.
  • Terminal actions prefer $TERMINAL, then xdg-terminal-exec, then the
    built-in emulator table, and the action's directory becomes the helper's
    working directory.
  • theme.toml's [layout].panel_header sets the action panel's header band
    height, 28 by default.

Changed

  • Breaking: config.toml, plugins.toml, theme.toml and the Lua plugin
    directory now live under $XDG_CONFIG_HOME/wayrun, and state.db under
    $XDG_STATE_HOME/wayrun (migrated automatically from the old location). A
    user who sets XDG_CONFIG_HOME must move the three files and the plugin
    directory there. The cache follows dirs::cache_dir, and the socket and its
    lock require an absolute $XDG_RUNTIME_DIR; a missing value is an error, not
    a shared /tmp fallback.
  • The default [font] family is the generic sans-serif, resolved by
    cosmic-text per machine, instead of a named family.
  • The README carries measured warm and cold query latencies, with the full
    per-provider table and the method folded into a details block.
  • Local release builds use thin LTO and the default codegen units; the
    shipped binary keeps fat LTO and one codegen unit, set by the CI and release
    workflows.
  • The large modules are split by concern — the surface, plugin registry, file
    provider, icon cache, executor's terminal handling, theme config and Lua
    host — with no behaviour change.

Fixed

  • The POSIX and freedesktop audit batch: a detached sh or gio no longer
    inherits the JSON-RPC pipe, a helper is bounded by a 2 s deadline, a host
    command resolves like execvp, XDG config dirs and relative data dirs are
    honored, flatpak user exports and flat pixmaps resolve, ShowItems gets its
    URI list first, an action honors Exec/Path/Terminal, and the cache,
    state, config and kv directories are created 0700.
  • Launched children get SIGPIPE back to its default; an ignored disposition
    survives exec and Rust ignores it.
  • The remaining desktop and process edge cases: nested ids resolve, an empty
    %i icon is dropped, ~user stays unresolved, sqlite temporaries are
    per-process, a cross-device rename falls back to copy, the IPC client fails
    on an error reply, accepts back off, the instance lock is taken before
    Wayland, and a dead core exits 1 instead of looking like a clean dismiss.
  • Localisation follows GLib's order — LANGUAGE first, ignored for a C base
    locale — and the session's original LANGUAGE is handed to launched apps
    rather than the launcher's pinned UI locale.
  • The help usage placeholder and the window workspace summary are translated,
    not inline English.
  • Program resolution checks the exec bit, as execvp does.
  • The fallback walk follows user-dirs.dirs, including localized and moved
    Desktop/Documents/Downloads.
  • An unset, empty or separator-only XDG_DATA_DIRS means the spec default,
    and the flatpak user export path is built from $XDG_DATA_HOME.
  • ~/.icons precedes the system icon roots, matching the Icon Theme spec's
    legacy location.
  • Clipboard history skips entries whose id is not numeric, and the copy
    pipeline runs without a nested shell wrapper.
  • Path completion resolves each typed parent component case-insensitively,
    after trying it exactly.

WayRun v0.7.0

Choose a tag to compare

@github-actions github-actions released this 01 Oct 09:34
v0.7.0
871f77b

Added

  • The plugin contract carries a version. wire::PLUGIN_API is one number both
    plugin surfaces report — a host from list_plugins's api, a Lua script from
    its plugin table's api — and the core logs a mismatch against it rather than
    refusing the plugin, which may still work; a plugin written before versioning
    counts as 0 and is told so until it states what it means. Lua reads the
    current number as wayrun.api, so one script can span two launcher versions.
    It moves when a plugin can observe the change, not for an addition or a
    launcher-internal change: adding a binding leaves it alone, while tightening a
    sandbox rule moves it. See plugins.md and jsonrpc.md.
  • A Lua plugin declares the areas it may read (read: absolute paths or
    ~/…, no patterns) and the environment names it may read (env: exact
    names, no patterns). A path is resolved through symlinks, so a link cannot
    escape, and the plugin's own directory and its script's directory are
    implicit. A sqlite handle answers only for a plugin that could have
    opened its source itself, so a sibling cannot borrow another plugin's
    snapshot. See plugins.md.
  • wayrun.kv keeps strings under keys in a SQLite database inside the
    plugin's own directory, with an optional TTL per entry, so a cache can
    outlive one show: it is the sandbox's only write, bounded to that directory,
    its keys not paths. kv.keys and kv.pairs enumerate the store as ordered
    arrays with expired rows filtered out, so a plugin keeping a list of its own
    no longer maintains an index key by hand.
  • wayrun.http.post carries a JSON, form or raw body, and both verbs take an
    options table — timeout_ms, headers, and a ttl on get that caches a
    2xx reply in the plugin's own key-value store. A reply's response headers
    come back lowercased and its body as raw bytes, and the timeout defaults to
    two seconds, down from five, clamped inside the host call's own ceiling.
    A headers sub-table among params and a bare timeout as the third
    argument both still work. The one network exit is ureq now — a connection
    pool, system-root TLS and gzip — where minreq was, so request header
    names go out lowercased. See resident.md.
  • wayrun.which(name) answers an executable's path from the host's $PATH —
    the same one a run row's command will see — or nil, and
    wayrun.fuzzy.match(query, candidates) ranks a script's own candidates by
    the built-ins' match kinds, best first, ties keeping the input order.
  • wayrun.crypto answers sha256, md5 and hmac_sha256 as hex digests
    over raw bytes, plus base64_encode/base64_decode, where a decode
    answers nil on garbage rather than raising, so the translation and base64
    plugins no longer hand-roll them.

Changed

  • Breaking: the empty-query launch history is gone. An empty query returns
    no rows and clears the list locally, and the top and forget methods, the
    history read path, the host forget relay, the panel's launcher-owned
    Remove from history entry and the builtin:remove glyph go with it. A
    host's own top default view is a different method and stays. See
    jsonrpc.md.
  • Breaking: pins are gone, with the pin/unpin methods, the pin table
    and the panel's Pin to top/Unpin entries. A pin's scope was the exact
    trimmed query, so a pinned row could only be summoned by retyping that
    string, and pinning froze a copy of the row beside its live result; the
    action panel covers the same ground with entries a plugin owns and can make
    default.
  • Breaking: select is record, taking {"on_click": Action}, and the
    database moves to state.db with the usage table shrunk to (on_click, count). The old usage.db is left where it is and no longer read, so the
    counts and the remembered defaults start over once. See jsonrpc.md.
  • Breaking: an actions entry's action is an Action object
    ({"type":"run",…}) rather than {"type":"execute","command":{…}};
    ResultItem loses its badge and ephemeral fields, and a row is exempt
    from recording only when its command is a copy. A host that sets either
    field is ignored rather than obeyed: the badge's only producer was the pin
    that just went, and with history gone the counts are the whole story.
  • Breaking: wayrun.env raises for a name the calling plugin has not
    declared, and fs.list, fs.stat, sqlite.snapshot and sqlite.query
    refuse a path — or a handle whose source lies — outside its declared read
    areas. A script that read the environment or the filesystem without
    declaring them must declare them now.
  • Breaking: wayrun.icon() no longer answers a builtin: glyph, and a
    host's icon must be an absolute path — a file it ships, or a theme icon or
    papirus: spec that wayrun.icon() resolved. The built-in glyphs render in
    the shell now, from its own compiled SVGs, and the core keeps only the
    vocabulary (wire::BUILTIN_GLYPHS) it validates a spec against. The
    bookmark, clock and globe glyphs went with the plugins that shipped
    them, the images/ fallback next to the executable, under an XDG data dir
    or in the dev tree is gone, and a glyph no longer touches the cache
    directory, so a show writes nothing and a missing or unwritable cache no
    longer costs a row its placeholder. See plugins.md.
  • Breaking: wayrun.t is gone: a Lua script carries its own text. The
    table it read was the launcher's own key set, which had a Lua-side owner
    only while the bundled plugins were in tree; plugin-side localisation would
    arrive as a locale accessor instead.
  • Breaking: theme.toml keeps only the keys a user reaches for. [colors]
    keeps the three base roles plus dim, and every other surface derives from
    its role at a shipped alpha; [layout] keeps width, radius, top_ratio,
    align and max_rows; [motion] keeps reduced. The width triple folds
    into one key, follow_system goes (an unset key already follows the system,
    per key), and the stroke, offset and derived-radius keys become constants.
    Every dropped key is inert rather than an error, and an untouched file still
    renders the same frame. See theme.md.
  • Breaking: config.toml's [web_search] table goes, with
    wayrun.web_search_engine(): the engine choice drives the web-search plugin
    alone, which keeps its own setting now. See config.md.
  • The card is one surface: the inner field rectangle is never drawn, the search
    line sits above the rows, and a pristine card rests at the height it fills
    instead of reserving a gap and a footer band it would not fill. The ✕ clear
    button goes with it (Ctrl+A plus Delete, or backspacing, still clear the
    field), so theme.toml's [colors] field and [layout] field_radius are
    inert.
  • The keyword chip goes too — it echoed the prefix the typed text already
    stated, so [layout] chip_radius is inert — and the footer renders no hints
    while the field is untouched, the old help line having become the whole
    message on an empty card. The placeholder is "Type to search": the line it
    replaces promised a web search a given plugin set may not have installed.
  • The result list draws no default dot. A remembered default is filed per
    plugin scope, so it covers every row that scope decorates at once and could
    never single one out; the panel still marks the effective entry and the
    footer still names the selected row's Enter action.
  • The README demo is re-recorded.
  • The Lua plugin guide moved here, beside the SDK it documents: lua.md now
    carries the plugin table, the wayrun table, the sandbox and registration,
    and a guard test holds its binding table to the table the sandbox builds, so a
    binding added without a row is a red test rather than a stale page. The
    WayRun-Plugins workspace keeps the Python framework and both example sets. The
    reference material the two repos had each restated — the Action shapes, the
    result-item keys, the icon rules, the plugins.toml fields — now has one home
    each, and the new page links instead of copying.
  • The tree follows the 2018 module shape — every foo/mod.rs is foo.rs
    beside its foo/ directory — and the layer-named model.rs files fold into
    the module they serve: Meta joins the Plugin trait, the plugins.toml
    schema and the host cache join the registry, both config/model.rs merge
    into their config.rs. The index builder renames to builder.rs, which a
    build.rs reads as a Cargo build script. No behaviour change.
  • The resident core's icon memo drops whole at 4096 distinct specs: a host's
    wayrun.icon() was the one caller that could mint keys without bound.

Fixed

  • A cleared query no longer shows rows under it. An empty text sent as a
    notification cancels the pending search at the core, where it was previously
    ignored, and the shell drops any payload that lands while its query is
    empty. See jsonrpc.md.
  • fs.list sorts the names it hands to Lua, and the $PATH ranking falls back
    to the name when hits share their kind and length, so a listing and a row
    order no longer follow readdir or $PATH order, which differ per machine.
  • wayrun.sqlite reuses one snapshot handle per source, whose connection
    follows its newest copy, instead of opening a connection per call in a
    resident host; pruning leaves another source's copies alone.
  • A one-shot external host's stderr joins the journal, as a resident host's
    already did, so wayrun.log reaches it on both paths.

WayRun v0.6.0

Choose a tag to compare

@github-actions github-actions released this 26 Sep 10:28
v0.6.0
59d210f

Added

  • A plugin can be one Lua script the launcher runs itself. wayrun --lua-host <script.lua> answers the external-host contract (list_plugins, search,
    top, forget) with Lua 5.4 compiled into the binary, so nothing has to be
    installed beside it, and a plugins.toml command entry points at the script
    like any other host, its shebang naming the mode. The script runs sandboxed: a
    curated global set (no os, io, package, load or print) and a
    wayrun table of bindings — t() for locale-correct strings, icon,
    urlencode, json/toml decoders, sqlite over an immutable snapshot of a
    database, http.get, a scoped fs, time, env, home, cache_dir,
    web_search_engine, script_dir, plugin_dir and log. The API guide lives
    in the WayRun-Plugins workspace (docs/en/LUA.md).
  • resident = true keeps a host process alive across calls: about a
    millisecond per call against the fresh fork's several. A per-request deadline
    kills and restarts a stalled or crashed host, a call a newer one overtook is
    skipped so a keystroke burst cannot stack work on the pipe, and a host is
    reaped when the launcher dismisses or after two minutes idle; a resident
    host's stderr joins the journal, where a fork-per-call child's is nulled. See
    plugins.md.
  • wayrun.plugin_dir(id) names ~/.config/wayrun/plugins/<id>/, the directory
    a plugin keeps its files in, and fs.read reads a relative path under it,
    refusing an absolute path or a ..; wayrun.toml.decode parses the plugin's
    own config file, the format the launcher's own configs are written in. A
    plugin id is validated as a plain name, since it becomes a directory root.

Changed

  • Breaking: b, h and s no longer ship. The Firefox and web plugins are
    Lua scripts in the WayRun-Plugins workspace now, registered as ordinary hosts
    with a command entry, and what remains in the launcher is the mechanism:
    --lua-host, the bindings and resident. See plugins.md.
  • Breaking: wayrun.http.get answers {status, body} instead of the bare
    body string, and takes a headers sub-table beside the query parameters. A
    script that read the body must read res.body; the headers are there because
    minreq sends no User-Agent of its own, so an API that requires one
    (GitHub's) was unreachable from a plugin while the Python SDKs, whose urllib
    sends one by default, never saw the problem.
  • Host rows parse from the reply without a per-item clone: measured on the real
    Firefox payloads, the bookmark query takes 1.56 → 1.36 ms and the history
    query 2.48 → 2.35 ms, and every Python host call gains the same slice.

Fixed

  • ui.locale governs the text the .desktop files contribute (application
    names, their comments and desktop action labels), not just the launcher's own
    strings: the core pins the configured locale into LANGUAGE as well, which is
    the variable glib reads its language from, and the executor hands every app it
    launches the session's original value back. See config.md and usage.md.

WayRun v0.5.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 16:54
v0.5.0
2bfa6df

Added

  • Every spawn in executor.rs goes through systemd-run --user --scope --collect --slice=app.slice, so an app the launcher starts is no longer
    accounted to wayrun-launcher.service: the unit's memory and CPU stay its own,
    a restart cannot strand apps as left-over process, and systemd-oomd's victim
    is the app rather than the launcher plus everything it ever started. Expansion
    stays off (--expand-environment=no), since systemd-run's default rewrites a
    literal ${HOME} in a command line or URI; the gio paths go through gio launch/gio open so the process gio forks lands in the scope too, and a spawn
    now hands the child to a task that waits it, so it no longer lingers as a
    zombie. Without a reachable user manager or the gio CLI the spawn keeps its
    in-process call, and apps launched before this release keep their old cgroup —
    a scope is not retroactive. See resident.md.
  • The dismiss method: the launcher says it has closed, and the core cancels
    the search still in flight and drops the payload a pin names rows in. A
    results payload that lands after a dismissal no longer refills the rows or
    warms their icons.

Changed

  • Breaking: [files] depth is gone. It only mattered with the index off, so
    the fallback walk owns it as a constant now; a config still carrying the key
    parses and the key is ignored. An absent exclude now means the shipped
    node_modules, target and __pycache__ rather than no exclusion at all, a
    user's own list replaces those names whole, and exclude = [] searches
    everything but hidden names. A [files] section that set depth or relied on
    omitting exclude should be reviewed. See config.md.
  • Breaking: pin takes {"scope","on_click": Action}, the pair unpin
    already took, and no longer accepts an item payload: the core looks the row
    up in the payload it last emitted for that scope, so a client names the row by
    the command it carries, and a command that payload no longer holds answers
    pinned: false instead of storing a stale row. Every row used to embed a copy
    of itself in its pin entry, and that copy crossed the wire twice; on a 20k-row
    history the top payload fell 17,131,343 → 13,004,661 bytes (a row 942 → 678,
    its pin entry 349 → 116) and peak RSS 74–76 → 69.6 MB, at 0.13 s wall either
    way. What a pin stores is unchanged. See jsonrpc.md.
  • The file index loads lazily again, on the first f/d: pre-warming it cost
    every launcher open 32 MB of page cache and a 33 MB mapping whether or not the
    index was ever wanted. An index found stale now answers the query that found it
    stale instead of falling back to the depth-3 walk, which buys recall (hundreds
    of shallow rows against tens of thousands, once the image is a minute old) at
    the price of row data up to ~0.1 s out of date.
  • The interactive path, by effect: a clipboard or window search answers from the
    last fetch and revalidates in the background, where niri msg -j windows
    (~12 ms) and cliphist list (~4 ms) used to run on every search past the
    500 ms burst window; the file scan's chunks go through rayon (d download p50
    2.29 → 2.02 ms, and the pool parks between searches: 0 CPU ticks over 90 s
    idle); a streaming top no longer runs on the read loop, so typing does not
    queue behind a full history build; the usage database gained an
    (on_click, key) index and WAL, taking a one-shot select from 8 fdatasyncs
    to 0; icons decode on a worker thread instead of in the frame that draws them;
    the query and session-bus work moved off the runtime's workers; and a hidden
    resident launcher drops the rows it was holding.
  • The release binary is linked with full LTO rather than thin: 6,984,904 →
    6,510,872 bytes (6.8% smaller, ~2.87 MB gzipped), with startup unchanged.

Fixed

  • A run line reaches the shell as it was typed. %u, %U, %f and %F were
    being deleted from it, so r date +%F ran date +, and a host's run{cmd}
    was stripped the same way; the terminal path never did it, so which of the two
    a command took decided whether the codes survived. jsonrpc.md now states that
    only launch and desktop_action read .desktop field codes.
  • The shell's two external interactions are bounded. A clipboard read is killed
    after one second and answered with no text, so a stuck selection owner cannot
    wedge a paste, and the pipe is read from a thread of its own so a selection
    larger than the pipe buffer cannot deadlock it. The IPC listener takes the
    wayrun.lock flock before binding the socket, closing the race where two
    simultaneous starts both unlinked it.
  • The shared copy-link action files its default under its own copy-url scope
    instead of inheriting firefox-bookmarks, so a remembered default applies to
    every URL row whichever provider answered.
  • Opening or closing the action panel re-derives the hover, so a stationary
    pointer no longer highlights a row that moved out from under it; the shell's
    select payload sends summary and icon as null rather than an empty
    string, matching the rows the core emits.
  • A .desktop action's %c comes from the same locale list as the row's title,
    so a session that sets LC_ALL or LANGUAGE over LANG no longer launches an
    action named in a different language than the panel showed.

WayRun v0.4.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 02:11
v0.4.0
5bdc130

Added

  • f and d search the whole home directory at any depth through a background
    index ($XDG_CACHE_HOME/wayrun/file-index.bin): built on the first f/d
    search, mapped only while in use and unmapped after two minutes idle, and
    re-checked within a minute by a parallel sweep that re-reads just the
    directories whose mtime moved — a patch of ~0.1 s against the walk of ~1.2 s
    it replaces. Every row carries a bigram bloom (index format v4) that the scans
    reject on before touching a name. config.md's [files] holds index
    (default true), depth (the unindexed fallback, 3) and exclude.
  • [files] exclude names the directories the walk never enters. The shipped
    config.toml lists node_modules, target and __pycache__; a name
    starting with a dot is always hidden, and an edit to the list rebuilds on the
    next f/d search.

Changed

  • Breaking: a plain query no longer stops at the first provider with
    results. calculator, system-commands and app-search all answer, and
    their rows are merged by each row's relevance — the match kind's weight scaled
    by the surface it matched on — then by the row's usage count, then by
    registry order, so a prefix command can no longer hide an exact app.
  • Breaking: the app list's metadata surfaces are visible in a plain query:
    a keyword or GenericName matches by word and a Comment by prefix, and a
    near spelling of a name answers too. A title match leads a description match
    of comparable strength, while an exact keyword still beats a title the query
    only sits inside of.
  • Every provider ranks by one match vocabulary: the file index, the path scans,
    the runner, the window list and the app list share the same kinds, and
    nucleo is gone with its transitive crates. A f/d build logs itself on
    stderr (file index … (patched) / (loaded) / (capped)).

Fixed

  • A clipboard preview longer than 80 bytes is cut on a character boundary
    instead of panicking on a multi-byte preview, which silently emptied the
    whole list.
  • A keystroke burst no longer runs one search per key: the core coalesces
    superseded queries and drops their payloads.
  • Firefox snapshots are opened read-only and immutable, so a b/h query takes
    no locks on the private copy.
  • The plugin host cache (now under $XDG_CACHE_HOME/wayrun) and the built-in
    glyphs are written atomically, so a crash mid-write cannot leave a torn file
    behind.
  • The file index only serves a cache it can vouch for: an unreadable walk is
    never persisted as an empty index, a directory layout that is not the walk's
    own pre-order is rejected, a non-UTF-8 $HOME still indexes and serves, and
    the first search after an idle unmap remaps instead of falling back to the
    walk.
  • The index's own search no longer pays for work it discards: every indexed row
    ran a Loose subsequence pass its caller threw away and then a second
    substring pass. f report on this home's 555k-name index went ~12 ms -> ~3 ms
    — confident-only classifiers, a memchr2 candidate walk that fuses the word
    and substring checks, and a per-row bloom the scans reject on before touching
    a name.
  • An index build's peak memory fell 144 MB -> 96 MB on this home: the walk keeps
    one length-prefixed names buffer per directory instead of one allocation per
    name, and the image streams into the cache file instead of being materialised
    beside the tables.

WayRun v0.3.1

Choose a tag to compare

@github-actions github-actions released this 22 Sep 14:44
v0.3.1
25d3f4a

Added

  • The interface is translated: locales/en.yml and locales/zh_cn.yml hold
    every string the launcher shows, and the locale is resolved once at startup
    from $LC_ALL, $LC_MESSAGES, $LANG — zh_CN.UTF-8 becomes zh_cn, any
    zh_* variant reads the one Chinese table, anything else falls back to
    English. Plugin names and ready hints, action titles, the ? help line, the
    system commands and the web-search rows are all covered. wayrun status,
    --list-plugins and the RPC errors stay English, and whatever a host sends
    is relayed as it is.
  • config.toml's [ui] locale pins the interface language regardless of the
    session, which is what a resident service needs: its unit inherits the
    session's locale, or none at all. It is read at startup, so a change needs a
    restart.
  • The action panel leads with the row's own command (Open), so its first
    slot is what Enter runs: Shift+Enter then Enter opens the row instead of
    pinning it, and Alt+Enter on Open clears a remembered default whichever
    scope set it.
  • A remembered default is visible without opening the panel: the row carries the
    same dot, its footer names the action Enter will run (⏎ Open in terminal)
    instead of ⏎ Launch, and ? lists each plugin's remembered action.
  • An action an external host attaches can be made the default Enter action: the
    core stamps the host as the owner of the actions it parses out of a response,
    so the host's scope is what the gesture sets.
  • A new launcher mark, images/logo.svg (replacing
    images/application_default.png), trails three fading echoes behind the W,
    and the built-in builtin:app glyph is drawn from the same rest geometry.

Changed

  • A file or directory row lists "Open in terminal" next to Open, with
    "Reveal in file manager" and "Copy path" after them, so the open-family
    entries are grouped at the top of the panel instead of the terminal being
    last.
  • Pin/unpin and the default gesture re-send the query with the panel held open
    on the entry that changed, so the change lands where it was made. The resume
    is dropped by a close, a hide and every query edit, so a slow host's reply
    cannot resurrect a panel the user closed.
  • Both README editions no longer name Papirus as the icon theme: app and file
    rows follow the desktop's own theme. A License section credits the bundled
    Material Symbols (Apache-2.0) and links the notice.
  • The user-facing pages state what a feature is and how to use it: the
    implementation narrative (process split, caches, internal paths) is gone, and
    the two language editions keep the same sections.