Skip to content

feat: make a command and a menu entry for a program with raven env shortcut - #56

Merged
MotherSphere merged 2 commits into
Project-Colony:mainfrom
ghahramani:feat/shortcut-commands
Nov 3, 2026
Merged

MotherSphere merged 2 commits into
Project-Colony:mainfrom
ghahramani:feat/shortcut-commands

Conversation

@ghahramani

@ghahramani ghahramani commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Starting a program means typing the whole raven run <env> -- wine 'C:\…\program.exe' line every time. A program installed by copying a folder (a portable build, a game's own launcher) leaves no Start menu shortcut for Wine to turn into a menu entry, so it never appears in the applications menu. Started from a launcher, it has no terminal either, so whatever it prints when it crashes is lost.

What changes

raven env shortcut <env> <command> [--title NAME] [--cwd DIR] -- <argv> writes three files, the way an installer would:

  • The command: ~/.local/bin/<command>, or $XDG_BIN_HOME/<command> when that is set. It is a shell script that runs raven run <env> [--cwd DIR] -- <argv> "$@", so arguments given to the command reach the program. It writes stdout and stderr to $XDG_RUNTIME_DIR/raven-logs/<command>.log and keeps the start before as .log.1. Started from a terminal, it first prints where the log is. The script names the Raven binary by its path and falls back to raven on PATH once that binary has moved.
  • The menu entry: ~/.local/share/applications/raven-shortcut-<command>.desktop, which runs the command. It sets StartupWMClass to the program's file name in lower case, as Wine's own entries do, so the panel can match the program's windows to the entry.
  • The icon: read out of the .exe and saved as ~/.local/share/Colony/Raven/icons/<command>.png. The program is found by its C: path in the environment's layers (upper first, names matched without case, no mount needed). When there is no icon to read, the entry shows Raven's.

How it behaves:

  • Menu name: the program's file name without .exe, unless --title gives one.
  • Listing and removing: with no command it lists the environment's shortcuts, and --remove deletes all three files. Both still work after the environment is destroyed.
  • Files that aren't Raven's: each file carries a line marking it as Raven's. A file without it is never replaced or deleted (ShortcutTaken), and nothing is half-written when the menu entry's name is the one taken.
  • Names: a command name must be a plain command (letters, digits, -_.+, not starting with - or .), and raven, rvn, raven-gui and raven-linux are refused.
  • PATH warnings: Raven warns when the bin directory is not on PATH, or when another program of that name comes first on it.

icon.rs reads the icon without a new dependency:

  • Which icon: it takes the first RT_GROUP_ICON (the one Explorer shows) and that group's largest image.
  • PNG images are taken as they are.
  • Bitmaps are decoded: 32-bit with alpha, or 24, 8, 4 and 1 bit through the AND mask. The result is written as an RGBA PNG whose zlib stream uses stored blocks, so no encoder is needed.

Other changes:

  • Paths: paths::bin_dir and paths::logs_dir. The logs go in $XDG_RUNTIME_DIR/raven-logs, beside raven/ rather than inside it, because every name in raven/ is an environment's.
  • Errors and strings: four new error variants (BadShortcutName, ShortcutTaken, NoSuchShortcut, ShortcutFile), with every string in English and French.
  • Docs: a section in usage.md, the new files in mount-stack.md's "Where files live", a README bullet, and the test counts.

Testing

  • cargo test --workspace: 231 passed (213 before).
    • Icon tests: a PE built in the test with a PNG image and with 32-bit, 24-bit and 4-bit bitmaps. They check the alpha, the mask, the palette and the upright row order, read the written PNG back through its chunk CRCs and Adler-32, and check that a truncated file and a file with no icon give nothing.
    • Shortcut tests: each one writes a shortcut and runs the command with sh. They check that arguments containing quotes, $, spaces and * reach Raven intact, that both streams reach the log and the previous start is kept, the fallback to raven on PATH, the menu entry's contents, that files Raven did not write are left alone, listing and removal by environment, finding the program through the layers without case, and the PATH report.
  • cargo clippy --workspace --all-targets -- -D warnings: clean.
  • On the real Windows 11 base with Wine 11.20:
    • A game: a shortcut for a game installed by copying its folder made a command, a menu entry that passes desktop-file-validate, and the game's 256×256 icon.
    • Through the menu: a shortcut for wine cmd /c ver, started with gio launch on its menu entry, logged Microsoft Windows 10.0.22000, the same as when it is started from a shell.
    • Icons from real programs: the Rockstar Games Launcher, its uninstaller, a VC++ redistributable (32×32 bitmap), winecfg, regedit, taskmgr and calc all gave the right icon. mspaint, whose Windows 11 executable is a stub with no icon, got Raven's.
    • Removal: --remove deleted all three files of each test shortcut.

Not tested: a desktop other than KDE Plasma, or a --cwd shortcut started from the menu.

…hortcut`

`raven env shortcut <env> <command> -- <argv>` writes three files, the
way an installer would:

- `~/.local/bin/<command>` (or `$XDG_BIN_HOME`), a shell script that runs
  `raven run <env> -- <argv> "$@"`. It writes what the program prints to
  `$XDG_RUNTIME_DIR/raven-logs/<command>.log` and keeps the start before
  as `.log.1`, since a program started from the menu has no terminal.
- `~/.local/share/applications/raven-shortcut-<command>.desktop`, an
  applications menu entry that runs the command.
- The program's icon, read out of its `.exe` and written as a PNG to
  `~/.local/share/Colony/Raven/icons/<command>.png`.

Without a command it lists the environment's shortcuts, and `--remove`
deletes all three files. Each file is marked as Raven's, and a file
without that mark is never replaced or deleted. Raven also warns when the
bin directory is not on PATH, or when another program of that name comes
first on it.

The icon reader (`icon.rs`) follows the first RT_GROUP_ICON to its
largest image. A PNG image is taken as it is. A bitmap is decoded (32-bit
with alpha, or 24, 8, 4 and 1 bit with the AND mask) and written as a PNG
with stored deflate blocks, so the crate gets no new dependency.
@ghahramani
ghahramani force-pushed the feat/shortcut-commands branch from d9a11de to fe8f91a Compare November 3, 2026 02:40
- A shortcut cannot be named `wine` or `wineserver`, nor after any other
  program on PATH, nor after a bare first word of the command line it
  runs: `raven run` execs that word by PATH, inside the environment too,
  and would start the shortcut again instead of Wine.
- Without --cwd the program starts in its own directory inside the
  environment, as a Windows shortcut starts it; `setns` used to leave it
  in Z:\. When the program is not found, Raven says so.
- The log goes to ~/.cache/Colony/Raven/logs, a directory made 0700,
  instead of the runtime directory, a small tmpfs that also holds the
  session records. It is written only when no stream is a terminal, so a
  menu launch is logged and `game > out.txt` typed in a terminal is not
  redirected.
- Another environment's shortcut of the same name is refused instead of
  taken over. Removal deletes the menu entry, the icon, then the command,
  reports an entry it kept because it was not Raven's, and stops on an
  error. Names are at most 64 characters, ownership is checked before the
  program is read, and the menu entry is written last.
- X-Raven-Shortcut= comes right after the header, so a long title cannot
  push it past what is read. A temporary file is no longer listed.
- A program over 512 MiB is not read, and the read is bounded whatever
  the size claims. A C: path with `..` is refused. Paths that are not UTF-8 are refused
  instead of rewritten. The layers are found without the runtime
  directory.
- icon.rs: the section offset is added in usize (a PointerToRawData near
  u32::MAX panicked in debug builds); the images of the group are tried
  largest first, at most 16; a PNG image needs an IHDR within 1024 pixels and 4 MiB;
  the palette and pixels are cut out before decoding. from_exe returns
  the PNG bytes, and the module is crate-private.
- The temporary file write is shared with registry::text::write_atomic,
  which now also uses a dot-prefixed name.
- `raven env destroy` says when the environment's shortcuts are left.
- Strings, French wording and docs follow; 245 tests.
@MotherSphere
MotherSphere merged commit 3d40d65 into Project-Colony:main Nov 3, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants