README.md raw

liftoff

A classically Unix-ish application launcher for Wayland.

Most launchers today are built around XDG desktop entries — they show you .desktop files. liftoff does the older, simpler thing: it runs programs from your $PATH, optionally with arguments, the way a shell would. You type a command, it completes on the fly, and pressing space (to add arguments) or enter (to run) uses the highlighted match. It’s not identical to typing at a shell prompt, but it’s close.

liftoff completing a command prefix

Behavior

  • Completion, live. As you type, liftoff filters the executables on your $PATH and lists the matches. When the highlighted match continues what you typed, its remaining letters are shown as a dimmed “ghost” after the cursor.
  • $PATH order, not alphabetical. Matches are listed in search order — everything from the first directory on your $PATH, then the second, and so on — with names from the same directory sorted alphabetically. So the copy a shell would actually run is the one you reach first. A command found in several directories is listed once, under the earliest.
  • A whole name wins. If what you typed is a command, it heads the list wherever it lives on your $PATH: git gets you git, not gitk from some directory ahead of it. Where the matching ignores case, so does this — typing steam puts Steam at the top.
  • Forgiving matching. liftoff tries progressively looser criteria and stops at the first that finds anything: names that start with what you typed, then names that contain it, then a case-insensitive contains. So valve finds com.valvesoftware.Steam — but an exact prefix is never diluted by looser hits.
  • The highlighted match is what runs. It defaults to the first match listed; the arrow keys move it.
  • Space commits, then you type arguments. Pressing space replaces your typed text with the highlighted command and switches to argument entry. From there, further typing builds an argument string (split with shell-like quoting rules), and spaces are literal.
  • Enter runs it. The highlighted command is launched, detached, with whatever arguments you’ve typed, and liftoff exits.

Executables reached through symlinks count too, so flatpak’s exported app ids (like com.valvesoftware.Steam) turn up alongside everything else — no .desktop files needed. And because liftoff only ever launches a name it found on your $PATH, it never tries to run something that doesn’t exist.

Keys

KeyAction
(type)Filter commands by prefix
/ Move the highlight up / down the match list
Space / TabCommit the highlighted command and start typing arguments
EnterRun the highlighted command (with any arguments) and exit
BackspaceDelete a character; from empty arguments, return to editing the command
EscDismiss without running anything

Requirements

  • A Wayland compositor implementing the wlr-layer-shell protocol — the wlroots family (Sway, Hyprland, river, Wayfire, …) and others. liftoff appears as a centered overlay and takes keyboard focus while it is open.
  • A recent Rust toolchain (edition 2024).

liftoff renders itself in software with cosmic-text for font shaping, so it needs no GPU and pulls in no GTK/Qt. It uses your installed system fonts.

Install

git clone https://git.sr.ht/~djarb/liftoff
cd liftoff
cargo install --path .

This puts a liftoff binary in ~/.cargo/bin.

Use

liftoff has no options — run it and start typing. In practice you bind it to a key in your compositor. For example, in Sway:

bindsym $mod+space exec liftoff

or in Hyprland (Lua config):

hl.bind("SUPER + SPACE", hl.dsp.exec_cmd("liftoff"))

How it works

liftoff is split into a display-independent core library and a thin UI binary:

  • executables scans every directory on $PATH for executable files (following symlinks), keeping the names sorted and deduplicated so prefix matches are a contiguous binary-searched range and the substring fallbacks are a simple scan. Each name remembers which $PATH directory it came from, and the matches a search returns are stably re-sorted by exactness and then that — which, from an alphabetical starting point, yields the typed name first and then search order with an alphabetical tie-break.
  • query is the editing model behind the input line: a small state machine that moves between completing a command name and typing its arguments, and tracks which candidate is highlighted.
  • launch spawns the resolved command in its own session so it survives liftoff exiting.
  • The binary draws the overlay with smithay-client-toolkit (layer shell, input) and cosmic-text, compositing into a shared-memory buffer by hand.

The overlay is put on screen before anything slow happens. Until it is mapped it does not hold keyboard focus, so any key struck in the meantime goes to the window underneath — which matters, because both scanning $PATH and loading fonts can take a noticeable moment on a cold cache. So liftoff commits its surface first and does that work afterwards, with the $PATH scan on a worker thread. You can type immediately; a keystroke that needs the command list before it has arrived (enter, tab, the arrow keys) is held and applied the moment it does, in the order you typed it.

The core is covered by unit tests (cargo test).

License

liftoff is released into the public domain under the Unlicense. Do whatever you like with it.