Contributing to harrier #
Thank you for wanting to help. This file covers what you need to know to get a change into harrier. The README explains what harrier is and how it is put together, and its "Design" section is worth reading before you change anything structural.
Issues and pull requests #
Report bugs and open pull requests on the Tangled mirror: https://tangled.org/jcollie.dev/harrier.
For a bug, say:
- which compositor and GPU (or
llvmpipe) you ran it on; - what you did, and what you expected instead;
- the log on standard error.
HARRIER_STARTUP_TIMES=1adds timings for startup problems,--validationturns on Vulkan's validation layer for rendering problems, andAERIE_TRACE_POINTER=1logs every pointer enter, leave and button, and every change in the seat's devices, for a drag or selection that does not end when the button is let go.
Setting up #
Everything comes from the Nix flake:
$ nix develop
$ zig build run
$ zig build test --summary all
The development shell has Zig 0.17.0, the Vulkan loader and its validation layer, REUSE, and zon2nix.
Before you send a change #
All of these must pass, and CI runs each of them:
$ nix develop -c zig fmt --exclude zig-pkg --check .
$ nix develop -c reuse lint
$ nix develop -c zig build test --summary all
$ nix develop -c zig build -Dtarget=x86_64-windows-gnu
$ nix build .#msi
$ nix flake check
CI runs the two zig build commands through tools/zig-build.sh, for
example nix develop -c tools/zig-build.sh test --summary all. The
script gives Zig the dependencies Nix fetched, the same ones the package
build uses, so nothing is downloaded from the dependencies' own hosts.
Run them that way if a dependency's host is failing.
On Windows itself, zig build test --summary all runs the tests that do
not need a POSIX shell, the pseudoconsole's among them.
nix flake check builds the package and runs every NixOS VM test. A
single VM test can be run on its own, for example
nix build .#checks.x86_64-linux.sway. The VM tests need KVM. The
shortcuts test boots KDE Plasma and needs a guest with 4 GB of memory.
Tests #
- Logic goes under unit tests. Keep code that can be tested without a window apart from the Wayland and Vulkan code: layout, hit-testing, parsing, the placement of things on the grid. Test it in the same file.
- What only shows on screen goes in a VM test. Add or extend a test
in
tests/nixos/and register it inflake.nix'schecks. If CI should run it, add a step to.forgejo/workflows/test.yaml.- Assert on pixels: count a color that nothing else on the screen has.
- Assert what should not happen as well, such as nothing drawn with the feature turned off.
- Look at what you drew. Changes to drawing are worth checking by
hand in a headless sway, taking screenshots with
grim. The README's "Tests" section says what has been checked that way.
Style #
- Zig 0.17. Match the code around you: its naming, its comment density, and its doc comments, which explain why rather than restating the code.
- American English in code, comments and documentation.
- The README describes harrier as it is now, for a reader who has never seen it. Update it in the same change as the code: the feature list, the configuration, the design, and the tests. Leave history to the commit messages.
- Commit messages say what changed and why, in the imperative ("Draw images sent with kitty's graphics protocol"), with a body for anything not obvious.
Dependencies #
-
Zig dependencies go in
build.zig.zon. After adding, removing or updating one, regenerate the Nix expression and commit it with the change:$ nix develop -c tools/zon2nix.shThe script leaves out what only Ghostty's own application uses. If
nix buildthen stops with "lazy dependency package not found", the build does ask for that package: take it out of the script's list.The package builds with no network access, so a dependency missing from
build.zig.zon.nixfailsnix buildwhilezig buildstill works. -
libghostty-vt comes from the
zig-0.17-jeffbranch of https://git.jcollie.dev/jeff/ghostty. Changes to the terminal itself belong there, not in harrier. -
zig-aerie, the window system, the Vulkan renderer and its shaders, the font stack, the title bar and the desktop's settings, comes from https://git.jcollie.dev/jeff/zig-aerie, pinned in
build.zig.zon. A change to any of those belongs there, not in harrier: other programs draw with it too. To try one before it is pushed, build harrier against your checkout withzig build --fork=../zig-aerie; once it is pushed, pin the new commit withzig fetch --save=aerie git+https://git.jcollie.dev/jeff/zig-aerie.git#<commit>and regeneratebuild.zig.zon.nix. zig-aerie and harrier must pin the same commits of the packages they share — mdbus, zig-dbus-service, zig-xkb, the font libraries — and build them with the same options, or the build stops with "file exists in modules". -
Everything else (Vulkan, the fonts) comes from the flake.
Translations #
harrier's text is in locales/, in Fluent
syntax. locales/en-US.ftl is the source: every message is there, with a
comment saying what its arguments are. To add a language:
- Copy
en-US.ftltolocales/<tag>.ftl, named by its BCP 47 tag:de,pt-BR,zh-Hant. - Translate the values, never the message names or the
$arguments. The variants of a select expression ([failed],*[working]) are the values the program passes; translate what follows each, and add or drop plural forms as your language needs withNUMBER()and CLDR plural categories. The Fluent Syntax Guide explains all of it. - Add the tag to the list in
localesModuleinbuild.zig, after"en-US". zig build testchecks that every file parses. Try it with.{ .language = "<tag>" }in a configuration, orLANGUAGE=<tag>.
A message you leave out falls back to English, so a partial translation is better than none.
When code adds text users read, it goes into en-US.ftl with a comment,
and the code formats it through src/l10n.zig: l10n.text for a message
with no arguments, l10n.format or l10n.write for one with them. A new
message is a new name; change a message's name when its meaning changes,
so that translations of the old meaning stop matching.
Licensing #
harrier is MIT licensed and follows the REUSE specification:
- Every new file needs an SPDX header. Files that cannot carry one need an
annotation in
REUSE.toml. - Code ported from elsewhere keeps its original copyright line, above harrier's, and is listed in the README's "License" section.
- Only bring in code under a license compatible with MIT.
References #
If your change follows a specification, a protocol or someone else's documentation, add it to the README's "References cited" section.